UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

172 lines (171 loc) • 9.62 kB
import { uuidv7 } from "../../internal/harness.js"; import { snapshotActorAssertion } from "../../internal/llm.js"; import { MAX_STEER_INPUT_ID_CHARS } from "../checkpoint-store.js"; import { formatHookFeedback } from "../hooks.js"; import { classicEventBase, failedHandlerClause, screenUserPrompt } from "../mods/stations.js"; import { buildHumanInputEvent, frameMidTurnUserInput, projectHumanInput } from "../human-input-projection.js"; import { injectionLaneOf, isSystemInjectionPriority, steerPriorityOf, SYSTEM_INJECTION_PRIORITIES } from "../task-notification.js"; import { deliverEngineNotice } from "../types.js"; import { inlineUntrusted, sanitizeUntrustedText } from "../untrusted-text.js"; import { announceAcceptance, armAcceptance, nextHumanInputSeq } from "./steer-admission.js"; import { steerReplayRefusal } from "../steer-replay.js"; export function streamSteerVerb(input) { const { spec, internals, queue, acceptedSteerInputs, live, ready, orTimeout, readyTimeoutMs: READY_TIMEOUT_MS, steeringError, runner } = input; let steerChain = Promise.resolve(); const steer = async (text, options) => { if (options?.userAttachments !== undefined) { throw steeringError("a steer carries no attachments — declare them in TaskSpec.userAttachments on the next objective", "steering.invalid_content"); } const trusted = options?.trusted ? true : false; if (trusted && sanitizeUntrustedText(text) !== text) { throw steeringError("trusted steering text must not contain a </system-reminder> tag", "steering.invalid_content"); } const inputId = options?.inputId; if (inputId !== undefined) { if (typeof inputId !== "string") { throw steeringError("inputId must be a string when supplied", "steering.invalid_content"); } if (inputId === "" || inputId.length > MAX_STEER_INPUT_ID_CHARS) { throw steeringError(`inputId must be a non-empty string of at most ${MAX_STEER_INPUT_ID_CHARS} characters`, "steering.invalid_content"); } } const priorityIn = options?.priority; if (priorityIn !== undefined && !isSystemInjectionPriority(priorityIn)) { throw steeringError(`priority must be one of ${SYSTEM_INJECTION_PRIORITIES.join("/")} when supplied`, "steering.invalid_content"); } const priority = steerPriorityOf({ priority: priorityIn }); const actorIn = options?.actor; const actor = actorIn === undefined ? undefined : snapshotActorAssertion(actorIn); const projected = projectHumanInput({ text, actor, source: "steer" }); const effectiveInputId = typeof inputId === "string" ? inputId : uuidv7(); const parkRecord = { text, trusted, inputId: effectiveInputId, ...(priorityIn !== undefined ? { priority } : {}), ...(actor !== undefined ? { actor } : {}), }; let payload; let mintsAFrame; const publishQueued = (h) => { const identity = internals?.parentToolCallId !== undefined ? { parentToolCallId: internals.parentToolCallId, ...(spec.taskId !== undefined ? { sourceTaskId: spec.taskId } : {}) } : {}; queue.push({ ...buildHumanInputEvent({ carrier: "steer", source: "steer", delivery: "queued", sessionSeq: nextHumanInputSeq(h.harness), inputId: effectiveInputId, ...(actor !== undefined ? { actor } : {}), ...(actor?.issuer !== undefined ? { issuer: actor.issuer } : {}), ...(spec.principal !== undefined ? { principal: spec.principal } : {}), }), eventId: uuidv7(), ...identity, }); return identity; }; const noteAccepted = () => { if (!mintsAFrame) return; if (typeof inputId === "string") acceptedSteerInputs.set(inputId, parkRecord); announceAcceptance(parkRecord); }; const deliver = async () => { if (live.resultValue) throw steeringError("the task has already finished"); const h = live.handle ?? (await orTimeout(ready)); if (!h) throw steeringError("the task is not running"); payload = trusted ? formatHookFeedback(projected, h.reminderMark) : frameMidTurnUserInput(projected); mintsAFrame = payload.trim().length !== 0; if (typeof inputId === "string") { const prior = acceptedSteerInputs.get(inputId); if (prior !== undefined) { if (live.resultValue !== undefined || h.loop.ended) throw steeringError("the task is no longer running"); const refusal = steerReplayRefusal(prior, parkRecord, { seat: "accepted" }); if (refusal !== undefined) throw steeringError(refusal.message, "steering.duplicate_input_id", refusal.detail); return; } } if (live.resultValue !== undefined || h.loop.ended) throw steeringError("the task is no longer running"); if (mintsAFrame) { const screen = await screenUserPrompt(h.modBus, { ...classicEventBase(h.hookIdentity, h.permissionMode.observed), prompt: text, source: "steer", inputId: effectiveInputId, ...(actor !== undefined ? { actor: snapshotActorAssertion(actor) } : {}), }, h.abortController.signal); if (screen?.kind === "aborted") { throw steeringError(`the task was cancelled while the deployment's userPromptSubmit hook was still screening this steering input; the input was NOT accepted (fail-closed)`, "steering.blocked_by_hook"); } if (screen?.kind === "failed") { throw steeringError(`the deployment's userPromptSubmit hook ${failedHandlerClause(screen)} while screening this steering input; the input was NOT accepted (fail-closed)`, "steering.blocked_by_hook"); } if (screen?.block !== undefined && screen.block !== "") { throw steeringError(`the deployment's userPromptSubmit hook blocked this steering input: ${inlineUntrusted(screen.block)}`, "steering.blocked_by_hook"); } if (screen?.additionalContext !== undefined && screen.additionalContext !== "") { payload = `${formatHookFeedback(screen.additionalContext, h.reminderMark)}\n\n${payload}`; } } const injectFramed = async () => { const noteOptions = { provenance: "engine-note", callerAuthored: true, parkRecord, ...(actor !== undefined ? { actor } : {}) }; if (mintsAFrame) armAcceptance(parkRecord, () => publishQueued(h)); if (injectionLaneOf(priority) === "followUp") { await h.harness.followUp(payload, noteOptions); noteAccepted(); return; } const frame = await h.harness.steer(payload, { ...noteOptions, ...(priority === "now" ? { immediate: true } : {}) }); noteAccepted(); if (priority === "now" && frame !== undefined && h.harness.interruptTurn(frame)) { deliverEngineNotice(runner.deps.onNotice, { code: "task.turn_interrupted", message: "a caller-provenance steer with priority \"now\" interrupted the running turn: in-flight work was cut at " + "a manufactured boundary (finished tool calls keep their real results; never-started ones settle as " + "interrupted) and the run continues with the steer at the queue head.", detail: { inputId: effectiveInputId, sessionId: h.sessionId, runId: h.runId, ...(actor?.id !== undefined ? { actorId: actor.id } : {}), ...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}), }, }); } }; try { await injectFramed(); return; } catch (e) { if (!(e instanceof Error && e.code === "invalid_state")) throw e; } const birthDeadline = Date.now() + READY_TIMEOUT_MS; while (live.resultValue === undefined && !h.loop.ended && Date.now() < birthDeadline) { try { await injectFramed(); return; } catch (e2) { if (!(e2 instanceof Error && e2.code === "invalid_state")) throw e2; } await new Promise((r) => setTimeout(r, 10)); } throw steeringError("the task is no longer running"); }; const p = steerChain.then(deliver); steerChain = p.then(() => undefined, () => undefined); return p; }; return { steer }; }