diff --git a/apps/api/src/api/v1/platform/operator_runs.py b/apps/api/src/api/v1/platform/operator_runs.py index d39ee79f..03bc1f20 100644 --- a/apps/api/src/api/v1/platform/operator_runs.py +++ b/apps/api/src/api/v1/platform/operator_runs.py @@ -52,6 +52,7 @@ class RunItem(BaseModel): created_at: datetime timeout_at: datetime | None remediation_summary: dict[str, Any] | None = None + callback_reply_summary: dict[str, Any] | None = None class ListRunsResponse(BaseModel): diff --git a/apps/api/tests/test_awooop_operator_timeline_labels.py b/apps/api/tests/test_awooop_operator_timeline_labels.py index fd071e73..8f1dc549 100644 --- a/apps/api/tests/test_awooop_operator_timeline_labels.py +++ b/apps/api/tests/test_awooop_operator_timeline_labels.py @@ -1,6 +1,9 @@ from datetime import datetime +from decimal import Decimal from types import SimpleNamespace +from uuid import UUID +from src.api.v1.platform.operator_runs import ListRunsResponse from src.services.platform_operator_service import ( _collect_run_incident_ids, _legacy_mcp_timeline_status, @@ -226,6 +229,48 @@ def test_run_callback_reply_summary_marks_no_callback() -> None: assert summary["total"] == 0 +def test_list_runs_response_preserves_callback_reply_summary() -> None: + run_id = UUID("5c0306e0-591a-5445-9a33-80f499426b38") + response = ListRunsResponse.model_validate({ + "runs": [ + { + "run_id": run_id, + "project_id": "awoooi", + "agent_id": "legacy-telegram-gateway", + "state": "completed", + "is_shadow": True, + "cost_usd": Decimal("0.0000"), + "step_count": 0, + "created_at": datetime(2026, 5, 18, 7, 31, 37), + "timeout_at": None, + "remediation_summary": None, + "callback_reply_summary": { + "schema_version": "awooop_run_callback_reply_summary_v1", + "status": "failed", + "total": 1, + "sent": 0, + "fallback_sent": 0, + "rescue_sent": 0, + "failed": 1, + "needs_human": True, + "latest_status": "callback_reply_failed", + "latest_action": "detail", + "latest_incident_id": "INC-20260513-79ED5E", + "latest_at": "2026-05-18T07:31:37", + "latest_provider_message_id": "telegram_callback_reply:failed", + }, + } + ], + "total": 1, + "page": 1, + "per_page": 1, + }) + + dumped = response.model_dump(mode="json") + assert dumped["runs"][0]["callback_reply_summary"]["status"] == "failed" + assert dumped["runs"][0]["callback_reply_summary"]["needs_human"] is True + + def test_remediation_timeline_summary_surfaces_route_and_write_flags() -> None: summary = _remediation_timeline_summary({ "incident_id": "INC-20260514-F85F21",