Status: implemented
English | 中文
当 max-tokens step 只组装出 tool-call block 时,agent loop 会追加空 content assistant/message,因为 BlockAssembler.blocks() 会丢弃被截断的 tool call;该 message 保留 stream 与 usage,但不贡献 output block。三个消费方独立选取 child agent 输出,并把该 record 当成输出。进程内 driver 的 readResult 与 continuable Activation 的 subagent/end capture 不加过滤地选取最后一条 assistant/message,SDK backend observer 则让任何 assistant/message 优先于累计 text。在被 max-tokens 截断的多 step turn 中,最后的空 message 导致 SubagentResult.output、tool result、telemetry 与 subagent/end.lastAssistantMessage 漏掉真实 partial answer。进程内 driver 也缺少 streamed-text fallback,因此被取消 child 的唯一 text 若只存在于嵌入式 Assistant stream 中,也会报告 []。
dsh-subagent 在 src/assistant-output.ts 中拥有唯一规范选取规则:选取最后一条非空 Assistant message;没有时,从嵌入式 assistant/message 与 assistant/attempt stream 或 chunk-only transport 选取累计 text-delta content;忽略空 content message。增量 AssistantOutputFold 通过 push(event)、pushText(text) 与 collect() 实现该规则。finalAssistantOutput(events) 把规则应用于完整 event suffix,供进程内 readResult 与 Activation capture 使用。SDK backend 折叠 notification event;ACP backend 不公开完整 Assistant message,并折叠 raw chunk text。SubagentResult.output 定义 result contract,subagent/end.lastAssistantMessage 使用同一规则。child 不产生任一种输出时,一次性与 continuable run 的 lifecycle field 都缺省,而不是空 array。max-tokens 或 aborted result 保留实际 stop reason。
前台委派工具使用同一选取规则。非 completed 的结果仍是 isError 工具结果,但其消息会在终止原因标题之后呈现由非交互权限决策负责的可选安全提供方诊断,再附上子 agent 的部分文本。父模型会同时收到失败、独立的基础设施说明与已有 assistant 输出,而且不会把它们混为一体。
无密钥 SDK 后端测试使用 FAKE_EMPTY_MESSAGE 发出一条仅记录 usage 的终止消息。subagent-max-tokens-partial ACP 快照记录一个子 agent:它流式输出文本与一次工具调用,结束于仅含工具调用的 max-tokens 步骤,持久化日志中含一条空的 usage 消息,并通过父侧的错误工具结果返回部分文本。单元覆盖检查空终止消息、取消、消息顺序、不含文本的非空消息,以及排除工具结果内容。
各消费方就地修复、不抽共享辅助函数。 之所以否决:三处独立选取已发生分歧,而同一次运行的观察方必须对其输出达成一致。
让 loop 不再追加空消息。 之所以否决:这条消息记录 usage,并在持久化日志中保留该步骤("model-visible ⟺ logged");为处理输出选取而改动会话事件,会影响所有 replay 与 projection 消费方。
把空内容消息视为错误。 之所以否决:流式文本才是子代理真实的部分回答,且终止原因已经告诉消费方轮次被截断。
被 max-tokens 截断的多步子 agent 会报告其更早的文本;被取消的进程内子 agent 保留中止前已流式的文本;一次性与 continuable 的 subagent/end 事件同 SubagentResult.output 一致。内容非空但不含文本的消息(例如仅含 reasoning 的内容)仍然优先于流式文本,因为规则检查内容长度,而不是文本是否存在。非空消息同样优先于其后才流式出的文本:子 agent 在流式输出后续步骤时被取消,报告的是更早那条完整消息,终止原因则记录该截断。