fix(memory): honor disabled toolsets for provider tools

This commit is contained in:
flyingdoubleg 2026-07-13 20:15:49 +08:00 committed by kshitij
parent 8fdc9c58e0
commit e9a7c18890
5 changed files with 62 additions and 7 deletions

View file

@ -80,8 +80,17 @@ def normalize_tool_schema(schema: Any) -> Optional[Dict[str, Any]]:
return schema
def memory_provider_tools_enabled(enabled_toolsets: Optional[List[str]]) -> bool:
def memory_provider_tools_enabled(
enabled_toolsets: Optional[List[str]],
disabled_toolsets: Optional[List[str]] = None,
*,
memory_tool_present: bool = False,
) -> bool:
"""Return whether external memory-provider tools should be exposed."""
if disabled_toolsets and "memory" in disabled_toolsets:
return False
if memory_tool_present:
return True
if enabled_toolsets is None:
return True
if not enabled_toolsets:
@ -110,9 +119,10 @@ def inject_memory_provider_tools(agent: Any) -> int:
for tool in tools
if isinstance(tool, dict)
}
if (
"memory" not in existing_tool_names
and not memory_provider_tools_enabled(getattr(agent, "enabled_toolsets", None))
if not memory_provider_tools_enabled(
getattr(agent, "enabled_toolsets", None),
getattr(agent, "disabled_toolsets", None),
memory_tool_present="memory" in existing_tool_names,
):
return 0

View file

@ -81,6 +81,7 @@ LEGACY_AUTHOR_MAP = {
"marceloparra.hm@gmail.com": "marcelohildebrand", # PR #42346 salvage (lmstudio: JIT load mode)
"qlskssk@gmail.com": "Soju06", # agent turn-latency perf PRs
"m.guttmann@journaway.com": "mguttmann", # PR #63738 salvage (Anthropic setup-token pool auth normalization)
"wangzhe00zju@gmail.com": "flyingdoubleG", # PR #18166 salvage (memory-provider tools honor disabled_toolsets in initial and MCP-refresh injection)
"VrtxOmega@pm.me": "VrtxOmega", # PR #43809 salvage (desktop: WSL folder-picker path bridge)
"gn00742754@gmail.com": "SemonCat", # PR #56786 salvage (Slack Agent View manifests and Assistant APIs)
"KCAYAAI@users.noreply.github.com": "KCAYAAI", # PR #62248 partial salvage (resume typing after clarify reply)

View file

@ -1379,17 +1379,19 @@ class TestMemoryToolToolsetGate:
These tests exercise the shared gate used by agent init and ACP refreshes.
The gate condition is:
disabled_toolsets includes memory skip injection
enabled_toolsets is None no filter, inject (backward compat)
selected toolsets include memory user opted in, inject
otherwise (incl. []) skip injection
"""
@staticmethod
def _run_memory_injection(enabled_toolsets, memory_manager):
def _run_memory_injection(enabled_toolsets, memory_manager, disabled_toolsets=None):
"""Run the shared memory-tool injection helper against a fake agent."""
fake_agent = SimpleNamespace(
_memory_manager=memory_manager,
enabled_toolsets=enabled_toolsets,
disabled_toolsets=disabled_toolsets,
tools=[],
valid_tool_names=set(),
)
@ -1426,6 +1428,18 @@ class TestMemoryToolToolsetGate:
assert "hindsight_recall" in names
assert any(t["function"]["name"] == "hindsight_recall" for t in tools)
@pytest.mark.parametrize("enabled_toolsets", [None, ["memory"], ["all"], ["hermes-acp"]])
def test_disabled_memory_toolset_blocks_injection(self, enabled_toolsets):
"""An explicit memory disable wins over default or composite enablement."""
mgr = self._mgr_with_tools("hindsight_recall")
tools, names = self._run_memory_injection(
enabled_toolsets,
mgr,
disabled_toolsets=["memory"],
)
assert tools == []
assert names == set()
def test_empty_toolsets_blocks_injection(self):
"""`platform_toolsets: telegram: []` must suppress memory tools. (#5544)"""
mgr = self._mgr_with_tools("fact_store")

View file

@ -140,6 +140,32 @@ def test_refresh_preserves_memory_provider_and_context_engine_tools(monkeypatch)
assert added == {"mcp_new_server_tool"}
def test_refresh_does_not_reinject_disabled_memory_provider_tools(monkeypatch):
"""A refresh removes stale provider tools when memory becomes disabled."""
agent = _agent(
["read_file", "memory_search"],
enabled=["all"],
disabled=["memory"],
)
agent._memory_manager = types.SimpleNamespace(
get_all_tool_schemas=lambda: [
{"name": "memory_search", "description": "", "parameters": {}}
]
)
import model_tools
monkeypatch.setattr(
model_tools,
"get_tool_definitions",
lambda **kw: [_tool("read_file")],
)
mcp_tool.refresh_agent_mcp_tools(agent)
assert "memory_search" not in agent.valid_tool_names
assert all(t["function"]["name"] != "memory_search" for t in agent.tools)
def test_refresh_respects_context_engine_toolset_gate(monkeypatch):
"""#5544: context-engine tools must NOT be re-injected on a restricted
toolset. A platform with enabled_toolsets that excludes context_engine

View file

@ -6134,9 +6134,13 @@ def _reinject_post_build_tools(agent, tools_list: list, name_set: set) -> set:
memory_manager = getattr(agent, "_memory_manager", None)
get_mem_schemas = getattr(memory_manager, "get_all_tool_schemas", None) if memory_manager else None
if callable(get_mem_schemas):
# Honor the same enablement gate inject_memory_provider_tools uses.
# Honor the same toolset gate inject_memory_provider_tools uses.
from agent.memory_manager import memory_provider_tools_enabled
if "memory" in name_set or memory_provider_tools_enabled(getattr(agent, "enabled_toolsets", None)):
if memory_provider_tools_enabled(
getattr(agent, "enabled_toolsets", None),
getattr(agent, "disabled_toolsets", None),
memory_tool_present="memory" in name_set,
):
for schema in get_mem_schemas():
if isinstance(schema, dict):
_add(schema)