- 续审 Agent 声明(AgentSpec) + 结构化输出契约(ContinuityReview/Conflict 五类) - LangGraph 并行审子图(可扩四审) + collect 落 chapter_reviews 留痕 + review SSE(section/conflict) - 验收-side Repository:章节 accepted 版本晋升 + digest append-only + 审稿留痕/裁决 - API:review(SSE) + reviews 历史 + accept(单原子事务:晋升 version + 终稿 digest + 裁决留痕) - 冲突 gate:未决裁决拦截(CONFLICT_UNRESOLVED);digest 从终稿提炼(不变量#4) - 前端:审稿报告页 + 冲突就地标注 + 裁决(采纳/忽略/手改) + 未决禁验收 + 「本次将更新」清单 - M2 E2E:真实 DB + 多档位 mock 网关零 token 走通 写→审→裁决→验收→摘要入库 - 多 agent 协同台账(PROGRESS.md) + 共享记忆(memory/contracts·decisions·gotchas)
35 lines
1.2 KiB
TypeScript
35 lines
1.2 KiB
TypeScript
// 审稿历史归一:把后端 ReviewHistoryItem 的松散 conflicts(dict[])收紧成 ReviewConflict[]。
|
||
// 纯逻辑(可单测);schema 把 conflicts 标成 {[k]:unknown}[],这里安全收窄。
|
||
|
||
import type { ReviewHistoryItem } from "@/lib/api/types";
|
||
import type { ReviewConflict } from "./sse";
|
||
|
||
function asString(v: unknown, fallback = ""): string {
|
||
return typeof v === "string" ? v : fallback;
|
||
}
|
||
|
||
function asStringArray(v: unknown): string[] {
|
||
if (!Array.isArray(v)) return [];
|
||
return v.filter((x): x is string => typeof x === "string");
|
||
}
|
||
|
||
// 把一条留痕的 conflicts 收紧(缺字段给安全默认;保持顺序=下标身份,对齐冲突 gate)。
|
||
export function normalizeConflicts(
|
||
item: ReviewHistoryItem | undefined,
|
||
): ReviewConflict[] {
|
||
const raw = item?.conflicts ?? [];
|
||
return raw.map((c) => ({
|
||
type: asString(c["type"], "未分类"),
|
||
where: asString(c["where"]),
|
||
refs: asStringArray(c["refs"]),
|
||
suggestion: asString(c["suggestion"]),
|
||
}));
|
||
}
|
||
|
||
// 最近一条留痕(GET .../reviews 已按新→旧排序)。
|
||
export function latestReview(
|
||
items: readonly ReviewHistoryItem[] | undefined,
|
||
): ReviewHistoryItem | undefined {
|
||
return items?.[0];
|
||
}
|