fix(a2a): Pipeline 取消后收敛残留 working 的步骤到终态 - #297
Closed
ruanzhengxin-zhuxing wants to merge 2 commits into
Closed
Conversation
The pre-commit format hook runs `ruff format src/ tests/` with the ruff version resolved from uv.lock, which rewrites these files. CI only runs `ruff check`, so the drift went unnoticed and made every local commit fail the hook. This commit is pure formatter output with no behavior change, so subsequent commits can pass the hook.
A run interrupted mid-step never emits step_completed/step_failed for the step it was executing, so the snapshot reducer left that step at status="working" with conclusion null even though the run itself had already reached a terminal state. Canceled runs therefore reported intent_parsing as still in progress forever, and downstream consumers could not derive the real outcome from step state. On pipeline_canceled/pipeline_failed, finalize every still-open step, candidate and candidate step onto the run's terminal status with a terminal timestamp and a non-empty conclusion. This mirrors web.pipeline_transcript._on_pipeline_canceled so the snapshot and the transcript agree on the outcome of one run. pipeline_completed is deliberately excluded, since marking an unfinished step as completed would fabricate a successful business conclusion. Synthesized conclusions carry a pipelineTerminated marker so the pipeline handoff context skips them instead of passing them on as real step results.
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.
问题
Pipeline 被取消后,A2A 快照中
intent_parsing步骤仍停留在非终态working且conclusion为 null,而 run 级status已是canceled。步骤终态与 run 终态不一致,前端长期显示"进行中",下游消费者无法据步骤状态判断真实终态。该现象在多个 pipeline session(83ef6fae60c24ef78c238aa89797a29a、f2379f4a6a80436297f5b5058d881ed5、21ac2ae1c63f47e297b667f1d8576b26)重复出现。根因
src/iac_code/a2a/pipeline_snapshot.py中_PipelineSnapshotReducer._apply的终态分支只写 run 级状态并清理 pending / active 控制字段:被中途打断的 step 不会再收到
step_completed/step_failed,而_upsert_step/_upsert_candidate/_upsert_candidate_step创建节点时默认status="working",因此这些节点永久滞留working、无conclusion。Web 端转录器
web/pipeline_transcript.py的_on_pipeline_canceled/_on_pipeline_failed早已实现同语义收敛(并在注释中明确目标是让中断的步骤"stops showing 进行中 forever"),快照 reducer 缺失该逻辑,导致两条投影对同一次 run 给出不一致结论。改动
src/iac_code/a2a/pipeline_snapshot.py_finalize_open_nodes(terminal_status, event),在终态分支末尾调用:把所有非终态 step / candidate / candidateStep 置为 run 的终态,写入canceledAt/failedAt,先合并终止事件自带的conclusion/errorSummary,仍缺失时补写合成结论{"pipelineTerminated": true, "terminalStatus": ..., "reason": ...}。is_terminated_node_conclusion,供下游区分合成结论与真实业务结论。src/iac_code/a2a/pipeline_executor.py_flat_pipeline_context_from_a2a_snapshot跳过带pipelineTerminated标记的合成结论,避免取消后的 normal-chat 交接上下文把它当成真实步骤结论注入。设计取舍
interrupt_received上收敛:中断先经interrupt_classified分类,只有判定为取消才发pipeline_canceled;在interrupt_received收敛会把回滚、追问类中断的步骤误置终态。收敛点放在pipeline_canceled/pipeline_failed,语义等价且无误伤。pipeline_completed不参与收敛:把未完成的步骤标成completed等于伪造成功的业务结论。pendingTerminal事务语义不变:backup 待发布的终止事件仍只记录pendingTerminal,待backup_committed转为权威事件后才触发收敛。测试
新增 11 个用例(
tests/a2a/test_pipeline_snapshot.py10 个、tests/a2a/test_pipeline_executor.py1 个),覆盖 step / candidate / candidateStep 收敛、waiting_input收敛、无reason时字段省略、pipeline_failed保留errorSummary、已终态结论不被覆盖、pipeline_completed不伪造结论、pending_backup不触发收敛、跨次 reduce 幂等、handoff 上下文跳过合成结论。tests/a2a/+tests/web/test_pipeline_transcript.py:1557 passedpytest tests/:14331 passed / 5 skipped / 16 failed;16 项失败均与本次变更无关——13 项tests/test_i18n.py因*.pot(gitignore 的生成产物)在环境中缺失,另 3 项已在基线提交88ed89c上复现同样失败。make lint(ruff check + ty check)通过。附带提交说明
4edc8f1 style: apply ruff format ...为纯格式化产物。仓库 pre-commitformat钩子按uv.lock锁定的 ruff 版本执行ruff format src/ tests/会重写 16 个既有文件(CI 仅跑ruff check故未暴露),导致任何提交都无法通过钩子。将该机械改动单独成一次提交,使修复提交保持可评审。如不希望纳入,可只取404be5a。