UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

154 lines (153 loc) 6.21 kB
import { n as isTruthyEnvValue } from "./env-M3R40TOb.js"; import { l as toSafeImportPath } from "./plugin-module-loader-cache-lf3kAaBw.js"; import { u as getActivePluginRegistry } from "./runtime-BL4wZfTq.js"; import "./gateway-request-scope-BCMYlsDI.js"; import "./hook-runner-global-0kfmMG4T.js"; import { a as claimPluginInteractiveCallbackDedupe, i as resolvePluginInteractiveRegistrationsMatch, o as commitPluginInteractiveCallbackDedupe, s as releasePluginInteractiveCallbackDedupe } from "./interactive-registry-DbHFuhgi.js"; import { c as getCurrentPluginConversationBinding, f as requestPluginConversationBinding, s as detachPluginConversationBinding } from "./conversation-binding-DNzZGFgH.js"; import "./commands-BUsmcpiw.js"; import "./command-specs-BwM0QcBl.js"; //#region src/plugins/interactive-binding-helpers.ts /** Helpers for binding interactive plugin handlers to conversations and sessions. */ function createInteractiveConversationBindingHelpers(params) { const { registration, senderId, conversation } = params; const pluginRoot = registration.pluginRoot; return { requestConversationBinding: async (binding = {}) => { if (!pluginRoot) return { status: "error", message: "This interaction cannot bind the current conversation." }; return requestPluginConversationBinding({ pluginId: registration.pluginId, pluginName: registration.pluginName, pluginRoot, requestedBySenderId: senderId, conversation, binding }); }, detachConversationBinding: async () => { if (!pluginRoot) return { removed: false }; return detachPluginConversationBinding({ pluginRoot, conversation }); }, getCurrentConversationBinding: async () => { if (!pluginRoot) return null; return getCurrentPluginConversationBinding({ pluginRoot, conversation }); } }; } //#endregion //#region src/plugins/interactive.ts function resolveActivePluginInteractiveNamespaceMatch(channel, data) { return resolvePluginInteractiveRegistrationsMatch(getActivePluginRegistry()?.interactiveHandlers ?? [], channel, data); } /** Dispatches one interactive callback payload to a matching plugin handler. */ async function dispatchPluginInteractiveHandler(params) { const match = resolveActivePluginInteractiveNamespaceMatch(params.channel, params.data); if (!match) return { matched: false, handled: false, duplicate: false }; const dedupeKey = params.dedupeId?.trim(); if (dedupeKey && !claimPluginInteractiveCallbackDedupe(dedupeKey)) return { matched: true, handled: true, duplicate: true }; try { await params.onMatched?.(); const resolved = await params.invoke(match); await params.afterInvoke?.(resolved); if (dedupeKey) commitPluginInteractiveCallbackDedupe(dedupeKey); const shouldExposeResult = Boolean(resolved) && typeof resolved === "object" && Object.keys(resolved).some((key) => key !== "handled"); return { matched: true, handled: resolved?.handled ?? true, duplicate: false, ...shouldExposeResult ? { result: resolved } : {} }; } catch (error) { if (dedupeKey) releasePluginInteractiveCallbackDedupe(dedupeKey); throw error; } } /** Creates a channel dispatcher for plugin-owned interactive callbacks. */ function createChannelInteractiveDispatcher(config) { return async (params) => await dispatchPluginInteractiveHandler({ channel: config.channel, data: params.data, dedupeId: params.dedupeId, onMatched: params.onMatched, afterInvoke: params.afterInvoke, invoke: ({ registration, namespace, payload }) => { const dispatchInteractiveKey = config.dispatchInteractiveKey ?? config.interactiveKey; const { [dispatchInteractiveKey]: interactiveContext, ...handlerContext } = params.ctx; const conversation = params.conversation ?? { channel: config.channel, accountId: params.ctx.accountId, conversationId: params.ctx.conversationId, parentConversationId: params.ctx.parentConversationId, threadId: params.ctx.threadId }; const senderId = params.ctx.senderId?.trim(); const accountId = params.ctx.accountId.trim(); const conversationId = params.ctx.conversationId.trim(); const bindingHelpers = createInteractiveConversationBindingHelpers({ registration: params.ctx.auth.isAuthorizedSender && senderId && accountId && conversationId ? registration : { ...registration, pluginRoot: void 0 }, senderId: params.ctx.senderId, conversation }); return registration.handler({ ...handlerContext, channel: config.channel, [config.interactiveKey]: { ...interactiveContext, data: params.data, namespace, payload }, respond: params.respond, ...bindingHelpers }); } }); } //#endregion //#region src/plugins/lazy-service-module.ts function resolveExport(mod, names) { for (const name of names) { const value = mod[name]; if (typeof value === "function") return value; } return null; } async function defaultLoadOverrideModule(specifier, importModule = async (source) => await import(source)) { return importModule(toSafeImportPath(specifier)); } async function startLazyPluginServiceModule(params) { const skipEnvVar = params.skipEnvVar?.trim(); if (skipEnvVar && isTruthyEnvValue(process.env[skipEnvVar])) return null; const overrideEnvVar = params.overrideEnvVar?.trim(); const override = overrideEnvVar ? process.env[overrideEnvVar]?.trim() : void 0; const loadOverrideModule = params.loadOverrideModule ?? defaultLoadOverrideModule; const validatedOverride = override && params.validateOverrideSpecifier ? params.validateOverrideSpecifier(override) : override; const mod = validatedOverride ? await loadOverrideModule(validatedOverride) : await params.loadDefaultModule(); const start = resolveExport(mod, params.startExportNames); if (!start) return null; const stop = params.stopExportNames && params.stopExportNames.length > 0 ? resolveExport(mod, params.stopExportNames) : null; await start(); return { stop: stop ?? (async () => {}) }; } //#endregion export { createInteractiveConversationBindingHelpers as i, createChannelInteractiveDispatcher as n, dispatchPluginInteractiveHandler as r, startLazyPluginServiceModule as t };