From 1360e0dbcc815808eb031bc90829e8e42c1c5b87 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Mon, 11 May 2026 12:09:57 -0700 Subject: [PATCH] Show basher summary prompt in TUI --- .../blocks/agent-branch-wrapper.tsx | 11 ++-- cli/src/utils/__tests__/agent-display.test.ts | 66 +++++++++++++++++++ .../__tests__/sdk-event-handlers.test.ts | 34 ++++++++++ cli/src/utils/agent-display.ts | 21 ++++++ cli/src/utils/sdk-event-handlers.ts | 1 + 5 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 cli/src/utils/__tests__/agent-display.test.ts create mode 100644 cli/src/utils/agent-display.ts diff --git a/cli/src/components/blocks/agent-branch-wrapper.tsx b/cli/src/components/blocks/agent-branch-wrapper.tsx index d07355735..79c7b6ae0 100644 --- a/cli/src/components/blocks/agent-branch-wrapper.tsx +++ b/cli/src/components/blocks/agent-branch-wrapper.tsx @@ -17,6 +17,7 @@ import { ToolBlockGroup } from './tool-block-group' import { useTheme } from '../../hooks/use-theme' import { useChatStore } from '../../state/chat-store' import { isTextBlock } from '../../types/chat' +import { getAgentDisplayPrompt } from '../../utils/agent-display' import { getAgentStatusInfo } from '../../utils/agent-helpers' import { processBlocks, @@ -64,9 +65,10 @@ function getCollapsedPreview( } } - // Default preview: use initialPrompt or first line of text content - if (agentBlock.initialPrompt) { - return sanitizePreview(agentBlock.initialPrompt) + // Default preview: use the displayed prompt or first line of text content. + const displayPrompt = getAgentDisplayPrompt(agentBlock) + if (displayPrompt) { + return sanitizePreview(displayPrompt) } const textContent = @@ -413,6 +415,7 @@ export const AgentBranchWrapper = memo( // Compute collapsed preview text const preview = getCollapsedPreview(agentBlock, isStreaming, isCollapsed) + const displayPrompt = getAgentDisplayPrompt(agentBlock) const effectiveStatus = isStreaming ? 'running' : agentBlock.status const { @@ -429,7 +432,7 @@ export const AgentBranchWrapper = memo( , +): AgentContentBlock => ({ + type: 'agent', + agentId: 'agent-1', + agentName: 'Basher', + agentType: 'basher', + content: '', + status: 'running', + blocks: [], + initialPrompt: '', + ...overrides, +}) + +describe('getAgentDisplayPrompt', () => { + test('uses initial prompt when present', () => { + const block = createAgentBlock({ + initialPrompt: 'Run tests', + params: { + what_to_summarize: 'Summarize failures', + }, + }) + + expect(getAgentDisplayPrompt(block)).toBe('Run tests') + }) + + test('uses basher what_to_summarize when prompt is omitted', () => { + const block = createAgentBlock({ + params: { + command: 'bun test', + what_to_summarize: 'Summarize failing tests only', + }, + }) + + expect(getAgentDisplayPrompt(block)).toBe('Summarize failing tests only') + }) + + test('normalizes scoped and versioned basher agent ids', () => { + const block = createAgentBlock({ + agentType: 'codebuff/basher@1.0.0', + params: { + what_to_summarize: 'Summarize command output', + }, + }) + + expect(getAgentDisplayPrompt(block)).toBe('Summarize command output') + }) + + test('ignores non-basher what_to_summarize params', () => { + const block = createAgentBlock({ + agentName: 'code-searcher', + agentType: 'code-searcher', + params: { + what_to_summarize: 'This is not a basher prompt', + }, + }) + + expect(getAgentDisplayPrompt(block)).toBeUndefined() + }) +}) diff --git a/cli/src/utils/__tests__/sdk-event-handlers.test.ts b/cli/src/utils/__tests__/sdk-event-handlers.test.ts index b86566b43..c1e244265 100644 --- a/cli/src/utils/__tests__/sdk-event-handlers.test.ts +++ b/cli/src/utils/__tests__/sdk-event-handlers.test.ts @@ -295,6 +295,40 @@ describe('sdk-event-handlers', () => { expect(getStreamingAgents().size).toBe(0) }) + test('preserves spawn_agents params on placeholder agent blocks', () => { + const { ctx, getMessages, getStreamingAgents } = createTestContext() + const handleEvent = createEventHandler(ctx) + + handleEvent({ + type: 'tool_call', + toolCallId: 'tool-1', + toolName: 'spawn_agents', + input: { + agents: [ + { + agent_type: 'basher', + params: { + command: 'git status --short', + what_to_summarize: 'Report whether the worktree is clean', + }, + }, + ], + }, + agentId: 'main-agent', + parentAgentId: undefined, + } as any) + + const agentBlock = (getMessages()[0].blocks ?? [])[0] as AgentContentBlock + expect(agentBlock.agentId).toBe('tool-1-0') + expect(agentBlock.agentType).toBe('basher') + expect(agentBlock.initialPrompt).toBe('') + expect(agentBlock.params).toEqual({ + command: 'git status --short', + what_to_summarize: 'Report whether the worktree is clean', + }) + expect(getStreamingAgents().has('tool-1-0')).toBe(true) + }) + test('handles spawn_agents tool results and clears streaming agents', () => { const { ctx, getMessages, getStreamingAgents } = createTestContext() ctx.message.updater.addBlock( diff --git a/cli/src/utils/agent-display.ts b/cli/src/utils/agent-display.ts new file mode 100644 index 000000000..18c3668fd --- /dev/null +++ b/cli/src/utils/agent-display.ts @@ -0,0 +1,21 @@ +import { getAgentBaseName } from './message-block-helpers' + +import type { AgentContentBlock } from '../types/chat' + +export function getAgentDisplayPrompt( + agentBlock: AgentContentBlock, +): string | undefined { + const initialPrompt = agentBlock.initialPrompt?.trim() + if (initialPrompt) { + return initialPrompt + } + + if (getAgentBaseName(agentBlock.agentType) !== 'basher') { + return undefined + } + + const whatToSummarize = agentBlock.params?.what_to_summarize + return typeof whatToSummarize === 'string' && whatToSummarize.trim() + ? whatToSummarize.trim() + : undefined +} diff --git a/cli/src/utils/sdk-event-handlers.ts b/cli/src/utils/sdk-event-handlers.ts index 42c273a82..ca9ee14b6 100644 --- a/cli/src/utils/sdk-event-handlers.ts +++ b/cli/src/utils/sdk-event-handlers.ts @@ -285,6 +285,7 @@ const handleSpawnAgentsToolCall = ( agentId: `${event.toolCallId}-${originalIndex}`, agentType: agent.agent_type || '', prompt: agent.prompt, + params: agent.params, spawnToolCallId: event.toolCallId, spawnIndex: originalIndex, parentAgentType,