180 lines · 5.0 KB · TypeScript
RawDownload
import { describe, expect, it } from "@effect/vitest"; import type {  EnvironmentId,  OrchestrationProjectShell,  OrchestrationThreadShell,  ThreadId,  TurnId,} from "@t3tools/contracts";import { ProviderInstanceId } from "@t3tools/contracts"; import { projectThreadAwareness } from "./agentAwareness.ts"; const NOW = "2026-05-22T12:00:00.000Z"; const project = {  title: "t3code",} satisfies Pick<OrchestrationProjectShell, "title">; function thread(  overrides: Partial<OrchestrationThreadShell> = {},): Pick<  OrchestrationThreadShell,  | "id"  | "title"  | "modelSelection"  | "session"  | "latestTurn"  | "updatedAt"  | "hasPendingApprovals"  | "hasPendingUserInput"> {  return {    id: "thread-1" as ThreadId,    title: "Fix failing CI",    modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.4" },    session: null,    latestTurn: null,    updatedAt: NOW,    hasPendingApprovals: false,    hasPendingUserInput: false,    ...overrides,  };} describe("projectThreadAwareness", () => {  it("returns null for idle threads without an active awareness state", () => {    expect(      projectThreadAwareness({        environmentId: "env-1" as EnvironmentId,        project,        thread: thread(),      }),    ).toBeNull();  });   it("prioritizes approval requests over running state", () => {    const state = projectThreadAwareness({      environmentId: "env-1" as EnvironmentId,      project,      thread: thread({        hasPendingApprovals: true,        session: {          threadId: "thread-1" as ThreadId,          status: "running",          providerName: "Codex",          runtimeMode: "full-access",          activeTurnId: "turn-1" as TurnId,          lastError: null,          updatedAt: NOW,        },      }),    });     expect(state?.phase).toBe("waiting_for_approval");    expect(state?.headline).toBe("Approval needed");  });   it("projects running provider sessions", () => {    const state = projectThreadAwareness({      environmentId: "env-1" as EnvironmentId,      project,      thread: thread({        session: {          threadId: "thread-1" as ThreadId,          status: "running",          providerName: "Codex",          runtimeMode: "full-access",          activeTurnId: "turn-1" as TurnId,          lastError: null,          updatedAt: NOW,        },      }),    });     expect(state).toMatchObject({      phase: "running",      headline: "Agent is working",      detail: "Codex is active.",      modelTitle: "gpt-5.4",      deepLink: "/threads/env-1/thread-1",    });  });   it("projects completed turns as completed even when teardown settled them as interrupted", () => {    const finishedTurn = {      turnId: "turn-1" as TurnId,      state: "interrupted" as const,      requestedAt: NOW,      startedAt: NOW,      completedAt: NOW,      assistantMessageId: null,    };    const state = projectThreadAwareness({      environmentId: "env-1" as EnvironmentId,      project,      thread: thread({ latestTurn: finishedTurn }),    });     // Session teardown settles still-running turns by session status, and    // that write can race turn.completed; the completion timestamp is the    // durable signal. Without this the thread resolves to null persistently    // and gets tombstoned off the lock-screen card instead of showing Done.    expect(state?.phase).toBe("completed");     const trulyInterrupted = projectThreadAwareness({      environmentId: "env-1" as EnvironmentId,      project,      thread: thread({ latestTurn: { ...finishedTurn, completedAt: null } }),    });    expect(trulyInterrupted).toBeNull();  });   it("projects ready sessions with no materialized turn as completed", () => {    // Quick threads without code changes never get a checkpoint, so the SQL    // shell has no latestTurn row and latest_turn_id is cleared when the    // session settles; the ready session is the only completion signal left.    const state = projectThreadAwareness({      environmentId: "env-1" as EnvironmentId,      project,      thread: thread({        session: {          threadId: "thread-1" as ThreadId,          status: "ready",          providerName: "Codex",          runtimeMode: "full-access",          activeTurnId: null,          lastError: null,          updatedAt: NOW,        },      }),    });     expect(state?.phase).toBe("completed");  });   it("projects failures with the session error detail", () => {    const state = projectThreadAwareness({      environmentId: "env-1" as EnvironmentId,      project,      thread: thread({        session: {          threadId: "thread-1" as ThreadId,          status: "error",          providerName: "Codex",          runtimeMode: "full-access",          activeTurnId: null,          lastError: "Provider process exited.",          updatedAt: NOW,        },      }),    });     expect(state).toMatchObject({      phase: "failed",      headline: "Agent failed",      detail: "Provider process exited.",    });  });});