Files
agentic-coding-workflow/internal/orchestrator/domain.go
T
2026-06-22 08:55:57 +08:00

160 lines
5.7 KiB
Go

// 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)
}