import type { LiveSessionHandoff, WorkflowAgentSessionEvent } from "./types.js"; export function createLiveSessionHandoff(): LiveSessionHandoff { let state: LiveSessionHandoff["state"] = "local-running"; let turnActive = false; let boundary: Promise | undefined; let resolveBoundary: (() => void) | undefined; let takeover: Promise | undefined; let resolveTakeover: (() => void) | undefined; let takenOver = false; let resume: Promise | undefined; let resolveResume: (() => void) | undefined; let request: Promise | undefined; const waitForBoundary = (): Promise => { if (!turnActive) return Promise.resolve(); boundary ??= new Promise((resolve) => { resolveBoundary = resolve; }); return boundary; }; const finishBoundary = () => { turnActive = false; resolveBoundary?.(); boundary = undefined; resolveBoundary = undefined; }; const finishTakeover = () => { takenOver = true; state = "herdr-running"; resolveTakeover?.(); resolveTakeover = undefined; }; const isReleased = (): boolean => state === "completed"; return { get state() { return state; }, get transferred() { return takenOver; }, observe(event: WorkflowAgentSessionEvent) { if (["turn_start", "turn_started", "turnStarted", "agent_start"].includes(event.type)) turnActive = true; if (["turn_end", "turnEnded", "agent_end", "agent_settled"].includes(event.type)) finishBoundary(); }, async request(launch: () => Promise): Promise { if (request) return request; if (isReleased()) return; state = "handoff-pending"; takeover = new Promise((resolve) => { resolveTakeover = resolve; }); resume = new Promise((resolve) => { resolveResume = resolve; }); request = (async () => { await waitForBoundary(); if (isReleased()) return; state = "herdr-running"; try { await launch(); } finally { if (!takenOver) { state = "returning-local"; resolveTakeover?.(); resolveTakeover = undefined; } resolveResume?.(); state = "completed"; } })(); return request; }, waitForTakeover() { return takeover ?? Promise.resolve(); }, takeover() { if (state === "herdr-running" && !takenOver) finishTakeover(); }, waitForResume() { return resume ?? Promise.resolve(); }, release() { state = "completed"; finishBoundary(); resolveTakeover?.(); resolveTakeover = undefined; resolveResume?.(); resolveResume = undefined; }, }; }