feat(rag): align LightRAG native citations and MCP bridge

This commit is contained in:
lix-2026
2026-06-09 09:20:56 +08:00
parent 0e8b03daf8
commit 8e3be8b0b7
39 changed files with 2255 additions and 2732 deletions
@@ -2038,6 +2038,22 @@ export function createSidebarPageAiRuntime(context) {
});
}
function pageAiKnowledgeRagFallbackQuery(prompt) {
var text = searchText(prompt);
if (!text) return '';
var afterColon = text.split(/[:]/).slice(1).join('').trim();
var candidate = afterColon || text;
candidate = candidate
.replace(/^(请|请用|帮我|帮忙|用)?(资料库|知识库|lightrag|rag)?(搜索|检索|查找|查询|回答|说明|解释|总结)?/i, '')
.replace(/(请)?(给出|给我|附上|提供)?(链接|引用|来源|出处|证据|定位).*$/i, '')
.trim();
var stopIndex = candidate.search(/(在|的|是|有哪些|有什么|如何|怎么|用于|用途|作用|资料|文献|论文)/);
if (stopIndex > 0) candidate = candidate.slice(0, stopIndex).trim();
var cjkMatch = candidate.match(/[A-Za-z0-9\u4e00-\u9fff·α-ωΑ-Ω\-]{2,24}/);
if (cjkMatch && cjkMatch[0]) return cjkMatch[0];
return text;
}
function pageAiCleanDegradedCitationNotes(content) {
return String(content || '')
.split('\n')
@@ -2050,38 +2066,92 @@ export function createSidebarPageAiRuntime(context) {
.trim();
}
function pageAiCollectKnowledgeRagApiCitations(payload) {
var references = pageAiNormalizeArray(payload && payload.references);
var citations = references.map(function(reference) {
return String(reference && reference.citationMarkdown || '').trim();
}).filter(Boolean);
var hasPreciseCitation = references.some(function(reference) {
return String(reference && reference.citationMarkdown || '').trim() && reference && reference.locatorDegraded !== true;
function pageAiCitationPrecisionLabel(value) {
var precision = searchText(value || '').toLowerCase();
if (precision === 'bbox') return '精确定位';
if (precision === 'paragraph') return '段落级';
if (precision === 'file') return '文件级';
return '';
}
function pageAiCitationSourceTitle(citation) {
if (!citation || typeof citation !== 'object') return '';
var path = searchText(citation.sourceRootRelativePath || citation.sourcePath || citation.filePath || citation.lightRagFilePath || '');
if (path) {
var parts = path.split('/').filter(Boolean);
return parts[parts.length - 1] || path;
}
var markdown = searchText(citation.citationMarkdown || '');
var labelMatch = markdown.match(/^\[([^\]]+)\]/);
return labelMatch ? labelMatch[1] : '';
}
function pageAiCitationDisplayMarkdown(value) {
if (typeof value === 'string') return value.trim();
if (!value || typeof value !== 'object') return '';
var markdown = searchText(value.citationMarkdown || '');
var citationId = searchText(value.citationLabel || (value.citationId ? '[' + value.citationId + ']' : ''));
var title = pageAiCitationSourceTitle(value);
var headingPath = pageAiNormalizeArray(value.headingPath).map(function(item) {
return searchText(item);
}).filter(Boolean).join(' > ');
var precisionLabel = pageAiCitationPrecisionLabel(value.locatorPrecision);
var quote = searchText(value.displayQuote || value.quote || '');
if (quote.length > 120) quote = quote.slice(0, 117) + '...';
var head = markdown || title;
if (citationId && head.indexOf(citationId) < 0) head = citationId + ' ' + head;
var details = [];
if (precisionLabel) details.push(precisionLabel);
if (headingPath) details.push(headingPath);
if (quote) details.push(quote);
return [head].concat(details).filter(Boolean).join(' · ').trim();
}
function pageAiFilterCitationCards(values) {
var cards = pageAiNormalizeArray(values);
var hasPreciseCitation = cards.some(function(value) {
if (typeof value === 'string') return value.indexOf('来源定位降级') < 0;
return value && typeof value === 'object' && searchText(value.citationMarkdown || '') && value.locatorDegraded !== true;
});
var seen = {};
return citations.filter(function(citation) {
if (seen[citation]) return false;
if (hasPreciseCitation && citation.indexOf('来源定位降级') >= 0) return false;
seen[citation] = true;
return cards.map(pageAiCitationDisplayMarkdown).filter(function(card, index) {
var source = cards[index];
if (!card || seen[card]) return false;
if (hasPreciseCitation) {
if (typeof source === 'string' && source.indexOf('来源定位降级') >= 0) return false;
if (source && typeof source === 'object' && source.locatorDegraded === true) return false;
}
seen[card] = true;
return true;
}).slice(0, 5);
}
function pageAiCollectKnowledgeRagApiCitations(payload) {
var structuredCitations = pageAiNormalizeArray(payload && payload.citations);
if (structuredCitations.length) {
return pageAiFilterCitationCards(structuredCitations);
}
var references = pageAiNormalizeArray(payload && payload.references);
return pageAiFilterCitationCards(references);
}
async function pageAiAppendKnowledgeRagFallbackCitations(runId, promptText) {
if (!pageAiPromptNeedsKnowledgeRagCitations(promptText)) return;
var rootUri = currentRootUri();
if (!rootUri) return;
var fallbackQuery = pageAiKnowledgeRagFallbackQuery(promptText);
if (!fallbackQuery) return;
try {
var response = await fetch('/api/knowledge-rag/query', {
var response = await fetch('/api/knowledge-rag/search', {
method: 'POST',
headers: { 'content-type': 'application/json', 'accept': 'application/json' },
body: JSON.stringify({
workspaceId: resolveWorkspaceId(document.body) || undefined,
rootUri: rootUri,
query: String(promptText || '').trim(),
query: fallbackQuery,
mode: 'mix',
topK: 8,
chunkTopK: 8,
topK: 12,
chunkTopK: 24,
includeChunkContent: true
})
});
@@ -2193,10 +2263,11 @@ export function createSidebarPageAiRuntime(context) {
return;
}
if (typeof node !== 'object') return;
if (typeof node.citationMarkdown === 'string') add(node.citationMarkdown);
if (typeof node.citationMarkdown === 'string') add(pageAiCitationDisplayMarkdown(node));
if (Array.isArray(node.citationMarkdowns)) {
node.citationMarkdowns.forEach(function(value) {
if (typeof value === 'string') add(value);
else if (value && typeof value === 'object') add(pageAiCitationDisplayMarkdown(value));
else visit(value);
});
}