89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
"""Kompilacja prymitywów APM do obiektów agno.
|
|
|
|
To jest sedno rozwiązania: definicja agenta (rola, model, narzędzia, skille, schemat wyjścia)
|
|
jest wersjonowanym artefaktem APM, a nie kodem. Zmiana zachowania sieci agentowej
|
|
nie wymaga zmiany Pythona - wymaga podbicia wersji pakietu kontekstowego.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from typing import Any
|
|
|
|
from agno.agent import Agent
|
|
from agno.skills import LocalSkills, Skills
|
|
|
|
from ..config import Settings
|
|
from ..llm import ModelFactory
|
|
from .loader import ApmContext
|
|
from .primitives import AgentPrimitive
|
|
|
|
|
|
class ToolResolutionError(RuntimeError):
|
|
pass
|
|
|
|
|
|
def _resolve_tools(names: list[str], registry: dict[str, Callable[..., Any]]) -> list[Callable[..., Any]]:
|
|
unknown = [n for n in names if n not in registry]
|
|
if unknown:
|
|
raise ToolResolutionError(
|
|
f"Definicja agenta odwołuje się do nieistniejących narzędzi: {', '.join(unknown)}. "
|
|
f"Dostępne: {', '.join(sorted(registry))}"
|
|
)
|
|
return [registry[n] for n in names]
|
|
|
|
|
|
def build_skills(ctx: ApmContext, names: list[str]) -> Skills | None:
|
|
"""Buduje natywny obiekt `Skills` agno z katalogów skilli dostarczonych przez APM.
|
|
|
|
agno waliduje katalogi względem specyfikacji Agent Skills - niepoprawny skill
|
|
wysadza przebieg na starcie, a nie w połowie modyfikacji kodu.
|
|
"""
|
|
if not names:
|
|
return None
|
|
paths = ctx.skill_paths(names)
|
|
return Skills(loaders=[LocalSkills(str(p)) for p in paths])
|
|
|
|
|
|
def build_agent(
|
|
definition: AgentPrimitive,
|
|
ctx: ApmContext,
|
|
settings: Settings,
|
|
model_factory: ModelFactory,
|
|
tool_registry: dict[str, Callable[..., Any]],
|
|
schema_registry: dict[str, type] | None = None,
|
|
) -> Agent:
|
|
schema_registry = schema_registry or {}
|
|
|
|
instructions: list[str] = []
|
|
instructions.extend(ctx.context_bodies(definition.context_names))
|
|
instructions.append(definition.body)
|
|
instructions.extend(ctx.instruction_bodies(definition.instruction_names))
|
|
|
|
output_schema = None
|
|
if definition.output_schema_name:
|
|
if definition.output_schema_name not in schema_registry:
|
|
raise KeyError(
|
|
f"Agent '{definition.name}' deklaruje output_schema='{definition.output_schema_name}', "
|
|
f"którego nie ma w rejestrze schematów: {sorted(schema_registry)}"
|
|
)
|
|
output_schema = schema_registry[definition.output_schema_name]
|
|
|
|
return Agent(
|
|
name=definition.name,
|
|
description=definition.description or None,
|
|
model=model_factory.for_profile(definition.model_profile, definition.temperature),
|
|
instructions=instructions,
|
|
tools=_resolve_tools(definition.tool_names, tool_registry) or None,
|
|
skills=build_skills(ctx, definition.skill_names),
|
|
output_schema=output_schema,
|
|
tool_call_limit=definition.tool_call_limit or settings.tool_call_limit,
|
|
markdown=False,
|
|
telemetry=False,
|
|
add_datetime_to_context=True,
|
|
# Nazwa roli w kontekście systemowym: pomaga modelowi trzymać się swojego zadania,
|
|
# a atrapie LLM (llm/mock_server.py) rozpoznać, który agent pyta.
|
|
add_name_to_context=True,
|
|
retries=2,
|
|
)
|