feat(workbench): redesign investigation reports and diagrams
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { z } from "zod";
|
||||
import type { AgentTaskDiscussionContext } from "@/features/agent";
|
||||
|
||||
export type InvestigationDiscussion = { prompt?: string; context?: AgentTaskDiscussionContext };
|
||||
|
||||
const text = z.string().trim().min(1);
|
||||
export const investigationDiagramSchema = z
|
||||
.object({
|
||||
title: text,
|
||||
mermaid: text
|
||||
.max(20000)
|
||||
.refine(
|
||||
(source) =>
|
||||
/^\s*(?:flowchart|graph)\s+(?:TD|TB|BT|LR|RL)\b/.test(source) &&
|
||||
!source.includes("```") &&
|
||||
!source.includes("%%{") &&
|
||||
!/(?:^|[;\n])\s*click\b/.test(source),
|
||||
"调查图只接受不含指令或回调的 Mermaid 流程描述"
|
||||
),
|
||||
node_refs: z
|
||||
.array(
|
||||
z
|
||||
.object({
|
||||
node_id: z.string().regex(/^[A-Za-z_][A-Za-z0-9_-]{0,79}$/),
|
||||
label: text,
|
||||
evidence_refs: z.array(text).default([]),
|
||||
action_refs: z.array(z.string().uuid()).default([])
|
||||
})
|
||||
.strict()
|
||||
)
|
||||
.max(100)
|
||||
.default([])
|
||||
})
|
||||
.strict()
|
||||
.superRefine((diagram, ctx) => {
|
||||
if (new Set(diagram.node_refs.map((node) => node.node_id)).size !== diagram.node_refs.length) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "调查图节点引用重复" });
|
||||
}
|
||||
});
|
||||
const dataGapSchema = z
|
||||
.object({
|
||||
gap_id: text,
|
||||
node_id: text.nullish(),
|
||||
missing_data: text,
|
||||
scope: text,
|
||||
impact: text,
|
||||
required_data: text,
|
||||
evidence_refs: z.array(text).min(1),
|
||||
blocking: z.boolean()
|
||||
})
|
||||
.strict();
|
||||
|
||||
/** Historical omissions remain unknown. Never infer outcomes from report prose. */
|
||||
export const investigationReportSchema = z
|
||||
.object({
|
||||
title: text,
|
||||
current_conclusion: text,
|
||||
conclusion_boundary: text,
|
||||
evidence_refs: z.array(text),
|
||||
recommendations: z.array(text),
|
||||
pending_items: z.array(text),
|
||||
stage: z.enum(["interim", "final"]).nullish(),
|
||||
outcome: z.enum(["concluded", "insufficient_data"]).nullish(),
|
||||
stop_reason: text.nullish(),
|
||||
data_gaps: z.array(dataGapSchema).nullish(),
|
||||
diagram: investigationDiagramSchema.nullish()
|
||||
})
|
||||
.strict()
|
||||
.superRefine((report, ctx) => {
|
||||
const invalid = (message: string) => ctx.addIssue({ code: z.ZodIssueCode.custom, message });
|
||||
if (report.outcome == null) {
|
||||
if (report.stage != null || report.stop_reason != null || report.data_gaps != null)
|
||||
invalid("报告结构化字段必须一起提供");
|
||||
return;
|
||||
}
|
||||
if (report.stage == null || report.data_gaps == null) {
|
||||
invalid("报告缺少阶段或数据缺口清单");
|
||||
return;
|
||||
}
|
||||
if (new Set(report.data_gaps.map((gap) => gap.gap_id)).size !== report.data_gaps.length)
|
||||
invalid("数据缺口编号重复");
|
||||
const blocking = report.data_gaps.some((gap) => gap.blocking);
|
||||
if (report.outcome === "insufficient_data") {
|
||||
if (report.stage !== "final" || !report.stop_reason || !blocking)
|
||||
invalid("证据不足必须提供最终报告、结束原因和关键缺口");
|
||||
if (report.recommendations.length || report.pending_items.length)
|
||||
invalid("证据不足退出后不再生成后续处置建议或待办");
|
||||
} else if (report.stop_reason != null || blocking)
|
||||
invalid("已形成结论不能包含结束原因或阻塞缺口");
|
||||
});
|
||||
|
||||
export type InvestigationReport = z.infer<typeof investigationReportSchema>;
|
||||
export type InvestigationDiagram = z.infer<typeof investigationDiagramSchema>;
|
||||
Reference in New Issue
Block a user