From 93795db09ffc0251a0574675a0097c60cdf2dbfa Mon Sep 17 00:00:00 2001 From: JackChen Date: Wed, 15 Apr 2026 15:11:12 +0800 Subject: [PATCH] fix: apply disallowedTools filtering to runtime-added custom tools Previously runtime-added tools bypassed all filtering including disallowedTools, contradicting the documented behavior. Now custom tools still bypass preset/allowlist but respect the denylist. --- src/agent/runner.ts | 13 +++++++++---- tests/tool-filtering.test.ts | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/agent/runner.ts b/src/agent/runner.ts index d1a1ebb..df1cbc0 100644 --- a/src/agent/runner.ts +++ b/src/agent/runner.ts @@ -448,8 +448,10 @@ export class AgentRunner { } // 3. Apply denylist filter if set - if (this.options.disallowedTools) { - const denied = new Set(this.options.disallowedTools) + const denied = this.options.disallowedTools + ? new Set(this.options.disallowedTools) + : undefined + if (denied) { filteredTools = filteredTools.filter(t => !denied.has(t.name)) } @@ -457,8 +459,11 @@ export class AgentRunner { const frameworkDenied = new Set(AGENT_FRAMEWORK_DISALLOWED) filteredTools = filteredTools.filter(t => !frameworkDenied.has(t.name)) - // Runtime-added custom tools stay available regardless of filtering rules. - return [...filteredTools, ...runtimeCustomTools] + // Runtime-added custom tools bypass preset / allowlist but respect denylist. + const finalRuntime = denied + ? runtimeCustomTools.filter(t => !denied.has(t.name)) + : runtimeCustomTools + return [...filteredTools, ...finalRuntime] } // ------------------------------------------------------------------------- diff --git a/tests/tool-filtering.test.ts b/tests/tool-filtering.test.ts index f42b8e1..418e702 100644 --- a/tests/tool-filtering.test.ts +++ b/tests/tool-filtering.test.ts @@ -216,8 +216,8 @@ describe('Tool filtering', () => { const tools = (runner as any).resolveTools() as LLMToolDef[] const toolNames = tools.map((t: LLMToolDef) => t.name).sort() + // custom_tool is runtime-added but disallowedTools still blocks it expect(toolNames).toEqual([ - 'custom_tool', 'file_edit', 'file_read', 'file_write', @@ -286,7 +286,7 @@ describe('Tool filtering', () => { expect(toolNames).toEqual(['custom_tool']) }) - it('runtime-added tools bypass filtering regardless of tool name', () => { + it('runtime-added tools are blocked by disallowedTools', () => { const runtimeBuiltinNamedRegistry = new ToolRegistry() runtimeBuiltinNamedRegistry.register(defineTool({ name: 'file_read', @@ -306,7 +306,7 @@ describe('Tool filtering', () => { ) const tools = (runtimeBuiltinNamedRunner as any).resolveTools() as LLMToolDef[] - expect(tools.map(t => t.name)).toEqual(['file_read']) + expect(tools.map(t => t.name)).toEqual([]) }) })