diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 813af04..71b8b71 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,26 +1,23 @@ # Forja — Arquitectura técnica -> Documento "vivo" con las decisiones técnicas. El spec original está en -> [`docs/superpowers/specs/2026-05-09- forja-design.md`](docs/superpowers/specs/2026-05-09- forja-design.md). +> Documento vivo con las decisiones técnicas. ## Visión general -Two-tier: -- `forja-core` — FastAPI 8000. Dominio de gobierno, runtime LangGraph, - guardrails y persistencia. -- `forja-dashboard` — Streamlit 8501. Cliente HTTP del core. +Forja es un **único servicio FastAPI** (:8000): +- Todo el dominio de gobierno, runtime LangGraph, guardrails y persistencia. +- UI embebida (HTMX) para uso humano + API REST completa bajo `/api`. ## Diagrama ``` -┌─────────────────────┐ HTTP/JSON ┌─────────────────────┐ -│ Dashboard (Stream.) │ ───────────► │ Core (FastAPI) │ -└─────────────────────┘ └─────────┬───────────┘ - │ - ┌─────────────────────────┬────────┴──────┬────────────┐ - ▼ ▼ ▼ ▼ - LLM layer Guardrails layer LangGraph State - (Strategy pattern) (Strategy pattern) Runtime JSON+SQL+JSONL +┌────────────────────────────────────────────────────────────┐ +│ forja-core :8000 │ +│ UI HTMX (humanos) + REST API (/api) + dominio completo │ +│ │ +│ LLM (strategy) │ Guardrails (strategy) │ LangGraph │ +│ │ │ + checkpoints│ +└────────────────────────────────────────────────────────────┘ ``` ## Patrones aplicados @@ -50,7 +47,7 @@ Se usa la API dinámica `interrupt(payload)` de LangGraph ≥0.2 dentro del nodo `approve_gate`. Sólo pausa cuando hay acciones de alto riesgo (`risk_score >= threshold` o `requires_approval=True`). El cliente envía `Command(resume={"approved_action_ids": [...]})` vía -`POST /executions/{trace_id}/approve`. +`POST /api/executions/{trace_id}/approve`. ## Observabilidad diff --git a/README.md b/README.md index e78fd79..7074dc5 100644 --- a/README.md +++ b/README.md @@ -7,30 +7,28 @@ ejecución controlada con runtime stateful, Human-in-the-Loop y observabilidad c ## Arquitectura +Forja es un **único servicio** (FastAPI en :8000) que expone: + +- API REST completa bajo `/api` (agentes, políticas, ejecuciones, aprobaciones, violaciones). +- UI embebida moderna (HTMX + Tailwind + Jinja) en rutas amigables (`/agents`, `/run`, `/approvals`, `/history`, `/policies`). + ``` -┌───────────────────────── docker-compose ──────────────────────────┐ -│ │ -│ ┌─────────────────────┐ HTTP/JSON ┌────────────────────┐ │ -│ │ forja-dashboard │ ────────────────► │ forja-core │ │ -│ │ Streamlit :8501 │ ◄──────────────── │ FastAPI :8000 │ │ -│ └─────────────────────┘ └────────────────────┘ │ -│ │ -│ Strategy pattern para LLMProvider, GuardrailEngine, Registry. │ -│ Persistencia: YAML (defs versionadas), JSONL (logs), SQLite │ -│ (checkpoints LangGraph + HITL). │ -└────────────────────────────────────────────────────────────────────┘ +┌───────────────────────────────────────────────────────────────┐ +│ forja-core :8000 │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ UI HTMX (navegador humano) │ API REST (/api/*) │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ Strategy factories (LLM / Guardrails / Registry) │ +│ LangGraph runtime + SQLite checkpoints (HITL real) │ +│ Persistencia: YAML versionado + JSONL + SQLite │ +└───────────────────────────────────────────────────────────────┘ ``` -Detalles completos en [`ARCHITECTURE.md`](ARCHITECTURE.md). Además: -- [`docs/walkthrough.html`](docs/walkthrough.html) — **walkthrough HTML autocontenido** - (de alto a bajo nivel, con diagramas). Ábrelo directamente en el navegador - (`xdg-open docs/walkthrough.html`); no requiere servidor. -- [`docs/explicacion.md`](docs/explicacion.md) — explicación didáctica de extremo a - extremo (conceptos, recorrido por todos los módulos y sus interrelaciones, y el - viaje de una petición de principio a fin). -- [`docs/componentes.md`](docs/componentes.md) — referencia de cableado a bajo nivel - (grafo de dependencias de módulos, inyección de dependencias, firmas de los - contratos entre capas, cadenas de llamada de cada endpoint). +Documentación viva: +- [`ARCHITECTURE.md`](ARCHITECTURE.md) — decisiones técnicas. +- [`docs/explicacion.md`](docs/explicacion.md) — explicación didáctica completa. +- [`docs/componentes.md`](docs/componentes.md) — referencia de cableado a bajo nivel. +- [`docs/futuro.md`](docs/futuro.md) — roadmap. ## Quickstart @@ -39,7 +37,7 @@ cp .env.example .env docker compose up ``` -Abre [http://localhost:8501](http://localhost:8501). +Abre [http://localhost:8000](http://localhost:8000). Funciona out-of-the-box (`LLM_PROVIDER=mock`, sin API keys). Si quieres usar Azure OpenAI real, edita `.env`. @@ -64,8 +62,8 @@ Azure OpenAI real, edita `.env`. | LangGraph + HITL + checkpoints | `core/src/forja_core/runtime/` | | Observabilidad (trace + structlog) | `core/src/forja_core/observability/` | | LLM abstraction | `core/src/forja_core/llm/` | -| Editores gráficos (nuevo) | dashboard páginas Forjar Agente / Política | -| API REST + dashboard | forja-core :8000 + forja-dashboard :8501 | +| UI embebida (HTMX) | `core/src/forja_core/web/` (ruta raíz) | +| API REST completa | bajo `/api` en forja-core :8000 | ## Variables de entorno @@ -79,13 +77,12 @@ Ver [`docs/futuro.md`](docs/futuro.md). ``` forja/ -├── core/ servicio FastAPI (gobernanza + runtime) -├── dashboard/ Streamlit (UI + editores gráficos) +├── core/ servicio FastAPI único (API + UI HTMX embebida) ├── agents/ definiciones de agentes (YAML versionados) ├── policies/ políticas de guardrails (YAML versionados) ├── data/ runtime state (gitignored) ├── tests/ -└── docs/ +└── docs/ (explicacion.md, componentes.md, futuro.md, ARCHITECTURE.md) ``` ## Tests diff --git a/core/src/forja_core/api/executions.py b/core/src/forja_core/api/executions.py index 9646285..a41ae0d 100644 --- a/core/src/forja_core/api/executions.py +++ b/core/src/forja_core/api/executions.py @@ -216,12 +216,19 @@ async def approve_execution( ) -> AgentExecution: agent_def, policy = _resolve(registry, policies, settings.data_dir, trace_id) await _ensure_awaiting(orchestrator, agent_def, policy, trace_id) + # Empty approved_action_ids from UI "Aprobar todo" → approve everything that was waiting + approved = body.approved_action_ids + if not approved: + # Try to resolve the actual ids from current snapshot (best effort) + snap = await orchestrator.snapshot(agent_def=agent_def, policy=policy, trace_id=trace_id) + if snap and snap.needs_human_for: + approved = [a.id for a in snap.needs_human_for] execution = await orchestrator.resume( agent_def=agent_def, policy=policy, trace_id=trace_id, decision={ - "approved_action_ids": body.approved_action_ids, + "approved_action_ids": approved, "comment": body.comment, "rejected": False, }, diff --git a/core/src/forja_core/main.py b/core/src/forja_core/main.py index b9d1349..320d4d7 100644 --- a/core/src/forja_core/main.py +++ b/core/src/forja_core/main.py @@ -24,18 +24,18 @@ def create_app() -> FastAPI: async def health() -> dict[str, str]: return {"status": "ok"} - from forja_core.web import ui from forja_core.api import agents, executions, policies, violations + from forja_core.web import ui - # UI HTMX embebida (Opción A) — se registra primero para que las páginas - # tengan preferencia sobre los endpoints JSON cuando se accede desde navegador. + # UI HTMX embebida (Opción A) en rutas amigables para humanos. + # Toda la API REST vive bajo /api para eliminar ambigüedad y conflictos de ruta. app.include_router(ui.router) - app.include_router(agents.router, prefix="/agents", tags=["agents"]) - app.include_router(executions.invoke_router, prefix="/agents", tags=["agents"]) - app.include_router(executions.router, prefix="/executions", tags=["executions"]) - app.include_router(policies.router, prefix="/policies", tags=["policies"]) - app.include_router(violations.router, prefix="/violations", tags=["violations"]) + app.include_router(agents.router, prefix="/api/agents", tags=["agents"]) + app.include_router(executions.invoke_router, prefix="/api/agents", tags=["agents"]) + app.include_router(executions.router, prefix="/api/executions", tags=["executions"]) + app.include_router(policies.router, prefix="/api/policies", tags=["policies"]) + app.include_router(violations.router, prefix="/api/violations", tags=["violations"]) return app diff --git a/core/src/forja_core/web/templates/agent_detail.html b/core/src/forja_core/web/templates/agent_detail.html index 95b75b2..1b465eb 100644 --- a/core/src/forja_core/web/templates/agent_detail.html +++ b/core/src/forja_core/web/templates/agent_detail.html @@ -25,7 +25,7 @@ {% if agent.category %}
Executions with high-risk actions are paused here. Approve or reject so the graph can continue (or fail). The list updates after every action.
- Gobernanza profesional para agentes de IA -
+Invoca un agente con todo el gobierno (guardrails + HITL + observabilidad).
+Invoke an agent with full governance (guardrails + HITL + observability).
{execution.model_dump_json(indent=2)}
- - Plataforma de gobernanza genérica para agentes IA de cualquier tipo. - Renombrada, generalizada y con editores gráficos completos. -
- -forja-core:dev)FORJA_CORE_URL)POST /agents/{name}/versions + upsertPOST /policies/{name}/versions + upsert simétricoGET /policies/validators (metadata para UI)FileSystemPolicyStore.upsert_version()docker compose up (con :rw)Seguimiento de Progreso
++ La interfaz se ha transformado en una vista única de fábrica. + El objetivo es que el usuario entienda de un vistazo cómo se "forja" un agente, + mostrando solo los bloques que generan inputs configurables o + outputs significativos. +
+Este documento puede servir como registro vivo del proyecto.
+Añade aquí nuevas decisiones, experimentos visuales o cambios de rumbo cuando ocurran.
+