fix(gateway): refresh cached agents after MCP tool changes
This commit is contained in:
parent
a7fb79efb2
commit
7fae87bc00
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user