Skip to content

[Architecture] tool_call 流块改用 DataPart 承载,避免语义混淆 #155

@liujuanjuan1984

Description

@liujuanjuan1984

现象

当前 opencode-a2a-serve 在输出流式 tool_call 块时,会把工具调用状态序列化为 JSON 字符串,并放进 TextPart

  • artifact.parts[*].kind = "text"
  • 同时在 artifact.metadata.shared.stream.block_type = "tool_call" 中表达真实块类型

这在 A2A SDK 类型上是可运行的,但语义层存在混淆:parts.kind 表示载体是文本,而块语义实际上是工具调用。

影响

  1. 下游如果没有严格优先读取 metadata.shared.stream.block_type,很容易把 tool_call 误判为普通文本。
  2. 调试和抓包时,可读性不直观;同一个事件同时表达“文本载体”和“工具调用语义”。
  3. 对非本仓库实现的通用 A2A 客户端而言,这种表达方式的兼容成本更高。

根因

当前实现使用 TextPart(text=<json string>) 作为工具调用流块的承载容器。

这不是 SDK 层面的非法用法,但从协议建模角度,工具调用状态更接近结构化数据,而不是自由文本。

建议方案

将流式 tool_call 块的承载从 TextPart 调整为 DataPart

  1. artifact.metadata.shared.stream.block_type 继续保留并作为块语义权威字段。
  2. artifact.parts[*] 改为 DataPart(data={ ...structured tool payload... })
  3. text/reasoning 仍继续使用 TextPart
  4. 文档与测试同步更新,明确 tool_call 的结构化数据形状。

为什么这样更好

  • DataPart 更符合“工具调用是结构化状态对象”的语义。
  • 可减少下游把 tool_call 当成普通文本的概率。
  • metadata.shared.stream.block_type 组合后,协议表达更清晰。

验收标准

  1. 流式 tool_call 更新输出为 DataPart
  2. artifact.metadata.shared.stream.block_type 仍为 tool_call
  3. 现有 text/reasoning 流块行为不回归。
  4. 新增测试覆盖 tool_callDataPart 输出。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions