diff --git a/dashboard/src/agentforge_dashboard/components/diff_view.py b/dashboard/src/agentforge_dashboard/components/diff_view.py new file mode 100644 index 0000000..f5d6b24 --- /dev/null +++ b/dashboard/src/agentforge_dashboard/components/diff_view.py @@ -0,0 +1,26 @@ +"""Componente para renderizar diffs unificados con coloreado básico.""" + +from __future__ import annotations + +import streamlit as st + + +def render_unified_diff(diff_text: str) -> None: + if not diff_text.strip(): + st.info("Sin diferencias entre las versiones seleccionadas.") + return + lines: list[str] = [] + for line in diff_text.splitlines(): + if line.startswith("+") and not line.startswith("+++"): + lines.append(f'{line}') + elif line.startswith("-") and not line.startswith("---"): + lines.append(f'{line}') + elif line.startswith("@@"): + lines.append(f'{line}') + else: + lines.append(line) + html = ( + "
" + "\n".join(lines) + "
" + ) + st.markdown(html, unsafe_allow_html=True) diff --git a/dashboard/src/agentforge_dashboard/pages/1_🏛️_Registro.py b/dashboard/src/agentforge_dashboard/pages/1_🏛️_Registro.py new file mode 100644 index 0000000..3a183b4 --- /dev/null +++ b/dashboard/src/agentforge_dashboard/pages/1_🏛️_Registro.py @@ -0,0 +1,60 @@ +"""Página de registro de agentes: lista, detalle, versiones y diff.""" + +from __future__ import annotations + +import streamlit as st + +from agentforge_dashboard.client import CoreClient +from agentforge_dashboard.components.diff_view import render_unified_diff + + +@st.cache_resource +def get_client() -> CoreClient: + return CoreClient() + + +client = get_client() +st.title("🏛️ Registro de Agentes") +st.caption("Catálogo central de agentes con versionado tipo Git.") + +agents = client.list_agents() +if not agents: + st.warning("No hay agentes registrados. Coloca YAMLs bajo `agents//`.") + st.stop() + +names = [a["name"] for a in agents] +selected_name = st.selectbox("Agente", names) +agent = client.get_agent(selected_name) + +col1, col2 = st.columns([2, 1]) +with col1: + st.subheader(f"{agent['name']} @ {agent['version']}") + st.write(f"**Estado:** `{agent['state']}` | **Owner:** {agent['owner']}") + st.write(f"**Propósito:** {agent['purpose']}") + st.write(f"**Guardrails activos:** {', '.join(agent['guardrails'])}") + st.write(f"**Threshold HITL:** risk_score ≥ {agent['risk_threshold_for_hitl']}") + with st.expander("System prompt"): + st.code(agent["system_prompt"], language="markdown") + with st.expander("Output schema"): + st.json(agent["output_schema"]) + +with col2: + st.subheader("LLM") + st.json(agent["llm"]) + +st.divider() +st.subheader("Historial de versiones") +versions = client.list_versions(selected_name) +st.dataframe(versions, hide_index=True, use_container_width=True) + +if len(versions) >= 2: + st.subheader("Comparar versiones") + ids = [v["id"] for v in versions] + cf, ct = st.columns(2) + with cf: + v_from = st.selectbox("Desde", ids, index=0) + with ct: + v_to = st.selectbox("Hasta", ids, index=len(ids) - 1) + if v_from != v_to: + diff = client.diff_versions(selected_name, v_from, v_to) + render_unified_diff(diff["unified_diff"]) diff --git a/pyproject.toml b/pyproject.toml index cfba581..f03f58e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,11 @@ target-version = "py311" select = ["E", "F", "W", "I", "N", "UP", "B", "C4", "SIM", "ASYNC", "RUF"] ignore = ["E501"] +[tool.ruff.lint.per-file-ignores] +# Streamlit exige que las páginas se llamen "__