Skip to content

Commit 0c153a6

Browse files
feat: Enhance Aider process monitoring and auto-response handling
- Implemented comprehensive progress callback system for Aider process - Added intelligent auto-response handling for various Aider prompts - Introduced advanced health check and activity monitoring mechanisms - Implemented robust timeout and process termination strategies - Enhanced logging and real-time status tracking for Aider operations - Refined error handling and progress reporting across different execution stages
1 parent b9016ba commit 0c153a6

File tree

3 files changed

+687
-67
lines changed

3 files changed

+687
-67
lines changed

.env.example

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@ PATCH_MODEL_HYBRID_TYPESCRIPT=gpt-4o
8282
PATCH_DEFAULT_MODE=patcher
8383

8484
# Additional arguments to pass to the AI engine (comma-separated)
85-
# IMPORTANT: When using Claude models, you MUST include --use-anthropic here
86-
# PATCH_EXTRA_ARGS=--use-anthropic
85+
# For Claude models, older versions required --use-anthropic but newer versions use --sonnet, --opus, etc. flags
86+
# The appropriate flag will be added automatically based on the model name
87+
PATCH_EXTRA_ARGS=
8788

8889
# Mode-specific extra arguments (comma-separated, optional)
89-
# PATCH_EXTRA_ARGS_ARCHITECT=--use-anthropic,--extra-arg
90+
# PATCH_EXTRA_ARGS_ARCHITECT=--extra-arg
9091
# PATCH_EXTRA_ARGS_PATCHER=--timeout=300
91-
# PATCH_EXTRA_ARGS_HYBRID_SECURITY=--use-anthropic,--security-focus
92+
# PATCH_EXTRA_ARGS_HYBRID_SECURITY=--security-focus
9293

9394
# Multi-pass processing configuration
9495
PATCH_ENABLE_MULTIPASS=true

src/multi-pass-processor.ts

Lines changed: 131 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ export class MultiPassProcessor {
122122
issueTitle,
123123
issueBody,
124124
branchName,
125-
authToken
125+
authToken,
126+
undefined, // baseBranch
127+
this.createProgressCallbackHandler(mode) // Add progress callback
126128
);
127129

128130
return {
@@ -183,7 +185,9 @@ export class MultiPassProcessor {
183185
issueTitle,
184186
issueBody,
185187
primaryBranchName,
186-
authToken
188+
authToken,
189+
undefined, // baseBranch
190+
this.createProgressCallbackHandler(primaryMode) // Add progress callback
187191
);
188192

189193
if (!primaryResult.success) {
@@ -232,7 +236,8 @@ export class MultiPassProcessor {
232236
`${issueBody}\n\n---\n\n${contextMessage}`,
233237
finalBranchName,
234238
authToken,
235-
primaryBranchName
239+
primaryBranchName,
240+
this.createProgressCallbackHandler(secondaryMode) // Add progress callback
236241
);
237242

238243
// Combine the changes from both passes
@@ -265,4 +270,127 @@ export class MultiPassProcessor {
265270
};
266271
}
267272
}
273+
274+
/**
275+
* Creates a progress callback handler function for streaming Aider output to console
276+
*/
277+
private createProgressCallbackHandler(mode: string): (status: string, data?: any) => void {
278+
let lastActivityTimestamp = Date.now();
279+
let stuckWarningIssued = false;
280+
281+
return (status: string, data?: any) => {
282+
switch (status) {
283+
case 'starting':
284+
console.log(`🚀 [${mode}] Starting Aider process: ${data?.title || ''}`);
285+
break;
286+
287+
case 'cloning':
288+
console.log(`📥 [${mode}] Cloning repository: ${data?.repo || ''}`);
289+
break;
290+
291+
case 'checkout':
292+
console.log(`🔀 [${mode}] Checking out branch: ${data?.branch || ''}`);
293+
break;
294+
295+
case 'branch':
296+
console.log(`🌿 [${mode}] Creating branch: ${data?.name || ''}`);
297+
break;
298+
299+
case 'aider_start':
300+
console.log(`⚙️ [${mode}] Starting Aider with model: ${data?.model || ''}`);
301+
console.log(` Mode: ${data?.mode || 'unknown'}`);
302+
lastActivityTimestamp = Date.now();
303+
break;
304+
305+
case 'output':
306+
// Only log non-empty output that's not too long for readability
307+
if (data?.text && data.text.trim() && data.text.length < 500) {
308+
// Remove redundant newlines for cleaner logs
309+
const cleanedText = data.text.replace(/\n{3,}/g, '\n\n').trim();
310+
console.log(`🔄 [${mode}] ${cleanedText}`);
311+
}
312+
lastActivityTimestamp = Date.now();
313+
stuckWarningIssued = false;
314+
break;
315+
316+
case 'url_detected':
317+
console.log(`🔗 [${mode}] URLs detected in Aider output:`);
318+
if (data?.urls && Array.isArray(data.urls)) {
319+
data.urls.forEach((url: string) => console.log(` ${url}`));
320+
}
321+
lastActivityTimestamp = Date.now();
322+
break;
323+
324+
case 'auto_response':
325+
console.log(`🤖 [${mode}] Auto-responded "${data?.response}" to Aider's "${data?.prompt}" prompt`);
326+
lastActivityTimestamp = Date.now();
327+
break;
328+
329+
case 'health_check':
330+
console.log(`💓 [${mode}] Health check sent to Aider (inactive for ${data?.inactive_seconds || 0}s, check #${data?.consecutive_checks || 1})`);
331+
break;
332+
333+
case 'forced_termination':
334+
console.error(`⚠️ [${mode}] Forcefully terminating Aider process: ${data?.reason || 'unknown reason'}`);
335+
console.error(` Inactive for ${data?.inactive_seconds || 0} seconds`);
336+
break;
337+
338+
case 'max_time_reached':
339+
console.error(`⏰ [${mode}] Maximum time limit of ${data?.minutes || 30} minutes reached. Force terminating Aider.`);
340+
break;
341+
342+
case 'error':
343+
console.error(`❌ [${mode}] Error: ${data?.text || data?.message || 'Unknown error'}`);
344+
lastActivityTimestamp = Date.now();
345+
break;
346+
347+
case 'status':
348+
if (data?.status === 'working') {
349+
const inactiveSeconds = data?.inactive_seconds || 0;
350+
// Check if Aider might be stuck
351+
if (inactiveSeconds > 120 && !stuckWarningIssued) { // 2 minutes of inactivity
352+
console.warn(`⚠️ [${mode}] Warning: Aider has been inactive for ${inactiveSeconds} seconds, it may be stuck`);
353+
console.warn(` Last output: ${data?.last_output || 'none'}`);
354+
stuckWarningIssued = true;
355+
}
356+
} else {
357+
console.log(`ℹ️ [${mode}] Status: ${data?.status || 'unknown'}`);
358+
lastActivityTimestamp = Date.now();
359+
stuckWarningIssued = false;
360+
}
361+
break;
362+
363+
case 'timeout':
364+
console.warn(`⏰ [${mode}] Timeout reached after ${data?.seconds || 'unknown'} seconds`);
365+
break;
366+
367+
case 'aider_complete':
368+
console.log(`✅ [${mode}] Aider completed with exit code: ${data?.exitCode}`);
369+
break;
370+
371+
case 'no_changes':
372+
console.log(`ℹ️ [${mode}] No changes were made by Aider`);
373+
break;
374+
375+
case 'committing':
376+
console.log(`📝 [${mode}] Committing changes`);
377+
break;
378+
379+
case 'pushing':
380+
console.log(`📤 [${mode}] Pushing changes to remote`);
381+
break;
382+
383+
case 'complete':
384+
console.log(`🎉 [${mode}] Processing complete with ${data?.files?.length || 0} changed files`);
385+
if (data?.files?.length > 0) {
386+
console.log(` Changed files: ${data.files.join(', ')}`);
387+
}
388+
break;
389+
390+
default:
391+
// For any other events, just log them with data
392+
console.log(`[${mode}] ${status}: ${JSON.stringify(data || {})}`);
393+
}
394+
};
395+
}
268396
}

0 commit comments

Comments
 (0)