Files
deepseek-harness/.agents/notes/implemented/bug-fix/2026-07-24-recursive-python-sdk-session-notifications.zh.md
2026-07-24 12:21:10 +08:00

2.9 KiB
Raw Blame History

Agent Note: Python SDK 递归会话通知

Status: implemented

English | 中文

问题

Python SDK 过去通过将每条通知的 payload 与根会话 ID 直接比较来过滤轮次通知。直接子 agent 的生命周期通知因 parent ID 指向根会话而能够通过,但孙级生命周期通知与所有后代 session.event 都会被拒绝。JSON-RPC 服务器仍会发出这些通知,因此它们会堆积在底层全局队列中,而高层消费者会丢失嵌套轨迹的关系与结束状态。

决策

HarnessClient 会在分发通知前,记录每条有效 subagent.started 所包含的 child-to-parent子到父关系。后续的 subagent.finished 会依据自身不可变的 parent ID 路由,但不会改写当前祖先关系,因此旧 run 即使在其 child ID 已被复用后才结束,也无法覆盖替代它的新会话。其他会话通知会沿客户端生命周期内保存的祖先关系图回溯自身 session ID判断它们是否属于请求的根会话。该关系图会跨连续订阅保留因此某个后代即使跨过一次 Session.run(),在后续轮次中发出通知时仍能正确归属;客户端启动新的运行时进程时会重置关系图。

Session.run() 通过 TurnResult.notificationson_notification 提供已发现会话树的完整通知流。只有 sessionId 等于请求根会话的 session.event 才会进入 TurnResult.events 或参与最终回复重建。因此调用方能够观察后代事件,同时子会话回复不会覆盖根会话回复。

考虑过的替代方案

在每条 JSON-RPC 通知中加入根会话 ID。 服务器已经提供精确的直接父子关系;在线路协议中重复传递祖先关系,会迫使每个生产者承担客户端订阅状态的职责。

把 subagent 限制为一层。 部署可以设置 maxDepth: 1,但让 SDK 依赖该策略,会对合法的递归组合产生静默误报。

只订阅后代生命周期通知。 这可以修复关系与结束状态的上报,但后代会话事件仍会堆积在全局队列中,回调看到的会话树也不完整。

在 JSON-RPC 线路上公开并索引每个 subagent run ID。 当客户端必须关联同一 child 的两个并发结果时,精确 run 身份很有价值;但会话树路由已经拥有权威 start 关系和每条终止通知中不可变的 parent。没有必要为这一归属决策扩展协议。

后果

高层消费者会按线上的原始顺序收到嵌套生命周期与会话通知,同时根轮次结果保持原有回复语义。客户端会为每个已观察到的子会话保留一条当前父关系,直到运行时重启;祖先回溯能够安全处理环,无关会话通知仍可从全局队列获取。无密钥 Python 测试覆盖两层派生、根回复隔离、会话树通知不堆积、跨订阅复用祖先关系,以及旧 run 乱序结束的复用 child ID。