feat(telegram): persist callback status chain snapshots
This commit is contained in:
@@ -95,6 +95,7 @@ class CallbackReplyItem(BaseModel):
|
||||
run_created_at: datetime | None = None
|
||||
callback_reply: dict[str, Any]
|
||||
awooop_status_chain: dict[str, Any] | None = None
|
||||
persisted_awooop_status_chain: dict[str, Any] | None = None
|
||||
km_stale_completion_summary: dict[str, Any] | None = None
|
||||
persisted_km_stale_completion_summary: dict[str, Any] | None = None
|
||||
run_detail_href: str | None = None
|
||||
|
||||
@@ -374,6 +374,8 @@ async def list_callback_replies(
|
||||
m.sent_at,
|
||||
m.triggered_by_state,
|
||||
m.source_envelope -> 'callback_reply' AS callback_reply,
|
||||
m.source_envelope -> 'awooop_status_chain'
|
||||
AS persisted_awooop_status_chain,
|
||||
m.source_envelope -> 'km_stale_completion_summary'
|
||||
AS persisted_km_stale_completion_summary,
|
||||
r.agent_id,
|
||||
@@ -1055,6 +1057,9 @@ def _callback_reply_event_item(row: Mapping[str, Any]) -> dict[str, Any]:
|
||||
"agent_id": row.get("agent_id"),
|
||||
"run_created_at": row.get("run_created_at"),
|
||||
"callback_reply": callback_reply,
|
||||
"persisted_awooop_status_chain": _as_dict(
|
||||
row.get("persisted_awooop_status_chain"),
|
||||
) or None,
|
||||
"persisted_km_stale_completion_summary": _as_dict(
|
||||
row.get("persisted_km_stale_completion_summary"),
|
||||
) or None,
|
||||
|
||||
@@ -825,6 +825,7 @@ def _callback_reply_source_envelope_extra(
|
||||
parse_mode: str | None = None,
|
||||
error: str | None = None,
|
||||
km_stale_completion_summary: dict[str, object] | None = None,
|
||||
awooop_status_chain: dict[str, object] | None = None,
|
||||
) -> dict[str, object] | None:
|
||||
"""Build AwoooP metadata for Telegram detail/history callback replies."""
|
||||
if not incident_id:
|
||||
@@ -856,6 +857,8 @@ def _callback_reply_source_envelope_extra(
|
||||
)
|
||||
if km_snapshot:
|
||||
extra["km_stale_completion_summary"] = km_snapshot
|
||||
if isinstance(awooop_status_chain, dict):
|
||||
extra["awooop_status_chain"] = awooop_status_chain
|
||||
|
||||
return extra
|
||||
|
||||
@@ -909,6 +912,131 @@ def _callback_reply_km_stale_completion_snapshot(
|
||||
return snapshot
|
||||
|
||||
|
||||
def _callback_reply_awooop_status_chain_snapshot(
|
||||
*,
|
||||
incident_id: str | None,
|
||||
truth_chain: dict[str, object] | None = None,
|
||||
remediation_history: dict[str, object] | None = None,
|
||||
) -> dict[str, object] | None:
|
||||
"""Persist a compact AwoooP status-chain snapshot with callback evidence."""
|
||||
if not incident_id or (not truth_chain and not remediation_history):
|
||||
return None
|
||||
|
||||
truth_status = (
|
||||
truth_chain.get("truth_status")
|
||||
if isinstance(truth_chain, dict) and isinstance(truth_chain.get("truth_status"), dict)
|
||||
else {}
|
||||
)
|
||||
quality = (
|
||||
truth_chain.get("automation_quality")
|
||||
if isinstance(truth_chain, dict) and isinstance(truth_chain.get("automation_quality"), dict)
|
||||
else {}
|
||||
)
|
||||
facts = quality.get("facts") if isinstance(quality.get("facts"), dict) else {}
|
||||
latest = _latest_remediation_history_item(remediation_history)
|
||||
remediation_state = _remediation_evidence_state(remediation_history) or "missing"
|
||||
remediation_total = (
|
||||
_safe_int(remediation_history.get("total"))
|
||||
if isinstance(remediation_history, dict)
|
||||
else 0
|
||||
)
|
||||
latest_route = "none"
|
||||
if latest:
|
||||
latest_route = (
|
||||
f"{latest.get('agent_id') or 'unknown_agent'}/"
|
||||
f"{latest.get('tool_name') or 'current_state'}/"
|
||||
f"{latest.get('required_scope') or 'unknown'}"
|
||||
)
|
||||
|
||||
current_stage = str(truth_status.get("current_stage") or "unknown")
|
||||
stage_status = str(truth_status.get("stage_status") or "unknown")
|
||||
verdict = str(quality.get("verdict") or "unknown")
|
||||
verification = (
|
||||
facts.get("verification_result")
|
||||
or latest.get("verification_result_preview")
|
||||
or "missing"
|
||||
)
|
||||
auto_repair_records = _safe_int(facts.get("auto_repair_execution_records"))
|
||||
operation_records = _safe_int(facts.get("automation_operation_records"))
|
||||
gateway_total = _safe_int(facts.get("mcp_gateway_total"))
|
||||
km_entries = _safe_int(facts.get("knowledge_entries"))
|
||||
needs_human = bool(truth_status.get("needs_human"))
|
||||
|
||||
if verdict == "auto_repaired_verified":
|
||||
repair_state = "auto_repaired_verified"
|
||||
next_step = "monitor_for_regression"
|
||||
elif auto_repair_records > 0 or operation_records > 0:
|
||||
repair_state = "executed_pending_verification" if verification == "missing" else "executed"
|
||||
next_step = "verify_execution_result"
|
||||
elif remediation_state == "read_only":
|
||||
repair_state = "read_only_dry_run"
|
||||
next_step = "approve_or_escalate_from_awooop"
|
||||
elif remediation_state == "write_observed":
|
||||
repair_state = "write_observed_manual_review"
|
||||
next_step = "review_write_evidence"
|
||||
elif remediation_state == "blocked":
|
||||
repair_state = "blocked_manual_required"
|
||||
next_step = "manual_investigation"
|
||||
elif needs_human:
|
||||
repair_state = "manual_required"
|
||||
next_step = "manual_investigation"
|
||||
else:
|
||||
repair_state = "no_execution_evidence"
|
||||
next_step = "collect_evidence_or_wait"
|
||||
|
||||
if remediation_state in {"blocked", "fetch_failed"}:
|
||||
needs_human = True
|
||||
if (
|
||||
remediation_state == "write_observed"
|
||||
and repair_state != "auto_repaired_verified"
|
||||
):
|
||||
needs_human = True
|
||||
|
||||
truth_blockers = (
|
||||
truth_status.get("blockers") if isinstance(truth_status.get("blockers"), list) else []
|
||||
)
|
||||
quality_blockers = (
|
||||
quality.get("blockers") if isinstance(quality.get("blockers"), list) else []
|
||||
)
|
||||
blockers = [
|
||||
str(item)
|
||||
for item in [*truth_blockers, *quality_blockers]
|
||||
if item
|
||||
]
|
||||
|
||||
return {
|
||||
"schema_version": "awooop_status_chain_callback_reply_snapshot_v1",
|
||||
"source_schema_version": "awooop_status_chain_v1",
|
||||
"source": "telegram_callback_reply_snapshot",
|
||||
"source_id": incident_id,
|
||||
"incident_ids": [incident_id],
|
||||
"current_stage": current_stage,
|
||||
"stage_status": stage_status,
|
||||
"verdict": verdict,
|
||||
"repair_state": repair_state,
|
||||
"verification": str(verification),
|
||||
"needs_human": needs_human,
|
||||
"next_step": next_step,
|
||||
"blockers": blockers[:8],
|
||||
"evidence": {
|
||||
"auto_repair_records": auto_repair_records,
|
||||
"operation_records": operation_records,
|
||||
"mcp_gateway_total": gateway_total,
|
||||
"knowledge_entries": km_entries,
|
||||
"remediation_total": remediation_total,
|
||||
"remediation_state": remediation_state,
|
||||
"latest_route": latest_route,
|
||||
"latest_mode": latest.get("mode"),
|
||||
"latest_at": latest.get("created_at"),
|
||||
"latest_preview": latest.get("verification_result_preview"),
|
||||
},
|
||||
"writes": {
|
||||
"incident": latest.get("writes_incident_state"),
|
||||
"auto_repair": latest.get("writes_auto_repair_result"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _merge_outbound_source_envelope_extra(
|
||||
envelope: dict[str, object],
|
||||
extra: dict[str, object] | None,
|
||||
@@ -925,6 +1053,10 @@ def _merge_outbound_source_envelope_extra(
|
||||
if isinstance(km_stale_completion_summary, dict):
|
||||
envelope["km_stale_completion_summary"] = km_stale_completion_summary
|
||||
|
||||
awooop_status_chain = extra.get("awooop_status_chain")
|
||||
if isinstance(awooop_status_chain, dict):
|
||||
envelope["awooop_status_chain"] = awooop_status_chain
|
||||
|
||||
extra_refs = extra.get("source_refs")
|
||||
if isinstance(extra_refs, dict):
|
||||
source_refs = envelope.setdefault("source_refs", {})
|
||||
@@ -6123,6 +6255,7 @@ class TelegramGateway:
|
||||
incident_id=incident_id,
|
||||
project_id=project_id,
|
||||
)
|
||||
truth_chain: dict[str, object] | None = None
|
||||
try:
|
||||
from src.services.awooop_truth_chain_service import fetch_truth_chain
|
||||
|
||||
@@ -6156,6 +6289,11 @@ class TelegramGateway:
|
||||
lines += _format_km_stale_completion_lines(km_completion_summary)
|
||||
lines += _format_remediation_history_lines(remediation_history)
|
||||
|
||||
awooop_status_chain_snapshot = _callback_reply_awooop_status_chain_snapshot(
|
||||
incident_id=incident_id,
|
||||
truth_chain=truth_chain,
|
||||
remediation_history=remediation_history,
|
||||
)
|
||||
await self._send_html_line_message(
|
||||
lines,
|
||||
failure_context="incident_detail",
|
||||
@@ -6163,6 +6301,7 @@ class TelegramGateway:
|
||||
incident_id=incident_id,
|
||||
callback_action="detail",
|
||||
km_stale_completion_summary=km_completion_summary,
|
||||
awooop_status_chain=awooop_status_chain_snapshot,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
@@ -6281,6 +6420,7 @@ class TelegramGateway:
|
||||
incident_id=incident_id,
|
||||
project_id=project_id,
|
||||
)
|
||||
truth_chain: dict[str, object] | None = None
|
||||
try:
|
||||
from src.services.awooop_truth_chain_service import fetch_truth_chain
|
||||
|
||||
@@ -6309,6 +6449,11 @@ class TelegramGateway:
|
||||
lines += _format_km_stale_completion_lines(km_completion_summary)
|
||||
lines += _format_remediation_history_lines(remediation_history)
|
||||
|
||||
awooop_status_chain_snapshot = _callback_reply_awooop_status_chain_snapshot(
|
||||
incident_id=incident_id,
|
||||
truth_chain=truth_chain,
|
||||
remediation_history=remediation_history,
|
||||
)
|
||||
await self._send_html_line_message(
|
||||
lines,
|
||||
failure_context="incident_history",
|
||||
@@ -6316,6 +6461,7 @@ class TelegramGateway:
|
||||
incident_id=incident_id,
|
||||
callback_action="history",
|
||||
km_stale_completion_summary=km_completion_summary,
|
||||
awooop_status_chain=awooop_status_chain_snapshot,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
@@ -6555,6 +6701,7 @@ class TelegramGateway:
|
||||
incident_id: str | None = None,
|
||||
callback_action: str | None = None,
|
||||
km_stale_completion_summary: dict[str, object] | None = None,
|
||||
awooop_status_chain: dict[str, object] | None = None,
|
||||
) -> None:
|
||||
"""Send a multi-line HTML message without cutting Telegram tags in half."""
|
||||
chunks = _telegram_html_chunks(lines)
|
||||
@@ -6575,6 +6722,7 @@ class TelegramGateway:
|
||||
callback_action=callback_action,
|
||||
parse_mode="HTML",
|
||||
km_stale_completion_summary=km_stale_completion_summary,
|
||||
awooop_status_chain=awooop_status_chain,
|
||||
)
|
||||
if source_extra:
|
||||
payload[_AWOOOP_SOURCE_ENVELOPE_EXTRA_KEY] = source_extra
|
||||
@@ -6606,6 +6754,7 @@ class TelegramGateway:
|
||||
parse_mode="plain_text",
|
||||
error=str(exc),
|
||||
km_stale_completion_summary=km_stale_completion_summary,
|
||||
awooop_status_chain=awooop_status_chain,
|
||||
)
|
||||
if fallback_source_extra:
|
||||
fallback_payload[_AWOOOP_SOURCE_ENVELOPE_EXTRA_KEY] = fallback_source_extra
|
||||
@@ -6639,6 +6788,7 @@ class TelegramGateway:
|
||||
parse_mode="plain_text",
|
||||
error=str(fallback_exc),
|
||||
km_stale_completion_summary=km_stale_completion_summary,
|
||||
awooop_status_chain=awooop_status_chain,
|
||||
)
|
||||
if rescue_source_extra:
|
||||
rescue_payload[_AWOOOP_SOURCE_ENVELOPE_EXTRA_KEY] = rescue_source_extra
|
||||
|
||||
@@ -375,6 +375,12 @@ def test_callback_reply_event_item_surfaces_run_link_and_human_flag() -> None:
|
||||
"incident_id": "INC-20260513-79ED5E",
|
||||
"error": "HTTP error: 400",
|
||||
},
|
||||
"persisted_awooop_status_chain": {
|
||||
"schema_version": "awooop_status_chain_callback_reply_snapshot_v1",
|
||||
"repair_state": "blocked_manual_required",
|
||||
"needs_human": True,
|
||||
"next_step": "manual_investigation",
|
||||
},
|
||||
"persisted_km_stale_completion_summary": {
|
||||
"schema_version": "km_stale_owner_review_callback_reply_snapshot_v1",
|
||||
"status": "no_related_owner_review",
|
||||
@@ -398,6 +404,9 @@ def test_callback_reply_event_item_surfaces_run_link_and_human_flag() -> None:
|
||||
assert item["persisted_km_stale_completion_summary"]["triage"]["ai_lead_agent"] == (
|
||||
"Hermes"
|
||||
)
|
||||
assert item["persisted_awooop_status_chain"]["repair_state"] == (
|
||||
"blocked_manual_required"
|
||||
)
|
||||
|
||||
|
||||
def test_list_callback_replies_response_preserves_callback_evidence() -> None:
|
||||
@@ -434,6 +443,30 @@ def test_list_callback_replies_response_preserves_callback_evidence() -> None:
|
||||
"repair_state": "read_only_dry_run",
|
||||
"needs_human": True,
|
||||
},
|
||||
"persisted_awooop_status_chain": {
|
||||
"schema_version": "awooop_status_chain_callback_reply_snapshot_v1",
|
||||
"source_schema_version": "awooop_status_chain_v1",
|
||||
"source": "telegram_callback_reply_snapshot",
|
||||
"source_id": "INC-20260513-79ED5E",
|
||||
"incident_ids": ["INC-20260513-79ED5E"],
|
||||
"current_stage": "approval_required",
|
||||
"stage_status": "waiting",
|
||||
"verdict": "approval_required",
|
||||
"repair_state": "read_only_dry_run",
|
||||
"verification": "missing",
|
||||
"needs_human": True,
|
||||
"next_step": "approve_or_escalate_from_awooop",
|
||||
"evidence": {
|
||||
"auto_repair_records": 0,
|
||||
"operation_records": 0,
|
||||
"mcp_gateway_total": 1,
|
||||
"knowledge_entries": 0,
|
||||
},
|
||||
"writes": {
|
||||
"incident": False,
|
||||
"auto_repair": False,
|
||||
},
|
||||
},
|
||||
"km_stale_completion_summary": {
|
||||
"schema_version": (
|
||||
"km_stale_owner_review_completion_callback_summary_v1"
|
||||
@@ -497,6 +530,9 @@ def test_list_callback_replies_response_preserves_callback_evidence() -> None:
|
||||
assert dumped["items"][0]["awooop_status_chain"]["repair_state"] == (
|
||||
"read_only_dry_run"
|
||||
)
|
||||
assert dumped["items"][0]["persisted_awooop_status_chain"]["next_step"] == (
|
||||
"approve_or_escalate_from_awooop"
|
||||
)
|
||||
assert dumped["items"][0]["km_stale_completion_summary"]["ready_count"] == 3
|
||||
assert dumped["items"][0]["km_stale_completion_summary"]["related_total"] == 1
|
||||
assert dumped["items"][0]["persisted_km_stale_completion_summary"]["triage"][
|
||||
|
||||
@@ -177,6 +177,58 @@ def test_awooop_status_chain_lines_show_read_only_manual_gate() -> None:
|
||||
assert "pending_human_approval" in joined
|
||||
|
||||
|
||||
def test_callback_reply_awooop_status_chain_snapshot_marks_manual_gate() -> None:
|
||||
"""Callback evidence 要保存當下 AwoooP 狀態鏈,不只保存 live query 結果。"""
|
||||
snapshot = telegram_gateway_module._callback_reply_awooop_status_chain_snapshot(
|
||||
incident_id="INC-20260514-F85F21",
|
||||
truth_chain={
|
||||
"truth_status": {
|
||||
"current_stage": "approval_required",
|
||||
"stage_status": "waiting",
|
||||
"needs_human": True,
|
||||
"blockers": ["pending_human_approval"],
|
||||
},
|
||||
"automation_quality": {
|
||||
"verdict": "approval_required",
|
||||
"facts": {
|
||||
"auto_repair_execution_records": 0,
|
||||
"automation_operation_records": 0,
|
||||
"verification_result": "missing",
|
||||
"mcp_gateway_total": 1,
|
||||
"knowledge_entries": 0,
|
||||
},
|
||||
"blockers": [],
|
||||
},
|
||||
},
|
||||
remediation_history={
|
||||
"total": 1,
|
||||
"items": [
|
||||
{
|
||||
"agent_id": "investigator",
|
||||
"tool_name": "ssh_diagnose",
|
||||
"required_scope": "read",
|
||||
"safety_level": "read_only",
|
||||
"verification_result_preview": "degraded",
|
||||
"writes_incident_state": False,
|
||||
"writes_auto_repair_result": False,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
assert snapshot is not None
|
||||
assert snapshot["schema_version"] == (
|
||||
"awooop_status_chain_callback_reply_snapshot_v1"
|
||||
)
|
||||
assert snapshot["repair_state"] == "read_only_dry_run"
|
||||
assert snapshot["needs_human"] is True
|
||||
assert snapshot["next_step"] == "approve_or_escalate_from_awooop"
|
||||
assert snapshot["evidence"]["mcp_gateway_total"] == 1
|
||||
assert snapshot["evidence"]["latest_route"] == "investigator/ssh_diagnose/read"
|
||||
assert snapshot["writes"]["incident"] is False
|
||||
assert snapshot["blockers"] == ["pending_human_approval"]
|
||||
|
||||
|
||||
def test_km_stale_completion_lines_show_owner_review_queue_state() -> None:
|
||||
"""詳情/歷史要顯示 KM owner-review completion queue 是否卡住或可處理。"""
|
||||
lines = telegram_gateway_module._format_km_stale_completion_lines({
|
||||
@@ -329,6 +381,15 @@ async def test_send_request_strips_awooop_callback_metadata_before_telegram_api(
|
||||
"status": "callback_reply_sent",
|
||||
"incident_id": "INC-20260513-79ED5E",
|
||||
},
|
||||
"awooop_status_chain": {
|
||||
"schema_version": "awooop_status_chain_callback_reply_snapshot_v1",
|
||||
"repair_state": "read_only_dry_run",
|
||||
"needs_human": True,
|
||||
"evidence": {
|
||||
"auto_repair_records": 0,
|
||||
"operation_records": 0,
|
||||
},
|
||||
},
|
||||
"km_stale_completion_summary": {
|
||||
"schema_version": (
|
||||
"km_stale_owner_review_callback_reply_snapshot_v1"
|
||||
@@ -349,6 +410,9 @@ async def test_send_request_strips_awooop_callback_metadata_before_telegram_api(
|
||||
assert captured["mirror"]["source_envelope_extra"]["callback_reply"]["status"] == (
|
||||
"callback_reply_sent"
|
||||
)
|
||||
assert captured["mirror"]["source_envelope_extra"]["awooop_status_chain"][
|
||||
"repair_state"
|
||||
] == "read_only_dry_run"
|
||||
assert captured["mirror"]["source_envelope_extra"][
|
||||
"km_stale_completion_summary"
|
||||
]["ready_count"] == 2
|
||||
@@ -407,6 +471,29 @@ async def test_send_html_line_message_marks_callback_reply_evidence(monkeypatch)
|
||||
reply_markup=reply_markup,
|
||||
incident_id="INC-20260514-F85F21",
|
||||
callback_action="history",
|
||||
awooop_status_chain={
|
||||
"schema_version": "awooop_status_chain_callback_reply_snapshot_v1",
|
||||
"source": "telegram_callback_reply_snapshot",
|
||||
"source_id": "INC-20260514-F85F21",
|
||||
"incident_ids": ["INC-20260514-F85F21"],
|
||||
"current_stage": "approval_required",
|
||||
"stage_status": "waiting",
|
||||
"verdict": "approval_required",
|
||||
"repair_state": "read_only_dry_run",
|
||||
"verification": "missing",
|
||||
"needs_human": True,
|
||||
"next_step": "approve_or_escalate_from_awooop",
|
||||
"evidence": {
|
||||
"auto_repair_records": 0,
|
||||
"operation_records": 0,
|
||||
"mcp_gateway_total": 1,
|
||||
"knowledge_entries": 0,
|
||||
},
|
||||
"writes": {
|
||||
"incident": False,
|
||||
"auto_repair": False,
|
||||
},
|
||||
},
|
||||
km_stale_completion_summary={
|
||||
"schema_version": "km_stale_owner_review_completion_callback_summary_v1",
|
||||
"project_id": "awoooi",
|
||||
@@ -443,6 +530,10 @@ async def test_send_html_line_message_marks_callback_reply_evidence(monkeypatch)
|
||||
assert first_extra["status"] == "callback_reply_sent"
|
||||
assert first_extra["action"] == "history"
|
||||
assert first_extra["parse_mode"] == "HTML"
|
||||
assert first_source_extra["awooop_status_chain"]["repair_state"] == (
|
||||
"read_only_dry_run"
|
||||
)
|
||||
assert first_source_extra["awooop_status_chain"]["needs_human"] is True
|
||||
assert first_source_extra["km_stale_completion_summary"]["ready_count"] == 3
|
||||
assert first_source_extra["km_stale_completion_summary"]["triage"]["flow_stage"] == (
|
||||
"callback_observed_owner_review_link_missing"
|
||||
@@ -450,6 +541,9 @@ async def test_send_html_line_message_marks_callback_reply_evidence(monkeypatch)
|
||||
assert fallback_extra["status"] == "callback_reply_fallback_sent"
|
||||
assert fallback_extra["incident_id"] == "INC-20260514-F85F21"
|
||||
assert fallback_extra["parse_mode"] == "plain_text"
|
||||
assert fallback_source_extra["awooop_status_chain"]["next_step"] == (
|
||||
"approve_or_escalate_from_awooop"
|
||||
)
|
||||
assert fallback_source_extra["km_stale_completion_summary"]["triage"][
|
||||
"ai_lead_agent"
|
||||
] == "Hermes"
|
||||
|
||||
@@ -2796,6 +2796,7 @@
|
||||
"providerMessage": "Message: {messageId}",
|
||||
"previewEmpty": "No preview",
|
||||
"openRun": "Open Run",
|
||||
"awooopSnapshotTitle": "Callback-time AwoooP Status Chain",
|
||||
"kmCompletion": {
|
||||
"title": "KM Owner Review",
|
||||
"status": "Status: {status}",
|
||||
|
||||
@@ -2797,6 +2797,7 @@
|
||||
"providerMessage": "Message:{messageId}",
|
||||
"previewEmpty": "無摘要",
|
||||
"openRun": "開啟 Run",
|
||||
"awooopSnapshotTitle": "Callback 當下 AwoooP 狀態鏈",
|
||||
"kmCompletion": {
|
||||
"title": "KM Owner Review",
|
||||
"status": "狀態:{status}",
|
||||
|
||||
@@ -370,6 +370,7 @@ interface CallbackReplyEvent {
|
||||
agent_id?: string | null;
|
||||
run_detail_href?: string | null;
|
||||
awooop_status_chain?: AwoooPStatusChain | null;
|
||||
persisted_awooop_status_chain?: AwoooPStatusChain | null;
|
||||
km_stale_completion_summary?: KmStaleCompletionSummary | null;
|
||||
persisted_km_stale_completion_summary?: KmStaleCompletionSummary | null;
|
||||
}
|
||||
@@ -1732,6 +1733,21 @@ function CallbackReplyEvidencePanel({
|
||||
compact
|
||||
className="mt-3"
|
||||
/>
|
||||
{event.persisted_awooop_status_chain ? (
|
||||
<div className="mt-3 border-t border-[#e0ddd4] pt-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity className="h-3.5 w-3.5 text-[#1f5b9b]" aria-hidden="true" />
|
||||
<p className="text-xs font-semibold text-[#141413]">
|
||||
{t("awooopSnapshotTitle")}
|
||||
</p>
|
||||
</div>
|
||||
<AwoooPStatusChainPanel
|
||||
chain={event.persisted_awooop_status_chain}
|
||||
compact
|
||||
className="mt-2"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<CallbackKmCompletionSummary
|
||||
summary={event.km_stale_completion_summary}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user