[code-mode] `exec` results honour the script's `max_output_tokens` with no upper bound — one 497 KB shell result reached the model as ~138K tokens (function mode clamps to the model's truncation policy)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of Codex CLI is running?
codex-cli 0.137.0-alpha.4 (app-server, driven through the openai-codex Python SDK 0.1.0b3). The same code is on main today.
Which model were you using?
gpt-5.6-luna (Azure OpenAI deployment; the catalog resolves it to tool_mode: code_mode_only). Also seen with gpt-5.6-terra.
What issue are you seeing?
In code mode, the size of a tool result the model receives is bounded only by what the model itself asked for:
codex-rs/core/src/tools/code_mode/mod.rs—truncate_code_mode_resultusesresolve_max_tokens(max_output_tokens), i.e. the// @exec: {"max_output_tokens": N}pragma value (or 10 000 when absent), with no clamp;codex-rs/core/src/tools/context.rs— the function-mode pathExecCommandToolOutput::model_output_max_tokensdoes clamp:resolve_max_tokens(self.max_output_tokens).min(self.truncation_policy.token_budget());codex-rs/code-mode/src/description.rsonly checks the pragma is a non-negative safe integer.
So a script that raises the pragma passes a raw shell result of any size (up to the 1 MiB UNIFIED_EXEC_OUTPUT_MAX_BYTES buffer) straight into the context. Observed in an automated evaluation run (2026-09-02): an rg … | head -240 over a repository returned 496 887 bytes in 57 very long lines; the next model request carried 159 055 uncached input tokens (≈138K of them that tool result) and took 1 113 s to be answered against the Azure deployment (the same request shape on 2026-08-31, without a raised budget, was cut to ~10K tokens and answered in 2 s). Across ~680 shell results ≥100 KB in the same evaluation archive (gpt-5.6 models), exactly two reached the model uncut — so this is rare, but when it happens it costs a turn's worth of time and tokens and the harness has no knob: tool_output_token_limit only rewrites model.truncation_policy, which the code-mode result path never reads; the catalog's tool_mode overrides features.code_mode* (session/turn_context.rs), so the harness cannot leave code mode either.
Related but the inverse framing: #33402 (outer exec truncates below nested budgets). This report is about the upper direction.
Expected
Code-mode exec/wait results are clamped the way function-mode results already are — min(requested, truncation_policy.token_budget()) (or a configurable ceiling) — so a model cannot request more tool output than the model's own output policy allows.
Steps to reproduce
- Any code-mode model (catalog
tool_mode: code_mode_only, e.g. gpt-5.6-*). - Have the model run an
execscript whose first line is// @exec: {"max_output_tokens": 200000}and whose body callsexec_command({ cmd: "yes 'x…(8 KB line)' | head -60" })andtext(result.output). - In the rollout JSONL, the
custom_tool_call_outputcarries the full ~480 KB; the next request'sinput_tokensgrows by ~130K.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in codex-rs/core/src/tools/code_mode/mod.rs at truncate_code_mode_result, then compare its resolve_max_tokens handling with ExecCommandToolOutput::model_output_max_tokens in codex-rs/core/src/tools/context.rs and the pragma validation in codex-rs/code-mode/src/description.rs. Done means code-mode exec and wait results apply the truncation policy ceiling to the requested max_output_tokens, preventing oversized results from reaching the model.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli, devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100