- 作者:@ignatov
电梯演讲
向现有的SessionUpdate 通知类型添加一个 session_info_update 变体,允许代理更新会话元数据(特别是标题/名称),从而实现客户端 UI 中的动态会话识别,而不需要新的端点。
现状
目前,ACP 协议通过session/new、session/load 和 session/list(不稳定)提供会话管理。session/list 端点返回包含可选 title 字段的 SessionInfo 对象,用于在客户端 UI 中显示会话名称。
然而,有几个问题:
-
无法传达标题更新 -
SessionInfo中的title字段在列表响应中是静态的。代理无法随着会话的发展动态更新它。 -
没有实时元数据更新机制 - 与命令(
available_commands_update)或模式(current_mode_update)不同,代理无法:- 在第一次有意义的交换后自动生成标题
- 随着对话上下文的变化更新标题
- 提供反映会话状态的自定义元数据
-
与协议模式不一致 - 其他动态会话属性使用
session/update通知(命令、模式、计划),但元数据没有等效机制。
- 维护自己的标题映射(不会持久化或同步)
- 只显示
session/list中的静态元数据 - 无法实时接收代理生成的标题
我们提议对此做什么
向现有的SessionUpdate 可区分联合添加一个新的 session_info_update 变体,允许代理通知客户端元数据更改。此更新将:
-
遵循现有的
SessionUpdate模式:- 使用与
available_commands_update、current_mode_update等相同的通知机制 - 通过
session/update方法发送 - 代理发起,不需要请求/响应
- 使用与
-
与
SessionInfo结构保持一致:- 包含与
session/list中的SessionInfo相同的字段 - 所有字段都是可选的(部分更新)
- 支持增量元数据更新
- 重要:
SessionInfoUpdate必须与SessionInfo保持一致——当新字段添加到SessionInfo时,它们也应该作为可选字段添加到SessionInfoUpdate
- 包含与
-
支持常见用例:
- 代理在第一个提示后自动生成标题
- 代理随着对话上下文的变化更新标题
- 代理为客户端功能提供自定义元数据(标签、状态等)
- 用户明确请求标题更改(代理用更新通知响应)
-
无缝集成:
- 不需要新功能(使用现有的
session/update机制) - 与
session/list兼容——元数据应该持久化并在列表响应中反映 - 在活动会话期间工作
- 不需要新功能(使用现有的
通知结构
代理发送带有sessionUpdate: "session_info_update" 的 session/update 通知:
SessionInfoUpdate 类型
更新类型镜像SessionInfo,但所有字段都是可选的:
sessionId 和 cwd 不包括在内,因为:
sessionId已经在通知的params中cwd是不可变的,在session/new期间设置
示例
更新标题和工作目录元数据
在用户发送他们的第一个有意义的提示之后,代理可以生成并发送一个标题以及关于工作目录的元数据:随着对话发展更新标题
随着对话焦点转变:美好的未来
一旦这个功能存在,事情将如何发展?
-
动态会话识别 - 代理可以:
- 从对话内容中自动生成有意义的标题
- 随着对话的发展更新标题
- 提供更好的组织的丰富元数据
-
改进的客户端 UI - 客户端可以:
- 在会话列表中显示实时标题更新
- 显示会话状态、标签或其他元数据
- 无需轮询
session/list立即更新 UI
- 一致的协议模式 - 会话元数据更新与其他动态会话属性(命令、模式)一样工作,创建统一模型
-
双向工作流 - 与潜在的未来请求方法结合:
- 用户重命名会话 → 客户端发送请求 → 代理用
session_info_update通知确认 - 代理自动生成标题 → 发送
session_info_update通知 → 客户端显示它
- 用户重命名会话 → 客户端发送请求 → 代理用
-
增强的用例:
- 自动设置标题和标签的会话模板
- 通过
_meta进行进度指示器 - 通过元数据与外部工具集成
- 丰富的会话浏览和过滤
实施细节和计划
第 1 阶段:模式更改
- 更新
schema.unstable.json:- 添加
SessionInfoUpdate类型定义 - 在
SessionUpdateoneOf 数组中添加新的变体 - 使字段与
SessionInfo保持一致但都是可选的
- 添加
SessionUpdate oneOf:
第 2 阶段:协议文档
-
在
/docs/protocol/session-metadata.mdx中创建文档:- 解释通知机制
- 提供常见模式的示例
- 记录
_meta的合并语义 - 阐明与
session/list的关系
-
更新现有文档:
- 在
/docs/protocol/session-setup.mdx中引用 - 添加到
/docs/protocol/prompt-turn.mdx会话更新部分
- 在
第 3 阶段:SDK 实施
-
在 Rust SDK 中实现:
- 添加
SessionInfoUpdate结构体 - 添加
SessionUpdate枚举中的变体 - 更新代理和客户端特征中的通知处理
- 为常见模式添加辅助方法
- 添加
-
在 TypeScript SDK 中实现(如果适用):
- 添加 TypeScript 类型
- 更新通知处理程序
- 添加辅助方法
第 4 阶段:示例实施
- 更新示例代理:
- 演示从第一个提示自动生成标题
- 显示会话期间的元数据更新
- 使用
_meta进行自定义字段的示例
兼容性考虑
- 完全向后兼容:这向现有机制添加了一个新的通知变体
- 没有破坏性更改:现有代理和客户端继续工作
- 优雅降级:不处理此通知的客户端只是忽略它
- 不需要新功能:使用现有的
session/update基础设施
设计决策
为什么是通知而不是请求/响应?- 与现有的
SessionUpdate模式(available_commands_update、current_mode_update)一致 - 代理根据会话状态发起更新
- 比双向请求/响应更简单
- 支持实时更新而不需要轮询
- 允许部分更新(只更新改变的)
- 更高效——不重新发送未更改的数据
- 更灵活的用例
- 镜像其他协议中的部分更新模式
sessionId 和 cwd?
sessionId已经在通知 params 中cwd是不可变的(在session/new中设置,永不改变)- 保持更新专注于可变的元数据
_meta 更新如何工作?
- 合并语义:新的
_meta字段与现有的合并 - 要清除特定字段:
"_meta": { "fieldName": null } - 要清除所有自定义元数据:
"_meta": null
安全考虑
- 没有额外的安全问题:使用现有的会话身份验证
- 输入验证:
- 代理应该验证标题长度(建议最多 500 个字符)
- 清理元数据以防止注入
- 根据代理要求验证
_meta结构
- 资源限制:代理应该限制更新频率和元数据大小
常见问题
为什么不像 session/update-metadata 那样创建一个新的端点?
通知模式更合适,因为:
- 一致性:其他动态会话属性(命令、模式)使用通知
- 代理发起:代理通常从对话上下文生成标题
- 实时:没有请求/响应开销,更新自然流动
- 更简单:重用现有的
session/update基础设施
这与 session/list 如何工作?
更新的元数据应该持久化并在后续的 session/list 调用中反映。通知为连接的客户端提供实时更新,而 session/list 提供发现的当前状态。
客户端可以触发标题更新吗?
这个 RFD 涵盖代理发起的更新。客户端发起的更新可以通过以下方式工作:- 客户端发送要求重命名会话的提示
- 代理更新其内部状态
- 代理发送
session_info_update通知 - 客户端接收并显示更新
如果快速连续发送多个更新怎么办?
客户端应该按顺序增量应用更新。每个通知代表一个增量,而不是完全替换(除了明确设置为null 的字段)。
代理是否应该自动设置 updatedAt?
是的,通常代理应该在发生任何会话活动时更新此时间戳,而不仅仅是元数据更改时。然而,在 session_info_update 中包含它允许代理在需要时明确控制它。
代理需要新功能吗?
不需要。支持session/update 通知的所有代理都可以发送此变体。不识别它的客户端会忽略它(标准的 JSON-RPC 行为)。
这如何与 session/fork 交互?
在分叉时,父会话的元数据可以被复制(实现选择)。分叉的会话将有自己的 sessionId,并可以接收单独的 session_info_update 通知。
如果标题太长怎么办?
这是实现选择。代理可以:- 截断长标题
- 拒绝更新(尽管这是通知,所以没有错误响应)
- 设置合理的限制(例如,500 个字符)
_meta 可以有嵌套对象吗?
是的,_meta 是一个任意对象。代理定义其结构。合并语义递归应用——嵌套对象被合并,而不是完全替换。
您考虑了哪些替代方法,为什么选择这一个?
考虑了几种替代方案:-
添加一个新的请求/响应端点(
session/update-metadata)——这将与如何处理其他动态会话属性(命令、模式)不一致。通知模式对于代理发起的更新更合适。 -
在
session/new中添加标题参数——只允许在创建时设置标题,不支持随着对话发展的动态更新。 - 仅客户端元数据跟踪——无法跨设备工作,可能不同步,并重复存储。这是当前的解决方法,有重大限制。
-
用于所有属性的通用
session/update请求——可能与不可变属性(sessionId、cwd)冲突,并且不清楚什么可以更新。
- 一致于现有协议模式
- 灵活适用于代理发起和用户发起的更新
- 简单实现和理解
- 可扩展通过
_meta字段
修订历史
- 2025-11-28:初始提案草稿