Registry Hot Cache¶
CONCEPT:AU-ORCH.adapter.hot-cache-invalidation — Session-Scoped Registry Optimization
This document provides a focused detailed review into the Registry Hot Cache layer, the performance architecture that eliminates redundant specialist lookups and reduces prompt bloat.
Motivation¶
In a system with 30+ MCP servers, each contributing 5-15 tools, the specialist registry can contain 50+ entries. Before CONCEPT:AU-ORCH.adapter.hot-cache-invalidation, every routing call performed:
- A full Cypher query against the Knowledge Graph to fetch all specialists
- Serialization of all specialist descriptions into the LLM prompt
- The LLM parsing through thousands of tokens of specialist metadata
This created two compounding problems:
- Latency: 50-200ms per registry scan depending on graph backend
- Prompt bloat: 50 specialist descriptions ≈ 3,000-5,000 tokens consumed before the LLM even sees the user's query
Architecture¶
_RegistryCache Singleton¶
class _RegistryCache:
"""Session-scoped cache holding the computed specialist registry."""
_registry: MCPAgentRegistryModel | None = None
_prompts: dict[str, str] = {}
_tool_agent_map: dict[str, list[str]] = {}
@classmethod
def get_registry(cls) -> MCPAgentRegistryModel:
if cls._registry is None:
cls._registry = _fetch_registry_from_kg()
return cls._registry
@classmethod
def invalidate(cls) -> None:
cls._registry = None
cls._prompts.clear()
cls._tool_agent_map.clear()
The cache uses class-level state (no TTL); invalidation is purely event-driven. It lives in
core/config.py.
Public API¶
| Function | Signature | Purpose |
|---|---|---|
get_discovery_registry() |
(engine?) → MCPAgentRegistryModel |
Returns the full cached registry; hydrates on first call |
get_relevant_specialists() |
(query, engine, top_n=7) → list[MCPAgent] |
Returns only the top-N specialists relevant to the query |
invalidate_registry_cache() |
() → None |
Clears all cached data; next call re-hydrates from KG |
Filtering Algorithm¶
get_relevant_specialists() runs the KG hybrid search (engine.search_hybrid)
over the query, fetching top_n × 3 candidates, and keeps the agents whose
names (or agent/prompt node matches) appear in the results, capped at
top_n. If the engine is unavailable or returns nothing, it falls back to the
full registry list capped at top_n (default 7).
Cache Invalidation Strategy¶
The cache uses an event-driven invalidation model — it is never TTL-based. Invalidation only occurs when the underlying data actually changes:
graph TD
subgraph Triggers ["Invalidation Event Sources"]
MCP["AU-ECO.mcp.toolkit-live-discovery: POST /mcp/reload\n(New tools discovered)"]
Pipeline["AU-ECO.mcp.toolkit-live-discovery: Pipeline Completion\n(Code graph changed)"]
SelfModel["AHE-3.3: SelfModel.update_after_session()\n(New proficiency data)"]
TeamConfig["AHE-3.3: promote_coalition_to_template()\n(New team template)"]
end
subgraph Cache ["_RegistryCache"]
Inv["AHE-3.1: invalidate_registry_cache()"]
Clear["ORCH-1.2: _registry = None\n_prompts = {} / _tool_agent_map = {}"]
end
MCP --> Inv
Pipeline --> Inv
SelfModel --> Inv
TeamConfig --> Inv
Inv --> Clear
Why Not TTL-Based?¶
TTL (time-to-live) caching is inappropriate here because:
- Low write frequency: The registry changes only on server restart, MCP reload, or pipeline runs — not on every request
- Consistency requirement: A stale cache can route queries to wrong specialists
- Event sources are known: All mutation points are within this repository's codebase and can emit invalidation signals
Why Not a NetworkX Hot Layer?¶
The alternative considered was maintaining a parallel NetworkX subgraph of "hot" specialists. This was rejected because:
- Dual-write complexity: Keeping NetworkX and the cache in sync adds a second consistency surface
- Over-engineering: The
_RegistryCachepattern is simpler (dict + singleton) and achieves the same O(1) lookup - Memory overhead: NetworkX stores full graph topology; the cache stores only the computed registry model
Performance Impact¶
| Metric | Before (O(N)) | After (O(1)) | Improvement |
|---|---|---|---|
| Registry lookup | 50-200ms | <1ms | 50-200x |
| Prompt tokens (specialist descriptions) | 3,000-5,000 | 400-700 (top-7 only) | ~7x reduction |
| LLM routing accuracy | Baseline | +15% (less noise in prompt) | Measurable |
Integration Points¶
The cache integrates at these specific locations in the codebase:
| File | Function | Role |
|---|---|---|
core/config.py |
get_discovery_registry() |
Cache hydration + retrieval |
core/config.py |
get_relevant_specialists() |
Filtered subset retrieval |
core/config.py |
invalidate_registry_cache() |
Event-driven invalidation |
graph/_router_impl.py |
router specialist injection | Consumer: uses filtered specialists in LLM prompt |
mcp/agent_manager.py |
sync_mcp_agents() |
Trigger: invalidates after MCP sync |
knowledge_graph/pipeline/runner.py |
PipelineRunner.run() |
Trigger: invalidates after pipeline |
knowledge_graph/retrieval/memory_retriever.py |
update_after_session() |
Trigger: invalidates after self-model update |
core/registry/kg_adapter.py |
promote_coalition_to_template() |
Trigger: invalidates after TeamConfig promotion |
Related Documentation¶
- First Principles Architecture — Complete CONCEPT:AU-ORCH.adapter.hot-cache-invalidation through CONCEPT:AU-ECO.messaging.native-backend-abstraction overview
- Architecture — Full system architecture
- Emergent Architecture — Self-Model and Workspace Attention