MCPcopy Create free account
hub / github.com/Qinbf/groundmap / validateAnswerRefs

Function validateAnswerRefs

tools/debug-console/lib/agent-loop.ts:117–184  ·  view source on GitHub ↗

ANSWER 后验:扫描所有引用,验证是否有效

(text: string)

Source from the content-addressed store, hash-verified

115
116 /** ANSWER 后验:扫描所有引用,验证是否有效 */
117 async function* validateAnswerRefs(text: string): AsyncGenerator<AgentEvent> {
118 const refs = collectRefs([text]);
119 if (refs.length === 0) return;
120 // 先把已读过的标为 valid,未读过的批量调 HTTP 验证
121 const toCheck: string[] = [];
122 const resultMap = new Map<string, { ok: boolean; read: boolean }>();
123 for (const r of refs) {
124 if (availableSources.has(r.ref.path)) {
125 resultMap.set(r.ref.path, { ok: true, read: true });
126 } else {
127 toCheck.push(r.ref.path);
128 }
129 }
130 if (toCheck.length > 0) {
131 const exists = await validatePaths(toCheck);
132 for (const [p, ok] of exists) {
133 resultMap.set(p, { ok, read: false });
134 }
135 }
136 const broken = refs
137 .filter((r) => {
138 const res = resultMap.get(r.ref.path);
139 return !res || !res.ok;
140 })
141 .map((r) => r.ref.path);
142 const unread = refs
143 .filter((r) => {
144 const res = resultMap.get(r.ref.path);
145 return res && res.ok && !res.read;
146 })
147 .map((r) => r.ref.path);
148
149 // 块级 + 语义核对(基线,与 mode 无关):对每条块级引用 read_block 验锚点存在性,
150 // 再用 启发式→LLM判官 两级判断块内容是否支撑论断;不支撑的 key 进 downgraded,
151 // 由 UI(downgradeRefAnchors)去掉假精度、改成整页链接。
152 // 只挑**块级**锚点(p/t/c/f-seq-hash):按锚点形态判别,兼容模型漏写 ^ 的 [[x#p-3-abc]]
153 // (isBlock 标志只看 ^,会漏);排除 h-(heading 指向整节,read_block 只回标题行,不宜按数字降级)。
154 const BLOCK_ANCHOR_RE = /^[ptcf]-\d+(?:-\d+)?-[a-z0-9]/;
155 const blockRefs = refs
156 .filter((r) => !!r.ref.anchor && BLOCK_ANCHOR_RE.test(r.ref.anchor as string))
157 .map((r) => ({ key: r.key, path: r.ref.path, anchor: r.ref.anchor as string }));
158 let downgraded: string[] = [];
159 if (blockRefs.length > 0) {
160 try {
161 ({ downgraded } = await verifyBlockCitations(text, blockRefs));
162 } catch {
163 downgraded = [];
164 }
165 }
166
167 if (broken.length > 0 || unread.length > 0 || downgraded.length > 0) {
168 const segs: string[] = [];
169 if (broken.length) segs.push(`${broken.length} 条文件失效`);
170 if (unread.length) segs.push(`${unread.length} 条未读`);
171 if (downgraded.length) segs.push(`${downgraded.length} 条锚点不支撑论断→已降级`);
172 yield {
173 kind: "status",
174 text: `引用验证:${segs.join(" / ")}`,

Callers 2

runAgentFunction · 0.85
finalizeWithoutToolsFunction · 0.85

Calls 3

collectRefsFunction · 0.90
validatePathsFunction · 0.90
verifyBlockCitationsFunction · 0.90

Tested by

no test coverage detected