import { describe, expect, it } from "vitest"; import type { ProviderEvent, ProviderSession } from "@t3tools/contracts";import { type WorkLogEntry, applyEventToMessages, derivePendingApprovals, deriveTurnDiffSummaries, deriveTimelineEntries, deriveWorkLogEntries, evolveSession,} from "./session-logic";import type { ChatMessage } from "./types"; function makeEvent(overrides: Partial<ProviderEvent>): ProviderEvent { return { id: "evt-1", kind: "notification", provider: "codex", sessionId: "sess-1", createdAt: "2026-02-08T10:00:00.000Z", method: "noop", ...overrides, };} function makeSession(overrides: Partial<ProviderSession> = {}): ProviderSession { return { sessionId: "sess-1", provider: "codex", status: "ready", createdAt: "2026-02-08T09:59:00.000Z", updatedAt: "2026-02-08T09:59:00.000Z", ...overrides, };} describe("deriveTimelineEntries", () => { it("interleaves messages and work entries by timestamp", () => { const messages: ChatMessage[] = [ { id: "m-user", role: "user", text: "Hi", createdAt: "2026-02-08T10:00:00.000Z", streaming: false, }, { id: "m-assistant", role: "assistant", text: "Hello", createdAt: "2026-02-08T10:05:00.000Z", streaming: false, }, ]; const workEntries: WorkLogEntry[] = [ { id: "w-1", label: "Tool call", createdAt: "2026-02-08T10:02:00.000Z", tone: "tool", }, { id: "w-2", label: "Preamble", createdAt: "2026-02-08T10:03:00.000Z", tone: "thinking", }, ]; const timeline = deriveTimelineEntries(messages, workEntries); expect(timeline.map((entry) => entry.id)).toEqual([ "message:m-user", "work:w-1", "work:w-2", "message:m-assistant", ]); }); it("prefers work entries when timestamps are equal", () => { const messages: ChatMessage[] = [ { id: "m-1", role: "assistant", text: "Done", createdAt: "2026-02-08T10:00:00.000Z", streaming: false, }, ]; const workEntries: WorkLogEntry[] = [ { id: "w-1", label: "Tool call", createdAt: "2026-02-08T10:00:00.000Z", tone: "tool", }, ]; const timeline = deriveTimelineEntries(messages, workEntries); expect(timeline.map((entry) => entry.id)).toEqual(["work:w-1", "message:m-1"]); });}); describe("deriveWorkLogEntries", () => { it("drops preamble/work events from the visible work log", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-1", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", payload: { item: { type: "preamble", text: "thinking" } }, }), makeEvent({ id: "evt-2", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { type: "work", text: "planning" } }, }), makeEvent({ id: "evt-3", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", payload: { item: { type: "tool_call", command: "ls -la" } }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Tool call"); }); it("does not surface successful turn completion as a work-log row", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-complete", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:10.000Z", payload: { turn: { id: "turn-1", status: "completed" } }, }), ], "turn-1", ); expect(entries).toHaveLength(0); }); it("shows failed turn completion in the work log", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-complete", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:10.000Z", payload: { turn: { id: "turn-1", status: "failed", error: { message: "sandbox denied" }, }, }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Turn failed"); expect(entries[0]?.detail).toBe("sandbox denied"); }); it("hides reasoning and agent-message noise from the visible work log", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-turn-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-summary-part", method: "item/reasoning/summaryPartAdded", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", }), makeEvent({ id: "evt-summary-delta", method: "item/reasoning/summaryTextDelta", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", }), makeEvent({ id: "evt-agent-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:03.000Z", payload: { item: { id: "item-msg", type: "agentMessage", text: "Working..." }, }, }), makeEvent({ id: "evt-agent-complete", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:04.000Z", payload: { item: { id: "item-msg", type: "agentMessage", text: "Done response", }, }, }), makeEvent({ id: "evt-tool-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-tool", type: "tool_call", command: "ls -la" }, }, }), makeEvent({ id: "evt-tool-complete", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:06.000Z", payload: { item: { id: "item-tool", type: "tool_call", command: "ls -la" }, }, }), makeEvent({ id: "evt-turn-complete", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:08.000Z", payload: { turn: { id: "turn-1", status: "completed" } }, }), ], "turn-1", ); expect(entries.map((entry) => entry.label)).toEqual(["Tool call"]); }); it("coalesces command start/completed lifecycle into one entry", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-command-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { id: "item-command", type: "command_execution", command: "git status --short", }, }, }), makeEvent({ id: "evt-command-complete", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", payload: { item: { id: "item-command", type: "command_execution", command: "git status --short", }, }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Command run"); expect(entries[0]?.detail).toBe("git status --short"); }); it("preserves full tool-call detail text without data truncation", () => { const longCommand = 'node ./scripts/sync.js --project ct-round-5 --mode dry-run --include "very long argument with lots of detail and metadata to verify there is no hard truncation in session logic"'; const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-tool-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-tool", type: "tool_call", command: longCommand }, }, }), ], "turn-1", ); expect(entries[0]?.detail).toBe(longCommand); }); it("hides generic tool-call rows that have no identifying detail", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-tool-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-tool", type: "tool_call" }, }, }), ], "turn-1", ); expect(entries).toHaveLength(0); }); it("includes collab tool-call rows with tool name detail", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-collab-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-collab", type: "collabAgentToolCall", tool: "spawnAgent", }, }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Tool call"); expect(entries[0]?.detail).toBe("spawnAgent"); }); it("can derive work-log entries across all turns when not scoped", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-turn-1-tool", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { type: "tool_call", command: "ls -la" } }, }), makeEvent({ id: "evt-turn-2-tool", method: "item/started", turnId: "turn-2", createdAt: "2026-02-08T10:00:02.000Z", payload: { item: { type: "tool_call", command: "pwd" } }, }), ], undefined, ); expect(entries).toHaveLength(2); expect(entries.map((entry) => entry.detail)).toEqual(["pwd", "ls -la"]); });}); describe("deriveTurnDiffSummaries", () => { it("collects per-turn file changes and links them to assistant message completion", () => { const summaries = deriveTurnDiffSummaries([ makeEvent({ id: "evt-turn-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-file-change", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { id: "item-file-change", type: "fileChange", status: "completed", changes: [ { path: "src/a.ts", kind: "modified", diff: "diff --git a/src/a.ts b/src/a.ts\n@@ -1 +1 @@\n-old\n+new\n", }, ], }, }, }), makeEvent({ id: "evt-turn-diff-updated", method: "turn/diff/updated", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", payload: { threadId: "thr-1", turnId: "turn-1", diff: [ "diff --git a/src/a.ts b/src/a.ts", "@@ -1 +1 @@", "-old", "+new", "diff --git a/src/b.ts b/src/b.ts", "@@ -0,0 +1 @@", "+created", ].join("\n"), }, }), makeEvent({ id: "evt-agent-msg", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:03.000Z", payload: { item: { id: "msg-1", type: "agentMessage", text: "Done", }, }, }), makeEvent({ id: "evt-turn-completed", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:04.000Z", payload: { turn: { id: "turn-1", status: "completed", }, }, }), makeEvent({ id: "evt-turn-2-file-change", method: "item/completed", turnId: "turn-2", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-file-change-2", type: "fileChange", status: "completed", changes: [ { path: "src/unfinished.ts", kind: "modified", diff: "diff --git a/src/unfinished.ts b/src/unfinished.ts", }, ], }, }, }), ]); expect(summaries).toHaveLength(1); expect(summaries[0]?.turnId).toBe("turn-1"); expect(summaries[0]?.assistantMessageId).toBe("msg-1"); expect(summaries[0]?.files.map((file) => file.path)).toEqual(["src/a.ts", "src/b.ts"]); expect(summaries[0]?.files[0]?.kind).toBe("modified"); });}); describe("derivePendingApprovals", () => {Lines 1–500 of 804. Load more
import { describe, expect, it } from "vitest"; import type { ProviderEvent, ProviderSession } from "@t3tools/contracts"; import { type WorkLogEntry, applyEventToMessages, derivePendingApprovals, deriveTurnDiffSummaries, deriveTimelineEntries, deriveWorkLogEntries, evolveSession, } from "./session-logic"; import type { ChatMessage } from "./types"; function makeEvent(overrides: Partial<ProviderEvent>): ProviderEvent { return { id: "evt-1", kind: "notification", provider: "codex", sessionId: "sess-1", createdAt: "2026-02-08T10:00:00.000Z", method: "noop", ...overrides, }; } function makeSession(overrides: Partial<ProviderSession> = {}): ProviderSession { return { sessionId: "sess-1", provider: "codex", status: "ready", createdAt: "2026-02-08T09:59:00.000Z", updatedAt: "2026-02-08T09:59:00.000Z", ...overrides, }; } describe("deriveTimelineEntries", () => { it("interleaves messages and work entries by timestamp", () => { const messages: ChatMessage[] = [ { id: "m-user", role: "user", text: "Hi", createdAt: "2026-02-08T10:00:00.000Z", streaming: false, }, { id: "m-assistant", role: "assistant", text: "Hello", createdAt: "2026-02-08T10:05:00.000Z", streaming: false, }, ]; const workEntries: WorkLogEntry[] = [ { id: "w-1", label: "Tool call", createdAt: "2026-02-08T10:02:00.000Z", tone: "tool", }, { id: "w-2", label: "Preamble", createdAt: "2026-02-08T10:03:00.000Z", tone: "thinking", }, ]; const timeline = deriveTimelineEntries(messages, workEntries); expect(timeline.map((entry) => entry.id)).toEqual([ "message:m-user", "work:w-1", "work:w-2", "message:m-assistant", ]); }); it("prefers work entries when timestamps are equal", () => { const messages: ChatMessage[] = [ { id: "m-1", role: "assistant", text: "Done", createdAt: "2026-02-08T10:00:00.000Z", streaming: false, }, ]; const workEntries: WorkLogEntry[] = [ { id: "w-1", label: "Tool call", createdAt: "2026-02-08T10:00:00.000Z", tone: "tool", }, ]; const timeline = deriveTimelineEntries(messages, workEntries); expect(timeline.map((entry) => entry.id)).toEqual(["work:w-1", "message:m-1"]); }); }); describe("deriveWorkLogEntries", () => { it("drops preamble/work events from the visible work log", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-1", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", payload: { item: { type: "preamble", text: "thinking" } }, }), makeEvent({ id: "evt-2", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { type: "work", text: "planning" } }, }), makeEvent({ id: "evt-3", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", payload: { item: { type: "tool_call", command: "ls -la" } }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Tool call"); }); it("does not surface successful turn completion as a work-log row", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-complete", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:10.000Z", payload: { turn: { id: "turn-1", status: "completed" } }, }), ], "turn-1", ); expect(entries).toHaveLength(0); }); it("shows failed turn completion in the work log", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-complete", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:10.000Z", payload: { turn: { id: "turn-1", status: "failed", error: { message: "sandbox denied" }, }, }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Turn failed"); expect(entries[0]?.detail).toBe("sandbox denied"); }); it("hides reasoning and agent-message noise from the visible work log", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-turn-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-summary-part", method: "item/reasoning/summaryPartAdded", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", }), makeEvent({ id: "evt-summary-delta", method: "item/reasoning/summaryTextDelta", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", }), makeEvent({ id: "evt-agent-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:03.000Z", payload: { item: { id: "item-msg", type: "agentMessage", text: "Working..." }, }, }), makeEvent({ id: "evt-agent-complete", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:04.000Z", payload: { item: { id: "item-msg", type: "agentMessage", text: "Done response", }, }, }), makeEvent({ id: "evt-tool-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-tool", type: "tool_call", command: "ls -la" }, }, }), makeEvent({ id: "evt-tool-complete", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:06.000Z", payload: { item: { id: "item-tool", type: "tool_call", command: "ls -la" }, }, }), makeEvent({ id: "evt-turn-complete", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:08.000Z", payload: { turn: { id: "turn-1", status: "completed" } }, }), ], "turn-1", ); expect(entries.map((entry) => entry.label)).toEqual(["Tool call"]); }); it("coalesces command start/completed lifecycle into one entry", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-command-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { id: "item-command", type: "command_execution", command: "git status --short", }, }, }), makeEvent({ id: "evt-command-complete", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", payload: { item: { id: "item-command", type: "command_execution", command: "git status --short", }, }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Command run"); expect(entries[0]?.detail).toBe("git status --short"); }); it("preserves full tool-call detail text without data truncation", () => { const longCommand = 'node ./scripts/sync.js --project ct-round-5 --mode dry-run --include "very long argument with lots of detail and metadata to verify there is no hard truncation in session logic"'; const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-tool-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-tool", type: "tool_call", command: longCommand }, }, }), ], "turn-1", ); expect(entries[0]?.detail).toBe(longCommand); }); it("hides generic tool-call rows that have no identifying detail", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-tool-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-tool", type: "tool_call" }, }, }), ], "turn-1", ); expect(entries).toHaveLength(0); }); it("includes collab tool-call rows with tool name detail", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-collab-start", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-collab", type: "collabAgentToolCall", tool: "spawnAgent", }, }, }), ], "turn-1", ); expect(entries).toHaveLength(1); expect(entries[0]?.label).toBe("Tool call"); expect(entries[0]?.detail).toBe("spawnAgent"); }); it("can derive work-log entries across all turns when not scoped", () => { const entries = deriveWorkLogEntries( [ makeEvent({ id: "evt-turn-1-tool", method: "item/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { type: "tool_call", command: "ls -la" } }, }), makeEvent({ id: "evt-turn-2-tool", method: "item/started", turnId: "turn-2", createdAt: "2026-02-08T10:00:02.000Z", payload: { item: { type: "tool_call", command: "pwd" } }, }), ], undefined, ); expect(entries).toHaveLength(2); expect(entries.map((entry) => entry.detail)).toEqual(["pwd", "ls -la"]); }); }); describe("deriveTurnDiffSummaries", () => { it("collects per-turn file changes and links them to assistant message completion", () => { const summaries = deriveTurnDiffSummaries([ makeEvent({ id: "evt-turn-start", method: "turn/started", turnId: "turn-1", createdAt: "2026-02-08T10:00:00.000Z", }), makeEvent({ id: "evt-file-change", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:01.000Z", payload: { item: { id: "item-file-change", type: "fileChange", status: "completed", changes: [ { path: "src/a.ts", kind: "modified", diff: "diff --git a/src/a.ts b/src/a.ts\n@@ -1 +1 @@\n-old\n+new\n", }, ], }, }, }), makeEvent({ id: "evt-turn-diff-updated", method: "turn/diff/updated", turnId: "turn-1", createdAt: "2026-02-08T10:00:02.000Z", payload: { threadId: "thr-1", turnId: "turn-1", diff: [ "diff --git a/src/a.ts b/src/a.ts", "@@ -1 +1 @@", "-old", "+new", "diff --git a/src/b.ts b/src/b.ts", "@@ -0,0 +1 @@", "+created", ].join("\n"), }, }), makeEvent({ id: "evt-agent-msg", method: "item/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:03.000Z", payload: { item: { id: "msg-1", type: "agentMessage", text: "Done", }, }, }), makeEvent({ id: "evt-turn-completed", method: "turn/completed", turnId: "turn-1", createdAt: "2026-02-08T10:00:04.000Z", payload: { turn: { id: "turn-1", status: "completed", }, }, }), makeEvent({ id: "evt-turn-2-file-change", method: "item/completed", turnId: "turn-2", createdAt: "2026-02-08T10:00:05.000Z", payload: { item: { id: "item-file-change-2", type: "fileChange", status: "completed", changes: [ { path: "src/unfinished.ts", kind: "modified", diff: "diff --git a/src/unfinished.ts b/src/unfinished.ts", }, ], }, }, }), ]); expect(summaries).toHaveLength(1); expect(summaries[0]?.turnId).toBe("turn-1"); expect(summaries[0]?.assistantMessageId).toBe("msg-1"); expect(summaries[0]?.files.map((file) => file.path)).toEqual(["src/a.ts", "src/b.ts"]); expect(summaries[0]?.files[0]?.kind).toBe("modified"); }); }); describe("derivePendingApprovals", () => {