深入理解 VS Code Copilot 的 /chronicle search:会话历史搜索提示词、SQL 工具与 SQLite FTS5 索引实现

📅 发布时间:2026/9/7 3:10:04
深入理解 VS Code Copilot 的 /chronicle search:会话历史搜索提示词、SQL 工具与 SQLite FTS5 索引实现 深入理解 VS Code Copilot 的 /chronicle search会话历史搜索提示词、SQL 工具与 SQLite FTS5 索引实现【免费下载链接】vscodeVisual Studio Code项目地址: https://gitcode.com/GitHub_Trending/vscode6/vscode本文以 VS Code 仓库中 Copilot 扩展的chronicle-search.prompt.md提示词文件为核心完整讲解/chronicle search命令的工作机制如何用关键词、文件路径或 PR/Issue 引用检索本地与云端会话历史、底层copilot_sessionStoreSql工具的参数契约与安全边界以及本地 SQLite FTS5 会话库的表结构与索引细节。读完之后你可以准确理解这条提示词背后的检索策略、写出合规的搜索 SQL并掌握云端 DuckDB 后端下的性能约束。一、文档本体/chronicle search斜杠提示词extensions/copilot/assets/prompts/chronicle-search.prompt.md是 Copilot 扩展内建的一组 Chronicle 提示词之一同目录还有chronicle-standup.prompt.md、chronicle-tips.prompt.md、chronicle-cost-tips.prompt.md、chronicle-improve.prompt.md、chronicle-reindex.prompt.md。它的 YAML frontmatter 定义了命令名与用途--- name: chronicle:search description: Search recent chat sessions by keyword, file path, or PR/issue ref ---正文要求模型完成一件事按用户提供的查询关键词、文件路径或 PR/Issue/Commit 引用搜索 Copilot 会话历史并列出匹配的会话。文档同时给出三条关键的实现约束必须使用 chronicle 技能即extensions/copilot/assets/prompts/skills/chronicle/SKILL.md。该技能是copilot_sessionStoreSql工具、会话库 Schema 与搜索工作流的唯一权威说明Schema 要点sessions表的主键是id不是session_id对话内容存放在turns表中而不在sessions上本地 SQLite 后端应使用 FTS5 的search_index表并且直接 SELECTsession_id列——绝不能把search_index.rowid与turns.rowid做 JOIN两者彼此独立JOIN 会拉入无关会话云端性能规则用WITH hits ... JOIN sessions的“聚合一次”模式且对turns表使用默认 90 天窗口技能文档中进一步细化为 7 天起步、逐步放宽见下文。文档最后一行是一条强制调用约定每次调用copilot_sessionStoreSql时都必须设置subcommand: search。这条约定在工具源码中有明确落点——subcommand参数被定义为standup | tips | cost-tips | search | improve | reindex的枚举注释写明其用途是“仅用于遥测归因”telemetry attribution only见 sessionStoreSqlTool.ts。也就是说设置subcommand: search不会改变查询行为而是让chronicle.sqlQuery遥测事件能够区分这次调用来自哪条/chronicle命令与模型自行发起的临时查询unknown区分开。二、chronicle 技能搜索工作流的权威定义/chronicle search query被触发后模型依据 chronicle/SKILL.md 执行以下流程。1. 搜索策略技能的 Search 工作流要求覆盖三类匹配目标因为用户的查询可能命中的是主题、文件路径或 PR/Issue 编号中的任意一种跨会话摘要sessions.summary、对话轮次turns中的用户消息和助手回复以及其他索引内容checkpoints、文件路径、refs 如 PR/issue/commit搜索为每个匹配会话收集足够的元数据用于标注s.id、s.repository、s.branch、s.summary、s.updated_at外加一段能说明“为什么匹配”的短片段例如云端用substr(user_message, 1, 160)或命中的file_path/ref_value结果按仓库分组按最近更新时间排序输出。2. 编写查询Schema 硬约束调用copilot_sessionStoreSql时使用action: query并附带description: Search sessions for query。技能中列出的 Schema 要点值得逐条掌握sessions表主键是id不是session_id其余所有表都以session_id作为指向sessions.id的外键。查询必须始终投影s.id不要臆造列名没有started_at用created_at/updated_at、没有workspace本地用cwd云端没有该列、没有title用summary、没有content/messages用turns.user_message/turns.assistant_response或云端events.user_content/events.assistant_content本地 SQLite正文检索优先使用 FTS5 的search_index表——WHERE search_index MATCH query。search_index自带session_id列直接 SELECT 即可文件路径和 refs不在FTS 索引里需要与session_files.file_path、session_refs.ref_value上的LIKE条件组合使用云端 DuckDB没有 FTS5对sessions、turns、checkpoints、session_files、session_refs的文本列使用ILIKE %query%。转义规则用户查询中的单引号要翻倍转义its→its多词 FTS5 查询要整体加引号当作短语MATCH apply patch。3. 云端性能规则避免超时云端DuckDB上ILIKE %X%作用于turns是全文扫描运行时间过长会返回context deadline exceeded。技能给出的对策两步法推荐先用 CTE 从turns中按窄时间窗口收集匹配的session_idGROUP BY session_id聚合再从sessions用WHERE id IN (...)补全元数据——避免对大规模扫描结果做昂贵 JOIN每会话的匹配信息用GROUP BY session_id配合any_value()/MIN()/array_agg()聚合而不是标量子查询或相关子查询云端对重量表默认使用7 天窗口turns上WHERE timestamp now() - INTERVAL 7 dayscheckpoints上同理用created_at无结果时逐步放宽 7 天 → 30 天 → 90 天并在摘要行中注明窗口范围最终 SELECT 保持LIMIT 50查询超时时应缩小窗口而不是扩大或去掉最重的表通常是turns并告知用户裁剪了什么绝不能用相同窗口重试。这与提示词原文“default 90-day window onturns”的表述相互印证90 天是窗口放宽的上限日常执行从更窄的窗口起步。4. 输出格式与无结果处理每个会话渲染为一行标签优先用summary否则用返回的片段截断至约 80 字符禁止输出(no summary)、(no metadata)或裸会话 ID 列表。技能规定的结果模板**Search results for query** (n sessions, scope: e.g. last 7 days / all time) _owner/repo_ - session-id — **summary 或 snippet** branch · updated 相对时间 · matched in match_kind配套规则每个仓库可见结果上限约 10 条超出时追加…and N more (refine your query)尽量带上· matched in match_kindturn / file / ref / checkpoint / meta帮助用户理解每个会话为什么命中repository为 NULL 的会话归入Other分组。若无结果技能要求给出四条建议换更宽泛的关键词单词或子串代替短语、扩大时间窗口“search all time”、若尚未建索引则运行/chronicle reindex、或运行/chronicle standup查看近期活动。三、源码佐证copilot_sessionStoreSql工具的运行机制提示词与技能描述的每一个约束都能在 sessionStoreSqlTool.ts 中找到对应实现。1. 参数契约与 action 路由工具入参为actionquery/reindex缺省为query、query、force仅 reindex 用、description必填与subcommand。invoke方法按action分派reindex走_invokeReindex其余一律走_invokeQuery见 invoke 入口。2. 查询安全黑名单 白名单 单语句_invokeQuery对模型提交的 SQL 做四层校验去除首尾空白与尾随分号模型常自作主张追加空查询直接报错黑名单正则BLOCKED_PATTERNS拦截INSERT/UPDATE/DELETE/DROP/CREATE/ALTER/TRUNCATE/REPLACE、ATTACH/DETACH、PRAGMA保留data_version例外供 FTS5 内部使用、VACUUM、REINDEX、ANALYZE、LOAD_EXTENSION、事务控制词BEGIN/COMMIT/ROLLBACK/SAVEPOINT/RELEASE白名单先剥掉前导行注释与块注释防止/* 注释 */ VACUUM这类“注释夹带”再要求语句必须以SELECT或WITH开头语句中出现任何分号即拒绝每次调用只允许一条 SQL。这些行为有专门的测试固化sessionStoreSqlTool.spec.ts 验证了DROP TABLE、VACUUM INTO、SELECT load_extension(...)、PRAGMA data_version、注释前缀夹带、多语句、空查询等全部被Blocked SQL拦截而WITH x AS (SELECT 1 AS n) SELECT * FROM x的 CTE 查询可以正常放行尾随分号会被剥离后再执行。3. 本地/云端路由与方言切换路由由SessionIndexingPreference.hasCloudConsent()决定开启云同步时经CloudSessionStoreClient查询云端 DuckDB包含跨设备、跨 Agent 的全部会话鉴权或网络失败时自动回退本地结果标记source: local_fallback未开启则直接查本地 SQLite。方言差异不是靠模型自觉而是由alternativeDefinition在运行时替换工具定义实现的——云同步开启时工具描述被换成CLOUD_MODEL_DESCRIPTIONDuckDB 语法、now() - INTERVAL日期运算、ILIKE文本检索query参数的 schema 描述同步改写见 alternativeDefinition。本地版描述则声明在 package.json 的languageModelTools中SQLite 语法、datetime(now, -1 day)日期运算、FTS5MATCH并指回chronicle技能查列级细节。值得注意的契约设计测试文件 中有一段注释明确“列级 Schema 的唯一事实来源在 chronicle/SKILL.md”工具描述只承载低漂移信号方言、只读约束、表名、技能指引并有回归测试钉住这些锚点字符串。搜索提示词文档与技能文档的分工正是这一设计的体现。4. 结果格式与上下文预算结果以 Markdown 表格返回两个硬预算防止撑爆上下文窗口行数上限MAX_ROWS 100对应技能中“Always use LIMIT (max 100)”的要求总输出字符预算TOTAL_FORMAT_BUDGET 30_000——超出时单元格先被均匀地自适应截断整体再兜底截断并附加[TRUNCATED]/ “Add a LIMIT clause or narrow your query” 提示见 formatSqlResult。四、本地会话库SQLite FTS5 的表结构与索引会话库由 sessionStore.ts 中的SessionStore类实现node:sqlite FTS5Schema 版本 3。ensureSchema创建的表结构与技能文档一致且注释说明该 Schema 与 copilot-agent-runtimeCLI 侧的 SessionStore 相同以便查询在两个表面间可移植表关键列说明sessionsid主键、cwd、repository、branch、host_type、summary、agent_name、agent_description、created_at、updated_at会话元数据云端中cwd恒为 NULLturnssession_id、turn_index、user_message、assistant_response、timestamp对话内容所在表UNIQUE(session_id, turn_index)assistant_response仅存开头约 1000 字符checkpointssession_id、checkpoint_number、title、overview、history、work_done、technical_details、important_files、next_steps、created_at压缩compaction检查点session_filessession_id、file_path、tool_name、turn_index、first_seen_at会话触碰过的文件session_refssession_id、ref_typecommit/pr/issue、ref_value、turn_index、created_atPR/Issue/Commit 引用search_indexFTS5 虚拟表content、session_id UNINDEXED、source_type UNINDEXED、source_id UNINDEXED本地全文索引与搜索直接相关的三个实现细节FTS 条目的写入路径insertTurn把user_message与assistant_response合并为一条source_type turn的索引记录source_id为{session_id}:turn:{turn_index}insertCheckpoint则把 overview/history/work_done/technical_details/important_files/next_steps 六个非空段落分别建成独立条目见 insertTurn。这就解释了技能文档的告诫search_index的rowid是自增序号与turns.idAUTOINCREMENT 主键没有任何对应关系JOIN 它们只会匹配到无关行——正确做法是直接投影search_index.session_id。BM25 排序的内置检索SessionStore.search()使用bm25(search_index) AS rank ... ORDER BY rank做全文检索见 search 方法技能同时给出取片段的两种方式snippet(search_index, 0, [, ], …, 12)或substr(content, 1, 160)。引擎级只读强制executeReadOnly在 Node.js 24.2提供setAuthorizer时安装一个动作码白名单——只放行SQLITE_READ、SQLITE_SELECT、SQLITE_FUNCTION且load_extension被显式拒绝、SQLITE_RECURSIVE并为 FTS5 的内部探测放行PRAGMA data_version见 executeReadOnly。这是工具层正则校验之外的第二道防线也是PRAGMA data_version能出现在例外注释里的原因。此外Schema 建立了idx_sessions_repo、idx_sessions_cwd、idx_session_files_path、idx_session_refs_type_value、idx_turns_session、idx_checkpoints_session等索引见 ensureSchema搜索中按仓库、文件路径、引用值过滤时可以走索引。远端工作区网络文件系统下存储会切换为PRAGMA journal_mode DELETE 更长busy_timeout并带有一次性的损坏库重建逻辑属于运维细节与查询语义无关。五、实战查询形态结合提示词、技能与上述实现三类搜索目标对应的查询形态如下。1. 关键词搜索本地 SQLiteFTS5SELECT session_id, snippet(search_index, 0, [, ], …, 12) AS snippet FROM search_index WHERE search_index MATCH apply patch LIMIT 50多词短语查询用MATCH apply patch单引号翻倍转义。拿到session_id集合后再按技能要求从sessions补元数据。文件路径与 refs 不在 FTS 索引中需要并行查询-- 文件路径命中 SELECT s.id, s.repository, s.branch, s.summary, s.updated_at, f.file_path FROM session_files f JOIN sessions s ON s.id f.session_id WHERE f.file_path LIKE %copilot%; -- PR/Issue/Commit 引用命中 SELECT s.id, s.repository, s.branch, s.summary, s.updated_at, r.ref_type, r.ref_value FROM session_refs r JOIN sessions s ON s.id r.session_id WHERE r.ref_value LIKE %1234%;2. 云端 DuckDB 两步法聚合一次避免超时技能给出的“WITH hits ... JOIN sessions”模式落地为WITH hits AS ( SELECT session_id, MIN(timestamp) AS first_hit, array_agg(user_message) AS samples FROM turns WHERE timestamp now() - INTERVAL 7 days AND (user_message ILIKE %query% OR assistant_response ILIKE %query%) GROUP BY session_id ) SELECT s.id, s.repository, s.branch, s.summary, s.updated_at FROM sessions s JOIN hits h ON h.session_id s.id ORDER BY s.updated_at DESC LIMIT 50;时间窗口从 7 天起步无结果时放宽到 30/90 天并在结果头部注明窗口超时时缩小窗口或去掉turns条件而不是原样重试。3. 通用查询守则Query Guidelines技能“Query Guidelines”一节对搜索同样适用每次调用只发一条查询不要分号拼接仅允许SELECT/WITHDESCRIBE/SHOW/PRAGMA一律被拦——不要试图自省库结构直接读技能中的 Schema始终带LIMIT工具上限 100 行、优先COUNT/GROUP BY聚合而非裸行转储时间范围过滤一律用updated_at而非created_at分析对话内容时 JOINsessions与turns不要只依赖sessions.summary。六、前置条件、配套命令与边界前置设置技能声明 Chronicle 要求github.copilot.chat.localIndex.enabled为true若copilot_sessionStoreSql工具不可用应提示用户在 VS Code Settings 中开启而工具声明本身的可见性条件写在 package.json 的when: github.copilot.sessionSearch.enabled中。两处分别控制“索引/工具能力开启”与“工具声明注册”排查时都应检查。云同步chat.sessionSync.enabled决定查询路由到云端 DuckDB全设备、全 Agent 数据还是本地 SQLite仅本设备会话。这也决定了文本检索手段——FTS5MATCH仅本地可用云端用ILIKE。重建索引搜索无结果且怀疑未建索引时运行/chronicle reindex即action: reindex可选force: true重处理已索引会话工具会从调试日志重建本地库并在开启云同步时上传新会话返回前后统计对照表见 _invokeReindex。删除不在工具能力内copilot_sessionStoreSql有意不支持删除语句黑名单 白名单双重拦截且引擎层 authorizer 只放行读操作。删除会话数据须走命令面板的Delete Session Sync Datagithub.copilot.sessionSync.deleteSessions命令从本地与云端选择删除。七、小结chronicle-search.prompt.md虽然只有一页篇幅但它把一个完整的检索系统设计压缩成了三条硬约束加一条调用约定用 chronicle 技能、守住 Schema 要点主键id、内容在turns、FTS5 直查session_id、遵循云端聚合一次的性能规则并始终以subcommand: search调用工具。从源码看这些约束背后分别对应SessionStoreSqlTool的白名单/黑名单校验与方言切换、SessionStore的 FTS5 写入与 BM25 检索、以及“列级 Schema 唯一事实来源在 SKILL.md”的契约化测试——提示词文档、技能文档与工具实现三者互为印证构成了 VS Code Copilot 会话历史搜索这一特性的完整证据链。【免费下载链接】vscodeVisual Studio Code项目地址: https://gitcode.com/GitHub_Trending/vscode6/vscode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考