proyecto generalizado

This commit is contained in:
2026-05-23 16:44:45 +02:00
parent 2f990ea636
commit b4964261ec
94 changed files with 1032 additions and 320 deletions
+1 -1
View File
@@ -33,4 +33,4 @@ EXPOSE 8000
HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=3 \
CMD curl -fsS http://localhost:8000/health || exit 1
CMD ["uvicorn", "agentforge_core.main:app", "--host", "0.0.0.0", "--port", "8000"]
CMD ["uvicorn", "forja_core.main:app", "--host", "0.0.0.0", "--port", "8000"]
-23
View File
@@ -1,23 +0,0 @@
"""Router /policies: listado de políticas y de sus versiones."""
from __future__ import annotations
from fastapi import APIRouter, HTTPException
from agentforge_core.api.deps import PolicyStoreDep
from agentforge_core.domain.policy import PolicyDefinition, PolicyVersionMeta
router = APIRouter()
@router.get("", response_model=list[PolicyDefinition])
def list_policies(store: PolicyStoreDep) -> list[PolicyDefinition]:
return store.list_policies()
@router.get("/{name}/versions", response_model=list[PolicyVersionMeta])
def list_versions(name: str, store: PolicyStoreDep) -> list[PolicyVersionMeta]:
try:
return store.list_versions(name)
except FileNotFoundError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@@ -2,15 +2,22 @@
from __future__ import annotations
from fastapi import APIRouter, HTTPException
from fastapi import APIRouter, HTTPException, status
from pydantic import BaseModel
from agentforge_core.api.deps import RegistryDep
from agentforge_core.domain.agent import AgentDefinition, AgentVersionMeta
from agentforge_core.registry.versioning import DiffResult
from forja_core.api.deps import RegistryDep
from forja_core.domain.agent import AgentDefinition, AgentVersionMeta
from forja_core.registry.versioning import DiffResult
router = APIRouter()
class CreateAgentVersionRequest(BaseModel):
agent: AgentDefinition
message: str
author: str = "dashboard"
@router.get("", response_model=list[AgentDefinition])
def list_agents(registry: RegistryDep) -> list[AgentDefinition]:
return registry.list_agents()
@@ -43,3 +50,12 @@ def get_version(name: str, version: str, registry: RegistryDep) -> AgentDefiniti
@router.get("/{name}/versions/{v_from}/diff/{v_to}", response_model=DiffResult)
def diff_versions(name: str, v_from: str, v_to: str, registry: RegistryDep) -> DiffResult:
return registry.diff_versions(name, v_from, v_to)
@router.post("/{name}/versions", response_model=AgentVersionMeta, status_code=status.HTTP_201_CREATED)
def create_agent_version(name: str, req: CreateAgentVersionRequest, registry: RegistryDep) -> AgentVersionMeta:
try:
return registry.upsert_version(name, req.agent, req.message, req.author)
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
@@ -12,15 +12,15 @@ from typing import Annotated
from fastapi import Depends
from agentforge_core.config import Settings
from agentforge_core.guardrails.base import GuardrailEngine
from agentforge_core.guardrails.factory import build_guardrail_engine
from agentforge_core.llm.base import LLMProvider
from agentforge_core.llm.factory import build_llm_provider
from agentforge_core.registry.factory import build_agent_registry, build_policy_store
from agentforge_core.registry.policy_store import FileSystemPolicyStore
from agentforge_core.registry.repository import FileSystemAgentRegistry
from agentforge_core.runtime.orchestrator import AgentOrchestrator
from forja_core.config import Settings
from forja_core.guardrails.base import GuardrailEngine
from forja_core.guardrails.factory import build_guardrail_engine
from forja_core.llm.base import LLMProvider
from forja_core.llm.factory import build_llm_provider
from forja_core.registry.factory import build_agent_registry, build_policy_store
from forja_core.registry.policy_store import FileSystemPolicyStore
from forja_core.registry.repository import FileSystemAgentRegistry
from forja_core.runtime.orchestrator import AgentOrchestrator
@lru_cache(maxsize=1)
@@ -9,23 +9,23 @@ from uuid import UUID
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field
from agentforge_core.api.deps import (
from forja_core.api.deps import (
OrchestratorDep,
PolicyStoreDep,
RegistryDep,
SettingsDep,
)
from agentforge_core.api.persistence import (
from forja_core.api.persistence import (
append_execution,
append_violation,
read_execution_summaries,
)
from agentforge_core.domain.agent import AgentDefinition
from agentforge_core.domain.execution import AgentExecution, AgentExecutionSummary
from agentforge_core.domain.policy import PolicyDefinition
from agentforge_core.registry.policy_store import FileSystemPolicyStore
from agentforge_core.registry.repository import FileSystemAgentRegistry
from agentforge_core.runtime.orchestrator import AgentOrchestrator
from forja_core.domain.agent import AgentDefinition
from forja_core.domain.execution import AgentExecution, AgentExecutionSummary
from forja_core.domain.policy import PolicyDefinition
from forja_core.registry.policy_store import FileSystemPolicyStore
from forja_core.registry.repository import FileSystemAgentRegistry
from forja_core.runtime.orchestrator import AgentOrchestrator
router = APIRouter()
# POST /agents/{name}/invoke vive aquí pero se monta en main bajo el prefijo /agents.
@@ -8,7 +8,7 @@ from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoin
from starlette.requests import Request
from starlette.responses import Response
from agentforge_core.observability.logging import bind_trace_id, clear_trace_id
from forja_core.observability.logging import bind_trace_id, clear_trace_id
class TraceIdMiddleware(BaseHTTPMiddleware):
@@ -8,8 +8,8 @@ from __future__ import annotations
from pathlib import Path
from agentforge_core.domain.execution import AgentExecution, AgentExecutionSummary
from agentforge_core.domain.guardrail import GuardrailViolation
from forja_core.domain.execution import AgentExecution, AgentExecutionSummary
from forja_core.domain.guardrail import GuardrailViolation
def append_violation(data_dir: Path, violation: GuardrailViolation) -> None:
+47
View File
@@ -0,0 +1,47 @@
"""Router /policies: listado de políticas y de sus versiones."""
from __future__ import annotations
from fastapi import APIRouter, HTTPException, status
from pydantic import BaseModel
from forja_core.api.deps import PolicyStoreDep
from forja_core.domain.policy import PolicyDefinition, PolicyVersionMeta
router = APIRouter()
class CreatePolicyVersionRequest(BaseModel):
policy: PolicyDefinition
message: str
author: str = "dashboard"
@router.get("", response_model=list[PolicyDefinition])
def list_policies(store: PolicyStoreDep) -> list[PolicyDefinition]:
return store.list_policies()
@router.get("/{name}/versions", response_model=list[PolicyVersionMeta])
def list_versions(name: str, store: PolicyStoreDep) -> list[PolicyVersionMeta]:
try:
return store.list_versions(name)
except FileNotFoundError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@router.post("/{name}/versions", response_model=PolicyVersionMeta, status_code=status.HTTP_201_CREATED)
def create_policy_version(name: str, req: CreatePolicyVersionRequest, store: PolicyStoreDep) -> PolicyVersionMeta:
try:
return store.upsert_version(name, req.policy, req.message, req.author)
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
@router.get("/validators")
def list_validators() -> dict[str, list[str]]:
return {
"input": ["detect_pii", "prompt_injection", "toxic_language", "forbidden_topics"],
"output": ["schema_match", "pii_leakage", "forbidden_action_keywords", "telco_safety_rules"],
}
@@ -7,9 +7,9 @@ from uuid import UUID
from fastapi import APIRouter, Query
from agentforge_core.api.deps import SettingsDep
from agentforge_core.api.persistence import read_violations
from agentforge_core.domain.guardrail import GuardrailViolation
from forja_core.api.deps import SettingsDep
from forja_core.api.persistence import read_violations
from forja_core.domain.guardrail import GuardrailViolation
router = APIRouter()
@@ -41,3 +41,9 @@ class AgentDefinition(BaseModel):
output_schema: dict[str, Any]
risk_threshold_for_hitl: int = Field(default=4, ge=1, le=5)
updated_at: datetime
input_label: str | None = None
input_placeholder: str | None = None
category: str | None = None
tags: list[str] = Field(default_factory=list)
icon: str | None = None
template: str = "governed_llm"
@@ -8,7 +8,7 @@ from uuid import UUID
from pydantic import BaseModel, Field
from agentforge_core.domain.guardrail import GuardrailViolation
from forja_core.domain.guardrail import GuardrailViolation
class ProposedAction(BaseModel):
@@ -5,8 +5,8 @@ from __future__ import annotations
from typing import Any, Protocol
from uuid import UUID
from agentforge_core.domain.guardrail import GuardrailViolation
from agentforge_core.domain.policy import PolicyDefinition
from forja_core.domain.guardrail import GuardrailViolation
from forja_core.domain.policy import PolicyDefinition
class GuardrailEngine(Protocol):
@@ -6,9 +6,9 @@ import asyncio
from typing import Any
from uuid import UUID
from agentforge_core.domain.guardrail import GuardrailViolation
from agentforge_core.domain.policy import PolicyDefinition
from agentforge_core.guardrails.base import GuardrailEngine
from forja_core.domain.guardrail import GuardrailViolation
from forja_core.domain.policy import PolicyDefinition
from forja_core.guardrails.base import GuardrailEngine
class CompositeGuardrailEngine:
@@ -2,11 +2,11 @@
from __future__ import annotations
from agentforge_core.config import Settings
from agentforge_core.guardrails.base import GuardrailEngine
from agentforge_core.guardrails.composite import CompositeGuardrailEngine
from agentforge_core.guardrails.guardrails_ai import GuardrailsAIEngine
from agentforge_core.guardrails.nemo import NeMoGuardrailsEngine
from forja_core.config import Settings
from forja_core.guardrails.base import GuardrailEngine
from forja_core.guardrails.composite import CompositeGuardrailEngine
from forja_core.guardrails.guardrails_ai import GuardrailsAIEngine
from forja_core.guardrails.nemo import NeMoGuardrailsEngine
def build_guardrail_engine(settings: Settings) -> GuardrailEngine:
@@ -9,9 +9,9 @@ from uuid import UUID
import structlog
from agentforge_core.domain.guardrail import GuardrailViolation
from agentforge_core.domain.policy import PolicyDefinition, PolicyValidator
from agentforge_core.guardrails.validators import (
from forja_core.domain.guardrail import GuardrailViolation
from forja_core.domain.policy import PolicyDefinition, PolicyValidator
from forja_core.guardrails.validators import (
detect_pii,
forbidden_action_keywords,
forbidden_topics,
@@ -12,8 +12,8 @@ from uuid import UUID
import structlog
from agentforge_core.domain.guardrail import GuardrailViolation
from agentforge_core.domain.policy import PolicyDefinition
from forja_core.domain.guardrail import GuardrailViolation
from forja_core.domain.policy import PolicyDefinition
log = structlog.get_logger(__name__)
@@ -10,7 +10,7 @@ from uuid import UUID
import jsonschema
from agentforge_core.domain.guardrail import GuardrailViolation
from forja_core.domain.guardrail import GuardrailViolation
_INJECTION_PATTERNS = [
r"ignore (the )?(previous|prior|above) (instruction|prompt|message)",
@@ -8,7 +8,7 @@ from typing import Any
from openai import AsyncAzureOpenAI
from agentforge_core.llm.base import CompletionResult, Message
from forja_core.llm.base import CompletionResult, Message
class AzureOpenAIProvider:
@@ -2,11 +2,11 @@
from __future__ import annotations
from agentforge_core.config import Settings
from agentforge_core.llm.azure import AzureOpenAIProvider
from agentforge_core.llm.base import LLMProvider
from agentforge_core.llm.mock import MockProvider
from agentforge_core.llm.openai import OpenAIProvider
from forja_core.config import Settings
from forja_core.llm.azure import AzureOpenAIProvider
from forja_core.llm.base import LLMProvider
from forja_core.llm.mock import MockProvider
from forja_core.llm.openai import OpenAIProvider
def build_llm_provider(settings: Settings) -> LLMProvider:
@@ -7,7 +7,7 @@ import json
import time
from typing import Any
from agentforge_core.llm.base import CompletionResult, Message
from forja_core.llm.base import CompletionResult, Message
_CANONICAL_RESPONSES: dict[str, dict[str, Any]] = {
"sip": {
@@ -8,7 +8,7 @@ from typing import Any
from openai import AsyncOpenAI
from agentforge_core.llm.base import CompletionResult, Message
from forja_core.llm.base import CompletionResult, Message
class OpenAIProvider:
@@ -1,12 +1,12 @@
"""Composición raíz de la aplicación FastAPI (agentforge-core)."""
"""Composición raíz de la aplicación FastAPI (forja-core)."""
from __future__ import annotations
from fastapi import FastAPI
from agentforge_core.api.middlewares import TraceIdMiddleware
from agentforge_core.config import Settings
from agentforge_core.observability.logging import configure_logging
from forja_core.api.middlewares import TraceIdMiddleware
from forja_core.config import Settings
from forja_core.observability.logging import configure_logging
def create_app() -> FastAPI:
@@ -14,7 +14,7 @@ def create_app() -> FastAPI:
settings = Settings()
configure_logging(level=settings.log_level)
app = FastAPI(
title="AgentForge Core",
title="Forja Core",
version="0.1.0",
description="Plataforma de gobernanza de agentes IA — API REST.",
)
@@ -24,7 +24,7 @@ def create_app() -> FastAPI:
async def health() -> dict[str, str]:
return {"status": "ok"}
from agentforge_core.api import agents, executions, policies, violations
from forja_core.api import agents, executions, policies, violations
app.include_router(agents.router, prefix="/agents", tags=["agents"])
app.include_router(executions.invoke_router, prefix="/agents", tags=["agents"])
@@ -2,9 +2,9 @@
from __future__ import annotations
from agentforge_core.config import Settings
from agentforge_core.registry.policy_store import FileSystemPolicyStore
from agentforge_core.registry.repository import FileSystemAgentRegistry
from forja_core.config import Settings
from forja_core.registry.policy_store import FileSystemPolicyStore
from forja_core.registry.repository import FileSystemAgentRegistry
def build_agent_registry(settings: Settings) -> FileSystemAgentRegistry:
@@ -2,13 +2,14 @@
from __future__ import annotations
from datetime import datetime
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
import yaml
from agentforge_core.domain.policy import PolicyDefinition, PolicyVersionMeta
from forja_core.domain.policy import PolicyDefinition, PolicyVersionMeta
from forja_core.registry.versioning import compute_hash
class FileSystemPolicyStore:
@@ -62,3 +63,48 @@ class FileSystemPolicyStore:
if isinstance(value, datetime):
return value
return datetime.fromisoformat(value.replace("Z", "+00:00"))
def upsert_version(
self,
name: str,
body: PolicyDefinition,
message: str,
author: str,
) -> PolicyVersionMeta:
policy_dir = self._root / name
versions_dir = policy_dir / "versions"
versions_dir.mkdir(parents=True, exist_ok=True)
version_id = body.version
yaml_text = yaml.safe_dump(
body.model_dump(mode="json"),
sort_keys=False,
allow_unicode=True,
)
h = compute_hash(yaml_text)
version_path = versions_dir / f"{version_id}.yaml"
version_path.write_text(yaml_text, encoding="utf-8")
meta = PolicyVersionMeta(
id=version_id,
hash=h,
author=author,
message=message,
created_at=datetime.now(UTC),
)
index_path = policy_dir / "index.yaml"
if index_path.exists():
with index_path.open(encoding="utf-8") as f:
index: dict[str, Any] = yaml.safe_load(f)
else:
index = {"name": name, "versions": [], "active_version": version_id}
index["versions"] = [v for v in index["versions"] if v["id"] != version_id]
index["versions"].append(meta.model_dump(mode="json"))
index["active_version"] = version_id
with index_path.open("w", encoding="utf-8") as f:
yaml.safe_dump(index, f, sort_keys=False, allow_unicode=True)
return meta
@@ -8,8 +8,8 @@ from typing import Any
import yaml
from agentforge_core.domain.agent import AgentDefinition, AgentVersionMeta
from agentforge_core.registry.versioning import DiffResult, compute_hash, unified_diff
from forja_core.domain.agent import AgentDefinition, AgentVersionMeta
from forja_core.registry.versioning import DiffResult, compute_hash, unified_diff
class FileSystemAgentRegistry:
@@ -7,11 +7,11 @@ from typing import Any
from langgraph.checkpoint.base import BaseCheckpointSaver
from langgraph.graph import END, START, StateGraph
from agentforge_core.domain.agent import AgentDefinition
from agentforge_core.domain.policy import PolicyDefinition
from agentforge_core.guardrails.base import GuardrailEngine
from agentforge_core.llm.base import LLMProvider
from agentforge_core.runtime.nodes import (
from forja_core.domain.agent import AgentDefinition
from forja_core.domain.policy import PolicyDefinition
from forja_core.guardrails.base import GuardrailEngine
from forja_core.llm.base import LLMProvider
from forja_core.runtime.nodes import (
build_node_approve_gate,
build_node_finalize,
build_node_llm_reason,
@@ -19,7 +19,7 @@ from agentforge_core.runtime.nodes import (
build_node_validate_input,
build_node_validate_output,
)
from agentforge_core.runtime.state import AgentState
from forja_core.runtime.state import AgentState
def build_graph(
@@ -12,11 +12,11 @@ from uuid import UUID
import structlog
from langgraph.types import interrupt
from agentforge_core.domain.agent import AgentDefinition
from agentforge_core.domain.policy import PolicyDefinition
from agentforge_core.guardrails.base import GuardrailEngine
from agentforge_core.llm.base import LLMProvider, Message
from agentforge_core.runtime.state import AgentState
from forja_core.domain.agent import AgentDefinition
from forja_core.domain.policy import PolicyDefinition
from forja_core.guardrails.base import GuardrailEngine
from forja_core.llm.base import LLMProvider, Message
from forja_core.runtime.state import AgentState
log = structlog.get_logger(__name__)
@@ -18,14 +18,14 @@ from uuid import UUID, uuid4
import structlog
from langgraph.types import Command
from agentforge_core.domain.agent import AgentDefinition
from agentforge_core.domain.execution import AgentExecution, DecisionStep, ProposedAction
from agentforge_core.domain.guardrail import GuardrailViolation
from agentforge_core.domain.policy import PolicyDefinition
from agentforge_core.guardrails.base import GuardrailEngine
from agentforge_core.llm.base import LLMProvider
from agentforge_core.runtime.checkpointer import build_checkpointer
from agentforge_core.runtime.graph import build_graph
from forja_core.domain.agent import AgentDefinition
from forja_core.domain.execution import AgentExecution, DecisionStep, ProposedAction
from forja_core.domain.guardrail import GuardrailViolation
from forja_core.domain.policy import PolicyDefinition
from forja_core.guardrails.base import GuardrailEngine
from forja_core.llm.base import LLMProvider
from forja_core.runtime.checkpointer import build_checkpointer
from forja_core.runtime.graph import build_graph
log = structlog.get_logger(__name__)