From 0d793eed45f4cf3a6f6d115fb3d57a18e573b41c Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Fri, 23 Oct 2026 17:42:18 -0700 Subject: [PATCH] Pass snapshot requests intact through the snapshot pipeline --- internal/agents/manager.go | 2 +- internal/agents/snapshots.go | 49 +++++++++++++++++------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/internal/agents/manager.go b/internal/agents/manager.go index 2c35df1..1979d3e 100644 --- a/internal/agents/manager.go +++ b/internal/agents/manager.go @@ -1376,7 +1376,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error { return err } if snapshot && !held { - m.snapshotSoon(liveTarget(l), api.SnapshotTriggerTurnEnd, 0, review, false) + m.snapshotSoon(snapRequest{target: liveTarget(l), trigger: api.SnapshotTriggerTurnEnd, review: review}) } if end.Discard != store.DiscardNone { diff --git a/internal/agents/snapshots.go b/internal/agents/snapshots.go index af5c680..ca47432 100644 --- a/internal/agents/snapshots.go +++ b/internal/agents/snapshots.go @@ -20,7 +20,6 @@ import ( type snapRequest struct { target snapTarget trigger api.SnapshotTrigger - seq int64 review bool force bool } @@ -54,27 +53,27 @@ func (m *Manager) snapStateLocked(taskID string) *snapState { return st } -func (m *Manager) snapshotSoon(t snapTarget, trigger api.SnapshotTrigger, seq int64, review, force bool) { +func (m *Manager) snapshotSoon(req snapRequest) { + t := req.target m.snapMu.Lock() defer m.snapMu.Unlock() st := m.snapStateLocked(t.taskID) if st.closed { - m.dropRequest(t.taskID, &snapRequest{review: review}) + m.dropRequest(&req) return } - req := &snapRequest{target: t, trigger: trigger, seq: seq, review: review, force: force} if st.running { if p := st.pending; p != nil && p.force { req.force = true req.trigger = p.trigger } - m.dropRequest(t.taskID, st.pending) - st.pending = req + m.dropRequest(st.pending) + st.pending = &req return } st.running = true - go m.runSnapshots(st, req) + go m.runSnapshots(st, &req) } func (m *Manager) runSnapshots(st *snapState, req *snapRequest) { @@ -86,15 +85,15 @@ func (m *Manager) runSnapshots(st *snapState, req *snapRequest) { closed := st.closed m.snapMu.Unlock() if !closed { - snap, err := m.takeSnapshot(context.Background(), t, req.trigger, req.seq, req.force, req.review) + snap, err := m.takeSnapshot(context.Background(), *req) if err != nil { slog.Error("take snapshot", "task", t.taskID, "trigger", req.trigger, "err", err) } if snap == nil { - m.dropRequest(t.taskID, req) + m.dropRequest(req) } } else { - m.dropRequest(t.taskID, req) + m.dropRequest(req) } st.mu.Unlock() unlock() @@ -103,7 +102,7 @@ func (m *Manager) runSnapshots(st *snapState, req *snapRequest) { req = st.pending st.pending = nil if req == nil || st.closed { - m.dropRequest(t.taskID, req) + m.dropRequest(req) st.running = false m.snapMu.Unlock() return @@ -112,9 +111,9 @@ func (m *Manager) runSnapshots(st *snapState, req *snapRequest) { } } -func (m *Manager) dropRequest(taskID string, req *snapRequest) { +func (m *Manager) dropRequest(req *snapRequest) { if req != nil && req.review { - m.endReviewRequest(taskID) + m.endReviewRequest(req.target.taskID) } } @@ -125,13 +124,11 @@ func (m *Manager) endReviewRequest(taskID string) { } } -func (m *Manager) takeSnapshot(ctx context.Context, t snapTarget, trigger api.SnapshotTrigger, seq int64, force, review bool) (*api.Snapshot, error) { - if seq == 0 { - var err error - seq, err = m.store.LastTaskSeq(ctx, t.taskID) - if err != nil { - return nil, err - } +func (m *Manager) takeSnapshot(ctx context.Context, req snapRequest) (*api.Snapshot, error) { + t := req.target + seq, err := m.store.LastTaskSeq(ctx, t.taskID) + if err != nil { + return nil, err } tree, err := git.Snapshot(ctx, t.dir) @@ -147,12 +144,12 @@ func (m *Manager) takeSnapshot(ctx context.Context, t snapTarget, trigger api.Sn if err != nil && !errors.Is(err, store.ErrNotFound) { return nil, err } - if err == nil && reviewed.TreeSha == tree && !force { + if err == nil && reviewed.TreeSha == tree && !req.force { return nil, nil } n := last.N + 1 - commit, err := git.CommitSnapshot(ctx, t.dir, tree, git.SnapshotRef(t.taskID, n), fmt.Sprintf("byre snapshot #%d (%s)", n, trigger), git.IdentityEnv(t.gitName, t.gitEmail)) + commit, err := git.CommitSnapshot(ctx, t.dir, tree, git.SnapshotRef(t.taskID, n), fmt.Sprintf("byre snapshot #%d (%s)", n, req.trigger), git.IdentityEnv(t.gitName, t.gitEmail)) if err != nil { return nil, err } @@ -165,10 +162,10 @@ func (m *Manager) takeSnapshot(ctx context.Context, t snapTarget, trigger api.Sn CommitSha: commit, TreeSha: tree, EventSeq: seq, - Trigger: trigger, + Trigger: req.trigger, CreatedAt: time.Now().UTC(), } - err = m.store.CreateSnapshot(ctx, snap, t.projectID, review) + err = m.store.CreateSnapshot(ctx, snap, t.projectID, req.review) if err != nil { return nil, err } @@ -215,7 +212,7 @@ func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error { if err != nil { return err } - m.snapshotSoon(t, api.SnapshotTriggerRequested, 0, true, true) + m.snapshotSoon(snapRequest{target: t, trigger: api.SnapshotTriggerRequested, review: true, force: true}) return nil } @@ -256,7 +253,7 @@ func (m *Manager) cutSnapshot(ctx context.Context, t snapTarget, held bool, trig if closed { return nil, nil } - return m.takeSnapshot(ctx, t, trigger, 0, true, false) + return m.takeSnapshot(ctx, snapRequest{target: t, trigger: trigger, force: true}) } func (m *Manager) takeSnapshotTool(l *live) mcp.Tool {