Run each workflow stage as its own task, with fan-out and fan-in
This commit is contained in:
@@ -58,6 +58,8 @@ type Manager struct {
|
||||
|
||||
reviewMu sync.Mutex
|
||||
|
||||
workflowMu sync.Mutex
|
||||
|
||||
bad *badLines
|
||||
watchStop chan struct{}
|
||||
}
|
||||
@@ -74,8 +76,7 @@ type live struct {
|
||||
projectID string
|
||||
owner string
|
||||
reviewID string
|
||||
stage int
|
||||
stages int
|
||||
stage string
|
||||
stopping bool
|
||||
interrupted bool
|
||||
asked bool
|
||||
@@ -130,18 +131,6 @@ func (m *Manager) Create(ctx context.Context, task api.Task, creator api.User, p
|
||||
}
|
||||
|
||||
func (m *Manager) create(ctx context.Context, task api.Task, creator api.User, prompt, model, actor string, images []string) (api.AgentSession, error) {
|
||||
existing, err := m.store.ListSessions(ctx, task.Id)
|
||||
if err != nil {
|
||||
return api.AgentSession{}, err
|
||||
}
|
||||
stage := 0
|
||||
if len(existing) > 0 && existing[len(existing)-1].WorkflowStage != nil {
|
||||
stage = *existing[len(existing)-1].WorkflowStage
|
||||
}
|
||||
return m.createAt(ctx, task, creator, prompt, model, actor, images, stage)
|
||||
}
|
||||
|
||||
func (m *Manager) createAt(ctx context.Context, task api.Task, creator api.User, prompt, model, actor string, images []string, stage int) (api.AgentSession, error) {
|
||||
if creator.GitName == "" || creator.GitEmail == "" {
|
||||
return api.AgentSession{}, ErrNoGitIdentity
|
||||
}
|
||||
@@ -173,9 +162,6 @@ func (m *Manager) createAt(ctx context.Context, task api.Task, creator api.User,
|
||||
CreatedBy: creator.Login,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
}
|
||||
if stage > 0 {
|
||||
sess.WorkflowStage = &stage
|
||||
}
|
||||
|
||||
err = m.store.CreateSession(ctx, sess, task.ProjectId)
|
||||
if err != nil {
|
||||
@@ -549,13 +535,12 @@ func (m *Manager) ensureLive(ctx context.Context, sess api.AgentSession, task ap
|
||||
return nil, err
|
||||
}
|
||||
tools := []mcp.Tool{m.askTool(l), m.cancelQuestionTool(l), m.createTaskTool(l), m.setMergeTitleTool(l), m.stopMergeTool(l), m.exposePortTool(l)}
|
||||
if sess.Role == api.Implementer && sess.WorkflowStage != nil {
|
||||
if sess.Role == api.Implementer && task.WorkflowStage != nil {
|
||||
frozen, err := m.store.TaskWorkflow(ctx, task.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.stage = *sess.WorkflowStage
|
||||
l.stages = len(frozen.Definition.Stages)
|
||||
l.stage = *task.WorkflowStage
|
||||
g += stageGuidance(frozen, l.stage)
|
||||
tools = append(tools, m.finishStageTool(l))
|
||||
}
|
||||
@@ -629,7 +614,7 @@ func (m *Manager) pump(l *live) {
|
||||
}
|
||||
|
||||
m.logUndelivered(ctx, l.id, "agent process exited mid-turn")
|
||||
if l.stage > 0 {
|
||||
if l.stage != "" {
|
||||
err = m.store.DropStageOutput(ctx, l.id)
|
||||
if err != nil {
|
||||
slog.Error("drop stage output", "session", l.id, "err", err)
|
||||
@@ -837,7 +822,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
|
||||
stageFinished := false
|
||||
switch {
|
||||
case l.stage == 0:
|
||||
case l.stage == "":
|
||||
case finished && !handoff && mergingBy == "":
|
||||
stageFinished, err = m.store.FinishStage(ctx, l.id)
|
||||
default:
|
||||
@@ -870,9 +855,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
}
|
||||
if stageFinished {
|
||||
go m.advanceStage(l)
|
||||
if l.stage < l.stages {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = m.Deliver(ctx, l.id)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user