UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

87 lines (86 loc) • 5.63 kB
import { valveLeaves } from "../../agents/tool-filter.js"; import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool, isLiveQuestionFace } from "../ask-question.js"; import { boundInputHashOf } from "../canonical-json.js"; import { durableParkOptInDeclared } from "../tool-policy.js"; import { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js"; import { RosterBuilder } from "../tool-roster.js"; export { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js"; export function prepareQuestionFace(input) { const { frozenOnQuestion, spec, deps, checkpointStore, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, toolFaceSnapshot, inheritedUnavailableAsks } = input; const tools = roster.tools; const onQuestion = frozenOnQuestion; const liveQuestionFace = isLiveQuestionFace(onQuestion) ? onQuestion : undefined; const contentAskBindings = new Map(); const questionParkStoreWired = checkpointStore !== undefined; const questionDurableMandateBinding = runtimeCaps?.forceDurableGate === true && questionParkStoreWired; const contentAskRoutable = (toolCallId) => liveQuestionFace !== undefined && mountedQuestionTool !== undefined && tools.includes(mountedQuestionTool) && !questionDurableMandateBinding && !inheritedUnavailableAsks().has(toolCallId); const lateStrandedAnswers = []; const discloseStrandedAnswers = (records, why) => { if (records.length === 0) return; try { deps.onError?.(new Error(`AskUserQuestion: ${records.length} question(s) were answered by a person but the call never ` + `executed to collect the answer (${records.map((r) => `${r.toolCallId} [delivery ${r.deliveryId}]`).join(", ")}) — ${why}. The answer(s) were NOT ` + `delivered to the model and are gone with this leg; re-ask if the decision is still needed.`), { phase: "degraded", sessionId, classification: "unconsumed-human-answer" }); } catch { } }; const settleContentAskBindings = () => { const stranded = []; for (const [callId, bound] of contentAskBindings) { if (bound.kind === "answered") stranded.push({ deliveryId: bound.deliveryId, toolCallId: callId }); } contentAskBindings.clear(); discloseStrandedAnswers(stranded, "the leg ended first (abort, batch teardown, or a loop failure)"); const byDelivery = new Map(); for (const r of [...stranded, ...lateStrandedAnswers]) byDelivery.set(r.deliveryId, r); return [...byDelivery.values()]; }; const durableQuestionFace = questionParkStoreWired && durableParkOptInDeclared({ forceDurableGate: runtimeCaps?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined }); const mountedQuestionFace = liveQuestionFace !== undefined ? async (req, signal) => { const bound = contentAskBindings.get(req.toolCallId); if (bound !== undefined) { if (bound.questionsHash === boundInputHashOf(req.questions)) { contentAskBindings.delete(req.toolCallId); if (bound.kind === "answered") return bound.answer; throw bound.error; } contentAskBindings.delete(req.toolCallId); } return liveQuestionFace(req, signal); } : onQuestion; const questionToolMounted = (spec.interactiveTools === true || (spec.interactiveTools !== false && (onQuestion !== undefined || durableQuestionFace))) && valveLeaves(spec, toolFaceSnapshot.selector)({ name: ASK_USER_QUESTION_TOOL_NAME }); let mountedQuestionTool; if (questionToolMounted) roster.mount((mountedQuestionTool = createAskUserQuestionTool(mountedQuestionFace, { principal: spec.principal, sourceTaskId: sessionId }, { ...(resume?.redeemedContentAskCallId !== undefined ? { redeemedApprovalCallId: resume.redeemedContentAskCallId, ...(resume.redeemedContentAskQuestionsHash !== undefined ? { redeemedApprovalQuestionsHash: resume.redeemedContentAskQuestionsHash } : {}), } : {}), ...(resolvedInteractionPosture !== undefined ? { posture: resolvedInteractionPosture } : {}), ...(spec.interactiveQuestionFallback === true ? { interactiveFallback: true } : {}), onSyntheticContinuation: ({ questionId, reason }) => { deps.onError?.(new Error(`AskUserQuestion ${questionId}: no human answer was obtainable (` + (reason === "seam_absent" ? "no onQuestion seam is wired" : reason === "declined_unavailable" ? "the wired question channel reported nobody was reachable" : "the wired question channel failed") + `) — the model was instructed to self-answer and the run CONTINUES (warning, not a failure).`), { phase: "degraded", sessionId, classification: "no-human-autoanswered" }); }, })), { source: "builtin", mountedBy: "optional" }); return { checkpointStore, liveQuestionFace, contentAskBindings, contentAskRoutable, lateStrandedAnswers, discloseStrandedAnswers, settleContentAskBindings, durableQuestionFace, mountedQuestionFace, questionToolMounted, mountedQuestionTool }; }