feat(dashboard): página Ejecutar con trace timeline y violations rendering
- components/trace_view.render_trace: decision_path como timeline con duración. - components/violation_view.render_violations: violaciones con badge de severidad. - pages/2_▶️_Ejecutar.py: selector de agente, botones de escenarios pregrabados, textarea, invoke y render de status/output/violations/traza. Aviso si queda en awaiting_approval. (Se omite la variable muerta chosen_example del plan.) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
"""Página para invocar un agente y visualizar la traza completa."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import streamlit as st
|
||||
|
||||
from agentforge_dashboard.client import CoreClient
|
||||
from agentforge_dashboard.components.trace_view import render_trace
|
||||
from agentforge_dashboard.components.violation_view import render_violations
|
||||
|
||||
|
||||
@st.cache_resource
|
||||
def get_client() -> CoreClient:
|
||||
return CoreClient()
|
||||
|
||||
|
||||
client = get_client()
|
||||
st.title("▶️ Ejecutar Agente")
|
||||
st.caption("Lanza una ejecución con la cadena completa de gobierno.")
|
||||
|
||||
agents = client.list_agents()
|
||||
if not agents:
|
||||
st.warning("No hay agentes registrados.")
|
||||
st.stop()
|
||||
|
||||
names = [a["name"] for a in agents]
|
||||
agent_name = st.selectbox("Agente", names)
|
||||
|
||||
# Cargar escenarios pregrabados si existen en el disco montado.
|
||||
examples_dir = Path("agents") / agent_name / "examples"
|
||||
example_files = sorted(examples_dir.glob("*.txt")) if examples_dir.exists() else []
|
||||
|
||||
col_l, col_r = st.columns([3, 1])
|
||||
with col_r:
|
||||
st.markdown("**Escenarios**")
|
||||
for ef in example_files:
|
||||
if st.button(ef.stem, use_container_width=True):
|
||||
st.session_state["input_text"] = ef.read_text(encoding="utf-8")
|
||||
|
||||
with col_l:
|
||||
user_input = st.text_area(
|
||||
"Descripción del incidente",
|
||||
height=240,
|
||||
key="input_text",
|
||||
placeholder="Pega aquí la descripción del incidente o usa un escenario...",
|
||||
)
|
||||
|
||||
if st.button("🚀 Invocar agente", type="primary", disabled=not user_input):
|
||||
with st.spinner("Ejecutando..."):
|
||||
result = client.invoke_agent(agent_name, {"input": user_input})
|
||||
st.session_state["last_execution"] = result
|
||||
|
||||
execution = st.session_state.get("last_execution")
|
||||
if execution and "error" not in execution:
|
||||
st.divider()
|
||||
st.markdown(f"**trace_id:** `{execution['trace_id']}`")
|
||||
st.markdown(f"**Status:** `{execution['status']}`")
|
||||
|
||||
if execution["status"] == "awaiting_approval":
|
||||
st.warning(
|
||||
"Esta ejecución requiere aprobación humana. "
|
||||
"Ve a la página **Aprobaciones** para revisar y decidir."
|
||||
)
|
||||
if execution.get("final_output"):
|
||||
st.subheader("📦 Output final")
|
||||
st.json(execution["final_output"])
|
||||
render_violations(execution.get("violations", []))
|
||||
render_trace(execution.get("decision_path", []))
|
||||
elif execution and "error" in execution:
|
||||
st.error(f"Error de la API: {execution['error']}")
|
||||
Reference in New Issue
Block a user