758 lines · 24.2 KB · TypeScript
RawDownload
import { describe, expect, it } from "vite-plus/test"; import {  CheckpointRef,  EventId,  MessageId,  ProjectId,  ProviderInstanceId,  ThreadId,  TurnId,} from "@t3tools/contracts";import type { OrchestrationThread } from "@t3tools/contracts"; import { applyThreadDetailEvent } from "./threadReducer.ts"; const baseEventFields = {  eventId: EventId.make("event-1"),  commandId: null,  causationEventId: null,  correlationId: null,  metadata: {},} as const; const baseThread: OrchestrationThread = {  id: ThreadId.make("thread-1"),  projectId: ProjectId.make("project-1"),  title: "Test Thread",  modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.4" },  runtimeMode: "full-access",  interactionMode: "default",  branch: null,  worktreePath: null,  latestTurn: null,  createdAt: "2026-04-01T00:00:00.000Z",  updatedAt: "2026-04-01T00:00:00.000Z",  archivedAt: null,  settledOverride: null,  settledAt: null,  deletedAt: null,  messages: [],  proposedPlans: [],  activities: [],  checkpoints: [],  session: null,}; describe("applyThreadDetailEvent", () => {  describe("project events", () => {    it("returns unchanged for project.created", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 1,        occurredAt: "2026-04-01T01:00:00.000Z",        aggregateKind: "project",        aggregateId: ProjectId.make("project-1"),        type: "project.created",        payload: {          projectId: ProjectId.make("project-1"),          title: "T3 Code",          workspaceRoot: "/repo",          repositoryIdentity: null,          defaultModelSelection: null,          scripts: [],          createdAt: "2026-04-01T01:00:00.000Z",          updatedAt: "2026-04-01T01:00:00.000Z",          deletedAt: null,        },      } as any);      expect(result.kind).toBe("unchanged");    });  });   describe("thread.created", () => {    it("creates a fresh thread", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 1,        occurredAt: "2026-04-01T01:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-2"),        type: "thread.created",        payload: {          threadId: ThreadId.make("thread-2"),          projectId: ProjectId.make("project-1"),          title: "New Thread",          modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.4" },          runtimeMode: "full-access",          interactionMode: "default",          branch: "main",          worktreePath: null,          createdAt: "2026-04-01T01:00:00.000Z",          updatedAt: "2026-04-01T01:00:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.id).toBe("thread-2");        expect(result.thread.title).toBe("New Thread");        expect(result.thread.branch).toBe("main");        expect(result.thread.messages).toEqual([]);        expect(result.thread.session).toBeNull();      }    });  });   describe("thread.deleted", () => {    it("returns deleted signal", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 2,        occurredAt: "2026-04-01T02:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.deleted",        payload: {          threadId: ThreadId.make("thread-1"),          deletedAt: "2026-04-01T02:00:00.000Z",        },      });      expect(result.kind).toBe("deleted");    });  });   describe("thread.archived / thread.unarchived", () => {    it("sets archivedAt", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 3,        occurredAt: "2026-04-01T03:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.archived",        payload: {          threadId: ThreadId.make("thread-1"),          archivedAt: "2026-04-01T03:00:00.000Z",          updatedAt: "2026-04-01T03:00:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.archivedAt).toBe("2026-04-01T03:00:00.000Z");      }    });     it("clears archivedAt", () => {      const archivedThread = { ...baseThread, archivedAt: "2026-04-01T03:00:00.000Z" };      const result = applyThreadDetailEvent(archivedThread, {        ...baseEventFields,        sequence: 4,        occurredAt: "2026-04-01T04:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.unarchived",        payload: {          threadId: ThreadId.make("thread-1"),          updatedAt: "2026-04-01T04:00:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.archivedAt).toBeNull();      }    });  });   describe("thread.settled / thread.unsettled", () => {    it("sets the settled override and timestamp", () => {      const settledAt = "2026-04-01T05:00:00.000Z";      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 5,        occurredAt: settledAt,        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.settled",        payload: {          threadId: ThreadId.make("thread-1"),          settledAt,          updatedAt: settledAt,        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.settledOverride).toBe("settled");        expect(result.thread.settledAt).toBe(settledAt);      }    });     it.each([      ["user", "active"],      ["activity", null],    ] as const)("unsettles for %s with override %s", (reason, settledOverride) => {      const settledThread: OrchestrationThread = {        ...baseThread,        settledOverride: "settled",        settledAt: "2026-04-01T05:00:00.000Z",      };      const updatedAt = "2026-04-01T06:00:00.000Z";      const result = applyThreadDetailEvent(settledThread, {        ...baseEventFields,        sequence: 6,        occurredAt: updatedAt,        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.unsettled",        payload: {          threadId: ThreadId.make("thread-1"),          reason,          updatedAt,        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.settledOverride).toBe(settledOverride);        expect(result.thread.settledAt).toBeNull();      }    });  });   describe("thread.meta-updated", () => {    it("patches title and branch", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 5,        occurredAt: "2026-04-01T05:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.meta-updated",        payload: {          threadId: ThreadId.make("thread-1"),          title: "Updated Title",          branch: "feature/demo",          updatedAt: "2026-04-01T05:00:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.title).toBe("Updated Title");        expect(result.thread.branch).toBe("feature/demo");        // Model selection should be unchanged since it wasn't in the payload        expect(result.thread.modelSelection).toEqual(baseThread.modelSelection);      }    });  });   describe("thread.message-sent", () => {    it("appends a new message", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 6,        occurredAt: "2026-04-01T06:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.message-sent",        payload: {          threadId: ThreadId.make("thread-1"),          messageId: MessageId.make("msg-1"),          role: "user",          text: "Hello, world!",          turnId: null,          streaming: false,          createdAt: "2026-04-01T06:00:00.000Z",          updatedAt: "2026-04-01T06:00:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.messages).toHaveLength(1);        expect(result.thread.messages[0]?.text).toBe("Hello, world!");      }    });     it("appends text for streaming messages", () => {      const threadWithMessage: OrchestrationThread = {        ...baseThread,        messages: [          {            id: MessageId.make("msg-2"),            role: "assistant",            text: "Hello",            turnId: TurnId.make("turn-1"),            streaming: true,            createdAt: "2026-04-01T06:00:00.000Z",            updatedAt: "2026-04-01T06:00:00.000Z",          },        ],      };       const result = applyThreadDetailEvent(threadWithMessage, {        ...baseEventFields,        sequence: 7,        occurredAt: "2026-04-01T06:01:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.message-sent",        payload: {          threadId: ThreadId.make("thread-1"),          messageId: MessageId.make("msg-2"),          role: "assistant",          text: ", world!",          turnId: TurnId.make("turn-1"),          streaming: true,          createdAt: "2026-04-01T06:00:00.000Z",          updatedAt: "2026-04-01T06:01:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.messages).toHaveLength(1);        expect(result.thread.messages[0]?.text).toBe("Hello, world!");      }    });     it("updates latestTurn for assistant messages with a turn", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 8,        occurredAt: "2026-04-01T07:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.message-sent",        payload: {          threadId: ThreadId.make("thread-1"),          messageId: MessageId.make("msg-3"),          role: "assistant",          text: "Done.",          turnId: TurnId.make("turn-1"),          streaming: false,          createdAt: "2026-04-01T07:00:00.000Z",          updatedAt: "2026-04-01T07:00:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.latestTurn?.turnId).toBe("turn-1");        expect(result.thread.latestTurn?.state).toBe("completed");        expect(result.thread.latestTurn?.assistantMessageId).toBe("msg-3");      }    });     it("keeps latestTurn running for interim assistant messages while the session runs the turn", () => {      const threadWithRunningSession: OrchestrationThread = {        ...baseThread,        session: {          threadId: ThreadId.make("thread-1"),          status: "running",          providerName: "claude",          runtimeMode: "full-access",          activeTurnId: TurnId.make("turn-1"),          lastError: null,          updatedAt: "2026-04-01T06:59:00.000Z",        },        latestTurn: {          turnId: TurnId.make("turn-1"),          state: "running",          requestedAt: "2026-04-01T06:59:00.000Z",          startedAt: "2026-04-01T06:59:00.000Z",          completedAt: null,          assistantMessageId: null,        },      };       const result = applyThreadDetailEvent(threadWithRunningSession, {        ...baseEventFields,        sequence: 8,        occurredAt: "2026-04-01T07:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.message-sent",        payload: {          threadId: ThreadId.make("thread-1"),          messageId: MessageId.make("msg-3"),          role: "assistant",          text: "Interim commentary between tool calls.",          turnId: TurnId.make("turn-1"),          streaming: false,          createdAt: "2026-04-01T07:00:00.000Z",          updatedAt: "2026-04-01T07:00:00.000Z",        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.latestTurn?.state).toBe("running");        expect(result.thread.latestTurn?.completedAt).toBeNull();      }    });  });   describe("thread.session-set", () => {    it("settles a running latestTurn when the session leaves the running status", () => {      const threadWithRunningTurn: OrchestrationThread = {        ...baseThread,        latestTurn: {          turnId: TurnId.make("turn-1"),          state: "running",          requestedAt: "2026-04-01T07:00:00.000Z",          startedAt: "2026-04-01T07:00:00.000Z",          completedAt: null,          assistantMessageId: MessageId.make("msg-3"),        },      };       const result = applyThreadDetailEvent(threadWithRunningTurn, {        ...baseEventFields,        sequence: 9,        occurredAt: "2026-04-01T08:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.session-set",        payload: {          threadId: ThreadId.make("thread-1"),          session: {            threadId: ThreadId.make("thread-1"),            status: "ready",            providerName: "claude",            runtimeMode: "full-access",            activeTurnId: null,            lastError: null,            updatedAt: "2026-04-01T08:00:00.000Z",          },        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.latestTurn?.state).toBe("completed");        expect(result.thread.latestTurn?.completedAt).toBe("2026-04-01T08:00:00.000Z");      }    });     it("updates session and latestTurn for a running session", () => {      const result = applyThreadDetailEvent(baseThread, {        ...baseEventFields,        sequence: 9,        occurredAt: "2026-04-01T08:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.session-set",        payload: {          threadId: ThreadId.make("thread-1"),          session: {            threadId: ThreadId.make("thread-1"),            status: "running",            providerName: "codex",            runtimeMode: "full-access",            activeTurnId: TurnId.make("turn-1"),            lastError: null,            updatedAt: "2026-04-01T08:00:00.000Z",          },        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.session?.status).toBe("running");        expect(result.thread.latestTurn?.turnId).toBe("turn-1");        expect(result.thread.latestTurn?.state).toBe("running");      }    });  });   describe("thread.session-stop-requested", () => {    it("marks session as stopped", () => {      const threadWithSession: OrchestrationThread = {        ...baseThread,        session: {          threadId: ThreadId.make("thread-1"),          status: "running",          providerName: "codex",          runtimeMode: "full-access",          activeTurnId: TurnId.make("turn-1"),          lastError: null,          updatedAt: "2026-04-01T08:00:00.000Z",        },      };       const result = applyThreadDetailEvent(threadWithSession, {        ...baseEventFields,        sequence: 10,        occurredAt: "2026-04-01T09:00:00.000Z",        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.session-stop-requested",        payload: {          threadId: ThreadId.make("thread-1"),          createdAt: "2026-04-01T09:00:00.000Z",        },      });       expect(result.kind).toBe("updated");

Lines 1–500 of 758.