202 lines · 6.2 KB · TypeScript
RawDownload
import { EventId, TurnId, type OrchestrationThreadActivity } from "@t3tools/contracts";import { describe, expect, it } from "vitest"; import {  derivePendingApprovals,  deriveWorkLogEntries,  hasToolActivityForTurn,  isLatestTurnSettled,} from "./session-logic"; function makeActivity(overrides: {  id?: string;  createdAt?: string;  kind?: string;  summary?: string;  tone?: OrchestrationThreadActivity["tone"];  payload?: Record<string, unknown>;  turnId?: string;}): OrchestrationThreadActivity {  const payload = overrides.payload ?? {};  return {    id: EventId.makeUnsafe(overrides.id ?? crypto.randomUUID()),    createdAt: overrides.createdAt ?? "2026-02-23T00:00:00.000Z",    kind: overrides.kind ?? "tool.started",    summary: overrides.summary ?? "Tool call",    tone: overrides.tone ?? "tool",    payload,    turnId: overrides.turnId ? TurnId.makeUnsafe(overrides.turnId) : null,  };} describe("derivePendingApprovals", () => {  it("tracks open approvals and removes resolved ones", () => {    const activities: OrchestrationThreadActivity[] = [      makeActivity({        id: "approval-open",        createdAt: "2026-02-23T00:00:01.000Z",        kind: "approval.requested",        summary: "Command approval requested",        tone: "approval",        payload: {          requestId: "req-1",          requestKind: "command",          detail: "bun run lint",        },      }),      makeActivity({        id: "approval-close",        createdAt: "2026-02-23T00:00:02.000Z",        kind: "approval.resolved",        summary: "Approval resolved",        tone: "info",        payload: { requestId: "req-2" },      }),      makeActivity({        id: "approval-closed-request",        createdAt: "2026-02-23T00:00:01.500Z",        kind: "approval.requested",        summary: "File-change approval requested",        tone: "approval",        payload: { requestId: "req-2", requestKind: "file-change" },      }),    ];     expect(derivePendingApprovals(activities)).toEqual([      {        requestId: "req-1",        requestKind: "command",        createdAt: "2026-02-23T00:00:01.000Z",        detail: "bun run lint",      },    ]);  });}); describe("deriveWorkLogEntries", () => {  it("omits tool started entries and keeps completed entries", () => {    const activities: OrchestrationThreadActivity[] = [      makeActivity({        id: "tool-complete",        createdAt: "2026-02-23T00:00:03.000Z",        summary: "Tool call complete",        kind: "tool.completed",      }),      makeActivity({        id: "tool-start",        createdAt: "2026-02-23T00:00:02.000Z",        summary: "Tool call",        kind: "tool.started",      }),    ];     const entries = deriveWorkLogEntries(activities, undefined);    expect(entries.map((entry) => entry.id)).toEqual(["tool-complete"]);  });   it("filters by turn id when provided", () => {    const activities: OrchestrationThreadActivity[] = [      makeActivity({ id: "turn-1", turnId: "turn-1", summary: "Tool call", kind: "tool.started" }),      makeActivity({        id: "turn-2",        turnId: "turn-2",        summary: "Tool call complete",        kind: "tool.completed",      }),      makeActivity({ id: "no-turn", summary: "Checkpoint captured", tone: "info" }),    ];     const entries = deriveWorkLogEntries(activities, TurnId.makeUnsafe("turn-2"));    expect(entries.map((entry) => entry.id)).toEqual(["turn-2"]);  });   it("omits checkpoint captured info entries", () => {    const activities: OrchestrationThreadActivity[] = [      makeActivity({        id: "checkpoint",        createdAt: "2026-02-23T00:00:01.000Z",        summary: "Checkpoint captured",        tone: "info",      }),      makeActivity({        id: "tool-complete",        createdAt: "2026-02-23T00:00:02.000Z",        summary: "Command run complete",        tone: "tool",        kind: "tool.completed",      }),    ];     const entries = deriveWorkLogEntries(activities, undefined);    expect(entries.map((entry) => entry.id)).toEqual(["tool-complete"]);  });}); describe("hasToolActivityForTurn", () => {  it("returns false when turn id is missing", () => {    const activities: OrchestrationThreadActivity[] = [      makeActivity({ id: "tool-1", turnId: "turn-1", kind: "tool.completed", tone: "tool" }),    ];     expect(hasToolActivityForTurn(activities, undefined)).toBe(false);    expect(hasToolActivityForTurn(activities, null)).toBe(false);  });   it("returns true only for matching tool activity in the target turn", () => {    const activities: OrchestrationThreadActivity[] = [      makeActivity({ id: "tool-1", turnId: "turn-1", kind: "tool.completed", tone: "tool" }),      makeActivity({ id: "info-1", turnId: "turn-2", kind: "turn.completed", tone: "info" }),    ];     expect(hasToolActivityForTurn(activities, TurnId.makeUnsafe("turn-1"))).toBe(true);    expect(hasToolActivityForTurn(activities, TurnId.makeUnsafe("turn-2"))).toBe(false);  });}); describe("isLatestTurnSettled", () => {  const latestTurn = {    turnId: TurnId.makeUnsafe("turn-1"),    startedAt: "2026-02-27T21:10:00.000Z",    completedAt: "2026-02-27T21:10:06.000Z",  } as const;   it("returns false while the same turn is still active in a running session", () => {    expect(      isLatestTurnSettled(latestTurn, {        orchestrationStatus: "running",        activeTurnId: TurnId.makeUnsafe("turn-1"),      }),    ).toBe(false);  });   it("returns false while any turn is running to avoid stale latest-turn banners", () => {    expect(      isLatestTurnSettled(latestTurn, {        orchestrationStatus: "running",        activeTurnId: TurnId.makeUnsafe("turn-2"),      }),    ).toBe(false);  });   it("returns true once the session is no longer running that turn", () => {    expect(      isLatestTurnSettled(latestTurn, {        orchestrationStatus: "ready",        activeTurnId: undefined,      }),    ).toBe(true);  });   it("returns false when turn timestamps are incomplete", () => {    expect(      isLatestTurnSettled(        {          turnId: TurnId.makeUnsafe("turn-1"),          startedAt: null,          completedAt: "2026-02-27T21:10:06.000Z",        },        null,      ),    ).toBe(false);  });});