UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

203 lines (202 loc) 8.89 kB
import { r as createLazyRuntimeModule } from "./lazy-runtime-CgCh8H_K.js"; import { c as WRITE_SCOPE, n as APPROVALS_SCOPE } from "./operator-scopes-Dw7Gu2cA.js"; import { t as DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS } from "./timeouts-D2XMKe-X.js"; import "./method-scopes-K6J_UQGL.js"; import { l as registerSubagentCompletionToolHandoff, s as cancelSubagentCompletionToolHandoff, u as dispatchGatewayRequestInProcess } from "./server-plugin-in-process-dispatch-DYlW9gzA.js"; import { t as createSyntheticPluginRuntimeClient } from "./server-plugin-runtime-client-CfhFBErP.js"; import { r as registerGatewayRecoveryRuntime } from "./server-recovery-runtime-context-Cx7vLPdb.js"; import { t as createApprovalNativeRouteCoordinator } from "./approval-native-route-coordinator-dwijzZNW.js"; import { t as GATEWAY_NATIVE_APPROVAL_METHODS } from "./approval-gateway-runtime-methods-CZtHej9H.js"; import { t as createOutboundSendDeps } from "./outbound-send-deps-CzQHPhLv.js"; import { t as createInternalAgentTurnFacade } from "./internal-facade-BbuEc6gV.js"; //#region src/gateway/server-instance-runtime.ts const loadOutboundMessageRuntime = createLazyRuntimeModule(() => import("./message-BJzxaHQV.js")); const RECOVERY_NOTICE_COMPLETION_RETENTION = { idPrefix: "main-session-restart-recovery:", maxAgeMs: 864e5, maxEntries: 2e3 }; /** Creates closed internal principals bound to one concrete Gateway lifecycle. */ function createGatewayInstanceRuntime(options) { const approvalSubscribers = /* @__PURE__ */ new Set(); const routeCoordinator = createApprovalNativeRouteCoordinator(); let closed = false; const assertDispatchAvailable = (method) => { if (closed || !options.isDispatchAvailable()) throw new Error(`Gateway instance dispatch unavailable for ${method}`); }; const createAgentTurnFacade = (principal) => { const assertContextCurrent = () => { assertDispatchAvailable("agent turn"); principal.assertContextCurrent?.(); }; return createInternalAgentTurnFacade({ ...principal, assertContextCurrent, getContext: options.getContext, getMethodRegistry: options.getMethodRegistry }); }; const dispatch = async (params) => { assertDispatchAvailable(params.method); if (!params.allowedMethods.has(params.method)) throw new Error(`Gateway internal principal cannot dispatch ${params.method}`); return await dispatchGatewayRequestInProcess(params.method, params.payload, { client: params.client, context: options.getContext(), methodRegistry: options.getMethodRegistry(), requestIdPrefix: "gateway-internal", timeoutMs: params.timeoutMs }); }; const recoveryClient = createSyntheticPluginRuntimeClient({ operatorRoleActor: { kind: "system" }, scopes: [WRITE_SCOPE] }); const recoveryAgentTurns = createAgentTurnFacade({ client: recoveryClient }); const recoveryControlMethods = /* @__PURE__ */ new Set(["chat.abort"]); const approvalClient = createSyntheticPluginRuntimeClient({ operatorRoleActor: { kind: "system" }, scopes: [APPROVALS_SCOPE] }); const approvalMethods = new Set(GATEWAY_NATIVE_APPROVAL_METHODS); const approvalRouteClient = createSyntheticPluginRuntimeClient({ operatorRoleActor: { kind: "system" }, scopes: [WRITE_SCOPE] }); const approvalRouteMethods = /* @__PURE__ */ new Set(["send"]); const recovery = { abortAgent: async (payload, timeoutMs) => await dispatch({ allowedMethods: recoveryControlMethods, client: recoveryClient, method: "chat.abort", payload, timeoutMs }), dispatchAgent: async (payload, timeoutMs, dispatchOptions = {}) => { assertDispatchAvailable("agent"); const delegatedToolPolicyHandoffId = dispatchOptions.delegatedToolPolicyHandoff ? registerSubagentCompletionToolHandoff(dispatchOptions.delegatedToolPolicyHandoff) : void 0; const agentTurns = Boolean(dispatchOptions.allowModelOverride === true || dispatchOptions.allowSyntheticModelOverride === true || dispatchOptions.allowSyntheticCronRunContinuation === true || dispatchOptions.internalDeliveryMediaUrls || dispatchOptions.internalDeliverySuppressText === true || delegatedToolPolicyHandoffId || dispatchOptions.scopes || dispatchOptions.syntheticScopes) ? createAgentTurnFacade({ client: createSyntheticPluginRuntimeClient({ operatorRoleActor: { kind: "system" }, allowModelOverride: dispatchOptions.allowModelOverride === true || dispatchOptions.allowSyntheticModelOverride === true, cronRunContinuation: dispatchOptions.allowSyntheticCronRunContinuation === true, internalDeliveryMediaUrls: dispatchOptions.internalDeliveryMediaUrls, internalDeliverySuppressText: dispatchOptions.internalDeliverySuppressText, delegatedToolPolicyHandoffId, scopes: dispatchOptions.scopes ?? dispatchOptions.syntheticScopes }) }) : recoveryAgentTurns; try { return await agentTurns.dispatch(payload, { expectFinal: dispatchOptions.expectFinal, onAccepted: dispatchOptions.onAccepted, onExecutionStarted: dispatchOptions.onExecutionStarted, onSignalAbort: dispatchOptions.onSignalAbort, signal: dispatchOptions.signal, timeoutMs }); } finally { cancelSubagentCompletionToolHandoff(delegatedToolPolicyHandoffId); } }, waitForAgent: async (payload, timeoutMs) => { assertDispatchAvailable("agent.wait"); return await recoveryAgentTurns.wait(payload, timeoutMs); }, sendRecoveryNotice: async (payload) => { if (closed || !options.isDispatchAvailable()) throw new Error("Gateway instance dispatch unavailable for recovery notice"); const { sendMessage } = await loadOutboundMessageRuntime(); if (payload.isCurrent?.() === false) throw new Error("Recovery notice owner retired before delivery"); const context = options.getContext(); const result = await sendMessage({ cfg: context.getRuntimeConfig(), deps: createOutboundSendDeps(context.deps), channel: payload.channel, to: payload.to, accountId: payload.accountId, threadId: payload.threadId, content: payload.text, gatewayOwnedDelivery: true, bestEffort: true, idempotencyKey: payload.idempotencyKey, deliveryIntentId: payload.idempotencyKey, reusePendingDeliveryIntent: true, completionRetention: RECOVERY_NOTICE_COMPLETION_RETENTION, onPlatformSendDispatch: async () => { if (closed || !options.isDispatchAvailable() || payload.isCurrent?.() === false) throw new Error("Recovery notice owner retired before delivery"); }, abortSignal: AbortSignal.timeout(1e4) }); if (result.deliveryStatus === "failed" || result.deliveryStatus === "partial_failed") throw new Error(result.error ?? "recovery notice delivery failed"); return { suppressed: result.deliveryStatus === "suppressed" }; } }; const releaseRecoveryRuntime = registerGatewayRecoveryRuntime(recovery); const publish = (kind, callback, shouldDeliver) => { if (closed) return 0; let delivered = 0; for (const subscriber of approvalSubscribers) { if (!subscriber.eventKinds.has(kind)) continue; try { if (shouldDeliver && !shouldDeliver(subscriber)) continue; callback(subscriber); delivered += 1; } catch (error) { options.logError?.(`internal approval subscriber failed: ${String(error)}`); } } return delivered; }; return { createAgentTurnFacade, approvalEvents: { publishRequested: (kind, request) => publish(kind, (subscriber) => subscriber.onRequested(request), (subscriber) => subscriber.shouldHandle(request)), publishResolved: (kind, resolved) => { publish(kind, (subscriber) => subscriber.onResolved(resolved)); } }, nativeApprovals: { request: async (method, payload, requestOptions) => await dispatch({ allowedMethods: approvalMethods, client: requestOptions?.clientDisplayName ? { ...approvalClient, connect: { ...approvalClient.connect, client: { ...approvalClient.connect.client, displayName: requestOptions.clientDisplayName } } } : approvalClient, method, payload, timeoutMs: DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS }), requestRoute: async (method, payload) => await dispatch({ allowedMethods: approvalRouteMethods, client: approvalRouteClient, method, payload, timeoutMs: DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS }), routeCoordinator, subscribe: (subscriber) => { if (closed) throw new Error("Gateway instance approval runtime is closed"); approvalSubscribers.add(subscriber); let subscribed = true; return () => { if (!subscribed) return; subscribed = false; approvalSubscribers.delete(subscriber); }; } }, recovery, isAvailable: () => !closed && options.isDispatchAvailable(), close: () => { closed = true; releaseRecoveryRuntime(); approvalSubscribers.clear(); routeCoordinator.close(); } }; } //#endregion export { createGatewayInstanceRuntime };