主要变更: - Skill Learning 闭环系统 (9/9 AC) - Opus 4.7 模型层接入 + adaptive thinking - Prompt 工程优化 (64 审计测试) - Agent Teams 简化门控 (默认启用) - Windows Terminal 后端修复 (EncodedCommand/WT_SESSION) - TF-IDF 技能搜索精准化 (字段加权/CJK 优化) - Autonomy 系统 (/autonomy 命令) - ACP 协议完整实现 - mock.module 泄漏修复 (CI 全绿) - 152+ lint/type 修复
13 KiB
/summary 完整实现设计(基于现有代码反推)
更新日期: 2026-04-15 设计目标: 基于当前仓库已有能力,设计一个完整可交付的
/summary命令,而不是只补最小可用版本。 结论口径: 以当前源码为准,优先复用现有SessionMemory、session transcript、resume/session listing 相关能力,不另起一套平行系统。
一、设计结论
/summary 的完整实现,应该分成两条能力线:
-
当前会话摘要
- 显式触发一次最新摘要生成
- 读取并展示当前 session memory 的
summary.md
-
历史会话摘要查看
- 查看最近会话的摘要
- 按 session id 查看指定会话的摘要
- 按标题关键词查找会话摘要
这两条能力线应复用两套已有系统:
- 当前会话:
SessionMemory - 历史会话:
sessionStorage.ts/listSessionsImpl.ts
不应该做的是:
- 新造一个“即时摘要模型调用”系统
- 用另一套 prompt 平行生成 summary
- 把
/summary做成和现有 session memory 脱钩的独立功能
二、现有代码里已经具备的基础
2.1 命令入口已注册,但当前仍是 stub
文件:
src/commands/summary/index.jssrc/commands.ts
现状:
src/commands.ts已静态导入summarysrc/commands/summary/index.js仍为隐藏 stub
这说明:
/summary已经是一个明确存在的产品面- 不是“新功能提案”,而是“已注册但未实现的命令”
2.2 当前会话摘要:已有专门的手动触发入口
文件:
src/services/SessionMemory/sessionMemory.ts
现状:
源码注释已经明确说明:
/**
* Manually trigger session memory extraction, bypassing threshold checks.
* Used by the /summary command.
*/
export async function manuallyExtractSessionMemory(...)
这意味着 /summary 当前会话模式的核心调用入口已经被设计好了。
2.3 当前会话摘要内容:已有统一读取口
文件:
src/services/SessionMemory/sessionMemoryUtils.tssrc/utils/permissions/filesystem.ts
现状:
getSessionMemoryPath()返回当前 session memory 文件路径getSessionMemoryContent()返回当前summary.md内容
因此 /summary 不需要再自己拼装“当前会话摘要文本”,而应直接展示该文件内容。
2.4 历史会话摘要:已有 transcript 元数据能力
文件:
src/utils/sessionStorage.tssrc/utils/listSessionsImpl.ts
已有能力:
getLastSessionLog(sessionId):读取单个 session 的 transcript 汇总视图searchSessionsByCustomTitle(query):按自定义标题搜索 sessionlistSessionsImpl(options):列出 session 摘要元数据getSessionFilesLite(projectDir, limit):快速拿 lite logs
这意味着:
/summary session <id>不需要重新扫完整 transcript 逻辑/summary find <query>不需要重新造搜索层/summary recent可以直接复用 session listing
2.5 现有命令体系支持“一级命令 + 二级动作”
文件:
src/types/command.tssrc/utils/processUserInput/processSlashCommand.tsxsrc/commands/mcp/mcp.tsxsrc/commands/job/job.tsxsrc/commands/daemon/daemon.tsx
当前 slash command 体系本来就是:
processSlashCommand()解析/command [args]- 再把
args原样传给命令实现 - 命令自己解析二级动作
因此 /summary 最合理的实现方式也是:
- 一级命令:
/summary - 二级动作:由
args解析
而不是额外拆成:
/summary-last/summary-find/summary-session
这种平铺命名。
三、命令形态:一级命令 + 二级动作
建议统一语法:
/summary <subcommand> [args]
无参数时:
/summary
等价于:
/summary refresh
也就是:
- 对当前会话显式触发一次 session memory 提取
- 然后展示摘要结果
3.1 当前会话动作
/summary
/summary refresh
/summary raw
/summary path
语义:
/summary刷新当前会话摘要并以友好格式展示/summary refresh与/summary等价,但语义更显式/summary raw刷新后输出完整summary.md/summary path输出当前摘要文件路径
3.2 历史会话动作
/summary last
/summary recent
/summary recent <n>
/summary session <session-id>
/summary find <query>
语义:
/summary last查看最近一个会话的摘要/summary recent列出最近若干会话摘要/summary recent <n>列出最近n个会话摘要/summary session <session-id>查看指定 session 的摘要/summary find <query>按标题关键词搜索并展示匹配会话摘要
3.3 为什么 find <query> 第一版只查 title
因为当前已有现成能力就是:
searchSessionsByCustomTitle(query)
如果第一版就强行做:
- title + firstPrompt + summary 全字段模糊搜索
那就会把简单实现拖进一个新的 session search 设计里。
完整实现不等于“一口气做最大范围”;完整实现应该先建立稳定语义,再逐步扩展搜索范围。
四、每种模式对应的数据源
| 模式 | 数据源 | 说明 |
|---|---|---|
summary / refresh / raw / path |
SessionMemory |
当前会话,显式触发提取后读取 summary.md |
last |
listSessionsImpl + getLastSessionLog |
先找最近 session,再读详细摘要 |
session <id> |
getLastSessionLog |
直接读取指定 session |
recent [n] |
listSessionsImpl |
展示摘要列表,不需要全量 transcript |
find <query> |
searchSessionsByCustomTitle |
第一版先按 customTitle 查找 |
五、命令模块设计
建议实现文件:
src/commands/summary/index.ts
导出形态:
const summary = {
type: 'local',
name: 'summary',
description: 'Generate or view session summaries',
supportsNonInteractive: true,
load: () => Promise.resolve({ call }),
} satisfies Command
5.1 为什么是 local
因为当前实现需要:
- 参数路由
- 条件分支
- 调用已有函数
- 错误处理
- 文件读取
这不是“给模型一段说明让它去决定”的场景,而是“命令协调器”的场景。
5.2 为什么不拆成多条平铺命令
因为当前仓库已有约定是:
- 一个命令负责一个命名空间
- 子动作由
args解析
所以 /summary 的实现应更接近:
/mcp .../job .../daemon ...
而不是单独拆出多条并列命令。
六、内部实现结构建议
建议拆成 4 组 helper,而不是把所有逻辑塞进 call():
6.1 参数解析
建议函数:
function parseSummaryArgs(args: string): SummaryCommandInput
返回一个判别联合:
type SummaryCommandInput =
| { mode: 'current'; raw: boolean }
| { mode: 'path' }
| { mode: 'last' }
| { mode: 'session'; sessionId: UUID }
| { mode: 'recent'; limit: number }
| { mode: 'find'; query: string }
建议实际解析规则:
'' -> { mode: 'current', raw: false }
'refresh' -> { mode: 'current', raw: false }
'raw' -> { mode: 'current', raw: true }
'path' -> { mode: 'path' }
'last' -> { mode: 'last' }
'recent' -> { mode: 'recent', limit: DEFAULT_RECENT_LIMIT }
'recent 5' -> { mode: 'recent', limit: 5 }
'session <id>' -> { mode: 'session', sessionId }
'find foo bar' -> { mode: 'find', query: 'foo bar' }
6.2 当前会话摘要执行
建议函数:
async function runCurrentSessionSummary(
messages: Message[],
toolUseContext: ToolUseContext,
opts: { raw?: boolean }
): Promise<LocalCommandResult>
职责:
- 校验是否有消息
- 调用
manuallyExtractSessionMemory() - 调用
getSessionMemoryContent() - 组装文本结果
6.3 历史会话摘要读取
建议函数:
async function runHistoricalSummary(
input: HistoricalSummaryInput
): Promise<LocalCommandResult>
支持:
lastsessionrecentfind
6.4 格式化输出
建议统一 formatter:
function formatCurrentSummary(...)
function formatSessionSummary(...)
function formatRecentSessionList(...)
避免命令逻辑和显示逻辑缠在一起。
七、当前会话模式的完整调用链
/summary
-> processSlashCommand()
-> commands.ts 中 summary
-> summary/index.ts local call()
-> parseSummaryArgs()
-> runCurrentSessionSummary()
-> manuallyExtractSessionMemory(messages, toolUseContext)
-> SessionMemory 子代理更新 summary.md
-> getSessionMemoryContent()
-> formatCurrentSummary()
-> 返回 LocalCommandResult { type: 'text' }
八、历史会话模式的完整调用链
8.1 /summary last
/summary last
-> listSessionsImpl({ dir: getOriginalCwd(), includeWorktrees: true, limit: 2+ })
-> 取最近一条非当前 session
-> getLastSessionLog(sessionId)
-> formatSessionSummary()
8.2 /summary session <id>
/summary session <id>
-> getLastSessionLog(sessionId)
-> formatSessionSummary()
8.3 /summary recent [n]
/summary recent 5
-> listSessionsImpl({ dir: getOriginalCwd(), includeWorktrees: true, limit: 5 })
-> formatRecentSessionList()
8.4 /summary find <query>
/summary find auth
-> searchSessionsByCustomTitle('auth')
-> formatSessionSummary() or formatRecentSessionList()
九、输出格式设计
9.1 当前会话默认输出
建议:
Session summary updated.
<summary.md 内容>
9.2 当前会话 path 模式
Session summary path:
<absolute-path>
9.3 历史会话摘要输出
建议包含:
- session id
- custom title / summary / firstPrompt 的优先展示
- modified 时间
- tag / gitBranch / projectPath(若存在)
例如:
Session: <id>
Title: Fix auth redirect loop
Updated: 2026-04-15 14:20
Branch: fix/auth-redirect
Tag: auth
Summary:
<summary text>
9.4 recent 模式输出
建议压缩成列表:
Recent sessions:
1. <id> Fix auth redirect loop
Updated: 2026-04-15 14:20
2. <id> Add session memory tests
Updated: 2026-04-15 10:03
十、错误模型
至少覆盖以下情况:
10.1 当前会话
- 没有消息可总结
- 手动提取失败
- 提取成功但读取失败
- 文件为空
10.2 历史会话
- session id 不合法
- session 不存在
- session 存在但没有可提取摘要
find无匹配结果
建议文案:
No messages to summarize.Failed to generate session summary: <error>Session summary was updated, but could not be read back.Session summary is empty.Session not found: <id>No matching sessions found for "<query>".
十一、和现有能力的边界
11.1 不替代 task summary
task summary 仍然只负责:
- 后台会话中途状态
claude ps风格展示
/summary 不要去读或改 saveTaskSummary() 这条链。
11.2 不替代 away summary
away summary 仍然是:
- 极短 recap
- 离开/回来场景
/summary 应该输出更完整内容。
11.3 不新造第二套 session summary 存储
当前会话继续使用:
summary.md
历史会话继续使用:
- transcript 中已有
summary/customTitle/firstPrompt
十二、测试设计
建议新建:
src/commands/__tests__/summary.test.ts
至少覆盖:
12.1 当前会话
/summary成功路径/summary raw/summary pathmanuallyExtractSessionMemory()失败getSessionMemoryContent()返回空
12.2 历史会话
/summary session <id>成功/summary session <id>找不到 session/summary last/summary recent/summary find <query>有结果/summary find <query>无结果
12.3 参数解析
- 无参数
- 非法参数
- 缺少
session <id>的 id recent的 limit 非法
十三、分阶段落地
Phase 1:当前会话
/summary/summary refresh/summary raw/summary path
Phase 2:历史会话
/summary last/summary session <id>/summary recent [n]
Phase 3:搜索
/summary find <query>- 搜索范围增强(如标题之外的字段)
十四、验收标准
完整实现完成时,应满足:
/summary不再是隐藏 stub- 当前会话摘要链路完整可用
- 历史会话摘要查看链路完整可用
- 参数语义稳定
- 错误分支有清晰输出
- 测试覆盖当前会话 + 历史会话主路径
十五、后续扩展
在完整实现落地后,再考虑:
- section 过滤
- richer search
- 指定输出格式(markdown/plain/json)
- 与
/resume和 session picker 的更强联动
但这些不应阻塞本次实现。