import { AnswerUiView, parseAnswerUiBlock, type AnswerUiBlock, type AnswerUiSelection } from "@/features/agent"; import type { OperationalTask, OperationalTaskReport } from "../api/operational-task-client"; import type { InvestigationDiscussion, InvestigationMapTarget } from "../api/investigation-report"; import { formatInvestigationText } from "../utils/investigation-text"; export function InvestigationReportBlocks({ task, snapshot, onContinue, onLocate }: { task: Pick; snapshot: OperationalTaskReport; onContinue: (discussion?: InvestigationDiscussion) => Promise | boolean | void; onLocate?: (targets: InvestigationMapTarget[]) => Promise | void; }) { const blocks = snapshot.report.ui_blocks ?? []; if (!blocks.length) return null; const ask = async (selection: AnswerUiSelection) => { const result = await onContinue({ reference: { title: `${snapshot.report.title} · 报告第 ${snapshot.revision} 版 · ${selection.title}`, text: `${selection.text}\n报告第 ${snapshot.revision} 版${snapshot.execution_generation ? ` · 第 ${snapshot.execution_generation} 轮` : ""}` }, context: { report_revision: snapshot.revision }, reportGeneration: snapshot.execution_generation }); if (result === false) throw new Error("引用暂未带入对话,请重试。"); }; return

数据与分析

查看报告中的数据与依据;定位和补充资料使用各自入口。

{blocks.map((item) => { const parsed = parseAnswerUiBlock(item.block); const evidence = task.evidence.filter((entry) => item.evidence_refs.includes(entry.evidence_id)); const quote = (selection: AnswerUiSelection) => ask({ ...selection, text: `${selection.text}\n引用依据:${item.evidence_refs.map((id) => { const record = evidence.find((entry) => entry.evidence_id === id); return record ? `${record.source_label}(${id})` : `${id}(记录当前不可用)`; }).join("、")}` }); // Evidence facts are supplied by the saved task record, not generated presentation props. const block: AnswerUiBlock | null = parsed ? { ...parsed, spec: { ...parsed.spec, elements: Object.fromEntries(Object.entries(parsed.spec.elements).map(([id, node]) => { if (node.type !== "Evidence") return [id, node]; const record = evidence.find((entry) => entry.evidence_id === node.props.evidence_id); return [id, record ? { ...node, props: { ...node.props, summary: record.summary, source: record.source_label, observed_at: record.observed_at, kind: record.kind === "synthetic" ? "demo" : record.kind === "human_input" ? "human_input" : "observed" } } : { type: "Text", children: [], props: { text: "这条引用证据当前不可用。", tone: "warning" } }]; })) } } : null; const shownEvidence = new Set(block ? Object.values(block.spec.elements) .filter((node) => node.type === "Evidence").map((node) => node.props.evidence_id) : []); const remainingRefs = item.evidence_refs.filter((id) => !shownEvidence.has(id)); return
{block ? quote({ title: "补充资料", text })} onLocate={onLocate ? (target) => onLocate(target.feature_ids.map((id) => ({ source_id: target.layer, feature_id: id }))) : undefined} /> :

{formatInvestigationText(item.block.fallback_text)}

} {remainingRefs.length ?

引用依据:{[...new Set(remainingRefs.map((id) => evidence.find((entry) => entry.evidence_id === id)?.source_label ?? `${id}(记录当前不可用)`))].join("、")}

: null}
; })}
; }