Skip to content

更加完善的 Task Rerun 方案 #23

Description

@Kherrisan

背景

当前 task rerun 会为 terminal task 创建一个新的同级 task:复用原 task input、复制 inputs/ 目录、在名称后增加 (rerun) 并重新入队。该方案能重新执行,但对 rerun lineage、Agent 会话起点、结果生效范围和下游数据一致性缺少明确语义。

主要问题包括:

  • rerun 只是一个新 task,无法可靠表达第几次 attempt、源 task 和 rerun root
  • input 目录通过名称、stage 和 parent task 进行启发式查找,缺少不可变 input snapshot
  • rerun 成功后,原结果和新结果哪个是当前有效结果不明确
  • 已生成的下游 task、candidate、analysis、verification 和 triage 可能继续引用旧输出
  • 多次点击、批量 rerun、worker 重启和并发执行可能创建重复 task
  • 复用、fork 或新建 Agent session 的策略不明确

目标

建议方案

1. Logical Task 与 Attempt

把 pipeline 中的逻辑 task 和具体执行 attempt 分开。至少持久化:

  • logicalTaskId / rerunRootTaskId
  • sourceTaskId
  • attemptNumber
  • rerunRequestId
  • inputSnapshot
  • pipelineDefinitionSnapshot / definition version
  • runtimeConfigSnapshot
  • agentSessionId、session strategy
  • status、开始/结束时间、错误和输出 artifact

历史 attempt 保持不可变,通过 activeAttemptId 指定当前对下游生效的成功 attempt。

2. Rerun 模式

提供两个明确模式:

  • Isolated rerun:使用相同 input snapshot 重新执行,仅用于比较和调试;不替换 active attempt,不创建下游 task。
  • Replace and propagate:成功后原子切换 active attempt,把依赖旧 attempt 的 descendants 标记为 stale,并按 pipeline edges 重新生成受影响的下游子树。

默认使用 Isolated,避免一次误操作改变整个 job 结果。切换为新结果需要显式确认并展示受影响的 downstream task/candidate 数量。

3. 不可变执行输入

Rerun 必须读取原 attempt 创建时保存的输入与 definition snapshot,不再通过 task 名称或目录存在性猜测来源。UI 可另外提供“使用当前配置重新运行”,但必须标记为 non-reproducible rerun,并保存新的 snapshot。

所有 artifact 引用在 rerun 前校验;文件缺失、schema 不匹配或 definition 已无法加载时明确报错,不静默 fallback 到其他 task 的目录。

4. ACP Session 策略

为 rerun 显式选择 session strategy:

  • Fresh(默认):创建新 ACP session,避免旧 task 输出污染本次结果。
  • Fork from original base:从原 task 执行前记录的 parent/base ACP session fork,复现当时上下文起点。
  • Continue from task:仅用于人工调试,基于原 task session 继续,不作为可复现 rerun。

如果选择 fork,Agent 必须 advertise sessionCapabilities.fork;不支持时 fail fast,不改为拼接历史。需要在 task 创建时保存原生 base session ID,不能等 rerun 时再猜测。

5. 下游失效与结果发布

Replace and propagate 应在事务中:

  1. 校验 rerun attempt 已成功且输出满足 stage schema
  2. 切换 logical task 的 active attempt
  3. 标记引用旧 attempt output 的 descendants 为 stale
  4. 使旧 lineage 的 projection/result 不再参与 latest 聚合
  5. 使用新 output 按 YAML edge、fan-out 和 idempotency key 重建下游

旧 task、artifact 和 candidate lineage 保留用于审计,但不能与新 lineage 混合成为同一条“最新结果”。

6. 并发、幂等与 Job 状态

  • API 接受 rerunRequestId,相同请求只创建一次 attempt
  • 同一 logical task 同时只允许一个 publishing rerun;isolated rerun 可按配置限制并发
  • attempt 带 execution epoch,旧 worker 的迟到结果不能覆盖当前 active attempt
  • paused job 可以创建 rerun request,但在 Resume 前不调度
  • canceled job 默认只允许 isolated rerun;需要恢复 job 时显式操作
  • 批量 rerun 应作为一个服务端 batch request 执行,返回逐项结果,不由浏览器循环调用单 task API

UI 与可观测性

  • Task detail 展示完整 attempt timeline、source、模式、配置差异和 session strategy
  • rerun 前预览 input snapshot、预计失效范围和下游 task 数量
  • 支持比较两个 attempt 的输出、token usage、耗时、模型和错误
  • 明确标识 active、isolated、stale、superseded 和 publishing attempt
  • 日志记录 rerun request、active attempt 切换和每个 descendant 的失效/重建原因

验收标准

  • 多次点击或重复请求不会创建重复 rerun attempt
  • 每个 rerun 都能追溯 source、root、attempt number、input 和 definition snapshot
  • 默认 isolated rerun 不改变现有 pipeline/candidate 的有效结果
  • Replace and propagate 只重建受影响的下游子树,不重复生成有效 candidate/result
  • 旧 lineage 的迟到结果不能覆盖新 active attempt
  • Fresh、fork-from-base 和 continue 三种 session 语义明确;fork 不可用时 fail fast
  • 服务重启、Pause / Resume 和批量 rerun 后仍保持一致
  • 覆盖 root/fan-out/candidate task、并发 rerun、发布失败、缺失 artifact、下游失效和迟到提交测试

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions