-
-
{languageLabel}
+
+ {label ? (
+ <>
+ {label}
+ ·
+ >
+ ) : null}
+
+ {languageLabel}
+
{lineCountLabel}
diff --git a/desktop/src/components/chat/MessageList.test.tsx b/desktop/src/components/chat/MessageList.test.tsx
index db0d3820..9cd52e34 100644
--- a/desktop/src/components/chat/MessageList.test.tsx
+++ b/desktop/src/components/chat/MessageList.test.tsx
@@ -1545,6 +1545,15 @@ describe('MessageList nested tool calls', () => {
expect(screen.queryByText(/Read .*example\.ts.*done/i)).toBeNull()
fireEvent.click(screen.getByRole('button', { name: /dispatched an agent/i }))
expect(screen.getByText(/Read .*example\.ts.*done/i)).toBeTruthy()
+
+ const agentRow = container.querySelector('[data-agent-call-layout="row"]')
+ expect(agentRow).toBeTruthy()
+ expect(agentRow?.className).not.toMatch(/\b(?:border|rounded)-/)
+
+ fireEvent.click(screen.getByRole('button', { name: 'Expand agent' }))
+ const nestedToolRow = container.querySelector('[data-tool-call-chrome="row"]')
+ expect(nestedToolRow).toBeTruthy()
+ expect(nestedToolRow?.textContent).toContain('Read')
expect(container.textContent).toContain('Agent')
})
diff --git a/desktop/src/components/chat/ToolCallBlock.tsx b/desktop/src/components/chat/ToolCallBlock.tsx
index 842650c5..084ebb30 100644
--- a/desktop/src/components/chat/ToolCallBlock.tsx
+++ b/desktop/src/components/chat/ToolCallBlock.tsx
@@ -20,8 +20,8 @@ import {
/**
* `card` is the standalone bordered block. `row` strips the border, the ink icon
* square and the bold name so the call reads as one line inside an expanded
- * activity group — the fix for "one card per tool call" (#1177). Its own output
- * still gets a card, but only once the row is expanded.
+ * activity group. Expanded row details stay inline on a nested guide instead of
+ * rebuilding the card stack that the activity-group treatment removed (#1177).
*/
export type ToolCallChrome = 'card' | 'row'
@@ -156,8 +156,14 @@ export const ToolCallBlock = memo(function ToolCallBlock({ toolName, input, resu
)
const liveStatsSummary = liveStats ? formatContentStats(liveStats, t) : ''
- const preview = useMemo(() => renderPreview(toolName, obj, result, t), [obj, result, toolName, t])
- const details = useMemo(() => renderDetails(toolName, obj, t, isPending ? partialInput : undefined), [isPending, obj, partialInput, toolName, t])
+ const preview = useMemo(
+ () => renderPreview(toolName, obj, result, t, isRow),
+ [isRow, obj, result, toolName, t],
+ )
+ const details = useMemo(
+ () => renderDetails(toolName, obj, t, isPending ? partialInput : undefined, isRow),
+ [isPending, isRow, obj, partialInput, toolName, t],
+ )
const hasResultDetails = Boolean(result && extractTextContent(result.content))
const hasEditPreview = toolName === 'Edit' && typeof obj.old_string === 'string' && typeof obj.new_string === 'string'
const hasWritePreview = toolName === 'Write' && typeof obj.content === 'string'
@@ -211,13 +217,16 @@ export const ToolCallBlock = memo(function ToolCallBlock({ toolName, input, resu
}
return (
-
+