diff --git a/core/src/agentforge_core/domain/agent.py b/core/src/agentforge_core/domain/agent.py new file mode 100644 index 0000000..3007b99 --- /dev/null +++ b/core/src/agentforge_core/domain/agent.py @@ -0,0 +1,43 @@ +"""Modelos de dominio del agente: definición, configuración LLM y metadata de versión.""" + +from __future__ import annotations + +from datetime import datetime +from typing import Any, Literal + +from pydantic import BaseModel, Field + + +class LLMConfig(BaseModel): + """Configuración del proveedor LLM utilizado por un agente.""" + + provider: Literal["mock", "azure", "openai"] = "mock" + model: str = "gpt-4o" + temperature: float = Field(default=0.2, ge=0.0, le=2.0) + max_tokens: int = Field(default=2000, ge=1, le=128_000) + + +class AgentVersionMeta(BaseModel): + """Metadatos de una versión concreta de un agente (estilo commit Git).""" + + id: str + hash: str + author: str + message: str + created_at: datetime + + +class AgentDefinition(BaseModel): + """Definición declarativa completa de un agente.""" + + name: str + version: str + owner: str + purpose: str + state: Literal["draft", "active", "deprecated"] + guardrails: list[str] + llm: LLMConfig + system_prompt: str + output_schema: dict[str, Any] + risk_threshold_for_hitl: int = Field(default=4, ge=1, le=5) + updated_at: datetime diff --git a/tests/unit/test_domain_agent.py b/tests/unit/test_domain_agent.py new file mode 100644 index 0000000..203a289 --- /dev/null +++ b/tests/unit/test_domain_agent.py @@ -0,0 +1,70 @@ +"""Tests unitarios para los modelos de dominio del agente.""" + +from datetime import UTC, datetime + +import pytest +from pydantic import ValidationError + +from agentforge_core.domain.agent import ( + AgentDefinition, + AgentVersionMeta, + LLMConfig, +) + + +def test_llm_config_default_provider_is_mock() -> None: + cfg = LLMConfig() + assert cfg.provider == "mock" + assert cfg.model == "gpt-4o" + assert cfg.temperature == 0.2 + + +def test_llm_config_rechaza_provider_invalido() -> None: + with pytest.raises(ValidationError): + LLMConfig(provider="bedrock") # type: ignore[arg-type] + + +def test_agent_version_meta_serialize() -> None: + meta = AgentVersionMeta( + id="v1", + hash="abc123", + author="Juan", + message="inicial", + created_at=datetime(2026, 5, 9, tzinfo=UTC), + ) + dumped = meta.model_dump(mode="json") + assert dumped["id"] == "v1" + assert dumped["created_at"].startswith("2026-05-09") + + +def test_agent_definition_minimo_valido() -> None: + agent = AgentDefinition( + name="incident_analyzer", + version="v1", + owner="Juan", + purpose="Análisis de incidentes", + state="active", + guardrails=["default"], + llm=LLMConfig(), + system_prompt="eres un analista...", + output_schema={"type": "object"}, + updated_at=datetime.now(UTC), + ) + assert agent.risk_threshold_for_hitl == 4 # default + assert agent.state == "active" + + +def test_agent_definition_rechaza_state_invalido() -> None: + with pytest.raises(ValidationError): + AgentDefinition( + name="x", + version="v1", + owner="x", + purpose="x", + state="archived", # type: ignore[arg-type] + guardrails=[], + llm=LLMConfig(), + system_prompt="x", + output_schema={}, + updated_at=datetime.now(UTC), + )