Each agent now exports a module-level MANIFEST declaring id, version, pref_schema, required_consents, ttl_sec, and silenced_in_contexts. The registry surfaces both the agent and its manifest, and rejects on mismatch so the two cannot drift. ml/serving exposes GET /agents/registry; services/api proxies it as GET /api/agents/registry with a 60s in-process cache so admin pageviews don't hammer upstream. Failures aren't cached. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
59 lines
2.1 KiB
Python
59 lines
2.1 KiB
Python
"""Agent registry — single point of registration for sub-agents (ADR-0014).
|
|
|
|
Each agent module contributes:
|
|
- a `BaseAgent` subclass instance
|
|
- a module-level `MANIFEST: AgentManifest`
|
|
|
|
The orchestrator, registry endpoint, and inference framework all read from
|
|
here. Adding an agent is: add a module, register it once below.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from .base import BaseAgent
|
|
from .manifest import AgentManifest
|
|
from .overdue_task import OverdueTaskAgent, MANIFEST as OVERDUE_TASK_MANIFEST
|
|
from .momentum import MomentumAgent, MANIFEST as MOMENTUM_MANIFEST
|
|
from .time_of_day import TimeOfDayAgent, MANIFEST as TIME_OF_DAY_MANIFEST
|
|
from .recent_patterns import RecentPatternsAgent, MANIFEST as RECENT_PATTERNS_MANIFEST
|
|
from .focus_area import FocusAreaAgent, MANIFEST as FOCUS_AREA_MANIFEST
|
|
|
|
_REGISTERED: list[tuple[BaseAgent, AgentManifest]] = [
|
|
(OverdueTaskAgent(), OVERDUE_TASK_MANIFEST),
|
|
(MomentumAgent(), MOMENTUM_MANIFEST),
|
|
(TimeOfDayAgent(), TIME_OF_DAY_MANIFEST),
|
|
(RecentPatternsAgent(), RECENT_PATTERNS_MANIFEST),
|
|
(FocusAreaAgent(), FOCUS_AREA_MANIFEST),
|
|
]
|
|
|
|
# Sanity check — agent_id and manifest.id must agree, otherwise the registry
|
|
# becomes inconsistent across endpoints.
|
|
for _agent, _manifest in _REGISTERED:
|
|
if _agent.agent_id != _manifest.id:
|
|
raise RuntimeError(
|
|
f"Manifest mismatch: {_agent.__class__.__name__}.agent_id={_agent.agent_id!r} "
|
|
f"≠ MANIFEST.id={_manifest.id!r}"
|
|
)
|
|
|
|
_AGENTS: dict[str, BaseAgent] = {a.agent_id: a for a, _ in _REGISTERED}
|
|
_MANIFESTS: dict[str, AgentManifest] = {m.id: m for _, m in _REGISTERED}
|
|
|
|
|
|
def get_agent(agent_id: str) -> BaseAgent:
|
|
if agent_id not in _AGENTS:
|
|
raise KeyError(f"Unknown agent: {agent_id!r}. Known: {sorted(_AGENTS)}")
|
|
return _AGENTS[agent_id]
|
|
|
|
|
|
def all_agents() -> list[BaseAgent]:
|
|
return list(_AGENTS.values())
|
|
|
|
|
|
def get_manifest(agent_id: str) -> AgentManifest:
|
|
if agent_id not in _MANIFESTS:
|
|
raise KeyError(f"Unknown agent: {agent_id!r}. Known: {sorted(_MANIFESTS)}")
|
|
return _MANIFESTS[agent_id]
|
|
|
|
|
|
def all_manifests() -> list[AgentManifest]:
|
|
return list(_MANIFESTS.values())
|