Computes natal chart (Sun/Moon/Mercury/Venus/Mars/Jupiter/Saturn) from birth_date and finds active transits (conjunction/sextile/square/trine/ opposition) between today's sky and the user's natal positions. Top 3 most-exact transits are passed to the orchestrator as interpretive themes to colour the tip — grounded and actionable, not predictive. Birth date sourced from agent_prefs (populated by a connected Google data source); requires data:google-health consent. Agent self-silences when birth_date is absent. pyswisseph added to ml/serving/requirements.txt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
65 lines
2.4 KiB
Python
65 lines
2.4 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
|
|
from .health_vitals import HealthVitalsAgent, MANIFEST as HEALTH_VITALS_MANIFEST
|
|
from .tarot import TarotAgent, MANIFEST as TAROT_MANIFEST
|
|
from .stars import StarsAgent, MANIFEST as STARS_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),
|
|
(HealthVitalsAgent(), HEALTH_VITALS_MANIFEST),
|
|
(TarotAgent(), TAROT_MANIFEST),
|
|
(StarsAgent(), STARS_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())
|