summaryrefslogtreecommitdiffhomepage
path: root/src/core/chunks/reducer.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-10-21 14:52:42 +0900
committerAdam Malczewski <[email protected]>2026-10-21 14:52:42 +0900
commite9786bf1dbf258b68f793870d02378c390939d3d (patch)
tree4cecca2c569ce374aabf071cfd33976c936f850e /src/core/chunks/reducer.ts
parent0bdb04b0aa0c0500e68e2e985b1a2880730ad7e8 (diff)
downloaddispatch-web-e9786bf1dbf258b68f793870d02378c390939d3d.tar.gz
dispatch-web-e9786bf1dbf258b68f793870d02378c390939d3d.zip
fix(review-followup-fed): reconcile compaction-queued send acknowledgements
Diffstat (limited to 'src/core/chunks/reducer.ts')
-rw-r--r--src/core/chunks/reducer.ts31
1 files changed, 27 insertions, 4 deletions
diff --git a/src/core/chunks/reducer.ts b/src/core/chunks/reducer.ts
index 0af2ddd..53af9c1 100644
--- a/src/core/chunks/reducer.ts
+++ b/src/core/chunks/reducer.ts
@@ -246,11 +246,17 @@ function reduceEvent(state: TranscriptState, event: AgentEvent): TranscriptState
// text) emits no `user-message` and is not de-duped here.
if (event.text.length === 0) return state;
const run = trailingRun(state.provisional, "user");
- const alreadyEchoed = run.some((p) => p.chunk.type === "text" && p.chunk.text === event.text);
- if (alreadyEchoed) {
+ const echoed = run.find((p) => p.chunk.type === "text" && p.chunk.text === event.text);
+ if (echoed !== undefined) {
return {
...state,
- provisional: tagTrailingUserEcho(state.provisional, event.turnId),
+ // Preserve the live text independently of the local send. A delayed
+ // queued ack may remove its images, but cannot erase this server event.
+ provisional: tagTrailingUserEcho(state.provisional, event.turnId).map((p) => {
+ if (p.chunk !== echoed.chunk || p.localRequestId === undefined) return p;
+ const { localRequestId: _local, ...confirmed } = p;
+ return confirmed;
+ }),
generating: true,
};
}
@@ -463,6 +469,7 @@ export function appendUserMessage(
state: TranscriptState,
text: string,
images?: readonly ImageInput[],
+ localRequestId?: string,
): TranscriptState {
const provisional = flushAccumulating(state.provisional, state.accumulating);
const userChunks: Chunk[] = [];
@@ -484,7 +491,23 @@ export function appendUserMessage(
}
return {
...state,
- provisional: [...provisional, ...userChunks.map((chunk) => ({ role: "user", chunk }) as const)],
+ provisional: [
+ ...provisional,
+ ...userChunks.map(
+ (chunk) =>
+ ({
+ role: "user",
+ chunk,
+ ...(localRequestId !== undefined ? { localRequestId } : {}),
+ }) as const,
+ ),
+ ],
accumulating: null,
};
}
+
+/** Remove only still-local artifacts of one accepted queued send; never history/live text. */
+export function removeLocalEcho(state: TranscriptState, requestId: string): TranscriptState {
+ const provisional = state.provisional.filter((p) => p.localRequestId !== requestId);
+ return provisional.length === state.provisional.length ? state : { ...state, provisional };
+}