You've already forked agentic-coding-workflow
bugfix
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
// 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)
|
||||
}
|
||||
Reference in New Issue
Block a user