UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

301 lines (300 loc) 14 kB
import { t as asNonArrayRecord } from "./record-coerce-DItp3I4t.js"; import { o as isToolExecutionAllowed } from "./tool-policy-shared-DIyS0iQC.js"; import { c as copyInternalToolExecutionPreparer } from "./internal-hooks-CgPsiqhr.js"; import { r as copyCodeModeControlToolIdentity } from "./code-mode-control-tools-CRK5FQqM.js"; import { n as copyPluginToolMeta, r as getPluginToolMeta } from "./tool-metadata-B5aqo73s.js"; //#region src/agents/agent-tool-availability.ts const availabilityBindings = /* @__PURE__ */ new WeakMap(); function bindAgentToolAvailability(tool, binding) { availabilityBindings.set(tool, { binding }); return tool; } function getAgentToolAvailabilityBinding(tool) { return availabilityBindings.get(tool)?.binding; } function copyAgentToolAvailability(source, target) { const metadata = availabilityBindings.get(source); if (metadata) availabilityBindings.set(target, metadata); return target; } /** Record an executor denial so later schema-only catalog projections cannot undo it. */ function markAgentToolExecutionUnavailable(tool) { const metadata = availabilityBindings.get(tool); if (metadata) availabilityBindings.set(tool, { ...metadata, executionDenied: true }); return tool; } /** Finalize owner-controlled affordances after filtering; never rebind or grant tools. */ function finalizeAgentToolAvailability(tools, options) { const winners = new Map(tools.map((tool) => [tool.name, tool])); const callableTools = new Map([...winners.values()].filter((tool) => !availabilityBindings.get(tool)?.executionDenied && (!options?.toolExecutionAllow || isToolExecutionAllowed(options.toolExecutionAllow, tool.name))).map((tool) => [tool.name, tool])); for (const tool of tools) { const binding = availabilityBindings.get(tool)?.binding; if (binding) { binding.prepare(tool, callableTools); options?.onPrepared?.(tool); } } return [...tools]; } function resolveAgentToolExecutionSchema(tool, schema) { return availabilityBindings.get(tool)?.binding.executionSchema?.(schema) ?? schema; } //#endregion //#region src/agents/before-tool-call-metadata.ts const BEFORE_TOOL_CALL_WRAPPED = Symbol("beforeToolCallWrapped"); const BEFORE_TOOL_CALL_DIAGNOSTIC_OPTIONS = Symbol("beforeToolCallDiagnosticOptions"); const BEFORE_TOOL_CALL_SOURCE_TOOL = Symbol("beforeToolCallSourceTool"); const BEFORE_TOOL_CALL_HOOK_CONTEXT = Symbol("beforeToolCallHookContext"); function withBeforeToolCallMetadata(tool) { return tool; } function getBeforeToolCallSourceTool(tool) { return withBeforeToolCallMetadata(tool)[BEFORE_TOOL_CALL_SOURCE_TOOL]; } function getBeforeToolCallHookContext(tool) { return withBeforeToolCallMetadata(tool)[BEFORE_TOOL_CALL_HOOK_CONTEXT]; } function clearBeforeToolCallWrappedMarker(tool) { delete withBeforeToolCallMetadata(tool)[BEFORE_TOOL_CALL_WRAPPED]; } /** Return true when a tool already carries the before_tool_call wrapper marker. */ function isToolWrappedWithBeforeToolCallHook(tool) { return withBeforeToolCallMetadata(tool)[BEFORE_TOOL_CALL_WRAPPED] === true; } /** Toggle diagnostic event emission on an existing before_tool_call wrapper. */ function setBeforeToolCallDiagnosticsEnabled(tool, enabled) { const options = withBeforeToolCallMetadata(tool)[BEFORE_TOOL_CALL_DIAGNOSTIC_OPTIONS]; if (options) options.emitDiagnostics = enabled; } function getBeforeToolCallDiagnosticOptions(tool) { return withBeforeToolCallMetadata(tool)[BEFORE_TOOL_CALL_DIAGNOSTIC_OPTIONS]; } /** Copy before_tool_call marker metadata when another wrapper replaces a tool. */ function copyBeforeToolCallHookMarker(source, target) { if (!isToolWrappedWithBeforeToolCallHook(source)) return; Object.defineProperty(target, BEFORE_TOOL_CALL_WRAPPED, { value: true, enumerable: true }); const diagnosticOptions = withBeforeToolCallMetadata(source)[BEFORE_TOOL_CALL_DIAGNOSTIC_OPTIONS]; if (diagnosticOptions) Object.defineProperty(target, BEFORE_TOOL_CALL_DIAGNOSTIC_OPTIONS, { value: diagnosticOptions, enumerable: false }); const sourceTool = getBeforeToolCallSourceTool(source); if (sourceTool) Object.defineProperty(target, BEFORE_TOOL_CALL_SOURCE_TOOL, { value: sourceTool, enumerable: false }); const hookContext = getBeforeToolCallHookContext(source); Object.defineProperty(target, BEFORE_TOOL_CALL_HOOK_CONTEXT, { value: hookContext, enumerable: false }); } //#endregion //#region src/agents/channel-tool-metadata.ts const channelAgentToolMeta = /* @__PURE__ */ new WeakMap(); /** Read channel metadata attached to a channel-owned agent tool. */ function getChannelAgentToolMeta(tool) { return channelAgentToolMeta.get(tool); } /** Attach channel ownership metadata to a concrete agent tool. */ function setChannelAgentToolMeta(tool, meta) { channelAgentToolMeta.set(tool, meta); } /** Copy channel metadata when wrapping or replacing a channel-owned tool. */ function copyChannelAgentToolMeta(source, target) { const meta = channelAgentToolMeta.get(source); if (meta) channelAgentToolMeta.set(target, meta); } //#endregion //#region src/agents/exec-tool-target-pinning.ts const scheduledToolProjections = /* @__PURE__ */ new WeakMap(); const EXEC_POLICY_PARAMETER_NAMES = /* @__PURE__ */ new Set([ "host", "security", "ask" ]); const NODE_EXEC_PARAMETER_NAMES = /* @__PURE__ */ new Set([ "command", "workdir", "env", "timeoutSeconds", "node" ]); const PROCESS_FOLLOWUP_TEXT = "Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up."; /** Constructs and registers an alias from an exact host-owned shell source. */ function createCronScheduledToolProjection(sourceTool, assertActive, targetTool, projection) { assertActive(); if (projection.kind !== targetTool) throw new Error("scheduled tool projection does not match its host-created source"); const projectedTool = projection.kind === "exec" ? createScheduledExecProjection(sourceTool, projection) : { ...sourceTool, name: projection.name, description: projection.description }; const info = targetTool === "exec" ? Object.freeze({ targetTool, execTarget: Object.freeze({ host: "gateway", ...projection.kind === "exec" && projection.ask ? { ask: projection.ask } : {} }) }) : Object.freeze({ targetTool }); scheduledToolProjections.set(projectedTool, Object.freeze({ assertActive, sourceToolName: projectedTool.name, info, execute: projectedTool.execute })); return projectedTool; } function createScheduledExecProjection(sourceTool, projection) { const pinnedTool = pinExecToolTarget(sourceTool, { host: "gateway", ...projection.ask ? { ask: projection.ask } : {} }); return { ...pinnedTool, name: projection.name, description: projection.description, execute: async (toolCallId, args, signal, onUpdate) => { const result = await pinnedTool.execute(toolCallId, args, signal, onUpdate); return { ...result, content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, projection.followupText) }) : item) }; } }; } /** * Resolves the canonical identity of a host-created alias on the final * executable surface. Returns undefined for tools without a registered * projection; throws when a registered projection's executable or name was * changed after host creation, so tampered aliases never canonicalize. */ function readCronScheduledToolProjection(tool) { const projection = scheduledToolProjections.get(tool); if (!projection) return; projection.assertActive(); if (tool.name !== projection.sourceToolName || tool.execute !== projection.execute) throw new Error("scheduled tool projection executable changed after host creation"); return projection.info; } /** Preserves projection identity across shallow tool-object copies made by tool plumbing. */ function copyCronScheduledToolProjection(source, target) { const projection = scheduledToolProjections.get(source); if (projection && source.name === projection.sourceToolName && target.name === projection.sourceToolName && source.execute === projection.execute && target.execute === projection.execute) scheduledToolProjections.set(target, projection); } /** Restricts an exec tool to one host target even when callers submit broader arguments. */ function pinExecToolTarget(tool, target) { const pinnedNode = target.host === "node" ? target.node?.trim() : void 0; const pinArgs = (args) => pinExecToolArgs(args, target, pinnedNode); const prepare = tool.prepareBeforeToolCallParams; const finalize = tool.finalizeBeforeToolCallParams; return { ...tool, parameters: restrictExecToolParameters(tool.parameters, target.host, Boolean(pinnedNode)), ...prepare ? { prepareBeforeToolCallParams: (args, context) => prepare(pinArgs(args), context) } : {}, ...finalize ? { finalizeBeforeToolCallParams: (params, preparedParams) => finalize(pinArgs(params), preparedParams) } : {}, execute: (toolCallId, args, signal, onUpdate) => tool.execute(toolCallId, pinArgs(args), signal, onUpdate) }; } function pinExecToolArgs(args, target, pinnedNode) { const { host: _host, security: _security, ask: _ask, node: requestedNode, ...rest } = asNonArrayRecord(args); if (target.host === "gateway") return { ...rest, host: "gateway", ...target.ask ? { ask: target.ask } : {} }; const nodeArgs = Object.fromEntries(Object.entries(rest).filter(([name]) => NODE_EXEC_PARAMETER_NAMES.has(name))); const node = pinnedNode ?? (typeof requestedNode === "string" ? requestedNode.trim() : ""); return { ...nodeArgs, host: "node", ...node ? { node } : {} }; } function restrictExecToolParameters(parameters, host, hasPinnedNode) { if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return parameters; const schema = parameters; const rawProperties = schema.properties; if (!rawProperties || typeof rawProperties !== "object" || Array.isArray(rawProperties)) return parameters; const includeParameter = (name) => host === "node" ? NODE_EXEC_PARAMETER_NAMES.has(name) && !(hasPinnedNode && name === "node") : !EXEC_POLICY_PARAMETER_NAMES.has(name) && name !== "node"; const properties = Object.fromEntries(Object.entries(rawProperties).filter(([name]) => includeParameter(name))); const rawRequired = schema.required; const required = Array.isArray(rawRequired) ? rawRequired.filter((name) => typeof name !== "string" || includeParameter(name)) : rawRequired; return { ...parameters, properties, ...Array.isArray(rawRequired) ? { required } : {} }; } //#endregion //#region src/agents/tool-terminal-presentation.ts const terminalPresentationByTool = /* @__PURE__ */ new WeakMap(); function setToolTerminalPresentation(tool, formatter) { terminalPresentationByTool.set(tool, formatter); return tool; } function getToolTerminalPresentation(tool) { return terminalPresentationByTool.get(tool); } function copyToolTerminalPresentation(source, target) { const formatter = terminalPresentationByTool.get(source); if (formatter) terminalPresentationByTool.set(target, formatter); } //#endregion //#region src/agents/agent-tool-metadata.ts const actionDescriptors = /* @__PURE__ */ new WeakMap(); function bindAgentToolActionDescriptor(tool, descriptor) { actionDescriptors.set(tool, descriptor); } function getAgentToolActionDescriptor(tool) { return actionDescriptors.get(tool); } function copyAgentToolActionDescriptor(source, target) { const descriptor = actionDescriptors.get(source); if (descriptor) actionDescriptors.set(target, descriptor); } /** Preserve only the metadata owned by a before-tool-call wrapper rebuild. */ function copyBeforeToolCallWrapperMetadata(source, target) { copyPluginToolMeta(source, target); copyChannelAgentToolMeta(source, target); copyToolTerminalPresentation(source, target); copyAgentToolActionDescriptor(source, target); copyAgentToolAvailability(source, target); } /** Bind the broad family at final assembly from private, process-stable owner metadata. */ function bindAssembledAgentToolActionDescriptor(tool) { if (actionDescriptors.has(tool)) return; const kind = getPluginToolMeta(tool)?.kind; const memory = kind === "memory" || Array.isArray(kind) && kind.includes("memory"); actionDescriptors.set(tool, memory ? { family: "data", operation: "memory" } : { family: "tool", operation: "openclaw" }); } /** * Preserve identity-backed tool metadata that object spread cannot carry. * Losing it detaches policy, hooks, presentation, and control-flow ownership. */ function copyAgentToolMetadata(source, target) { if (source === target) return target; copyPluginToolMeta(source, target); copyChannelAgentToolMeta(source, target); copyBeforeToolCallHookMarker(source, target); copyToolTerminalPresentation(source, target); copyCodeModeControlToolIdentity(source, target); copyCronScheduledToolProjection(source, target); copyInternalToolExecutionPreparer(source, target); copyAgentToolActionDescriptor(source, target); copyAgentToolAvailability(source, target); return target; } //#endregion export { bindAgentToolAvailability as C, markAgentToolExecutionUnavailable as D, getAgentToolAvailabilityBinding as E, resolveAgentToolExecutionSchema as O, setBeforeToolCallDiagnosticsEnabled as S, finalizeAgentToolAvailability as T, clearBeforeToolCallWrappedMarker as _, getAgentToolActionDescriptor as a, getBeforeToolCallSourceTool as b, createCronScheduledToolProjection as c, getChannelAgentToolMeta as d, setChannelAgentToolMeta as f, BEFORE_TOOL_CALL_WRAPPED as g, BEFORE_TOOL_CALL_SOURCE_TOOL as h, copyBeforeToolCallWrapperMetadata as i, pinExecToolTarget as l, BEFORE_TOOL_CALL_HOOK_CONTEXT as m, bindAssembledAgentToolActionDescriptor as n, getToolTerminalPresentation as o, BEFORE_TOOL_CALL_DIAGNOSTIC_OPTIONS as p, copyAgentToolMetadata as r, setToolTerminalPresentation as s, bindAgentToolActionDescriptor as t, readCronScheduledToolProjection as u, getBeforeToolCallDiagnosticOptions as v, copyAgentToolAvailability as w, isToolWrappedWithBeforeToolCallHook as x, getBeforeToolCallHookContext as y };