openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
301 lines (300 loc) • 14 kB
JavaScript
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 };