Skip to content

fix(terminal): truncate console values by size and cycles, not nesting depth#4924

Merged
waleedlatif1 merged 1 commit into
stagingfrom
fix/log-truncation
Jun 9, 2026
Merged

fix(terminal): truncate console values by size and cycles, not nesting depth#4924
waleedlatif1 merged 1 commit into
stagingfrom
fix/log-truncation

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Terminal output panel showed [Truncated object] for tiny payloads (e.g. a ~400-byte CRM deal row) because normalizeConsoleValue replaced any value at nesting depth ≥ 6 with a marker — agent tool-call rows sit at exactly depth 6 (output → toolCalls → list[] → call → result → rows[] → row), so they died purely from position, not size.
  • The depth cap was also doing double duty as the only guard against infinite recursion on circular structures (normalizeConsoleValue had no cycle protection of its own).
  • Added a path-tracked WeakSet so true ancestor cycles resolve to [Circular] while values shared across sibling positions still render fully, and raised MAX_DEPTH 6 → 12 as a pathological-nesting backstop. Actual size stays bounded by the existing 50KB per-string cap and 256KB whole-value byte cap.
  • Display-only fix: verified (PlanetScale) the persisted execution log externalizes full trace spans to blob storage and never produced this marker server-side.

Type of Change

  • Bug fix

Testing

  • Added unit tests: deep-but-small renders fully, true cycle → [Circular], shared sibling ref renders fully, backstop still truncates past MAX_DEPTH, byte cap still independent.
  • bunx vitest run stores/terminal/console/utils.test.ts stores/terminal/console/store.test.ts — 15 passed.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…g depth

normalizeConsoleValue replaced any value at depth >= 6 with
[Truncated object], discarding tiny payloads solely for their position
in the tree (agent tool-call rows sit at exactly depth 6). The depth
cap was also the only guard against infinite recursion on circular
structures.

Add a path-tracked WeakSet so true ancestor cycles resolve to
[Circular] while values shared across sibling positions still render
fully, and raise MAX_DEPTH to 12 as a pathological-nesting backstop.
Actual size stays bounded by the existing 50KB string cap and 256KB
byte cap.
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 9, 2026 6:03pm

Request Review

@cursor

cursor Bot commented Jun 9, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Display-only normalization in the terminal console store; existing byte and string caps remain, with added tests and no auth or persistence changes.

Overview
Fixes the terminal output panel showing [Truncated object] for small nested payloads (e.g. agent tool-call rows at depth 6) by changing how normalizeConsoleValue bounds recursion.

normalizeConsoleValue now tracks the current ancestor chain with a WeakSet (seen): true cycles become [Circular], while the same object referenced from sibling fields still renders fully (objects are removed from seen in a finally block after visiting children). MAX_DEPTH is raised 6 → 12 only as a backstop for pathological nesting; size limits (50KB strings, 256KB serialized cap via capNormalizedValue) are unchanged.

New unit tests cover tool-call-shaped nesting, cycles, shared references, depth backstop, and existing byte/string caps.

Reviewed by Cursor Bugbot for commit 18b10a6. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes premature [Truncated object] markers in the terminal output panel by replacing the old depth-only guard with two independent bounds: a path-tracking WeakSet for true ancestor cycles (add before processing, delete in finally), and a raised MAX_DEPTH 6 → 12 as a pathological-nesting backstop.

  • normalizeConsoleValue now threads a seen WeakSet through the recursion and deletes each entry in a finally block, so sibling references render fully while true cycles get [Circular].
  • MAX_DEPTH is raised from 6 to 12, unblocking agent tool-call rows (which sit at depth 6 in the output → toolCalls → list[] → call → result → rows[] chain).
  • Five new unit tests cover the reported regression, cycle detection, sibling reference rendering, the depth backstop, and the byte-cap path.

Confidence Score: 5/5

Safe to merge — the change is display-only, the algorithm is the standard ancestor-chain pattern, and the unit tests cover all the targeted edge cases.

The path-tracking WeakSet (add → recurse → delete in finally) is the correct standard algorithm for distinguishing true ancestor cycles from shared sibling references. The depth check short-circuits cleanly before the cycle check, so the two guards remain orthogonal. MAX_DEPTH=12 leaves a large enough safety margin while eliminating the spurious truncation at depth 6. safeConsoleStringify (unchanged) still uses a global non-path-tracking set, but since normalizeConsoleValue always materialises fresh output objects, that function is never handed shared-reference data in any of the three call sites.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/stores/terminal/console/utils.ts Adds path-tracking WeakSet cycle detection (seen.add / finally seen.delete) to normalizeConsoleValue; raises MAX_DEPTH from 6 to 12; all logic is correct and well-structured.
apps/sim/stores/terminal/console/utils.test.ts Adds five targeted tests: deep-but-small renders fully, true cycle to [Circular], shared sibling renders fully, MAX_DEPTH backstop truncates, byte cap is independent. Coverage is thorough.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[normalizeConsoleValue called] --> B{Primitive or null or Error?}
    B -- yes --> C[Return early]
    B -- no --> D{depth >= MAX_DEPTH?}
    D -- yes --> E[Return Truncated marker]
    D -- no --> F{seen.has objectValue?}
    F -- yes --> G[Return Circular marker]
    F -- no --> H[seen.add objectValue]
    H --> I{Array?}
    I -- yes --> J[Recurse items with depth+1 and seen]
    I -- no --> K[Recurse values with depth+1 and seen]
    J --> L[finally: seen.delete objectValue]
    K --> L
    L --> M[Return normalised value]
Loading

Reviews (1): Last reviewed commit: "fix(terminal): truncate console values b..." | Re-trigger Greptile

@waleedlatif1 waleedlatif1 merged commit 37f1141 into staging Jun 9, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/log-truncation branch June 9, 2026 18:10
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