1461 lines · 47.9 KB · TypeScript
RawDownload
import { describe, expect, it } from "vite-plus/test"; import {  CheckpointRef,  CommandId,  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 and clears title regeneration", () => {      const regeneratingThread: OrchestrationThread = {        ...baseThread,        titleRegeneration: {          requestId: CommandId.make("regenerate-title"),          startedAt: "2026-04-01T02:00:00.000Z",        },      };      const result = applyThreadDetailEvent(regeneratingThread, {        ...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");        expect(result.thread.titleRegeneration).toBeNull();      }    });     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, activeOrderKey: "m" },        {          ...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);        expect(result.thread.activeOrderKey).toBeNull();      }    });     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.pinned / thread.unpinned", () => {    it("sets pinnedAt", () => {      const pinnedAt = "2026-04-01T05:00:00.000Z";      const result = applyThreadDetailEvent(        { ...baseThread, activeOrderKey: "m" },        {          ...baseEventFields,          sequence: 5,          occurredAt: pinnedAt,          aggregateKind: "thread",          aggregateId: ThreadId.make("thread-1"),          type: "thread.pinned",          payload: {            threadId: ThreadId.make("thread-1"),            pinnedAt,            updatedAt: pinnedAt,          },        },      );       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.pinnedAt).toBe(pinnedAt);        expect(result.thread.activeOrderKey).toBe("m");      }    });     it("clears pinnedAt", () => {      const pinnedThread: OrchestrationThread = {        ...baseThread,        pinnedAt: "2026-04-01T05:00:00.000Z",      };      const updatedAt = "2026-04-01T06:00:00.000Z";      const result = applyThreadDetailEvent(pinnedThread, {        ...baseEventFields,        sequence: 6,        occurredAt: updatedAt,        aggregateKind: "thread",        aggregateId: ThreadId.make("thread-1"),        type: "thread.unpinned",        payload: {          threadId: ThreadId.make("thread-1"),          updatedAt,        },      });       expect(result.kind).toBe("updated");      if (result.kind === "updated") {        expect(result.thread.pinnedAt).toBeNull();      }    });  });   describe("thread.meta-updated", () => {    it.each(["f", null] as const)(      "updates the active key to %s without activity",      (activeOrderKey) => {        const result = applyThreadDetailEvent(          { ...baseThread, activeOrderKey: "m" },          {            ...baseEventFields,            sequence: 5,            occurredAt: "2026-04-01T05:00:00.000Z",            aggregateKind: "thread",            aggregateId: baseThread.id,            type: "thread.meta-updated",            payload: {              threadId: baseThread.id,              activeOrderKey,              updatedAt: baseThread.updatedAt,            },          },        );        expect(result.kind).toBe("updated");        if (result.kind === "updated") {          expect(result.thread.activeOrderKey).toBe(activeOrderKey);          expect(result.thread.updatedAt).toBe(baseThread.updatedAt);        }      },    );     it("patches title and branch", () => {      const result = applyThreadDetailEvent(        { ...baseThread, activeOrderKey: "m" },        {          ...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");        expect(result.thread.activeOrderKey).toBe("m");        // Model selection should be unchanged since it wasn't in the payload        expect(result.thread.modelSelection).toEqual(baseThread.modelSelection);      }    });     it.each(["linkedPullRequest", "branchPullRequest"] as const)(      "sets and clears %s without changing the other link",      (field) => {        const linkedPullRequest = {          projectId: ProjectId.make("project-1"),          repository: "pingdotgg/t3code",          number: 42,          url: "https://github.com/pingdotgg/t3code/pull/42",        };        const otherField =          field === "linkedPullRequest" ? "branchPullRequest" : "linkedPullRequest";        const otherPullRequest = {          ...linkedPullRequest,          number: 43,          url: "https://github.com/pingdotgg/t3code/pull/43",        };        const linked = applyThreadDetailEvent(          { ...baseThread, [otherField]: otherPullRequest },          {            ...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"),              [field]: linkedPullRequest,              updatedAt: "2026-04-01T05:00:00.000Z",            },          },        );         expect(linked.kind).toBe("updated");        if (linked.kind !== "updated") return;        expect(linked.thread[field]).toEqual(linkedPullRequest);        expect(linked.thread[otherField]).toEqual(otherPullRequest);         const cleared = applyThreadDetailEvent(linked.thread, {          ...baseEventFields,          sequence: 6,          occurredAt: "2026-04-01T06:00:00.000Z",          aggregateKind: "thread",          aggregateId: ThreadId.make("thread-1"),          type: "thread.meta-updated",          payload: {            threadId: ThreadId.make("thread-1"),            [field]: null,            updatedAt: "2026-04-01T06:00:00.000Z",          },        });         expect(cleared.kind).toBe("updated");        if (cleared.kind === "updated") {          expect(cleared.thread[field]).toBeNull();          expect(cleared.thread[otherField]).toEqual(otherPullRequest);        }      },    );  });   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("keeps imported replies turnless when delivered again", () => {      const event = {        ...baseEventFields,        sequence: 6,        occurredAt: "2026-04-01T06:00:00.000Z",        aggregateKind: "thread",        aggregateId: baseThread.id,        type: "thread.message-sent",        payload: {          threadId: baseThread.id,          messageId: MessageId.make("import:codex:session-1:000001"),          role: "assistant",          text: "Imported reply",          turnId: null,          streaming: false,          createdAt: "2026-03-01T06:00:00.000Z",          updatedAt: "2026-03-01T06:00:00.000Z",        },      } as const;       const imported = applyThreadDetailEvent(baseThread, event);      expect(imported.kind).toBe("updated");      if (imported.kind !== "updated") return;      expect(imported.thread.latestTurn).toBeNull();      expect(imported.thread.checkpoints).toBe(baseThread.checkpoints);       const repeated = applyThreadDetailEvent(imported.thread, { ...event, sequence: 7 });      expect(repeated.kind).toBe("updated");      if (repeated.kind !== "updated") return;      expect(repeated.thread.messages).toEqual(imported.thread.messages);      expect(repeated.thread.latestTurn).toBeNull();      expect(repeated.thread.checkpoints).toBe(baseThread.checkpoints);    });     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,

Lines 1–500 of 1461.