Files
deepseek-harness/.agents/notes/implemented/bug-fix/2026-08-11-owned-run-finish-reason.zh.md
T
2026-08-11 16:48:41 +08:00

2.7 KiB

Agent Note: 自有运行的结束原因报告

Status: implemented

English | 中文

问题

Python SDK 消费方需要简洁地判断自有活动区间如何进入 idle。要求每个消费方扫描原始 turn/end 事件会重复协议知识,而通用的成功状态会丢失 token 上限与模型错误之间的区别。

决策

RunResult.finish_reason 是从已提交消息进入持久 inbox 的回执开始、到整个 agent 下一次进入 idle 为止所收集的根会话最后一个 turn/end 的字符串 kind。如果该区间没有 turn/end,字段为 None。缺少字符串 data.reason.kind 的 turn/end 会抛出 SdkProtocolError,而不会报告为区间内没有轮次结束。该字段描述自有运行区间;它不会把这个结束原因归属于已提交的提示词。自有运行边界决策仍禁止提示词级结果归因。

该字段只公开 kind,因为调用方需要稳定的分类,完整的结构化原因仍可从 RunResult.events 取得。传输丢失、超时和协议故障仍会抛出异常,而不会生成结束原因。

考虑过的替代方案

恢复 status。 由部署映射的 ok 或 error 状态会混淆不同的持久结束情况,而且看起来像传输成功状态,因此无法回答区间为何结束。

公开模型 FinishReason。 一次运行可能包含多个模型步骤,中间的 tool-calls 结束并不代表运行结束。agent 最后一个 turn/end 才是相关的运行级观测。

将字段命名为 stop_reason。 ACP 和 subagent seam 会把轮次结束原因映射到各自的 stopReason 取值集合。Python 字段保留原始的 agent 原因 kind,因此沿用它们的名称会让人误以为该接口也执行了这种映射。

公开完整的结构化轮次原因。 原始事件流已经保留错误与取消的详细信息。在 RunResult 上复制这个对象会产生两种需要 Python 调用方协调的表示。

验证

Python SDK 测试覆盖选择最后一个轮次结束、区间内没有轮次结束,以及拒绝畸形轮次结束原因。SDK README 记录字段取值、None 情况、失败行为和运行级范围。

后果

调用方无需解析事件列表,即可按 completed、max-tokens、error 和未来的原因 kind 分支。该字段可能描述区间内加入的 steering、注入上下文或排队工作,因此不能将其表述为初始提示词的因果结果。仓库内的 TypeScript SDK 只通过类型化事件提供结束原因观测;其调用方可以直接从 SessionEvent[] 读取该观测。