fix(tool-subagent): a partial toolFilter must not materialize an empty allow-list

ds-review-bot finding: forcing only the OUTER toolFilter key absent left
the nested arrays materializing — a deny-only config gained allow: [],
which means deny-EVERYTHING. The nested arrays now default to undefined
too; an explicit allow: [] (grant-only children) still survives. Pinned by
a capture-provider regression test.
This commit is contained in:
Tianyi Cui
2026-07-09 04:03:22 +08:00
parent 513ba2716d
commit 9ff8720da5
2 changed files with 33 additions and 2 deletions

View File

@@ -484,4 +484,30 @@ describe('dsh-tool-subagent', () => {
expect(seen?.toolFilter).toMatchObject({ deny: ['subagent'] })
expect(seen?.maxDepth).toBe(2)
})
it('a partial toolFilter (deny only) does not materialize an empty allow-list (deny-all trap)', async () => {
let seen: { toolFilter?: { allow?: string[]; deny?: string[] } } | undefined
const ctx = new Context()
await ctx.plugin(SystemPrompt)
await ctx.plugin(ToolRegistry)
await ctx.plugin(SubagentService)
ctx.subagents.registerProvider({
name: 'capture3',
capabilities: { outputSchema: false, depthLimit: false, toolFilter: true, persona: false },
inheritsParentContext: false,
start: (request) => {
seen = request
return {
id: AgentId('capture3-child'),
result: Promise.resolve({ output: [{ type: 'text', text: 'ok' }], stopReason: 'completed' as const }),
cancel() {},
dispose: async () => {},
}
},
})
await ctx.plugin(tool, { provider: 'capture3', toolFilter: { deny: ['subagent'] } })
await callSubagent(ctx, { description: 'd', prompt: 'p' })
expect(seen?.toolFilter).toEqual({ deny: ['subagent'] })
expect(seen?.toolFilter).not.toHaveProperty('allow')
})
})