UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

723 lines (722 loc) 37.1 kB
import { c as normalizeOptionalLowercaseString } from "./string-coerce-CIXf7egm.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { t as AUTOMATIONS_TOOL_NAME } from "./automations-tool-name-DBMZPbPL.js"; import { a as expandToolGroups, c as normalizeToolPolicyName } from "./tool-policy-shared-DIyS0iQC.js"; import { t as createRuntimeToolMatcher } from "./tool-policy-match-TnFxBs5z.js"; import { c as hasRestrictiveAllowPolicy, u as replaceWithEffectiveToolAllowlist } from "./tool-policy-Wi0C45cX.js"; import { _ as resolveSessionAgentId } from "./agent-scope-DbtJyKUL.js"; import { i as logWarn } from "./logger-DwECwNVZ.js"; import { i as resolveGatewayMessageChannel } from "./message-channel-normalize-B81s0XMO.js"; import "./message-channel-BQrhwUEA.js"; import { c as isCompletionReportInputProvenance } from "./input-provenance-DiG-Cwnd.js"; import { t as ToolAuthorizationError } from "./tool-input-error-mjW74R8m.js"; import "./common-Bm6UTDDA.js"; import { r as resolveImageSanitizationLimits } from "./image-sanitization-DhkMOJXD.js"; import { n as copyPluginToolMeta, r as getPluginToolMeta } from "./tool-metadata-B5aqo73s.js"; import { l as pinExecToolTarget, n as bindAssembledAgentToolActionDescriptor, r as copyAgentToolMetadata } from "./agent-tool-metadata-CZvIgxro.js"; import { s as wrapToolWithGatewayCallerIdentity } from "./gateway-caller-context-BxVUFvkR.js"; import { i as resolveSessionPermissionExecPolicy, n as resolveSessionPermissionCoreToolPolicy } from "./session-permission-exec-mode-CJHB47SR.js"; import { r as resolveToolFsConfig } from "./tool-fs-policy-BciYLPcO.js"; import { d as filterToolsByClientCaps, f as resolveOpenClawPluginToolsForOptions, p as listChannelAgentTools, t as createOpenClawTools } from "./openclaw-tools-CNOZOjlX.js"; import { A as getActiveAgentRingZeroTools, D as TOOL_SEARCH_CODE_MODE_TOOL_NAME, E as TOOL_DESCRIBE_RAW_TOOL_NAME, M as mergeAgentRingZeroTools, T as TOOL_CALL_RAW_TOOL_NAME, i as resolveLocalModelLeanPreserveToolNames, k as TOOL_SEARCH_RAW_TOOL_NAME, l as createToolSearchTools, n as filterLocalModelLeanTools, o as messageToolOwnsVisibleReply, p as resolveToolSearchConfig } from "./local-model-lean-B52ThaBJ.js"; import { n as resolveSessionPlacementComputer, t as resolveConversationCapabilityProfile } from "./conversation-capability-profile-B6PkMXFD.js"; import { n as resolveSandboxFileIdentity } from "./file-mutation-identity-dqR8BH1r.js"; import { t as resolveProcessToolScopeKey } from "./bash-process-scope-Bmw8_ghL.js"; import { t as HEARTBEAT_RESPONSE_TOOL_NAME } from "./heartbeat-tool-response-B4VYc0rg.js"; import { t as applyExecPolicyLayer } from "./exec-policy-D6Y68q04.js"; import { n as resolveEventSessionRoutingPolicy } from "./event-session-routing-CJOO5dMS.js"; import { r as bindCronManagementGrant, t as bindActiveCronCreatorAuthorityResolver } from "./cron-creator-authority-context-CkDgGats.js"; import { i as replaceWithEffectiveCronCreatorToolAllowlist } from "./cron-tool-DbVyRyAj.js"; import { t as applyToolPolicyPipeline } from "./tool-policy-pipeline-BwOD5Xc9.js"; import { n as projectConversationToolNames, r as resolveConversationToolPolicies, t as buildConversationToolPolicyPipelineSteps } from "./conversation-tool-policy-pipeline-BzM9yFTb.js"; import { t as buildDeclaredToolAllowlistContext } from "./tool-policy-declared-context-CcJz-5tf.js"; import { s as shouldSuppressManagedWebSearchTool } from "./codex-native-web-search-core-Du_GEtBK.js"; import { n as mergeGatewayAgentCliPath } from "./openclaw-cli-shim-DSn93Ndv.js"; import { r as appendRuntimePluginToolGrant } from "./tools-D1ohN2ZT.js"; import { a as getActiveSecretsRuntimeConfigSnapshot } from "./runtime-state-C4aJ8Hzz.js"; import { r as GATEWAY_OWNER_ONLY_CORE_TOOLS } from "./dangerous-tools-Caeym4XK.js"; import { n as isApplyPatchAllowedForModel, r as finalizeAgentTools, t as createCoreCodingTools } from "./core-coding-tools-DMh_iw8e.js"; import { d as wrapToolMemoryFlushAppendOnlyWrite, p as createMemoryWriteProvenanceObserver, t as resolveToolLoopDetectionConfig } from "./tool-loop-detection-config-Bg911KiY.js"; import "./codex-native-web-search-7ibjhLaT.js"; import { n as resolveExecToolConfig } from "./lazy-exec-tool-BWPZD5in.js"; import { l as prepareGitHubToolEnvironment } from "./github-tool-identity-CsNyDjEx.js"; import { t as resolveScheduledToolCallerContext } from "./scheduled-tool-policy-CkIMk4GS.js"; //#region src/agents/agent-tools.message-provider-policy.ts /** * Message-provider tool filtering. * Channels can restrict tool names after runtime assembly when the active * transport cannot safely render or execute a class of tools. */ const TOOL_DENY_BY_MESSAGE_PROVIDER = { "discord-voice": ["tts"], voice: ["tts"] }; const TOOL_ALLOW_BY_MESSAGE_PROVIDER = { node: [ "canvas", "pdf", "tts", "view_image", "web_fetch", "web_search" ] }; /** Applies message-provider filtering while preserving duplicate tool entries. */ function filterToolsByMessageProvider(tools, messageProvider) { const normalizedProvider = normalizeOptionalLowercaseString(messageProvider); if (!normalizedProvider) return [...tools]; const allowedTools = TOOL_ALLOW_BY_MESSAGE_PROVIDER[normalizedProvider]; if (allowedTools && allowedTools.length > 0) { const allowedSet = new Set(allowedTools); return tools.filter((tool) => allowedSet.has(tool.name)); } const deniedTools = TOOL_DENY_BY_MESSAGE_PROVIDER[normalizedProvider]; if (!deniedTools || deniedTools.length === 0) return [...tools]; const deniedSet = new Set(deniedTools); return tools.filter((tool) => !deniedSet.has(tool.name)); } //#endregion //#region src/agents/delegation-capability.ts const log = createSubsystemLogger("agents/delegation-capability"); const NEW_DELEGATION_TOOL_NAMES = /* @__PURE__ */ new Set([ "codex_session_send", "llm-task", "openclaw", "sessions_send", "sessions_spawn" ]); const REPORT_ONLY_TOOL_ACTIONS = /* @__PURE__ */ new Map([ [AUTOMATIONS_TOOL_NAME, /* @__PURE__ */ new Set([ "get", "list", "remove", "runs", "status" ])], ["image_generate", /* @__PURE__ */ new Set(["list", "status"])], ["music_generate", /* @__PURE__ */ new Set(["list", "status"])], ["video_generate", /* @__PURE__ */ new Set(["list", "status"])] ]); const REPORT_ONLY_ERROR = "New delegation is unavailable while reporting a completion through a fallback model."; function resolveDelegationCapability(params) { if (!isCompletionReportInputProvenance(params.inputProvenance)) return "full"; if (params.fallbackActive || params.disableTools === true) return "report_only"; if (params.toolsAllow === void 0) return "full"; return [...NEW_DELEGATION_TOOL_NAMES].some(createRuntimeToolMatcher(params.toolsAllow)) ? "full" : "report_only"; } function readToolAction(params) { if (!params || typeof params !== "object" || Array.isArray(params)) return ""; const action = params.action; return typeof action === "string" ? action.trim().toLowerCase() : ""; } function wrapReportOnlyTool(tool, allowedActions) { const wrapped = new Proxy(tool, { get(target, property, receiver) { if (property !== "execute") return Reflect.get(target, property, receiver); return async (toolCallId, params, signal, onUpdate) => { if (!allowedActions.has(readToolAction(params))) throw new ToolAuthorizationError(REPORT_ONLY_ERROR); return await target.execute(toolCallId, params, signal, onUpdate); }; } }); copyPluginToolMeta(tool, wrapped); return wrapped; } /** * Enforces the run's delegation capability after ordinary tool authorization. * Tool names and safe actions here are explicit built-in/plugin contracts: the * gate removes task launchers while retaining status, history, and cleanup. */ function applyDelegationCapability(tools, capability) { if (capability !== "report_only") return tools; const removed = []; const narrowed = []; const gated = tools.flatMap((tool) => { const name = normalizeToolPolicyName(tool.name); if (NEW_DELEGATION_TOOL_NAMES.has(name)) { removed.push(name); return []; } const allowedActions = REPORT_ONLY_TOOL_ACTIONS.get(name); if (!allowedActions) return [tool]; narrowed.push(name); return [wrapReportOnlyTool(tool, allowedActions)]; }); if (removed.length > 0 || narrowed.length > 0) log.debug("delegation capability restricted run tools", { removed, narrowed }); return gated; } //#endregion //#region src/agents/agent-tools.ts const MEMORY_FLUSH_ALLOWED_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "write"]); function applyModelProviderToolPolicy(toolsInput, params) { let tools = toolsInput; tools = filterLocalModelLeanTools({ tools, config: params?.config, agentId: params?.agentId, sessionKey: params?.sessionKey, preserveToolNames: params?.localModelLeanPreserveToolNames ?? params?.runtimeToolAllowlist }); if (params?.suppressManagedWebSearch !== false && shouldSuppressManagedWebSearchTool({ config: params?.config, modelProvider: params?.modelProvider, modelApi: params?.modelApi, modelId: params?.modelId, agentId: params?.agentId, sessionKey: params?.sessionKey, agentDir: params?.agentDir })) return tools.filter((tool) => tool.name !== "web_search"); return tools; } function createOpenClawCodingToolsInternal(options) { const sandbox = options?.sandbox?.enabled ? options.sandbox : void 0; const isMemoryFlushRun = options?.trigger === "memory"; if (isMemoryFlushRun && !options?.memoryFlushWritePath) throw new Error("memoryFlushWritePath required for memory-triggered tool runs"); const memoryFlushWritePath = isMemoryFlushRun ? options.memoryFlushWritePath : void 0; const cronSelfRemoveOnlyJobId = options?.trigger === "cron" && options.jobId?.trim() ? options.jobId.trim() : void 0; const capabilityProfile = options?.conversationCapabilityProfile ?? resolveConversationCapabilityProfile({ config: options?.config, sessionKey: options?.sessionKey, runSessionKey: options?.runSessionKey, sessionId: options?.sessionId, runId: options?.runId, agentId: options?.policyAgentId ?? options?.agentId, agentDir: options?.agentDir, agentAccountId: options?.agentAccountId, messageProvider: options?.messageProvider, messageChannel: options?.messageChannel, chatType: options?.chatType, messageTo: options?.messageTo, messageThreadId: options?.messageThreadId, conversationToolPolicy: options?.conversationToolPolicy, currentChannelId: options?.currentChannelId, currentMessagingTarget: options?.currentMessagingTarget, currentThreadTs: options?.currentThreadTs, currentMessageId: options?.currentMessageId, groupId: options?.groupId, groupChannel: options?.groupChannel, groupSpace: options?.groupSpace, memberRoleIds: options?.memberRoleIds, spawnedBy: options?.spawnedBy, senderId: options?.senderId, senderName: options?.senderName, senderUsername: options?.senderUsername, senderE164: options?.senderE164, senderIsOwner: options?.senderIsOwner, modelProvider: options?.modelProvider, modelId: options?.modelId, modelApi: options?.modelApi, modelContextWindowTokens: options?.modelContextWindowTokens, modelHasVision: options?.modelHasVision, workspaceDir: options?.workspaceDir, cwd: options?.cwd, spawnWorkspaceDir: options?.spawnWorkspaceDir, skillsSnapshot: options?.skillsSnapshot, sandboxToolPolicy: sandbox?.tools, runtimeToolAllowlist: options?.runtimeToolAllowlist, inheritRuntimeToolAllowlist: options?.inheritRuntimeToolAllowlist, inputProvenance: options?.inputProvenance, trustedInternalHandoff: options?.trustedInternalHandoff, scheduledToolPolicy: options?.scheduledToolPolicy, pluginMetadataSnapshot: options?.preparedModelRuntime?.metadataSnapshot }); const { agentId, runtimePluginToolGrant } = capabilityProfile.policy; const executionAgentId = options?.agentId ?? (options?.runSessionKey ? resolveSessionAgentId({ config: options.config, sessionKey: options.runSessionKey }) : agentId); const executionSessionKey = options?.runSessionKey ?? options?.sessionKey; const enableHeartbeatTool = options?.enableHeartbeatTool === true || options?.trigger === "heartbeat" && options?.config?.messages?.visibleReplies === "message_tool"; const forceHeartbeatTool = options?.forceHeartbeatTool === true || enableHeartbeatTool; const toolSearchConfig = resolveToolSearchConfig(options?.config); const toolSearchControlsEnabled = options?.includeToolSearchControls === true && toolSearchConfig.enabled; const toolSearchControlAllowlist = toolSearchControlsEnabled ? [ TOOL_SEARCH_CODE_MODE_TOOL_NAME, TOOL_SEARCH_RAW_TOOL_NAME, TOOL_DESCRIBE_RAW_TOOL_NAME, TOOL_CALL_RAW_TOOL_NAME ] : []; const runtimeToolAllowlistIncludesMessage = expandToolGroups(options?.runtimeToolAllowlist ?? []).some((toolName) => { const normalized = normalizeToolPolicyName(toolName); return normalized === "*" || normalized === "message"; }); const sourceReplyOnly = capabilityProfile.policy.requesterPolicySource === "completion-handoff" && options?.sourceReplyDeliveryMode === "message_tool_only"; const localModelLeanPreserveToolNames = resolveLocalModelLeanPreserveToolNames({ toolNames: capabilityProfile.policy.explicitToolOverrideAllowlist, forceMessageTool: options?.forceMessageTool, sourceReplyDeliveryMode: options?.sourceReplyDeliveryMode }); const runtimeProfileAlsoAllow = [ ...options && messageToolOwnsVisibleReply(options) ? ["message"] : [], ...runtimeToolAllowlistIncludesMessage ? ["message"] : [], ...forceHeartbeatTool ? [HEARTBEAT_RESPONSE_TOOL_NAME] : [], ...toolSearchControlAllowlist ]; const conversationToolPolicies = resolveConversationToolPolicies({ capabilityProfile, additionalProfileAllow: runtimeProfileAlsoAllow, additionalPolicyAllow: toolSearchControlAllowlist }); const sandboxWorkspaceMediaReadAllowed = projectConversationToolNames({ capabilityProfile, toolNames: ["read"], warn: () => void 0 }).length === 1; const scopeKey = resolveProcessToolScopeKey({ scopeKey: options?.exec?.scopeKey, sessionKey: options?.sessionKey, sessionId: options?.sessionId, agentId }); options?.recordToolPrepStage?.("tool-policy"); const execConfig = resolveExecToolConfig({ cfg: options?.config, agentId }); const execRuntimeConfig = options?.exec?.config ?? options?.config; const preparedRunEnvironment = execRuntimeConfig && executionAgentId ? prepareGitHubToolEnvironment({ config: execRuntimeConfig, sourceConfig: getActiveSecretsRuntimeConfigSnapshot()?.sourceConfig, agentId: executionAgentId }) : void 0; const fsConfig = resolveToolFsConfig({ cfg: options?.config, agentId }); const sessionPermissionPolicy = options?.sessionPermissionPolicy; const sessionCoreToolPolicy = sessionPermissionPolicy ? resolveSessionPermissionCoreToolPolicy(sessionPermissionPolicy) : void 0; const sandboxRoot = sandbox?.workspaceDir; const sandboxFsBridge = sandbox?.fsBridge; const allowWorkspaceWrites = sandbox?.workspaceAccess !== "ro"; const workspaceRoot = capabilityProfile.workspace.workspaceRoot; const runtimeRoot = capabilityProfile.workspace.runtimeRoot; const codingRoot = sandboxRoot ?? runtimeRoot; const containmentRoot = sandboxRoot ?? sessionPermissionPolicy?.root ?? codingRoot; const memoryFlushWriteRoot = sandboxRoot ?? workspaceRoot; const memoryWriteProvenance = createMemoryWriteProvenanceObserver({ mutationRoot: sandboxRoot ?? workspaceRoot, workspaceDir: sandboxRoot ?? workspaceRoot, resolvePath: sandboxFsBridge ? (filePath) => resolveSandboxFileIdentity({ bridge: sandboxFsBridge, filePath, cwd: sandboxRoot, signal: options?.abortSignal }) : void 0, resolveOriginClass: () => options?.senderIsOwner === false || options?.isTurnTainted?.() === true ? "untrusted" : "agent", sessionId: options?.sessionId, sessionKey: options?.runSessionKey ?? options?.sessionKey }); const includeCoreTools = options?.includeCoreTools !== false; const toolConstructionPlan = options?.toolConstructionPlan ?? { includeBaseCodingTools: includeCoreTools, includeShellTools: includeCoreTools, includeChannelTools: includeCoreTools, includeOpenClawTools: includeCoreTools, includePluginTools: true }; const includeBaseCodingTools = includeCoreTools && toolConstructionPlan.includeBaseCodingTools; const includeShellTools = includeCoreTools && toolConstructionPlan.includeShellTools; const includeOpenClawTools = includeCoreTools && toolConstructionPlan.includeOpenClawTools; const includeChannelTools = toolConstructionPlan.includeChannelTools; const includePluginTools = toolConstructionPlan.includePluginTools; const workspaceOnly = isMemoryFlushRun || (sessionCoreToolPolicy?.workspaceOnly ?? fsConfig.workspaceOnly === true); const fsPolicy = { workspaceOnly, ...sessionPermissionPolicy ? { root: sessionPermissionPolicy.root } : {} }; const readOnly = sessionCoreToolPolicy?.readOnly ?? false; const applyPatchConfig = execConfig.applyPatch; const applyPatchWorkspaceOnly = sessionCoreToolPolicy?.applyPatchWorkspaceOnly ?? (workspaceOnly || applyPatchConfig?.workspaceOnly !== false); const applyPatchEnabled = !readOnly && applyPatchConfig?.enabled !== false && isApplyPatchAllowedForModel({ modelProvider: options?.modelProvider, modelId: options?.modelId, allowModels: applyPatchConfig?.allowModels }); const imageSanitization = resolveImageSanitizationLimits(options?.config); options?.recordToolPrepStage?.("workspace-policy"); const { cleanupMs: cleanupMsOverride, ...execDefaults } = options?.exec ?? {}; const effectiveExecPolicy = sessionPermissionPolicy ? resolveSessionPermissionExecPolicy(sessionPermissionPolicy, options?.exec) : applyExecPolicyLayer(execConfig, options?.exec); const scheduledExecTarget = options?.scheduledToolPolicy?.execTarget; const processToolAvailabilityRef = {}; const coreTools = createCoreCodingTools({ abortSignal: options?.abortSignal, codingRoot, containmentRoot, includeBaseCodingTools, includeShellTools, workspaceOnly, readOnly, sandbox, skillsSnapshot: options?.skillsSnapshot, skillInstructionPaths: options?.skillUsagePaths?.map((entry) => entry.readPath), skillInstructionDeliveryCache: options?.skillInstructionDeliveryCache, modelContextWindowTokens: options?.modelContextWindowTokens, imageSanitization, modelHasVision: options?.modelHasVision, memoryWriteProvenance, applyPatchEnabled, applyPatchWorkspaceOnly, execDefaults: { ...execDefaults, bypassHostApprovalFloors: scheduledExecTarget?.ask !== "always" && sessionCoreToolPolicy?.bypassHostApprovalFloors && effectiveExecPolicy.security === "full", host: scheduledExecTarget?.host ?? options?.exec?.host ?? execConfig.host, mode: scheduledExecTarget?.ask ? void 0 : effectiveExecPolicy.mode, security: effectiveExecPolicy.security, ask: scheduledExecTarget?.ask ?? effectiveExecPolicy.ask, config: execRuntimeConfig, preparedRunEnvironment, reviewer: options?.exec?.reviewer ?? execConfig.reviewer, trigger: options?.trigger, node: options?.exec?.node ?? execConfig.node, pathPrepend: mergeGatewayAgentCliPath(options?.exec?.pathPrepend ?? execConfig.pathPrepend), safeBins: options?.exec?.safeBins ?? execConfig.safeBins, strictInlineEval: options?.exec?.strictInlineEval ?? execConfig.strictInlineEval, commandHighlighting: options?.exec?.commandHighlighting ?? execConfig.commandHighlighting, safeBinTrustedDirs: options?.exec?.safeBinTrustedDirs ?? execConfig.safeBinTrustedDirs, safeBinProfiles: options?.exec?.safeBinProfiles ?? execConfig.safeBinProfiles, agentId, processToolAvailabilityRef, scopeKey, sessionKey: options?.sessionKey, runId: options?.runId, operationalRunInstance: options?.operationalRunInstance, notifySessionKey: options?.runSessionKey ?? options?.sessionKey, sessionId: options?.sessionId, sessionStore: options?.config?.session?.store, eventRouting: resolveEventSessionRoutingPolicy({ cfg: options?.config, sessionKey: options?.runSessionKey ?? options?.sessionKey, channel: options?.messageProvider, accountId: options?.agentAccountId }), messageProvider: options?.messageProvider, currentChannelId: options?.currentChannelId, currentThreadTs: options?.currentThreadTs, channelContext: options?.channelContext, accountId: options?.agentAccountId, approvalReviewerDeviceId: options?.approvalReviewerDeviceId, nonInteractiveApproval: options?.swarmCollector, backgroundMs: options?.exec?.backgroundMs ?? execConfig.backgroundMs, timeoutSec: options?.exec?.timeoutSec ?? execConfig.timeoutSec, approvalRunningNoticeMs: options?.exec?.approvalRunningNoticeMs ?? execConfig.approvalRunningNoticeMs, notifyOnExit: options?.exec?.notifyOnExit ?? execConfig.notifyOnExit, notifyOnExitEmptySuccess: options?.exec?.notifyOnExitEmptySuccess ?? execConfig.notifyOnExitEmptySuccess }, processDefaults: { cleanupMs: cleanupMsOverride ?? execConfig.cleanupMs, scopeKey }, recordToolPrepStage: options?.recordToolPrepStage }); const cronCreatorAuthorityResolver = bindActiveCronCreatorAuthorityResolver(options?.runId); const cronManagementGrant = bindCronManagementGrant(options?.runId); const ownerOnlyCoreToolDenylist = options?.senderIsOwner === false ? GATEWAY_OWNER_ONLY_CORE_TOOLS.filter((toolName) => toolName !== "automations" || !(cronCreatorAuthorityResolver || cronManagementGrant)) : []; const ownerOnlyCoreToolPolicy = ownerOnlyCoreToolDenylist.length > 0 ? { deny: ownerOnlyCoreToolDenylist } : void 0; const pluginToolAllowlist = appendRuntimePluginToolGrant(capabilityProfile.policy.explicitToolAllowlist, runtimePluginToolGrant); const pluginToolDenylist = [...capabilityProfile.policy.explicitToolDenylist, ...ownerOnlyCoreToolDenylist]; const inheritedToolDenylist = [...pluginToolDenylist]; const inheritedToolAllowlist = options?.inheritedToolAllowlistRef ?? []; const shouldInheritEffectiveToolAllowlist = capabilityProfile.policy.inheritancePolicies.some(hasRestrictiveAllowPolicy); const cronCreatorToolAllowlist = options?.cronCreatorToolAllowlistRef ?? []; const cronCreatorToolAllowlistCaptureRef = options?.cronCreatorToolAllowlistCaptureRef; const gatewayCaller = resolveScheduledToolCallerContext({ scheduledToolPolicy: options?.scheduledToolPolicy, accountId: options?.agentAccountId, channel: resolveGatewayMessageChannel(options?.messageChannel ?? options?.messageProvider) }); const toolCallerIdentity = options && executionAgentId && executionSessionKey?.trim() ? { agentId: executionAgentId, sessionKey: executionSessionKey.trim(), ...options.abortSignal ? { approvalSignals: [options.abortSignal] } : {}, turnSourceChannel: resolveGatewayMessageChannel(options.messageChannel ?? options.messageProvider), turnSourceTo: options.currentMessagingTarget ?? options.currentChannelId ?? options.messageTo, turnSourceAccountId: gatewayCaller.accountId, turnSourceThreadId: options.currentThreadTs ?? options.messageThreadId } : void 0; const pluginToolsOnly = filterToolsByClientCaps(includeOpenClawTools || !includePluginTools ? [] : resolveOpenClawPluginToolsForOptions({ options: { agentSessionKey: options?.sessionKey, runSessionKey: options?.runSessionKey, runId: options?.runId, agentChannel: resolveGatewayMessageChannel(options?.messageChannel ?? options?.messageProvider), agentAccountId: options?.agentAccountId, agentTo: options?.messageTo, agentThreadId: options?.messageThreadId, nativeChannelId: options?.nativeChannelId, messageActionTurnCapability: options?.messageActionTurnCapability, agentDir: options?.agentDir, preparedModelRuntime: options?.preparedModelRuntime, workspaceDir: workspaceRoot, config: options?.config, fsPolicy, requesterSenderId: options?.senderId, senderIsOwner: options?.senderIsOwner, sessionId: options?.sessionId, conversationRecall: options?.conversationRecall, oneShotCliRun: options?.oneShotCliRun, sandboxBrowserBridgeUrl: sandbox?.browser?.bridgeUrl, allowHostBrowserControl: sandbox ? sandbox.browserAllowHostControl : true, sandboxed: Boolean(sandbox), pluginToolAllowlist, pluginToolDenylist, currentChannelId: options?.currentChannelId, currentMessagingTarget: options?.currentMessagingTarget, currentThreadTs: options?.currentThreadTs, currentMessageId: options?.currentMessageId, modelProvider: options?.modelProvider, modelId: options?.modelId, modelHasVision: options?.modelHasVision, requireExplicitMessageTarget: options?.requireExplicitMessageTarget, disableMessageTool: options?.disableMessageTool || options?.swarmCollector, requesterAgentIdOverride: executionAgentId, allowGatewaySubagentBinding: options?.allowGatewaySubagentBinding, clientCaps: options?.clientCaps, toolBindings: options?.toolBindings, authProfileStore: options?.authProfileStore }, resolvedConfig: options?.config }), options?.clientCaps); const ringZeroTools = includeOpenClawTools ? getActiveAgentRingZeroTools() : []; const toolSearchTools = toolSearchControlsEnabled && ringZeroTools.length === 0 ? createToolSearchTools({ config: options?.config, runtimeConfig: options?.config, agentId, sessionKey: options?.sessionKey, sessionId: options?.sessionId, runId: options?.runId, catalogRef: options?.toolSearchCatalogRef, abortSignal: options?.abortSignal, executeTool: options?.toolSearchCatalogExecutor }) : []; const tools = [ ...scheduledExecTarget ? coreTools.map((tool) => tool.name === "exec" ? copyAgentToolMetadata(tool, pinExecToolTarget(tool, scheduledExecTarget)) : tool) : coreTools, ...includeChannelTools ? listChannelAgentTools({ cfg: options?.config }) : [], ...includeOpenClawTools ? mergeAgentRingZeroTools(ringZeroTools, createOpenClawTools({ ...options?.systemAgentTool ? { systemAgentTool: options.systemAgentTool } : {}, sandboxBrowserBridgeUrl: sandbox?.browser?.bridgeUrl, allowHostBrowserControl: sandbox ? sandbox.browserAllowHostControl : true, agentSessionKey: options?.sessionKey, runId: options?.runId, ...options?.questionPrompt ? { questionPrompt: options.questionPrompt } : {}, requesterThinkingLevel: options?.requesterThinkingLevel, sessionPermissionPolicy, execSession: sessionPermissionPolicy ? { permissionMode: sessionPermissionPolicy.mode } : void 0, execOverrides: { host: scheduledExecTarget?.host ?? options?.exec?.host ?? execConfig.host, mode: scheduledExecTarget?.ask ? void 0 : effectiveExecPolicy.mode, security: effectiveExecPolicy.security, ask: scheduledExecTarget?.ask ?? effectiveExecPolicy.ask, node: options?.exec?.node ?? execConfig.node }, approvalReviewerDeviceIds: options?.approvalReviewerDeviceId ? [options.approvalReviewerDeviceId] : void 0, runSessionKey: options?.runSessionKey, agentChannel: resolveGatewayMessageChannel(options?.messageChannel ?? options?.messageProvider), agentAccountId: options?.agentAccountId, gatewayCallerAccountId: gatewayCaller.accountId, gatewayCallerChannel: gatewayCaller.channel, gatewayCallerLocal: gatewayCaller.local, gatewayCallerScheduled: gatewayCaller.scheduled, agentTo: options?.messageTo, agentThreadId: options?.messageThreadId, nativeChannelId: options?.nativeChannelId, messageActionTurnCapability: options?.messageActionTurnCapability, agentGroupId: options?.groupId ?? null, agentGroupChannel: options?.groupChannel ?? null, agentGroupSpace: options?.groupSpace ?? null, agentMemberRoleIds: options?.memberRoleIds, agentDir: options?.agentDir, preparedModelRuntime: options?.preparedModelRuntime, sandboxRoot, sandboxContainerWorkdir: sandbox?.containerWorkdir, sandboxFsBridge, stagedMediaPaths: options?.stagedMediaPaths, sandboxWorkspaceMediaReadAllowed, fsPolicy, workspaceDir: workspaceRoot, spawnWorkspaceDir: capabilityProfile.workspace.spawnWorkspaceRoot, cwd: sandbox ? capabilityProfile.workspace.spawnWorkspaceRoot ?? runtimeRoot : runtimeRoot, sandboxed: Boolean(sandbox), config: options?.config, sessionConfigSource: options?.sessionConfigSource, webFetchHostnameAllowlistRef: options?.webFetchHostnameAllowlistRef, webSearchEnabled: options?.webSearchEnabled, clientCaps: options?.clientCaps, toolBindings: options?.toolBindings, pluginToolAllowlist, pluginToolDenylist, runtimeToolAllowlist: options?.runtimeToolAllowlist, githubPublicationAvailable: options?.githubPublicationAvailable, cronCreatorToolAllowlist, cronCreatorToolAllowlistCaptureRef, resolveCronCreatorToolAuthority: cronCreatorAuthorityResolver, cronCreatorAuthorityUnavailableReason: options?.cronCreatorAuthorityUnavailableReason, currentChannelId: options?.currentChannelId, currentChatType: options?.chatType, currentMessagingTarget: options?.currentMessagingTarget, currentThreadTs: options?.currentThreadTs, currentMessageId: options?.currentMessageId, currentInboundAudio: options?.currentInboundAudio, hasCurrentInboundAudio: options?.hasCurrentInboundAudio, modelProvider: options?.modelProvider, modelId: options?.modelId, modelContextWindowTokens: options?.modelContextWindowTokens, skillWorkshop: options?.skillWorkshop, replyToMode: options?.replyToMode, hasRepliedRef: options?.hasRepliedRef, modelHasVision: options?.modelHasVision, computerContextEpoch: options?.computerContextEpoch, computerTransport: resolveSessionPlacementComputer(options?.operationalRunInstance), registerRunCleanup: options?.registerRunCleanup, requireExplicitMessageTarget: options?.requireExplicitMessageTarget, sourceReplyDeliveryMode: options?.sourceReplyDeliveryMode, sourceReplyOnly, taskSuggestionDeliveryMode: options?.taskSuggestionDeliveryMode, inboundEventKind: options?.inboundEventKind, disableMessageTool: options?.disableMessageTool || options?.swarmCollector, swarmCollector: options?.swarmCollector, swarmOutputSchema: options?.swarmOutputSchema, enableHeartbeatTool, disablePluginTools: !includePluginTools, wrapBeforeToolCallHook: false, ...cronSelfRemoveOnlyJobId ? { cronSelfRemoveOnlyJobId } : {}, requesterAgentIdOverride: executionAgentId, requesterSenderId: options?.senderId, senderIsOwner: options?.senderIsOwner, authProfileStore: options?.authProfileStore, sessionId: options?.sessionId, conversationRecall: options?.conversationRecall, oneShotCliRun: options?.oneShotCliRun, inheritedToolAllowlist, inheritedToolDenylist, onYield: options?.onYield, claimYieldCompletion: options?.claimYieldCompletion, allowGatewaySubagentBinding: options?.allowGatewaySubagentBinding, recordToolPrepStage: options?.recordToolPrepStage })) : pluginToolsOnly, ...toolSearchTools ]; options?.recordToolPrepStage?.("openclaw-tools"); const swarmStructuredOutputTool = options?.swarmCollector && options.swarmOutputSchema ? tools.find((tool) => tool.name === "structured_output") : void 0; const toolsForMemoryFlush = isMemoryFlushRun && memoryFlushWritePath ? [] : tools; if (isMemoryFlushRun && memoryFlushWritePath) for (const tool of tools) { if (!MEMORY_FLUSH_ALLOWED_TOOL_NAMES.has(tool.name)) continue; if (tool.name === "write") { toolsForMemoryFlush.push(wrapToolMemoryFlushAppendOnlyWrite(tool, { root: memoryFlushWriteRoot, relativePath: memoryFlushWritePath, memoryWriteProvenance, containerWorkdir: sandbox?.containerWorkdir, sandbox: sandboxRoot && sandboxFsBridge ? { root: sandboxRoot, bridge: sandboxFsBridge } : void 0 })); continue; } toolsForMemoryFlush.push(tool); } const unavailableCoreToolReason = isMemoryFlushRun && memoryFlushWritePath ? "memory-triggered compaction runs expose only read and append-only write" : void 0; const toolsForMessageProvider = filterToolsByMessageProvider(toolsForMemoryFlush, options?.toolPolicyMessageProvider ?? options?.messageProvider); options?.recordToolPrepStage?.("message-provider-policy"); const toolsForModelProvider = applyModelProviderToolPolicy(toolsForMessageProvider, { config: options?.config, modelProvider: options?.modelProvider, modelApi: options?.modelApi, modelId: options?.modelId, agentId, sessionKey: options?.sessionKey, agentDir: options?.agentDir, modelCompat: options?.modelCompat, suppressManagedWebSearch: options?.suppressManagedWebSearch, runtimeToolAllowlist: options?.runtimeToolAllowlist, localModelLeanPreserveToolNames }); options?.recordToolPrepStage?.("model-provider-policy"); const subagentFiltered = applyToolPolicyPipeline({ tools: toolsForModelProvider, toolMeta: (tool) => getPluginToolMeta(tool), warn: logWarn, steps: buildConversationToolPolicyPipelineSteps({ capabilityProfile, policies: conversationToolPolicies, additionalStepsAfterSandbox: [{ policy: ownerOnlyCoreToolPolicy, label: "gateway sender owner-only tools", unavailableCoreToolReason }], includeRuntimeToolPolicy: true, unavailableCoreToolReason }), declaredToolAllowlist: buildDeclaredToolAllowlistContext({ config: options?.config, metadataSnapshot: options?.preparedModelRuntime?.metadataSnapshot, workspaceDir: workspaceRoot, toolDenylist: pluginToolDenylist }) }); const authorizedTools = applyDelegationCapability(mergeAgentRingZeroTools(ringZeroTools, subagentFiltered), options?.delegationCapability).filter((tool) => !options?.swarmCollector || tool.name !== "ask_user" && tool.name !== "sessions_send" && tool.name !== "sessions_yield"); if (swarmStructuredOutputTool && !authorizedTools.some((tool) => tool.name === swarmStructuredOutputTool.name)) authorizedTools.push(swarmStructuredOutputTool); authorizedTools.forEach(bindAssembledAgentToolActionDescriptor); processToolAvailabilityRef.value = authorizedTools.some((tool) => tool.name === "process"); if (shouldInheritEffectiveToolAllowlist) replaceWithEffectiveToolAllowlist(inheritedToolAllowlist, authorizedTools); replaceWithEffectiveCronCreatorToolAllowlist(cronCreatorToolAllowlist, authorizedTools, (tool) => getPluginToolMeta(tool)); options?.recordToolPrepStage?.("authorization-policy"); const turnSourceChannel = options?.messageChannel ?? options?.messageProvider; const turnSourceTo = options?.currentMessagingTarget ?? options?.currentChannelId; const requester = { ...turnSourceChannel ? { channel: turnSourceChannel } : {}, ...options?.agentAccountId ? { accountId: options.agentAccountId } : {}, ...options?.senderId ? { senderId: options.senderId } : {}, ...options?.senderIsOwner !== void 0 ? { senderIsOwner: options.senderIsOwner } : {}, ...options?.memberRoleIds?.length ? { roleIds: [...options.memberRoleIds] } : {} }; const hasRequester = Object.keys(requester).length > 0; const hookContext = { agentId: executionAgentId, ...options?.config ? { config: options.config } : {}, cwd: codingRoot, workspaceDir: workspaceRoot, ...options?.skillsSnapshot ? { skillsSnapshot: options.skillsSnapshot } : {}, ...options?.skillUsagePaths ? { skillUsagePaths: options.skillUsagePaths } : {}, ...sandboxRoot && sandboxFsBridge && allowWorkspaceWrites ? { sandbox: { root: sandboxRoot, bridge: sandboxFsBridge } } : {}, sessionKey: executionSessionKey, sessionId: options?.sessionId, runId: options?.runId, trigger: options?.trigger, approvalReviewerDeviceId: options?.approvalReviewerDeviceId, channelId: options?.hookChannelId ?? options?.currentChannelId, ...hasRequester ? { requester } : {}, ...turnSourceChannel ? { turnSourceChannel } : {}, ...turnSourceTo ? { turnSourceTo } : {}, ...options?.agentAccountId ? { turnSourceAccountId: options.agentAccountId } : {}, ...options?.currentThreadTs ? { turnSourceThreadId: options.currentThreadTs } : {}, ...options?.trace ? { trace: options.trace } : {}, loopDetection: resolveToolLoopDetectionConfig({ cfg: options?.config, agentId }), onToolOutcome: options?.onToolOutcome, allocateToolOutcomeOrdinal: options?.allocateToolOutcomeOrdinal }; return finalizeAgentTools({ tools: authorizedTools, modelProvider: options?.modelProvider, modelId: options?.modelId, modelCompat: options?.modelCompat, hookContext, wrapBeforeToolCallHook: options?.wrapBeforeToolCallHook, emitBeforeToolCallDiagnostics: options?.emitBeforeToolCallDiagnostics, ...options?.swarmCollector ? { approvalMode: "deny" } : {}, abortSignal: options?.abortSignal, agentId: executionAgentId, recordToolPrepStage: options?.recordToolPrepStage }).map((tool) => wrapToolWithGatewayCallerIdentity(tool, toolCallerIdentity)); } /** Build the runtime tool list exposed through the public agent harness SDK. */ function createOpenClawCodingTools(options) { return createOpenClawCodingToolsInternal(options); } //#endregion export { filterToolsByMessageProvider as i, applyDelegationCapability as n, resolveDelegationCapability as r, createOpenClawCodingTools as t };