Add agent and skill system: implement Agent and Skill classes, register media and naked agents, and create media_info demo skill
Build and Push Agent API / build (push) Successful in 5s

This commit is contained in:
2026-05-10 19:24:44 +02:00
parent 54ac77ab51
commit cb4ebfa43e
7 changed files with 276 additions and 22 deletions
+64
View File
@@ -0,0 +1,64 @@
"""
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
+19
View File
@@ -0,0 +1,19 @@
"""
media-agent — an agent that knows how to handle media queries
(Jellyfin / Sonarr / Seerr / subtitle requests).
For now it only loads the *media_info* demo skill which teaches it
a structured response format. Later you'll add real API-calling skills.
"""
from agents import Agent, register
media_agent = Agent(
agent_id="media-agent",
description="Media assistant — handles movie/TV/subtitle/ticket requests. "
"Will eventually connect to Seerr, Sonarr, Jellyfin, etc.",
skills=["media_info"],
base_prompt="You are a media assistant. Help users with their media library.",
)
register(media_agent)
+15
View File
@@ -0,0 +1,15 @@
"""
naked agent — a barebone LLM with no extra skills attached.
Just a thin wrapper that instructs the LLM to be a general helpful assistant.
"""
from agents import Agent, register
naked_agent = Agent(
agent_id="naked",
description="A plain LLM — no extra skills, just a helpful assistant.",
skills=[], # no skills
base_prompt="You are a helpful, general-purpose assistant.",
)
register(naked_agent)