UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

289 lines (288 loc) 12.3 kB
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import { y as uniqueStrings } from "./string-normalization-DsCfAx8q.js"; import { r as defaultRuntime } from "./runtime-CF2WjnNZ.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { n as loadBundledPluginPublicArtifactModuleSync } from "./public-surface-loader-i-BsDNoA.js"; import { j as getPreparedMessageToolCatalog } from "./runtime-BL4wZfTq.js"; import { t as normalizeAnyChannelId } from "./registry-normalize-CY8V_nbx.js"; import "./registry-COqNvmCg.js"; import { i as listChannelPlugins, n as getLoadedChannelPlugin, t as getChannelPlugin } from "./registry-Cz6cv4VC.js"; import "./plugins-Cozj1Enf.js"; import { Type } from "typebox"; //#region src/channels/plugins/message-tool-api.ts /** * Bundled channel message-tool public artifact loader. * * Resolves lightweight discovery hooks without loading full channel plugins. */ const MESSAGE_TOOL_API_ARTIFACT_BASENAME = "message-tool-api.js"; const MISSING_PUBLIC_SURFACE_PREFIX = "Unable to resolve bundled plugin public surface "; function loadBundledChannelMessageToolApi(channelId) { const cacheKey = channelId.trim(); try { return loadBundledPluginPublicArtifactModuleSync({ dirName: cacheKey, artifactBasename: MESSAGE_TOOL_API_ARTIFACT_BASENAME }); } catch (error) { if (error instanceof Error && error.message.startsWith(MISSING_PUBLIC_SURFACE_PREFIX)) return; throw error; } } /** * Resolves a bundled channel's message-tool discovery adapter without loading the full plugin. */ function resolveBundledChannelMessageToolDiscoveryAdapter(channelId) { const describeMessageTool = loadBundledChannelMessageToolApi(channelId)?.describeMessageTool; if (typeof describeMessageTool !== "function") return; return { describeMessageTool }; } //#endregion //#region src/channels/plugins/message-action-discovery.ts /** * Channel message action discovery. * * Builds agent tool schema contributions from loaded or bundled channel action hooks. */ /** Lists message-action adapters from the caller's exact prepared registry. */ const listMessageActionDiscoveryChannels = (preparedMessageToolCatalog) => (preparedMessageToolCatalog ?? getPreparedMessageToolCatalog())?.channels ?? listChannelPlugins(); const loggedMessageActionErrors = /* @__PURE__ */ new Set(); /** * Normalizes a raw channel/provider id before consulting action discovery hooks. */ function resolveMessageActionDiscoveryChannelId(raw) { return normalizeAnyChannelId(raw) ?? normalizeOptionalString(raw); } /** * Builds the context object passed to plugin message-tool discovery hooks. */ function createMessageActionDiscoveryContext(params) { const currentChannelProvider = resolveMessageActionDiscoveryChannelId(params.channel ?? params.currentChannelProvider); return { cfg: params.cfg ?? {}, ...params.chatType ? { chatType: params.chatType } : {}, currentChannelId: params.currentChannelId, currentChannelProvider, currentThreadTs: params.currentThreadTs, currentMessageId: params.currentMessageId, accountId: params.accountId, sessionKey: params.sessionKey, sessionId: params.sessionId, agentId: params.agentId, requesterSenderId: params.requesterSenderId, senderIsOwner: params.senderIsOwner }; } function logMessageActionError(params) { const message = formatErrorMessage(params.error); const key = `${params.pluginId}:${params.operation}:${message}`; if (loggedMessageActionErrors.has(key)) return; loggedMessageActionErrors.add(key); const stack = params.error instanceof Error && params.error.stack ? params.error.stack : null; defaultRuntime.error?.(`[message-action-discovery] ${params.pluginId}.actions.${params.operation} failed: ${stack ?? message}`); } function describeMessageToolSafely(params) { try { return params.describeMessageTool(params.context) ?? null; } catch (error) { logMessageActionError({ pluginId: params.pluginId, operation: "describeMessageTool", error }); return null; } } /** * Normalizes plugin schema contributions into a list for merge callers. */ function normalizeToolSchemaContributions(value) { if (!value) return []; return Array.isArray(value) ? value : [value]; } /** * Resolves media-source parameter names, optionally scoped to one action. */ function normalizeMessageToolMediaSourceParams(mediaSourceParams, action) { if (Array.isArray(mediaSourceParams)) return mediaSourceParams; if (!mediaSourceParams || typeof mediaSourceParams !== "object") return []; const scopedMediaSourceParams = mediaSourceParams; if (action) { const scoped = scopedMediaSourceParams[action]; return Array.isArray(scoped) ? scoped : []; } return Object.values(scopedMediaSourceParams).flatMap((scoped) => Array.isArray(scoped) ? scoped : []); } /** * Finds the lightest available message-tool discovery adapter for one channel. */ function resolveCurrentChannelMessageToolDiscoveryAdapter(channel, preparedMessageToolCatalog) { const channelId = resolveMessageActionDiscoveryChannelId(channel); if (!channelId) return null; const catalog = preparedMessageToolCatalog ?? getPreparedMessageToolCatalog(); const prepared = catalog?.getChannel(channelId); if (prepared?.actions) return { pluginId: prepared.id, actions: prepared.actions }; if (!catalog) { const loadedPlugin = getLoadedChannelPlugin(channelId); if (loadedPlugin?.actions) return { pluginId: loadedPlugin.id, actions: loadedPlugin.actions }; } const bundledActions = resolveBundledChannelMessageToolDiscoveryAdapter(channelId); if (bundledActions) return { pluginId: channelId, actions: bundledActions }; const plugin = catalog ? void 0 : getChannelPlugin(channelId); return plugin?.actions ? { pluginId: plugin.id, actions: plugin.actions } : null; } /** * Resolves one plugin's message action metadata with caller-selected fields. */ function resolveMessageActionDiscoveryForPlugin(params) { const adapter = params.actions; if (!adapter) return { actions: [], capabilities: [], schemaContributions: [], mediaSourceParams: [] }; const described = describeMessageToolSafely({ pluginId: params.pluginId, context: params.context, describeMessageTool: adapter.describeMessageTool }); return { actions: params.includeActions && Array.isArray(described?.actions) ? [...described.actions] : [], capabilities: params.includeCapabilities && Array.isArray(described?.capabilities) ? described.capabilities : [], schemaContributions: params.includeSchema ? normalizeToolSchemaContributions(described?.schema) : [], mediaSourceParams: normalizeMessageToolMediaSourceParams(described?.mediaSourceParams, params.action) }; } /** * Lists actions whose schemas do not block cross-channel tool usage. */ function listCrossChannelSchemaSupportedMessageActions(params) { const channelId = resolveMessageActionDiscoveryChannelId(params.channel); if (!channelId) return []; const pluginActions = resolveCurrentChannelMessageToolDiscoveryAdapter(channelId, params.preparedMessageToolCatalog); if (!pluginActions?.actions) return []; const resolved = resolveMessageActionDiscoveryForPlugin({ pluginId: pluginActions.pluginId, actions: pluginActions.actions, context: createMessageActionDiscoveryContext(params), includeActions: true, includeSchema: true }); const schemaBlockedActions = /* @__PURE__ */ new Set(); for (const contribution of resolved.schemaContributions) { if ((contribution.visibility ?? "current-channel") !== "current-channel") continue; if (!Object.hasOwn(contribution, "actions")) return []; const actions = contribution.actions; if (!Array.isArray(actions)) return []; if (actions.length === 0) continue; for (const action of actions) schemaBlockedActions.add(action); } return resolved.actions.filter((action) => !schemaBlockedActions.has(action)); } /** * Merges schema properties while preserving the first plugin to define a key. */ function mergeToolSchemaProperties(target, source) { if (!source) return; for (const [name, schema] of Object.entries(source)) { if (name in target) continue; target[name] = Type.IsOptional(schema) ? schema : Type.Optional(schema); } } /** * Resolves extra message-tool schema properties from channel discovery hooks. */ function resolveChannelMessageToolSchemaProperties(params) { const properties = {}; const currentChannel = resolveMessageActionDiscoveryChannelId(params.channel); const discoveryBase = createMessageActionDiscoveryContext(params); const contextForPlugin = (pluginId) => ({ ...discoveryBase, accountId: !currentChannel || resolveMessageActionDiscoveryChannelId(pluginId) === currentChannel ? params.accountId : void 0 }); const seenPluginIds = /* @__PURE__ */ new Set(); const channels = listMessageActionDiscoveryChannels(params.preparedMessageToolCatalog); for (const plugin of channels) { if (!plugin.actions) continue; seenPluginIds.add(plugin.id); for (const contribution of resolveMessageActionDiscoveryForPlugin({ pluginId: plugin.id, actions: plugin.actions, context: contextForPlugin(plugin.id), includeSchema: true }).schemaContributions) { const visibility = contribution.visibility ?? "current-channel"; if (currentChannel) { if (visibility === "all-configured" || plugin.id === currentChannel) mergeToolSchemaProperties(properties, contribution.properties); continue; } mergeToolSchemaProperties(properties, contribution.properties); } } if (currentChannel && !seenPluginIds.has(currentChannel)) { const currentActions = resolveCurrentChannelMessageToolDiscoveryAdapter(currentChannel, params.preparedMessageToolCatalog); if (currentActions?.actions) { for (const contribution of resolveMessageActionDiscoveryForPlugin({ pluginId: currentActions.pluginId, actions: currentActions.actions, context: contextForPlugin(currentActions.pluginId), includeSchema: true }).schemaContributions) if ((contribution.visibility ?? "current-channel") === "all-configured" || currentActions.pluginId === currentChannel) mergeToolSchemaProperties(properties, contribution.properties); } } return properties; } /** * Resolves tool parameter names that should be treated as media source selectors. */ function resolveChannelMessageToolMediaSourceParamKeys(params) { const pluginActions = resolveCurrentChannelMessageToolDiscoveryAdapter(params.channel, params.preparedMessageToolCatalog); if (!pluginActions) return []; const described = resolveMessageActionDiscoveryForPlugin({ pluginId: pluginActions.pluginId, actions: pluginActions.actions, context: createMessageActionDiscoveryContext(params), action: params.action, includeSchema: false }); return uniqueStrings(described.mediaSourceParams); } /** * Returns whether any registered channel advertises a message capability. */ function channelSupportsMessageCapability(cfg, capability, preparedMessageToolCatalog) { return listMessageActionDiscoveryChannels(preparedMessageToolCatalog).map((plugin) => resolveMessageActionDiscoveryForPlugin({ pluginId: plugin.id, actions: plugin.actions, context: { cfg }, includeCapabilities: true }).capabilities).some((pluginCapabilities) => pluginCapabilities.includes(capability)); } /** * Returns whether the current channel advertises a message capability. */ function channelSupportsMessageCapabilityForChannel(params, capability) { const pluginActions = resolveCurrentChannelMessageToolDiscoveryAdapter(params.channel, params.preparedMessageToolCatalog); if (!pluginActions) return false; return resolveMessageActionDiscoveryForPlugin({ pluginId: pluginActions.pluginId, actions: pluginActions.actions, context: createMessageActionDiscoveryContext(params), includeCapabilities: true }).capabilities.includes(capability); } //#endregion export { listMessageActionDiscoveryChannels as a, resolveCurrentChannelMessageToolDiscoveryAdapter as c, listCrossChannelSchemaSupportedMessageActions as i, resolveMessageActionDiscoveryChannelId as l, channelSupportsMessageCapabilityForChannel as n, resolveChannelMessageToolMediaSourceParamKeys as o, createMessageActionDiscoveryContext as r, resolveChannelMessageToolSchemaProperties as s, channelSupportsMessageCapability as t, resolveMessageActionDiscoveryForPlugin as u };