804 lines · 21.5 KB · TypeScript
RawDownload
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.