UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

75 lines (74 loc) 4.08 kB
import { s as extractEmbeddedAssistantText } from "./embedded-agent-utils-DLNh77Fj.js"; import { r as prepareSimpleCompletionModelForAgent, t as completeWithPreparedSimpleCompletionModel } from "./simple-completion-runtime-Dgdi_92D.js"; import { t as classifySystemAgentApprovalText } from "./operator-approval-BAOcpwRx.js"; import { a as resolveSystemAgentVerifiedInferenceRoute } from "./verified-inference-D8I0G1w6.js"; //#region src/system-agent/approval-intent.ts const APPROVAL_INTENT_TIMEOUT_MS = 1e4; const APPROVAL_INTENT_MAX_TOKENS = 8; const APPROVAL_INTENT_SYSTEM_PROMPT = [ "You classify one chat message from a user who was just asked to approve a pending configuration change.", "Reply with exactly one word:", "approve — the message clearly consents to applying the pending change now.", "decline — the message clearly rejects or postpones the pending change.", "other — anything else: questions, new requests, partial or conditional agreement, or unclear intent.", "Only classify consent for the pending change itself. A message asking to change the proposal is not approval." ].join("\n"); /** * Judge whether a message approves the pending proposal. Closed-list answers * short-circuit so a literal "yes" cannot be reinterpreted by the conversation * model; ambiguous messages go to a separate configured completion call. * CLI-harness routes do not spawn a second harness for that check, so their * ambiguous replies stay "other" and the conversation asks for a clear yes. */ async function classifySystemAgentApprovalIntent(params, deps = {}) { const textIntent = classifySystemAgentApprovalText(params.message); if (textIntent !== "other") return textIntent; try { const resolveVerifiedRoute = deps.resolveVerifiedInferenceRoute ?? resolveSystemAgentVerifiedInferenceRoute; const route = await resolveVerifiedRoute(params.verifiedInference); if (!route || route.runner !== "embedded" || route.agentHarnessRuntimeOverride !== "openclaw") return "other"; const modelRef = route.authProfileId ? `${route.modelLabel}@${route.authProfileId}` : route.modelLabel; const prepared = await (deps.prepareSimpleCompletionModelForAgent ?? prepareSimpleCompletionModelForAgent)({ cfg: route.runConfig, agentId: route.agentId, agentDir: route.agentDir, modelRef, ...route.authProfileId ? { preferredProfile: route.authProfileId } : {}, allowMissingApiKeyModes: ["aws-sdk"], bindAuthOwner: true }); if ("error" in prepared) return "other"; if ((prepared.selection.runtimeProvider ?? prepared.selection.provider) !== route.provider || prepared.selection.modelId !== route.model || prepared.selection.agentDir !== route.agentDir || prepared.selection.profileId !== route.authProfileId || prepared.auth.profileId !== route.authProfileId || !params.verifiedInference.auth.authFingerprint || prepared.sourceAuthFingerprint !== params.verifiedInference.auth.authFingerprint) return "other"; const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), APPROVAL_INTENT_TIMEOUT_MS); try { const response = await (deps.completeWithPreparedSimpleCompletionModel ?? completeWithPreparedSimpleCompletionModel)({ model: prepared.model, auth: prepared.auth, cfg: route.runConfig, context: { systemPrompt: APPROVAL_INTENT_SYSTEM_PROMPT, messages: [{ role: "user", content: [`Pending change: ${params.proposal ?? "a configuration change proposed in this conversation"}`, `User message: ${params.message}`].join("\n"), timestamp: Date.now() }] }, options: { maxTokens: APPROVAL_INTENT_MAX_TOKENS, signal: controller.signal } }); if (!await resolveVerifiedRoute(params.verifiedInference)) return "other"; const verdict = extractEmbeddedAssistantText(response)?.trim().toLowerCase().split(/\s+/)[0]; if (verdict === "approve" || verdict === "decline") return verdict; return "other"; } finally { clearTimeout(timer); } } catch { return "other"; } } //#endregion export { classifySystemAgentApprovalIntent };