import type { EnvironmentId, OrchestrationV2ThreadShell, Project, ThreadId,} from "@t3tools/contracts";import * as DateTime from "effect/DateTime"; 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 function buildAgentAwarenessDeepLink(input: { readonly environmentId: EnvironmentId; readonly threadId: ThreadId;}): string { return `/threads/${encodeURIComponent(input.environmentId)}/${encodeURIComponent(input.threadId)}`;} export interface ProjectThreadAwarenessV2Input { readonly environmentId: EnvironmentId; readonly project: Pick<Project, "title">; readonly thread: Pick< OrchestrationV2ThreadShell, | "activityRunStatus" | "id" | "modelSelection" | "pendingRuntimeRequest" | "status" | "title" | "updatedAt" >;} /** Build relay activity directly from the V2 shell projection. */export function projectThreadAwarenessV2( input: ProjectThreadAwarenessV2Input,): AgentAwarenessState | null { const { environmentId, project, thread } = input; const phase = resolveThreadAwarenessPhaseV2(thread); if (phase === null) { return null; } const detail = phase === "completed" ? "Review the completed task." : phase === "failed" ? "The agent run failed." : undefined; return { environmentId, threadId: thread.id, projectTitle: project.title, threadTitle: thread.title, phase, headline: headlineForPhase(phase), ...(detail === undefined ? {} : { detail }), modelTitle: thread.modelSelection.model, updatedAt: DateTime.formatIso(thread.updatedAt), deepLink: buildAgentAwarenessDeepLink({ environmentId, threadId: thread.id }), };} function resolveThreadAwarenessPhaseV2( thread: ProjectThreadAwarenessV2Input["thread"],): AgentAwarenessPhase | null { if (thread.pendingRuntimeRequest?.kind === "user_input") { return "waiting_for_input"; } if ( thread.pendingRuntimeRequest !== null && thread.pendingRuntimeRequest.kind !== "auth_refresh" ) { return "waiting_for_approval"; } switch (thread.activityRunStatus ?? thread.status) { case "preparing": case "starting": return "starting"; case "running": case "waiting": return "running"; case "completed": return "completed"; case "failed": return "failed"; case "idle": case "queued": case "interrupted": case "cancelled": case "rolled_back": 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"; }}
import type {
EnvironmentId,
OrchestrationV2ThreadShell,
Project,
ThreadId,
} from "@t3tools/contracts";
import * as DateTime from "effect/DateTime";
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 function buildAgentAwarenessDeepLink(input: {
readonly environmentId: EnvironmentId;
readonly threadId: ThreadId;
}): string {
return `/threads/${encodeURIComponent(input.environmentId)}/${encodeURIComponent(input.threadId)}`;
}
export interface ProjectThreadAwarenessV2Input {
readonly environmentId: EnvironmentId;
readonly project: Pick<Project, "title">;
readonly thread: Pick<
OrchestrationV2ThreadShell,
| "activityRunStatus"
| "id"
| "modelSelection"
| "pendingRuntimeRequest"
| "status"
| "title"
| "updatedAt"
>;
}
/** Build relay activity directly from the V2 shell projection. */
export function projectThreadAwarenessV2(
input: ProjectThreadAwarenessV2Input,
): AgentAwarenessState | null {
const { environmentId, project, thread } = input;
const phase = resolveThreadAwarenessPhaseV2(thread);
if (phase === null) {
return null;
}
const detail =
phase === "completed"
? "Review the completed task."
: phase === "failed"
? "The agent run failed."
: undefined;
return {
environmentId,
threadId: thread.id,
projectTitle: project.title,
threadTitle: thread.title,
phase,
headline: headlineForPhase(phase),
...(detail === undefined ? {} : { detail }),
modelTitle: thread.modelSelection.model,
updatedAt: DateTime.formatIso(thread.updatedAt),
deepLink: buildAgentAwarenessDeepLink({ environmentId, threadId: thread.id }),
};
}
function resolveThreadAwarenessPhaseV2(
thread: ProjectThreadAwarenessV2Input["thread"],
): AgentAwarenessPhase | null {
if (thread.pendingRuntimeRequest?.kind === "user_input") {
return "waiting_for_input";
}
if (
thread.pendingRuntimeRequest !== null &&
thread.pendingRuntimeRequest.kind !== "auth_refresh"
) {
return "waiting_for_approval";
}
switch (thread.activityRunStatus ?? thread.status) {
case "preparing":
case "starting":
return "starting";
case "running":
case "waiting":
return "running";
case "completed":
return "completed";
case "failed":
return "failed";
case "idle":
case "queued":
case "interrupted":
case "cancelled":
case "rolled_back":
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";
}
}