Skip to content

fix(core): avoid duplicating stdout content in sandbox summary#1142

Merged
omeraplak merged 2 commits intoVoltAgent:mainfrom
SergioChan:fix/sandbox-summary-no-dup-1140
Mar 6, 2026
Merged

fix(core): avoid duplicating stdout content in sandbox summary#1142
omeraplak merged 2 commits intoVoltAgent:mainfrom
SergioChan:fix/sandbox-summary-no-dup-1140

Conversation

@SergioChan
Copy link
Copy Markdown
Contributor

@SergioChan SergioChan commented Mar 6, 2026

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

execute_command tool responses can duplicate large payloads because summary includes full stdout/stderr content that is already returned in structured fields.

What is the new behavior?

summary is now metadata-only for stream outputs:

  • keeps execution header (Exit code, Duration, etc.)
  • reports stream capture mode (captured inline, saved to <path>, or empty)
  • includes byte counts and truncation/eviction status
  • avoids repeating full stream content in summary

fixes #1140

Notes for reviewers

Validation:

  • Attempted: pnpm -C packages/core test src/workspace/sandbox/toolkit.spec.ts
  • Result: not runnable in this checkout because dependencies are not installed (node_modules missing / vitest not found).

I kept the diff scoped to packages/core/src/workspace/sandbox/toolkit.ts only.


Summary by cubic

Prevent duplication of STDOUT/STDERR content in sandbox execution summaries to reduce payload size and make responses clearer. The summary now reports stream metadata only, not the full content. Fixes #1140.

  • Bug Fixes
    • Make summary metadata-only for STDOUT/STDERR: capture mode, byte counts, truncation/eviction status, and errors.
    • Keep full stream content in structured fields only; remove it from the summary.
    • Replace formatStreamOutput with formatStreamSummary and update summary assembly.

Written for commit 4887248. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor
    • Consolidated per-stream output into single-line summaries to improve readability and display efficiency for evicted content, inline captures, and empty streams.
  • Bug Fix
    • Prevented duplication of stdout/stderr in sandbox summary metadata, ensuring each stream is reported once.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 6, 2026

🦋 Changeset detected

Latest commit: 4887248

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eb2c1e55-1c5f-4dfa-9e1f-38157a602579

📥 Commits

Reviewing files that changed from the base of the PR and between 1ef3e76 and 4887248.

📒 Files selected for processing (1)
  • .changeset/tidy-summary-no-dup.md

📝 Walkthrough

Walkthrough

Replaces a multi-line stream formatter with a single-line summary formatter in the sandbox toolkit, changing per-stream outputs (evicted, inline, empty) to compact single-line summaries and updating call sites to push one summary string per stream.

Changes

Cohort / File(s) Summary
Stream output formatting
packages/core/src/workspace/sandbox/toolkit.ts
Replaced formatStreamOutput() (returned string[]) with formatStreamSummary() (returns string). Evicted-stream, inline-content, and empty-stream cases now produce one-line summaries. Call sites updated to push a single summary string per stream (STDOUT/STDERR).
Changeset
.changeset/tidy-summary-no-dup.md
Added a changeset documenting a patch to @voltagent/core describing the fix to avoid duplicating stdout/stderr content in sandbox summary metadata.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 I hopped through lines and trimmed the fluff,
One tidy summary—no doubles, no stuff.
Streams now whisper a single neat tune,
Tokens saved under the sandbox moon. 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately describes the main change: avoiding duplication of stdout content in sandbox summary, which matches the core objective of the pull request.
Description check ✅ Passed The description comprehensively covers all required template sections: PR checklist, current behavior, new behavior, linked issue reference, and reviewer notes with validation attempts and scope clarification.
Linked Issues check ✅ Passed The pull request fully addresses the requirements in #1140: prevents stdout/stderr duplication in summary, keeps full content in structured fields, includes metadata-only summary with exit code, duration, capture mode, and byte counts.
Out of Scope Changes check ✅ Passed All changes are properly scoped to addressing the linked issue: refactoring formatStreamOutput to formatStreamSummary in toolkit.ts and adding a changeset file for release metadata, with no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

@SergioChan
Copy link
Copy Markdown
Contributor Author

Added a changeset in this branch to satisfy release/versioning checks:\n- .changeset/tidy-summary-no-dup.md (: patch)\n\nNo code-path changes beyond the original fix.

@SergioChan
Copy link
Copy Markdown
Contributor Author

Correction to my previous note (shell ate backticks):

Added changeset file: .changeset/tidy-summary-no-dup.md
Package bump: @voltagent/core -> patch

No runtime behavior changes in this follow-up commit; this is release metadata only.

@omeraplak
Copy link
Copy Markdown
Member

Hey @SergioChan ,
Thank you so much!! I'll release it soon 🔥

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/workspace/sandbox/toolkit.ts`:
- Around line 244-256: formatStreamSummary currently only shows eviction error
when info.evicted is true, but evictStream() sets info.error on fallback results
with evicted: false so errors get dropped and the message falls back to
"captured inline"; update formatStreamSummary to preserve and display
failed-eviction metadata: if info.error exists (regardless of info.evicted)
include the attempted save path (info.path if present) and the eviction error
note, and when evicted is false but path exists and error exists, render a
message like "<label>: attempted save to <path> failed (eviction error: <error>,
<bytes> bytes...)" so failed write attempts are distinguishable from normal
inline captures; modify the logic in formatStreamSummary (which consumes
StreamEvictionResult returned by evictStream) to check info.error before falling
back to inline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a42d1a3a-1e4c-43b2-9040-5415c5f17551

📥 Commits

Reviewing files that changed from the base of the PR and between faa5023 and 1ef3e76.

📒 Files selected for processing (1)
  • packages/core/src/workspace/sandbox/toolkit.ts

Comment on lines +244 to +256
const formatStreamSummary = (label: string, info: StreamEvictionResult): string => {
if (info.evicted && info.path) {
const note = info.truncated ? " (truncated)" : "";
lines.push(`${label}: saved to ${info.path} (${info.bytes} bytes${note})`);
if (info.error) {
lines.push(`${label} eviction error: ${info.error}`);
}
return lines;
const note = info.truncated ? ", truncated" : "";
const errorNote = info.error ? `, eviction error: ${info.error}` : "";
return `${label}: saved to ${info.path} (${info.bytes} bytes${note}${errorNote})`;
}

if (info.content) {
lines.push(`${label}:`);
lines.push(info.content);
return lines;
const note = info.truncated ? ", truncated" : "";
return `${label}: captured inline (${info.bytes} bytes${note})`;
}

lines.push(`${label}: (empty)`);
return lines;
return `${label}: (empty)`;
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.

⚠️ Potential issue | 🟡 Minor

Preserve failed-eviction metadata in the summary.

evictStream() only sets info.error on fallback results with evicted: false, so the errorNote here never renders. When a write fails, this formatter falls through to "captured inline" and drops both the attempted save path and the eviction failure, which makes that case indistinguishable from a normal inline capture.

Suggested fix
 const formatStreamSummary = (label: string, info: StreamEvictionResult): string => {
+  const note = info.truncated ? ", truncated" : "";
+
   if (info.evicted && info.path) {
-    const note = info.truncated ? ", truncated" : "";
-    const errorNote = info.error ? `, eviction error: ${info.error}` : "";
-    return `${label}: saved to ${info.path} (${info.bytes} bytes${note}${errorNote})`;
+    return `${label}: saved to ${info.path} (${info.bytes} bytes${note})`;
+  }
+
+  if (info.path && info.error) {
+    return `${label}: captured inline after save to ${info.path} failed (${info.bytes} bytes${note}, eviction error: ${info.error})`;
   }
 
   if (info.content) {
-    const note = info.truncated ? ", truncated" : "";
     return `${label}: captured inline (${info.bytes} bytes${note})`;
   }
 
   return `${label}: (empty)`;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const formatStreamSummary = (label: string, info: StreamEvictionResult): string => {
if (info.evicted && info.path) {
const note = info.truncated ? " (truncated)" : "";
lines.push(`${label}: saved to ${info.path} (${info.bytes} bytes${note})`);
if (info.error) {
lines.push(`${label} eviction error: ${info.error}`);
}
return lines;
const note = info.truncated ? ", truncated" : "";
const errorNote = info.error ? `, eviction error: ${info.error}` : "";
return `${label}: saved to ${info.path} (${info.bytes} bytes${note}${errorNote})`;
}
if (info.content) {
lines.push(`${label}:`);
lines.push(info.content);
return lines;
const note = info.truncated ? ", truncated" : "";
return `${label}: captured inline (${info.bytes} bytes${note})`;
}
lines.push(`${label}: (empty)`);
return lines;
return `${label}: (empty)`;
const formatStreamSummary = (label: string, info: StreamEvictionResult): string => {
const note = info.truncated ? ", truncated" : "";
if (info.evicted && info.path) {
return `${label}: saved to ${info.path} (${info.bytes} bytes${note})`;
}
if (info.path && info.error) {
return `${label}: captured inline after save to ${info.path} failed (${info.bytes} bytes${note}, eviction error: ${info.error})`;
}
if (info.content) {
return `${label}: captured inline (${info.bytes} bytes${note})`;
}
return `${label}: (empty)`;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/workspace/sandbox/toolkit.ts` around lines 244 - 256,
formatStreamSummary currently only shows eviction error when info.evicted is
true, but evictStream() sets info.error on fallback results with evicted: false
so errors get dropped and the message falls back to "captured inline"; update
formatStreamSummary to preserve and display failed-eviction metadata: if
info.error exists (regardless of info.evicted) include the attempted save path
(info.path if present) and the eviction error note, and when evicted is false
but path exists and error exists, render a message like "<label>: attempted save
to <path> failed (eviction error: <error>, <bytes> bytes...)" so failed write
attempts are distinguishable from normal inline captures; modify the logic in
formatStreamSummary (which consumes StreamEvictionResult returned by
evictStream) to check info.error before falling back to inline.

@omeraplak omeraplak merged commit 0f7ee7c into VoltAgent:main Mar 6, 2026
22 of 23 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.

[BUG] Sandbox tool: Redundant token usage due to repeated content in stdout and summary

2 participants