| 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 |