fix: Preserve readable agent result reports

Agent task notifications carry the user-facing Markdown report, while some Agent tool results contain structured intermediate payloads. The UI now keeps the terminal report as the modal/preview source when it exists, and falls back to raw tool output only when there is no report.

Constraint: Background Agent runs can emit structured tool_result payloads before the terminal task notification carries the readable Markdown report
Rejected: Convert every structured Agent payload into display Markdown | risks inventing summaries and still lets raw transport data compete with the real report
Confidence: high
Scope-risk: narrow
Directive: Do not let raw Agent tool_result content override terminal task result when both are present
Tested: cd desktop && bun run test -- run src/components/chat/MessageList.test.tsx -t "prefers the terminal task report"
Tested: cd desktop && bun run test -- run src/components/chat/MessageList.test.tsx -t agent
Not-tested: Full desktop gate per request to avoid broad gate/test runs
This commit is contained in:
程序员阿江(Relakkes) 2026-05-19 03:32:34 +08:00
parent 2323e6ec47
commit 430edc436e
2 changed files with 62 additions and 1 deletions

View File

@ -1075,6 +1075,65 @@ describe('MessageList nested tool calls', () => {
expect(within(screen.getByRole('dialog')).getByText(resultText)).toBeTruthy()
})
it('prefers the terminal task report over structured agent tool result JSON', () => {
const markdownReport = '## 审查安全风险\n\n- 最终报告应该按 Markdown 展示。'
useChatStore.setState({
sessions: {
[ACTIVE_TAB]: makeSessionState({
messages: [
{
id: 'tool-agent',
type: 'tool_use',
toolName: 'Agent',
toolUseId: 'agent-1',
input: { description: '查看安全报告' },
timestamp: 1,
},
{
id: 'result-agent',
type: 'tool_result',
toolUseId: 'agent-1',
content: {
results: [
{
file: 'git:v0.2.6..v0.2.7',
line: 0,
snippet: 'raw structured JSON should not be shown',
context: '结构化检索结果不是给用户看的最终报告。',
},
],
},
isError: false,
timestamp: 2,
},
],
agentTaskNotifications: {
'agent-1': {
taskId: 'agent-task-1',
toolUseId: 'agent-1',
status: 'completed',
summary: 'Agent "审查安全风险" completed',
result: markdownReport,
},
},
}),
},
})
render(<MessageList />)
expect(screen.getByText(/最终报告应该按 Markdown 展示。/)).toBeTruthy()
expect(screen.queryByText(/raw structured JSON should not be shown/)).toBeNull()
fireEvent.click(screen.getByRole('button', { name: 'View result' }))
const dialog = screen.getByRole('dialog')
expect(within(dialog).getByRole('heading', { name: '审查安全风险' })).toBeTruthy()
expect(within(dialog).getByText('最终报告应该按 Markdown 展示。')).toBeTruthy()
expect(within(dialog).queryByText(/raw structured JSON should not be shown/)).toBeNull()
})
it('renders copy controls for user messages and scopes assistant copy to a single reply', async () => {
const writeText = vi.fn().mockResolvedValue(undefined)
Object.assign(navigator, {

View File

@ -517,7 +517,9 @@ function AgentCallCard({
result && !result.isError && !isLaunchResult && !isAgentLifecycleResult(result.content)
? extractAgentDisplayText(result.content).trim()
: ''
const previewText = fullOutputText || (status === 'done' || status === 'stopped' ? taskResult || taskSummary : '')
const terminalTaskReport = status === 'done' || status === 'stopped' ? taskResult : ''
const terminalTaskSummary = status === 'done' || status === 'stopped' ? taskSummary : ''
const previewText = terminalTaskReport || fullOutputText || terminalTaskSummary
const outputSummary = previewText ? getAgentOutputSummary(previewText) : ''
const description = typeof input.description === 'string' ? input.description : ''