held merge should sync

This commit is contained in:
Ian Gulliver
2026-10-18 23:28:17 -07:00
parent 9625be25fd
commit 5aa8a8fbe4
2 changed files with 34 additions and 6 deletions
+33 -5
View File
@@ -39,6 +39,25 @@ func (m *Manager) MergeIn(ctx context.Context, task api.Task, user api.User, tar
return m.sendMergeIn(ctx, task, user, prompt)
}
func (m *Manager) headStartMerge(ctx context.Context, task api.Task, user api.User, target string) {
sess, err := m.mergeSession(ctx, task, user)
if errors.Is(err, ErrConflict) {
slog.Info("skip held merge head start", "task", task.Id, "err", err)
return
}
if err != nil {
slog.Error("held merge head start", "task", task.Id, "err", err)
return
}
prompt := mergeInPrompt(target) + fmt.Sprintf(" This task's Merge is held while another task merges into %s; this turn gets a head start, and byre merges %s in again when the held merge starts. If you stop for substantive changes, call stop_merge first, so byre drops the held merge and nothing is pushed before the review.", target, target)
go func() {
_, err := m.launch(context.Background(), sess, task, "byre", prompt, nil)
if err != nil {
slog.Error("start held merge head start", "task", task.Id, "err", err)
}
}()
}
func (m *Manager) sendMergeIn(ctx context.Context, task api.Task, user api.User, prompt string) (api.AgentSession, error) {
sess, found, err := m.liveSession(ctx, task.Id)
if err != nil {
@@ -98,6 +117,7 @@ func (m *Manager) Merge(ctx context.Context, task api.Task, project api.Project,
if err != nil {
return api.Task{}, err
}
m.headStartMerge(ctx, task, user, project.DefaultBranch)
}
m.clearMergeAfterReview(ctx, task.Id)
return m.store.GetTask(ctx, task.Id)
@@ -625,8 +645,8 @@ type stopMergeArgs struct {
func (m *Manager) stopMergeTool(l *live) mcp.Tool {
return mcp.Tool{
Name: "stop_merge",
Description: "Stop the merge byre is to make when this turn ends, so the task stays active and its snapshot is reviewed before anything is pushed. " +
"Call it during a Merge turn when resolving conflicts took substantive changes, then end your turn describing them. The human merges again after the review.",
Description: "Stop the merge byre is to make when this turn ends, or drop the held merge waiting for another task's, so the task stays active and its snapshot is reviewed before anything is pushed. " +
"Call it during a Merge turn, or a held merge's head-start merge-in, when resolving conflicts took substantive changes, then end your turn describing them. The human merges again after the review.",
InputSchema: json.RawMessage(`{
"type": "object",
"properties": {
@@ -654,10 +674,18 @@ func (m *Manager) stopMerge(ctx context.Context, l *live, raw json.RawMessage) (
if !m.leadsTask(ctx, l.taskID, l.id) {
return "", fmt.Errorf("%w: only the team's first agent runs the merge, so only it can stop it", ErrConflict)
}
if m.takeMerge(l.taskID) == "" {
return "No merge is pending for this task; just end your turn.", nil
switch {
case m.takeMerge(l.taskID) != "":
go m.releaseMerge(l.projectID, l.taskID)
default:
queuedBy, err := m.store.TakeQueuedMerge(ctx, l.taskID)
if err != nil {
return "", err
}
if queuedBy == "" {
return "No merge is pending for this task; just end your turn.", nil
}
}
go m.releaseMerge(l.projectID, l.taskID)
err = m.emit(ctx, l, agentActor, "task.merge_stopped", map[string]any{"id": l.taskID, "reason": reason})
if err != nil {