Add team tasks: several agents in one worktree sharing a board

This commit is contained in:
Ian Gulliver
2026-10-18 08:48:57 -07:00
parent 7f62df19d2
commit 6bcde13b2f
31 changed files with 1392 additions and 439 deletions
+18 -13
View File
@@ -68,7 +68,7 @@ func (m *Manager) Message(ctx context.Context, sessionID, actor, text, model str
if err != nil {
return api.AgentSession{}, false, err
}
err = m.store.AddTaskInput(ctx, store.TaskInput{TaskID: sess.TaskId, Actor: actor, Text: text, Images: images}, task.ProjectId, sess.Id)
err = m.store.AddTaskInput(ctx, store.TaskInput{TaskID: sess.TaskId, Member: sess.Member, Actor: actor, Text: text, Images: images}, task.ProjectId, sess.Id)
if err != nil {
return api.AgentSession{}, false, err
}
@@ -81,26 +81,18 @@ func (m *Manager) Withdraw(ctx context.Context, taskID string, inputID int64, ac
if err != nil {
return err
}
sessions, err := m.store.ListSessions(ctx, taskID)
if err != nil {
return err
}
if len(sessions) == 0 {
return fmt.Errorf("%w: message %d is not queued", ErrConflict, inputID)
}
sess := sessions[len(sessions)-1]
unlock := m.lockDelivery(queueLockKey(taskID))
defer unlock()
err = m.store.WithdrawTaskInput(ctx, taskID, inputID, task.ProjectId, sess.Id, actor)
sessionID, err := m.store.WithdrawTaskInput(ctx, taskID, inputID, task.ProjectId, actor)
if errors.Is(err, store.ErrNotFound) {
return fmt.Errorf("%w: message %d is not queued", ErrConflict, inputID)
}
if err != nil {
return err
}
slog.Info("queued message withdrawn", "session", sess.Id, "task", taskID, "input", inputID, "actor", actor)
slog.Info("queued message withdrawn", "session", sessionID, "task", taskID, "input", inputID, "actor", actor)
return nil
}
@@ -112,10 +104,16 @@ func (m *Manager) deliverQueued(ctx context.Context, sess api.AgentSession) (boo
unlock := m.lockDelivery(queueLockKey(sess.TaskId))
defer unlock()
inputs, err := m.store.TaskInputs(ctx, sess.TaskId)
inputs, err := m.store.TaskInputs(ctx, sess.TaskId, sess.Member)
if err != nil || len(inputs) == 0 {
return false, err
}
if sess.Member != "" {
started, err := m.store.SessionStarted(ctx, sess.Id)
if err != nil || !started {
return false, err
}
}
task, err := m.store.GetTask(ctx, sess.TaskId)
if err != nil {
@@ -170,7 +168,7 @@ func (m *Manager) takeQueuedMidTurn(ctx context.Context, l *live) []store.TaskIn
unlock := m.lockDelivery(queueLockKey(l.taskID))
defer unlock()
inputs, err := m.store.TaskInputs(ctx, l.taskID)
inputs, err := m.store.TaskInputs(ctx, l.taskID, l.member)
if err != nil {
slog.Error("list queued messages", "session", l.id, "err", err)
return nil
@@ -237,6 +235,9 @@ func (m *Manager) takeLeadQueuedMidTurn(ctx context.Context, l *live) []store.Le
func (m *Manager) recordQueued(ctx context.Context, l *live, msgs []queued) string {
b := &strings.Builder{}
for i, q := range msgs {
if l.implementer() && isMergeInPrompt(q.actor, q.text) {
m.takeMergeTurn(l)
}
err := m.emit(ctx, l, q.actor, "user.message", map[string]any{"text": q.text, "mid_turn": true})
if err != nil {
slog.Error("record mid-turn message", "session", l.id, "err", err)
@@ -244,6 +245,10 @@ func (m *Manager) recordQueued(ctx context.Context, l *live, msgs []queued) stri
if i > 0 {
b.WriteString("\n\n")
}
if q.actor == boardActor {
fmt.Fprintf(b, "While you were working, %s\n\nTake it into account now.", q.text)
continue
}
fmt.Fprintf(b, "%s sent you this message while you were working; take it into account now:\n\n%s", q.actor, q.text)
}
slog.Info("queued messages sent mid-turn", "session", l.id, "count", len(msgs))