Implement real supervisor-driven auto-recovery
Orchestrator changes:
- Force-spawn GAMMA on iteration_limit before abort
- GAMMA.synthesize() creates emergency handoff payload
- loadRecoveryContext() logs "Resuming from {task_id} handoff"
- POST to /api/pipeline/log for resume message visibility
AgentGamma changes:
- Add synthesize() method for emergency abort synthesis
- Merges existing proposals into coherent handoff
- Stores as synthesis_type: "abort_recovery"
Server changes:
- Add POST /api/pipeline/log endpoint for orchestrator logging
- Recovery pipeline properly inherits GAMMA synthesis
Test coverage:
- test_auto_recovery.py: 6 unit tests
- test_e2e_auto_recovery.py: 5 E2E tests
- test_supervisor_recovery.py: 3 supervisor tests
- Success on attempt 2 (recovery works)
- Max failures (3 retries then FAILED)
- Success on attempt 1 (no recovery needed)
Recovery flow:
1. iteration_limit triggers
2. GAMMA force-spawned for emergency synthesis
3. Handoff dumped with GAMMA synthesis
4. Exit code 3 triggers auto-recovery
5. Recovery pipeline loads handoff
6. Logs "Resuming from {prior_pipeline} handoff"
7. Repeat up to 3 times or until success
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
c96919fe35
commit
ef18567674
@@ -888,6 +888,69 @@ Output JSON: {
|
||||
return { achieved: acceptVotes.length >= 2, reasoning: response };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick synthesis for abort recovery - synthesizes existing proposals into a handoff payload.
|
||||
* Called when iteration_limit is hit to preserve work for the next run.
|
||||
*/
|
||||
async synthesize(task: TaskDefinition): Promise<any> {
|
||||
this.log("ABORT SYNTHESIS: Creating handoff payload from existing proposals...");
|
||||
|
||||
await this.updateState({ status: "WORKING", current_task: "Emergency synthesis for handoff" });
|
||||
|
||||
// Gather all current work
|
||||
const solutions = await this.blackboard.readSection("solutions");
|
||||
const synthesis = await this.blackboard.readSection("synthesis");
|
||||
const problem = await this.blackboard.readSection("problem");
|
||||
|
||||
if (solutions.length === 0) {
|
||||
this.log("No proposals to synthesize");
|
||||
return { synthesized: false, reason: "no_proposals" };
|
||||
}
|
||||
|
||||
this.log(`Synthesizing ${solutions.length} proposals...`);
|
||||
|
||||
try {
|
||||
const response = await this.callLLM(
|
||||
`You are Agent GAMMA performing emergency synthesis before abort. Quickly merge the best ideas from all proposals into a coherent handoff document.
|
||||
Output JSON: {
|
||||
"merged_solution": "comprehensive merged solution incorporating best elements",
|
||||
"key_insights": ["insight1", "insight2", ...],
|
||||
"unresolved_issues": ["issue1", "issue2", ...],
|
||||
"recommended_focus": "what the next run should prioritize",
|
||||
"confidence": 0.0-1.0
|
||||
}`,
|
||||
`Task: ${task.objective}\nProposals: ${JSON.stringify(solutions.map(s => ({ author: s.author, value: s.value })))}\nPrior synthesis attempts: ${JSON.stringify(synthesis.map(s => s.value))}`
|
||||
);
|
||||
|
||||
let result;
|
||||
try {
|
||||
const match = response.match(/\{[\s\S]*\}/);
|
||||
result = match ? JSON.parse(match[0]) : { merged_solution: response, confidence: 0.5 };
|
||||
} catch {
|
||||
result = { merged_solution: response, confidence: 0.5 };
|
||||
}
|
||||
|
||||
// Store the synthesis result for handoff
|
||||
await this.writeToBlackboard("synthesis", "gamma_emergency_synthesis", {
|
||||
...result,
|
||||
synthesis_type: "abort_recovery",
|
||||
timestamp: now(),
|
||||
proposals_merged: solutions.length
|
||||
});
|
||||
|
||||
this.log(`Synthesis complete: ${result.key_insights?.length || 0} insights, confidence ${result.confidence}`);
|
||||
|
||||
await this.updateState({ status: "COMPLETED", progress: 1.0 });
|
||||
|
||||
return { synthesized: true, ...result };
|
||||
|
||||
} catch (e: any) {
|
||||
this.log(`Synthesis failed: ${e.message}`);
|
||||
await this.updateState({ status: "FAILED" });
|
||||
return { synthesized: false, error: e.message };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { BaseAgent };
|
||||
|
||||
Reference in New Issue
Block a user