import assert from "node:assert/strict"; import test from "node:test"; import { makeFreshTab } from "../src/features/agent/messages/helpers"; import { runWorkspaceEffect, type WorkspaceEffectDeps, } from "../src/features/agent/workspace/effects"; import type { WorkspaceState } from "../src/features/agent/workspace/types"; function storage(): Pick & { values: Map; } { const values = new Map(); return { values, getItem: (key) => values.get(key) ?? null, setItem: (key, value) => values.set(key, value), removeItem: (key) => values.delete(key), }; } function workspace(session: ReturnType): WorkspaceState { return { sessions: new Map([[session.id, session]]), models: [], selectedModel: "", modelsLoading: false, layout: { kind: "leaf", paneId: "pane" }, panesById: new Map([["pane", { sessionId: session.id }]]), focusedPaneId: "pane", setupWarning: "", error: "", hydrated: true, lastHandledNavKey: "", }; } function depsFor(store: ReturnType): WorkspaceEffectDeps { return { storage: store, window: { Event, dispatchEvent: () => true }, api: {}, queueReplay: () => undefined, }; } function persistedText(store: ReturnType, piSessionId: string): string { const raw = store.values.get(`local-studio.agent.transcript.v2.${piSessionId}`); assert.ok(raw); const parsed = JSON.parse(raw) as { messages: Array<{ text: string }> }; return parsed.messages.at(-1)?.text ?? ""; } test("settled transcript persistence detects same-length assistant output changes", () => { const store = storage(); const first = makeFreshTab(); const session = { ...first, piSessionId: "pi-signature", status: "idle" as const, messages: [ { id: "user", role: "user" as const, text: "prompt" }, { id: "assistant", role: "assistant" as const, text: "old", blocks: [{ kind: "text" as const, id: "text", text: "old" }], }, ], }; const previous = workspace(session); const nextSession = { ...session, messages: session.messages.map((message) => message.role === "assistant" ? { ...message, text: "new", blocks: [{ kind: "text" as const, id: "text", text: "new" }] } : message, ), }; const next = workspace(nextSession); runWorkspaceEffect( { type: "patchSession", sessionId: session.id, patch: {} }, previous, next, depsFor(store), ); assert.equal(persistedText(store, "pi-signature"), "new"); }); test("settled transcript persistence detects changes before the last message", () => { const store = storage(); const first = makeFreshTab(); const session = { ...first, piSessionId: "pi-earlier", status: "idle" as const, messages: [ { id: "user", role: "user" as const, text: "old prompt" }, { id: "assistant", role: "assistant" as const, text: "answer", blocks: [{ kind: "text" as const, id: "text", text: "answer" }], }, ], }; const previous = workspace(session); const nextSession = { ...session, messages: [{ ...session.messages[0], text: "new prompt" }, session.messages[1]], }; const next = workspace(nextSession); runWorkspaceEffect( { type: "patchSession", sessionId: session.id, patch: {} }, previous, next, depsFor(store), ); const raw = store.values.get("local-studio.agent.transcript.v2.pi-earlier"); assert.ok(raw); const parsed = JSON.parse(raw) as { messages: Array<{ text: string }> }; assert.equal(parsed.messages[0]?.text, "new prompt"); });