fix: derive run status from final result

This commit is contained in:
mesalogo
2026-08-15 21:17:17 +08:00
parent 939c3ab1b1
commit 0b96400e51
5 changed files with 99 additions and 8 deletions
+52
View File
@@ -162,6 +162,58 @@ describe('ActivityPanel', () => {
).toHaveLength(2)
})
it('uses the latest top-level Agent result for conversation status', () => {
const request: ActivityRecord = {
...makeRecord(1, 'running'),
conversationId: 'conversation-status',
requestId: 'request-status',
kind: 'request',
title: '最终成功的任务'
}
const failedTool: ActivityRecord = {
...makeRecord(2, 'failed'),
conversationId: request.conversationId,
requestId: request.requestId,
kind: 'tool',
title: '中间失败的工具'
}
const cancelledSubagent: ActivityRecord = {
...makeRecord(3, 'cancelled'),
conversationId: request.conversationId,
requestId: request.requestId,
kind: 'subagent',
title: '已取消的子专家'
}
const result: ActivityRecord = {
...makeRecord(4, 'completed'),
conversationId: request.conversationId,
requestId: request.requestId,
kind: 'result',
title: '任务执行完成'
}
render(
<ActivityPanel
onClear={vi.fn()}
onOpenConversation={vi.fn()}
records={[result, cancelledSubagent, failedTool, request]}
tokenUsage={makeTokenUsage()}
/>
)
const conversation = screen
.getByText('对话:最终成功的任务')
.closest('summary')
expect(conversation).not.toBeNull()
if (!conversation) {
return
}
expect(within(conversation).getByText('已完成')).toBeInTheDocument()
expect(within(conversation).queryByText('失败')).not.toBeInTheDocument()
expect(
within(conversation).queryByText('已取消')
).not.toBeInTheDocument()
})
it('filters active and exceptional activity and opens its conversation', () => {
const onOpenConversation = vi.fn()
render(
+35 -3
View File
@@ -127,9 +127,32 @@ function activityScopeKey(scope: ActivityRecord['scope']): string {
function conversationStatus(
records: readonly ActivityRecord[]
): ActivityRecord['status'] {
const latestRecord = (
candidates: readonly ActivityRecord[]
): ActivityRecord | undefined =>
candidates.reduce<ActivityRecord | undefined>(
(latest, record) =>
!latest || record.createdAt > latest.createdAt ? record : latest,
undefined
)
const latestRequest = latestRecord(
records.filter((record) => record.kind === 'request')
)
if (latestRequest) {
const latestResult = latestRecord(
records.filter(
(record) =>
record.kind === 'result' &&
record.requestId === latestRequest.requestId
)
)
return latestResult?.status ?? latestRequest.status
}
return (
records.find(isActive)?.status ??
records.find(isFailed)?.status ??
latestRecord(records.filter((record) => record.kind === 'result'))
?.status ??
latestRecord(records)?.status ??
'completed'
)
}
@@ -154,6 +177,13 @@ function groupActivityRecordsByProject(
allRecords: readonly ActivityRecord[]
): ProjectActivityGroup[] {
const conversationTitles = getConversationTitles(allRecords)
const allConversationRecords = new Map<string, ActivityRecord[]>()
for (const record of allRecords) {
const conversationRecords =
allConversationRecords.get(record.conversationId) ?? []
conversationRecords.push(record)
allConversationRecords.set(record.conversationId, conversationRecords)
}
const projectGroups = new Map<
string,
{
@@ -186,7 +216,9 @@ function groupActivityRecordsByProject(
conversationTitles.get(conversationId) ?? items[0]!.title,
records: items,
latestAt: Math.max(...items.map((record) => record.createdAt)),
status: conversationStatus(items)
status: conversationStatus(
allConversationRecords.get(conversationId) ?? items
)
})
)
return {