VS Code Copilot Chronicle 技能实战:用 SQL 查询会话历史,实现 Standup、成本分析与会话检索
本文围绕 VS Code Copilot 扩展内置的 Chronicle(编年史)技能展开,它是 Copilot Agent 用于分析用户全部 Copilot 会话历史的能力模块。读完本文,你将掌握 Chronicle 的启用配置、copilot_sessionStoreSql 工具的两种动作(query / reindex)、本地 SQLite 与云端 DuckDB 双后端的 Schema 与 SQL 方言差异,以及 Standup 日报、使用技巧(Tips)、成本优化建议(Cost Tips)、指令改进(Improve)、会话检索(Search)、重建索引(Reindex)六大工作流的完整操作规范,并理解该工具在源码层面的安全限制与查询路由实现。
Chronicle 是什么:从技能定位到工具依赖
Chronicle 是一个定义在 SKILL.md 中的 Copilot 技能。它的职责是:基于用户的 Copilot 会话历史完成四类任务——生成站会(standup)报告、提供使用/成本优化建议、按关键词/文件/PR 检索历史会话、以及维护(重建)本地会话索引。其触发场景在技能 frontmatter 中写得很明确:当用户请求 standup、每日总结、使用技巧、工作流建议、想按关键词/文件/PR 查找历史会话、想重建会话索引,或询问删除会话数据时,应使用本技能。
整个技能的技术底座是 copilot_sessionStoreSql 工具。从源码看,该工具的注册名与参数定义位于 sessionStoreSqlTool.ts 与 toolNames.ts(其中 SessionStoreSql = 'copilot_sessionStoreSql'),并且它被归类为核心工具(ToolCategory.Core)。在 Agent 意图中,agentIntent.ts 明确将 ToolName.SessionStoreSql 加入允许工具列表,说明它主要服务于 Agent 模式的对话执行。
会话的存储形态是双重的:
- 本地:SQLite 数据库,只包含当前设备的会话;
- 云端(可选):开启
chat.sessionSync.enabled后同步到云端,供跨设备、跨 Agent 访问。
前置条件:Chronicle 要求 github.copilot.chat.localIndex.enabled 设置为 true。若 copilot_sessionStoreSql 工具不可用,应提示用户在 VS Code 设置中开启该选项。该设置在 package.json 中声明,本地化描述为 “Enable local session tracking. When enabled, session data is tracked locally for /chronicle commands.”
工具动作与调用参数
copilot_sessionStoreSql 工具支持两种动作:
| Action | 用途 | query 参数 |
|---|---|---|
query |
执行只读 SQL 查询 | 必填 |
reindex |
重建本地会话索引 + 云同步 | 不需要 |
从 sessionStoreSqlTool.ts 的参数接口可以看到完整的输入面:
export interface SessionStoreSqlParams {
readonly action?: 'query' | 'reindex';
readonly query?: string;
readonly force?: boolean; // 仅 reindex:强制重新处理已索引的会话
readonly description: string;
// 发起该调用的 /chronicle 斜杠命令(standup/tips/cost-tips/search/improve/reindex),仅用于遥测归因
readonly subcommand?: 'standup' | 'tips' | 'cost-tips' | 'search' | 'improve' | 'reindex';
}
几个对实际使用有影响的源码级细节:
- 行数上限:
MAX_ROWS = 100,超过即截断并在结果中标注[TRUNCATED],这与技能文档中 “Always use LIMIT (max 100)” 的查询规范相互印证; - 输出预算:查询结果以 Markdown 表格返回,总字符量受 30,000 的硬预算约束,超出会被整体截断——所以查询应优先聚合(
COUNT、GROUP BY)而非原始行转储; - reindex 的输出:工具会返回 Before / After / Delta 的统计表(Sessions、Turns、Files、Refs 四项),并追加 “N session(s) processed, M skipped”;若云同步开启,还会触发
github.copilot.sessionSync.reindex命令将新会话上传云端(该阶段失败不影响本地重建结果)。
查询路由:本地 SQLite 还是云端 DuckDB?
技能文档中反复强调 “Always follow the SQL syntax shown in the tool description”,这句话在源码中有精确的对应实现:工具类实现了 alternativeDefinition() 方法——当云同步开启时,工具动态替换自己暴露给模型的描述与输入 Schema 为 DuckDB 方言版本(CLOUD_MODEL_DESCRIPTION 明确写着 “Use now() - INTERVAL '1 day' … ILIKE for text search (no FTS5/MATCH)”)。
路由决策由 sessionIndexingPreference.ts 中的 SessionIndexingPreference 类完成,它读取两个设置:
chat.localIndex.enabled:启用本地 SQLite 跟踪与/chronicle命令;chat.sessionSync.enabled:启用云端上传,并支持chat.sessionSync.excludeRepositories按 picomatch 模式排除特定仓库。
由此得到的路由规则与技能文档一致:
- 云同步开启:查询路由到云端 DuckDB 后端,覆盖所有设备与 Agent(VS Code、CLI、Copilot Coding Agent、PR reviews)的会话;
- 云同步关闭:查询路由到本地 SQLite,仅含本机会话;
- 容错降级:云端调用若发生鉴权/网络失败(
CloudSessionStoreClient返回空值),工具自动回落到本地执行(遥测中记录为local_fallback)。
数据库 Schema:两张后端共有的表 + 云端专属表
本地与云端共有表
| 表 | 关键列 | 说明 |
|---|---|---|
sessions |
id, cwd, repository, branch, host_type, summary, agent_name, agent_description, created_at, updated_at | 会话主表;id 是主键(不是 session_id);云端中 cwd 恒为 NULL |
turns |
session_id, turn_index, user_message, assistant_response, timestamp | 对话轮次;assistant_response 只有开头约 1000 字符,可能被截断 |
checkpoints |
session_id, checkpoint_number, title, overview, history, work_done, technical_details, important_files, next_steps, created_at | 压缩(compaction)检查点,存储会话的摘要状态;云端列更少(无 history / work_done / technical_details) |
session_files |
session_id, file_path, tool_name, turn_index, first_seen_at | 会话中触碰的文件与工具 |
session_refs |
session_id, ref_type (commit/pr/issue), ref_value, turn_index, created_at | PR / Issue / Commit 引用 |
search_index |
content, session_id, source_type, source_id | 仅本地的 FTS5 虚拟表,用于全文检索 |
本地 SQLite 的建表 DDL 可以在 sessionStore.ts 中逐列对上号:sessions 以 id TEXT PRIMARY KEY 为主键,turns 有 UNIQUE(session_id, turn_index) 约束,session_files 与 session_refs 均带外键指向 sessions(id)。该文件还展示了 Schema 的演进方式——schema_version 表记录版本,v1→v2 通过 ALTER TABLE 增加 host_type 列,v1→v3 增加 agent_name / agent_description 列,与技能文档中 “checkpoints 云端列更少” 等差异描述一致。search_index 则是受保护的 FTS5 虚拟表(content, session_id UNINDEXED, source_type UNINDEXED, source_id UNINDEXED)。
云端专属表(DuckDB)
events:原始事件表(约 90 列)。关键列:session_id、timestamp、type、user_content、assistant_content、tool_start_name、tool_complete_success、tool_complete_result_content、usage_model、usage_input_tokens、usage_output_tokens。注意:本地 SQLite 没有events表,也不记录逐事件 token 用量——本地后端下无法做真正的 token 级分析;tool_requests:session_id、tool_call_id、name、arguments_json。
SQL 方言速查
| 需求 | 本地 SQLite | 云端 DuckDB |
|---|---|---|
| 近 1 天窗口 | datetime('now', '-1 day') |
now() - INTERVAL '1 day' |
| 近 7 天窗口 | datetime('now', '-7 days') |
now() - INTERVAL '7 days' |
| 文本检索 | FTS5:WHERE search_index MATCH '<query>' |
ILIKE '%<query>%'(无 FTS5/MATCH) |
| 时长计算 | — | date_diff('minute', start, end) |
工作流一:Standup(站会日报)
当用户请求 standup、每日总结或 “what did I do”(如 /chronicle standup)时,按三步执行:
Step 1:收集近 24 小时的活动
用 action: "query" 查询 sessions 表中 updated_at 落在最近 24 小时内的行,按 updated_at 降序。近期窗口谓词按后端区分:
- 本地 SQLite:
WHERE updated_at >= datetime('now', '-1 day') - 云端 DuckDB:
WHERE updated_at >= now() - INTERVAL '1 day'
随后对命中的 session id 从 session_refs 拉取关联引用(PR、issue、commit)。需要某个会话的更多细节时,再深入查询 turns(必要时加 session_files,云端可加 checkpoints)——不要一上来就把所有会话的每一轮对话都拉出来。
若近 24 小时没有任何会话,如实告知用户没有近期活动,建议加大时间窗口或执行 /chronicle reindex 后停止。不要编造 standup 内容。
Step 2:纳入无 PR 的工作
每一个近期会话都是候选工作项,即使它没有任何 PR / issue / commit 引用。PR 只是佐证而非事实来源。不能仅因缺少 PR 就省略某个会话或分支——应依据会话摘要与轮次内容判断收录。
Step 3:核对 PR 状态并格式化
对找到的 PR 引用,用 GitHub CLI 或 MCP 工具核对当前状态(open / merged / draft / closed)。每个工作项要么给一行 PR 状态,要么写 “No PR found”——绝不虚构 PR。
按工作流(分支/特性)分组输出,结构固定为:
Standup for <date>:
**✅ Done**
**Feature name** (`branch-name` branch, `repo-name`)
- 3-7 words describing the status
- Key files: 2-3 most important files changed
- Merged: [#123](https://github.com/owner/repo/pull/123) or No PR found
- Session: `full-session-id`
**🚧 In Progress**
**Feature name** (`branch-name` branch, `repo-name`)
- 3-7 words describing the current state of work
- Key files: 2-3 most important files being worked on
- Draft: [#789](https://github.com/owner/repo/pull/789) or No PR found
- Session: `full-session-id`
(上例中的 GitHub URL 为文档规定的 Markdown 链接占位格式,实际输出时应替换为对应 PR 的真实链接。)
格式规则:
- 保持简洁——用户随时可以追问细节;
- 用
turns数据(用户消息与助手回复)理解 “做了什么”; - 用
session_files中的文件路径判断影响了哪些组件/区域; - 同一分支的多个相关会话合并为一条;每个特性/分支只展示最近一个会话;
- PR 与 issue 用 Markdown 链接语法;
- 工作看起来已完成则归入 Done,否则归入 In Progress;
- 没有分支/仓库信息的会话归入 “Other” 小节。
工作流二:Tips(使用技巧与改进建议)
Step 1:调研用户的工作方式
用 action: "query" 探索近期会话。目标是理解模式:如何写 prompt、用哪些工具、时间花在哪里。直接开始查询,不要先解释要做什么。建议查询:
- 最近 7 天会话:数量、时长、所在仓库;
turns:读取真实用户消息,理解 prompt 模式;session_files:哪些文件/工具使用最频繁;session_refs:PR / issue / commit 活动模式。
Step 2:盘点可用能力
若当前工作区有 .github/ 目录,检查 .github/copilot-instructions.md、.github/skills/、.github/agents/ 中已有哪些自定义配置。不要查看工作区之外的东西。找出 “已有能力” 与 “用户实际使用” 之间的差距。
Step 3:给出 3-5 条具体可执行的建议
每条建议须:基于真实使用数据(引用观察到的具体模式);非显而易见(跳过普通用户已知的入门功能);聚焦于能通过某个功能、工作流变化或不同方法带来实质性改进的缺口。
可探索的分析维度:
- Prompt 模式:用户消息是含糊还是具体?是否提供上下文?是否频繁纠正/重定向 Agent?
- 工具使用:哪些工具用得最多?有哪些被低估的工具本可派上用场?
- 会话模式:会话多长?是否存在大量短命即弃的会话?
- 文件模式:代码库哪些区域被关注最多?同一批文件是否被反复编辑?
- 工作流:用户是否在用 Agent 模式、自定义指令、prompt 文件、skills?
若会话数据很少,如实说明,并基于工作区中找到的配置给出可尝试的功能建议。推荐自定义 skill / agent / instructions 作为建议时,应参考 agent-customization 技能中规范的建文件模式——不能只给 “去创建一个自定义 skill” 这种没有文件结构指导的空泛建议。
工作流三:Cost Tips(Token 成本优化建议)
当用户请求成本建议、减少 token 用量的方法(如 /chronicle cost-tips)时,目标是个性化的、以数据为据的推荐,而不是通用清单。每条 tip 必须指向你在数据中观察到的具体模式。
作用域:聚焦 VS Code 交互式聊天
其他 Agent 面(Copilot CLI、Copilot Coding Agent、Copilot Code Review、自定义 agent/subagent)的成本画像差异很大,混在一起会扭曲分析。默认应把每条查询过滤到交互式 VS Code 聊天;仅当用户明确要求分析 CLI / Coding Agent / 自定义 agent 时才扩大范围,且要为每种 agent 类型单独跑查询,不要混在一次分析里。
存储中的 agent_name 值因后端而异,必须精确匹配(大小写与空格都敏感):
- 云端(DuckDB):
sessions.agent_name = 'VS Code Chat' - 本地(SQLite):
sessions.agent_name = 'GitHub Copilot Chat'。本地还会把 subagent 调用(如Explore、summarizeConversationHistory)记录为独立会话行,默认过滤会正确排除它们。
先跑一次 agent 构成检查(例如 SELECT agent_name, COUNT(*) AS n FROM sessions WHERE updated_at > <30-day cutoff> GROUP BY 1 ORDER BY n DESC)确认被排除的是什么。如果交互式聊天只占用户会话的小头,要在总结中说明建议只覆盖了活动的一个切片,并主动提出可以对另一种 agent 类型单独跑一轮分析——点名你看到的候选值(如 “要不要对 Copilot CLI 或 Copilot Coding Agent 单独跑一遍?”)。用户要求扩大范围时,把默认 agent_name 过滤换成对应值,只对该切片做分析,并在总结中注明范围、以及当前后端无法分析的内容(例如本地后端下云端专属的 token 列)。
成本相关的 Schema 要点
- 仅云端 DuckDB 有逐事件计费数据——本地 SQLite 不记录逐事件 token 用量,也没有
events表。若当前后端是本地,应门控所有 token 查询,并告知用户真正的 token 级分析需要开启chat.sessionSync.enabled; events(云端):type = 'assistant.usage'的行携带usage_input_tokens、usage_output_tokens、usage_model。连接方式为JOIN events e到sessions s ON s.id = e.session_id,并过滤WHERE s.agent_name = 'VS Code Chat'保持作用域收紧;turns:用LENGTH(user_message)(云端则用events中type = 'user.message'行的LENGTH(user_content))定位超大粘贴内容。
Step 1:调研成本与 token 模式
云端(DuckDB)——深挖成本模式(events 行按 type = 'assistant.usage' 过滤,JOIN sessions 保持 agent_name = 'VS Code Chat'):
- Token 大户会话与轮次:按会话、按模型对
events(type = 'assistant.usage')的usage_input_tokens/usage_output_tokens求和。哪些会话烧 token 最多?用的哪些模型? - 输入/输出比:输入 token 远大于输出时,说明用户每轮都在为重发臃肿上下文付费——这是 compaction、缩小工作集或开新会话最能帮到的强信号;
- 模型构成:按
usage_model拆解花费。昂贵模型是否被用于改名、简单编辑、状态确认等常规工作? - 逐轮增长:长会话中
usage_input_tokens是否逐轮攀升?是未使用 compaction 的强信号; - 超大粘贴:
events(type = 'user.message')上的LENGTH(user_content)找出本应是文件引用的用户消息(在session_files中也表现为同一会话内对同一路径的重复读取)。
本地(SQLite)——无 token 数据,用代理指标(每条查询都过滤 sessions.agent_name = 'GitHub Copilot Chat'):
- 无 compaction 的长会话:轮次很多且
checkpoints中没有行的会话(每个 checkpoint 行代表一次成功的压缩)。LEFT JOIN checkpoints c ON c.session_id = s.id WHERE c.session_id IS NULL加轮次阈值即可筛出候选; - 压缩过晚:对有 checkpoint 的会话,对比
checkpoints.checkpoint_number与created_at和会话总轮次。80 轮会话在第 60 轮才首次压缩,远不如第 25 轮压缩有效; - 重复读取大文件:在
session_files中找同一会话内(或跨会话)被反复读取的同一文件; - 工具调用抖动:轮次很多且工具调用重复的会话,往往意味着 Agent 多次重新发现同样的上下文;
- 超大粘贴:
turns上的LENGTH(user_message)找出本应是文件引用的超长用户消息。
两种后端通用:
- 长跑会话:轮次多或跨越多小时的会话,会把不断增长的上下文窗口拖过每一轮;
- 重复劳动:同一文件/主题出现在很多会话中,或同一类 Agent 绊脚石反复出现——提示用自定义 skill、agent 或
copilot-instructions.md条目让模型一次做完; - subagent 使用:重量级调查是否在主会话里进行(其 token 计入主上下文),本可以委托给只返回摘要的 subagent?
对最贵的几个会话深挖,读真实对话轮次理解为什么贵——不要只报聚合数字,要解释成因。
Step 2:把发现映射到功能与习惯
若工作区有 .github/,检查 .github/copilot-instructions.md、.github/skills/、.github/agents/ 中已有什么。不要看工作区之外。与成本相关的能力清单:
- 会话中 compaction(如
/compact)缩小上下文窗口;对从不压缩的用户,这往往是最单一的最大收益; - 模型选择器——常规工作换更便宜的模型;
- 开新聊天而非续接臃肿会话;
- subagent/委托,把重研究移到 token 不会累积进主会话的子上下文;
- 自定义 skills(
.github/skills/)与自定义 agents(.github/agents/),避免重复工作流每次重新推导上下文; .github/copilot-instructions.md,把模型否则每次都要被告知的项目约定固化下来;- 云同步用户可查 Copilot 用量视图检查 premium 请求花费。
Step 3:给出建议
给 3-5 条具体可执行的 tip,每条要求:
- 扎根数据——引用观察到的具体会话、文件、模型或模式(有数字就给近似值:轮次数、token 总量、文件读取次数);
- 非显而易见——假设用户知道 compaction 和新聊天存在,帮他意识到自己没在该用的地方用;
- 能量化就量化——“在那个 80 轮会话的第 30 轮附近 compact,能砍掉之后每轮约 X 个输入 token” 远好于 “考虑 compact 一下”;
- 具体——点名工作流变化、命令或配置文件修改;若是建议自定义 skill/agent,勾勒它应覆盖什么;
- 留在 VS Code 聊天范围内——除非用户明确扩大范围,不要提 CLI / Coding Agent 专属的改动。
数据很少时(如云端存储为空,或本地只有寥寥几个交互式聊天会话),直说,并给出 2-3 条锚定在可用功能上的、非显而易见的省钱习惯,而不是编造发现。用户仅本地存储时,结尾注明开启 chat.sessionSync.enabled 能解锁逐事件 token 分析,让后续建议更锋利。
工作流四:Improve(基于历史改进 Agent 指令)
当用户请求基于会话历史改进 Agent 指令(如 /chronicle improve):
Step 1:读取当前指令文件
读取项目使用的指令文件(.github/copilot-instructions.md 或 AGENTS.md)。若文件不存在,则需要创建它——此时先分析代码库(参考 init 技能的代码库探索方法),再把该分析与 Step 2 的会话历史发现结合,产出一份全面的指令文件。
Step 2:调研会话历史
用 copilot_sessionStoreSql 探索,所有查询限定到当前仓库/工作目录的会话。先拿到本仓库近期会话总览,再深入。你在找的是摩擦——Agent 理解错误或用户被迫纠偏的信号:
- 纠正/重定向的用户消息:读可疑会话的真实轮次,找用户受挫的区域;
- 开发循环挣扎:Agent 是否在测试、lint、构建、类型检查上栽跟头?找反复失败的命令、测试重试、需要多次尝试的构建错误;
- 跨会话模式:同类错误是否反复出现?
自己判断该跑什么查询,看到有趣的东西就钻进去逐轮读对话。
Step 3:呈现建议
呈现前先参考 agent-customization 技能中的文件约定、内容原则(链接而非内嵌、最小化、简洁)与反模式——这决定了建议的写法。基于发现简洁地呈现 3-5 条建议,每条既说明发现的问题,也说明自定义指令如何化解。聚焦项目特有模式而非泛泛而谈,只建议数据中发生过不止一次的真实问题对应的指令。
呈现完所有建议后,询问用户想应用哪些,然后只对现有那一个指令文件做被批准的编辑(若不存在则创建 AGENTS.md)。
工作流五:Search(会话检索)
当用户要求按关键词搜索/查找历史会话(如 /chronicle search <query>):
检索策略
- 跨会话摘要、对话轮次(用户消息和助手回复)、以及其他索引内容(checkpoints、文件路径、PR/issue/commit 引用)搜索。用户查询可能命中主题、文件路径或 PR/issue 编号——三类都要覆盖;
- 对每个命中会话,收集足够的元数据用于标注:
s.id、s.repository、s.branch、s.summary、s.updated_at,外加一个展示为何命中的短片段(如云端的substr(user_message, 1, 160),或命中的file_path/ref_value); - 按仓库分组呈现,按最近更新时间降序。
写查询
调用 copilot_sessionStoreSql,action: "query"、description: "Search sessions for <query>",遵循工具描述中展示的方言(SQLite vs DuckDB)。写查询前必须重读 Schema 章节,要点:
sessions表主键是id(不是session_id);其他所有表用session_id外键指回sessions.id。始终从sessions投影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 session_id, content FROM search_index WHERE search_index MATCH ...)。不要把search_index.rowidJOIN 到turns.rowid——两者无关,会拉进不相干的会话。文件路径和引用不在 FTS 索引里——配合session_files.file_path与session_refs.ref_value上的LIKE一起查。这一点与 sessionStore.ts 中 FTS5 建表语句(content, session_id UNINDEXED, source_type UNINDEXED, source_id UNINDEXED)完全一致; - 云端 DuckDB:无 FTS5——对
sessions、turns、checkpoints、session_files、session_refs的文本列用ILIKE '%<query>%'。
单引号用双写转义(it's → it''s);FTS5 多词查询整体加引号:MATCH '"apply patch"'。
性能——避免云端超时
turns 上的 ILIKE '%X%' 是全表扫描,云端查询跑得过长会返回 context deadline exceeded。为守住预算:
- 两步模式(推荐):先在 CTE 中用窄时间窗口从
turns收集命中的session_id并GROUP BY session_id,再用WHERE id IN (...)从sessions补全元数据。避免在大扫描结果上昂贵 JOIN 导致超时; - 用
GROUP BY session_id配any_value()/MIN()/array_agg()聚合每会话命中信息,而非标量子查询或相关子查询; - 云端默认给重表(
turns用WHERE timestamp >= now() - INTERVAL '7 days',checkpoints用created_at同理)加 7 天窗口。查不到就渐进放宽:7 天 → 30 天 → 90 天。在总结行中注明窗口,让用户知道范围是有界的; - 最终 SELECT 保持
LIMIT 50; - 查询超时时,收窄窗口(而非放宽)或去掉最重的那张表(通常是
turns),并告知用户你裁掉了什么。不要用相同窗口重试——永远先缩小范围。
输出格式
每个会话用 summary 构建单行标签(无 summary 时用返回的 snippet,截断至约 80 字符)。绝不输出 (no summary)、(no metadata) 或裸 session-id 列表。若使用了时间窗口(如云端默认 7 天),把它写进标题;否则省略范围短语或写 “all time”:
**Search results for "<query>"** (<n> sessions, <scope: e.g. "last 7 days" / "all time">)
_owner/repo_
- `session-id` — **<summary or snippet>**
`branch` · updated <relative time> · matched in <match_kind>
- `session-id` — **<summary or snippet>**
`branch` · updated <relative time> · matched in <match_kind>
_other-owner/other-repo_
- ...
规则:
- 每行一个会话——绝不把多个 session id 用逗号串在一起;
- 标签优先
summary(非空时),否则用 snippet,否则用命中的文件路径等可用兜底;这些都为空就跳过该会话,而不是显示 “no summary”; - 能给出
· matched in <match_kind>(turn / file / ref / checkpoint / meta)就给出——帮助用户看到每个会话为何命中; - 按仓库分组;
repository为 NULL 的会话归入 Other 标题,格式相同; - 每个仓库可见结果上限约 10 条;更多则追加
…and N more (refine your query)。
无结果时
告知用户没有命中,并建议:换不同关键词或更宽的检索词(单个词、子串而非整句);放宽时间窗口(“搜全部时间”、“包含更早会话”);尚未建索引就跑 /chronicle reindex;或跑 /chronicle standup 看近期活动。
工作流六:Reindex 与 Delete Sessions(维护操作)
Reindex:用户要求重建/刷新会话存储时:
- 调用
copilot_sessionStoreSql,action: "reindex",description: "Reindex sessions"; - 工具从 debug log 重建本地会话存储,若云同步开启则把新会话上传云端;
- 把重建前后的统计与云同步结果呈现给用户。
源码上对应 sessionStoreSqlTool.ts 的 _invokeReindex:先取 getStats() 作为 Before 快照,调用 reindexSessions(实现位于 sessionReindexer.ts),再取 After 快照生成 Before / After / Delta 表格,最后尝试执行 github.copilot.sessionSync.reindex 完成云端补传。若用户说 “force reindex” 或想重新处理已索引会话,给调用加 force: true——默认情况下已索引的会话会被跳过以提速。
Delete Sessions:用户要求删除会话数据或清空历史时:
- 引导其在命令面板中执行 Delete Session Sync Data 命令(
github.copilot.sessionSync.deleteSessions); - 该命令让用户选择要删除的会话,同时作用于本地与云端;
- 工具本身不支持删除——这是有意设计,防止误删数据。
查询规范与工具安全边界
使用 action: "query" 时的规范(技能文档 + 源码实现双重印证):
- 每次调用只能一条查询——不要用分号串联多条语句;
- 只允许
SELECT和WITH(CTE)。DESCRIBE、SHOW、PRAGMA及一切变更语句都被拦截——不要试图自省数据库,重读本文 Schema 章节即可; - 始终带 LIMIT(最大 100),优先聚合(
COUNT、GROUP BY)而非原始行转储; - 查对话内容用 turns 表——它对 “发生了什么” 的洞察最丰富;
- 查文件路径与工具使用模式用 session_files;查 PR/issue/commit 链接用 session_refs;用
session_idJOIN 各表做完整分析; - 时间范围始终过滤
updated_at(而非created_at); - 分析会话内容时始终 JOIN
sessions与turns——不要只依赖sessions.summary。
这些限制不是纸面约定,而是写死在工具里的。sessionStoreSqlTool.ts 中定义了 BLOCKED_PATTERNS 黑名单(拦截 INSERT/UPDATE/DELETE/DROP/CREATE/ALTER/TRUNCATE/REPLACE、ATTACH/DETACH、PRAGMA、VACUUM、REINDEX、ANALYZE、LOAD_EXTENSION,以及事务控制语句),随后还做白名单校验:剥离前导注释后,SQL 必须以 SELECT 或 WITH 开头,且整句不允许出现分号。被拦截的查询会以明确错误信息返回并计入遥测。本地执行最终走 sessionStore.executeReadOnly(sql),在引擎层再通过 authorizer 做只读强制。
另外值得注意的实现细节:模型常常在查询末尾追加分号,工具会先 trim 并去掉尾部分号再进入校验;结果表格的单元格长度按 “总预算 30,000 字符 ÷ 总单元格数” 自适应分配,防止单条超长文本撑爆上下文窗口。
小结
Chronicle 把 “Copilot 用过什么、改过什么、花了多少 token” 从黑盒变成可查询的 SQL 问题:本地 SQLite 提供 FTS5 全文检索与轻量分析,云端 DuckDB 提供跨设备会话与逐事件 token 计费数据,二者通过 chat.sessionSync.enabled 与工具的动态描述切换无缝切换。六大工作流(standup / tips / cost-tips / improve / search / reindex)各有明确的输入、查询策略与输出格式约束,而 copilot_sessionStoreSql 工具的只读校验、行数上限与输出预算保证了模型可以安全地自由写 SQL。要开始使用,先确认 github.copilot.chat.localIndex.enabled 已开启,然后直接在聊天中请求 /chronicle standup 或 “搜索我上周改认证逻辑的会话” 即可。
工具行为的更多细节可参考测试文件 sessionStoreSqlTool.spec.ts,它覆盖了工具注册、modelDescription 动态切换与查询执行的断言;技能原文位于 chronicle/SKILL.md,同目录下的 agent-customization 与 init 技能是 Tips / Improve / Cost Tips 工作流的配套依赖。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00