From 36f8a8603d95d2447456b90c851d073888137e47 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 4 May 2026 02:47:26 +0100 Subject: [PATCH] fix(agents): gate optional media factories by tool policy --- CHANGELOG.md | 1 + .../openclaw-tools.media-factory-plan.test.ts | 18 +++++++++++++++ src/agents/openclaw-tools.ts | 23 ++++++++++++------- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ed90d5b7c1..6f5d5996d83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Docs: https://docs.openclaw.ai - Release validation: let Windows packaged-upgrade checks continue after the shipped 2026.5.2 updater hits its native-module swap cleanup fallback, verifying the fallback-installed candidate through package metadata and downstream smoke instead of crashing on the immediate update-status probe. Thanks @vincentkoc. - Doctor/plugins: skip channel-derived official plugin installs when another configured plugin is the effective owner for the same channel, so `doctor --repair` does not reinstall `feishu` while `openclaw-lark` handles `channels.feishu`. Fixes #76623. Thanks @fuyizheng3120. - Agents/tools: use config-only runtime snapshots for plugin tool registration and live runtime config getters, avoiding expensive full secrets snapshot clones on the core-plugin-tools prep path. Fixes #76295. +- Agents/tools: honor the effective tool denylist before constructing optional PDF/media tool factories, so `tools.deny: ["pdf"]` skips PDF setup before later policy filtering. Fixes #76997. - Agents/bootstrap: keep pending `BOOTSTRAP.md` and bootstrap truncation notices in system-prompt Project Context instead of copying setup text or raw warning diagnostics into WebChat user/runtime context. Fixes #76946. - Channels/WhatsApp: allow `@whiskeysockets/libsignal-node` in `onlyBuiltDependencies` so pnpm v9+ `blockExoticSubdeps` no longer rejects the baileys git-tarball subdep and silences all inbound agent replies. Fixes #76539. Thanks @ottodeng and @vincentkoc. - Gateway/install: keep `.env`-managed values in the macOS LaunchAgent env file while still tracking `OPENCLAW_SERVICE_MANAGED_ENV_KEYS`, so regenerated services do not boot without managed auth/provider keys. Fixes #75374. diff --git a/src/agents/openclaw-tools.media-factory-plan.test.ts b/src/agents/openclaw-tools.media-factory-plan.test.ts index c70b79d93dc..db3a9c61cf1 100644 --- a/src/agents/openclaw-tools.media-factory-plan.test.ts +++ b/src/agents/openclaw-tools.media-factory-plan.test.ts @@ -276,6 +276,24 @@ describe("optional media tool factory planning", () => { }); }); + it("applies global tool policy before optional media factories run", () => { + const config: OpenClawConfig = { tools: { deny: ["pdf"] } }; + installSnapshot(config, [ + createPlugin({ + id: "media-owner", + contracts: { mediaUnderstandingProviders: ["anthropic"] }, + setupProviders: [{ id: "anthropic", envVars: ["ANTHROPIC_API_KEY"] }], + }), + ]); + + expect( + __testing.resolveOptionalMediaToolFactoryPlan({ + config, + authStore: createAuthStore(["anthropic"]), + }).pdf, + ).toBe(false); + }); + it("applies wildcard deny patterns to optional factory planning", () => { const config: OpenClawConfig = {}; installSnapshot(config, [ diff --git a/src/agents/openclaw-tools.ts b/src/agents/openclaw-tools.ts index ffa2adcacde..f7f20194cd1 100644 --- a/src/agents/openclaw-tools.ts +++ b/src/agents/openclaw-tools.ts @@ -94,6 +94,11 @@ function isToolAllowedByFactoryPolicy(params: { }); } +function mergeFactoryPolicyList(...lists: Array): string[] | undefined { + const merged = lists.flatMap((list) => (Array.isArray(list) ? list : [])); + return merged.length > 0 ? Array.from(new Set(merged)) : undefined; +} + function resolveImageToolFactoryAvailable(params: { config?: OpenClawConfig; agentDir?: string; @@ -165,25 +170,27 @@ function resolveOptionalMediaToolFactoryPlan(params: { toolDenylist?: string[]; }): OptionalMediaToolFactoryPlan { const defaults = params.config?.agents?.defaults; + const toolAllowlist = mergeFactoryPolicyList(params.config?.tools?.allow, params.toolAllowlist); + const toolDenylist = mergeFactoryPolicyList(params.config?.tools?.deny, params.toolDenylist); const allowImageGenerate = isToolAllowedByFactoryPolicy({ toolName: "image_generate", - allowlist: params.toolAllowlist, - denylist: params.toolDenylist, + allowlist: toolAllowlist, + denylist: toolDenylist, }); const allowVideoGenerate = isToolAllowedByFactoryPolicy({ toolName: "video_generate", - allowlist: params.toolAllowlist, - denylist: params.toolDenylist, + allowlist: toolAllowlist, + denylist: toolDenylist, }); const allowMusicGenerate = isToolAllowedByFactoryPolicy({ toolName: "music_generate", - allowlist: params.toolAllowlist, - denylist: params.toolDenylist, + allowlist: toolAllowlist, + denylist: toolDenylist, }); const allowPdf = isToolAllowedByFactoryPolicy({ toolName: "pdf", - allowlist: params.toolAllowlist, - denylist: params.toolDenylist, + allowlist: toolAllowlist, + denylist: toolDenylist, }); const explicitImageGeneration = hasExplicitToolModelConfig(defaults?.imageGenerationModel); const explicitVideoGeneration = hasExplicitToolModelConfig(defaults?.videoGenerationModel);