Skip to content

Commit 1a03452

Browse files
committed
Merge branch 'develop'
2 parents 642a893 + 891f828 commit 1a03452

4 files changed

Lines changed: 147 additions & 16 deletions

File tree

.github/agent/agent.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,7 @@ async function callAI(promptText) {
967967
if (provider === "claude") {
968968
const response = await aiClient.messages.create({
969969
model: aiModel,
970-
max_tokens: 16384, // Increased for larger diffs
970+
max_tokens: 32768, // Increased to 32K for larger diffs
971971
temperature: 0.2,
972972
messages: [{ role: "user", content: promptText }],
973973
});

.github/agent/preprocess-task.mjs

Lines changed: 125 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import OpenAI from "openai";
2+
import fetch from "node-fetch";
23

34
/**
45
* Preprocess Task - Convert one-liner task descriptions to structured user stories
5-
*
6+
*
67
* 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+
* structured user story format using OpenAI, then creates a Confluence page
9+
* with the requirements before triggering the main agent.
810
*/
911

1012
const task = process.env.TASK || "";
1113
const openaiApiKey = process.env.OPENAI_API_KEY;
1214
const model = process.env.PREPROCESSING_MODEL || "gpt-4o-mini";
1315

16+
// Confluence configuration
17+
const confluenceUrl = process.env.CONFLUENCE_URL || "";
18+
const confluenceEmail = process.env.CONFLUENCE_EMAIL || "";
19+
const confluenceApiToken = process.env.CONFLUENCE_API_TOKEN || "";
20+
const confluenceSpaceKey = process.env.CONFLUENCE_SPACE_KEY || "AICODE";
21+
const confluenceParentPageId = process.env.CONFLUENCE_PARENT_PAGE_ID || "";
22+
1423
if (!task) {
1524
console.error("[PREPROCESS] TASK environment variable not set");
1625
process.exit(1);
@@ -33,51 +42,155 @@ Convert the given task description into a structured user story format following
3342
Acceptance Criteria:
3443
- [Criterion 1]
3544
- [Criterion 2]
36-
- [Criterion 3]"
45+
- [Criterion 3]
46+
47+
Technical Notes:
48+
- [Any technical considerations]
49+
- [Files likely to be modified]
50+
- [Potential risks or edge cases]"
3751
3852
Guidelines:
3953
- Identify the user role (administrator, developer, end user, etc.)
4054
- Extract the main action/feature requested
4155
- Clarify the benefit or goal
4256
- Break down the task into specific, testable acceptance criteria
57+
- Add technical notes about implementation details
4358
- Maintain all technical context and requirements
4459
- Keep it concise but comprehensive
4560
- If the task is already well-structured, enhance it rather than completely rewriting
4661
47-
Output ONLY the user story, no explanations or markdown formatting.`;
62+
Output ONLY the user story with technical notes, no explanations or markdown formatting.`;
4863

4964
const userPrompt = `Convert this task description into a structured user story:
5065
5166
${task}`;
5267

68+
/**
69+
* Create a Confluence page with the requirements
70+
* @param {string} title - Page title
71+
* @param {string} content - Page content (user story)
72+
* @returns {Promise<string|null>} Confluence page URL or null if failed
73+
*/
74+
async function createConfluencePage(title, content) {
75+
if (!confluenceUrl || !confluenceEmail || !confluenceApiToken) {
76+
console.log("[PREPROCESS] Confluence credentials not configured, skipping page creation");
77+
return null;
78+
}
79+
80+
try {
81+
console.log(`[PREPROCESS] Creating Confluence page in space ${confluenceSpaceKey}...`);
82+
if (confluenceParentPageId) {
83+
console.log(`[PREPROCESS] Parent page ID: ${confluenceParentPageId}`);
84+
}
85+
86+
// Format content as Confluence storage format (XHTML-based)
87+
const storageContent = `
88+
<h2>Original Task</h2>
89+
<p>${task.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br/>')}</p>
90+
91+
<h2>User Story</h2>
92+
<p>${content.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br/>')}</p>
93+
94+
<h2>Implementation Status</h2>
95+
<p><ac:structured-macro ac:name="status"><ac:parameter ac:name="colour">Yellow</ac:parameter><ac:parameter ac:name="title">In Progress</ac:parameter></ac:structured-macro></p>
96+
97+
<h2>Related Links</h2>
98+
<p>GitHub Run: <a href="https://github.com/htilly/SlackONOS/actions/runs/${process.env.GITHUB_RUN_ID || 'unknown'}">View Workflow</a></p>
99+
`.trim();
100+
101+
const auth = Buffer.from(`${confluenceEmail}:${confluenceApiToken}`).toString('base64');
102+
103+
// Build the page object
104+
const pageData = {
105+
type: 'page',
106+
title: title,
107+
space: { key: confluenceSpaceKey },
108+
body: {
109+
storage: {
110+
value: storageContent,
111+
representation: 'storage'
112+
}
113+
}
114+
};
115+
116+
// Add parent page if specified
117+
if (confluenceParentPageId) {
118+
pageData.ancestors = [{ id: confluenceParentPageId }];
119+
}
120+
121+
const response = await fetch(`${confluenceUrl}/rest/api/content`, {
122+
method: 'POST',
123+
headers: {
124+
'Authorization': `Basic ${auth}`,
125+
'Content-Type': 'application/json',
126+
'Accept': 'application/json'
127+
},
128+
body: JSON.stringify(pageData)
129+
});
130+
131+
if (!response.ok) {
132+
const errorText = await response.text();
133+
console.error(`[PREPROCESS] Failed to create Confluence page: ${response.status} ${response.statusText}`);
134+
console.error(`[PREPROCESS] Error details: ${errorText}`);
135+
return null;
136+
}
137+
138+
const data = await response.json();
139+
const pageUrl = `${confluenceUrl}/wiki${data._links.webui}`;
140+
console.log(`[PREPROCESS] ✅ Confluence page created: ${pageUrl}`);
141+
return pageUrl;
142+
143+
} catch (error) {
144+
console.error(`[PREPROCESS] Error creating Confluence page: ${error.message}`);
145+
return null;
146+
}
147+
}
148+
53149
async function preprocessTask() {
54150
try {
55151
console.log(`[PREPROCESS] Converting task to user story using ${model}...`);
56152
console.log(`[PREPROCESS] Original task: ${task}`);
57-
153+
58154
const response = await openai.chat.completions.create({
59155
model: model,
60156
messages: [
61157
{ role: "system", content: systemPrompt },
62158
{ role: "user", content: userPrompt }
63159
],
64160
temperature: 0.3, // Lower temperature for more consistent output
65-
max_tokens: 500, // User stories should be concise
161+
max_tokens: 800, // Increased for technical notes
66162
});
67-
163+
68164
const enhancedTask = response.choices[0].message.content.trim();
69-
165+
70166
console.log(`[PREPROCESS] Enhanced task (user story):`);
71167
console.log(enhancedTask);
72-
168+
169+
// Create Confluence page with requirements
170+
const timestamp = new Date().toISOString().split('T')[0];
171+
const requester = process.env.REQUESTER || 'unknown';
172+
const pageTitle = `AICODE: ${task.substring(0, 80)} (${timestamp})`;
173+
const confluenceUrl = await createConfluencePage(pageTitle, enhancedTask);
174+
73175
// Output to stdout for workflow to capture
74176
console.log(`\n[PREPROCESS] ENHANCED_TASK_START`);
75177
console.log(enhancedTask);
76178
console.log(`[PREPROCESS] ENHANCED_TASK_END`);
77-
179+
78180
// Also output as JSON for easier parsing
79-
process.stdout.write(`\nENHANCED_TASK_JSON:${JSON.stringify({ original: task, enhanced: enhancedTask })}\n`);
80-
181+
const outputData = {
182+
original: task,
183+
enhanced: enhancedTask,
184+
confluenceUrl: confluenceUrl || 'N/A',
185+
requester: requester,
186+
timestamp: timestamp
187+
};
188+
process.stdout.write(`\nENHANCED_TASK_JSON:${JSON.stringify(outputData)}\n`);
189+
190+
if (confluenceUrl) {
191+
console.log(`\n[PREPROCESS] 📝 Requirements documented: ${confluenceUrl}`);
192+
}
193+
81194
} catch (error) {
82195
console.error(`[PREPROCESS] Error during preprocessing: ${error.message}`);
83196
console.warn(`[PREPROCESS] Falling back to original task`);

.github/workflows/aicode-agent.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jobs:
3939
echo "Original task: ${{ github.event.client_payload.original_task || github.event.client_payload.task }}"
4040
echo "Enhanced task: ${{ github.event.client_payload.task }}"
4141
echo "Preprocessing run: ${{ github.event.client_payload.preprocessing_run_id || 'N/A' }}"
42+
echo "Confluence page: ${{ github.event.client_payload.confluence_url || 'N/A' }}"
4243
4344
- name: Run AI Agent
4445
id: agent
@@ -128,6 +129,7 @@ jobs:
128129
129130
**Task:** ${{ github.event.client_payload.task || github.event.client_payload.original_task }}
130131
**Original Task:** ${{ github.event.client_payload.original_task || 'N/A' }}
132+
**Requirements:** ${{ github.event.client_payload.confluence_url != 'N/A' && github.event.client_payload.confluence_url || 'Not documented' }}
131133
**Tests:** ✅ Passed
132134
**Validation:** ✅ Passed
133135
**Secrets Check:** ✅ Passed

.github/workflows/aicode-preprocess.yml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,17 @@ jobs:
3333
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
3434
PREPROCESSING_MODEL: ${{ secrets.PREPROCESSING_MODEL || 'gpt-4o-mini' }}
3535
TASK: ${{ github.event.client_payload.task }}
36+
REQUESTER: ${{ github.event.client_payload.requester }}
37+
CONFLUENCE_URL: ${{ secrets.CONFLUENCE_URL }}
38+
CONFLUENCE_EMAIL: ${{ secrets.CONFLUENCE_EMAIL }}
39+
CONFLUENCE_API_TOKEN: ${{ secrets.CONFLUENCE_API_TOKEN }}
40+
CONFLUENCE_SPACE_KEY: ${{ secrets.CONFLUENCE_SPACE_KEY || 'AICODE' }}
41+
CONFLUENCE_PARENT_PAGE_ID: ${{ secrets.CONFLUENCE_PARENT_PAGE_ID || '5177529' }}
42+
GITHUB_RUN_ID: ${{ github.run_id }}
3643
run: |
3744
OUTPUT=$(node .github/agent/preprocess-task.mjs 2>&1)
3845
echo "$OUTPUT"
39-
46+
4047
# Extract enhanced task from output
4148
if echo "$OUTPUT" | grep -q "ENHANCED_TASK_START"; then
4249
ENHANCED_TASK=$(echo "$OUTPUT" | sed -n '/ENHANCED_TASK_START/,/ENHANCED_TASK_END/p' | sed '1d;$d' | sed ':a;N;$!ba;s/\n/ /g')
@@ -47,12 +54,18 @@ jobs:
4754
# Fallback to original task
4855
echo "enhanced_task=${{ github.event.client_payload.task }}" >> $GITHUB_OUTPUT
4956
fi
50-
57+
5158
# Extract JSON if available
5259
JSON_LINE=$(echo "$OUTPUT" | grep "ENHANCED_TASK_JSON:" || true)
5360
if [ -n "$JSON_LINE" ]; then
5461
JSON_DATA=$(echo "$JSON_LINE" | sed 's/ENHANCED_TASK_JSON://')
5562
echo "task_json=$JSON_DATA" >> $GITHUB_OUTPUT
63+
64+
# Extract Confluence URL
65+
CONFLUENCE_URL=$(echo "$JSON_DATA" | jq -r '.confluenceUrl // "N/A"')
66+
echo "confluence_url=$CONFLUENCE_URL" >> $GITHUB_OUTPUT
67+
else
68+
echo "confluence_url=N/A" >> $GITHUB_OUTPUT
5669
fi
5770
5871
- name: Trigger main agent workflow
@@ -64,6 +77,7 @@ jobs:
6477
CHANNEL="${{ github.event.client_payload.channel }}"
6578
TIMESTAMP="${{ github.event.client_payload.timestamp }}"
6679
RUN_ID="${{ github.run_id }}"
80+
CONFLUENCE_URL="${{ steps.preprocess.outputs.confluence_url }}"
6781
6882
# Use jq to properly construct JSON payload with proper escaping
6983
PAYLOAD=$(jq -n \
@@ -74,6 +88,7 @@ jobs:
7488
--arg channel "$CHANNEL" \
7589
--arg timestamp "$TIMESTAMP" \
7690
--arg preprocessing_run_id "$RUN_ID" \
91+
--arg confluence_url "$CONFLUENCE_URL" \
7792
'{
7893
event_type: $event_type,
7994
client_payload: {
@@ -82,7 +97,8 @@ jobs:
8297
requester: $requester,
8398
channel: $channel,
8499
timestamp: $timestamp,
85-
preprocessing_run_id: $preprocessing_run_id
100+
preprocessing_run_id: $preprocessing_run_id,
101+
confluence_url: $confluence_url
86102
}
87103
}')
88104

0 commit comments

Comments
 (0)