UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

176 lines (175 loc) 9.51 kB
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js"; import { An as validatePluginApprovalResolveParams, kn as validatePluginApprovalRequestParams } from "./src-BiL5aQto.js"; import { d as errorShape } from "./error-codes-Bo8q2D1o.js"; import { a as resolveStoredSessionKeyForAgentStore } from "./session-store-key-8xEjWSNi.js"; import { i as sanitizeExecApprovalWarningText, n as sanitizeExecApprovalDisplayText, t as exceedsApprovalTextLimit } from "./exec-approval-text-sanitize-C1BzZQH8.js"; import { t as sanitizeApprovalScope } from "./approval-scope-BL54HpUv.js"; import { f as resolvePluginApprovalTimeoutMs, p as truncatePluginApprovalDetail } from "./plugin-approvals-BUrr4V_c.js"; import { t as resolveCanonicalPluginApprovalRequestAllowedDecisions } from "./plugin-approval-canonical-decisions-CwBFXTtw.js"; import { n as resolveRequestedSessionAgentId } from "./session-request-agent-CCRSEGCB.js"; import { n as takeMcpToolApprovalBinding } from "./mcp-tool-approval-binding-CMAQhA0e.js"; import { t as assertValidParams } from "./validation-pzrlzFvo.js"; import { a as handleApprovalResolve, c as registerPendingApprovalRecord, i as buildRequestedApprovalEvent, l as resolveApprovalDecisionParams, m as listVisiblePendingApprovalRequests, n as bindApprovalReviewerDeviceIds, o as handleApprovalWaitDecision, s as handlePendingApprovalRequest, t as bindApprovalRequesterMetadata } from "./approval-shared-ahH5xF_7.js"; import { t as runApprovalRequestDeliveries } from "./approval-request-delivery-BVUQ3faZ.js"; import { randomUUID } from "node:crypto"; //#region src/gateway/server-methods/plugin-approval.ts /** Create plugin approval handlers backed by the shared approval manager. */ function createPluginApprovalHandlers(manager, opts) { return { "plugin.approval.list": async ({ respond, client, context }) => { respond(true, listVisiblePendingApprovalRequests({ manager, client, approvalKind: "plugin", ...client?.authenticatedUserProfile ? { cfg: context.getRuntimeConfig() } : {} }), void 0); }, "plugin.approval.request": async ({ params, client, respond, context }) => { if (!assertValidParams(params, validatePluginApprovalRequestParams, "plugin.approval.request", respond)) return; const p = params; const twoPhase = p.twoPhase === true; const timeoutMs = resolvePluginApprovalTimeoutMs(p.timeoutMs); const trustedAgentRuntime = client?.internal?.agentRuntimeIdentity; if (trustedAgentRuntime && context.validateAgentRuntimeApprovalAuthority?.(trustedAgentRuntime) !== true) { respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "agent runtime approval authority is no longer active")); return; } if (trustedAgentRuntime && !trustedAgentRuntime.approvalOwnerPluginId) { respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "signed plugin approval owner is unavailable")); return; } const normalizeTrimmedString = (value) => normalizeOptionalString(value) || null; const rawSessionKey = normalizeOptionalString(trustedAgentRuntime?.sessionKey ?? p.sessionKey); const sessionOwner = rawSessionKey ? resolveRequestedSessionAgentId(context.getRuntimeConfig(), rawSessionKey, normalizeOptionalString(trustedAgentRuntime?.agentId ?? p.agentId)) : void 0; if (sessionOwner && !sessionOwner.ok) { respond(false, void 0, sessionOwner.error); return; } const sessionKey = rawSessionKey && sessionOwner?.ok ? resolveStoredSessionKeyForAgentStore({ cfg: context.getRuntimeConfig(), agentId: sessionOwner.agentId, sessionKey: rawSessionKey }) : null; const sanitizedTitle = sanitizeExecApprovalDisplayText(p.title); const sanitizedDescription = sanitizeExecApprovalWarningText(p.description); if (exceedsApprovalTextLimit(sanitizedTitle, 80) || exceedsApprovalTextLimit(sanitizedDescription, 512)) { respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "approval title or description exceeds the display limit after sanitization")); return; } const rawDetail = normalizeTrimmedString(p.detail); const sanitizeMeta = (value) => normalizeTrimmedString(value) === null ? null : sanitizeExecApprovalDisplayText(normalizeTrimmedString(value)); const request = { pluginId: trustedAgentRuntime?.approvalOwnerPluginId ?? sanitizeMeta(p.pluginId), title: sanitizedTitle, description: sanitizedDescription, scope: p.scope ? sanitizeApprovalScope(p.scope) : null, detail: rawDetail === null ? null : truncatePluginApprovalDetail(sanitizeExecApprovalWarningText(rawDetail)), severity: p.severity ?? null, toolName: sanitizeMeta(p.toolName), toolCallId: p.toolCallId ?? null, ...trustedAgentRuntime && p.mcpTool ? { mcpTool: { ...p.mcpTool } } : {}, ...Array.isArray(p.allowedDecisions) ? { allowedDecisions: resolveCanonicalPluginApprovalRequestAllowedDecisions({ allowedDecisions: p.allowedDecisions }) } : {}, agentId: trustedAgentRuntime?.agentId ?? (sessionOwner?.ok ? sessionOwner.agentId : sanitizeMeta(p.agentId)), sessionKey, runId: trustedAgentRuntime?.operationalRunInstance.runId ?? null, turnSourceChannel: trustedAgentRuntime ? normalizeTrimmedString(trustedAgentRuntime.turnSourceChannel) : normalizeTrimmedString(p.turnSourceChannel), turnSourceTo: trustedAgentRuntime ? normalizeTrimmedString(trustedAgentRuntime.turnSourceTo) : normalizeTrimmedString(p.turnSourceTo), turnSourceAccountId: trustedAgentRuntime ? normalizeTrimmedString(trustedAgentRuntime.turnSourceAccountId) : normalizeTrimmedString(p.turnSourceAccountId), turnSourceThreadId: trustedAgentRuntime ? trustedAgentRuntime.turnSourceThreadId ?? null : p.turnSourceThreadId ?? null }; const record = manager.create(request, timeoutMs, `plugin:${randomUUID()}`); if (trustedAgentRuntime) { record.agentRuntimeDelegatedAuthority = trustedAgentRuntime.delegatedAuthority; if (request.mcpTool && request.toolCallId) record.mcpToolApprovalActive = takeMcpToolApprovalBinding({ authority: trustedAgentRuntime.delegatedAuthority, agentId: trustedAgentRuntime.agentId, toolCallId: request.toolCallId, ...request.mcpTool }); } if (trustedAgentRuntime?.executionIdentity && request.runId === trustedAgentRuntime.executionIdentity.runId) record.executionIdentityToken = trustedAgentRuntime.executionIdentity; bindApprovalRequesterMetadata({ record, client }); if (client?.internal?.approvalRuntime === true) bindApprovalReviewerDeviceIds({ record, deviceIds: p.approvalReviewerDeviceIds }); if (!registerPendingApprovalRecord({ manager, record, timeoutMs, respond, context })) return; const requestEvent = buildRequestedApprovalEvent(record, "plugin"); const forwardRequest = opts?.forwarder?.handlePluginApprovalRequested?.bind(opts.forwarder); const iosPushRequest = opts?.iosPushDelivery?.handleRequested?.bind(opts.iosPushDelivery); await handlePendingApprovalRequest({ manager, record, respond, context, clientConnId: client?.connId, requestEventName: "plugin.approval.requested", requestEvent, twoPhase, approvalKind: "plugin", deliverRequest: () => runApprovalRequestDeliveries({ context, record, forward: forwardRequest ? [() => forwardRequest(requestEvent), "plugin approvals: forward request failed"] : void 0, iosPush: iosPushRequest ? [(isTargetVisible) => iosPushRequest(requestEvent, { isTargetVisible }), "plugin approvals: iOS push request failed"] : void 0 }), afterDecision: async (decision) => { if (decision === null) await opts?.iosPushDelivery?.handleExpired?.(requestEvent); }, afterDecisionErrorLabel: "plugin approvals: iOS push expire failed" }); }, "plugin.approval.waitDecision": async ({ params, respond, client, context }) => { await handleApprovalWaitDecision({ manager, inputId: params.id, client, ...client?.authenticatedUserProfile ? { cfg: context.getRuntimeConfig() } : {}, respond }); }, "plugin.approval.resolve": async ({ params, respond, client, context }) => { const resolveParams = resolveApprovalDecisionParams({ rawParams: params, validate: validatePluginApprovalResolveParams, methodName: "plugin.approval.resolve", respond }); if (!resolveParams) return; const { inputId, decision, reviewer } = resolveParams; await handleApprovalResolve({ approvalKind: "plugin", manager, inputId, decision, respond, context, client, reviewer, exposeAmbiguousPrefixError: false, validateDecision: (snapshot) => resolveCanonicalPluginApprovalRequestAllowedDecisions(snapshot.request).includes(decision) ? null : { message: `${decision} is unavailable for this plugin approval`, details: { allowedDecisions: resolveCanonicalPluginApprovalRequestAllowedDecisions(snapshot.request) } }, forwardResolved: (resolvedEvent) => opts?.forwarder?.handlePluginApprovalResolved?.(resolvedEvent), forwardResolvedErrorLabel: "plugin approvals: forward resolve failed", extraResolvedHandlers: opts?.iosPushDelivery?.handleResolved ? [{ run: (resolvedEvent) => opts.iosPushDelivery.handleResolved(resolvedEvent), errorLabel: "plugin approvals: iOS push resolve failed" }] : void 0 }); } }; } //#endregion export { createPluginApprovalHandlers };