""" Agent system — each agent combines a base LLM with optional skills to produce tailored system prompts and behavior. An Agent is a lightweight wrapper: - agent_id : unique name (e.g. "naked", "media-agent") - description : human-readable summary - skills : list of skill names to load - base_prompt : default system prompt (optional — falls back to generic) """ from dataclasses import dataclass, field from typing import Dict, List from skills import Skill, get_combined_prompt, list_all as list_all_skills @dataclass class Agent: agent_id: str description: str = "" skills: List[str] = field(default_factory=list) base_prompt: str = "You are a helpful agent." def build_system_prompt(self) -> str: """Combine base_prompt with all registered skills' prompt fragments.""" return get_combined_prompt(self.skills, base_prompt=self.base_prompt) def __repr__(self) -> str: sk = ", ".join(self.skills) if self.skills else "none" return f"Agent(id={self.agent_id!r}, skills=[{sk}])" # --------------------------------------------------------------------------- # Global agent registry # --------------------------------------------------------------------------- _agent_registry: Dict[str, Agent] = {} def register(agent: Agent) -> None: """Register an agent so it can be looked up by agent_id.""" _agent_registry[agent.agent_id] = agent def get(agent_id: str) -> Agent | None: """Return a registered agent by id, or None.""" return _agent_registry.get(agent_id) def list_all() -> Dict[str, Agent]: """Return a shallow copy of the registry.""" return dict(_agent_registry) def load_all_agents() -> None: """ Import all agent modules so they self-register. Call this once at startup. """ import agents.naked # noqa: F401 import agents.media_agent # noqa: F401 # Also import skill modules so they self-register import skills.media_info # noqa: F401 import skills.seerr # noqa: F401 import skills.triage # noqa: F401 import skills.easter_eggs # noqa: F401 import skills.watch_history # noqa: F401