From 2cedc443a50ca18ddde4532c75203640e0372871 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Thu, 16 Apr 2026 19:15:40 +0300 Subject: [PATCH] fix(sync): keep deltas after initial part.updated coalescing --- .../src/sync/__tests__/event-pipeline.test.js | 31 +++++++++++++++++++ packages/ui/src/sync/debug.ts | 2 +- packages/ui/src/sync/event-pipeline.ts | 5 --- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/packages/ui/src/sync/__tests__/event-pipeline.test.js b/packages/ui/src/sync/__tests__/event-pipeline.test.js index cbc32e85..afabd19a 100644 --- a/packages/ui/src/sync/__tests__/event-pipeline.test.js +++ b/packages/ui/src/sync/__tests__/event-pipeline.test.js @@ -336,6 +336,37 @@ describe('createEventPipeline', () => { expect(received[1].payload.type).toBe('message.part.updated'); }); + it('keeps text delta after an initial part.updated when no newer part.updated replaced it', async () => { + const received = await runPipelineWithEvents([ + { + directory: 'dir-a', + payload: { + type: 'message.part.updated', + properties: { + part: { id: 'part-1', type: 'text', messageID: 'msg-1' }, + }, + }, + }, + { + directory: 'dir-a', + payload: { + type: 'message.part.delta', + properties: { + messageID: 'msg-1', + partID: 'part-1', + field: 'text', + delta: 'hello', + }, + }, + }, + ]); + + expect(received).toHaveLength(2); + expect(received[0].payload.type).toBe('message.part.updated'); + expect(received[1].payload.type).toBe('message.part.delta'); + expect(received[1].payload.properties.delta).toBe('hello'); + }); + it('coalesces message.part.updated events for the same part', async () => { installDomStubs(); diff --git a/packages/ui/src/sync/debug.ts b/packages/ui/src/sync/debug.ts index f9dd69ba..f4191854 100644 --- a/packages/ui/src/sync/debug.ts +++ b/packages/ui/src/sync/debug.ts @@ -80,4 +80,4 @@ export const syncDebug = { eventApplied: (eventType: string, sessionID?: string, messageID?: string) => log("dispatch", "event → applied", { eventType, sessionID, messageID }), }, -} as const \ No newline at end of file +} as const diff --git a/packages/ui/src/sync/event-pipeline.ts b/packages/ui/src/sync/event-pipeline.ts index 5732ec2b..e91676b5 100644 --- a/packages/ui/src/sync/event-pipeline.ts +++ b/packages/ui/src/sync/event-pipeline.ts @@ -286,11 +286,6 @@ export function createEventPipeline(input: EventPipelineInput) { } d.coalesced.set(k, d.queue.length) } - if (normalizedPayload.type === "message.part.updated") { - const part = (normalizedPayload.properties as { part: { messageID: string; id: string } }).part - d.staleDeltas.add(deltaKey(part.messageID, part.id, "text")) - d.staleDeltas.add(deltaKey(part.messageID, part.id, "output")) - } d.queue.push(normalizedPayload) scheduleDir(routedDirectory)