Skip to content

Commit ff6f0f9

Browse files
committed
feat(agent): implement label-triggered analysis workflow for GitHub issues
1 parent 0dbcaaa commit ff6f0f9

3 files changed

Lines changed: 613 additions & 3 deletions

File tree

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
name: AI Agent - Label Triggered Analysis
2+
3+
on:
4+
issues:
5+
types: [labeled]
6+
7+
jobs:
8+
label-triggered-analysis:
9+
runs-on: ubuntu-latest
10+
if: github.event_name == 'issues' && github.event.action == 'labeled'
11+
12+
steps:
13+
- name: Checkout repository
14+
uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0
17+
18+
- name: Install Ripgrep
19+
run: sudo apt-get update && sudo apt-get install -y ripgrep
20+
21+
- name: Setup Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: '20'
25+
26+
- name: Install pnpm
27+
uses: pnpm/action-setup@v4
28+
with:
29+
version: 8
30+
31+
- name: Install workspace dependencies
32+
run: pnpm install
33+
34+
- name: Build packages in correct order
35+
run: |
36+
pnpm --filter worker-core build
37+
pnpm --filter worker-protobuf build
38+
pnpm --filter context-worker build
39+
pnpm --filter github-agent build
40+
41+
- name: Label-Specific AI Analysis
42+
timeout-minutes: 10
43+
run: |
44+
cd packages/github-agent
45+
46+
LABEL_NAME="${{ github.event.label.name }}"
47+
ISSUE_NUMBER="${{ github.event.issue.number }}"
48+
REPOSITORY="${{ github.repository }}"
49+
50+
echo "🏷️ Label '$LABEL_NAME' added to issue #$ISSUE_NUMBER"
51+
echo "🎯 Repository: $REPOSITORY"
52+
echo "📋 Issue Title: ${{ github.event.issue.title }}"
53+
echo ""
54+
55+
# Set timeout and error handling
56+
set -e
57+
trap 'echo "❌ Label analysis interrupted or timed out"; exit 1' INT TERM
58+
59+
# The agent.js will automatically detect the labeled event and generate appropriate analysis
60+
timeout 480s node bin/agent.js --auto-upload --verbose --workspace "${{ github.workspace }}" \
61+
--command "Smart analysis triggered by label" || {
62+
echo "⚠️ Label-triggered analysis timed out or failed, but continuing..."
63+
exit 0
64+
}
65+
66+
echo "✅ Label-triggered analysis completed successfully"
67+
env:
68+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
70+
DEEPSEEK_TOKEN: ${{ secrets.DEEPSEEK_TOKEN }}
71+
GLM_TOKEN: ${{ secrets.GLM_TOKEN }}
72+
NODE_OPTIONS: "--max-old-space-size=4096"
73+
# GitHub Actions context variables
74+
GITHUB_ACTIONS: true
75+
GITHUB_REPOSITORY: ${{ github.repository }}
76+
GITHUB_EVENT_NAME: ${{ github.event_name }}
77+
GITHUB_EVENT_PATH: ${{ github.event_path }}
78+
79+
# Special handling for critical labels
80+
critical-label-analysis:
81+
runs-on: ubuntu-latest
82+
if: |
83+
github.event_name == 'issues' &&
84+
github.event.action == 'labeled' &&
85+
(github.event.label.name == 'critical' ||
86+
github.event.label.name == 'security' ||
87+
github.event.label.name == 'breaking-change')
88+
89+
steps:
90+
- name: Checkout repository
91+
uses: actions/checkout@v4
92+
with:
93+
fetch-depth: 0
94+
95+
- name: Setup Node.js
96+
uses: actions/setup-node@v4
97+
with:
98+
node-version: '20'
99+
100+
- name: Install pnpm
101+
uses: pnpm/action-setup@v4
102+
with:
103+
version: 8
104+
105+
- name: Install workspace dependencies
106+
run: pnpm install
107+
108+
- name: Build packages
109+
run: |
110+
pnpm --filter worker-core build
111+
pnpm --filter worker-protobuf build
112+
pnpm --filter context-worker build
113+
pnpm --filter github-agent build
114+
115+
- name: Critical Issue Deep Analysis
116+
timeout-minutes: 15
117+
run: |
118+
cd packages/github-agent
119+
120+
LABEL_NAME="${{ github.event.label.name }}"
121+
ISSUE_NUMBER="${{ github.event.issue.number }}"
122+
123+
echo "🚨 CRITICAL: Issue #$ISSUE_NUMBER labeled with '$LABEL_NAME'"
124+
echo "🔍 Performing deep analysis for critical issue..."
125+
126+
# Extended timeout for critical issues
127+
timeout 720s node bin/agent.js --auto-upload --verbose --workspace "${{ github.workspace }}" \
128+
--command "CRITICAL ANALYSIS: Issue #$ISSUE_NUMBER has been marked as $LABEL_NAME. Perform comprehensive deep analysis with maximum detail and urgency." || {
129+
echo "⚠️ Critical analysis timed out or failed"
130+
exit 1
131+
}
132+
env:
133+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
134+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
135+
DEEPSEEK_TOKEN: ${{ secrets.DEEPSEEK_TOKEN }}
136+
GLM_TOKEN: ${{ secrets.GLM_TOKEN }}
137+
NODE_OPTIONS: "--max-old-space-size=6144"
138+
GITHUB_ACTIONS: true
139+
GITHUB_REPOSITORY: ${{ github.repository }}
140+
GITHUB_EVENT_NAME: ${{ github.event_name }}
141+
GITHUB_EVENT_PATH: ${{ github.event_path }}
142+
143+
- name: Notify Team for Critical Issues
144+
if: success()
145+
uses: actions/github-script@v7
146+
with:
147+
script: |
148+
const labelName = '${{ github.event.label.name }}';
149+
const issueNumber = ${{ github.event.issue.number }};
150+
151+
let notificationMessage = '';
152+
if (labelName === 'critical') {
153+
notificationMessage = '🚨 **CRITICAL ISSUE ALERT** - This issue requires immediate attention from the development team.';
154+
} else if (labelName === 'security') {
155+
notificationMessage = '🔒 **SECURITY ALERT** - This issue has security implications and needs urgent review.';
156+
} else if (labelName === 'breaking-change') {
157+
notificationMessage = '💥 **BREAKING CHANGE ALERT** - This issue involves breaking changes that need careful coordination.';
158+
}
159+
160+
if (notificationMessage) {
161+
await github.rest.issues.createComment({
162+
issue_number: issueNumber,
163+
owner: context.repo.owner,
164+
repo: context.repo.repo,
165+
body: `${notificationMessage}\n\nAI analysis has been triggered and will be posted shortly.`
166+
});
167+
}
168+
169+
# Special handling for newcomer-friendly labels
170+
newcomer-friendly-analysis:
171+
runs-on: ubuntu-latest
172+
if: |
173+
github.event_name == 'issues' &&
174+
github.event.action == 'labeled' &&
175+
(github.event.label.name == 'good-first-issue' ||
176+
github.event.label.name == 'help-wanted' ||
177+
github.event.label.name == 'beginner-friendly')
178+
179+
steps:
180+
- name: Checkout repository
181+
uses: actions/checkout@v4
182+
183+
- name: Setup Node.js
184+
uses: actions/setup-node@v4
185+
with:
186+
node-version: '20'
187+
188+
- name: Install pnpm
189+
uses: pnpm/action-setup@v4
190+
with:
191+
version: 8
192+
193+
- name: Install workspace dependencies
194+
run: pnpm install
195+
196+
- name: Build packages
197+
run: |
198+
pnpm --filter worker-core build
199+
pnpm --filter worker-protobuf build
200+
pnpm --filter context-worker build
201+
pnpm --filter github-agent build
202+
203+
- name: Newcomer-Friendly Analysis
204+
run: |
205+
cd packages/github-agent
206+
207+
echo "👋 Generating newcomer-friendly analysis for issue #${{ github.event.issue.number }}"
208+
209+
# The smart command generation will handle newcomer-specific analysis
210+
node bin/agent.js --auto-upload --verbose --workspace "${{ github.workspace }}" \
211+
--command "Newcomer guidance analysis"
212+
env:
213+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
214+
DEEPSEEK_TOKEN: ${{ secrets.DEEPSEEK_TOKEN }}
215+
GITHUB_ACTIONS: true
216+
GITHUB_REPOSITORY: ${{ github.repository }}
217+
GITHUB_EVENT_NAME: ${{ github.event_name }}
218+
GITHUB_EVENT_PATH: ${{ github.event_path }}
219+
220+
- name: Add Newcomer Welcome Comment
221+
uses: actions/github-script@v7
222+
with:
223+
script: |
224+
await github.rest.issues.createComment({
225+
issue_number: ${{ github.event.issue.number }},
226+
owner: context.repo.owner,
227+
repo: context.repo.repo,
228+
body: `👋 **Welcome Contributors!**
229+
230+
This issue has been marked as beginner-friendly. Our AI agent is analyzing the issue and will provide detailed guidance shortly.
231+
232+
**For new contributors:**
233+
- 📚 Check our [Contributing Guide](../blob/master/CONTRIBUTING.md) if available
234+
- 💬 Feel free to ask questions in the comments
235+
- 🤝 Don't hesitate to request help or clarification
236+
237+
The AI analysis will include step-by-step guidance and learning resources to help you get started!`
238+
});

packages/github-agent/bin/agent.js

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,65 @@ async function main() {
6161
}
6262
}
6363

64+
/**
65+
* Generate label-specific analysis command
66+
*/
67+
function generateLabelSpecificCommand(githubContext) {
68+
if (githubContext?.eventContext?.type !== 'labeled') {
69+
return null;
70+
}
71+
72+
const { owner, repo, issueNumber, eventContext } = githubContext;
73+
const { labelName, allLabels } = eventContext;
74+
const repository = `${owner}/${repo}`;
75+
const basePrompt = `Issue #${issueNumber} in ${repository}`;
76+
77+
// Define label-specific analysis strategies
78+
const labelStrategies = {
79+
// Technical analysis labels
80+
'bug': `${basePrompt} has been labeled as a bug. Perform comprehensive bug analysis: 1) Examine related code to identify the root cause, 2) Trace the bug's impact across the system, 3) Provide step-by-step debugging guidance, 4) Suggest specific code fixes with examples, 5) Recommend testing strategies to prevent regression.`,
81+
82+
'enhancement': `${basePrompt} has been labeled as an enhancement. Analyze this feature request: 1) Evaluate technical feasibility and complexity, 2) Identify affected components and dependencies, 3) Suggest implementation approach with code examples, 4) Estimate development effort and potential risks, 5) Recommend testing and rollout strategies.`,
83+
84+
'performance': `${basePrompt} has been labeled as a performance issue. Conduct performance analysis: 1) Identify performance bottlenecks in related code, 2) Analyze algorithmic complexity and resource usage, 3) Suggest optimization strategies with code examples, 4) Provide benchmarking recommendations, 5) Consider scalability implications.`,
85+
86+
'security': `${basePrompt} has been labeled as a security issue. Perform security audit: 1) Identify potential vulnerabilities in related code, 2) Analyze security implications and attack vectors, 3) Suggest security best practices and fixes, 4) Provide remediation steps with priority levels, 5) Recommend security testing approaches.`,
87+
88+
'refactor': `${basePrompt} has been labeled for refactoring. Analyze refactoring needs: 1) Identify code smells and technical debt, 2) Suggest refactoring strategies and patterns, 3) Provide step-by-step refactoring plan, 4) Estimate impact on existing functionality, 5) Recommend testing strategies during refactoring.`,
89+
90+
// Workflow and priority labels
91+
'critical': `${basePrompt} is marked as critical. Provide urgent analysis: 1) Assess immediate impact and business risks, 2) Identify quick mitigation strategies, 3) Provide emergency fix suggestions with code examples, 4) Outline long-term solution approach, 5) Recommend monitoring and alerting improvements.`,
92+
93+
'needs-analysis': `${basePrompt} needs detailed analysis. Provide comprehensive technical analysis: 1) Deep dive into the issue context and requirements, 2) Examine all related code components and dependencies, 3) Provide detailed technical insights and trade-offs, 4) Suggest multiple solution approaches with pros/cons, 5) Recommend implementation roadmap.`,
94+
95+
'help-wanted': `${basePrompt} is seeking community help. Create newcomer-friendly analysis: 1) Explain the issue in simple, accessible terms, 2) Identify good starting points for new contributors, 3) Provide learning resources and documentation links, 4) Suggest incremental contribution steps, 5) Highlight mentoring opportunities.`,
96+
97+
'good-first-issue': `${basePrompt} is marked as good for first-time contributors. Create beginner-friendly guidance: 1) Explain the issue simply with clear context, 2) Provide step-by-step implementation hints, 3) Suggest relevant learning resources and tutorials, 4) Identify potential mentoring points and code review focus areas, 5) Recommend testing approaches for beginners.`,
98+
99+
// Domain-specific labels
100+
'frontend': `${basePrompt} has been labeled as frontend-related. Provide frontend-focused analysis: 1) Examine UI/UX implications and user experience, 2) Analyze frontend code architecture and patterns, 3) Suggest modern frontend best practices, 4) Consider accessibility and performance implications, 5) Recommend testing strategies for frontend changes.`,
101+
102+
'backend': `${basePrompt} has been labeled as backend-related. Provide backend-focused analysis: 1) Analyze server-side architecture and data flow, 2) Examine API design and database implications, 3) Consider scalability and performance factors, 4) Suggest backend best practices and patterns, 5) Recommend monitoring and logging strategies.`,
103+
104+
'api': `${basePrompt} has been labeled as API-related. Provide API-focused analysis: 1) Analyze API design and RESTful principles, 2) Examine request/response patterns and data structures, 3) Consider versioning and backward compatibility, 4) Suggest API documentation improvements, 5) Recommend testing and validation strategies.`,
105+
106+
'database': `${basePrompt} has been labeled as database-related. Provide database-focused analysis: 1) Analyze database schema and query patterns, 2) Examine data relationships and constraints, 3) Consider performance and indexing strategies, 4) Suggest migration and backup considerations, 5) Recommend monitoring and optimization approaches.`
107+
};
108+
109+
// Check for label combinations that might need special handling
110+
const hasMultipleImportantLabels = allLabels.filter(label =>
111+
['critical', 'security', 'performance', 'breaking-change'].includes(label)
112+
).length > 1;
113+
114+
if (hasMultipleImportantLabels) {
115+
return `${basePrompt} has been labeled with "${labelName}" and has multiple high-priority labels: [${allLabels.join(', ')}]. Provide comprehensive analysis considering all these aspects: 1) Analyze the issue from multiple perspectives based on all labels, 2) Identify potential conflicts or synergies between different concerns, 3) Prioritize recommendations based on label importance, 4) Suggest coordinated approach addressing all labeled concerns, 5) Provide implementation roadmap considering all constraints.`;
116+
}
117+
118+
// Return label-specific strategy or default
119+
return labelStrategies[labelName] ||
120+
`${basePrompt} has been labeled with "${labelName}". Analyze this issue in the context of this label: 1) Explain why this label is relevant to the issue, 2) Provide insights specific to this label's domain, 3) Suggest appropriate next steps and solutions, 4) Consider related issues or patterns, 5) Recommend best practices for this type of issue.`;
121+
}
122+
64123
/**
65124
* Extract GitHub context from environment variables (GitHub Actions)
66125
*/
@@ -100,10 +159,38 @@ function extractGitHubContextFromEnv() {
100159

101160
// Extract issue number for issue events
102161
let issueNumber = null;
162+
let eventContext = null;
103163
if (eventName === 'issues' && eventData.issue) {
104164
issueNumber = eventData.issue.number;
165+
166+
// Add context based on the specific action
167+
switch (eventData.action) {
168+
case 'labeled':
169+
eventContext = {
170+
type: 'labeled',
171+
labelName: eventData.label?.name,
172+
labelColor: eventData.label?.color,
173+
allLabels: eventData.issue.labels?.map(l => l.name) || []
174+
};
175+
break;
176+
case 'assigned':
177+
eventContext = {
178+
type: 'assigned',
179+
assignee: eventData.assignee?.login,
180+
allAssignees: eventData.issue.assignees?.map(a => a.login) || []
181+
};
182+
break;
183+
default:
184+
eventContext = {
185+
type: eventData.action || 'unknown'
186+
};
187+
}
105188
} else if (eventName === 'issue_comment' && eventData.issue) {
106189
issueNumber = eventData.issue.number;
190+
eventContext = {
191+
type: 'comment',
192+
commentAuthor: eventData.comment?.user?.login
193+
};
107194
}
108195

109196
if (issueNumber) {
@@ -112,7 +199,8 @@ function extractGitHubContextFromEnv() {
112199
repo,
113200
issueNumber,
114201
eventType: eventName,
115-
action: eventData.action
202+
action: eventData.action,
203+
eventContext
116204
};
117205

118206
console.log('📋 GitHub context detected:', context);
@@ -191,10 +279,23 @@ function parseArgs(args) {
191279
* Process a single command and exit
192280
*/
193281
async function processSingleCommand(agent, command, config) {
194-
console.log(`🎯 Processing command: ${command}\n`);
282+
// Check if we have GitHub context and should generate a smart command
283+
const githubContext = extractGitHubContextFromEnv();
284+
let finalCommand = command;
285+
286+
// Generate label-specific command if this is a labeled event
287+
if (githubContext?.eventContext?.type === 'labeled') {
288+
const smartCommand = generateLabelSpecificCommand(githubContext);
289+
if (smartCommand) {
290+
finalCommand = smartCommand;
291+
console.log(`🏷️ Generated label-specific command for "${githubContext.eventContext.labelName}" label`);
292+
}
293+
}
294+
295+
console.log(`🎯 Processing command: ${finalCommand}\n`);
195296

196297
try {
197-
const response = await agent.processInput(command);
298+
const response = await agent.processInput(finalCommand);
198299
const githubToken = process.env.GITHUB_TOKEN;
199300
console.log(`try uploading response to GitHub with autoUpload: ${config.autoUpload}, githubContext: ${response.githubContext}, githubToken: ${githubToken ? githubToken.substring(0, 4) + '...' : 'undefined'}`);
200301

0 commit comments

Comments
 (0)