fix(acp): preserve memory provider tools

This commit is contained in:
helix4u
2026-06-13 04:51:44 -07:00
committed by Teknium
parent 2a5dc0ef3d
commit 2d474e39c7
5 changed files with 122 additions and 61 deletions
+21 -2
View File
@@ -1797,6 +1797,11 @@ class TestRegisterSessionMcpServers:
state.agent.tools = []
state.agent.valid_tool_names = set()
state.agent._cached_system_prompt = "old prompt"
state.agent._memory_manager = SimpleNamespace(
get_all_tool_schemas=lambda: [
{"name": "hindsight_recall", "description": "Recall", "parameters": {}}
]
)
server = McpServerStdio(
name="srv",
@@ -1807,6 +1812,7 @@ class TestRegisterSessionMcpServers:
fake_tools = [
{"function": {"name": "mcp_srv_search"}},
{"function": {"name": "memory"}},
{"function": {"name": "terminal"}},
]
@@ -1820,8 +1826,21 @@ class TestRegisterSessionMcpServers:
quiet_mode=True,
)
assert state.agent.enabled_toolsets == ["hermes-acp", "mcp-srv"]
assert state.agent.tools == fake_tools
assert state.agent.valid_tool_names == {"mcp_srv_search", "terminal"}
assert state.agent.tools is fake_tools
assert state.agent.tools[-1] == {
"type": "function",
"function": {
"name": "hindsight_recall",
"description": "Recall",
"parameters": {},
},
}
assert state.agent.valid_tool_names == {
"hindsight_recall",
"memory",
"mcp_srv_search",
"terminal",
}
# _invalidate_system_prompt should have been called
state.agent._invalidate_system_prompt.assert_called_once()
+22 -27
View File
@@ -2,10 +2,11 @@
import json
import pytest
from types import SimpleNamespace
from unittest.mock import MagicMock
from agent.memory_provider import MemoryProvider
from agent.memory_manager import MemoryManager
from agent.memory_manager import MemoryManager, inject_memory_provider_tools
# ---------------------------------------------------------------------------
# Concrete test provider
@@ -1320,38 +1321,25 @@ class TestMemoryToolToolsetGate:
causing 10x latency on local models (Qwen3-30B: 1.7s → 42s) and
tool-call loops on small models.
These tests mirror the gate logic in agent/agent_init.py around the
memory provider tool injection block. The gate condition is:
These tests exercise the shared gate used by agent init and ACP refreshes.
The gate condition is:
enabled_toolsets is None → no filter, inject (backward compat)
"memory" in enabled_toolsets → user opted in, inject
selected toolsets include memory → user opted in, inject
otherwise (incl. []) → skip injection
"""
@staticmethod
def _run_memory_injection(enabled_toolsets, memory_manager):
"""Simulate the gated memory-tool injection block from agent_init.py."""
tools = []
valid_tool_names = set()
if memory_manager and tools is not None and (
enabled_toolsets is None or "memory" in enabled_toolsets
):
_existing = {
t.get("function", {}).get("name")
for t in tools
if isinstance(t, dict)
}
for _schema in memory_manager.get_all_tool_schemas():
_tname = _schema.get("name", "")
if _tname and _tname in _existing:
continue
tools.append({"type": "function", "function": _schema})
if _tname:
valid_tool_names.add(_tname)
_existing.add(_tname)
return tools, valid_tool_names
"""Run the shared memory-tool injection helper against a fake agent."""
fake_agent = SimpleNamespace(
_memory_manager=memory_manager,
enabled_toolsets=enabled_toolsets,
tools=[],
valid_tool_names=set(),
)
inject_memory_provider_tools(fake_agent)
return fake_agent.tools, fake_agent.valid_tool_names
def _mgr_with_tools(self, *tool_names):
"""Build a MemoryManager whose providers expose the named tool schemas."""
@@ -1376,6 +1364,13 @@ class TestMemoryToolToolsetGate:
tools, names = self._run_memory_injection(["terminal", "memory", "web"], mgr)
assert "fact_store" in names
def test_composite_toolset_with_memory_injects(self):
"""Composite toolsets that include memory should inject provider tools."""
mgr = self._mgr_with_tools("hindsight_recall")
tools, names = self._run_memory_injection(["hermes-acp"], mgr)
assert "hindsight_recall" in names
assert any(t["function"]["name"] == "hindsight_recall" for t in tools)
def test_empty_toolsets_blocks_injection(self):
"""`platform_toolsets: telegram: []` must suppress memory tools. (#5544)"""
mgr = self._mgr_with_tools("fact_store")
@@ -1384,7 +1379,7 @@ class TestMemoryToolToolsetGate:
assert names == set()
def test_toolsets_without_memory_blocks_injection(self):
"""Toolset list that doesn't name 'memory' must suppress injection."""
"""Toolsets that don't include memory must suppress injection."""
mgr = self._mgr_with_tools("fact_store")
tools, names = self._run_memory_injection(["terminal", "web"], mgr)
assert tools == []