feat: orçamento de tokens por run/fase + timeout de fase com corte mid-stream - #49
Merged
Conversation
…com corte mid-stream Não existia NENHUM teto de tokens/custo no runtime: run.tokens era acumulado e nunca comparado a limite, fases agent não tinham timeout nem max-turns (os CLIs não expõem), e um resume resetava o medidor. Medido em projeto real: um run de 112M tokens e uma única fase de 36M. - stop.token_budget (default 30M, LIGADO): teto de VIDA do run — resume carrega o baseline de sessions.total_tokens (fail open); warnings únicos em 50%/80% (evento budget_warning) e parada limpa como budget_exhausted, checada entre fases e entre sends. - stop.phase_token_budget (default 8M, LIGADO): teto de UMA fase (sends + correções + relay legs); o filho do engine é cortado mid-send no espaço restante (SIGTERM→SIGKILL em modules/agent-limits.mjs, armado nos 3 adapters via request.limits). Nunca arma relay — refazer noutra engine re-gastaria. - stop.phase_timeout_minutes (default 50, LIGADO): kill com quase nenhum gasto (<500k) = CLI travado, tratado como crash (1 retry mesma engine, depois relay); kill com gasto real = StopCondition, nunca re-paga a fase. - Label do outcome corrigido para "budget exhausted (time or tokens)" (outcome + espelho do viewer); tracer ganha sessionTokens() (reader fail-open). - fia.config.yaml (3 chaves no bloco stop), DOCS.md §9.7 (tabela + parágrafo) e cookbook run_fda.md atualizados — run parado por orçamento nunca troca de LLM sozinho: decisão humana no knob. - Testes em test/fia-token-budget.test.js (harness de engines fake): defaults ON/0-off/typos, armLimits (corte único, timeout, finish), orçamento de run com warnings 50/80, orçamento de fase, baseline no resume (e fresh ignora), timeout hung vs busy, asserts de fonte nos 3 adapters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPYaKxNaVRhPumKbawFNT3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Contexto
Terceira PR do estudo de consumo (após #47 e #48). Não existia nenhum teto de tokens no runtime:
run.tokensera acumulado e nunca comparado a limite, fases agent não tinham timeout nem cap de turnos (os CLIsclaude/pinão expõem--max-turns— verificado), e um--resumeresetava o medidor. No ledger real: um run de 112M tokens e uma única fase de 36M.O que muda
Três chaves novas no
stop:(todas ligadas por default, com folga generosa;0desliga; tolerantes a typo como as demais):token_budgetsessions.total_tokens, fail-open); warnings únicos em 50%/80% (budget_warning); parada limpabudget_exhausted, checada entre fases E entre sendsphase_token_budgetmodules/agent-limits.mjs: SIGTERM→SIGKILL, armado nos 3 adapters). Nunca arma relay — refazer noutra engine re-gastaria tudophase_timeout_minutesRun parado por orçamento não troca de LLM sozinho: pausa com o painel calmo apontando o knob (alinhado à decisão do Elber de que corte seco cego não é a solução). Cursor não reporta usage ⇒ tetos de token não o enxergam (timeout aplica; documentado).
Extras: label do outcome vira "budget exhausted (time or tokens)" (+ espelho do viewer — a lição do PAGE),
tracer.sessionTokens()fail-open, DOCS.md §9.7 (tabela nova) e cookbookrun_fda.md(regra: reportar o gasto e deixar o engenheiro decidir entre corrigir a abordagem e subir o knob — nunca subir sozinho).Testes
test/fia-token-budget.test.js(8 testes, harness de engines fake): defaults/0-off/typos;armLimits(corte único no teto, timeout, finish limpa e reporta); orçamento de run parando a 2ª fase com warnings 50/80 exatamente uma vez; orçamento de fase isolado; baseline no resume (e run fresh ignora); timeout hung (2 tentativas → EngineFailure) vs busy (StopCondition); asserts de fonte nos 3 adapters.deepEqualdostopPolicyOfexistente atualizado. Suite completa 1457 pass + lint limpo (re-testada pós-rebase na main).🤖 Generated with Claude Code
https://claude.ai/code/session_01NPYaKxNaVRhPumKbawFNT3