Questions tab, question bubbles, answer snapshots; errors to transcript

This commit is contained in:
Ian Gulliver
2026-10-18 15:06:06 -07:00
parent 1ef3594016
commit 10a80ccb22
31 changed files with 744 additions and 665 deletions
+41 -5
View File
@@ -145,7 +145,11 @@ 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 && last.TreeSha == tree && !force {
reviewed, err := m.store.LastSnapshotNot(ctx, t.taskID, api.SnapshotTriggerAnswer)
if err != nil && !errors.Is(err, store.ErrNotFound) {
return nil, err
}
if err == nil && reviewed.TreeSha == tree && !force {
return nil, nil
}
@@ -179,7 +183,7 @@ func (m *Manager) takeSnapshot(ctx context.Context, t snapTarget, trigger api.Sn
}
func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error {
task, project, err := m.activeTask(ctx, taskID)
task, _, err := m.activeTask(ctx, taskID)
if err != nil {
return err
}
@@ -204,8 +208,7 @@ func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error {
if len(sessions) == 0 {
return fmt.Errorf("%w: task %s has no agent session to attribute a snapshot to", ErrConflict, task.Id)
}
sess := sessions[len(sessions)-1]
creator, err := m.store.GetUser(ctx, sess.CreatedBy)
t, err := m.sessionTarget(ctx, sessions[len(sessions)-1], task)
if err != nil {
return err
}
@@ -213,11 +216,44 @@ func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error {
if err != nil {
return err
}
t := snapTarget{taskID: task.Id, projectID: project.Id, sessionID: sess.Id, dir: task.WorktreePath, gitName: creator.GitName, gitEmail: creator.GitEmail}
m.snapshotSoon(t, api.SnapshotTriggerRequested, 0, true, true)
return nil
}
func (m *Manager) sessionTarget(ctx context.Context, sess api.AgentSession, task api.Task) (snapTarget, error) {
creator, err := m.store.GetUser(ctx, sess.CreatedBy)
if err != nil {
return snapTarget{}, err
}
return snapTarget{taskID: task.Id, projectID: task.ProjectId, sessionID: sess.Id, dir: task.WorktreePath, gitName: creator.GitName, gitEmail: creator.GitEmail}, nil
}
func (m *Manager) snapshotForAnswer(ctx context.Context, t snapTarget, held bool) int {
if !held {
unlock := m.lockTask(t.taskID)
defer unlock()
}
m.snapMu.Lock()
st := m.snapStateLocked(t.taskID)
m.snapMu.Unlock()
st.mu.Lock()
defer st.mu.Unlock()
m.snapMu.Lock()
closed := st.closed
m.snapMu.Unlock()
if closed {
return 0
}
snap, err := m.takeSnapshot(ctx, t, api.SnapshotTriggerAnswer, 0, true)
if err != nil {
slog.Error("take snapshot", "task", t.taskID, "trigger", api.SnapshotTriggerAnswer, "err", err)
m.recordError(&live{id: t.sessionID, taskID: t.taskID, projectID: t.projectID}, fmt.Sprintf("byre couldn't snapshot the worktree before handing over an answer, so the answer went to the agent without one: %v", err))
return 0
}
return snap.N
}
func (m *Manager) takeSnapshotTool(l *live) mcp.Tool {
return mcp.Tool{
Name: "take_snapshot",