fix(api): /executions incluye también las ejecuciones HITL pendientes
`GET /executions` solo leía `executions.jsonl`, donde nunca se escribe una ejecución en `awaiting_approval` (esas viven solo en el checkpointer). La página de Aprobaciones del dashboard hace `[e for e in list_executions() if e.status=="awaiting_approval"]`, así que nunca encontraba aprobaciones pendientes. Ahora `list_executions` reconstruye las no-terminales desde `execution_index.json` + `orchestrator.snapshot()` y las fusiona con las del JSONL. Añade `test_list_executions_incluye_la_awaiting`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -147,8 +147,47 @@ async def invoke_agent(
|
||||
|
||||
|
||||
@router.get("", response_model=list[AgentExecutionSummary])
|
||||
def list_executions(settings: SettingsDep) -> list[AgentExecutionSummary]:
|
||||
return read_execution_summaries(settings.data_dir)
|
||||
async def list_executions(
|
||||
registry: RegistryDep,
|
||||
policies: PolicyStoreDep,
|
||||
orchestrator: OrchestratorDep,
|
||||
settings: SettingsDep,
|
||||
) -> list[AgentExecutionSummary]:
|
||||
"""Resumen de ejecuciones: las terminales del JSONL más las pausadas en HITL.
|
||||
|
||||
Una ejecución en ``awaiting_approval`` no se escribe en el log append-only
|
||||
(`executions.jsonl`); solo vive en el checkpointer. Para que la página de
|
||||
aprobaciones del dashboard la encuentre, aquí se reconstruyen esas desde el
|
||||
índice `execution_index.json` + el checkpointer.
|
||||
"""
|
||||
summaries = read_execution_summaries(settings.data_dir)
|
||||
seen = {str(s.trace_id) for s in summaries}
|
||||
for trace_id, meta in _load_index(settings.data_dir).items():
|
||||
if trace_id in seen:
|
||||
continue
|
||||
try:
|
||||
agent_def = registry.get_version(meta["agent_name"], meta["version"])
|
||||
policy = policies.get_policy(agent_def.guardrails[0])
|
||||
execution = await orchestrator.snapshot(
|
||||
agent_def=agent_def, policy=policy, trace_id=UUID(trace_id)
|
||||
)
|
||||
except (FileNotFoundError, IndexError, KeyError, ValueError):
|
||||
continue
|
||||
if execution is None:
|
||||
continue
|
||||
summaries.append(
|
||||
AgentExecutionSummary(
|
||||
trace_id=execution.trace_id,
|
||||
agent_name=execution.agent_name,
|
||||
agent_version=execution.agent_version,
|
||||
status=execution.status,
|
||||
started_at=execution.started_at,
|
||||
finished_at=execution.finished_at,
|
||||
n_violations=len(execution.violations),
|
||||
n_proposed_actions=len(execution.proposed_actions),
|
||||
)
|
||||
)
|
||||
return summaries
|
||||
|
||||
|
||||
@router.get("/{trace_id}", response_model=AgentExecution)
|
||||
|
||||
Reference in New Issue
Block a user