pagina unica
This commit is contained in:
+53
-53
@@ -1,9 +1,9 @@
|
||||
# Forja explicado de principio a fin
|
||||
|
||||
> **Nota de estado (mayo 2026):** Este documento fue escrito para la arquitectura
|
||||
> anterior (dos servicios + Streamlit/NiceGUI). Forja ahora es un **único servicio
|
||||
> FastAPI** con UI HTMX embebida. El núcleo (runtime, guardrails, HITL, versionado)
|
||||
> sigue siendo el mismo. Algunas secciones de UI y despliegue están desactualizadas.
|
||||
> **Nota de estado (junio 2026):** Forja es un **único servicio FastAPI** con UI
|
||||
> HTMX embebida. Además del runtime gobernado, incluye la capa MLOps: datasets y
|
||||
> modelos versionados, training runs contra backends externos, evaluación
|
||||
> post-training y promoción gobernada draft → active.
|
||||
>
|
||||
> Si solo quieres arrancarlo, ve al [`README.md`](../README.md).
|
||||
|
||||
@@ -49,37 +49,33 @@ Si entiendes estas seis ideas, entiendes el proyecto. Todo lo demás son detalle
|
||||
|
||||
---
|
||||
|
||||
## 3. Vista de pájaro: dos servicios
|
||||
## 3. Vista de pájaro: un único servicio
|
||||
|
||||
Forja son **dos procesos** que se hablan por HTTP/JSON:
|
||||
Forja es **un solo proceso** FastAPI (puerto 8000) con dos caras:
|
||||
|
||||
```
|
||||
┌───────────────────────────── docker-compose ──────────────────────────────┐
|
||||
│ │
|
||||
│ ┌──────────────────────┐ HTTP/JSON ┌────────────────────────┐ │
|
||||
│ │ forja-dashboard │ ───────────────► │ forja-core │ │
|
||||
│ │ Streamlit :8501 │ ◄─────────────── │ FastAPI :8000 │ │
|
||||
│ │ (la "consola") │ │ (el cerebro) │ │
|
||||
│ └──────────────────────┘ └───────────┬────────────┘ │
|
||||
│ │ │
|
||||
│ ┌────────────────┬────────────────────┼───────────────┤
|
||||
│ ▼ ▼ ▼ │
|
||||
│ capa LLM capa Guardrails runtime LangGraph │
|
||||
│ (Strategy+factory) (Strategy+factory) (grafo + checkpointer) │
|
||||
│ │ │ │ │
|
||||
│ └────────────────┴──────────┬──────────┘ │
|
||||
│ ▼ │
|
||||
│ Persistencia: YAML · JSON · JSONL · SQLite │
|
||||
│ forja-core :8000 │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ UI HTMX (humanos, Jinja2) │ API REST (/api/*) │ │
|
||||
│ └────────────────────────────┬────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ capa LLM capa Guardrails runtime LangGraph │
|
||||
│ (Strategy+factory) (Strategy+factory) (grafo + checkpointer) │
|
||||
│ │ │ │ │
|
||||
│ └──────────────────┴───────────┬──────────┘ │
|
||||
│ ▼ │
|
||||
│ Persistencia: YAML · JSON · JSONL · SQLite │
|
||||
└────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **`forja-core`** (FastAPI, puerto 8000) — todo el dominio: registry de
|
||||
agentes, motor de guardrails, runtime de ejecución, persistencia. No tiene UI.
|
||||
- **`forja-dashboard`** (Streamlit, puerto 8501) — una consola visual. **No
|
||||
contiene lógica de negocio**: es un cliente HTTP del core con cinco páginas.
|
||||
|
||||
La separación importa: el core podría servir a una CLI, a otro servicio, a un
|
||||
pipeline... el dashboard es solo una de las caras posibles.
|
||||
- La **API REST** (bajo `/api`) es el contrato para máquinas: CLI, pipelines,
|
||||
otros servicios.
|
||||
- La **UI HTMX** es **una sola página** (`/`) organizada como las seis etapas
|
||||
del ciclo de vida (Define → Run → Approve → Train → Promote → Audit). Se
|
||||
sirve desde el mismo proceso y llama a los mismos servicios internos — no hay
|
||||
un cliente HTTP intermedio ni lógica de negocio duplicada. Las rutas antiguas
|
||||
(`/agents`, `/run`, ...) redirigen a su etapa.
|
||||
|
||||
### Las capas del core (de fuera hacia dentro)
|
||||
|
||||
@@ -285,25 +281,20 @@ inyectan). Dependen de él: la API (`api/executions.py` solo conoce el
|
||||
Y la **raíz de la app**: `core/src/ forja_core/main.py` → `create_app()` instancia
|
||||
`FastAPI`, añade el `TraceIdMiddleware`, monta los routers, y expone `/health`.
|
||||
|
||||
Depende de: todo lo de arriba (vía `deps.py`). Dependen de él: el dashboard (por
|
||||
HTTP) y los tests de integración (`tests/integration/`, vía `TestClient`).
|
||||
Depende de: todo lo de arriba (vía `deps.py`). Dependen de él: la UI HTMX
|
||||
(mismo proceso) y los tests (`TestClient`).
|
||||
|
||||
### 4.8 `dashboard/` — la consola Streamlit
|
||||
### 4.8 `web/` — la UI HTMX embebida (una página)
|
||||
|
||||
| Fichero | Rol |
|
||||
|---------|-----|
|
||||
| `client.py` | `CoreClient`: un cliente HTTP síncrono (httpx, con reintentos) que envuelve **todos** los endpoints del core y mapea 404/409/422 a `{"error": ...}`. Es lo único que sabe hablar con el core. |
|
||||
| `app.py` | La página raíz: sidebar de branding + un health-check del core. |
|
||||
| `pages/1_🏛️_Registro.py` | Catálogo de agentes: detalle (prompt, esquema, LLM, guardrails), tabla de versiones, **diff coloreado v1↔v2**. |
|
||||
| `pages/2_▶️_Ejecutar.py` | Lanza un agente: botones con los escenarios pregrabados, textarea, `invoke`, y render del status + output + violaciones + *timeline* del `decision_path`. Avisa si quedó en `awaiting_approval`. |
|
||||
| `pages/3_🤝_Aprobaciones.py` | La cola de HITL: lista las ejecuciones `awaiting_approval`, muestra cada acción propuesta (risk_score coloreado, target, rollback_plan) con un checkbox, y aprueba el subconjunto elegido o rechaza con motivo. |
|
||||
| `pages/4_📜_Historial.py` | Pestaña de ejecuciones (tabla + detalle por `trace_id`) y pestaña de violaciones (filtrable por severidad). |
|
||||
| `pages/5_📐_Politicas.py` | Inventario de políticas: validadores de entrada/salida (cada uno expandible con su config) y versiones. |
|
||||
| `components/` | Trozos reutilizables de UI: `diff_view` (pinta `+`/`-`/`@@`), `trace_view` (el timeline del `decision_path`), `violation_view` (badges de severidad). |
|
||||
| `ui.py` | `GET /` (la página completa), `POST /run`, `GET /fragments/{agents,approvals,training,promotions,history}` y redirects 301 de las rutas antiguas. Llama a los mismos singletons de `deps.py` que la API; no hay cliente HTTP intermedio. |
|
||||
| `templates/index.html` | La página única: seis etapas (Define → Run → Approve → Train → Promote → Audit), cada una con su explicación y su panel. |
|
||||
| `templates/_*.html` | Fragmentos por etapa. Cada panel lleva `hx-get="/fragments/X" hx-trigger="forja-refresh from:body"`: cualquier botón de acción dispara el evento `forja-refresh` al terminar y **todos los paneles se re-renderizan** — el ciclo entero se recorre con clicks, sin recargar la página. |
|
||||
|
||||
Depende de: el `forja-core` por HTTP (vía `FORJA_CORE_URL`). **Nadie del
|
||||
core depende del dashboard.** No tiene tests unitarios (mal coste/beneficio para
|
||||
Streamlit); su verificación es la checklist manual de [`docs/manual_qa.md`](manual_qa.md).
|
||||
Los botones de acción (approve/reject/train/evaluate/promote) hacen `hx-post`
|
||||
con la extensión `json-enc` directamente contra los endpoints `/api/*`; el botón
|
||||
**Run demo incident** lanza un incidente pregrabado que pausa en HITL.
|
||||
|
||||
### 4.9 Lo que no es código: `agents/`, `policies/`, `data/`
|
||||
|
||||
@@ -348,7 +339,7 @@ Esta es la sección que conviene leer despacio: aquí se ve cómo encaja todo. S
|
||||
### Acto 1 — la petición entra y se ejecuta el grafo
|
||||
|
||||
```
|
||||
Cliente (dashboard o curl)
|
||||
Cliente (UI o curl)
|
||||
│ POST /agents/incident_analyzer/invoke { "input": "<texto del incidente SIP>" }
|
||||
▼
|
||||
TraceIdMiddleware ............ genera trace_id = UUID, lo bind-ea al log
|
||||
@@ -391,10 +382,10 @@ router: status no es terminal → NO se escribe en executions.jsonl,
|
||||
respuesta 200 { status: "awaiting_approval", trace_id, needs_human_for: [act-1], decision_path: [...], ... }
|
||||
```
|
||||
|
||||
En el dashboard, la página **Ejecutar** muestra el timeline y un aviso "ve a
|
||||
Aprobaciones". La página **Aprobaciones** hace `GET /executions`, encuentra esta
|
||||
ejecución (el endpoint reconstruye las `awaiting_approval` desde el índice + el
|
||||
checkpointer) y muestra `act-1` con su risk_score, target y rollback_plan.
|
||||
En la UI, la página **Runs** muestra el timeline y un aviso "Open Approvals".
|
||||
La página **Approvals** reconstruye las ejecuciones `awaiting_approval` desde el
|
||||
índice + el checkpointer y muestra `act-1` con su risk_score, target y
|
||||
rollback_plan.
|
||||
|
||||
### Acto 2 — el humano decide; el grafo se reanuda
|
||||
|
||||
@@ -431,7 +422,7 @@ respuesta 200 { status: "completed", final_output: { ..., approved_actions: [ac
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as Cliente / Dashboard
|
||||
participant U as Cliente / UI
|
||||
participant MW as TraceIdMiddleware
|
||||
participant API as router (api/executions.py)
|
||||
participant ORCH as AgentOrchestrator
|
||||
@@ -477,6 +468,7 @@ Forja no usa una sola base de datos; usa la herramienta adecuada para cada cosa.
|
||||
| Mapa `trace_id → agente/versión` | **JSON** (`execution_index.json`) | Necesario para reanudar un HITL sabiendo qué configuración lo ejecutó; debe sobrevivir a reinicios. |
|
||||
| Log de ejecuciones terminales y de violaciones | **JSONL append-only** | Inmutable, auditable, trivial de "shipear" a un sistema de logs. |
|
||||
| Estado intermedio del grafo (incl. pausas HITL) | **SQLite** (`checkpoints.sqlite`, vía LangGraph) | Es lo que LangGraph espera; permite reanudar una ejecución pausada entre reinicios del proceso. |
|
||||
| Training runs, evaluaciones y promociones | **JSON por entidad** bajo `data/` (+ JSONL para promociones aprobadas) | Estado mutable consultable por id; la auditoría de promociones es append-only. |
|
||||
|
||||
---
|
||||
|
||||
@@ -497,6 +489,9 @@ Forja no usa una sola base de datos; usa la herramienta adecuada para cada cosa.
|
||||
| **Factory** | Función `build_X(settings)` que monta la implementación de `X` adecuada según la configuración. |
|
||||
| **Status de ejecución** | `running`, `awaiting_approval` (pausada en HITL), `blocked_by_guardrail` (la frenó un validador), `completed`, `failed`. |
|
||||
| **Estados de un agente** | `draft`, `active`, `deprecated` (metadato en su YAML). |
|
||||
| **Training run** | Job de fine-tuning enviado a un backend externo (mock o Azure ML) con dataset, modelo base y versión candidata del agente. |
|
||||
| **Evaluación post-training** | Ejecutar los escenarios canónicos del agente (`examples/*.txt`) por el runtime gobernado; pasa si no hay violaciones bloqueantes. Es el gate de promoción. |
|
||||
| **Promoción** | Petición de gobernanza para pasar una versión `draft` a `active`; requiere run `succeeded` + evaluación `passed` de esa misma versión + aprobación humana. |
|
||||
|
||||
---
|
||||
|
||||
@@ -508,18 +503,22 @@ Forja no usa una sola base de datos; usa la herramienta adecuada para cada cosa.
|
||||
│ ├── src/ forja_core/
|
||||
│ │ ├── domain/ ← los modelos de datos (empieza por execution.py)
|
||||
│ │ ├── config.py · observability/ ← cimientos transversales
|
||||
│ │ ├── llm/ ← proveedores LLM (Protocol + impls + factory)
|
||||
│ │ ├── registry/ ← catálogo y versionado (YAML/JSON, hash, diff)
|
||||
│ │ ├── llm/ ← proveedores LLM (Protocol + impls + fallback + factory)
|
||||
│ │ ├── registry/ ← catálogo y versionado (base yaml_store.py + 4 stores)
|
||||
│ │ ├── guardrails/ ← motor de validación (Protocol + composite + validators)
|
||||
│ │ ├── runtime/ ← el grafo LangGraph (state, nodes, graph, checkpointer, orchestrator)
|
||||
│ │ ├── training/ ← backends de fine-tuning (mock, Azure ML)
|
||||
│ │ ├── evaluation/ ← escenarios canónicos + evaluación post-training
|
||||
│ │ ├── api/ ← FastAPI (middlewares, deps, routers, persistence)
|
||||
│ │ ├── web/ ← UI HTMX (ui.py + templates/)
|
||||
│ │ └── main.py ← create_app(): ensambla la app
|
||||
│ ├── Dockerfile · requirements.txt
|
||||
├── agents/incident_analyzer/ ← el agente de ejemplo (YAMLs + escenarios .txt)
|
||||
├── policies/default/ ← la política de guardrails de ejemplo
|
||||
├── datasets/ · models/ ← datasets y modelos base versionados (YAML)
|
||||
├── data/ ← estado runtime (gitignored)
|
||||
├── tests/ ← pytest: tests/unit/ y tests/integration/
|
||||
├── docs/ ← este documento, manual_qa.md, futuro.md, superpowers/
|
||||
├── docs/ ← este documento, componentes.md, futuro.md, product-voice.md
|
||||
├── docker-compose.yml ← levanta core (API + UI HTMX en puerto 8000)
|
||||
├── Makefile ← install / test / test-all / lint / smoke / up / down
|
||||
├── README.md · ARCHITECTURE.md
|
||||
@@ -531,7 +530,8 @@ Forja no usa una sola base de datos; usa la herramienta adecuada para cada cosa.
|
||||
3. `runtime/nodes.py` y `runtime/graph.py` — el flujo de ejecución.
|
||||
4. `api/executions.py` — cómo se expone (invoke / approve / reject).
|
||||
5. `tests/integration/test_invoke_hitl.py` — el ciclo completo, en ~40 líneas.
|
||||
6. Levanta `docker compose up` y haz clic por las cinco páginas del dashboard.
|
||||
6. Levanta `docker compose up` y recorre la página única de arriba abajo:
|
||||
los 6 clicks de la demo del README cubren el ciclo completo.
|
||||
|
||||
---
|
||||
|
||||
@@ -540,4 +540,4 @@ Forja no usa una sola base de datos; usa la herramienta adecuada para cada cosa.
|
||||
Es un MVP. La detección de PII más fina (modelos grandes, español), autenticación,
|
||||
OpenTelemetry, multi-tenant, persistencia en Postgres, evaluadores LLM-as-judge,
|
||||
una cola de aprobaciones con SLA... están en el roadmap: [`docs/futuro.md`](futuro.md).
|
||||
El estado actual y cómo verificarlo: [`README.md`](../README.md) y [`docs/manual_qa.md`](manual_qa.md).
|
||||
El estado actual y cómo verificarlo: [`README.md`](../README.md).
|
||||
|
||||
Reference in New Issue
Block a user