fix(ui): handle message.part.delta streaming

Wire message.part.delta SSE events into the v2 message store and append deltas onto existing part fields.
This commit is contained in:
Shantur Rathore
2026-02-15 00:54:31 +00:00
parent edd3ded1d8
commit 5067db3dd0
6 changed files with 93 additions and 5 deletions

View File

@@ -189,6 +189,7 @@ export interface InstanceMessageStore {
hydrateMessages: (sessionId: string, inputs: MessageUpsertInput[], infos?: Iterable<MessageInfo>) => void
upsertMessage: (input: MessageUpsertInput) => void
applyPartUpdate: (input: PartUpdateInput) => void
applyPartDelta: (input: { messageId: string; partId: string; field: string; delta: string; bumpRevision?: boolean }) => void
removeMessage: (messageId: string) => void
removeMessagePart: (messageId: string, partId: string) => void
bufferPendingPart: (entry: PendingPartEntry) => void
@@ -597,6 +598,45 @@ export function createInstanceMessageStore(instanceId: string, hooks?: MessageSt
bumpSessionRevision(message.sessionId)
}
function applyPartDelta(input: { messageId: string; partId: string; field: string; delta: string; bumpRevision?: boolean }) {
if (!input?.messageId || !input.partId || !input.field || typeof input.delta !== "string") {
return
}
const message = state.messages[input.messageId]
if (!message) {
// Best-effort: drop deltas for unknown messages.
return
}
let applied = false
setState(
"messages",
input.messageId,
produce((draft: MessageRecord) => {
const entry = draft.parts[input.partId]
if (!entry?.data) return
const part = entry.data as any
const currentValue = part?.[input.field]
if (typeof currentValue === "string" || currentValue === undefined || currentValue === null) {
part[input.field] = `${currentValue ?? ""}${input.delta}`
applied = true
}
if (!applied) return
entry.revision += 1
draft.updatedAt = Date.now()
if (input.bumpRevision ?? true) {
draft.revision += 1
}
}),
)
if (applied) {
bumpSessionRevision(message.sessionId)
}
}
function removeMessage(messageId: string) {
if (!messageId) return
@@ -1087,19 +1127,20 @@ export function createInstanceMessageStore(instanceId: string, hooks?: MessageSt
setState(reconcile(createInitialState(instanceId)))
}
return {
return {
instanceId,
state,
setState,
addOrUpdateSession,
hydrateMessages,
upsertMessage,
hydrateMessages,
upsertMessage,
applyPartUpdate,
applyPartDelta,
removeMessage,
removeMessagePart,
bufferPendingPart,
flushPendingParts,
flushPendingParts,
replaceMessageId,
setMessageInfo,
getMessageInfo,
@@ -1125,4 +1166,3 @@ export function createInstanceMessageStore(instanceId: string, hooks?: MessageSt
}
}