Module: 7 · Duration: 40 min · Environment: Codespace, Node 18+.
const turnLog: {input_hash: string, output_hash: string, tool: string}[] = [];
const disabledTools = new Set<string>();
function checkStuck(tool: string, inputHash: string, outputHash: string, threshold = 3): boolean {
turnLog.push({input_hash: inputHash, output_hash: outputHash, tool});
const recent = turnLog.slice(-threshold);
if (recent.length < threshold) return false;
const allSame = recent.every(t => t.input_hash === inputHash && t.output_hash === outputHash && t.tool === tool);
if (allSame) { disabledTools.add(tool); return true; }
return false;
}
function dispatch(toolCall) {
if (disabledTools.has(toolCall.name)) return {ok: false, error: `${toolCall.name} disabled for session (circuit breaker)`};
// ... execute, get result + hashes, checkStuck ...
}
Verify: call a failing tool 3x with same input → on the 3rd, circuit breaker trips; 4th call returns "disabled."
Simulate exhausting the budget at "step 15 of 30." The harness should: save a checkpoint (Module 8 style), write a handoff (Module 4 style: "completed 15 of 30; budget exhausted; resume at step 16"), and exit cleanly — NOT crash.
# Lab Specification — Module 7: Error Handling & Recovery
**Module**: 7 · **Duration**: 40 min · **Environment**: Codespace, Node 18+.
## Learning objectives
1. Implement a **stuck-loop detector** as harness middleware.
2. Add a **circuit breaker** that disables a failing tool.
3. Simulate **budget exhaustion** and verify graceful degradation (checkpoint + handoff).
## Phase 1 — Stuck-loop detector + circuit breaker (20 min)
```typescript
const turnLog: {input_hash: string, output_hash: string, tool: string}[] = [];
const disabledTools = new Set<string>();
function checkStuck(tool: string, inputHash: string, outputHash: string, threshold = 3): boolean {
turnLog.push({input_hash: inputHash, output_hash: outputHash, tool});
const recent = turnLog.slice(-threshold);
if (recent.length < threshold) return false;
const allSame = recent.every(t => t.input_hash === inputHash && t.output_hash === outputHash && t.tool === tool);
if (allSame) { disabledTools.add(tool); return true; }
return false;
}
function dispatch(toolCall) {
if (disabledTools.has(toolCall.name)) return {ok: false, error: `${toolCall.name} disabled for session (circuit breaker)`};
// ... execute, get result + hashes, checkStuck ...
}
```
**Verify**: call a failing tool 3x with same input → on the 3rd, circuit breaker trips; 4th call returns "disabled."
## Phase 2 — Budget exhaustion graceful degradation (15 min)
Simulate exhausting the budget at "step 15 of 30." The harness should: save a checkpoint (Module 8 style), write a handoff (Module 4 style: "completed 15 of 30; budget exhausted; resume at step 16"), and exit cleanly — NOT crash.
## Deliverables
- [ ] Phase 1: detector + breaker code; 4th-call-disabled confirmation
- [ ] Phase 2: checkpoint + handoff written on budget exhaustion; clean exit
## Stretch goals
1. Add the 4-category taxonomy classifier: given an error, classify it and apply the correct response (retry / self-correct / interrupt / halt).
2. Test the taxonomy: feed a 503 (transient → retry), a wrong-path (LLM-recoverable → self-correct), a missing-cred (user-fixable → interrupt), a sandbox-crash (fatal → halt). Verify each gets the right response.