feat(chat): enhance resumeStream handling to manage transient status during stream resumption

This commit is contained in:
DIYgod 2025-11-06 17:41:15 +08:00
parent 264bd711e6
commit 959904d72e
No known key found for this signature in database
2 changed files with 28 additions and 0 deletions

View File

@ -17,6 +17,17 @@ export class ZustandChat extends AbstractChat<BizUIMessage> {
const state = new ZustandChatState(messages, updateZustandState, init.id || "")
super({ ...init, state })
this.state = state
const baseResumeStream = this.resumeStream.bind(this)
// Track resume calls so the state can ignore the temporary "submitted" status when no stream exists.
this.resumeStream = async (...args) => {
this.state.setResumingStream(true)
try {
return await baseResumeStream(...args)
} finally {
this.state.setResumingStream(false)
}
}
}
// Public getter for state access

View File

@ -15,6 +15,7 @@ export class ZustandChatState implements ChatState<BizUIMessage> {
#status: ChatStatus = "ready"
#error: Error | undefined = undefined
#eventEmitter = new ChatStateEventEmitter()
#isResumingStream = false
constructor(
initialMessages: BizUIMessage[] = [],
@ -61,12 +62,24 @@ export class ZustandChatState implements ChatState<BizUIMessage> {
})
this.#eventEmitter.on("status", ({ status }) => {
// Suppress the transient "submitted" status emitted when resumeStream probes for an active stream.
if (this.#isResumingStream && status === "submitted") {
return
}
this.updateZustandState((state) => {
const isStreaming = status === "streaming"
if (isStreaming) {
void state.chatActions.markSessionSynced()
}
if (
this.#isResumingStream &&
(status === "ready" || status === "streaming" || status === "error")
) {
this.#isResumingStream = false
}
return {
...state,
status,
@ -185,4 +198,8 @@ export class ZustandChatState implements ChatState<BizUIMessage> {
destroy(): void {
this.#eventEmitter.clear()
}
setResumingStream(isResuming: boolean) {
this.#isResumingStream = isResuming
}
}