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

Function readWithSourcesFallback

web/app/api/agent-tool/route.ts:81–138  ·  view source on GitHub ↗

* 锚点查找 fallback:AI 常把一条**真实的 raw 块锚点**(如 [[raw/papers/2024-10-lightrag#^p-54]]) * 误标到它正在读的摘要页路径上(写成 [[wiki/sources/lightrag#^p-54]])——锚点是对的、路径错了。 * * 程序兜底:当 path 是 wiki/sources/X.md 且 anchor 在该路径未找到时,按以下顺序到对应 raw 文件重试: * 1. 摘要页 frontmatter 里**声明的 `sources:`**(精确——能处理 `2024-10-lightrag` 这类日期前缀

(
  cmd: "read-block" | "read-section",
  originalPath: string,
  anchor: string,
)

Source from the content-addressed store, hash-verified

79 * 仅对 anchor-not-found 类错误兜底,其他错误(路径不存在 / 权限等)原样返回。
80 */
81async function readWithSourcesFallback(
82 cmd: "read-block" | "read-section",
83 originalPath: string,
84 anchor: string,
85) {
86 const primary = await callKCli([cmd, originalPath, anchor]);
87 if (primary.ok) return primary;
88 if (!primary.error.includes("未找到 anchor")) return primary;
89 const m = originalPath.match(/^wiki\/sources\/(.+\.md)$/);
90 if (!m) return primary;
91 const basename = m[1];
92
93 // 候选 raw 路径:优先用摘要页 frontmatter 声明的 sources(精确),再退到 basename 猜测。
94 const candidates: string[] = [];
95 try {
96 const page = await getPage(originalPath);
97 const srcs = (page?.frontmatter as { sources?: unknown } | undefined)?.sources;
98 if (Array.isArray(srcs)) {
99 for (const s of srcs) {
100 if (typeof s !== "string") continue;
101 const mm = s.match(/\[\[([^\]|#]+)/); // 取 [[ 后、到 | / # / ]] 前的路径
102 if (!mm) continue;
103 let p = mm[1].trim();
104 if (!p.endsWith(".md")) p += ".md";
105 if (p.startsWith("raw/") && isSafeRelPath(p)) candidates.push(p);
106 }
107 }
108 } catch {
109 // getPage 失败(页面损坏等)→ 忽略,退到 basename 猜测
110 }
111 candidates.push(`raw/articles/${basename}`, `raw/papers/${basename}`);
112
113 const seen = new Set<string>();
114 for (const candidate of candidates) {
115 if (seen.has(candidate)) continue;
116 seen.add(candidate);
117 const retry = await callKCli([cmd, candidate, anchor]);
118 if (retry.ok) {
119 // eslint-disable-next-line no-console
120 console.log(
121 `[anchor-fallback] ${cmd} ${originalPath}#${anchor} → ${candidate}`,
122 );
123 const augmented =
124 retry.data && typeof retry.data === "object" && !Array.isArray(retry.data)
125 ? {
126 ...(retry.data as Record<string, unknown>),
127 _fallback: {
128 from: originalPath,
129 to: candidate,
130 reason: "anchor 未在 wiki/sources 找到,已回退到对应 raw 文件",
131 },
132 }
133 : retry.data;
134 return { ok: true as const, data: augmented };
135 }
136 }
137 return primary;
138}

Callers 2

read_sectionFunction · 0.85
read_blockFunction · 0.85

Calls 3

getPageFunction · 0.90
isSafeRelPathFunction · 0.90
callKCliFunction · 0.85

Tested by

no test coverage detected