返回 DeepSeek-Reasonix
submission-projection.test.ts
根目录 / desktop / frontend / src / __tests__ / submission-projection.test.ts
1 import assert from "node:assert/strict";
2 import { initialState, reducer } from "../lib/useController";
3 import { entryToRecord, convertRecord } from "../lib/transcriptRecordProjection";
4 import { toolPresentation, type ToolItem } from "../lib/chatToolPresentation";
5 import { ChatSource } from "../lib/chatViewSource";
6
7 const record = entryToRecord({ entryId: "m:backend-user", turn: 1, order: 0, refs: [], message: {
8 role: "user", content: "same input", messageId: "backend-user", submissionId: "submit-1",
9 } });
10 const converted = convertRecord(record, { records: [record], indexOf: new Map([[record.entryId, 0]]), toolResultOwners: new Map() }, new Set());
11 const projection = { items: converted.items, removeIds: [], startTurn: 0, endTurn: 1, totalTurns: 1,
12 hasOlder: false, hasNewer: false, revision: 1, revisionKnown: true, digest: "cut" };
13 for (const eventFirst of [true, false]) {
14 let state = reducer({ ...initialState, transcriptProtocol: 2 }, { type: "user", seq: 0, text: "same input", submissionId: "submit-1" });
15 const event = { type: "event" as const, e: { kind: "user_message" as const, source: "executor" as const, messageId: "backend-user", submissionId: "submit-1", text: "same input" } };
16 if (eventFirst) {
17 state = reducer(state, event);
18 assert.equal(state.items.length, 0, "v2 admission binds identity without installing a durable row");
19 assert.equal(state.localSubmissions["submit-1"]?.messageId, "backend-user");
20 }
21 state = reducer(state, { type: "transcript_records", confirmedUsers: [], projection });
22 if (!eventFirst) state = reducer(state, event);
23 state = reducer(state, { type: "transcript_records", confirmedUsers: [], projection });
24 const users = state.items.filter(item => item.kind === "user");
25 assert.equal(users.length, 1);
26 assert.equal(users[0].id, "m:backend-user");
27 assert.equal(users[0].messageId, "backend-user");
28 assert.equal(state.localSubmissionOrder.length, 0);
29 state = reducer(state, { type: "user", seq: 1, text: "same input", submissionId: "submit-2" });
30 assert.equal(state.items.filter(item => item.kind === "user").length, 1);
31 assert.equal(state.localSubmissionOrder.length, 1);
32 }
33
34 {
35 let state = reducer({ ...initialState, transcriptProtocol: 2 }, { type: "user", seq: 0, text: "question", submissionId: "shared-submit" });
36 const first = { kind: "user" as const, id: "m:first", messageId: "first", submissionId: "shared-submit", text: "question" };
37 const second = { kind: "user" as const, id: "m:second", messageId: "second", submissionId: "shared-submit", text: "question" };
38 state = reducer(state, { type: "transcript_records", confirmedUsers: [], projection: { ...projection, items: [first, second] } });
39 assert.deepEqual(state.items.filter(item => item.kind === "user").map(item => item.id), ["m:first", "m:second"]);
40 assert.equal(state.localSubmissionOrder.length, 0, "one local echo is consumed at most once");
41 }
42
43 {
44 const source = new ChatSource("bounded-display-keys");
45 const local = { submissionId: "display-submit", localId: "u0", text: "question", createdAt: 1, sequence: 0, status: "sending" as const };
46 source.update({ items: [], localSubmissions: [local], running: true, hydrating: false, hasOlder: false, loadingOlder: false });
47 assert.ok(source.getOrderSnapshot().includes("submission:display-submit"));
48 source.update({ items: [{ kind: "user", id: "m:display", messageId: "display", submissionId: "display-submit", text: "question" }],
49 localSubmissions: [], running: true, hydrating: false, hasOlder: false, loadingOlder: false });
50 assert.ok(source.getOrderSnapshot().includes("submission:display-submit"), "canonical handoff inherits the mounted presentation key");
51 source.update({ items: [], localSubmissions: [], running: false, hydrating: false, hasOlder: false, loadingOlder: false });
52 source.update({ items: [{ kind: "user", id: "m:reloaded", messageId: "reloaded", submissionId: "display-submit", text: "question" }],
53 localSubmissions: [], running: false, hydrating: false, hasOlder: false, loadingOlder: false });
54 assert.ok(source.getOrderSnapshot().includes("m:reloaded"), "reloaded history uses a fresh durable presentation key after reclaim");
55 source.dispose();
56 }
57 const shell: ToolItem = { kind: "tool", id: "call", name: "bash", args: "{}", status: "done", readOnly: false };
58 assert.equal(toolPresentation(shell).label, "chat.unknown");
59 assert.equal(toolPresentation({ ...shell, status: "stopped" }).dot, "warning");
60 assert.equal(toolPresentation({ ...shell, execution: { kind: "shell", supportsAndAnd: true, state: "timed_out", exitCode: 0 } }).label, "chat.timedOut");
61 assert.equal(toolPresentation({ ...shell, execution: { kind: "shell", supportsAndAnd: true, state: "completed", exitCode: 0 } }).dot, "done");
62 console.log("submission identity ordering and authoritative tool states passed");
63
63 lines TYPESCRIPT