|
@@ -871,13 +871,45 @@ export class ChatTranscriptStore {
|
|
|
} else if (['message.complete', 'run.completed', 'run.complete', 'run.failed', 'error'].includes(type)) {
|
|
} else if (['message.complete', 'run.completed', 'run.complete', 'run.failed', 'error'].includes(type)) {
|
|
|
// A replayed terminal snapshot updates the terminal slot. It never starts
|
|
// A replayed terminal snapshot updates the terminal slot. It never starts
|
|
|
// another turn (the next run.started/delta owns advancing the queue).
|
|
// another turn (the next run.started/delta owns advancing the queue).
|
|
|
|
|
+ // Hermes also closes each model segment with message.complete, including
|
|
|
|
|
+ // a tool round. That is not the end of the user-visible turn.
|
|
|
const old = current()
|
|
const old = current()
|
|
|
const wasTerminal = state.terminal
|
|
const wasTerminal = state.terminal
|
|
|
- state.terminal = false
|
|
|
|
|
const failed =
|
|
const failed =
|
|
|
['run.failed', 'error'].includes(type) || p.error || ['failed', 'error'].includes(p.status)
|
|
['run.failed', 'error'].includes(type) || p.error || ['failed', 'error'].includes(p.status)
|
|
|
const interrupted = ['interrupted', 'cancelled', 'canceled'].includes(p.status)
|
|
const interrupted = ['interrupted', 'cancelled', 'canceled'].includes(p.status)
|
|
|
|
|
+ const finish = String(
|
|
|
|
|
+ p.finish_reason ?? p.finishReason ?? p.message?.finish_reason ?? p.message?.finishReason ?? '',
|
|
|
|
|
+ ).toLowerCase()
|
|
|
|
|
+ const payloadCalls = p.tool_calls ?? p.message?.tool_calls
|
|
|
|
|
+ const openTools =
|
|
|
|
|
+ !!state.turn &&
|
|
|
|
|
+ this.all(...scope).some(
|
|
|
|
|
+ (m) =>
|
|
|
|
|
+ m.turn_id === state.turn &&
|
|
|
|
|
+ (m.tool_calls as Data[] | undefined)?.some((t) =>
|
|
|
|
|
+ ['running', 'pending'].includes(String(t.status)),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ const explicitStop = ['stop', 'end', 'end_turn', 'length', 'content_filter'].includes(finish)
|
|
|
|
|
+ const toolRound =
|
|
|
|
|
+ ['tool_calls', 'tool_use', 'function_call'].includes(finish) ||
|
|
|
|
|
+ (Array.isArray(payloadCalls) && payloadCalls.length > 0)
|
|
|
|
|
+ const continues =
|
|
|
|
|
+ type === 'message.complete' && !failed && !interrupted && !explicitStop && (toolRound || openTools)
|
|
|
const output = p.output ?? p.text ?? p.content ?? p.message?.content
|
|
const output = p.output ?? p.text ?? p.content ?? p.message?.content
|
|
|
|
|
+ if (continues) {
|
|
|
|
|
+ if (old || output || p.attachments)
|
|
|
|
|
+ saveAssistant({
|
|
|
|
|
+ content: output === '' ? (old?.content ?? '') : (output ?? old?.content ?? ''),
|
|
|
|
|
+ status: 'streaming',
|
|
|
|
|
+ final_result: false,
|
|
|
|
|
+ })
|
|
|
|
|
+ state.running = true
|
|
|
|
|
+ state.terminal = false
|
|
|
|
|
+ state.queued = state.queue.length > 0 || Number(p.queue_remaining ?? 0) > 0
|
|
|
|
|
+ } else {
|
|
|
|
|
+ state.terminal = false
|
|
|
if (old || output || p.attachments)
|
|
if (old || output || p.attachments)
|
|
|
saveAssistant({
|
|
saveAssistant({
|
|
|
content: output === '' ? (old?.content ?? '') : (output ?? old?.content ?? ''),
|
|
content: output === '' ? (old?.content ?? '') : (output ?? old?.content ?? ''),
|
|
@@ -908,6 +940,7 @@ export class ChatTranscriptStore {
|
|
|
state.pendingClarification = null
|
|
state.pendingClarification = null
|
|
|
state.liveStatus = null
|
|
state.liveStatus = null
|
|
|
if (wasTerminal && state.queue.length === 0) state.running = false
|
|
if (wasTerminal && state.queue.length === 0) state.running = false
|
|
|
|
|
+ }
|
|
|
} else if (type === 'route.resumed') {
|
|
} else if (type === 'route.resumed') {
|
|
|
const inflight = p.inflight ?? {},
|
|
const inflight = p.inflight ?? {},
|
|
|
running = p.running === true || p.info?.running === true || inflight.streaming === true
|
|
running = p.running === true || p.info?.running === true || inflight.streaming === true
|