Replies: 2 comments 1 reply
|
This failure mode bit us too. Our incident write-up: a stalled model in a loop burned through budget before detection caught up — detection lagged ~90 seconds, which was the real gap. Two mitigations that stuck: a hard step budget inside the loop, and per-request cost telemetry so anomalous burn shows up in logs rather than on the invoice. Full notes, including what we'd do differently: https://github.com/NovaRouteAI/failover-field-notes |
|
Verified against the current checkout (master @ 1. The unbounded loop is confirmed at source.
2. The cost claim checks out, and the telemetry foundation already exists. 3. Fix design fits two existing patterns almost exactly.
4. Two subtleties that make "just set a counter and break" insufficient:
5. On the #2107 distinction — agreed, they're orthogonal: compaction governs context length across turns; a step budget governs model-call count within one turn. A capped turn still spins fine with broken compaction, and working compaction doesn't stop a model that keeps calling tools. The two fixes compose; they don't substitute. The suggested |
Uh oh!
There was an error while loading. Please reload this page.
packages/core/agent-loop/src/agent.ts'sReactLoopAgent.turn()runs an unboundedwhile (true)step loop. There is nomaxSteps/step-budget/timeout circuit breaker anywhere in the codebase (confirmed viagrep -rn "maxSteps\|max_steps\|maxIterations\|stepLimit"acrosspackages/andapps/— zero matches). The only exits are:max-tokens, orconcludesTurn: true.If the model keeps calling tools indefinitely, nothing in the harness intervenes.
Repro
A single exploratory Q&A turn ("how do I delete an archived branch conversation in the Web GUI?") ran 27 steps over ~103s before I manually interrupted it with a new message. The model's own
reasoningblocks explicitly concluded it had enough information at least twice (step 9/10 and step 22/23 — "Now I have all the facts I need. Let me summarize") but kept issuing newbash/greptool calls anyway instead of emitting a final text-only message.Why it gets expensive fast
Each step's
buildRequest()callsthis.session.deriveMessages()(agent.ts:342) and resends the entire accumulated session history asmessages(agent.ts:488) — there's no summarization/windowing inside a turn. So per-step input token cost grows roughly linearly with step count, making total turn cost grow close to quadratically. In this session (deepseek-v4-flash,reasoningEffort: high,maxTokens: 256000/step), 27 steps pushed cumulative token usage to roughly 1M.Suggested fix
maxStepsper turn (alongside the existingmaxParallelToolCallsinAgentLoopSettings), and giveTurnEndReasona newmax-stepsvariant so hitting the cap ends the turn cleanly instead of running forever.Related but distinct
This looks related to #2107 (web profile ships with
compaction-basic/command-compact/tool-result-prunerdisabled, so long web sessions never auto-compact and eventually hitcontext-exceeded), but it's a separate root cause: #2107 is about compaction not firing; this report is about the step loop itself having no ceiling regardless of compaction state. Fixing one doesn't fix the other — a turn can still spin indefinitely even with working compaction, and compaction alone won't stop a model that keeps calling tools past the point of having enough information.Environment
deepseek-v4-flashviadeepseek-officialreasoningEffort: high,maxTokens: 256000standard,contextWindow: 1000000All reactions