// Package orchestrator 实现"编排器/规划器":一个 per-requirement 的 run 聚合根, // 驱动 6 阶段状态机(planning → prototyping → auditing → implementing → reviewing // → done)。每个 step 选取一个 agent-kind + prompt,以特权但真实的 owner 身份经 // acp.SessionService 创建一个 ACP session,发一条 prompt 并阻塞等待回合完成 // (session/prompt stopReason),评估阶段网关后推进或回环。run 状态落库到 // orchestrator_runs / orchestrator_steps,每个 step 由 jobs (orchestrator.step) 驱动, // 因而能跨重启恢复并复用既有 backoff/dead-letter 机制。 // // agent-to-agent handoff 发生在编排器层:特权身份创建下一个 session,不放松 // checkNotSystemToken。request_subtask MCP 工具让运行中的 agent 在 depth/fan-out // 限制内入队一个子 step。崩溃的 session 在同一 worktree 上重试/恢复。 package orchestrator import ( "context" "time" "github.com/google/uuid" "github.com/yan1h/agent-coding-workflow/internal/project" ) // RunStatus 是 orchestrator_runs.status 枚举。 type RunStatus string const ( RunPending RunStatus = "pending" RunRunning RunStatus = "running" RunPaused RunStatus = "paused" RunSucceeded RunStatus = "succeeded" RunFailed RunStatus = "failed" RunCanceled RunStatus = "canceled" ) // IsTerminal 报告 run 是否已到终态(不再驱动)。 func (s RunStatus) IsTerminal() bool { return s == RunSucceeded || s == RunFailed || s == RunCanceled } // IsActive 报告 run 是否处于可驱动状态(pending/running)。paused 不驱动但非终态。 func (s RunStatus) IsActive() bool { return s == RunPending || s == RunRunning } // StepStatus 是 orchestrator_steps.status 枚举。 type StepStatus string const ( StepPending StepStatus = "pending" StepSpawning StepStatus = "spawning" StepRunning StepStatus = "running" StepAwaitingGate StepStatus = "awaiting_gate" StepSucceeded StepStatus = "succeeded" StepFailed StepStatus = "failed" StepDead StepStatus = "dead" ) // Run 是一次编排运行聚合根。 type Run struct { ID uuid.UUID ProjectID uuid.UUID RequirementID uuid.UUID WorkspaceID uuid.UUID OwnerID uuid.UUID Status RunStatus CurrentPhase project.Phase Config RunConfig LastError *string CreatedAt time.Time UpdatedAt time.Time EndedAt *time.Time } // Step 是 run 内一次阶段尝试。parent_step_id 非 nil 表示由 request_subtask fan-out。 type Step struct { ID uuid.UUID RunID uuid.UUID Phase project.Phase Attempt int ParentStepID *uuid.UUID Depth int Status StepStatus AgentKindID uuid.UUID ACPSessionID *uuid.UUID Prompt string StopReason *string GateResult *GateResult LastError *string JobID *uuid.UUID CreatedAt time.Time UpdatedAt time.Time EndedAt *time.Time } // RunConfig 是 run 的 per-phase 配置(落 JSONB)。零值合法:PhaseToAgentKind 退回 // defaults,MaxAttemptsPerPhase/MaxDepth/FanOutLimit<=0 时由 service 用配置默认填充。 type RunConfig struct { PhaseAgentKinds map[project.Phase]uuid.UUID `json:"phase_agent_kinds,omitempty"` PromptOverrides map[project.Phase]string `json:"prompt_overrides,omitempty"` MaxAttemptsPerPhase int `json:"max_attempts_per_phase,omitempty"` MaxDepth int `json:"max_depth,omitempty"` FanOutLimit int `json:"fan_out_limit,omitempty"` } // GateResult 是一次阶段网关评估结果。Pass=true 推进;Retry=true 且未通过 → 可重试 // (回环本阶段);Retry=false 且未通过 → 永久失败(dead-letter)。 type GateResult struct { Pass bool `json:"pass"` Retry bool `json:"retry"` Reason string `json:"reason,omitempty"` Detail map[string]any `json:"detail,omitempty"` } // PhaseGate 是可插拔的阶段网关接口。v1 实现见 gate.go。 type PhaseGate interface { Evaluate(ctx context.Context, run *Run, step *Step, stopReason string) (GateResult, error) } // Caller 表示发起编排操作的用户上下文(与其他模块的 Caller 同语义)。 type Caller struct { UserID uuid.UUID IsAdmin bool } // StartRunInput 是启动一次编排运行的入参。 type StartRunInput struct { ProjectSlug string RequirementNumber int StartPhase project.Phase Config RunConfig } // SubtaskInput 是 request_subtask 的入参(由 MCP bridge 透传)。 type SubtaskInput struct { Phase project.Phase Prompt string AgentKindID *uuid.UUID } // RunFilter 控制 ListRuns 的过滤维度。零值不过滤。 type RunFilter struct { ProjectID *uuid.UUID RequirementID *uuid.UUID Status RunStatus Limit int } // Service 暴露编排器聚合根的应用服务方法。 type Service interface { StartRun(ctx context.Context, c Caller, in StartRunInput) (*Run, error) GetRun(ctx context.Context, c Caller, id uuid.UUID) (*Run, error) ListRuns(ctx context.Context, c Caller, f RunFilter) ([]*Run, error) Pause(ctx context.Context, c Caller, id uuid.UUID) error Resume(ctx context.Context, c Caller, id uuid.UUID) error Cancel(ctx context.Context, c Caller, id uuid.UUID) error // RequestSubtask 由 MCP bridge 调用:运行中的 agent 请求编排器为其当前 step 派生子 step。 RequestSubtask(ctx context.Context, parentACPSessionID uuid.UUID, in SubtaskInput) (*Step, error) // EnqueueStepRedrive 由 acp supervisor onExit 注入的回调间接调用:把崩溃 session 的 // step 重新入队(带 backoff)。 EnqueueStepRedrive(ctx context.Context, stepID uuid.UUID, reason string) }