fix(model_runner): cap oversized tool results to avoid 413 on next request#252
Draft
CorrectRoadH wants to merge 1 commit into
Draft
fix(model_runner): cap oversized tool results to avoid 413 on next request#252CorrectRoadH wants to merge 1 commit into
CorrectRoadH wants to merge 1 commit into
Conversation
…quest A single oversized tool result (e.g. `grep` over a minified bundle or source map under node_modules, where individual lines are megabytes) was returned inline in full. `head -50` is no protection when lines are that long. The full output flowed into the tape and back into the next request body, which the provider/reverse-proxy rejected with `413 Request Entity Too Large`, failing the whole turn. Cap each tool result at the single choke point in `ModelRunner.run` (after execution, before record_chat), so the bound protects the tape, the trace, the streamed event, and the next request alike, and runs once per execution. Oversized string results are truncated to a byte budget and the full output is spilled to `<bub.home>/tool-output/<run>-call-N.txt`, with a footer pointing the agent at the file and `tail`/`rg` hints so debugging info is preserved. - new `bub.builtin.tool_output.cap_tool_result` (byte-budgeted, UTF-8 safe) - `BUB_MAX_TOOL_RESULT_BYTES` setting (default 128 KB, 0 disables) - treat `request entity too large` as a context-overflow so auto_handoff can recover as a best-effort backstop - regression test: 4 MB single-line result -> next request stays bounded and the agent can read the full output from the spill file - docs + env.example synced Closes bubbuild#249 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WAgZfqMU5X8qbF4LX1ag4U
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.
Closes #249
问题
单次工具输出过大时,会被原样回灌进下一轮请求体,触发 provider / 反向代理的
413 Request Entity Too Large,整个 agent 回合直接失败。复现路径:agent 在
node_modules/next里跑grep ... | head -50。head -50形同虚设,因为 compiled bundle / source map 是超长单行,50 行也有几 MB。数据流:bash直接return shell.output.strip()(tools.py:190),无任何上限build_messages还原成{"role":"tool","content": <几 MB>}(context.py:99)413→ 回合失败补刀问题:
413返回的是 HTML,原本的is_context_length_error匹配不到,连 auto_handoff 自救都不会触发。怎么解决的
在唯一收口点
ModelRunner.run(工具执行之后、record_chat之前)对每个结果做字节级截断。选这个点是因为它一次性保护了 tape、trace、stream 事件、下一轮 request,且每次执行只跑一次(落盘不重复)。采用 issue 推荐的 spill-to-file,而非纯硬截断,以保留调试能力:超限的字符串结果截断到字节预算,完整输出落盘到
<bub.home>/tool-output/<run_id>-call-<n>.txt,inline 内容替换为:要点:
errors="ignore"避免在截断边界切坏多字节字符改动
bub.builtin.tool_output.cap_tool_result:隔离、纯函数、可单测model_runner.py:_cap_tool_results在收口点替换结果,record + 两个 StreamEvent 统一用截断后的版本BUB_MAX_TOOL_RESULT_BYTES(默认 128 KB,设0关闭)request entity too large加进CONTEXT_LENGTH_PATTERNS,让 auto_handoff 可作为 best-effort backstopenv.example+ 中英 settings 文档同步为什么
bash.output没解决bash.output只服务后台 shell,且只是"让模型主动选窗口"的便利工具,不是强制护栏;不传limit照样拿全部。413 是安全问题,必须在结果边界强制收口。测试
tests/test_tool_output_cap.py:小/非字符串放行、截断+落盘完整内容、多字节不切坏、端到端(4 MB 单行经 model_runner → 断言下一轮 request 的 tool message ≤ limit 且含 spill 路径、完整内容可从文件读回)、413 被识别。验证:
pytest全绿(216 passed)·ruff全过 · 改动文件mypy干净。🤖 Generated with Claude Code
https://claude.ai/code/session_01WAgZfqMU5X8qbF4LX1ag4U