Skip to content

ui: subagent tool result body is rendered raw — markdown shows as literal **/##/code-fences #491

@esengine

Description

@esengine

Problem

spawn_subagent returns its child's final answer wrapped in a JSON envelope via formatSubagentResult (src/tools/subagent.ts:337):

return JSON.stringify({ success: true, output: r.output, turns, tool_iters, elapsed_ms, cost_usd });

That string becomes the tool result, which the TUI renders through ToolCard (src/cli/ui/cards/ToolCard.tsx). The card body just splits on \n and dumps the tail through plain <Text> (ToolCard.tsx:70). No markdown pass, no JSON unwrap.

In practice the child loop is an LLM — its assistant_final is markdown by default: ## Headings, **bold**, bullet lists, fenced code blocks. Because we (a) JSON-stringify it and (b) render the JSON body as raw text, the user sees:

{"success":true,"output":"## Findings\n\n- \`src/foo.ts:42\` …\n\n\`\`\`ts\nfoo()\n\`\`\`\n", …}

— literal \n, literal backticks, literal **. The streaming reply path uses Markdown (StreamingCard.tsx:83); the subagent path doesn't.

What I want

When the tool name is spawn_subagent (and the result is a successful envelope), the card body should render output through the same Markdown component the streaming reply uses, not through raw Text. Failure envelopes can stay as-is — the error field is a single line.

Sketch:

  • In ToolCard, branch on card.name === "spawn_subagent". Parse the JSON; on a success: true shape with a string output, render <Markdown text={output} /> instead of the line-tail loop.
  • Keep the existing tail/clip behavior as a fallback for parse failures and for success: false.

Out of scope

  • Changing what formatSubagentResult returns. The model still wants the JSON envelope so it can read success, cost_usd, etc.; only the TUI projection needs to change.
  • Markdown rendering for every tool result. Most tools (read_file, run_command, …) emit code/log output where literal ** is correct.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomersrenderingTerminal rendering / flicker / repaint issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions