From 9db00c6d3386627ec85a8ccc7a531f8d3b9051f4 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Tue, 21 Jul 2026 15:28:46 +0800 Subject: [PATCH] feat: render workflow receipt evidence rows --- frontend/src/app/page.tsx | 11 +++++++- frontend/src/components/chat-message-row.tsx | 2 +- .../src/components/evidence-audit-panel.tsx | 26 +++++++++++++++++-- frontend/src/lib/chat-message-view.ts | 6 +++++ frontend/tests/evidence-audit-panel.test.ts | 13 ++++++++++ 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index c84fe4de..353ccc8e 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -2098,6 +2098,15 @@ export default function Home() { } if (!response.body) throw new Error("浏览器未收到可读取的回答流"); const techniqueTruth = response.headers.get("x-jyotish-technique-truth") ?? "unknown"; + const workflowReceipt = { + route: response.headers.get("x-jyotish-workflow-route") ?? "unknown", + status: response.headers.get("x-jyotish-workflow-status") ?? "unknown", + preciseTiming: response.headers.get("x-jyotish-precise-timing") ?? "unknown", + missingLayers: (response.headers.get("x-jyotish-missing-layers") ?? "none") + .split(",") + .map((item) => item.trim()) + .filter((item) => item && item !== "none"), + }; const reader = response.body.getReader(); const decoder = new TextDecoder(); @@ -2126,7 +2135,7 @@ export default function Home() { const completedSession: ChatSession = { ...userSession, title: currentSession.messages.length === 0 && reply.title ? reply.title : userSession.title, - messages: [...userSession.messages, { role: "assistant", text: reply.text, suggestions: reply.suggestions, techniqueTruth }], + messages: [...userSession.messages, { role: "assistant", text: reply.text, suggestions: reply.suggestions, techniqueTruth, workflowReceipt }], updatedAt: timestamp(), }; updateSession(sessionId, () => completedSession); diff --git a/frontend/src/components/chat-message-row.tsx b/frontend/src/components/chat-message-row.tsx index c262b32c..3aded28a 100644 --- a/frontend/src/components/chat-message-row.tsx +++ b/frontend/src/components/chat-message-row.tsx @@ -25,7 +25,7 @@ export function ChatMessageRow({ message }: { readonly message: ChatMessageView {message.role === "assistant" ? ( message.state === "thinking" ?
{message.text}
} diff --git a/frontend/src/components/evidence-audit-panel.tsx b/frontend/src/components/evidence-audit-panel.tsx index 5cdb328f..2d766a25 100644 --- a/frontend/src/components/evidence-audit-panel.tsx +++ b/frontend/src/components/evidence-audit-panel.tsx @@ -4,6 +4,13 @@ type AuditRow = { boundary: string; }; +type WorkflowReceipt = { + route: string; + status: string; + preciseTiming: string; + missingLayers: readonly string[]; +}; + const defaultAuditRows: AuditRow[] = [ { label: "D1 / Natal", status: "required", boundary: "基础命盘层" }, { label: "Varga: D9 / D10 / D2 / D11", status: "required", boundary: "按问题域调用,不混用" }, @@ -15,12 +22,27 @@ const defaultAuditRows: AuditRow[] = [ { label: "MEVG / Real Case Calibration", status: "blocked", boundary: "外部校准不足时降级" }, ]; -export function EvidenceAuditPanel({ claimStatus }: { readonly claimStatus?: string }) { +function workflowRows(receipt?: WorkflowReceipt): AuditRow[] { + if (!receipt) return defaultAuditRows; + return [ + { label: `Workflow route: ${receipt.route}`, status: receipt.status === "blocked" ? "blocked" : "required", boundary: "后端实际路由" }, + { label: `Precise timing: ${receipt.preciseTiming}`, status: receipt.preciseTiming === "allowed" ? "partial" : "blocked", boundary: "精确应期 claim gate" }, + { + label: "Missing route layers", + status: receipt.missingLayers.length ? "blocked" : "required", + boundary: receipt.missingLayers.length ? receipt.missingLayers.join(" / ") : "none", + }, + ...defaultAuditRows, + ]; +} + +export function EvidenceAuditPanel({ claimStatus, workflowReceipt }: { readonly claimStatus?: string; readonly workflowReceipt?: WorkflowReceipt }) { + const rows = workflowRows(workflowReceipt); return (