Skip to content

Make truncation marker honest before the size-cap blob spill - #542

Merged
TheGreatAxios merged 7 commits into
mainfrom
cl-6908-size-cap-tells-the-model-full-output-available-at-a-blob
Aug 23, 2026
Merged

Make truncation marker honest before the size-cap blob spill#542
TheGreatAxios merged 7 commits into
mainfrom
cl-6908-size-cap-tells-the-model-full-output-available-at-a-blob

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Summary

Tool results are truncated to MAX_RESULT_CHARS (80,000 chars) by src/plugins/result-truncation-plugin.ts in the posix chain (src/agent/posix-tool-plugins.ts) and the MCP runner (src/mcp/plugin.ts) before the reactor's size-cap transform runs (vendor/intx-inference/src/transforms/size-cap.ts). For an output over 80k, the size-cap transform spills the already-truncated text as the blob and tells the model "Full output available at tool-output:///{id} — use read_file with that URI to see the rest." That promise is false: the remainder was discarded upstream and the blob only contains the same truncated text. The model reads the blob, finds it cut in the same place, and re-runs the command — an observed loop shape in production traces.

vendor/ is edit-locked, so this fixes it at the source: the truncation marker in result-truncation-plugin.ts now tells the truth up front, so the lie doesn't get a chance to survive the size-cap spill.

Tradeoff

Kept the honest-but-terse wording rather than a fuller explanation, to stay under the MAX_RESULT_CHARS + 200 char allowance asserted by the real-chain ripgrep integration test (tests/unit/ripgrep-plugin.test.ts). The marker text is:

[output truncated at 80,000 chars — {n} chars discarded, NOT retrievable (no tool-output URI has them; re-running gives the same cut). Use offset/limit or a narrower query.]

This sacrifices some guidance detail for staying inside that budget, but the load-bearing part — "NOT retrievable" / "re-running gives the same cut" — is what stops the retry loop, so it comes first.

Test plan

  • src/plugins/result-truncation-plugin.test.ts (new): asserts the marker never promises a retrievable remainder, and that it survives a real createSizeCapTransform spill (blob content ends with the marker, inline output still points at tool-output:///{id})
  • tests/unit/ripgrep-plugin.test.ts: existing real-chain oversized-grep tests still pass within MAX_RESULT_CHARS + 200
  • bunx prettier --check / bunx eslint on touched files
  • bun run typecheck, bun run build
  • bun test ./src ./tests ./evals (5116 pass, 1 pre-existing unrelated failure in src/agent/lsp-availability.test.ts present on main with no node_modules — not touched by this change)

Fixes CL-6908

Tool results are truncated to MAX_RESULT_CHARS before the reactor's
size-cap transform spills the (already-truncated) text as a blob and
tells the model the full output is at tool-output:///{id}. For
oversized outputs the promised remainder never existed, so the model
reads the blob, finds it cut, and re-runs the command.

Rework the truncation marker to say the discarded remainder is not
retrievable anywhere, so the lie doesn't survive the blob spill.
Sized to stay within the ripgrep integration test's MAX_RESULT_CHARS
+ 200 allowance.
@linear-code

linear-code Bot commented Aug 23, 2026

Copy link
Copy Markdown

CL-6908

@TheGreatAxios
TheGreatAxios merged commit d6f92a3 into main Aug 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant