diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 045d0816..9ec77a24 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -3030,6 +3030,24 @@ "km": "KM", "adr100": "ADR-100 Route" }, + "toolchain": { + "title": "AI Agent Evidence Chain", + "mcp": "MCP / Custom MCP", + "mcpValue": "Gateway {success}/{total}, failed {failed}, blocked {blocked}", + "mcpDetail": "top={topTool}; first-class={firstClass}; legacy={legacy}; policy={policy}", + "source": "Sentry / SigNoz", + "sourceValue": "{status}; direct {direct}, candidate {candidate}, applied {applied}", + "sourceDetail": "{providers}", + "execution": "Executor", + "executionValue": "{executor} / {status}", + "executionDetail": "operation={operation}; action={action}; ops={ops}", + "playbook": "PlayBook / Ansible", + "playbookValue": "{playbook}", + "playbookDetail": "ansible={ansible}; candidates={candidates}; check-mode={checkMode}; status={status}", + "learning": "KM / Learning", + "learningValue": "KM {km}; AutoRepair {autoRepair}; Ops {ops}", + "learningDetail": "verification={verification}; next={nextStep}" + }, "source": { "status": "Source Link", "verification": "Status-chain Verification", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index ca18c2c4..aebdc5e6 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -3031,6 +3031,24 @@ "km": "KM", "adr100": "ADR-100 Route" }, + "toolchain": { + "title": "AI Agent 證據鏈", + "mcp": "MCP / 自建 MCP", + "mcpValue": "Gateway {success}/{total},失敗 {failed},阻擋 {blocked}", + "mcpDetail": "top={topTool}; first-class={firstClass}; legacy={legacy}; policy={policy}", + "source": "Sentry / SigNoz", + "sourceValue": "{status}; direct {direct}, candidate {candidate}, applied {applied}", + "sourceDetail": "{providers}", + "execution": "Executor", + "executionValue": "{executor} / {status}", + "executionDetail": "operation={operation}; action={action}; ops={ops}", + "playbook": "PlayBook / Ansible", + "playbookValue": "{playbook}", + "playbookDetail": "ansible={ansible}; candidates={candidates}; check-mode={checkMode}; status={status}", + "learning": "KM / Learning", + "learningValue": "KM {km}; AutoRepair {autoRepair}; Ops {ops}", + "learningDetail": "verification={verification}; next={nextStep}" + }, "source": { "status": "來源關聯", "verification": "狀態鏈驗證", diff --git a/apps/web/src/components/awooop/status-chain.tsx b/apps/web/src/components/awooop/status-chain.tsx index 86744b0f..1af6f328 100644 --- a/apps/web/src/components/awooop/status-chain.tsx +++ b/apps/web/src/components/awooop/status-chain.tsx @@ -1,6 +1,6 @@ "use client"; -import { Activity, CheckCircle2, Link2, RadioTower, Route, ShieldAlert, TriangleAlert } from "lucide-react"; +import { Activity, BookOpenCheck, CheckCircle2, Link2, RadioTower, Route, ShieldAlert, TriangleAlert, Wrench } from "lucide-react"; import { useTranslations } from "next-intl"; import { cn } from "@/lib/utils"; @@ -316,6 +316,110 @@ export function AwoooPStatusChainPanel({ }), }, ] : []; + const mcpGateway = chain.mcp?.gateway ?? {}; + const legacyMcp = chain.mcp?.legacy ?? {}; + const topTool = chain.mcp?.top_tools?.[0]; + const execution = chain.execution ?? {}; + const ansible = execution.ansible ?? {}; + const candidatePlaybook = ansible.candidate_playbooks?.[0]; + const selectedPlaybook = execution.playbook_paths?.[0] + ?? execution.playbook_ids?.[0] + ?? ansible.latest_playbook_path + ?? candidatePlaybook?.playbook_path + ?? candidatePlaybook?.catalog_id + ?? emptyLabel; + const mcpGatewayTotal = mcpGateway.total ?? 0; + const mcpGatewayProblemTotal = (mcpGateway.failed ?? 0) + (mcpGateway.blocked ?? 0); + const executionTotal = execution.operation_total ?? 0; + const sourceToolchainTone: SourceFlowTone = sourceCorrelation + ? (sourceLinkVerified ? "success" : (sourceVerificationBlocked ? "blocked" : "warning")) + : "neutral"; + const toolchainItems = [ + { + key: "mcp", + Icon: RadioTower, + tone: (mcpGatewayTotal > 0 + ? (mcpGatewayProblemTotal > 0 ? "warning" : "success") + : "neutral") as SourceFlowTone, + label: t("toolchain.mcp"), + value: t("toolchain.mcpValue", { + success: mcpGateway.success ?? 0, + total: mcpGatewayTotal, + failed: mcpGateway.failed ?? 0, + blocked: mcpGateway.blocked ?? 0, + }), + detail: t("toolchain.mcpDetail", { + topTool: topTool?.tool_name ?? emptyLabel, + firstClass: mcpGateway.first_class_total ?? 0, + legacy: legacyMcp.total ?? 0, + policy: mcpGateway.policy_enforced_total ?? 0, + }), + }, + { + key: "source", + Icon: Link2, + tone: sourceToolchainTone, + label: t("toolchain.source"), + value: t("toolchain.sourceValue", { + status: sourceStatusLabels[sourceStatus] ?? valueOrEmpty(sourceStatus, emptyLabel), + direct: directRefTotal, + candidate: candidateTotal, + applied: appliedLinkTotal, + }), + detail: t("toolchain.sourceDetail", { + providers: sourceProviderSummary || emptyLabel, + }), + }, + { + key: "execution", + Icon: Activity, + tone: (executionTotal > 0 + ? (String(execution.latest_status ?? "").toLowerCase().includes("fail") ? "blocked" : "success") + : "neutral") as SourceFlowTone, + label: t("toolchain.execution"), + value: t("toolchain.executionValue", { + executor: execution.latest_executor ?? emptyLabel, + status: execution.latest_status ?? emptyLabel, + }), + detail: t("toolchain.executionDetail", { + operation: execution.latest_operation_type ?? emptyLabel, + action: execution.latest_action ?? emptyLabel, + ops: executionTotal, + }), + }, + { + key: "playbook", + Icon: Wrench, + tone: (ansible.considered || (ansible.candidate_count ?? 0) > 0 + ? (ansible.latest_status === "applied" ? "success" : "warning") + : "neutral") as SourceFlowTone, + label: t("toolchain.playbook"), + value: selectedPlaybook, + detail: t("toolchain.playbookDetail", { + ansible: boolValue(ansible.considered, emptyLabel), + candidates: ansible.candidate_count ?? 0, + checkMode: valueOrEmpty(ansible.latest_check_mode, emptyLabel), + status: ansible.latest_status ?? emptyLabel, + }), + }, + { + key: "learning", + Icon: BookOpenCheck, + tone: ((evidence.knowledge_entries ?? 0) > 0 + ? ((evidence.auto_repair_records ?? 0) > 0 ? "success" : "warning") + : "neutral") as SourceFlowTone, + label: t("toolchain.learning"), + value: t("toolchain.learningValue", { + km: evidence.knowledge_entries ?? 0, + autoRepair: evidence.auto_repair_records ?? 0, + ops: evidence.operation_records ?? 0, + }), + detail: t("toolchain.learningDetail", { + verification: valueOrEmpty(chain.verification, emptyLabel), + nextStep: valueOrEmpty(chain.next_step, emptyLabel), + }), + }, + ]; return (
@@ -388,6 +492,33 @@ export function AwoooPStatusChainPanel({ +
+

{t("toolchain.title")}

+
+
+ {toolchainItems.map((item) => ( +
+
+ + +
+

{item.label}

+

+ {item.value} +

+
+
+

+ {item.detail} +

+
+ ))} +
+ {sourceCorrelation && (
diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index b7d8d82b..fd84933f 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -20034,3 +20034,49 @@ screenshot: - KM governance:約 84%。 - AI Provider lane visibility:約 92%。 - 完整 AI 自動化管理產品化:約 95.6%。 + +--- + +## 2026-05-25 T181 — AwoooP 共用狀態鏈補 AI Agent 證據鏈矩陣 + +**背景**: + +- 使用者要求 Telegram / 前端要能清楚回答:AI Agent 是否真的用了 MCP / 自建 MCP、是否關聯 Sentry / SigNoz、是否產生或匹配 PlayBook、Ansible 是否進入 check-mode / apply、KM / Learning 是否有寫入。 +- 盤點後確認 `/api/v1/platform/status-chain` 已回傳 `awooop_status_chain_v1`,內含 `mcp.gateway`、`mcp.legacy`、`mcp.top_tools`、`source_refs.correlation`、`execution`、`execution.ansible`、`evidence.knowledge_entries` 等欄位;本輪不需要新增後端 API,也不新增假資料。 +- production API sample(`INC-20260525-69E971`)顯示:MCP Gateway `17/19` success、top tool `error_logs_summary`、Sentry/SigNoz provider heartbeat 存在但未匹配、Executor `ansible / dry_run`、Ansible 候選 `110-devops.yml` / `188-ai-web.yml`、KM `1`、AutoRepair `1`、Ops `1`。 + +**本輪修正**: + +- `AwoooPStatusChainPanel` 新增「AI Agent 證據鏈」矩陣,所有使用該共用面板的頁面同步受益(Work Items、Runs detail、callback history / persisted snapshot)。 +- 矩陣五格: + - `MCP / 自建 MCP`:Gateway 成功/總數、失敗、阻擋、top tool、first-class / legacy / policy count。 + - `Sentry / SigNoz`:source correlation 狀態、direct / candidate / applied 數量、provider 摘要。 + - `Executor`:latest executor、operation status、operation type、action、ops count。 + - `PlayBook / Ansible`:已選 PlayBook 或候選 playbook path、Ansible considered、candidate count、check-mode、status。 + - `KM / Learning`:KM、AutoRepair、Ops、verification、next step。 +- 新增 zh-TW / en i18n key;未新增內網 IP、未新增 mock data、未新增新付費 provider。 + +**local validation(完成)**: + +```text +jq empty apps/web/messages/zh-TW.json apps/web/messages/en.json +git diff --check +pnpm --dir apps/web exec tsc --noEmit --tsBuildInfoFile /tmp/awoooi-t181-tsconfig.tsbuildinfo +pnpm --dir apps/web lint -- --file src/components/awooop/status-chain.tsx +NEXT_PUBLIC_API_URL=https://awoooi.wooo.work pnpm --dir apps/web run build +``` + +**目前整體進度**: + +- AwoooP 告警可觀測鏈:約 99.38%。 +- 低風險自動修復閉環:約 95.8%。 +- 前端 AI 自動化管理介面同步:約 98.6%。 +- 首頁 KPI / 小龍蝦流程 truth alignment:約 96.5%。 +- Telegram 詳情 / 歷史可追溯:約 95.5%。 +- callback / DB replayability:約 96.3%。 +- MCP / 自建 MCP 可視化:約 92%。 +- Sentry / SigNoz source correlation:約 91%。 +- Ansible / PlayBook 可視化:約 90%。 +- KM governance:約 84.5%。 +- AI Provider lane visibility:約 92%。 +- 完整 AI 自動化管理產品化:約 96.1%。