AltimateAI / AltimateAI/altimate-code

todowrite runaway: 9,139 calls/session escapes per-message doom-loop detector

Aperta
#834 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
bug
Lingua principale
TypeScript
Stelle
811
Fork
134
Merge medio
3g 2h
PR unite (30g)
50

Descrizione

## Problem

Telemetry-2026-05-21 (2,503 machines, 14 days) shows the todowrite loop pattern from March is **still active and worse**:

- 29,562 total todowrite calls in the window
- Top 3 machines = 63% of all calls
- Single machine peak: **9,139 todowrite calls across 28 sessions** (~325/session)

Sessions at this scale burn tokens, induce context bloat, and produce visibly broken UX. The existing doom-loop detector in `session/processor.ts` (`TOOL_REPEAT_THRESHOLD = 30`) is per-assistant-message scope: its counter resets every time a new assistant message starts. The pathological pattern is *slow-burn* — ~10-15 calls per LLM turn, accumulating across many turns within a single session.

## Root cause

`SessionProcessor.create()` instantiates a fresh `toolCallCounts: Record` per message. A new processor is created per assistant message, so the counter never accumulates across the full session. The detector only catches a single turn that spams a tool 30+ times.

Real loops look like this: agent calls todowrite 10x in turn 1, 10x in turn 2, 10x in turn 3... totaling 100 within 10 turns. Each turn is under threshold; the cross-turn pattern is invisible to the per-message counter.

## Fix

Add a tool-level per-session counter inside `TodoWriteTool` itself. New constants:
- `TODOWRITE_WARN_THRESHOLD = 25` — emit warning in tool output + telemetry event; the agent sees the warning text and can self-correct
- `TODOWRITE_REFUSE_THRESHOLD = 50` — refuse the call entirely; return a structured message telling the agent to stop calling todowrite and continue with the work

Both thresholds emit `doom_loop_detected` telemetry events so dashboards see the pattern even when the agent ignores the warning.

Extracted into a testable helper `recordTodoWriteCall(sessionID)` returning `{ action: "ok" | "warn" | "refuse", count }`. Counter is module-scoped in-memory Map; stale entries from old sessions are harmless because lookup is per-sessionID.

## Impact

Telemetry should show:
- `todowrite` call volume per session capped at ~50 (down from 9,000+ peaks)
- `doom_loop_detected` events for `todowrite` at much higher rates (every session that crosses the threshold now reports)
- Reduced token/context burn from runaway todo updates

Guida per i contributori

Apri la guida per i contributori

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.