50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
import type { Message } from '@/stores/hermes/chat'
|
|
|
|
// Group only within an uninterrupted turn. Tool rows remain available after
|
|
// the combined answer; user, command and system messages are hard boundaries.
|
|
export function groupRunMessages(messages: Message[], runActive: boolean): Message[] {
|
|
const result: Message[] = []
|
|
let assistants: Message[] = []
|
|
let tools: Message[] = []
|
|
let marker: string | null = null
|
|
|
|
function flush(completed: boolean) {
|
|
if (assistants.length) {
|
|
const first = assistants[0]
|
|
result.push({
|
|
...first,
|
|
toolMessages: tools.length ? tools : undefined,
|
|
contentSegments: assistants.map(m => m.content).filter(text => text.trim()),
|
|
id: assistants[assistants.length - 1].id,
|
|
content: assistants.map(m => m.content).filter(text => text.trim()).join('\n\n'),
|
|
reasoning: assistants.map(m => m.reasoning).filter(Boolean).join('\n\n') || undefined,
|
|
attachments: assistants.flatMap(m => m.attachments || []),
|
|
isStreaming: assistants.some(m => m.isStreaming),
|
|
})
|
|
}
|
|
if (tools.length && !assistants.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' })
|
|
}
|
|
assistants = []
|
|
tools = []
|
|
marker = null
|
|
}
|
|
|
|
for (const message of messages) {
|
|
if (message.role !== 'assistant' && message.role !== 'tool') {
|
|
flush(true)
|
|
result.push(message)
|
|
continue
|
|
}
|
|
if (marker && message.runMarker && marker !== message.runMarker) flush(true)
|
|
marker ||= message.runMarker || null
|
|
if (message.role === 'assistant') assistants.push(message)
|
|
else tools.push(message)
|
|
}
|
|
flush(!runActive)
|
|
return result
|
|
}
|