feat: initial commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""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,
|
||||
)
|
||||
Reference in New Issue
Block a user