diff options
| author | Adam Malczewski <[email protected]> | 2026-10-21 15:36:54 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-10-21 15:36:54 +0900 |
| commit | ac43e92d174ed1f081c387944e9044643ee9efc2 (patch) | |
| tree | 3110ac7c1fa722ad6c092200ea02aead5384b5d3 /src/core/chunks/selectors.test.ts | |
| parent | e9786bf1dbf258b68f793870d02378c390939d3d (diff) | |
| download | dispatch-web-ac43e92d174ed1f081c387944e9044643ee9efc2.tar.gz dispatch-web-ac43e92d174ed1f081c387944e9044643ee9efc2.zip | |
fix(review-followup-fee): recover omitted chat payloads through history
Diffstat (limited to 'src/core/chunks/selectors.test.ts')
| -rw-r--r-- | src/core/chunks/selectors.test.ts | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/src/core/chunks/selectors.test.ts b/src/core/chunks/selectors.test.ts index 57c1415..05dcc4e 100644 --- a/src/core/chunks/selectors.test.ts +++ b/src/core/chunks/selectors.test.ts @@ -1,6 +1,6 @@ import type { AgentEvent, StepId, StoredChunk } from "@dispatch/wire"; import { describe, expect, it } from "vitest"; -import { applyHistory, foldEvent, initialState } from "./reducer"; +import { applyHistory, foldEvent, initialState, markHistoryRecovering } from "./reducer"; import { selectChunks } from "./selectors"; import type { TranscriptState } from "./types"; @@ -131,6 +131,34 @@ describe("selectChunks — de-dup of a late-join replay against committed histor expect(rendered.filter((r) => r.provisional)).toHaveLength(3); }); + it("preserves an uncommitted accumulating tail even when its text repeats history", () => { + const committed: StoredChunk[] = [ + ...committedStep0, + { seq: 5, role: "assistant", chunk: { type: "text", text: "final" }, turnId: T }, + ]; + let s = applyHistory(initialState(), committed); + s = markHistoryRecovering(s, T); + s = fold(s, [userMsg, turnStart, think("plan"), call("a"), result("a"), text("final")]); + const rendered = selectChunks(s); + expect(rendered).toHaveLength(6); + expect(rendered.slice(0, 5).every((r) => !r.provisional)).toBe(true); + expect(rendered[5]).toMatchObject({ + provisional: true, + streaming: true, + chunk: { type: "text", text: "final" }, + }); + }); + + it("reconciles the same step identity even when provisional payload differs", () => { + let s = applyHistory(initialState(), committedStep0); + s = markHistoryRecovering(s, T); + s = fold(s, [userMsg, turnStart, think("DIFFERENT"), call("a"), result("a")]); + const rendered = selectChunks(s); + // Authoritative identity wins; payload equality cannot identify omitted/truncated content. + expect(rendered.filter((r) => r.provisional)).toHaveLength(0); + expect(rendered.map((r) => r.chunk)).toEqual(committedStep0.map((r) => r.chunk)); + }); + it("does nothing when the committed tail belongs to another turn", () => { const other = committedStep0.map((c) => ({ ...c, turnId: "older" })); let s = applyHistory(initialState(), other); |
