142 lines · 3.8 KB · TypeScript
RawDownload
import type {  EnvironmentId,  OrchestrationProjectShell,  OrchestrationThreadShell,  ThreadId,} from "@t3tools/contracts"; export type AgentAwarenessPhase =  | "starting"  | "running"  | "waiting_for_approval"  | "waiting_for_input"  | "completed"  | "failed"  | "stale"; export interface AgentAwarenessState {  readonly environmentId: EnvironmentId;  readonly threadId: ThreadId;  readonly projectTitle: string;  readonly threadTitle: string;  readonly phase: AgentAwarenessPhase;  readonly headline: string;  readonly detail?: string;  readonly modelTitle: string;  readonly updatedAt: string;  readonly deepLink: string;} export interface ProjectThreadAwarenessInput {  readonly environmentId: EnvironmentId;  readonly project: Pick<OrchestrationProjectShell, "title">;  readonly thread: Pick<    OrchestrationThreadShell,    | "id"    | "title"    | "modelSelection"    | "session"    | "latestTurn"    | "updatedAt"    | "hasPendingApprovals"    | "hasPendingUserInput"  >;} export function buildAgentAwarenessDeepLink(input: {  readonly environmentId: EnvironmentId;  readonly threadId: ThreadId;}): string {  return `/threads/${encodeURIComponent(input.environmentId)}/${encodeURIComponent(input.threadId)}`;} export function isTerminalAgentAwarenessPhase(phase: AgentAwarenessPhase): boolean {  return phase === "completed" || phase === "failed";} export function isInterruptiveAgentAwarenessPhase(phase: AgentAwarenessPhase): boolean {  return phase === "waiting_for_approval" || phase === "waiting_for_input" || phase === "failed";} export function projectThreadAwareness(  input: ProjectThreadAwarenessInput,): AgentAwarenessState | null {  const { environmentId, project, thread } = input;  const phase = resolveThreadAwarenessPhase(thread);  if (!phase) {    return null;  }   const detail = detailForPhase(phase, thread);  return {    environmentId,    threadId: thread.id,    projectTitle: project.title,    threadTitle: thread.title,    phase,    headline: headlineForPhase(phase),    ...(detail === undefined ? {} : { detail }),    modelTitle: thread.modelSelection.model,    updatedAt: thread.updatedAt,    deepLink: buildAgentAwarenessDeepLink({ environmentId, threadId: thread.id }),  };} function resolveThreadAwarenessPhase(  thread: ProjectThreadAwarenessInput["thread"],): AgentAwarenessPhase | null {  if (thread.hasPendingApprovals) {    return "waiting_for_approval";  }  if (thread.hasPendingUserInput) {    return "waiting_for_input";  }  if (thread.session?.status === "error" || thread.latestTurn?.state === "error") {    return "failed";  }  if (thread.session?.status === "starting") {    return "starting";  }  if (thread.session?.status === "running" || thread.latestTurn?.state === "running") {    return "running";  }  if (thread.latestTurn?.state === "completed") {    return "completed";  }  return null;} function headlineForPhase(phase: AgentAwarenessPhase): string {  switch (phase) {    case "starting":      return "Starting agent";    case "running":      return "Agent is working";    case "waiting_for_approval":      return "Approval needed";    case "waiting_for_input":      return "Waiting for input";    case "completed":      return "Agent finished";    case "failed":      return "Agent failed";    case "stale":      return "Update delayed";  }} function detailForPhase(  phase: AgentAwarenessPhase,  thread: ProjectThreadAwarenessInput["thread"],): string | undefined {  if (phase === "failed") {    return thread.session?.lastError ?? undefined;  }  if (phase === "completed") {    return "Review the completed task.";  }  if (phase === "running" && thread.session?.providerName) {    return `${thread.session.providerName} is active.`;  }  return undefined;}