fix(acp): pass agent.disabled_toolsets to AIAgent — config-disabled tools stayed executable over ACP

The CLI (cli.py: CLI_CONFIG['agent'].get('disabled_toolsets')) and the
gateway (gateway/run.py) both read agent.disabled_toolsets from config
and pass it to AIAgent. The ACP adapter's _make_agent never did, so
state.agent.disabled_toolsets was always None and the ACP tool-registry
rebuild (acp_adapter/server.py -> get_tool_definitions) included every
tool in the enabled toolsets — a toolset the user disabled in config
(todo, browser, ...) remained fully executable in editor/ACP sessions.

Observed live: a 'todo' tool call executed from a profile whose config
lists todo in agent.disabled_toolsets.

Read agent.disabled_toolsets in _make_agent and pass it through,
mirroring the CLI and gateway paths.

Claude-Session: https://claude.ai/code/session_01YNvCUipheR7yx4VorUL2jW
This commit is contained in:
Tym Rabchuk
2026-07-03 00:24:35 +00:00
committed by Teknium
parent 6d150c7e78
commit 2c12e7ae84
2 changed files with 57 additions and 1 deletions

View File

@@ -463,6 +463,7 @@ class SessionManager:
return self._agent_factory()
from run_agent import AIAgent
from agent.skill_utils import parse_config_string_list
from hermes_cli.config import load_config
from hermes_cli.runtime_provider import resolve_runtime_provider
from hermes_constants import resolve_reasoning_config
@@ -485,7 +486,9 @@ class SessionManager:
"platform": "acp", "quiet_mode": True, "session_id": session_id, "session_db": self._get_db(),
"enabled_toolsets": (list(enabled_toolsets) if enabled_toolsets is not None
else _expand_acp_enabled_toolsets(["hermes-acp"], mcp_server_names=configured_mcp_servers)),
"disabled_toolsets": list(disabled_toolsets) if disabled_toolsets is not None else None,
# agent.disabled_toolsets is subtracted at tool granularity by the agent, as on the CLI/gateway/cron.
"disabled_toolsets": (list(disabled_toolsets) if disabled_toolsets is not None
else parse_config_string_list((config.get("agent") or {}).get("disabled_toolsets")) or None),
"model": model or default_model,
"cwd": cwd,
# Same chokepoint as the CLI/gateway/TUI/cron: without it ``agent.reasoning_effort: none`` never

View File

@@ -190,6 +190,59 @@ class TestCreateSession:
assert seen[0]["credential_pool"] is sentinel_pool
@staticmethod
def _patch_make_agent_env(monkeypatch, config):
class FakeAgent:
model = "fake-model"
def __init__(self, **kwargs):
self.kwargs = kwargs
monkeypatch.setattr("run_agent.AIAgent", FakeAgent)
monkeypatch.setattr("acp_adapter.session.load_config", lambda: config, raising=False)
monkeypatch.setattr("hermes_cli.config.load_config", lambda: config)
monkeypatch.setattr(
"hermes_cli.runtime_provider.resolve_runtime_provider",
lambda requested=None: {
"provider": requested,
"api_mode": "openai_chat",
"base_url": "https://example.invalid",
"api_key": "test-key",
},
)
monkeypatch.setattr("acp_adapter.session._register_task_cwd", lambda task_id, cwd: None)
def test_make_agent_passes_configured_disabled_toolsets(self, monkeypatch):
# The CLI and gateway hand agent.disabled_toolsets to AIAgent, but the
# ACP path dropped it — config-disabled toolsets (e.g. todo) remained
# executable in editor/ACP sessions.
self._patch_make_agent_env(
monkeypatch,
{
"model": {"default": "fake-model", "provider": "fake-provider"},
"mcp_servers": {},
"agent": {"disabled_toolsets": ["todo", "browser"]},
},
)
state = SessionManager(db=None).create_session(cwd="/tmp/project")
assert state.agent.kwargs.get("disabled_toolsets") == ["todo", "browser"]
def test_make_agent_omits_disabled_toolsets_when_none_configured(self, monkeypatch):
self._patch_make_agent_env(
monkeypatch,
{
"model": {"default": "fake-model", "provider": "fake-provider"},
"mcp_servers": {},
"agent": {},
},
)
state = SessionManager(db=None).create_session(cwd="/tmp/project")
assert "disabled_toolsets" not in state.agent.kwargs