openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
814 lines (813 loc) • 42.5 kB
JavaScript
import { t as createSubsystemLogger } from "./subsystem-4NzR43uz.mjs";
import { h as resolveSessionAgentId } from "./agent-scope-bJOokm5r.mjs";
import { t as AUTOMATIONS_TOOL_NAME } from "./automations-tool-name-DaxQ5QU2.mjs";
import { c as normalizeToolPolicyName, i as expandToolGroups } from "./tool-policy-shared-CNWjndK7.mjs";
import { n as createRuntimeToolMatcher } from "./tool-policy-match-BXLYReRw.mjs";
import { c as hasRestrictiveAllowPolicy, u as replaceWithEffectiveToolAllowlist } from "./tool-policy-BrMCyUgN.mjs";
import { o as getRuntimeConfigSnapshot } from "./runtime-snapshot-De_QxZI9.mjs";
import { i as resolveGatewayMessageChannel } from "./message-channel-normalize-JIxBUi40.mjs";
import "./message-channel-AvA3r_Xp.mjs";
import { i as logWarn } from "./logger-DZaOV_pr.mjs";
import { c as rewrapToolWithBeforeToolCallHook, l as wrapToolWithBeforeToolCallHook } from "./agent-tools.before-tool-call-CQkX3nOj.mjs";
import { o as getActiveSecretsRuntimeConfigSnapshot } from "./runtime-state-B9uZIjU9.mjs";
import { t as ToolAuthorizationError } from "./tool-input-error-mjW74R8m.mjs";
import { u as isCompletionReportInputProvenance } from "./input-provenance-B5YZS2Do.mjs";
import { t as HEARTBEAT_RESPONSE_TOOL_NAME } from "./heartbeat-tool-response-CBuqAXpY.mjs";
import { r as projectEffectiveExecPolicy } from "./session-permission-exec-mode-w9RzCNiZ.mjs";
import { g as wrapToolWithGatewayCallerIdentity } from "./gateway-caller-context-CU8n6n_e.mjs";
import { n as copyPluginToolMeta, r as getPluginToolMeta } from "./tool-metadata-D5DsuLcG.mjs";
import { r as finalizeAgentToolAvailability } from "./agent-tool-availability-ChrbIW4j.mjs";
import { d as pinExecToolTarget, i as copyAgentToolMetadata, r as bindAssembledAgentToolActionDescriptor, x as isToolWrappedWithBeforeToolCallHook } from "./agent-tool-metadata-DU21au_v.mjs";
import "./common-BkU19q6Q.mjs";
import { w as waitForExecScope } from "./bash-process-registry-CI4nrAyM.mjs";
import { t as resolveScheduledToolCallerContext } from "./scheduled-tool-policy-9TJ3ygDd.mjs";
import { t as resolveSessionPlacementComputer } from "./session-placement-computer-Bem5hZb0.mjs";
import { t as resolveConversationCapabilityProfile } from "./conversation-capability-profile-Bzbp--xF.mjs";
import { t as getProcessSupervisor } from "./supervisor-DLkAGOz1.mjs";
import { n as resolveEventSessionRoutingPolicy } from "./event-session-routing-Dm8aw0lJ.mjs";
import { m as wrapToolWithAbortSignal } from "./tool-contract-error-CznWpQuP.mjs";
import { r as messageToolOwnsVisibleReply } from "./source-reply-delivery-mode-CBzJmohC.mjs";
import { n as mergeGatewayAgentCliPath } from "./openclaw-cli-shim-LRKaYTVB.mjs";
import { t as appendRuntimePluginToolGrant } from "./tool-grant-allowlist-m1tXxJWt.mjs";
import { t as applyToolPolicyPipeline } from "./tool-policy-pipeline-4Av_cTF8.mjs";
import { i as resolveConversationToolPolicies, n as isConversationToolAllowed, t as buildConversationToolPolicyPipelineSteps } from "./conversation-tool-policy-pipeline-qvZEbKgk.mjs";
import { t as applyToolAvailabilityDescriptions } from "./agent-tools.deferred-followup-CGTaTZqK.mjs";
import { a as resolveMemoryFlushToolSetup, i as projectMemoryFlushTools, o as warnIfMemoryFlushFileWriterUnavailable, r as assertMemoryFlushPersistenceToolAvailable, s as filterToolsByMessageProvider, t as createCoreCodingTools } from "./core-coding-tools-DFJcX7yX.mjs";
import { p as createMemoryWriteProvenanceObserver } from "./agent-tools.read-KaO_d_Xi.mjs";
import { n as resolveSandboxFileIdentity } from "./file-mutation-identity-C_-O-u-P.mjs";
import { C as filterLocalModelLeanTools, T as resolveLocalModelLeanPreserveToolNames, c as resolveToolSearchConfig, n as createToolSearchTools, v as TOOL_CALL_RAW_TOOL_NAME, x as TOOL_SEARCH_RAW_TOOL_NAME, y as TOOL_DESCRIBE_RAW_TOOL_NAME } from "./tool-search-BorBxVGT.mjs";
import { t as resolveNativeWebSearchRoute } from "./native-web-search-bW6OOGeW.mjs";
import { r as mergeAgentRingZeroTools, t as getActiveAgentRingZeroTools } from "./agent-tools.ring-zero-context-DcmTQndF.mjs";
import { t as resolveProcessToolScopeKey } from "./bash-process-scope-2cvMG8cQ.mjs";
import { n as listChannelAgentTools } from "./channel-tools-DbPPjer2.mjs";
import { n as resolveExecToolConfig } from "./lazy-exec-tool-CzsaJ12F.mjs";
import { i as bindCronManagementGrant, n as bindActiveCronCreatorAuthorityResolver } from "./cron-creator-authority-context-DJ_0mFxL.mjs";
import { l as prepareGitHubToolEnvironment } from "./github-tool-identity-DbK12gfx.mjs";
import { S as resolveOpenClawPluginToolsForOptions, d as withPreparedToolConstruction, f as applySwarmCollectorToolContract, r as createOpenClawToolsWithPreparation, t as createOpenClawTools, x as filterToolsByClientCaps } from "./openclaw-tools-CSSYZDKR.mjs";
import { a as getInProcessGatewayToolContext } from "./in-process-gateway-BYRZzLBf.mjs";
import { r as subagentAttachmentRootForRun } from "./subagent-attachment-paths-CBAfNBVu.mjs";
import { n as filterRequesterYieldTools } from "./openclaw-tools.requester-yield-CgnBWU3N.mjs";
import { n as getSessionRowProjection } from "./session-row-projection-access-C2RDnj28.mjs";
import { i as resolveGatewayOwnerOnlyToolDenylist } from "./dangerous-tools-7P77gGzs.mjs";
import { t as resolveToolLoopDetectionConfig } from "./tool-loop-detection-config-TObMWR7t.mjs";
import { i as replaceWithEffectiveCronCreatorToolAllowlist } from "./cron-tool-D1QAKUFW.mjs";
import { t as prepareCoreToolPolicy } from "./prepared-tool-surface-uIlMCUI4.mjs";
import { t as buildDeclaredToolAllowlistContext } from "./tool-policy-declared-context-lXzP_dWs.mjs";
import { t as captureSessionPortalTarget } from "./session-portal-target-D54R2k-a.mjs";
import { normalizeToolParameterSchema } from "@openclaw/ai/internal/tool-schema";
//#region src/agents/agent-tools.caller.ts
/** Carries the coding surface's prepared policy and requesting route into plugin delegation. */
function createCodingToolsGatewayCaller(params) {
const { options, agentId, sessionKey, capabilityProfile } = params;
const settleBatch = capabilityProfile.policy.requesterPolicySource === "completion-handoff" ? options?.trustedInternalHandoff?.settleBatch : void 0;
const identity = options && agentId && sessionKey?.trim() ? {
agentId,
sessionKey: sessionKey.trim(),
sessionEventToolsAllow: params.sessionEventSourcePolicy?.toolsAllow,
sessionEventSettings: params.sessionEventSourcePolicy?.settings ?? { permissionMode: options.sessionPermissionPolicy?.mode },
...options.sourceReplyDeliveryMode === "message_tool_only" ? { sessionEventDelivery: false } : {},
receiptAuthority: settleBatch?.isCurrent,
receiptAdmissions: settleBatch?.receiptAdmission ? [settleBatch.receiptAdmission] : void 0,
assertToolAllowed: (toolName) => {
if (!isConversationToolAllowed(capabilityProfile, toolName)) throw new Error(`${toolName} is not allowed by this conversation's tool policy`);
},
...options.abortSignal ? { approvalSignals: [options.abortSignal] } : {},
turnSourceChannel: resolveGatewayMessageChannel(options.messageChannel ?? options.messageProvider),
turnSourceTo: options.currentMessagingTarget ?? options.currentChannelId ?? options.messageTo,
turnSourceAccountId: params.accountId,
turnSourceThreadId: options.currentThreadTs ?? options.messageThreadId
} : void 0;
return (tool) => wrapToolWithGatewayCallerIdentity(tool, identity);
}
//#endregion
//#region src/agents/agent-tools.schema.ts
/**
* Tool schema normalization wrappers.
* Applies provider-compatible parameter schema cleanup while preserving
* identity-backed metadata on normalized tools.
*/
function isObjectSchemaWithNoRequiredParams(schema) {
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return false;
const record = schema;
const type = record.type;
if (!(type === "object" || Array.isArray(type) && type.some((entry) => entry === "object"))) return false;
return !schemaHasRequiredParams(record);
}
function schemaHasRequiredParams(schema) {
if (Array.isArray(schema.required) && schema.required.length > 0) return true;
for (const key of [
"allOf",
"anyOf",
"oneOf"
]) {
const variants = schema[key];
if (!Array.isArray(variants)) continue;
if (variants.some((variant) => variant !== null && typeof variant === "object" && !Array.isArray(variant) && schemaHasRequiredParams(variant))) return true;
}
return false;
}
/** Normalize a tool's parameter schema for the selected provider/model. */
function normalizeToolParameters(tool, options) {
const schema = tool.parameters && typeof tool.parameters === "object" ? tool.parameters : void 0;
if (!schema) return tool;
const parameters = normalizeToolParameterSchema(schema, options);
const normalized = {
...tool,
parameters
};
if (isObjectSchemaWithNoRequiredParams(parameters)) normalized.prepareArguments = (args) => {
const prepared = tool.prepareArguments ? tool.prepareArguments(args) : args;
return prepared === null || prepared === void 0 ? {} : prepared;
};
return copyAgentToolMetadata(tool, normalized);
}
//#endregion
//#region src/agents/agent-tools.finalize.ts
function finalizeAgentTools(options) {
finalizeAgentToolAvailability(options.tools, { beforeNormalization: true });
const normalized = options.tools.map((tool) => normalizeToolParameters(tool, {
modelProvider: options.modelProvider,
modelId: options.modelId,
modelCompat: options.modelCompat
}));
options.recordToolPrepStage?.("schema-normalization");
const hookOptions = {
emitDiagnostics: options.emitBeforeToolCallDiagnostics,
...options.approvalMode ? { approvalMode: options.approvalMode } : {}
};
const withHooks = options.wrapBeforeToolCallHook === false ? normalized : normalized.map((tool) => typeof options.wrapBeforeToolCallHook === "function" && !options.wrapBeforeToolCallHook(tool) ? tool : isToolWrappedWithBeforeToolCallHook(tool) ? rewrapToolWithBeforeToolCallHook(tool, options.hookContext, hookOptions) : wrapToolWithBeforeToolCallHook(tool, options.hookContext, hookOptions));
options.recordToolPrepStage?.("tool-hooks");
const abortSignal = options.abortSignal;
const withAbort = abortSignal ? withHooks.map((tool) => wrapToolWithAbortSignal(tool, abortSignal)) : withHooks;
options.recordToolPrepStage?.("abort-wrappers");
const finalized = applyToolAvailabilityDescriptions(withAbort);
options.recordToolPrepStage?.("deferred-followup-descriptions");
return finalized;
}
//#endregion
//#region src/agents/agent-tools.model-provider-policy.ts
function applyModelProviderToolPolicy(toolsInput, params) {
const tools = filterLocalModelLeanTools({
tools: toolsInput,
config: params?.config,
agentId: params?.agentId,
sessionKey: params?.sessionKey,
preserveToolNames: params?.localModelLeanPreserveToolNames ?? params?.runtimeToolAllowlist
});
if (params?.suppressManagedWebSearch !== false && resolveNativeWebSearchRoute({
config: params?.config,
modelProvider: params?.modelProvider,
modelApi: params?.modelApi,
modelBaseUrl: params?.modelBaseUrl,
modelId: params?.modelId,
agentId: params?.agentId,
sessionKey: params?.sessionKey,
agentDir: params?.agentDir,
runtimeToolAllowlist: params?.runtimeToolAllowlist,
pluginMetadataSnapshot: params?.preparedModelRuntime?.metadataSnapshot
}).kind === "native") return tools.filter((tool) => tool.name !== "web_search");
return tools;
}
//#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/scheduled-message-invocation.ts
/** Admit each new invocation against published policy without changing an accepted invocation. */
function createScheduledMessageInvocationAdmission(params) {
let cached;
return () => {
const config = getRuntimeConfigSnapshot() ?? params.config;
if (!config) throw new Error("Scheduled message tools require an active runtime configuration.");
if (cached?.config !== config) cached = {
config,
allowed: params.isAllowed(config)
};
if (!cached.allowed) throw new Error("Scheduled message invocation is not allowed by the current tool policy.");
return config;
};
}
/** Reuse the assembled embedded catalog and resource ceilings for prospective message policy. */
function createEmbeddedMessageInvocationPolicy(params) {
const policies = resolveConversationToolPolicies({
capabilityProfile: params.capabilityProfile,
additionalProfileAllow: params.runtimeProfileAlsoAllow,
additionalPolicyAllow: params.toolSearchControlAllowlist
});
const filter = (currentProfile = params.capabilityProfile, onFilter) => {
const currentPolicies = currentProfile === params.capabilityProfile ? policies : resolveConversationToolPolicies({
capabilityProfile: currentProfile,
additionalProfileAllow: params.runtimeProfileAlsoAllow,
additionalPolicyAllow: params.toolSearchControlAllowlist
});
const { tools, declaredToolAllowlist, unavailableCoreToolReason } = params.catalog();
return applyToolPolicyPipeline({
tools,
toolMeta: (tool) => getPluginToolMeta(tool),
warn: logWarn,
steps: buildConversationToolPolicyPipelineSteps({
capabilityProfile: currentProfile,
policies: {
...currentPolicies,
groupPolicy: policies.groupPolicy,
senderPolicy: policies.senderPolicy,
sandboxPolicy: policies.sandboxPolicy,
subagentPolicy: policies.subagentPolicy,
runtimeToolPolicy: policies.runtimeToolPolicy,
inheritedToolPolicy: policies.inheritedToolPolicy
},
additionalStepsAfterSandbox: [{
policy: params.ownerOnlyCoreToolPolicy,
source: { kind: "session" },
label: "gateway sender owner-only tools",
unavailableCoreToolReason
}],
includeRuntimeToolPolicy: true,
unavailableCoreToolReason
}),
declaredToolAllowlist,
onFilter
});
};
return {
filter,
admit: createScheduledMessageInvocationAdmission({
config: params.config,
isAllowed: (config) => {
const profile = params.capabilityProfile;
const currentProfile = config === params.config ? profile : resolveConversationCapabilityProfile({
...profile.conversation,
config,
agentId: profile.policy.agentId,
sessionKey: profile.policy.sessionKey,
agentAccountId: profile.serviceIdentity.accountId,
modelProvider: profile.model.provider,
modelId: profile.model.id,
senderIsOwner: profile.sender.isOwner,
scheduledToolPolicy: params.scheduledToolPolicy,
runtimePluginToolGrant: profile.policy.runtimePluginToolGrant,
pluginMetadataSnapshot: params.pluginMetadataSnapshot
});
return params.isAvailable() && filter(currentProfile).some((tool) => tool.name === "message");
}
})
};
}
//#endregion
//#region src/agents/tools/session-portal-target.ts
function prepareSessionPortalToolAccess(input) {
const sessionPortalTarget = input.senderIsOwner === false && !input.sandboxed ? prepareSessionPortalToolTarget(input) : void 0;
const ownerOnlyCoreToolDenylist = resolveGatewayOwnerOnlyToolDenylist(input.senderIsOwner).filter((name) => (name !== "portal" || !sessionPortalTarget) && name !== "sessions" && (name !== "automations" || !input.hasAutomationGrant));
return {
sessionPortalTarget,
ownerOnlyCoreToolDenylist,
ownerOnlyCoreToolPolicy: ownerOnlyCoreToolDenylist.length ? { deny: ownerOnlyCoreToolDenylist } : void 0
};
}
/** Availability uses resident execution facts; the scoped RPC still authorizes every call. */
function prepareSessionPortalToolTarget(input) {
if (!input.sessionId || !input.sessionKey || !input.agentId) return;
const context = getInProcessGatewayToolContext();
const environments = context?.workerEnvironmentService;
const projection = getSessionRowProjection(context);
const query = {
agentId: input.agentId,
key: input.sessionKey
};
const readCurrentTarget = () => {
const row = projection?.capture(query);
const state = projection?.sharingTargetState(query);
if (!row?.storedEntry || row.unresolvedDatabaseFacts || !projection?.isCurrent(row) || state?.status !== "ready" || state.target.generation !== row.generation || state.target.agentId !== row.agentId || state.target.canonicalKey !== row.key || state.target.storePath !== row.storeTarget.storePath || state.target.entry.sessionId !== row.storedEntry.sessionId || state.target.entry.lifecycleRevision !== row.storedEntry.lifecycleRevision || row.storedEntry.modelSelectionLocked === true) return;
return state.target;
};
const row = readCurrentTarget();
const generation = row?.generation;
const record = row && {
agentId: row.agentId,
sessionKey: row.canonicalKey,
sessionId: row.entry.sessionId,
sessionLifecycleRevision: row.entry.lifecycleRevision
};
if (!context?.portalService || !environments || !record || record.sessionKey !== input.sessionKey || record.agentId !== input.agentId || record.sessionId !== input.sessionId) return;
try {
const target = captureSessionPortalTarget(environments, record);
return {
sessionKey: record.sessionKey,
agentId: record.agentId,
environmentId: target.binding.environmentId,
assertCurrent: () => {
if (getInProcessGatewayToolContext() !== context) throw new Error("Session preview belongs to a different or retired Gateway");
const current = readCurrentTarget();
if (!current || current.generation !== generation || current.entry.sessionId !== record.sessionId || current.entry.lifecycleRevision !== record.sessionLifecycleRevision) throw new Error("Conversation preview policy or session identity changed");
target.assertCurrent();
}
};
} catch {
return;
}
}
//#endregion
//#region src/agents/agent-tools.ts
function* assembleOpenClawCodingTools(options, skillReadResources, onPolicyFilter, preparedSurface) {
const preparedTools = preparedSurface?.tools;
const sandbox = options?.sandbox?.enabled ? options.sandbox : void 0;
const { isMemoryFlushRun, memoryFlush, memoryFlushWritePath } = resolveMemoryFlushToolSetup(options);
const cronSelfRemoveOnlyJobId = options?.trigger === "cron" && options.jobId?.trim() ? options.jobId.trim() : void 0;
const capabilityProfile = options?.conversationCapabilityProfile ?? resolveConversationCapabilityProfile({
...options,
agentId: options?.policyAgentId ?? options?.agentId,
sandboxToolPolicy: sandbox?.tools,
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 attachmentReadRoot = subagentAttachmentRootForRun(executionAgentId, executionSessionKey);
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_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 sandboxWorkspaceMediaReadAllowed = isConversationToolAllowed(capabilityProfile, "read");
const scopeKey = resolveProcessToolScopeKey({
scopeKey: options?.exec?.scopeKey,
sessionKey: executionSessionKey,
sessionId: options?.sessionId,
agentId: executionAgentId
});
if (options?.oneShotCliRun && scopeKey && options.registerRunCleanup) {
const cleanupScope = getProcessSupervisor().acquireScopeCleanup(scopeKey, { processTree: "owned-only" });
options.registerRunCleanup(async () => {
const failed = (await Promise.allSettled([cleanupScope(), waitForExecScope(scopeKey)])).find((result) => result.status === "rejected");
if (failed) throw failed.reason;
});
}
options?.recordToolPrepStage?.("tool-policy");
const execConfig = resolveExecToolConfig({
cfg: options?.config,
agentId
});
const execRuntimeConfig = options?.exec?.config ?? options?.config;
const preparedRunEnvironment = preparedTools === void 0 && execRuntimeConfig && executionAgentId ? prepareGitHubToolEnvironment({
config: execRuntimeConfig,
sourceConfig: getActiveSecretsRuntimeConfigSnapshot()?.sourceConfig,
agentId: executionAgentId
}) : void 0;
const sessionPermissionPolicy = options?.sessionPermissionPolicy;
const coreToolPolicy = preparedSurface?.policy ?? prepareCoreToolPolicy({
...options,
agentId
}, execConfig);
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 fsPolicy = {
workspaceOnly: coreToolPolicy.workspaceOnly,
...sessionPermissionPolicy ? { root: sessionPermissionPolicy.root } : {},
...attachmentReadRoot ? { readOnlyRoots: [attachmentReadRoot] } : {}
};
options?.recordToolPrepStage?.("workspace-policy");
const execDefaults = options?.exec ?? {};
const scheduledExecTarget = options?.scheduledToolPolicy?.execTarget;
const effectiveExecPolicy = projectEffectiveExecPolicy({
base: execConfig,
overrides: options?.exec,
permissionPolicy: sessionPermissionPolicy,
scheduledExecTarget
});
const coreTools = preparedTools === void 0 ? createCoreCodingTools({
abortSignal: options?.abortSignal,
attachmentReadRoot,
codingRoot,
containmentRoot,
includeBaseCodingTools,
shellTools: includeShellTools ? "full" : "disabled",
...coreToolPolicy,
sandbox,
skillsSnapshot: options?.skillsSnapshot,
skillReadResources,
skillInstructionPaths: options?.skillUsagePaths?.map((entry) => entry.readPath),
skillInstructionDeliveryCache: options?.skillInstructionDeliveryCache,
memoryWriteProvenance,
execDefaults: {
...execDefaults,
...effectiveExecPolicy,
config: execRuntimeConfig,
preparedRunEnvironment,
reviewer: options?.exec?.reviewer ?? execConfig.reviewer,
reviewTranscript: options?.exec?.reviewTranscript,
trigger: options?.trigger,
continuesConversation: options?.continuesConversation,
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,
cleanupMs: options?.exec?.cleanupMs ?? execConfig.cleanupMs,
scopeKey,
sessionKey: options?.sessionKey,
runId: options?.runId,
operationalRunInstance: options?.operationalRunInstance,
runSessionKey: executionSessionKey,
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: { scopeKey },
recordToolPrepStage: options?.recordToolPrepStage
}) : [];
const cronCreatorAuthorityResolver = bindActiveCronCreatorAuthorityResolver(options?.runId);
const cronManagementGrant = bindCronManagementGrant(options?.runId);
const { sessionPortalTarget, ownerOnlyCoreToolDenylist, ownerOnlyCoreToolPolicy } = prepareSessionPortalToolAccess({
sessionKey: executionSessionKey,
agentId: executionAgentId,
sessionId: options?.sessionId,
senderIsOwner: options?.senderIsOwner,
sandboxed: Boolean(sandbox),
hasAutomationGrant: Boolean(cronCreatorAuthorityResolver || cronManagementGrant)
});
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 gatewayCaller = resolveScheduledToolCallerContext({
scheduledToolPolicy: options?.scheduledToolPolicy,
accountId: options?.agentAccountId,
channel: resolveGatewayMessageChannel(options?.messageChannel ?? options?.messageProvider)
});
const pluginToolOptions = {
...options,
agentSessionKey: options?.sessionKey,
agentChannel: resolveGatewayMessageChannel(options?.messageChannel ?? options?.messageProvider),
agentTo: options?.messageTo,
agentThreadId: options?.messageThreadId,
workspaceDir: workspaceRoot,
fsPolicy,
requesterSenderId: options?.senderId,
memoryFlush,
sandboxBrowserBridgeUrl: sandbox?.browser?.bridgeUrl,
allowHostBrowserControl: sandbox ? sandbox.browserAllowHostControl : true,
sandboxed: Boolean(sandbox),
pluginToolAllowlist,
pluginToolDenylist,
disableMessageTool: options?.disableMessageTool || options?.swarmCollector,
requesterAgentIdOverride: executionAgentId
};
const pluginToolsOnly = filterToolsByClientCaps(includeOpenClawTools || !includePluginTools ? [] : resolveOpenClawPluginToolsForOptions({
options: pluginToolOptions,
resolvedConfig: options?.config
}), options?.clientCaps);
const ringZeroTools = includeOpenClawTools && !isMemoryFlushRun ? getActiveAgentRingZeroTools() : [];
const toolSearchTools = toolSearchControlsEnabled && ringZeroTools.length === 0 ? createToolSearchTools({
...options,
runtimeConfig: options?.config,
agentId,
catalogRef: options?.toolSearchCatalogRef,
executeTool: options?.toolSearchCatalogExecutor
}) : [];
const scheduledCoreTools = scheduledExecTarget ? coreTools.map((tool) => tool.name === "exec" ? copyAgentToolMetadata(tool, pinExecToolTarget(tool, scheduledExecTarget)) : tool) : coreTools;
const messageInvocationPolicy = createEmbeddedMessageInvocationPolicy({
config: options?.config,
capabilityProfile,
runtimeProfileAlsoAllow,
toolSearchControlAllowlist,
scheduledToolPolicy: options?.scheduledToolPolicy,
pluginMetadataSnapshot: options?.preparedModelRuntime?.metadataSnapshot,
ownerOnlyCoreToolPolicy,
catalog: () => ({
tools: toolsForModelProvider,
declaredToolAllowlist,
unavailableCoreToolReason
}),
isAvailable: () => authorizedTools.some((tool) => tool.name === "message")
});
const assembledTools = [
...scheduledCoreTools,
...includeChannelTools ? listChannelAgentTools({ cfg: options?.config }) : [],
...includeOpenClawTools ? mergeAgentRingZeroTools(ringZeroTools, yield {
...pluginToolOptions,
sessionPortalTarget,
sandboxSessionRenameOnly: capabilityProfile.policy.sandboxSessionRenameOnly,
sessionPermissionPolicy,
execSession: sessionPermissionPolicy ? { permissionMode: sessionPermissionPolicy.mode } : void 0,
execOverrides: {
host: effectiveExecPolicy.host,
mode: effectiveExecPolicy.mode,
security: effectiveExecPolicy.security,
ask: effectiveExecPolicy.ask,
node: options?.exec?.node ?? execConfig.node
},
approvalReviewerDeviceIds: options?.approvalReviewerDeviceId ? [options.approvalReviewerDeviceId] : void 0,
gatewayCallerAccountId: gatewayCaller.accountId,
gatewayCallerChannel: gatewayCaller.channel,
gatewayCallerLocal: gatewayCaller.local,
gatewayCallerScheduled: gatewayCaller.scheduled,
admitScheduledMessageInvocation: options?.messageActionTurnCapability ? messageInvocationPolicy.admit : void 0,
agentGroupId: options?.groupId ?? null,
agentGroupChannel: options?.groupChannel ?? null,
agentGroupSpace: options?.groupSpace ?? null,
agentMemberRoleIds: options?.memberRoleIds,
sandboxRoot,
sandboxContainerWorkdir: sandbox?.containerWorkdir,
sandboxFsBridge,
sandboxReadOnlyResourceMounts: sandbox?.readOnlyResourceMounts,
sandboxWorkspaceMediaReadAllowed,
spawnWorkspaceDir: capabilityProfile.workspace.spawnWorkspaceRoot,
cwd: sandbox ? capabilityProfile.workspace.spawnWorkspaceRoot ?? runtimeRoot : runtimeRoot,
gatewayConfigReadAllowed: capabilityProfile.policy.gatewayConfigReadAllowed,
cronCreatorToolAllowlist,
cronCreatorToolAllowlistCaptureRef: options?.cronCreatorToolAllowlistCaptureRef,
resolveCronCreatorToolAuthority: cronCreatorAuthorityResolver,
currentChatType: options?.chatType,
computerTransport: options?.computerTransport === null ? null : options?.computerTransport ?? resolveSessionPlacementComputer(options?.operationalRunInstance),
sourceReplyOnly,
enableHeartbeatTool,
disablePluginTools: !includePluginTools,
wrapBeforeToolCallHook: false,
...cronSelfRemoveOnlyJobId ? { cronSelfRemoveOnlyJobId } : {},
inheritedToolAllowlist,
inheritedToolDenylist,
inheritedToolPolicySource: capabilityProfile.policy.inheritedToolPolicySource,
processScopeKey: scopeKey
}) : pluginToolsOnly,
...toolSearchTools
];
options?.recordToolPrepStage?.("openclaw-tools");
const tools = preparedTools ? [...new Map([...assembledTools, ...preparedTools].map((tool) => [tool.name, tool])).values()] : assembledTools;
const swarmStructuredOutputTool = options?.swarmCollector && options.swarmOutputSchema ? tools.find((tool) => tool.name === "structured_output") : void 0;
const toolsForMemoryFlush = projectMemoryFlushTools(tools, isMemoryFlushRun && memoryFlushWritePath ? {
root: memoryFlushWriteRoot,
relativePath: memoryFlushWritePath,
memoryWriteProvenance,
containerWorkdir: sandbox?.containerWorkdir,
sandbox: sandboxRoot && sandboxFsBridge ? {
root: sandboxRoot,
bridge: sandboxFsBridge
} : void 0
} : isMemoryFlushRun ? options?.memoryFlushTools : void 0);
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, {
...options,
agentId,
localModelLeanPreserveToolNames
});
options?.recordToolPrepStage?.("model-provider-policy");
const declaredToolAllowlist = buildDeclaredToolAllowlistContext({
config: options?.config,
metadataSnapshot: options?.preparedModelRuntime?.metadataSnapshot,
workspaceDir: workspaceRoot,
toolDenylist: pluginToolDenylist
});
const subagentFiltered = messageInvocationPolicy.filter(capabilityProfile, onPolicyFilter);
const authorizedTools = applySwarmCollectorToolContract(applyDelegationCapability(mergeAgentRingZeroTools(ringZeroTools, subagentFiltered), options?.delegationCapability), {
swarmCollector: options?.swarmCollector,
structuredOutputTool: swarmStructuredOutputTool
});
assertMemoryFlushPersistenceToolAvailable(authorizedTools, options?.memoryFlushTools);
authorizedTools.forEach(bindAssembledAgentToolActionDescriptor);
if (shouldInheritEffectiveToolAllowlist) replaceWithEffectiveToolAllowlist(inheritedToolAllowlist, authorizedTools);
replaceWithEffectiveCronCreatorToolAllowlist(cronCreatorToolAllowlist, authorizedTools, (tool) => getPluginToolMeta(tool));
warnIfMemoryFlushFileWriterUnavailable({
tools: authorizedTools,
relativePath: memoryFlushWritePath,
messageProvider: options?.toolPolicyMessageProvider ?? options?.messageProvider
});
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
};
const finalizedTools = finalizeAgentTools({
...options,
tools: filterRequesterYieldTools(authorizedTools, executionSessionKey),
wrapBeforeToolCallHook: preparedTools ? (tool) => options?.wrapBeforeToolCallHook !== false && !preparedTools.some((prepared) => prepared.name === tool.name) : options?.wrapBeforeToolCallHook,
hookContext,
...options?.swarmCollector ? { approvalMode: "deny" } : {}
});
return finalizedTools.map(createCodingToolsGatewayCaller({
options,
agentId: executionAgentId,
sessionKey: executionSessionKey,
accountId: gatewayCaller.accountId,
capabilityProfile,
sessionEventSourcePolicy: options?.sessionEventSourcePolicy ?? { toolsAllow: finalizedTools.map((tool) => tool.name) }
}));
}
/** @deprecated Use createOpenClawCodingToolsInternalAsync for runtime construction. */
function createOpenClawCodingToolsInternal(...args) {
const assembly = assembleOpenClawCodingTools(...args);
let step = assembly.next();
while (!step.done) step = assembly.next(createOpenClawTools(step.value));
return step.value;
}
/** Internal preparation data stays outside the public harness factory options. */
async function createOpenClawCodingToolsInternalAsync(options, skillReadResources, onPolicyFilter, preparedSurface, preparation = {}) {
return withPreparedToolConstruction(options?.config, {
...preparation,
signal: options?.abortSignal && preparation.signal ? AbortSignal.any([options.abortSignal, preparation.signal]) : options?.abortSignal ?? preparation.signal
}, async (shared) => {
const assembly = assembleOpenClawCodingTools({
...options,
config: shared.config
}, skillReadResources, onPolicyFilter, preparedSurface);
let step = assembly.next();
while (!step.done) {
const tools = await createOpenClawToolsWithPreparation(step.value, shared);
shared.assertCurrent();
step = assembly.next(tools);
}
return step.value;
});
}
/** @deprecated Use createOpenClawCodingToolsAsync to prepare policy through the worker. */
function createOpenClawCodingTools(options) {
return createOpenClawCodingToolsInternal(options);
}
/** Build the SDK tool list with a fresh, source-bound exec policy. */
function createOpenClawCodingToolsAsync(options) {
return createOpenClawCodingToolsInternalAsync(options);
}
//#endregion
export { prepareSessionPortalToolTarget as a, resolveDelegationCapability as c, createOpenClawCodingToolsInternalAsync as i, createOpenClawCodingToolsAsync as n, createScheduledMessageInvocationAdmission as o, createOpenClawCodingToolsInternal as r, applyDelegationCapability as s, createOpenClawCodingTools as t };