From fb9030ff67c66cc8ce8bb82892e6fc0dc3932729 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 3 May 2026 17:05:06 +0100 Subject: [PATCH] fix: honor wildcard tool denylists in factory planning (#76773) (thanks @dorukardahan) --- CHANGELOG.md | 2 +- .../openclaw-tools.media-factory-plan.test.ts | 39 +++++++++++++++++++ src/agents/openclaw-tools.ts | 26 +++---------- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b8c5ff6c8c..328bdab7a21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ Docs: https://docs.openclaw.ai ### Changes -- Agents/tools: skip optional media and PDF tool factories when the effective tool denylist already blocks them, avoiding unnecessary hot-path setup for tools that will be filtered out before model use. +- Agents/tools: skip optional media and PDF tool factories when the effective tool denylist already blocks them, avoiding unnecessary hot-path setup for tools that will be filtered out before model use. (#76773) Thanks @dorukardahan. - Gateway/performance: lazy-load early runtime discovery and shutdown-hook helpers, defer maintenance timers until after readiness, and trim duplicate plugin auto-enable work during Gateway startup. - QA/Mantis: add a `pnpm openclaw qa mantis discord-smoke` runner and manual GitHub workflow that verify the Mantis Discord bot can see the configured guild/channel, post a smoke message, add a reaction, and upload artifacts. - Gateway/performance: lazy-load the heavy cron runtime after the rest of Gateway startup, defer restart-sentinel refresh after readiness, and let the Gateway startup benchmark write per-run V8 CPU profiles with `--cpu-prof-dir`. diff --git a/src/agents/openclaw-tools.media-factory-plan.test.ts b/src/agents/openclaw-tools.media-factory-plan.test.ts index ad2916343f7..c70b79d93dc 100644 --- a/src/agents/openclaw-tools.media-factory-plan.test.ts +++ b/src/agents/openclaw-tools.media-factory-plan.test.ts @@ -276,6 +276,45 @@ describe("optional media tool factory planning", () => { }); }); + it("applies wildcard deny patterns to optional factory planning", () => { + const config: OpenClawConfig = {}; + installSnapshot(config, [ + createPlugin({ + id: "image-owner", + contracts: { imageGenerationProviders: ["image-owner"] }, + setupProviders: [{ id: "image-owner", envVars: ["IMAGE_OWNER_API_KEY"] }], + }), + createPlugin({ + id: "video-owner", + contracts: { videoGenerationProviders: ["video-owner"] }, + setupProviders: [{ id: "video-owner", envVars: ["VIDEO_OWNER_API_KEY"] }], + }), + createPlugin({ + id: "music-owner", + contracts: { musicGenerationProviders: ["music-owner"] }, + setupProviders: [{ id: "music-owner", envVars: ["MUSIC_OWNER_API_KEY"] }], + }), + createPlugin({ + id: "media-owner", + contracts: { mediaUnderstandingProviders: ["anthropic"] }, + setupProviders: [{ id: "anthropic", envVars: ["ANTHROPIC_API_KEY"] }], + }), + ]); + + expect( + __testing.resolveOptionalMediaToolFactoryPlan({ + config, + authStore: createAuthStore(["image-owner", "video-owner", "music-owner", "anthropic"]), + toolDenylist: ["*_generate", "p*"], + }), + ).toEqual({ + imageGenerate: false, + videoGenerate: false, + musicGenerate: false, + pdf: false, + }); + }); + it("keeps auth-backed providers on the factory path", () => { const config: OpenClawConfig = {}; installSnapshot(config, [ diff --git a/src/agents/openclaw-tools.ts b/src/agents/openclaw-tools.ts index 675d45c1423..ffa2adcacde 100644 --- a/src/agents/openclaw-tools.ts +++ b/src/agents/openclaw-tools.ts @@ -22,7 +22,7 @@ import { import type { SandboxFsBridge } from "./sandbox/fs-bridge.js"; import type { SpawnedToolContext } from "./spawned-context.js"; import type { ToolFsPolicy } from "./tool-fs-policy.js"; -import { expandToolGroups, normalizeToolName } from "./tool-policy.js"; +import { isToolAllowedByPolicyName } from "./tool-policy-match.js"; import { createAgentsListTool } from "./tools/agents-list-tool.js"; import { createCanvasTool } from "./tools/canvas-tool.js"; import type { AnyAgentTool } from "./tools/common.js"; @@ -83,31 +83,15 @@ function hasExplicitImageModelConfig(config: OpenClawConfig | undefined): boolea return hasToolModelConfig(coerceImageModelConfig(config)); } -function isToolAllowedByFactoryAllowlist(toolName: string, allowlist?: string[]): boolean { - if (!allowlist || allowlist.length === 0) { - return true; - } - const expanded = new Set(expandToolGroups(allowlist)); - return expanded.has("*") || expanded.has(normalizeToolName(toolName)); -} - -function isToolDeniedByFactoryDenylist(toolName: string, denylist?: string[]): boolean { - if (!denylist || denylist.length === 0) { - return false; - } - const expanded = new Set(expandToolGroups(denylist)); - return expanded.has("*") || expanded.has(normalizeToolName(toolName)); -} - function isToolAllowedByFactoryPolicy(params: { toolName: string; allowlist?: string[]; denylist?: string[]; }): boolean { - if (isToolDeniedByFactoryDenylist(params.toolName, params.denylist)) { - return false; - } - return isToolAllowedByFactoryAllowlist(params.toolName, params.allowlist); + return isToolAllowedByPolicyName(params.toolName, { + allow: params.allowlist, + deny: params.denylist, + }); } function resolveImageToolFactoryAvailable(params: {