Skip to content

fix: bound tool input projections - #952

Merged
Astro-Han merged 9 commits into
devfrom
codex/tool-input-projection
May 27, 2026
Merged

fix: bound tool input projections#952
Astro-Han merged 9 commits into
devfrom
codex/tool-input-projection

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 27, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes a repeated projection-boundary bug where long or invalid tool inputs could leak into compact UI summaries or model replay during compaction. There is no linked issue; this came from a user-reported long-question failure that also matched an earlier apply_patch-class failure shape.

  • Bound failed tool row summaries so question and todo tool rows use stable tool metadata instead of raw schema errors or raw todo content.
  • Add an optional tool input cap for model-message projection and apply it to both compaction estimate and compaction process replay.
  • Add focused regression coverage for long failed question inputs, compaction payload capture, and budget-aware tool input traversal.
  • Repair the desktop-smoke Electron install path used only by CI, ensuring raw Electron smoke launches have both path metadata and the macOS framework before running.

Why

Tool rows and compaction were treating raw tool state as presentation/replay data. That made one malformed or very long tool input able to break the summarization surfaces that are supposed to make the transcript smaller and safer to replay.

Related Issue

No issue. User-reported regression in the long-question tool path.

Human Review Status

Pending

Review Focus

Please focus on whether the input cap is applied at the correct projection boundary, without changing persisted tool state or normal tool execution behavior.

Risk Notes

Low to moderate. The raw tool input remains stored for lifecycle/debug/export paths; truncation is only applied when callers opt into model-message projection limits. The visible UI change affects compact tool row summary copy. The platform/CI surface is limited to desktop-smoke: the new Electron repair script is only called from .github/workflows/desktop-smoke.yml to restore Electron install metadata and verify the macOS framework before the raw CI smoke launch. It does not change packaged app runtime behavior, updater, signing, user paths, shell behavior, or permissions.

How To Verify

bun --cwd packages/ui test src/components/message-part/context-tool-helpers.test.ts --timeout 10000: 8 passed
bun --cwd packages/opencode test test/session/message-v2.test.ts --timeout 10000: 45 passed
bun --cwd packages/opencode test test/session/compaction.test.ts --timeout 30000: passed
bun --cwd packages/opencode test test/session/message-v2.test.ts test/session/compaction.test.ts --timeout 30000: 96 passed
bun --cwd packages/desktop-electron test scripts/repair-electron-install.test.ts scripts/ci-smoke.test.ts --timeout 10000: 16 passed
bun --cwd packages/opencode test test/github/desktop-smoke-workflow.test.ts --timeout 10000: 1 passed
node ./scripts/repair-electron-install.mjs (from packages/desktop-electron): passed locally
bun --cwd packages/desktop-electron typecheck: passed
bun --cwd packages/ui typecheck: passed
bun --cwd packages/opencode typecheck: passed
bun run snap session-trow: passed; reviewed docs/design/preview/screenshots/session-trow.png locally
Scope blast: reviewed remaining raw tool input/error call sites; remaining raw uses are persistence/lifecycle/export paths, not summary or compaction projection
PR CI: desktop-smoke / smoke-macos-arm64 passed after Electron repair workflow update; all required checks passed

Screenshots or Recordings

Visible check performed with bun run snap session-trow; reviewed the generated docs/design/preview/screenshots/session-trow.png locally for the compact tool row surface.

Checklist

  • Type label — this PR carries exactly one of bug, enhancement, task, documentation. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this.
  • Routing labels — this PR carries at least one of app, ui, platform, harness, ci. The labeler bot assigns these on PR open based on changed paths. Confirm the bot's choice (or override if wrong), then tick this.
  • Priority label — this PR carries exactly one of P0, P1, P2, P3. The priority-triage bot suggests one on PR open. Confirm or override, then tick this.
  • Human Review Status above is set to Pending, Approved by @<reviewer>, or Not required: <reason> (default is Pending; "not required" is restricted to bot-authored low-risk PRs).
  • I linked the related issue, or stated in Summary why there is no issue.
  • I described the review focus and any meaningful risks.
  • I replaced the example block in How To Verify with the real verification steps and the key result for each.
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope.
  • (conditional) I manually checked visible UI or copy changes when needed, with screenshots or recordings. Leave unticked only if no visible UI or copy changed.
  • (conditional) I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes. Desktop-smoke CI now repairs Electron install metadata and validates the macOS framework before raw smoke; no packaged runtime, updater, signing, user path, shell, or permission behavior changed.
  • (conditional) I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant. Leave unticked only if none of those surfaces was touched.
  • I reviewed the final diff for unrelated changes and suspicious dependency changes.
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English.

Summary by CodeRabbit

  • Bug Fixes

    • Consistent automatic truncation of oversized tool inputs to prevent oversized payloads.
    • Bounded/truncated display of tool error details to avoid leaking verbose/raw error text.
  • New Features

    • Tool info now shows localized item counts for todos and questions (pluralization added).
  • Tests

    • Added and updated tests to verify truncation behavior and compact tool summaries.

Review Change Stack

@Astro-Han Astro-Han added bug Something isn't working ui Design system and user interface harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority labels May 27, 2026
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds recursive tool-input truncation and a toolInputMaxChars option to MessageV2, applies a 2,000-char cap during compaction, and updates UI tool summaries with localized item counts and bounded error text.

Changes

Tool Input Truncation and UI Display

Layer / File(s) Summary
Truncation helpers and MessageV2 API + tests
packages/opencode/src/session/message-v2.ts, packages/opencode/test/session/message-v2.test.ts
Adds truncateToolInputString and recursive truncateToolInput, extends toModelMessagesEffect/toModelMessages to accept toolInputMaxChars, and adds tests asserting truncation markers, length bounds, and traversal/budget behavior.
Compaction Tool Input Sizing
packages/opencode/src/session/compaction.ts, packages/opencode/test/session/compaction.test.ts
Introduces TOOL_INPUT_MAX_CHARS = 2_000 and passes it to both token-estimation and model-message serialization code paths used by compaction; test updated to assert truncated tool input appears and unique tail is omitted.
Tool Display with Item Counts and Localization
packages/ui/src/components/tool-info.ts, packages/ui/src/components/message-part/context-tool-helpers.ts, packages/ui/src/components/message-part/context-tool-helpers.test.ts, packages/ui/src/i18n/en.ts, packages/ui/src/i18n/zh.ts
toolInfoForInput now shows localized item-count subtitles for TODOWRITE/QUESTION; contextToolDetail bounds/suppresses long error details via boundedToolStateError. Adds i18n keys for todo singular/plural and tests ensuring summaries are compact and do not leak raw content.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Astro-Han/pawwork#270: Updates compaction/message serialization truncation options in a related area (passes truncation caps into MessageV2 serialization).

Poem

🐰 I nibble long inputs down to size and cheer,
Two-thousand chars keep prompts snug and clear,
Counts bloom in subtitles, errors tuck away,
Compaction and messages now agree all day,
A happy rabbit hops—no oversized payloads here!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: bound tool input projections' clearly and concisely summarizes the main change—bounding tool input projections to prevent leaks into summaries and compaction.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive and complete, covering all required sections: Summary, Why, Related Issue, Human Review Status, Review Focus, Risk Notes, How To Verify, Screenshots/Recordings, and a fully-ticked Checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/tool-input-projection

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested priority: P2 (includes non-doc, non-test paths outside the low-risk bucket).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces truncation for long tool inputs during session compaction to prevent excessive token usage, setting a limit of 2,000 characters. It also refactors the UI to display concise tool summaries based on item counts (such as the number of questions or to-dos) rather than raw contents or schema errors. The review feedback notes that the subtitle for TOOL_TODOWRITE uses hardcoded English strings instead of localized keys, and suggests using i18n.t for proper internationalization.

Comment thread packages/ui/src/components/tool-info.ts Outdated
@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Perf delta summary

Comparator: pass

Profile / Scenario interaction median interaction worst long task max tbt frame gap p95 frame gap max jank count cls status
default / homepage-cold 24 -> 24 (0) 56 -> 40 (-16) 96 -> 72 (-24) 46 -> 22 (-24) 33.3 -> 33.4 (+0.1) 133.3 -> 133.3 (0) 4 -> 3 (-1) 0 -> 0 (0) pass
default / long-session-input-lag 48 -> 40 (-8) 48 -> 48 (0) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.7 (0) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-streaming-long 32 -> 32 (0) 48 -> 56 (+8) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.8 (+0.1) 33.3 -> 16.8 (-16.5) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-call-expand 24 -> 24 (0) 24 -> 24 (0) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.8 (+0.1) 16.7 -> 16.8 (+0.1) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-default-open-heavy-bash 16 -> 16 (0) 24 -> 24 (0) 66 -> 70 (+4) 16 -> 28 (+12) 49.9 -> 50 (+0.1) 116.7 -> 133.3 (+16.6) 3 -> 3 (0) 0.004 -> 0.004 (0) pass
default / terminal-side-panel-open 48 -> 40 (-8) 48 -> 64 (+16) 0 -> 0 (0) 0 -> 0 (0) 33.3 -> 33.3 (0) 33.4 -> 33.4 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-scroll-reading 24 -> 16 (-8) 32 -> 32 (0) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.7 (-0.1) 16.8 -> 16.7 (-0.1) 0 -> 0 (0) 0 -> 0 (0) pass

@github-actions github-actions Bot added ci Continuous integration / GitHub Actions platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work labels May 27, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/src/session/message-v2.ts`:
- Around line 94-102: The function truncateToolInput doesn't consistently honor
zero/negative maxChars for non-string inputs; add an explicit check early (after
the null check) that if maxChars <= 0 returns toolInputTruncatedMarker(maxChars)
so non-string paths behave the same as the string path (which uses
truncateToolInputString). Update truncateToolInput to return the marker for
maxChars <= 0 before calling serializedToolInputLength or processing objects;
keep existing calls to truncateToolInputString, serializedToolInputLength, and
toolInputTruncatedMarker unchanged otherwise.
- Around line 86-91: The current loop in appendToolInputMarkerToObject produces
a nested _truncated object (e.g., { _truncated: { _truncated: "..." } }) because
withMarker is built as { ...output, _truncated: marker } while output may
already contain a _truncated object; fix this by ensuring the final _truncated
value is the marker string itself (not an object) before measuring size: when
constructing withMarker, set _truncated to marker (a string) unconditionally or
replace any existing output._truncated with the marker string, then call
serializedToolInputLength(withMarker); update the logic around keys, output,
marker, withMarker and serializedToolInputLength to avoid nesting and to only
drop fields as needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 64f88b83-0aa4-474c-ba05-6fcc42ceed06

📥 Commits

Reviewing files that changed from the base of the PR and between 67edf85 and 11d569c.

📒 Files selected for processing (4)
  • packages/opencode/src/session/message-v2.ts
  • packages/opencode/test/session/message-v2.test.ts
  • packages/ui/src/components/message-part/context-tool-helpers.test.ts
  • packages/ui/src/components/message-part/context-tool-helpers.ts

Comment thread packages/opencode/src/session/message-v2.ts Outdated
Comment thread packages/opencode/src/session/message-v2.ts
@Astro-Han Astro-Han removed the task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work label May 27, 2026
@github-actions github-actions Bot added the task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work label May 27, 2026
@Astro-Han Astro-Han removed the bug Something isn't working label May 27, 2026
@Astro-Han
Astro-Han merged commit 3cbaea7 into dev May 27, 2026
36 of 41 checks passed
@Astro-Han
Astro-Han deleted the codex/tool-input-projection branch May 27, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Continuous integration / GitHub Actions harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work ui Design system and user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant