feat(web): surface awooop agent evidence chain
All checks were successful
CD Pipeline / tests (push) Successful in 1m22s
Code Review / ai-code-review (push) Successful in 12s
CD Pipeline / build-and-deploy (push) Successful in 3m28s
CD Pipeline / post-deploy-checks (push) Successful in 1m18s

This commit is contained in:
Your Name
2026-05-25 15:57:56 +08:00
parent 683984dc47
commit 48a31ea2b9
4 changed files with 214 additions and 1 deletions

View File

@@ -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",

View File

@@ -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": "狀態鏈驗證",

View File

@@ -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 (
<section className={cn("border border-[#e0ddd4] bg-white", className)}>
@@ -388,6 +492,33 @@ export function AwoooPStatusChainPanel({
</div>
</div>
<div className="border-t border-[#e0ddd4] bg-[#faf9f3] px-4 py-2">
<p className="text-xs font-semibold text-[#141413]">{t("toolchain.title")}</p>
</div>
<div className={cn("grid gap-px bg-[#e0ddd4]", compact ? "md:grid-cols-2" : "md:grid-cols-5")}>
{toolchainItems.map((item) => (
<div key={item.key} className="min-w-0 bg-white px-4 py-3">
<div className="flex min-w-0 items-start gap-3">
<span className={cn(
"flex h-8 w-8 shrink-0 items-center justify-center border",
sourceFlowToneClass(item.tone)
)}>
<item.Icon className="h-4 w-4" aria-hidden="true" />
</span>
<div className="min-w-0">
<p className="text-xs font-semibold text-[#77736a]">{item.label}</p>
<p className="mt-1 truncate font-mono text-sm font-semibold text-[#141413]" title={item.value}>
{item.value}
</p>
</div>
</div>
<p className="mt-2 truncate font-mono text-xs text-[#5f5b52]" title={item.detail}>
{item.detail}
</p>
</div>
))}
</div>
{sourceCorrelation && (
<div>
<div className={cn("grid gap-px bg-[#e0ddd4]", compact ? "grid-cols-1" : "md:grid-cols-3")}>

View File

@@ -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%。