现象
当前 opencode-a2a-serve 在输出流式 tool_call 块时,会把工具调用状态序列化为 JSON 字符串,并放进 TextPart:
artifact.parts[*].kind = "text"
- 同时在
artifact.metadata.shared.stream.block_type = "tool_call" 中表达真实块类型
这在 A2A SDK 类型上是可运行的,但语义层存在混淆:parts.kind 表示载体是文本,而块语义实际上是工具调用。
影响
- 下游如果没有严格优先读取
metadata.shared.stream.block_type,很容易把 tool_call 误判为普通文本。
- 调试和抓包时,可读性不直观;同一个事件同时表达“文本载体”和“工具调用语义”。
- 对非本仓库实现的通用 A2A 客户端而言,这种表达方式的兼容成本更高。
根因
当前实现使用 TextPart(text=<json string>) 作为工具调用流块的承载容器。
这不是 SDK 层面的非法用法,但从协议建模角度,工具调用状态更接近结构化数据,而不是自由文本。
建议方案
将流式 tool_call 块的承载从 TextPart 调整为 DataPart:
artifact.metadata.shared.stream.block_type 继续保留并作为块语义权威字段。
artifact.parts[*] 改为 DataPart(data={ ...structured tool payload... })。
text/reasoning 仍继续使用 TextPart。
- 文档与测试同步更新,明确
tool_call 的结构化数据形状。
为什么这样更好
DataPart 更符合“工具调用是结构化状态对象”的语义。
- 可减少下游把
tool_call 当成普通文本的概率。
- 与
metadata.shared.stream.block_type 组合后,协议表达更清晰。
验收标准
- 流式
tool_call 更新输出为 DataPart。
artifact.metadata.shared.stream.block_type 仍为 tool_call。
- 现有
text/reasoning 流块行为不回归。
- 新增测试覆盖
tool_call 的 DataPart 输出。
现象
当前
opencode-a2a-serve在输出流式tool_call块时,会把工具调用状态序列化为 JSON 字符串,并放进TextPart:artifact.parts[*].kind = "text"artifact.metadata.shared.stream.block_type = "tool_call"中表达真实块类型这在 A2A SDK 类型上是可运行的,但语义层存在混淆:
parts.kind表示载体是文本,而块语义实际上是工具调用。影响
metadata.shared.stream.block_type,很容易把tool_call误判为普通文本。根因
当前实现使用
TextPart(text=<json string>)作为工具调用流块的承载容器。这不是 SDK 层面的非法用法,但从协议建模角度,工具调用状态更接近结构化数据,而不是自由文本。
建议方案
将流式
tool_call块的承载从TextPart调整为DataPart:artifact.metadata.shared.stream.block_type继续保留并作为块语义权威字段。artifact.parts[*]改为DataPart(data={ ...structured tool payload... })。text/reasoning仍继续使用TextPart。tool_call的结构化数据形状。为什么这样更好
DataPart更符合“工具调用是结构化状态对象”的语义。tool_call当成普通文本的概率。metadata.shared.stream.block_type组合后,协议表达更清晰。验收标准
tool_call更新输出为DataPart。artifact.metadata.shared.stream.block_type仍为tool_call。text/reasoning流块行为不回归。tool_call的DataPart输出。