fix(python): reject malformed finish reasons
This commit is contained in:
@@ -10,7 +10,7 @@ Python SDK 消费方需要简洁地判断自有活动区间如何进入 idle。
|
||||
|
||||
## 决策
|
||||
|
||||
`RunResult.finish_reason` 是从已提交消息进入持久 inbox 的回执开始、到整个 agent 下一次进入 idle 为止所收集的根会话最后一个 `turn/end` 的字符串 `kind`。如果该区间没有 `turn/end`,字段为 `None`。该字段描述自有运行区间;它不会把这个结束原因归属于已提交的提示词。[自有运行边界决策](../architecture/2026-07-30-followup-enqueue-and-owned-runs.md)仍禁止提示词级结果归因。
|
||||
`RunResult.finish_reason` 是从已提交消息进入持久 inbox 的回执开始、到整个 agent 下一次进入 idle 为止所收集的根会话最后一个 `turn/end` 的字符串 `kind`。如果该区间没有 `turn/end`,字段为 `None`。缺少字符串 `data.reason.kind` 的 `turn/end` 会抛出 `SdkProtocolError`,而不会报告为区间内没有轮次结束。该字段描述自有运行区间;它不会把这个结束原因归属于已提交的提示词。[自有运行边界决策](../architecture/2026-07-30-followup-enqueue-and-owned-runs.md)仍禁止提示词级结果归因。
|
||||
|
||||
该字段只公开 kind,因为调用方需要稳定的分类,完整的结构化原因仍可从 `RunResult.events` 取得。传输丢失、超时和协议故障仍会抛出异常,而不会生成结束原因。
|
||||
|
||||
@@ -20,12 +20,14 @@ Python SDK 消费方需要简洁地判断自有活动区间如何进入 idle。
|
||||
|
||||
**公开模型 `FinishReason`。** 一次运行可能包含多个模型步骤,中间的 `tool-calls` 结束并不代表运行结束。agent 最后一个 `turn/end` 才是相关的运行级观测。
|
||||
|
||||
**将字段命名为 `stop_reason`。** ACP 和 subagent seam 会把轮次结束原因映射到各自的 `stopReason` 取值集合。Python 字段保留原始的 agent 原因 kind,因此沿用它们的名称会让人误以为该接口也执行了这种映射。
|
||||
|
||||
**公开完整的结构化轮次原因。** 原始事件流已经保留错误与取消的详细信息。在 `RunResult` 上复制这个对象会产生两种需要 Python 调用方协调的表示。
|
||||
|
||||
## 验证
|
||||
|
||||
Python SDK 测试覆盖最后一个轮次正常结束,以及区间内没有轮次结束的情况。SDK README 记录字段取值、`None` 情况和运行级范围。
|
||||
Python SDK 测试覆盖选择最后一个轮次结束、区间内没有轮次结束,以及拒绝畸形轮次结束原因。SDK README 记录字段取值、`None` 情况、失败行为和运行级范围。
|
||||
|
||||
## 后果
|
||||
|
||||
调用方无需解析事件列表,即可按 `completed`、`max-tokens`、`error` 和未来的原因 kind 分支。该字段可能描述区间内加入的 steering、注入上下文或排队工作,因此不能将其表述为初始提示词的因果结果。仓库近旁的 TypeScript SDK 保留仅提供类型化事件的接口;其调用方可以直接从 `SessionEvent[]` 读取同一观测。
|
||||
调用方无需解析事件列表,即可按 `completed`、`max-tokens`、`error` 和未来的原因 kind 分支。该字段可能描述区间内加入的 steering、注入上下文或排队工作,因此不能将其表述为初始提示词的因果结果。仓库内的 TypeScript SDK 只通过类型化事件提供结束原因观测;其调用方可以直接从 `SessionEvent[]` 读取该观测。
|
||||
|
||||
Reference in New Issue
Block a user