fix: align streaming terminal states and shared metadata#244
Merged
Conversation
This was referenced Mar 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
变更概览
本 PR 统一收敛 streaming 输出边界,合并处理流式完成判定、上游 in-band error 映射,以及 step/snapshot 事件的结构化下沉,修复以下四类问题:
message/stream在上游真正结束前过早输出completedstep-start/step-finish/snapshot的内部快照字符串被误当成正文透传shared.stream.source曾暴露part_text_diff等内部归一化实现值按模块说明
src/opencode_a2a_server/agent.pysend_message()返回作为成功完成条件。sessionID对应的session.idle。sessionID对应的session.error,并将其映射为对应的 A2A 失败态。session.error之后仍继续发送TaskState.completed的状态覆盖问题,确保流式请求只产生一个最终终态。session.idle/session.error前提前结束时,显式按上游协议错误处理,避免静默空完成。/session/{id}/messageresponse.info.error的失败映射,非流式和流式都不再把上游业务失败误报为完成态。message.updated -> info.error的兜底处理,避免上游已显式报错但最终仍落成completed。text/reasoningpart 输出到文本 artifact,不再把step-start/step-finish/snapshot这类内部快照直接当成正文透传。step-start/step-finish/snapshot增加结构化metadata.shared.progress输出,使这些事件像usage/interrupt一样以下游可消费的 shared metadata 形式暴露,而不是重新回退成正文。metadata.shared.stream.source兼容位,但对 artifact/update 场景仅暴露稳定公开值:文本/推理块统一为stream,工具块为tool_part_update,最终补发快照为final_snapshot,不再向 shared 协议暴露part_text_diff、delta_event等内部实现值。metadata.shared.stream.source标记status/progress/interrupt等控制语义,保持现有 shared metadata 风格一致。internal_source与对外shared_source语义边界,避免服务端内部来源标签与下游 shared 协议字段继续共槽位混用。src/opencode_a2a_server/text_parts.pytext/reasoningpart 汇总可见文本,不再回退到 snapshot 字段,避免 opaque snapshot/hash 在非流式场景中进入用户可见正文。src/opencode_a2a_server/extension_contracts.pyprogress_metadata_field与progress_fields,公开metadata.shared.progress的结构化字段路径。tests/test_streaming_output_contract.pysend_message()先返回、assistant 文本与session.idle后到的成功场景。session.error只产生单一失败终态、且不会再落成completed的场景。step-finishsnapshot 不再作为可见文本 artifact 输出,但相关 usage 仍可保留。step-start/step-finish/snapshot会以下游可消费的shared.progress形式输出。source只暴露稳定公开值,不再透出内部归一化来源。tests/test_agent_errors.pyresponse.info.error映射为失败态。response.info.error映射为失败态并输出错误 artifact。session.error映射为失败态。message.updated -> info.error最终仍应输出失败态。tests/test_text_parts.pytests/test_agent_card.pymetadata.shared.progress。tests/test_metrics.py文档
提交记录
a6eec87refactor: separate internal and shared stream sources #2468cd6734fix: normalize shared stream source values #246f18da97feat: surface step events as shared progress metadata #2464e22c86fix: suppress snapshot parts from visible text output5178f80fix: map upstream in-band errors to failed task state #24250dd7d2fix: preserve failed terminal state after session.error #2439372a84fix: wait for session terminal signals before completing stream #243最终决策
text/reasoning。step-start/step-finish/snapshot不再进入正文 artifact。step-start/step-finish/snapshot改为通过metadata.shared.progress暴露结构化阶段信息。step-finish仍保留usage提取职责,不与正文职责混用。metadata.shared.stream.source为兼容下游消费继续保留。metadata.shared.stream.source只承诺稳定公开值:stream、final_snapshot、tool_part_update。metadata.shared.stream.source继续用于控制语义标记,例如status、progress、interrupt。验证
uv run pre-commit run --all-filesuv run pytest关联 Issue
Closes #242
Closes #243
Closes #246