Agent chat: a tool result shows what its envelope holds besides its text

Merged
TE
14d ago
+306-66

Leo-ask: ask-16f0b7197f

Leo: "Bro, like, but can you just, like that JSON, it's so stupid. I mean, why is it wrapping it with that? Like, don't we have more rendering?"

Follow-up to #24030. #24030 unwraps a tool result's JSON envelope only when its text is all the envelope says, and leaves every other envelope as JSON. This PR unwraps those other envelopes too. The opened call shows the text first, then everything else the envelope holds as the JSON it is, so nothing is hidden.

What changes

conversation/toolResult.ts (peelEnvelope), used by the generic tool row and Find in Chat:

  • Blocks that are not text (images, audio, binary resources, resource links) follow the text as JSON.
  • A text resource reads as its URI and then its text.
  • MCP structuredContent follows the text as JSON. If a text block only repeats it, the text block gives way, unless that text holds a number a double would round.
  • A JSON-RPC error reads as its message, then its data. Any other error (a REST API's) reads as its message, then its other fields.
  • If any other part holds a number a double would change, or nests past the depth limit, the whole envelope shows as printed. JSON printed across lines still shows as printed.

conversation/mcpCalls.ts: the opened MCP call's response shows the same parts. It now keeps the structuredContent the base dropped. A value nested too deep to indent prints on one line.

Shell output is untouched. The strip for an envelope's images is the next PR (branch tp/unwrap-tool-json-images).

Before / after

Gallery entry agent-pane.transcript, variant tool-result-envelopes. The shots use synthetic fixtures this PR adds: an MCP result whose text repeats its structured content, and a JSON-RPC error with data. Before is base 4fcd827 with the same fixtures (branch tp/unwrap-tool-json-parts-before); after is cf78457. Both were captured on the Linux gallery in Chromium.

BeforeAfter
envelope parts before darkenvelope parts after dark
envelope parts before lightenvelope parts after light
  • "Look up the forecast" reads as its sentence, then its structured content once. The text block that repeated it is gone.
  • "Create issue" reads as its error message, then the error's data.

Tests

toolResult.test.ts covers:

  • rest parts shown as JSON after the text;
  • JSON-RPC and REST errors;
  • text resources;
  • structured-content dedup, including the precision exception;
  • the precision and depth fallbacks;
  • envelopes with nothing to read;
  • the MCP row.

Ran on huge-blue at 1fde885 (cf78457 adds only gallery fixtures): bun test src/agent-session/acpmux/conversation/ src/agent-session/acpmux/toolImages test/chat-find-matches.test.ts test/agent-pane-mcp-tool-rows.test.tsx, 217 pass, 1 fail. The failure is incomingMessage.test.ts, which is red on feat-cmux-next too and is a file this PR doesn't touch. vp fmt --check and vp lint are clean on the changed files.

Observed / Not run

  • Observed: the test run above, fmt and lint on the changed files, and the gallery capture above.
  • Not run: a native app capture. This change is in the webview only.

Agent session: cosmic-gray

🤖 Generated with Claude Code