Skip to content

Commit b6e3593

Browse files
committed
Add task preprocessing workflow and Confluence requirements documentation
- Add aicode-preprocess.yml: Converts one-liner tasks to structured user stories via OpenAI - Add preprocess-task.mjs: Script for OpenAI task conversion - Add confluence-requirements.yml: Publishes requirements to Confluence in parallel with code generation - Update aicode-agent.yml: Use enhanced tasks from preprocessing workflow - Workflow flow: aicode → preprocess → aicode-enhanced (triggers both agent and Confluence workflows)
1 parent f1d6ca8 commit b6e3593

4 files changed

Lines changed: 406 additions & 9 deletions

File tree

.github/agent/preprocess-task.mjs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import OpenAI from "openai";
2+
3+
/**
4+
* Preprocess Task - Convert one-liner task descriptions to structured user stories
5+
*
6+
* This script takes a natural language task description and converts it to a
7+
* structured user story format using OpenAI, making it clearer for code generation.
8+
*/
9+
10+
const task = process.env.TASK || "";
11+
const openaiApiKey = process.env.OPENAI_API_KEY;
12+
const model = process.env.PREPROCESSING_MODEL || "gpt-4o-mini";
13+
14+
if (!task) {
15+
console.error("[PREPROCESS] TASK environment variable not set");
16+
process.exit(1);
17+
}
18+
19+
if (!openaiApiKey) {
20+
console.warn("[PREPROCESS] OPENAI_API_KEY not set, skipping preprocessing");
21+
console.log(`[PREPROCESS] Original task: ${task}`);
22+
process.exit(0);
23+
}
24+
25+
const openai = new OpenAI({ apiKey: openaiApiKey });
26+
27+
const systemPrompt = `You are a task analysis assistant for a code generation system. Your job is to convert natural language task descriptions into structured user stories that are clearer and more actionable for AI code generation.
28+
29+
Convert the given task description into a structured user story format following this template:
30+
31+
"As a [role], I want to [action] so that [benefit].
32+
33+
Acceptance Criteria:
34+
- [Criterion 1]
35+
- [Criterion 2]
36+
- [Criterion 3]"
37+
38+
Guidelines:
39+
- Identify the user role (administrator, developer, end user, etc.)
40+
- Extract the main action/feature requested
41+
- Clarify the benefit or goal
42+
- Break down the task into specific, testable acceptance criteria
43+
- Maintain all technical context and requirements
44+
- Keep it concise but comprehensive
45+
- If the task is already well-structured, enhance it rather than completely rewriting
46+
47+
Output ONLY the user story, no explanations or markdown formatting.`;
48+
49+
const userPrompt = `Convert this task description into a structured user story:
50+
51+
${task}`;
52+
53+
async function preprocessTask() {
54+
try {
55+
console.log(`[PREPROCESS] Converting task to user story using ${model}...`);
56+
console.log(`[PREPROCESS] Original task: ${task}`);
57+
58+
const response = await openai.chat.completions.create({
59+
model: model,
60+
messages: [
61+
{ role: "system", content: systemPrompt },
62+
{ role: "user", content: userPrompt }
63+
],
64+
temperature: 0.3, // Lower temperature for more consistent output
65+
max_tokens: 500, // User stories should be concise
66+
});
67+
68+
const enhancedTask = response.choices[0].message.content.trim();
69+
70+
console.log(`[PREPROCESS] Enhanced task (user story):`);
71+
console.log(enhancedTask);
72+
73+
// Output to stdout for workflow to capture
74+
console.log(`\n[PREPROCESS] ENHANCED_TASK_START`);
75+
console.log(enhancedTask);
76+
console.log(`[PREPROCESS] ENHANCED_TASK_END`);
77+
78+
// Also output as JSON for easier parsing
79+
process.stdout.write(`\nENHANCED_TASK_JSON:${JSON.stringify({ original: task, enhanced: enhancedTask })}\n`);
80+
81+
} catch (error) {
82+
console.error(`[PREPROCESS] Error during preprocessing: ${error.message}`);
83+
console.warn(`[PREPROCESS] Falling back to original task`);
84+
console.log(`[PREPROCESS] Original task: ${task}`);
85+
// Output original task so workflow can continue
86+
console.log(`\n[PREPROCESS] ENHANCED_TASK_START`);
87+
console.log(task);
88+
console.log(`[PREPROCESS] ENHANCED_TASK_END`);
89+
process.exit(0); // Exit successfully with original task
90+
}
91+
}
92+
93+
preprocessTask();

.github/workflows/aicode-agent.yml

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ name: AICODE Agent
22

33
on:
44
repository_dispatch:
5-
types: [aicode]
5+
types: [aicode-enhanced]
6+
# workflow_run:
7+
# workflows: ["AICODE Preprocess"]
8+
# types: [completed]
69

710
jobs:
811
agent:
@@ -31,6 +34,12 @@ jobs:
3134
working-directory: .github/agent
3235
run: npm install
3336

37+
- name: Log task information
38+
run: |
39+
echo "Original task: ${{ github.event.client_payload.original_task || github.event.client_payload.task }}"
40+
echo "Enhanced task: ${{ github.event.client_payload.task }}"
41+
echo "Preprocessing run: ${{ github.event.client_payload.preprocessing_run_id || 'N/A' }}"
42+
3443
- name: Run AI Agent
3544
id: agent
3645
env:
@@ -54,8 +63,11 @@ jobs:
5463
GITHUB_RUN_ID: ${{ github.run_id }}
5564
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5665
GITHUB_REPOSITORY: ${{ github.repository }}
57-
TASK: ${{ github.event.client_payload.task }}
66+
# Use enhanced task from preprocessing if available, otherwise use original
67+
TASK: ${{ github.event.client_payload.task || github.event.client_payload.original_task }}
68+
ORIGINAL_TASK: ${{ github.event.client_payload.original_task || github.event.client_payload.task }}
5869
REQUESTER: ${{ github.event.client_payload.requester }}
70+
PREPROCESSING_RUN_ID: ${{ github.event.client_payload.preprocessing_run_id || '' }}
5971
DEBUG: ${{ vars.DEBUG || 'false' }}
6072
run: node .github/agent/agent.mjs
6173
continue-on-error: true
@@ -65,7 +77,7 @@ jobs:
6577
run: |
6678
curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
6779
-H "Content-Type: application/json" \
68-
-d "{\"text\":\"❌ AICODE Agent failed before tests\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"❌ *AICODE Agent Failed*\\n\\n*Task:* ${{ github.event.client_payload.task }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*Stage:* Agent execution\\n\\nCheck the logs for detailed error information.\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View GitHub Actions logs>\"}}]}"
80+
-d "{\"text\":\"❌ AICODE Agent failed before tests\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"❌ *AICODE Agent Failed*\\n\\n*Task:* ${{ github.event.client_payload.task || github.event.client_payload.original_task }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*Stage:* Agent execution\\n\\nCheck the logs for detailed error information.\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View GitHub Actions logs>\"}}]}"
6981
7082
- name: Validate diff format
7183
id: validate
@@ -107,18 +119,20 @@ jobs:
107119
uses: peter-evans/create-pull-request@v6
108120
with:
109121
token: ${{ secrets.GITHUB_TOKEN }}
110-
commit-message: "AI: ${{ github.event.client_payload.task }}"
122+
commit-message: "AI: ${{ github.event.client_payload.task || github.event.client_payload.original_task }}"
111123
branch: aicode-${{ github.run_number }}
112124
base: develop
113-
title: "AICODE: ${{ github.event.client_payload.task }}"
125+
title: "AICODE: ${{ github.event.client_payload.task || github.event.client_payload.original_task }}"
114126
body: |
115127
Autonomous code changes requested by @${{ github.event.client_payload.requester }}
116128
117-
**Task:** ${{ github.event.client_payload.task }}
129+
**Task:** ${{ github.event.client_payload.task || github.event.client_payload.original_task }}
130+
**Original Task:** ${{ github.event.client_payload.original_task || 'N/A' }}
118131
**Tests:** ✅ Passed
119132
**Validation:** ✅ Passed
120133
**Secrets Check:** ✅ Passed
121134
**Agent Run:** ${{ github.run_id }}
135+
**Preprocessing Run:** ${{ github.event.client_payload.preprocessing_run_id || 'N/A' }}
122136
123137
This PR will be automatically merged.
124138
@@ -156,18 +170,18 @@ jobs:
156170
CHANGED_FILES="${{ steps.changed-files.outputs.files }}"
157171
curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
158172
-H "Content-Type: application/json" \
159-
-d "{\"text\":\"✅ AICODE PR created: <https://github.com/htilly/SlackONOS/pull/${{ steps.cpr.outputs.pull-request-number }}|#${{ steps.cpr.outputs.pull-request-number }}>\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"✅ *AICODE Agent Success*\\n\\n*Task:* ${{ github.event.client_payload.task }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*PR:* <https://github.com/htilly/SlackONOS/pull/${{ steps.cpr.outputs.pull-request-number }}|#${{ steps.cpr.outputs.pull-request-number }}>\\n*Files changed:* ${CHANGED_FILES}\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View workflow run>\"}}]}"
173+
-d "{\"text\":\"✅ AICODE PR created: <https://github.com/htilly/SlackONOS/pull/${{ steps.cpr.outputs.pull-request-number }}|#${{ steps.cpr.outputs.pull-request-number }}>\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"✅ *AICODE Agent Success*\\n\\n*Task:* ${{ github.event.client_payload.task || github.event.client_payload.original_task }}\\n*Original:* ${{ github.event.client_payload.original_task || 'N/A' }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*PR:* <https://github.com/htilly/SlackONOS/pull/${{ steps.cpr.outputs.pull-request-number }}|#${{ steps.cpr.outputs.pull-request-number }}>\\n*Files changed:* ${CHANGED_FILES}\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View workflow run>\"}}]}"
160174
161175
- name: Notify Slack on validation failure
162176
if: steps.agent.outcome == 'success' && steps.secrets-check.outcome != 'success'
163177
run: |
164178
curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
165179
-H "Content-Type: application/json" \
166-
-d "{\"text\":\"🔒 AICODE failed: Security validation failed\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"🔒 *AICODE Security Validation Failed*\\n\\n*Task:* ${{ github.event.client_payload.task }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*Issue:* Potential secrets detected in generated code\\n\\nReview the changes manually before proceeding.\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View GitHub Actions logs>\"}}]}"
180+
-d "{\"text\":\"🔒 AICODE failed: Security validation failed\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"🔒 *AICODE Security Validation Failed*\\n\\n*Task:* ${{ github.event.client_payload.task || github.event.client_payload.original_task }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*Issue:* Potential secrets detected in generated code\\n\\nReview the changes manually before proceeding.\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View GitHub Actions logs>\"}}]}"
167181
168182
- name: Notify Slack on test failure
169183
if: steps.agent.outcome == 'success' && steps.secrets-check.outcome == 'success' && steps.tests.outcome != 'success'
170184
run: |
171185
curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
172186
-H "Content-Type: application/json" \
173-
-d "{\"text\":\"❌ AICODE failed: Tests didn't pass\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"❌ *AICODE Test Failure*\\n\\n*Task:* ${{ github.event.client_payload.task }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*Issue:* Generated code failed tests\\n\\nReview the test output and adjust the changes.\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View GitHub Actions logs>\"}}]}"
187+
-d "{\"text\":\"❌ AICODE failed: Tests didn't pass\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"❌ *AICODE Test Failure*\\n\\n*Task:* ${{ github.event.client_payload.task || github.event.client_payload.original_task }}\\n*Requested by:* ${{ github.event.client_payload.requester }}\\n*Issue:* Generated code failed tests\\n\\nReview the test output and adjust the changes.\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"<https://github.com/htilly/SlackONOS/actions/runs/${{ github.run_id }}|View GitHub Actions logs>\"}}]}"
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: AICODE Preprocess
2+
3+
on:
4+
repository_dispatch:
5+
types: [aicode]
6+
7+
jobs:
8+
preprocess:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
actions: write
13+
14+
steps:
15+
- name: Checkout develop
16+
uses: actions/checkout@v4
17+
with:
18+
ref: develop
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: 20
24+
cache: 'npm'
25+
26+
- name: Install agent dependencies
27+
working-directory: .github/agent
28+
run: npm install
29+
30+
- name: Preprocess task to user story
31+
id: preprocess
32+
env:
33+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
34+
PREPROCESSING_MODEL: ${{ secrets.PREPROCESSING_MODEL || 'gpt-4o-mini' }}
35+
TASK: ${{ github.event.client_payload.task }}
36+
run: |
37+
OUTPUT=$(node .github/agent/preprocess-task.mjs 2>&1)
38+
echo "$OUTPUT"
39+
40+
# Extract enhanced task from output
41+
if echo "$OUTPUT" | grep -q "ENHANCED_TASK_START"; then
42+
ENHANCED_TASK=$(echo "$OUTPUT" | sed -n '/ENHANCED_TASK_START/,/ENHANCED_TASK_END/p' | sed '1d;$d' | sed ':a;N;$!ba;s/\n/ /g')
43+
echo "enhanced_task<<EOF" >> $GITHUB_OUTPUT
44+
echo "$ENHANCED_TASK" >> $GITHUB_OUTPUT
45+
echo "EOF" >> $GITHUB_OUTPUT
46+
else
47+
# Fallback to original task
48+
echo "enhanced_task=${{ github.event.client_payload.task }}" >> $GITHUB_OUTPUT
49+
fi
50+
51+
# Extract JSON if available
52+
JSON_LINE=$(echo "$OUTPUT" | grep "ENHANCED_TASK_JSON:" || true)
53+
if [ -n "$JSON_LINE" ]; then
54+
JSON_DATA=$(echo "$JSON_LINE" | sed 's/ENHANCED_TASK_JSON://')
55+
echo "task_json=$JSON_DATA" >> $GITHUB_OUTPUT
56+
fi
57+
58+
- name: Trigger main agent workflow
59+
if: always()
60+
run: |
61+
ENHANCED_TASK="${{ steps.preprocess.outputs.enhanced_task }}"
62+
ORIGINAL_TASK="${{ github.event.client_payload.task }}"
63+
64+
# Escape JSON special characters in task strings
65+
ENHANCED_TASK_ESCAPED=$(echo "$ENHANCED_TASK" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
66+
ORIGINAL_TASK_ESCAPED=$(echo "$ORIGINAL_TASK" | sed 's/"/\\"/g')
67+
68+
curl -X POST "https://api.github.com/repos/${{ github.repository }}/dispatches" \
69+
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
70+
-H "Accept: application/vnd.github+json" \
71+
-H "Content-Type: application/json" \
72+
-d "{
73+
\"event_type\": \"aicode-enhanced\",
74+
\"client_payload\": {
75+
\"task\": \"$ENHANCED_TASK_ESCAPED\",
76+
\"original_task\": \"$ORIGINAL_TASK_ESCAPED\",
77+
\"requester\": \"${{ github.event.client_payload.requester }}\",
78+
\"channel\": \"${{ github.event.client_payload.channel }}\",
79+
\"timestamp\": \"${{ github.event.client_payload.timestamp }}\",
80+
\"preprocessing_run_id\": \"${{ github.run_id }}\"
81+
}
82+
}"
83+
84+
- name: Notify Slack on preprocessing completion
85+
if: always()
86+
run: |
87+
if [ "${{ steps.preprocess.outcome }}" == "success" ]; then
88+
curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
89+
-H "Content-Type: application/json" \
90+
-d "{\"text\":\"📝 Task preprocessed and enhanced. Triggering code generation...\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"📝 *Task Preprocessing Complete*\\n\\n*Original:* ${{ github.event.client_payload.task }}\\n\\n*Enhanced:* ${{ steps.preprocess.outputs.enhanced_task }}\"}}]}"
91+
else
92+
curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
93+
-H "Content-Type: application/json" \
94+
-d "{\"text\":\"⚠️ Preprocessing failed, using original task\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"⚠️ *Preprocessing Warning*\\n\\nPreprocessing failed, but code generation will continue with original task.\"}}]}"
95+
fi
96+
env:
97+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

0 commit comments

Comments
 (0)