Skip to content

feat: add tool allowlist, denylist, preset list#83

Merged
JackChen-me merged 4 commits into
open-multi-agent:mainfrom
ibrahimkzmv:feat.add-tool-denylist
Apr 7, 2026
Merged

feat: add tool allowlist, denylist, preset list#83
JackChen-me merged 4 commits into
open-multi-agent:mainfrom
ibrahimkzmv:feat.add-tool-denylist

Conversation

@ibrahimkzmv

Copy link
Copy Markdown
Member

What

Adds denylist support (disallowedTools) and predefined tool presets (toolPreset) to AgentConfig, and introduces a layered tool resolution system (preset → allowlist → denylist) with validation warnings.

Why

The current default-allow model is too permissive and lacks flexibility. Agents cannot explicitly exclude tools, must manually define full allowlists, and have no built-in safety constraints.

Closes #74

Checklist

  • npm run lint passes
  • npm test passes
  • Added/updated tests for changed behavior
  • No new runtime dependencies (or justified in the PR description)

@JackChen-me

Copy link
Copy Markdown
Member

Looks good overall, the three-layer resolution logic is clean. One thing missing before merge:

Custom tools aren't exempted from filtering. Issue spec says "Custom tools always included regardless of filtering" and the README claims addTool() bypasses filtering, but resolveTools() filters everything uniformly. Need to track which tools were added at runtime and append them after filtering, similar to the pseudocode in #74:

const customTools = this.options.customTools ?? []
return [...tools, ...customTools.map(t => t.toDefinition())]

The ToolRegistry doesn't distinguish built-in vs runtime-added tools right now, so that'll need a small change too (e.g. a Set<string> tracking runtime additions).

Minor:

  • Warning only reports the first overlapping tool, should report all
  • Missing newline at end of test file

@ibrahimkzmv

ibrahimkzmv commented Apr 7, 2026

Copy link
Copy Markdown
Member Author

@JackChen-me I've just addressed the issues you mentioned. Thanks for the review.

Btw, I slightly updated resolveTools in the latest commit. However, even before that, it was already exempting custom tools by appending them at the end.

@JackChen-me
JackChen-me merged commit 97c39b3 into open-multi-agent:main Apr 7, 2026
3 checks passed
JackChen-me added a commit that referenced this pull request Jun 7, 2026
A no-tools agent received every registered built-in, including an unsandboxed
bash, on the default path (runAgent, runTeam/runTasks, and the runTeam
short-circuit). Tool output flows back to the model provider, so under prompt
injection this was a remotely triggerable exec + exfiltration primitive. #83
added the allowlist/preset mechanism but kept default-allow; #264 sandboxed the
filesystem tools but left bash unsandboxed; together they opened this.

Built-in tools now require a positive grant via tools or toolPreset; with
neither, an agent resolves to zero. resolveTools() is the chokepoint and the
runner gates execution on the granted set, so a registered-but-ungranted call
returns a "not granted" error instead of running. Custom/runtime tools
(customTools/addTool) stay available since registration is the grant, and still
honor disallowedTools. delegate_to_agent follows the same rule. Same default-deny
model #87 enforces for cross-agent context.

OrchestratorConfig.defaultToolPreset restores the old allow-all in one line;
per-agent tools/toolPreset override it.

BREAKING CHANGE: agents relying on implicit built-in tools get none until
granted. Restore with defaultToolPreset: 'full', or grant per agent via
tools/toolPreset.
JackChen-me added a commit that referenced this pull request Jun 7, 2026
* fix(tools)!: make built-in tools opt-in (default-deny)

A no-tools agent received every registered built-in, including an unsandboxed
bash, on the default path (runAgent, runTeam/runTasks, and the runTeam
short-circuit). Tool output flows back to the model provider, so under prompt
injection this was a remotely triggerable exec + exfiltration primitive. #83
added the allowlist/preset mechanism but kept default-allow; #264 sandboxed the
filesystem tools but left bash unsandboxed; together they opened this.

Built-in tools now require a positive grant via tools or toolPreset; with
neither, an agent resolves to zero. resolveTools() is the chokepoint and the
runner gates execution on the granted set, so a registered-but-ungranted call
returns a "not granted" error instead of running. Custom/runtime tools
(customTools/addTool) stay available since registration is the grant, and still
honor disallowedTools. delegate_to_agent follows the same rule. Same default-deny
model #87 enforces for cross-agent context.

OrchestratorConfig.defaultToolPreset restores the old allow-all in one line;
per-agent tools/toolPreset override it.

BREAKING CHANGE: agents relying on implicit built-in tools get none until
granted. Restore with defaultToolPreset: 'full', or grant per agent via
tools/toolPreset.

* docs: clarify defaultToolPreset excludes coordinator, synthesis, and consensus agents
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P1] Tool Denylist and Role-Based Presets -- three-layer tool scoping

2 participants