UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

145 lines (144 loc) • 6.2 kB
import { boundedRedactedSummary } from "./untrusted-egress.js"; import { delimitUntrusted } from "./untrusted-text.js"; import { thrownText } from "./thrown-value.js"; import { assertOwnership, canAccessWorkflowRun, formatWorkflowRun, sleepPollStep, } from "./task-registry-shared.js"; export function registerWorkflowLane(core, input) { assertOwnership(input, "registerWorkflow"); const id = input.runId; if (core.handles.has(id)) throw new Error(`TaskRegistry: task id already registered: ${id}`); const now = input.now ?? Date.now(); const originatingSessionId = input.originatingSessionId; const handle = { id, type: "workflow", status: "running", ...(input.description !== undefined ? { description: input.description } : {}), ...(input.owner !== undefined ? { owner: input.owner } : {}), ...(input.scope !== undefined ? { scope: input.scope } : {}), ...(input.toolUseId !== undefined ? { toolUseId: input.toolUseId } : {}), createdAt: now, updatedAt: now, runId: id, handle: input.handle, ...(input.store !== undefined ? { store: input.store } : {}), ...(originatingSessionId !== undefined ? { originatingSessionId, sessionScoped: true } : {}), ...(input.onServedTerminal !== undefined ? { onServedTerminal: input.onServedTerminal } : {}), }; core.handles.set(id, handle); void input.handle.done.then((res) => { handle.status = "completed"; const run = res?.run; const r = run?.resultFull ?? run?.result; if (typeof r === "string") handle.result = r; if (run?.completionId !== undefined) handle.completionId = run.completionId; handle.updatedAt = Date.now(); }, (err) => { if (handle.status !== "cancelled") handle.status = "failed"; handle.error = boundedRedactedSummary(thrownText(err), 500); const rejectedRun = err !== null && (typeof err === "object" || typeof err === "function") ? err.workflowRun : undefined; if (rejectedRun?.completionId !== undefined) handle.completionId = rejectedRun.completionId; handle.updatedAt = Date.now(); }); return id; } function fireServedTerminalLane(handle) { const cb = handle.onServedTerminal; if (!cb) return; handle.onServedTerminal = undefined; try { cb(); } catch { } } export async function pollWorkflowLane(handle, access, deadline, signal) { const store = handle.store; if (store) { for (;;) { const run = await store.get(handle.runId); if (!run || !canAccessWorkflowRun(run, access)) break; if (run.status !== "running" || deadline === undefined || Date.now() >= deadline || signal?.aborted) { const out = formatWorkflowRun(run); if (run.status === "running" && deadline !== undefined && Date.now() >= deadline) out.details.retrieval_status = "timeout"; else if (run.status !== "running") fireServedTerminalLane(handle); return out; } await sleepPollStep(deadline, signal); } } while (handle.status === "running" && deadline !== undefined && Date.now() < deadline && !signal?.aborted) { await sleepPollStep(deadline, signal); } if (handle.status !== "running") fireServedTerminalLane(handle); return { content: JSON.stringify({ task_id: handle.id, runId: handle.id, type: "workflow", status: handle.status, ...(handle.status === "completed" && handle.result !== undefined ? { result: delimitUntrusted("workflow result", handle.result) } : {}), ...(handle.status === "failed" && handle.error !== undefined ? { error: delimitUntrusted("workflow error", handle.error) } : {}), note: handle.status === "running" ? "still running — poll again shortly." : handle.status === "completed" ? handle.result !== undefined ? "completed — `result` above is the workflow's return value." : "completed — its result was delivered on the completion notification." : handle.status === "failed" && handle.error !== undefined ? "failed — see error." : "workflow reached a terminal state.", }), details: { task_id: handle.id, type: "workflow", status: handle.status, retrieval_status: handle.status === "running" && deadline !== undefined && Date.now() >= deadline ? "timeout" : "success", ...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}), }, }; } export async function stopWorkflowLane(handle) { if (handle.status !== "running") { return { content: JSON.stringify({ task_id: handle.id, runId: handle.id, type: "workflow", status: handle.status, stopped: false, note: `workflow already ${handle.status} — nothing to stop; poll TaskOutput for its final state.`, }), details: { task_id: handle.id, type: "workflow", status: handle.status, retrieval_status: "success" }, }; } handle.status = "cancelled"; handle.updatedAt = Date.now(); handle.handle.cancel("TaskStop requested"); return { content: JSON.stringify({ task_id: handle.id, runId: handle.id, type: "workflow", status: "cancelled", stopped: true, note: "workflow cancellation requested; durable run status maps cancellation to failed when it finalizes.", }), details: { task_id: handle.id, type: "workflow", status: "cancelled", retrieval_status: "success" }, }; }