Skip to content

feat(subagent): cap child tool results at capture time (#6282) - #6294

Closed
xiechimon wants to merge 2 commits into
Hmbown:mainfrom
xiechimon:feat/tool-result-cap-6282
Closed

xiechimon wants to merge 2 commits into
Hmbown:mainfrom
xiechimon:feat/tool-result-cap-6282

Conversation

@xiechimon

Copy link
Copy Markdown
Contributor

Fixes #6282: a child subagent's tool results can inflate its message history past the button budget before the 75% pacing notice fires, causing read starvation (542KB file → 638k input tokens → dead, zero workspace changes).

Adopts codex-rs's placement rule: truncation at capture time, not accounting after insertion.

Changes

1. Hard cap at capture time

  • 1 MiB byte cap (SUBAGENT_TOOL_RESULT_BYTE_CAP), applied after existing spillover (100 KiB)
  • 10k token cap (SUBAGENT_TOOL_RESULT_TOKEN_CAP_DEFAULT), via conservative bytes/3 estimate
  • [truncated: true] plain-text marker appended when either fires (consistent with spillover footer)
  • UTF-8 boundary-safe truncation (is_char_boundary)

2. Budget pacing at result insertion

  • Per-tool-result: estimate token cost before push, truncate-to-fit remaining allowance
  • Break with budget_exhausted if even a minimal result won't fit

3. max_output_tokens parameter

  • Model-facing via agent tool input (parse_optional_bounded_limit with u32::MAX ceiling)
  • input_schema property with minimum: 1, maximum: 4294967295
  • Wiring: SpawnRequest → SubAgentSpawnOptions → SubAgentRuntime → child loop

Design doc

codewhale-ops/designs/TOOL-RESULT-CAP-20260917.md (ADR, carried in the first commit).

Tests

  • 6 unit tests for hard_cap_tool_result: passthrough, byte cap, token cap, UTF-8 boundary, custom cap, MIN
  • 1 parse test for max_output_tokens: valid round-trip + zero + excessive rejection
  • cargo test -p codewhale-tui --lib -- limits_tests: 28 passed, 0 failed

Notes

@xiechimon
xiechimon requested a review from Hmbown as a code owner September 17, 2026 04:45
Copilot AI lite review requested due to automatic review settings September 17, 2026 04:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

Thanks @xiechimon for taking the time to contribute.

This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant recurring PR access by commenting /lgtm on a pull request.

@xiechimon
xiechimon force-pushed the feat/tool-result-cap-6282 branch from 772d553 to 1825fae Compare September 17, 2026 04:48
Hard cap every child tool result before it enters message history:
- 1 MiB byte cap (SUBAGENT_TOOL_RESULT_BYTE_CAP), applied after spillover
- 10k token cap (SUBAGENT_TOOL_RESULT_TOKEN_CAP_DEFAULT), bytes/3 estimate
- [truncated: true] marker appended when either cap fires
- UTF-8 boundary-safe truncation via is_char_boundary()

Budget pacing checked at result-insertion time:
- Per-tool-result granularity: estimate token cost before push
- Truncate to fit remaining allowance, break with budget_exhausted if even
  a minimal result won't fit

max_output_tokens parameter:
- Model-facing via agent tool input (parse_optional_bounded_limit)
- input_schema property with minimum/maximum
- Wiring: SpawnRequest → SubAgentSpawnOptions → SubAgentRuntime → child loop

Tests: 6 hard_cap_tool_result unit tests + parse_spawn_request round-trip test
@xiechimon
xiechimon force-pushed the feat/tool-result-cap-6282 branch from 1825fae to 71194f9 Compare September 17, 2026 04:51
Hmbown pushed a commit that referenced this pull request Sep 17, 2026
A child subagent's tool results can inflate its message history past
the token budget before the pacing notice fires, causing read
starvation (542KB file -> 638k input tokens -> dead, zero workspace
changes). Adopts codex-rs's placement rule: truncation at capture
time, not accounting after insertion.

- 1 MiB byte cap + 10k token cap (bytes/3 estimate) per tool result,
  applied after spillover, with a [truncated: true] marker; UTF-8
  boundary-safe.
- Budget pacing at result insertion: shrink-to-fit remaining
  allowance, budget_exhausted when even a minimal result won't fit.
- max_output_tokens model-facing spawn option (narrow-only),
  SpawnRequest -> SpawnOptions -> Runtime -> child loop.

Tests: limits_tests 28 passed 0 failed; parse_spawn_request max
output tokens 1 passed 0 failed; subagent schema vocabulary 1
passed 0 failed. cargo fmt --all -- --check clean.

Harvested from PR #6294 by @xiechimon

Co-authored-by: Xmon Dai <157263579+xiechimon@users.noreply.github.com>
Hmbown pushed a commit that referenced this pull request Sep 17, 2026
Mechanical clippy-suggested fixes; no behavior change:
- git_history remote check uses contains (manual_contains, from 2c)
- spawn max_output_tokens parse drops redundant closure (from #6294)
- fragment edge cells use next_back on DoubleEndedIterator x2 (#6228)

TUI-lib clippy under the CONTRIBUTING allow list is green again.

Tests: git_fetch filter 5 passed 0 failed; fragment filter 19
passed 0 failed; max_output_tokens parse 1 passed 0 failed.
cargo fmt --all -- --check clean.
@github-actions

Copy link
Copy Markdown
Contributor

Thanks @xiechimon — your contribution landed in 2ca54ea8da93 on main:

feat(subagent): cap child tool results at capture time (#6282)

Closing this PR now that the code is on main. Credit lives in the commit message and (where applicable) the CHANGELOG.md entry for the next release. Apologies for not closing this at the time of the merge — the auto-close workflow is new in v0.8.31.

If you want to land more work and would prefer your future PRs merge cleanly without a harvest step, the CONTRIBUTING.md doc has a short note on what makes a contribution mergeable as-is.

@github-actions github-actions Bot closed this Sep 17, 2026

Hmbown commented Sep 17, 2026

Copy link
Copy Markdown
Owner

sorry I didn't get a clean merge here — editing my agents md files so this doesn't happen again. appreciate this a ton!!

Hmbown added a commit that referenced this pull request Sep 18, 2026
Version-drift gate needs one receipt per referenced issue: running-work
accounting + notices (#6180, #3757), launch governor (#6055), turn modes
(#6321), NUL/pin hardening (#5529, #6318, #6320), child context bounds +
write visibility (#6189, #6194), mail cancel + job control (#6176, #6169),
MCP supervision (#6187, #6142), search/fleet/verify program (#6298,
#6296), ChildGrant + ModelScope (#5633, #6299), capture caps + bounded
cwd (#6282, #6294). TUI changelog synced via sync-changelog.sh.
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.

v0.9.14: cap every child tool result at capture time — 1 MiB bytes / 10k tokens into context, pacing checked at result insertion

3 participants