Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions cli/src/components/blocks/agent-branch-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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 {
Expand All @@ -429,7 +432,7 @@ export const AgentBranchWrapper = memo(
<box key={keyPrefix} style={{ flexDirection: 'column', gap: 0 }}>
<AgentBranchItem
name={agentBlock.agentName}
prompt={agentBlock.initialPrompt}
prompt={displayPrompt}
agentId={agentBlock.agentId}
isCollapsed={isCollapsed}
isStreaming={isStreaming}
Expand Down
66 changes: 66 additions & 0 deletions cli/src/utils/__tests__/agent-display.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, expect, test } from 'bun:test'

import { getAgentDisplayPrompt } from '../agent-display'

import type { AgentContentBlock } from '../../types/chat'

const createAgentBlock = (
overrides: Partial<AgentContentBlock>,
): 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()
})
})
34 changes: 34 additions & 0 deletions cli/src/utils/__tests__/sdk-event-handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
21 changes: 21 additions & 0 deletions cli/src/utils/agent-display.ts
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions cli/src/utils/sdk-event-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading