Render agent thoughts as markdown and fix tool-arg chip alignment in the process timeline (#4156)

This commit is contained in:
Cyrus Gray
2026-06-26 15:01:54 +05:30
committed by GitHub
parent 47bb17b67b
commit d6149bb88f
@@ -12,6 +12,7 @@ import {
stripToolCallEnvelopes,
} from '../../../utils/toolTimelineFormatting';
import { parseWorkerThreadRef } from '../utils/workerThreadRef';
import { BubbleMarkdown } from './AgentMessageBubble';
import { agentNameTone, AgentTimelineRail } from './AgentTimelineRail';
import { WorkerThreadRefCard, type WorkerThreadStatus } from './WorkerThreadRefCard';
@@ -99,20 +100,30 @@ function ToolCallRow({
}) {
const tone = toolCallTone(call.status);
return (
<div className="flex items-center gap-1.5" data-testid="subagent-tool-call">
<span className={`text-[11px] ${tone}`}></span>
<span className="text-[12px] text-content-secondary">
<div className="flex min-w-0 items-center gap-1.5" data-testid="subagent-tool-call">
<span aria-hidden className={`shrink-0 text-[11px] ${tone}`}>
</span>
<span className="shrink-0 text-[12px] whitespace-nowrap text-content-secondary">
{call.displayName ?? formatToolName(call.toolName)}
</span>
{/* The contextual arg (path / recipient / query) can be long, so it
truncates to a single line and absorbs the row's spare width — the
full value stays available on hover — instead of wrapping into a
multi-line box that knocks the name and status out of alignment. */}
{call.detail ? (
<span className="rounded bg-surface-subtle px-1 font-mono text-[11px] text-content-muted">
<span
title={call.detail}
className="min-w-0 truncate rounded bg-surface-subtle px-1 py-px font-mono text-[11px] text-content-muted">
{call.detail}
</span>
) : null}
{/* Status reads as a tinted "Done" / "Failed" / "Running" tag. */}
<StatusTag status={call.status} />
<span className="shrink-0">
<StatusTag status={call.status} />
</span>
{call.elapsedMs != null && call.status !== 'running' ? (
<span className="text-[11px] text-content-faint">
<span className="shrink-0 text-[11px] text-content-faint">
{call.elapsedMs >= 1000
? `${(call.elapsedMs / 1000).toFixed(1)}s`
: `${call.elapsedMs}ms`}
@@ -132,14 +143,21 @@ function ToolCallRow({
*/
function ThoughtBlock({ text }: { text: string }) {
// Drop any inline `<tool_call>…</tool_call>` envelope the model emitted as
// text — the call already shows as its own row — then flatten to one line.
const clean = stripToolCallEnvelopes(text).replace(/\s+/g, ' ').trim();
// text — the call already shows as its own row. Keep the original newlines
// (only trim the ends) so the markdown renderer can see headings, lists,
// code fences and emphasis instead of flattening them to one plain line.
const clean = stripToolCallEnvelopes(text).trim();
if (!clean) return null;
// Rendered through the shared `BubbleMarkdown` so a thought formats markdown
// (bold, code, lists) — but scaled back to the original quiet thought look:
// small (12px) and light/muted, not the larger, darker agent-bubble prose.
// Descendant overrides on `.prose` beat the typography plugin's base sizing;
// code keeps its accent colour so inline `tool_names` still read clearly.
return (
<div
data-testid="subagent-thought"
className="my-0.5 border-l-2 border-line pl-2 text-[12px] break-words text-content-muted italic">
{clean}
className="my-0.5 break-words [&_.prose]:text-[12px] [&_.prose]:leading-relaxed [&_.prose]:text-content-muted [&_.prose_strong]:text-content-muted [&_.prose_:is(h1,h2,h3,h4,h5,h6)]:text-[12px] [&_.prose_:is(h1,h2,h3,h4,h5,h6)]:text-content-muted">
<BubbleMarkdown content={clean} />
</div>
);
}