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

Function verifyBlockCitations

tools/debug-console/lib/verify-citations.ts:197–283  ·  view source on GitHub ↗
(
  answerText: string,
  blockRefs: BlockRefSpec[],
  opts: { useJudge?: boolean } = {},
)

Source from the content-addressed store, hash-verified

195}
196
197export async function verifyBlockCitations(
198 answerText: string,
199 blockRefs: BlockRefSpec[],
200 opts: { useJudge?: boolean } = {},
201): Promise<CitationVerifyResult> {
202 const useJudge = opts.useJudge ?? judgeAvailable();
203 const brokenAnchors: string[] = [];
204 const downgraded: string[] = [];
205 const unverified: string[] = [];
206
207 const byKey = new Map<string, BlockRefSpec>();
208 for (const r of blockRefs) if (!byKey.has(r.key)) byKey.set(r.key, r);
209 const uniq = [...byKey.values()];
210
211 const reads = await Promise.all(
212 uniq.map((r) =>
213 executeTool("read_block", { path: r.path, anchor: `^${r.anchor}` }).then((res) => ({ r, res })),
214 ),
215 );
216
217 const grays: Array<{ key: string; claim: string; content: string }> = [];
218
219 for (const { r, res } of reads) {
220 if (!res.ok) {
221 if (errorIsNotFound(res.error || "")) {
222 brokenAnchors.push(r.key);
223 downgraded.push(r.key);
224 } else {
225 unverified.push(r.key); // 网络/超时 → 不降级
226 }
227 continue;
228 }
229 const content = blockContent(res.data);
230 if (!content.trim()) {
231 unverified.push(r.key);
232 continue;
233 }
234 if (blockKind(res.data) === "heading") continue; // heading 指整节、只回标题行,豁免
235
236 const ctxs = claimContextsFor(answerText, r.key).filter((c) => hasSalient(c));
237 if (ctxs.length === 0) continue;
238
239 const blockTok = hardNumericTokens(content);
240 let hardSupported = false; // 某出现处被块的 strong 要素命中 → 整 key 保留
241 let numericMismatch = false; // 某出现处有 strong 要素、块全未命中
242 let needsJudge = false; // 纯定性 / 仅年份 → 灰区
243 let judgeClaim = "";
244 for (const ctx of ctxs) {
245 const ct = hardNumericTokens(ctx);
246 if (ct.strong.size >= 1) {
247 if (matchHits(ct, blockTok).strongHit >= 1) hardSupported = true;
248 else numericMismatch = true;
249 } else {
250 // 仅年份 或 无硬要素 → 不凭启发式定,交灰区
251 needsJudge = true;
252 if (!judgeClaim) judgeClaim = ctx;
253 }
254 }

Callers 1

validateAnswerRefsFunction · 0.90

Calls 10

judgeAvailableFunction · 0.90
executeToolFunction · 0.90
judgeCitationFunction · 0.90
errorIsNotFoundFunction · 0.85
blockContentFunction · 0.85
blockKindFunction · 0.85
claimContextsForFunction · 0.85
hasSalientFunction · 0.85
hardNumericTokensFunction · 0.85
matchHitsFunction · 0.85

Tested by

no test coverage detected