fix(gateway): refresh cached agents after MCP tool changes

This commit is contained in:
helix4u 2026-04-29 20:52:55 -06:00 committed by Teknium
parent a7fb79efb2
commit 7fae87bc00
2 changed files with 43 additions and 4 deletions

View File

@ -9404,11 +9404,17 @@ class GatewayRunner:
@classmethod
def _extract_cache_busting_config(cls, user_config: dict | None) -> dict:
"""Pull the subset of config values that must bust the agent cache.
"""Pull values that must bust the cached agent.
Returns a flat dict keyed by 'section.key'. Missing keys and
non-dict sections yield None values, which still contribute to
the signature (so 'absent' vs 'present-and-null' differ).
Returns a flat dict keyed by 'section.key'. Missing config keys and
non-dict sections yield None values, which still contribute to the
signature (so 'absent' vs 'present-and-null' differ).
The live tool registry generation is included too. MCP reloads and
dynamic MCP tool-list changes mutate the registry without necessarily
changing config.yaml. Cached AIAgent instances freeze their tool
schemas at construction time, so a registry generation change must
rebuild the agent before the next turn.
"""
out: Dict[str, Any] = {}
cfg = user_config if isinstance(user_config, dict) else {}
@ -9418,6 +9424,12 @@ class GatewayRunner:
out[f"{section}.{key}"] = section_val.get(key)
else:
out[f"{section}.{key}"] = None
try:
from tools.registry import registry
out["tools.registry_generation"] = getattr(registry, "_generation", None)
except Exception:
out["tools.registry_generation"] = None
return out
@staticmethod

View File

@ -170,6 +170,22 @@ class TestAgentConfigSignature:
)
assert sig_a == sig_b
def test_tool_registry_generation_change_busts_cache(self):
"""MCP reloads mutate the tool registry, so cached agents must rebuild."""
from gateway.run import GatewayRunner
runtime = {"api_key": "k", "base_url": "u", "provider": "p"}
sig_before = GatewayRunner._agent_config_signature(
"m", runtime, ["telegram"], "",
cache_keys={"tools.registry_generation": 10},
)
sig_after = GatewayRunner._agent_config_signature(
"m", runtime, ["telegram"], "",
cache_keys={"tools.registry_generation": 11},
)
assert sig_before != sig_after
class TestExtractCacheBustingConfig:
"""Verify _extract_cache_busting_config pulls the documented subset of
@ -229,6 +245,17 @@ class TestExtractCacheBustingConfig:
out = GatewayRunner._extract_cache_busting_config(None)
for section, key in GatewayRunner._CACHE_BUSTING_CONFIG_KEYS:
assert out[f"{section}.{key}"] is None
assert "tools.registry_generation" in out
def test_extract_includes_live_tool_registry_generation(self, monkeypatch):
from gateway.run import GatewayRunner
from tools.registry import registry
monkeypatch.setattr(registry, "_generation", 12345)
out = GatewayRunner._extract_cache_busting_config({})
assert out["tools.registry_generation"] == 12345
def test_full_round_trip_busts_cache_on_real_edit(self):
"""End-to-end: simulate a config edit on main and verify the