feat(rag): harden post-LightRAG runtime
Retire legacy OCR/media/evidence fallbacks, add local-folder event bus and Page Aggregate guards, and archive completed design checklists. Validation: cargo test -p mnote-web -- --test-threads=1; cargo test --workspace -- --test-threads=1; git diff --check; codegraph sync .; codegraph_status.
This commit is contained in:
@@ -92,6 +92,58 @@ async function browserRefreshLocalIndex(page, root) {
|
||||
}, { rootUri: fileUrl(root) });
|
||||
}
|
||||
|
||||
async function browserUpdateLocalIndexSettings(page, root) {
|
||||
return page.evaluate(async ({ rootUri }) => {
|
||||
const response = await fetch("/api/search/local-index/settings", {
|
||||
method: "PUT",
|
||||
headers: { "content-type": "application/json", accept: "application/json" },
|
||||
body: JSON.stringify({
|
||||
workspaceId: "local-ws:user_real:task452",
|
||||
rootUri,
|
||||
includePaths: ["."],
|
||||
scheduleMode: "manual",
|
||||
scheduleTime: "02:00",
|
||||
runOnChange: false,
|
||||
}),
|
||||
});
|
||||
const payload = await response.json().catch(() => null);
|
||||
return {
|
||||
status: response.status,
|
||||
payload,
|
||||
};
|
||||
}, { rootUri: fileUrl(root) });
|
||||
}
|
||||
|
||||
async function browserFetchLocalIndexBacklinksAndTags(page, root, documentId) {
|
||||
return page.evaluate(async ({ rootUri, documentIdValue }) => {
|
||||
const backlinksParams = new URLSearchParams({
|
||||
workspaceId: "local-ws:user_real:task452",
|
||||
rootUri,
|
||||
documentId: documentIdValue,
|
||||
});
|
||||
const tagsParams = new URLSearchParams({
|
||||
workspaceId: "local-ws:user_real:task452",
|
||||
rootUri,
|
||||
});
|
||||
const backlinksResponse = await fetch(`/api/search/local-index/backlinks?${backlinksParams.toString()}`, {
|
||||
headers: { accept: "application/json" },
|
||||
});
|
||||
const tagsResponse = await fetch(`/api/search/local-index/tags?${tagsParams.toString()}`, {
|
||||
headers: { accept: "application/json" },
|
||||
});
|
||||
return {
|
||||
backlinks: {
|
||||
status: backlinksResponse.status,
|
||||
payload: await backlinksResponse.json().catch(() => null),
|
||||
},
|
||||
tags: {
|
||||
status: tagsResponse.status,
|
||||
payload: await tagsResponse.json().catch(() => null),
|
||||
},
|
||||
};
|
||||
}, { rootUri: fileUrl(root), documentIdValue: documentId });
|
||||
}
|
||||
|
||||
async function capturePanelDiagnostics(page) {
|
||||
try {
|
||||
return await page.evaluate(function() {
|
||||
@@ -99,12 +151,16 @@ async function capturePanelDiagnostics(page) {
|
||||
var tg = document.querySelector('[data-testid="wolai-page-settings-local-index-tags"]');
|
||||
var st = document.querySelector('[data-testid="wolai-page-settings-local-index-status"]');
|
||||
var popover = document.querySelector('[data-testid="mnote-local-index-settings-popover"]');
|
||||
var ranges = document.querySelector('[data-testid="wolai-page-settings-local-index-ranges"]');
|
||||
var pageSettingsIndexTab = document.querySelector('[data-page-settings-tab="index"]');
|
||||
return {
|
||||
backlinksHtml: bl ? bl.innerHTML : '(missing)',
|
||||
tagsHtml: tg ? tg.innerHTML : '(missing)',
|
||||
statusText: st ? st.textContent : '(missing)',
|
||||
popoverExists: Boolean(popover),
|
||||
popoverHidden: popover ? popover.hidden : null,
|
||||
rangeInputs: ranges ? ranges.querySelectorAll('[data-local-index-range-input]').length : 0,
|
||||
hasPageSettingsIndexTab: Boolean(pageSettingsIndexTab),
|
||||
locationHref: window.location.href,
|
||||
};
|
||||
});
|
||||
@@ -157,6 +213,9 @@ async function run() {
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const settingsBeforeSearch = await browserUpdateLocalIndexSettings(page, root);
|
||||
assert.equal(settingsBeforeSearch.status, 200, `更新本地索引设置应成功: ${JSON.stringify(settingsBeforeSearch)}`);
|
||||
debug.settingsBeforeSearch = settingsBeforeSearch.payload;
|
||||
const refreshedBeforeSearch = await browserRefreshLocalIndex(page, root);
|
||||
assert.equal(refreshedBeforeSearch.status, 200, `刷新本地索引应成功: ${JSON.stringify(refreshedBeforeSearch)}`);
|
||||
debug.refreshedBeforeSearch = refreshedBeforeSearch.payload;
|
||||
@@ -173,23 +232,19 @@ async function run() {
|
||||
waitUntil: "domcontentloaded",
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
await page.locator('[data-testid="mnote-local-index-settings-toggle"]').click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="mnote-local-index-settings-popover"]').waitFor({
|
||||
state: "visible",
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
debug.navigationIndexSettings = await page.evaluate(function() {
|
||||
var popover = document.querySelector('[data-testid="mnote-local-index-settings-popover"]');
|
||||
var ranges = document.querySelector('[data-testid="wolai-page-settings-local-index-ranges"]');
|
||||
var indexToggle = document.querySelector('[data-testid="mnote-local-index-settings-toggle"]');
|
||||
var ragToggle = document.querySelector('[data-testid="mnote-knowledge-rag-settings-toggle"]');
|
||||
var pageSettingsIndexTab = document.querySelector('[data-page-settings-tab="index"]');
|
||||
return {
|
||||
path: window.location.pathname,
|
||||
visible: Boolean(popover && !popover.hidden),
|
||||
rangeInputs: ranges ? ranges.querySelectorAll('[data-local-index-range-input]').length : 0,
|
||||
hasLocalIndexToggle: Boolean(indexToggle),
|
||||
hasKnowledgeRagToggle: Boolean(ragToggle),
|
||||
hasPageSettingsIndexTab: Boolean(pageSettingsIndexTab),
|
||||
};
|
||||
});
|
||||
assert.equal(debug.navigationIndexSettings.visible, true, `导航页应能打开索引设置: ${JSON.stringify(debug.navigationIndexSettings)}`);
|
||||
assert.equal(debug.navigationIndexSettings.hasLocalIndexToggle, false, `导航页不应恢复旧本地索引设置入口: ${JSON.stringify(debug.navigationIndexSettings)}`);
|
||||
assert.equal(debug.navigationIndexSettings.hasKnowledgeRagToggle, true, `导航页应保留资料库问答入口: ${JSON.stringify(debug.navigationIndexSettings)}`);
|
||||
assert.equal(debug.navigationIndexSettings.hasPageSettingsIndexTab, false, `索引设置不应留在页面设置页签: ${JSON.stringify(debug.navigationIndexSettings)}`);
|
||||
|
||||
await page.goto(documentUrl(root, firstRelativePath), {
|
||||
@@ -201,49 +256,46 @@ async function run() {
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
|
||||
// 拦截 API 请求与页面错误做诊断
|
||||
// 拦截页面错误做诊断;backlink/tag 当前不再由索引面板渲染,下面走 API 直验。
|
||||
var diagApiResponses = {};
|
||||
page.on('response', function onDiag(resp) {
|
||||
var url = resp.url();
|
||||
if (url.includes('/api/search/local-index/backlinks') || url.includes('/api/search/local-index/tags')) {
|
||||
resp.json().then(function(body) { diagApiResponses[url] = body; }).catch(function() {});
|
||||
}
|
||||
});
|
||||
page.on('pageerror', function onPageError(err) { diagApiResponses._pageError = String(err); });
|
||||
page.on('console', function onConsole(msg) {
|
||||
if (msg.type() === 'error') { diagApiResponses._consoleErrors = (diagApiResponses._consoleErrors || []).concat([msg.text()]); }
|
||||
});
|
||||
|
||||
await page.locator('[data-testid="mnote-local-index-settings-toggle"]').click({ timeout: UI_TIMEOUT_MS });
|
||||
|
||||
// 等待本地索引面板渲染;超时时捕获 DOM 诊断再抛
|
||||
try {
|
||||
await page.waitForFunction(() => {
|
||||
var bl = document.querySelector('[data-testid="wolai-page-settings-local-index-backlinks"]');
|
||||
var tg = document.querySelector('[data-testid="wolai-page-settings-local-index-tags"]');
|
||||
return Boolean(
|
||||
bl && bl.textContent && bl.textContent.includes("README.md")
|
||||
&& bl.textContent.includes("[Target](docs/search-target.md)")
|
||||
&& tg && tg.textContent && tg.textContent.includes("#alpha"),
|
||||
);
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
} catch (waitError) {
|
||||
debug.diagApiResponses = diagApiResponses;
|
||||
debug.failedPanelState = await capturePanelDiagnostics(page);
|
||||
throw waitError;
|
||||
}
|
||||
|
||||
debug.localIndexPanel = await page.evaluate(function() {
|
||||
var bl = document.querySelector('[data-testid="wolai-page-settings-local-index-backlinks"]');
|
||||
var tg = document.querySelector('[data-testid="wolai-page-settings-local-index-tags"]');
|
||||
var st = document.querySelector('[data-testid="wolai-page-settings-local-index-status"]');
|
||||
var indexToggle = document.querySelector('[data-testid="mnote-local-index-settings-toggle"]');
|
||||
var ragToggle = document.querySelector('[data-testid="mnote-knowledge-rag-settings-toggle"]');
|
||||
var pageSettingsIndexTab = document.querySelector('[data-page-settings-tab="index"]');
|
||||
return {
|
||||
backlinks: bl ? bl.innerHTML : '(missing)',
|
||||
tags: tg ? tg.innerHTML : '(missing)',
|
||||
status: st ? st.textContent : '(missing)',
|
||||
hasLocalIndexToggle: Boolean(indexToggle),
|
||||
hasKnowledgeRagToggle: Boolean(ragToggle),
|
||||
hasPageSettingsIndexTab: Boolean(pageSettingsIndexTab),
|
||||
hasLegacyBacklinksDom: Boolean(document.querySelector('[data-testid="wolai-page-settings-local-index-backlinks"]')),
|
||||
hasLegacyTagsDom: Boolean(document.querySelector('[data-testid="wolai-page-settings-local-index-tags"]')),
|
||||
};
|
||||
});
|
||||
debug.diagApiResponses = diagApiResponses;
|
||||
assert.equal(debug.localIndexPanel.hasLocalIndexToggle, false, `文档页不应恢复旧本地索引设置入口: ${JSON.stringify(debug.localIndexPanel)}`);
|
||||
assert.equal(debug.localIndexPanel.hasKnowledgeRagToggle, true, `文档页应保留资料库问答入口: ${JSON.stringify(debug.localIndexPanel)}`);
|
||||
assert.equal(debug.localIndexPanel.hasPageSettingsIndexTab, false, `文档页索引设置不应回落到页面设置页签: ${JSON.stringify(debug.localIndexPanel)}`);
|
||||
assert.equal(debug.localIndexPanel.hasLegacyBacklinksDom, false, `独立索引面板不应恢复旧 backlink DOM: ${JSON.stringify(debug.localIndexPanel)}`);
|
||||
assert.equal(debug.localIndexPanel.hasLegacyTagsDom, false, `独立索引面板不应恢复旧 tags DOM: ${JSON.stringify(debug.localIndexPanel)}`);
|
||||
|
||||
const backlinksAndTags = await browserFetchLocalIndexBacklinksAndTags(page, root, localMdDocumentId(firstRelativePath));
|
||||
assert.equal(backlinksAndTags.backlinks.status, 200, `反链 API 应继续可用: ${JSON.stringify(backlinksAndTags)}`);
|
||||
assert.equal(backlinksAndTags.tags.status, 200, `标签 API 应继续可用: ${JSON.stringify(backlinksAndTags)}`);
|
||||
debug.backlinksAndTags = backlinksAndTags;
|
||||
const backlinks = backlinksAndTags.backlinks.payload?.result?.backlinks || [];
|
||||
assert(
|
||||
backlinks.some((item) => item.documentId === localMdDocumentId("README.md")),
|
||||
`本地索引反链应能找到 README.md: ${JSON.stringify(backlinksAndTags.backlinks.payload)}`,
|
||||
);
|
||||
const tags = backlinksAndTags.tags.payload?.result?.tags || [];
|
||||
assert(
|
||||
tags.some((item) => item.tag === "alpha"),
|
||||
`本地索引标签 API 应能返回 alpha: ${JSON.stringify(backlinksAndTags.tags.payload)}`,
|
||||
);
|
||||
|
||||
fs.renameSync(path.join(root, firstRelativePath), path.join(root, renamedRelativePath));
|
||||
const refreshedAfterRename = await browserRefreshLocalIndex(page, root);
|
||||
|
||||
Reference in New Issue
Block a user