From 2f990ea63681301e602836222ec7ba2e5ef1f93a Mon Sep 17 00:00:00 2001 From: Juan Marquez Date: Thu, 21 May 2026 20:19:18 +0200 Subject: [PATCH] added plan of transformation --- plan.html | 1901 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1901 insertions(+) create mode 100644 plan.html diff --git a/plan.html b/plan.html new file mode 100644 index 0000000..3ecc846 --- /dev/null +++ b/plan.html @@ -0,0 +1,1901 @@ + + + + + +AgentForge Trading — Plan de Ejecución + + + + + +
+

AgentForge Trading — Plan de Ejecución

+
Repurpose completo: plataforma de gobernanza de incidentes telecom → fábrica de agentes de trading
+
+ Creado: 2026-05-21 + Última actualización: 2026-05-21 + Rama: main +
+
+ + +
+
Tareas totales
52
+
Completadas
0
+
En progreso
0
+
Pendientes
52
+
+ +
+
+
+ + +
+
TODO Pendiente
+
IN-PROGRESS En progreso
+
DONE Completada
+
archivo.py Modificar
+
archivo.py Crear nuevo
+
archivo.py Eliminar
+
+ + +
+
+
FASE 0
+
Eliminación de artefactos telecom
+
+ 0 done + 3 todo +
+
Limpieza quirúrgica: solo los 3 puntos donde vive el dominio telecom. El resto de la plataforma es agnóstico. Sin dependencias de fase previa.
+
+ +
+ + +
+
+
P0.T1
+ todo +
+
+
Eliminar directorio agents/incident_analyzer/ completo
+
+ agents/incident_analyzer/index.yaml + agents/incident_analyzer/versions/v1.yaml + agents/incident_analyzer/versions/v2.yaml + agents/incident_analyzer/examples/01_sip_registration_drop.txt + agents/incident_analyzer/examples/02_mos_degradation_pool_sbc.txt + agents/incident_analyzer/examples/03_hss_capacity_active_active.txt +
+
+ Borrar el directorio completo. Los tests de fixtures tienen su propia copia en + tests/fixtures/agents/incident_analyzer/ que se actualizará en Fase 8. + No afecta a ningún import de código Python. +
+
+
+ + +
+
+
P0.T2
+ todo +
+
+
Reemplazar contenido de policies/default/versions/v1.yaml
+
+ policies/default/versions/v1.yaml +
+
+ Reescribir como política base genérica de trading (sustituye la telecom). Mantiene + los validadores genéricos: detect_pii, prompt_injection, + toxic_language. Cambia forbidden_topics a temas relevantes + para trading (["manipulación de mercado", "insider trading", "credenciales de broker"]). + El schema_match de output pasa a validar el output schema genérico de trading: + campos requeridos [proposed_actions] con subcampos [id, action, target, + risk_score, rollback_plan, requires_approval]. Cambia forbidden_action_keywords + a términos peligrosos de trading (["DROP TABLE", "rm -rf", "liquidate all", + "market order all"]). Reemplaza telco_safety_rules con + trading_safety_rules (se implementa en Fase 2). +
Depende de: P2.T1 (trading_safety_rules debe existir antes de que la política use el validador)
+
+
+
+ + +
+
+
P0.T3
+ todo +
+
+
Actualizar NeMo Guardrails allowed_keywords a terminología trading
+
+ core/src/agentforge_core/guardrails/factory.py +
+
+ En build_guardrail_engine(), la lista allowed_keywords del + NeMoGuardrailsEngine contiene términos telecom (sip, ims, cscf, sbc, + mos, hss). Reemplazar con terminología de trading: + ["equity", "forex", "fx", "portfolio", "signal", "position", "order", + "market", "risk", "hedge", "rebalance", "execution", "volatility", "spread"]. + NeMo actúa como guardrail de off-topic: si el input no menciona ningún keyword de + la lista, emite un warning (no bloquea). Esto evita que el agente procese peticiones + fuera de dominio. +
+
+
+ +
+
+ + +
+
+
FASE 1
+
Extensiones del modelo de dominio
+
+ 0 done + 3 todo +
+
Cambios mínimos a los Pydantic models y Settings. Las fases 3, 4 y 6 dependen de estas extensiones.
+
+ +
+ + +
+
+
P1.T1
+ todo +
+
+
domain/agent.py — añadir hitl_timeout_minutes y soporte "anthropic" en LLMConfig
+
+ core/src/agentforge_core/domain/agent.py +
+
+ Dos cambios: +
    +
  • En LLMConfig: cambiar el Literal["mock", "azure", "openai"] + a Literal["mock", "azure", "openai", "anthropic"].
  • +
  • En AgentDefinition: añadir + hitl_timeout_minutes: int | None = Field(default=None, ge=1, le=1440). + Cuando es None, el HITL no expira. Cuando tiene valor, el background checker + de Fase 6 auto-rechaza la ejecución si el operador no decide en ese tiempo. + Valor recomendado para producción: 30 min equities, 60 min FX.
  • +
+
+
+
+ + +
+
+
P1.T2
+ todo +
+
+
runtime/state.py — añadir campo dry_run al AgentState
+
+ core/src/agentforge_core/runtime/state.py +
+
+ Añadir dry_run: bool al TypedDict AgentState. + El orquestrador lo inyecta en el estado inicial al invocar. El nodo + finalize lo lee para omitir la emisión de approved_actions + y marcar el output con "dry_run": True. + El campo se inicializa a False en orchestrator.invoke() + para preservar retrocompatibilidad. +
+
+
+ + +
+
+
P1.T3
+ todo +
+
+
config.py — añadir ANTHROPIC_API_KEY y parámetros SLA/control
+
+ core/src/agentforge_core/config.py +
+
+ Añadir a Settings: +
    +
  • anthropic_api_key: str = ""
  • +
  • Actualizar el Literal de llm_provider y + llm_fallback_provider para incluir "anthropic".
  • +
  • hitl_sla_check_interval_seconds: int = 60 — frecuencia del background + checker que auto-rechaza HITLs expirados.
  • +
  • system_halted: bool = False — flag de kill switch (en memoria; + en producción se persistiría en Redis/DB, pero para MVP es suficiente).
  • +
+
+
+
+ +
+
+ + +
+
+
FASE 2
+
Nuevos validadores de trading
+
+ 0 done + 5 todo +
+
Núcleo de las reglas de seguridad específicas de trading. Sustituye telco_safety_rules. Sin dependencias de otras fases.
+
+ +
+ + +
+
+
P2.T1
+ todo +
+
+
validators.py — reemplazar telco_safety_rules con trading_safety_rules
+
+ core/src/agentforge_core/guardrails/validators.py +
+
+ Eliminar la función telco_safety_rules() completa (líneas 265–300). + Añadir trading_safety_rules(payload, config, trace_id, stage) con estas reglas + declarativas activables vía config: +
    +
  • no_order_without_stop_loss: para cada acción con + action in ["BUY","SELL","SHORT","COVER"], el campo rollback_plan + no puede ser vacío, "n/a" ni "none". Bloquea si incumple.
  • +
  • no_leveraged_action_without_hedge: si la acción tiene + "leverage" o "margin" en su descripción, debe existir una acción + paralela con action="HEDGE" en el mismo output. Bloquea si incumple.
  • +
  • no_mass_liquidation_without_tranche: si target contiene + "all", "*" o "portfolio" y la acción es + SELL/CLOSE, el rollback_plan debe mencionar "tranche" + o "tramo". Bloquea si incumple.
  • +
  • require_notional_on_trade_actions: BUY/SELL deben tener el campo + "notional_usd" presente y ser un número positivo. Severity configurable.
  • +
+ Misma firma que el resto: devuelve list[GuardrailViolation]. +
+
+
+ + +
+
+
P2.T2
+ todo +
+
+
validators.py — añadir position_size_limit
+
+ core/src/agentforge_core/guardrails/validators.py +
+
+ Nueva función position_size_limit(payload, config, trace_id, stage). + Config keys: +
    +
  • max_notional_usd: float — si cualquier acción tiene + notional_usd mayor que este límite, bloquea.
  • +
  • max_pct_adv: float (opcional, future) — % máximo del Average Daily + Volume. Si no hay dato de ADV en el payload, se ignora la validación.
  • +
  • severity_on_breach: "block" | "warning" — default "block".
  • +
+ Itera payload.get("proposed_actions", []), extrae + notional_usd de cada acción (si presente), compara contra el límite. + El mensaje de violación incluye el instrumento, el notional real y el límite configurado. +
Nota: Si notional_usd no está presente en la acción, el validador emite + un warning indicando que el campo es requerido (nunca bloquea por ausencia, + ese chequeo es de trading_safety_rules). +
+
+
+ + +
+
+
P2.T3
+ todo +
+
+
validators.py — añadir forbidden_instruments
+
+ core/src/agentforge_core/guardrails/validators.py +
+
+ Nueva función forbidden_instruments(payload, config, trace_id, stage). + Config keys: +
    +
  • instruments: list[str] — lista de tickers/símbolos bloqueados + (e.g. ["GME", "AMC", "BBBY"] para restricted list, o instrumentos + en embargo regulatorio).
  • +
  • severity_on_match: "block" | "warning" — default "block".
  • +
+ Busca en el campo target de cada acción propuesta. La comparación es + case-insensitive. Si el ticker está en la lista, bloquea y reporta cuál instrumento + y qué acción lo referenciaba. +
+
+
+ + +
+
+
P2.T4
+ todo +
+
+
validators.py — añadir market_hours_check
+
+ core/src/agentforge_core/guardrails/validators.py +
+
+ Nueva función market_hours_check(payload, config, trace_id, stage). + Config keys: +
    +
  • asset_class: "equity" | "fx" | "crypto" — crypto nunca bloquea + (24/7); equity bloquea fuera de horario; FX emite warning (mercado casi 24/5).
  • +
  • timezone: str — e.g. "America/New_York" para NYSE/NASDAQ, + "Europe/London" para LSE. Default "America/New_York".
  • +
  • severity_outside_hours: "block" | "warning" | "info" — default + "warning".
  • +
+ Lógica: para equity, horario NYSE es 09:30–16:00 ET de lunes a viernes, + excluidas holidays principales (usa datetime.now(tz)). Para fx, + solo bloquear fin de semana. Para crypto, nunca bloquear. +
Nota: Usa la librería estándar zoneinfo (Python 3.9+, ya en el env). + No añadir dependencias externas. +
Este validador actúa sobre el input (momento de la invocación), no sobre + el output. Se registra en INPUT_VALIDATORS. +
+
+
+ + +
+
+
P2.T5
+ todo +
+
+
guardrails_ai.py — actualizar registries INPUT/OUTPUT con nuevos validadores
+
+ core/src/agentforge_core/guardrails/guardrails_ai.py +
+
+ Actualizar los dos diccionarios en guardrails_ai.py: +
    +
  • En INPUT_VALIDATORS: añadir "market_hours_check": market_hours_check.
  • +
  • En OUTPUT_VALIDATORS: quitar "telco_safety_rules": telco_safety_rules, + añadir "trading_safety_rules": trading_safety_rules, + "position_size_limit": position_size_limit, + "forbidden_instruments": forbidden_instruments.
  • +
+ Actualizar el import de validators al inicio del archivo para + referenciar las funciones nuevas y quitar telco_safety_rules. +
+
+
+ +
+
+ + +
+
+
FASE 3
+
Proveedor LLM Anthropic / Claude
+
+ 0 done + 4 todo +
+
Añadir Claude como proveedor LLM con prompt caching. Los system prompts de trading son largos y estables → ahorro ~90% en cache hits. Depende de P1.T1 (Literal) y P1.T3 (ANTHROPIC_API_KEY en Settings).
+
+ +
+ + +
+
+
P3.T1
+ todo +
+
+
llm/anthropic.py — nuevo proveedor con prompt caching
+
+ core/src/agentforge_core/llm/anthropic.py +
+
+ Crear clase AnthropicProvider que implementa el LLMProvider Protocol. + Puntos clave: +
    +
  • Usar SDK oficial anthropic con cliente AsyncAnthropic.
  • +
  • Prompt caching: el system prompt se envía con + cache_control: {"type": "ephemeral"} en el campo system + de la API de Messages. Esto activa el cache de 5 minutos de Anthropic. + Los system prompts de trading (instrucciones de análisis, reglas de riesgo) son + largos y no cambian entre invocaciones del mismo agente → máximo aprovechamiento.
  • +
  • Mapear list[Message] al formato de la API: + el primer mensaje con role="system" va en el campo system + (con cache_control), el resto van en messages.
  • +
  • Modelos soportados: claude-sonnet-4-6, claude-opus-4-7, + claude-haiku-4-5-20251001. Default en agentes: claude-sonnet-4-6.
  • +
  • Rellenar CompletionResult.tokens_in y tokens_out desde + response.usage. Incluir también cache_read_input_tokens y + cache_creation_input_tokens en el log de structlog para observabilidad + de costes.
  • +
  • El campo model en CompletionResult se toma de + response.model.
  • +
+ El constructor recibe api_key: str y model: str. +
+
+
+ + +
+
+
P3.T2
+ todo +
+
+
llm/factory.py — registrar proveedor anthropic
+
+ core/src/agentforge_core/llm/factory.py +
+
+ Añadir al match settings.llm_provider: + case "anthropic": return AnthropicProvider(api_key=settings.anthropic_api_key, model=settings.anthropic_model). +
Añadir anthropic_model: str = "claude-sonnet-4-6" a Settings + (en P1.T3 se puede añadir junto con la API key). +
+
+
+ + +
+
+
P3.T3
+ todo +
+
+
core/requirements.txt — añadir dependencia anthropic
+
+ core/requirements.txt +
+
+ Añadir anthropic>=0.40,<1.0. + Verificar que no hay conflictos con las dependencias existentes (httpx, pydantic). + El SDK de Anthropic usa httpx internamente, que ya está en requirements; + asegurarse de que el rango de versiones es compatible. +
+
+
+ + +
+
+
P3.T4
+ todo +
+
+
.env.example — añadir ANTHROPIC_API_KEY y ANTHROPIC_MODEL
+
+ .env.example +
+
+ Añadir sección: + # Anthropic / Claude (solo si LLM_PROVIDER=anthropic)
+ ANTHROPIC_API_KEY=
+ ANTHROPIC_MODEL=claude-sonnet-4-6
+ También añadir HITL_SLA_CHECK_INTERVAL_SECONDS=60. + Actualizar el comentario de LLM_PROVIDER para incluir anthropic. +
+
+
+ +
+
+ + +
+
+
FASE 4
+
Agentes de trading — definiciones YAML
+
+ 0 done + 12 todo +
+
Cuatro agentes con sus index, versión v1 y ejemplos de escenarios. Solo ficheros YAML y .txt, sin código Python. Depende de Fase 2 (los validadores de las políticas deben existir) y Fase 5 (las políticas deben existir para referenciarlas).
+
+ +
+ + +
+
+
P4.T1
+ todo +
+
+
signal_analyzer — index.yaml
+
+ agents/signal_analyzer/index.yaml +
+
+ Estructura idéntica a incident_analyzer/index.yaml. Versión activa: v1. + Campos: name: signal_analyzer, lista de versiones con id/hash/author/message/created_at, + active_version: v1. +
+
+
+ + +
+
+
P4.T2
+ todo +
+
+
signal_analyzer — versions/v1.yaml
+
+ agents/signal_analyzer/versions/v1.yaml +
+
+ Campos clave: +
    +
  • purpose: analiza señales de mercado (precio, volumen, indicadores técnicos, + contexto macro) y propone entradas/salidas con análisis de riesgo.
  • +
  • guardrails: [trading_equity]
  • +
  • risk_threshold_for_hitl: 3 (más conservador: risk ≥ 3 requiere aprobación).
  • +
  • hitl_timeout_minutes: 30
  • +
  • llm.provider: mock, model: claude-sonnet-4-6, + temperature: 0.1 (determinismo en señales).
  • +
  • system_prompt: Eres un analista cuantitativo senior. Recibes datos de mercado. + Devuelves JSON con: instrument, direction (BUY/SELL/HOLD), + rationale (string), confidence (0.0-1.0), timeframe + (intraday/swing/position), proposed_actions (lista con id, action, target, + quantity, notional_usd, risk_score 1-5, stop_loss, rollback_plan, requires_approval). + Reglas: nunca proponer sin stop_loss; acciones >$500k requieren requires_approval=true; + no proponer sobre instrumentos con spreads anómalos sin avisarlo en rationale.
  • +
  • output_schema: JSON Schema completo de lo anterior.
  • +
+
+
+
+ + +
+
+
P4.T3
+ todo +
+
+
signal_analyzer — 3 escenarios de ejemplo
+
+ agents/signal_analyzer/examples/01_tech_earnings_breakout.txt + agents/signal_analyzer/examples/02_macro_risk_off_session.txt + agents/signal_analyzer/examples/03_fx_momentum_divergence.txt +
+
+ Escenarios realistas de trading para usar en la demo del dashboard. +
    +
  • 01: Acción tech supera estimaciones de earnings; RSI en 65; precio rompe + resistencia; pedir entrada larga.
  • +
  • 02: VIX spike al 28; flows defensivos; sesión risk-off; evaluar reducción + de exposición en renta variable.
  • +
  • 03: EUR/USD con divergencia RSI bearish en H4; momentum negativo tras + datos de inflación; candidato a entrada corta con gestión del riesgo.
  • +
+
+
+
+ + +
+
+
P4.T4
+ todo +
+
+
portfolio_rebalancer — index.yaml
+
+ agents/portfolio_rebalancer/index.yaml +
+
+ Misma estructura. active_version: v1. +
+
+
+ + +
+
+
P4.T5
+ todo +
+
+
portfolio_rebalancer — versions/v1.yaml
+
+ agents/portfolio_rebalancer/versions/v1.yaml +
+
+
    +
  • purpose: recibe snapshot de cartera (posiciones actuales + pesos objetivo) + y propone órdenes de rebalanceo optimizando coste de transacción.
  • +
  • guardrails: [trading_equity]
  • +
  • risk_threshold_for_hitl: 2 — casi todo requiere aprobación humana; las + operaciones de cartera afectan múltiples posiciones simultáneamente.
  • +
  • hitl_timeout_minutes: 60
  • +
  • temperature: 0.0 — rebalanceo es matemático, máximo determinismo.
  • +
  • Output schema incluye: rebalance_summary (delta total en USD, coste + estimado de transacción), proposed_actions (una por instrumento afectado).
  • +
+
+
+
+ + +
+
+
P4.T6
+ todo +
+
+
portfolio_rebalancer — 2 escenarios de ejemplo
+
+ agents/portfolio_rebalancer/examples/01_quarterly_rebalance.txt + agents/portfolio_rebalancer/examples/02_tactical_tilt_bonds.txt +
+
+ 01: rebalanceo trimestral de una cartera 60/40 que ha derivado a 72/28 por el + rally de renta variable. 02: tilt táctico defensivo incrementando bonos al 45% + por entorno macro adverso. +
+
+
+ + +
+
+
P4.T7
+ todo +
+
+
risk_monitor — index.yaml + versions/v1.yaml + ejemplos
+
+ agents/risk_monitor/index.yaml + agents/risk_monitor/versions/v1.yaml + agents/risk_monitor/examples/01_drawdown_alert.txt + agents/risk_monitor/examples/02_concentration_risk.txt +
+
+ Monitoriza métricas de riesgo (VaR, drawdown, concentración, beta) y propone coberturas o + reducciones de posición. risk_threshold_for_hitl: 3, + hitl_timeout_minutes: 45. + Output schema: risk_summary (VaR 1d, max_drawdown_pct, concentration_top3), + alerts (lista de alertas activas con severity), proposed_actions + (hedges, reducciones, stops). +
+
+
+ + +
+
+
P4.T8
+ todo +
+
+
execution_planner — index.yaml + versions/v1.yaml + ejemplos
+
+ agents/execution_planner/index.yaml + agents/execution_planner/versions/v1.yaml + agents/execution_planner/examples/01_large_block_twap.txt + agents/execution_planner/examples/02_cross_venue_split.txt +
+
+ Descompone órdenes grandes en planes de ejecución que minimizan market impact. + risk_threshold_for_hitl: 4 (la aprobación de la orden ya vino del agente + anterior; aquí solo se planifica la ejecución). Output schema: execution_strategy + (TWAP/VWAP/IS/POV), slices (lista de sub-órdenes con timestamp, qty, venue), + estimated_market_impact_bps, proposed_actions. +
+
+
+ + + +
+
+
P4.T9
+ todo +
+
+
Verificar que todos los agentes cargan correctamente en el registry
+
+ core/src/agentforge_core/registry/repository.py +
+
+ Arrancar el core con docker compose up core y hacer + GET /agents. Verificar que los 4 nuevos agentes aparecen en el listado + y que sus versiones se pueden leer correctamente. Comprobar que el hash de contenido + se calcula sin errores. + No requiere cambio de código — es validación funcional. +
+
+
+ +
+
+ + +
+
+
FASE 5
+
Políticas de trading — definiciones YAML
+
+ 0 done + 7 todo +
+
Una política por asset class más la actualización de la default. Depende de Fase 2 (los validadores deben estar registrados).
+
+ +
+ + +
+
+
P5.T1
+ todo +
+
+
policies/trading_equity/ — index.yaml + versions/v1.yaml
+
+ policies/trading_equity/index.yaml + policies/trading_equity/versions/v1.yaml +
+
+ Política para renta variable (NYSE, NASDAQ, IBEX…). Validators: +
Input: detect_pii (block EMAIL, IBAN), + prompt_injection (block), market_hours_check + (asset_class: equity, tz: America/New_York, severity: warning), + forbidden_topics (block: ["insider", "material non-public", + "manipulación de mercado"]). +
Output: schema_match (block, schema validando + proposed_actions con campos de trading), pii_leakage (block), + forbidden_action_keywords (block: ["liquidate all", "margin call ignore", + "DROP TABLE"]), trading_safety_rules (block: all rules), + position_size_limit (block, max_notional_usd: 1000000), + forbidden_instruments (block: restricted list de ejemplo), +
on_validator_error: fail_closed +
+
+
+ + +
+
+
P5.T2
+ todo +
+
+
policies/trading_fx/ — index.yaml + versions/v1.yaml
+
+ policies/trading_fx/index.yaml + policies/trading_fx/versions/v1.yaml +
+
+ Política para FX (EURUSD, GBPUSD, USDJPY…). Diferencias respecto a equity: + market_hours_check con asset_class: fx (solo bloquea + en weekend), sin límite de horario intradía. El límite de notional es mayor: + max_notional_usd: 5000000 (FX es mercado más líquido). + trading_safety_rules activa solo + no_order_without_stop_loss y no_leveraged_action_without_hedge. +
+
+
+ + +
+
+
P5.T3
+ todo +
+
+
policies/trading_crypto/ — index.yaml + versions/v1.yaml
+
+ policies/trading_crypto/index.yaml + policies/trading_crypto/versions/v1.yaml +
+
+ Política para crypto (BTC, ETH, SOL…). Sin restricción de horario (24/7). + Límites más conservadores: max_notional_usd: 250000 (mayor volatilidad). + market_hours_check ausente o con asset_class: crypto + (nunca bloquea). forbidden_instruments incluye tokens con + restricciones regulatorias. +
+
+
+ + +
+
+
P5.T4
+ todo +
+
+
policies/default/ — actualizar v1.yaml (ya referenciado en P0.T2)
+
+ policies/default/versions/v1.yaml +
+
+ Completar la tarea P0.T2 una vez que P2.T1 esté done (trading_safety_rules existe). + La política default se convierte en la política base de trading genérica: + usa todos los validadores de trading pero con límites permisivos. Es la fallback para + agentes que no especifiquen política de asset class concreta. +
Nota: Esta tarea es la finalización formal de P0.T2. +
+
+
+ + +
+
+
P5.T5
+ todo +
+
+
Verificar que las 3 políticas nuevas cargan en el PolicyStore
+
+ core/src/agentforge_core/registry/policy_store.py +
+
+ Hacer GET /policies y comprobar que aparecen + trading_equity, trading_fx, trading_crypto. + Hacer GET /policies/trading_equity y verificar que los validadores + se deserializan correctamente sin errores de Pydantic. +
+
+
+ +
+
+ + +
+
+
FASE 6
+
Extensiones de API y runtime
+
+ 0 done + 7 todo +
+
Tres features nuevas: modo dry-run, kill switch y SLA HITL. Depende de Fase 1 (hitl_timeout_minutes en AgentDefinition, dry_run en AgentState).
+
+ +
+ + +
+
+
P6.T1
+ todo +
+
+
api/executions.py — añadir dry_run a InvokeRequest y propagarlo
+
+ core/src/agentforge_core/api/executions.py +
+
+ Añadir dry_run: bool = False a InvokeRequest. + En el handler invoke_agent(), añadir dry_run=body.dry_run + a la llamada orchestrator.invoke(). El orquestrador inyectará el valor + en el estado inicial del grafo (initial["dry_run"] = dry_run). + Si dry_run=True, la ejecución NO se escribe en el JSONL de historial + (solo en el checkpointer temporal). Añadir campo dry_run: bool + a AgentExecution en domain/execution.py para que el + response body refleje el modo. +
+
+
+ + +
+
+
P6.T2
+ todo +
+
+
runtime/nodes.py — nodo finalize respeta dry_run
+
+ core/src/agentforge_core/runtime/nodes.py +
+
+ En build_node_finalize(), añadir al inicio: + if state.get("dry_run"): final_output = {**parsed, "approved_actions": final_actions, "dry_run": True} + El comportamiento es idéntico excepto que el output está marcado con + "dry_run": True. El orquestrador y la API usarán ese flag para + no escribir la ejecución en el log append-only de produción. + También se puede añadir un step en el decision_path indicando + dry_run=True para trazabilidad. +
+
+
+ + +
+
+
P6.T3
+ todo +
+
+
api/control.py — nuevo router con kill switch
+
+ core/src/agentforge_core/api/control.py +
+
+ Crear router con dos endpoints: +
    +
  • GET /control/status: devuelve {"halted": bool, "pending_hitl_count": int, + "message": str}. Lee el estado global del sistema.
  • +
  • POST /control/halt: activa el kill switch. Comportamiento: +
      +
    1. Establece un flag global system_halted = True en el estado de la app + (variable de módulo o en Settings — MVP puede ser un módulo singleton).
    2. +
    3. Lee execution_index.json, encuentra todas las ejecuciones en + awaiting_approval y las rechaza automáticamente con reason + "kill_switch_activated" usando orchestrator.resume().
    4. +
    5. Devuelve {"halted": true, "auto_rejected": N}.
    6. +
    +
  • +
  • POST /control/resume: desactiva el kill switch (restaura operación normal).
  • +
+ En el handler invoke_agent() de executions.py, añadir una + comprobación al inicio: si system_halted, devolver 503. +
+
+
+ + +
+
+
P6.T4
+ todo +
+
+
main.py — montar router de control y añadir lifespan con SLA checker
+
+ core/src/agentforge_core/main.py +
+
+ Dos cambios: +
    +
  • Importar y montar control.router con prefix /control, + tag ["control"].
  • +
  • Añadir función lifespan con asyncio.create_task para + el background checker de SLA HITL. La tarea corre en bucle cada + settings.hitl_sla_check_interval_seconds segundos.
  • +
+ El lifespan de FastAPI se declara con el context manager async: + @asynccontextmanager async def lifespan(app): task = asyncio.create_task(sla_checker()); yield; task.cancel(). +
+
+
+ + +
+
+
P6.T5
+ todo +
+
+
SLA HITL checker — función background task
+
+ core/src/agentforge_core/runtime/sla.py +
+
+ Crear módulo runtime/sla.py con la función async + run_hitl_sla_checker(settings, registry, policies, orchestrator). + Algoritmo en cada tick: +
    +
  1. Leer execution_index.json.
  2. +
  3. Para cada trace_id, obtener snapshot del checkpointer.
  4. +
  5. Si status es awaiting_approval: +
      +
    • Obtener agent_def del registry.
    • +
    • Si agent_def.hitl_timeout_minutes no es None: +
        +
      • Comparar execution.started_at + timedelta(minutes=hitl_timeout_minutes) + con datetime.now(UTC).
      • +
      • Si expirado: llamar orchestrator.resume(decision={"approved_action_ids": [], + "rejected": True, "reason": "hitl_sla_expired"}) y escribir en JSONL.
      • +
      +
    • +
    +
  6. +
+ Logear cada auto-rechazo con structlog a nivel WARNING incluyendo trace_id y agent_name. +
+
+
+ + +
+
+
P6.T6
+ todo +
+
+
runtime/orchestrator.py — propagar dry_run en invoke()
+
+ core/src/agentforge_core/runtime/orchestrator.py +
+
+ Añadir parámetro dry_run: bool = False a invoke(). + Incluirlo en el dict initial: initial["dry_run"] = dry_run. + No se propaga a resume() — el dry_run se decide en la invocación inicial + y queda embebido en el estado del checkpointer. +
+
+
+ + +
+
+
P6.T7
+ todo +
+
+
Smoke test manual de dry-run y kill switch
+
+ docs/manual_qa.md +
+
+ Actualizar docs/manual_qa.md con los pasos de prueba manual: +
    +
  • Dry-run: invocar signal_analyzer con dry_run=true, + verificar que el output tiene "dry_run": true y que NO aparece en + el historial (GET /executions no lo lista).
  • +
  • Kill switch: invocar agente, pausar en HITL, activar POST /control/halt, + verificar que la ejecución pasa a failed con error kill_switch_activated, + verificar que intentar invocar devuelve 503. Luego POST /control/resume y + verificar que vuelve a funcionar.
  • +
  • SLA HITL: configurar hitl_timeout_minutes: 1 en un agente de test, + invocar, esperar 65 segundos, verificar auto-rechazo.
  • +
+
+
+
+ +
+
+ + +
+
+
FASE 7
+
Dashboard — actualizaciones de UI
+
+ 0 done + 5 todo +
+
Mayoritariamente cosmético. El dashboard es agnóstico de dominio — solo cambiar strings y añadir campos de trading en la vista de aprobaciones. Sin dependencias de código.
+
+ +
+ + +
+
+
P7.T1
+ todo +
+
+
Página Ejecutar — actualizar strings y añadir checkbox dry-run
+
+ dashboard/src/agentforge_dashboard/pages/2_▶️_Ejecutar.py +
+
+ Cambios: +
    +
  • st.title: "▶️ Ejecutar Agente" → sin cambio (genérico).
  • +
  • st.text_area label: "Descripción del incidente" + → "Señal de mercado / Instrucción de trading".
  • +
  • placeholder: actualizar con ejemplo de señal de trading.
  • +
  • Añadir dry_run = st.checkbox("🔬 Modo simulación (dry-run)", value=False) + antes del botón de invocar.
  • +
  • Pasar {"input": user_input, "dry_run": dry_run} al client.
  • +
  • Si execution["final_output"]["dry_run"] es True, mostrar + badge amarillo "SIMULACIÓN — sin efecto real".
  • +
+
+
+
+ + +
+
+
P7.T2
+ todo +
+
+
Página Aprobaciones — mostrar campos de trading prominentemente
+
+ dashboard/src/agentforge_dashboard/pages/3_🤝_Aprobaciones.py +
+
+ En el loop de acciones propuestas, si la acción tiene campos de trading, mostrarlos: +
    +
  • notional_usd: si presente, mostrar en grande con color según tamaño + (<100K verde, 100K–1M amarillo, >1M rojo).
  • +
  • stop_loss: mostrar si presente.
  • +
  • quantity: mostrar si presente.
  • +
  • asset_class: badge de tipo de activo si presente.
  • +
+ Estos campos son opcionales en el modelo existente — mostrarlos solo si existen + (no romper compatibilidad si faltan). +
+
+
+ + +
+
+
P7.T3
+ todo +
+
+
app.py — actualizar título y caption de la aplicación
+
+ dashboard/src/agentforge_dashboard/app.py +
+
+ Cambiar st.set_page_config title a "AgentForge Trading" + y el icono a 📈. Actualizar la página principal (si existe contenido) para describir + la plataforma como fábrica de agentes de trading. +
+
+
+ + +
+
+
P7.T4
+ todo +
+
+
main.py (FastAPI) — actualizar title y description
+
+ core/src/agentforge_core/main.py +
+
+ En create_app(): title="AgentForge Trading", + description="Plataforma de gobernanza de agentes IA para trading — API REST.", + version="0.2.0". Esto actualiza la UI de /docs de Swagger. + (Este cambio puede hacerse junto con P6.T4 que también modifica main.py.) +
+
+
+ + +
+
+
P7.T5
+ todo +
+
+
Página Políticas — verificar que muestra las nuevas políticas trading
+
+ dashboard/src/agentforge_dashboard/pages/5_📐_Politicas.py +
+
+ Verificación funcional sin cambio de código. Abrir la página, confirmar que + trading_equity, trading_fx, trading_crypto + aparecen en el selector y que sus validadores se muestran correctamente. + Si hay algún problema de renderizado con los nuevos tipos de validador, ajustar + la visualización aquí. +
+
+
+ +
+
+ + +
+
+
FASE 8
+
Suite de tests
+
+ 0 done + 9 todo +
+
Actualizar fixtures y tests existentes. Añadir tests para features nuevas. Goal: make test-all verde con todos los cambios del repurpose. Depende de todas las fases de código anteriores.
+
+ +
+ + +
+
+
P8.T1
+ todo +
+
+
Actualizar fixtures de agente (tests/fixtures)
+
+ tests/fixtures/agents/incident_analyzer/ + tests/fixtures/agents/signal_analyzer/index.yaml + tests/fixtures/agents/signal_analyzer/versions/v1.yaml + tests/fixtures/agents/test_agent/versions/v1.yaml +
+
+
    +
  • Eliminar tests/fixtures/agents/incident_analyzer/.
  • +
  • Crear tests/fixtures/agents/signal_analyzer/ con index y v1 (copia + simplificada de los YAML de producción, con provider: mock).
  • +
  • Actualizar test_agent/versions/v1.yaml: cambiar el output_schema + y system_prompt para que sean de trading (los tests que usan test_agent + deben funcionar con el nuevo schema de validación de políticas trading).
  • +
+
+
+
+ + +
+
+
P8.T2
+ todo +
+
+
Actualizar fixtures de política (tests/fixtures)
+
+ tests/fixtures/policies/default/versions/v1.yaml + tests/fixtures/policies/test_policy/versions/v1.yaml + tests/fixtures/policies/trading_equity/index.yaml + tests/fixtures/policies/trading_equity/versions/v1.yaml +
+
+ Sincronizar las fixtures de política con los YAMLs de producción actualizados. + La fixture test_policy puede simplificarse a solo schema_match + para mantener los tests unitarios simples. Añadir fixture trading_equity + para los tests de integración que usan signal_analyzer. +
+
+
+ + +
+
+
P8.T3
+ todo +
+
+
Tests de integración — actualizar para usar signal_analyzer
+
+ tests/integration/conftest.py + tests/integration/test_invoke_happy_path.py + tests/integration/test_invoke_hitl.py + tests/integration/test_invoke_pii_block.py + tests/integration/test_invoke_resume_after_restart.py +
+
+ Reemplazar todas las referencias a incident_analyzer y al output schema + telecom con signal_analyzer y el output schema de trading. + El MockProvider devuelve un JSON hardcodeado — actualizar el mock response + en conftest.py para que devuelva el formato de señal de trading: + {"instrument": "AAPL", "direction": "BUY", "rationale": "...", "confidence": 0.8, + "proposed_actions": [{"id": "a1", "action": "BUY", "target": "AAPL", + "quantity": 100, "notional_usd": 18500, "risk_score": 3, + "stop_loss": "18000", "rollback_plan": "Vender si cae -5%", "requires_approval": false}]}. + Los tests de PII, HITL y restart no necesitan cambios lógicos, solo las fixtures. +
+
+
+ + +
+
+
P8.T4
+ todo +
+
+
Tests unitarios — nuevos validadores de trading
+
+ tests/unit/test_validators_trading.py +
+
+ Crear fichero con tests para los 4 validadores nuevos: +
    +
  • trading_safety_rules: test happy path (con stop_loss), test que bloquea + sin stop_loss, test que bloquea mass liquidation sin tranche, test leveraged sin hedge.
  • +
  • position_size_limit: test que pasa si notional < max, + test que bloquea si notional > max, test que emite warning si notional ausente.
  • +
  • forbidden_instruments: test que pasa con ticker permitido, + test que bloquea con ticker restringido (case-insensitive).
  • +
  • market_hours_check: mockear datetime.now para simular + dentro/fuera de horario para equity, fx, crypto.
  • +
+
+
+
+ + +
+
+
P8.T5
+ todo +
+
+
Tests unitarios — domain/agent.py con hitl_timeout_minutes
+
+ tests/unit/test_domain_agent.py +
+
+ Añadir casos: AgentDefinition con hitl_timeout_minutes=None + (default), con valor válido (30), con valor fuera de rango (0 falla, 1441 falla). + Verificar que el Literal de LLMConfig.provider acepta "anthropic". +
+
+
+ + +
+
+
P8.T6
+ todo +
+
+
Test de integración — dry-run
+
+ tests/integration/test_invoke_dry_run.py +
+
+ Test que invoca signal_analyzer con dry_run=True: +
    +
  1. El status debe ser completed.
  2. +
  3. El final_output debe contener "dry_run": True.
  4. +
  5. El historial (executions.jsonl) no debe contener la ejecución.
  6. +
  7. La ejecución SÍ debe aparecer en el índice de memoria del checkpointer + (temporalmente).
  8. +
+
+
+
+ + +
+
+
P8.T7
+ todo +
+
+
Test unitario — kill switch (api/control.py)
+
+ tests/unit/test_api_control.py +
+
+ Tests con FastAPI TestClient: +
    +
  • GET /control/status devuelve {"halted": false, ...} por defecto.
  • +
  • POST /control/halt cambia el estado a halted: true.
  • +
  • Tras halt, POST /agents/test_agent/invoke devuelve 503.
  • +
  • POST /control/resume restaura operación normal.
  • +
+
+
+
+ + +
+
+
P8.T8
+ todo +
+
+
Actualizar tests unitarios existentes que referencian telco
+
+ tests/unit/test_guardrails_ai.py + tests/unit/test_runtime_nodes.py + tests/unit/test_runtime_orchestrator.py +
+
+ Eliminar cualquier referencia a telco_safety_rules en + test_guardrails_ai.py. Actualizar los mocks de AgentDefinition + en test_runtime_nodes.py y test_runtime_orchestrator.py + para usar el nuevo schema de trading (los tests de lógica de nodos son agnósticos + del dominio — solo necesitan que el fixture sea válido). +
+
+
+ + +
+
+
P8.T9
+ todo +
+
+
make test-all verde — validación final
+
+ Makefile +
+
+ Ejecutar make test-all (unit + integration) y make lint + (ruff + mypy). Goal: 0 errores, 0 warnings de tipo. Si hay fallos residuales, + resolverlos antes de marcar la fase completa. Esta tarea actúa como gate de calidad + para todo el trabajo anterior. +
+
+
+ +
+
+ + +
+
+
FASE 9
+
Documentación
+
+ 0 done + 3 todo +
+
Actualizar README, ARCHITECTURE y roadmap. Los docs internos (explicacion.md, componentes.md) quedan como trabajo futuro si el usuario lo solicita. Sin dependencias técnicas — puede hacerse en paralelo.
+
+ +
+ + +
+
+
P9.T1
+ todo +
+
+
README.md — actualizar para contexto trading
+
+ README.md +
+
+ Cambios: +
    +
  • Título y subtítulo: enfocado en trading.
  • +
  • Sección "¿Por qué?": adaptar al contexto de riesgo financiero y compliance.
  • +
  • Demo guiada: actualizar para usar signal_analyzer y los nuevos escenarios.
  • +
  • Tabla de capacidades: añadir dry-run, kill switch, SLA HITL, Anthropic provider.
  • +
  • Guardrails de trading: mencionar los 4 nuevos validadores.
  • +
  • Sección de agentes disponibles: listar los 4 agentes con su propósito.
  • +
+
+
+
+ + +
+
+
P9.T2
+ todo +
+
+
ARCHITECTURE.md — actualizar diagrama y descripciones
+
+ ARCHITECTURE.md +
+
+ Actualizar el diagrama ASCII para incluir el nuevo componente control + (kill switch), el background SLA checker, y los 4 nuevos tipos de agentes. + Añadir sección "Flujo de una orden de trading" que muestre cómo los guardrails + de trading se aplican en el grafo LangGraph. +
+
+
+ + +
+
+
P9.T3
+ todo +
+
+
docs/futuro.md — actualizar roadmap para trading
+
+ docs/futuro.md +
+
+ Reescribir el roadmap orientado a trading: +
    +
  • Integración con market data feeds (Polygon.io, Refinitiv).
  • +
  • Context injection: posiciones actuales de cartera en el prompt vía RAG.
  • +
  • Cuatro ojos: segundo approver para operaciones >$1M.
  • +
  • P&L attribution por agente/decisión.
  • +
  • Persistencia en Postgres + pgvector para alta disponibilidad.
  • +
  • OpenTelemetry: latencias por nodo, métricas de guardrail activations.
  • +
  • Stress testing: ejecutar agentes contra series históricas (2020 COVID crash, etc.).
  • +
  • Compliance reports: exportar audit trail en formato EMIR/MiFID II.
  • +
+
+
+
+ +
+
+ + +
+
+
FASE 10
+
Configuración e infraestructura
+
+ 0 done + 2 todo +
+
Cambios menores a pyproject.toml y verificación del smoke test Docker. Las dependencias de requirements.txt ya se cubren en Fase 3.
+
+ +
+ + +
+
+
P10.T1
+ todo +
+
+
pyproject.toml — actualizar descripción del proyecto
+
+ pyproject.toml +
+
+ Cambiar description de "Plataforma profesional de gobernanza de agentes IA" + a "Plataforma de gobernanza de agentes IA para trading — fábrica de agentes con guardrails, HITL y auditoría". + Sin cambios en dependencias ni en la configuración de herramientas. +
+
+
+ + +
+
+
P10.T2
+ todo +
+
+
make smoke — verificar que el stack Docker completo arranca
+
+ docker-compose.yml + Makefile +
+
+ Ejecutar make smoke (docker compose up + curl /health) con todos los + cambios del repurpose. Verificar: +
    +
  • Core arranca sin errores de arranque (guardrails registrados, NeMo keywords).
  • +
  • Dashboard arranca y carga los nuevos agentes.
  • +
  • GET /agents devuelve los 4 agentes de trading.
  • +
  • GET /policies devuelve las 3 políticas de trading + default.
  • +
  • GET /control/status devuelve {"halted": false, ...}.
  • +
+
+
+
+ +
+
+ + +
+
+

Orden de ejecución recomendado

+
+

Las fases son mayoritariamente independientes pero tienen algunas dependencias duras:

+
    +
  1. Fase 2 debe completarse antes que Fase 5 (los validadores deben existir para que las políticas los usen en los YAML — validación en arranque) y antes de finalizar P0.T2.
  2. +
  3. Fase 1 (extensiones de dominio) debe completarse antes que Fases 6 (dry_run en state, hitl_timeout_minutes en AgentDefinition).
  4. +
  5. Fase 3 (Anthropic) depende de P1.T1 y P1.T3.
  6. +
  7. Fases 4 y 5 son mayoritariamente YAML — pueden hacerse en cualquier momento después de Fase 2.
  8. +
  9. Fase 8 (tests) debe hacerse tras completar todas las fases de código (0–7).
  10. +
  11. Fases 7, 9 y 10 son independientes y pueden hacerse en paralelo con las demás.
  12. +
+

+ Secuencia óptima por sesión: + Fase 0 → Fases 1+2 (juntas, sin dep entre sí) → Fases 3+4+5 (paralelas) → Fase 6 → Fase 7 → Fase 8 (gate de calidad) → Fases 9+10. +

+
+
+ + +
+

⚠️ Invariantes — no modificar

+
+
    +
  • runtime/graph.py — grafo LangGraph, topología de nodos
  • +
  • runtime/checkpointer.py — persistencia SQLite de ejecuciones
  • +
  • runtime/orchestrator.py — lógica de invoke/resume/snapshot (solo añadir dry_run)
  • +
  • guardrails/base.py — Protocol GuardrailEngine
  • +
  • guardrails/composite.py — CompositeGuardrailEngine
  • +
  • guardrails/validators.py: detect_pii, prompt_injection, toxic_language, schema_match, pii_leakage, forbidden_action_keywords
  • +
  • domain/guardrail.py — GuardrailViolation
  • +
  • domain/execution.py — AgentExecution, ProposedAction (solo añadir dry_run)
  • +
  • domain/policy.py — PolicyDefinition, fail_open/fail_closed
  • +
  • api/agents.py, api/policies.py, api/violations.py — endpoints sin cambios
  • +
  • api/executions.py — endpoints approve/reject (solo añadir dry_run en InvokeRequest)
  • +
  • registry/repository.py, registry/versioning.py, registry/policy_store.py
  • +
  • observability/logging.py, api/middlewares.py
  • +
  • llm/base.py, llm/mock.py, llm/azure.py, llm/openai.py
  • +
+
+
+ +
+ plan.html — AgentForge Trading · Generado 2026-05-21 · Actualizar data-status="todo|in-progress|done" al ejecutar cada tarea +
+ + +