fix: deliver truncation notice as separate content block#7899
fix: deliver truncation notice as separate content block#7899DOsinga merged 2 commits intoblock:mainfrom
Conversation
When shell output exceeds the 50kB / 2000-line limit, the truncation notice (file path + read instructions) was appended directly to the preview text. This text then became the `stdout` field in the structured JSON output, causing the model to parse the notice as command data rather than acting on it. Changes: - Extract `TruncateResult` struct so `truncate_output()` returns the preview text and truncation metadata separately - Deliver the truncation notice as a separate `Content` block in the `CallToolResult`, keeping structured_content clean - Use platform-appropriate commands in the notice (PowerShell on Windows, head/tail/sed on Unix) The structured `ShellOutput` JSON now contains only the actual command output (truncated preview), while the instruction to read the full output arrives as a distinct message the model can see and act on. Fixes block#7846
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6d9ad815eb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let truncation_notices: Vec<String> = [ | ||
| &stdout_result.truncation, | ||
| &stderr_result.truncation, | ||
| &render_result.truncation, |
There was a problem hiding this comment.
Prioritize interleaved truncation notice over stream files
When output truncation happens on both streams, this order emits stdout/stderr notices before the interleaved notice even though the preview shown to the model comes from interleaved output. In that case, following the first suggested file path can hide stderr lines (or stdout/stderr ordering), which can change diagnosis for failing commands. Emitting only the interleaved notice (or at least placing it first) would avoid steering the model to incomplete logs.
Useful? React with 👍 / 👎.
* main: (337 commits) fix: replace panics with user-friendly errors in CLI session builder (#7901) fix: read GOOSE_CONTEXT_LIMIT from config.yaml, not just env vars (#7900) fix: deliver truncation notice as separate content block (#7899) fix: use platform-appropriate commands in developer extension instructions (#7898) fix: replace any with proper SVG types in icon components (#7873) chore: remove debug console.log statements, stale comments, and dead code (#8142) feat: Gemini OAuth provider (#8129) chore(deps): bump picomatch from 2.3.1 to 2.3.2 in /documentation (#8123) feat: show installed skills in UI (#7910) fix(deps): gate keyring platform features behind target-specific deps (#8039) chore(deps): bump yaml from 2.8.2 to 2.8.3 in /evals/open-model-gym/suite (#8124) fix: strip message wrapper in CLI session title generation (#7996) fix(providers): fall back to configured models when models endpoint fetch fails (#7530) chore(deps): bump brace-expansion from 5.0.3 to 5.0.5 in /evals/open-model-gym/suite (#8139) fix: prevent Ollama provider from hanging on tool-calling requests (#7723) fix: VMware Tanzu Platform provider - bug fixes, streaming, UI improvements (#8126) feat: allow GOOSE_CLI_SHOW_THINKING to be set in config.yaml (#8097) fix: GitHub Copilot auth fails to open browser in Desktop app (#6957) (#8019) fix(ci): produce .tar.gz archives for Zed ACP registry compatibility (#8054) feat: add GOOSE_SHOW_FULL_OUTPUT config to disable tool output truncation (#7919) ... # Conflicts: # crates/goose/src/providers/formats/openai.rs
* origin/main: (63 commits) remove name from blog post (#8157) fix: use `overflow: clip` to not disrupt sticky ToC (#8158) chore(deps): bump path-to-regexp from 0.1.12 to 0.1.13 in /documentation (#8161) chore(deps): bump node-forge from 1.3.2 to 1.4.0 in /documentation (#8145) refactor: goose-acp-server -> goose binary for TUI (#8155) fix "View as Markdown" feature not working (#8160) feat(tui): UI improvements for messages, tool calls, text entry, etc (#8156) feat(desktop): add i18n infrastructure with react-intl (#8105) fix(tui): ordering of messages (#8144) fix: extension command with quotes in cli (#8150) chore(aaif): Use Azure Artifact Signing for Windows (#8116) chore(aaif): Switch macOS code signing (#8076) Remove unused tool call json in logs (#8147) feat(tui): tab expand tool calls cleanly (#8136) fix: replace panics with user-friendly errors in CLI session builder (#7901) fix: read GOOSE_CONTEXT_LIMIT from config.yaml, not just env vars (#7900) fix: deliver truncation notice as separate content block (#7899) fix: use platform-appropriate commands in developer extension instructions (#7898) fix: replace any with proper SVG types in icon components (#7873) chore: remove debug console.log statements, stale comments, and dead code (#8142) ...
Signed-off-by: Cameron Yick <[email protected]>
* main: (337 commits) fix: replace panics with user-friendly errors in CLI session builder (#7901) fix: read GOOSE_CONTEXT_LIMIT from config.yaml, not just env vars (#7900) fix: deliver truncation notice as separate content block (#7899) fix: use platform-appropriate commands in developer extension instructions (#7898) fix: replace any with proper SVG types in icon components (#7873) chore: remove debug console.log statements, stale comments, and dead code (#8142) feat: Gemini OAuth provider (#8129) chore(deps): bump picomatch from 2.3.1 to 2.3.2 in /documentation (#8123) feat: show installed skills in UI (#7910) fix(deps): gate keyring platform features behind target-specific deps (#8039) chore(deps): bump yaml from 2.8.2 to 2.8.3 in /evals/open-model-gym/suite (#8124) fix: strip message wrapper in CLI session title generation (#7996) fix(providers): fall back to configured models when models endpoint fetch fails (#7530) chore(deps): bump brace-expansion from 5.0.3 to 5.0.5 in /evals/open-model-gym/suite (#8139) fix: prevent Ollama provider from hanging on tool-calling requests (#7723) fix: VMware Tanzu Platform provider - bug fixes, streaming, UI improvements (#8126) feat: allow GOOSE_CLI_SHOW_THINKING to be set in config.yaml (#8097) fix: GitHub Copilot auth fails to open browser in Desktop app (#6957) (#8019) fix(ci): produce .tar.gz archives for Zed ACP registry compatibility (#8054) feat: add GOOSE_SHOW_FULL_OUTPUT config to disable tool output truncation (#7919) ... # Conflicts: # crates/goose/src/providers/formats/openai.rs
Problem
When shell output exceeds the 50kB / 2000-line limit, the truncation notice (
[Full output saved to /tmp/... Read it with head, tail, or sed...]) is appended directly to the preview text. This causes two issues:Model ignores the notice. The notice text becomes part of the
stdoutfield in the structured JSON (ShellOutput). The model parses the JSON and treats the notice as command output data — it never "sees" it as an instruction to read the temp file.Unix-only commands on Windows. The notice references
head,tail, andsedwhich are unavailable on Windows.Fix
TruncateResultstruct sotruncate_output()returns the preview text and truncation metadata (path + reason) separatelyContentblock in theCallToolResult, keepingstructured_contentcleanThe structured
ShellOutputJSON now contains only the actual command output (truncated preview), while the instruction to read the full output arrives as a distinct message the model can see and act on.Changes
Single file:
crates/goose/src/agents/platform_extensions/developer/shell.rsTruncateResult/TruncationInfostructstruncation_notice()helper withcfg!(windows)branchingtruncate_output()andrender_output()return typesshell_with_cwd()to collect notices and emit as separate Content blockTesting
No behavioural change for output under the limit (returns
TruncateResultwithtruncation: None).Fixes #7846