feat(chat): collapse tool calls by run
Build / build (push) Canceled after 0s
Playwright / e2e (push) Canceled after 0s

This commit is contained in:
2026-11-05 11:40:51 +08:00
parent 276e2389d6
commit 1bdef36577
8 changed files with 56 additions and 3 deletions
@@ -492,6 +492,10 @@ defineExpose({
</template>
<template #item="{ message: msg }">
<div v-if="msg.systemType === 'run-end'" class="run-end" role="separator">{{ t('chat.runOutputEnded') }}</div>
<details v-else-if="msg.systemType === 'tool-group'" class="tool-group">
<summary>{{ t('chat.toolCallsGroup', { count: msg.toolMessages.length }) }}</summary>
<MessageItem v-for="tool in msg.toolMessages" :key="tool.id" :message="tool" />
</details>
<div v-else-if="msg.systemType === 'fork-divider' && forkLineage" class="fork-divider" role="separator">
<div class="fork-divider-line" aria-hidden="true"></div>
<div class="fork-divider-pill">
@@ -617,6 +621,8 @@ defineExpose({
></span>
</div>
<!-- Tool calls -->
<details v-if="visibleToolCalls.length" class="tool-group live-tool-group">
<summary>{{ t('chat.toolCallsGroup', { count: visibleToolCalls.length }) }}</summary>
<div
v-for="tc in visibleToolCalls"
:key="tc.id"
@@ -688,6 +694,7 @@ defineExpose({
/>
</svg>
</div>
</details>
</div>
</div>
</Transition>
@@ -875,6 +882,21 @@ defineExpose({
<style scoped lang="scss">
@use "@/styles/variables" as *;
.tool-group {
color: var(--color-text-3);
> summary {
cursor: pointer;
padding: 8px 0;
font-size: 13px;
user-select: none;
}
}
.live-tool-group {
width: 100%;
}
.run-end {
margin: 20px auto;
text-align: center;
@@ -20,7 +20,9 @@ export function groupRunMessages(messages: Message[], runActive: boolean): Messa
isStreaming: assistants.some(m => m.isStreaming),
})
}
result.push(...tools)
if (tools.length) {
result.push({ id: `tool-group-${tools[0].id}`, role: 'system', content: '', timestamp: tools[0].timestamp, systemType: 'tool-group', toolMessages: tools })
}
if (completed && assistants.length) {
result.push({ id: `run-end-${assistants[0].id}`, role: 'system', content: '', timestamp: assistants[assistants.length - 1].timestamp, systemType: 'run-end' })
}
+1
View File
@@ -459,6 +459,7 @@ export default {
// Chat
chat: {
toolCallsGroup: 'Tool calls ({count})',
runOutputEnded: 'Run output ended',
messageLoadFailed: 'Could not load this conversation. Please retry.',
contextRemaining: 'remaining',
+1
View File
@@ -459,6 +459,7 @@ export default {
// 对话
chat: {
toolCallsGroup: '工具调用({count} 次)',
runOutputEnded: '本轮输出结束',
messageLoadFailed: '会话加载失败,请重试。',
contextRemaining: '剩余',
+2 -1
View File
@@ -63,7 +63,8 @@ export interface Message {
// 不含 <think> 包裹标签;内容自身可以为多段纯文本。
reasoning?: string
queued?: boolean
systemType?: 'command' | 'error' | 'fork-divider' | 'run-end'
systemType?: 'command' | 'error' | 'fork-divider' | 'run-end' | 'tool-group'
toolMessages?: Message[]
commandAction?: string
commandData?: Record<string, unknown>
finishReason?: string | null