feat(semantic-index): expose semantic search via routes, agent tool and pipeline

Add shared /_web/ai/semantic-index HTTP routes and wire the service into
CLI web and Electron internal API. Introduce the semantic_search_current_chat
agent tool (AGENT-only, not MCP) with desensitized output and a narrowed
service interface, forward the semantic-search context through the CLI and
Desktop tool adapters, and integrate on-demand semantic search into the
agent pipeline with guidance and a max-result-token evidence budget.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
diguaandCursor committed 2026-06-21 16:18:39 +08:00
1 parent e3f38cfb8b
commit b9599da1c8
25 files changed
+741 -20

No files matched your search

@@ -6,6 +6,7 @@ export type { LlmRouteDecider, RequestRoute, RouteDecision, RouteDecisionSource,
export { buildPlanGuidance, createAnalysisPlanner, createPlanContentBlock } from './planner'
export { createDataSnapshotFromOverview } from './data-snapshot'
export type { ChatOverviewForSnapshot } from './data-snapshot'
export { buildSemanticSearchGuidance } from './semantic-search-guidance'
export type {
AnalysisPlanIntent,
AnalysisPlanner,
@@ -0,0 +1,24 @@
/**
* 语义检索工具引导语
*
* 仅当当前会话语义索引可检索、工具被暴露给 LLM 时,由两端 runner 注入 system prompt。
* 引导模型在需要历史证据时调用 semantic_search_current_chat,避免寒暄/写作类问题无谓检索。
*/
function isChinese(locale?: string): boolean {
return (locale ?? '').toLowerCase().startsWith('zh')
}
export function buildSemanticSearchGuidance(locale?: string): string {
if (isChinese(locale)) {
return [
'当需要确认本对话历史中的具体事实、人物、地点、事件或过往提及时,调用 semantic_search_current_chat 检索相关片段。',
'寒暄、写作、解释通用概念等不依赖历史证据的问题不要调用该工具。',
].join('')
}
return [
'When you need concrete facts, people, places, events, or past mentions from THIS conversation history, ',
'call semantic_search_current_chat to retrieve relevant excerpts. ',
'Do not call it for greetings, writing, or explaining general concepts that need no historical evidence.',
].join('')
}
@@ -17,6 +17,7 @@ function createPathProvider(root: string): PathProvider {
getSystemDir: () => root,
getUserDataDir: () => path.join(root, 'data'),
getDatabaseDir: () => path.join(root, 'data', 'databases'),
getVectorDir: () => path.join(root, 'data', 'vector'),
getAiDataDir: () => path.join(root, 'ai'),
getSettingsDir: () => path.join(root, 'settings'),
getCacheDir: () => path.join(root, 'cache'),