Add Away mode and an agent fork tool

This commit is contained in:
Ian Gulliver
2026-10-19 21:40:24 -07:00
parent bb60b685ba
commit f6f2440635
22 changed files with 617 additions and 317 deletions
@@ -0,0 +1 @@
ALTER TABLE users ADD COLUMN away INTEGER NOT NULL DEFAULT 0;
+14
View File
@@ -40,6 +40,20 @@ func (s *Store) UpdateDefaultModel(ctx context.Context, login, model string) (ap
return s.GetUser(ctx, login)
}
func (s *Store) UpdateAway(ctx context.Context, login string, away bool) (api.User, error) {
err := s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
_, err := tx.ExecContext(ctx, `UPDATE users SET away = ? WHERE login = ?`, away, login)
if err != nil {
return err
}
return emit(api.Event{Kind: "user.updated", Actor: login, Payload: map[string]any{"login": login}})
})
if err != nil {
return api.User{}, err
}
return s.GetUser(ctx, login)
}
func (s *Store) UpdateReviewModels(ctx context.Context, login, model, second string) (api.User, error) {
err := s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
_, err := tx.ExecContext(ctx, `UPDATE users SET review_model = ?, second_review_model = ? WHERE login = ?`, model, second, login)
+8 -3
View File
@@ -17,7 +17,7 @@ func (s *Store) CreateSnapshot(ctx context.Context, snap api.Snapshot, projectID
if err != nil {
return err
}
if snap.Trigger != api.SnapshotTriggerAnswer {
if !CutPoint(snap.Trigger) {
_, err = tx.ExecContext(ctx, `UPDATE tasks SET ready = '' WHERE id = ?`, snap.TaskId)
if err != nil {
return err
@@ -68,8 +68,13 @@ func (s *Store) LastSnapshot(ctx context.Context, taskID string) (api.Snapshot,
return snap, err
}
func (s *Store) LastSnapshotNot(ctx context.Context, taskID string, trigger api.SnapshotTrigger) (api.Snapshot, error) {
snap, err := scanSnapshot(s.db.QueryRowContext(ctx, `SELECT `+snapshotColumns+` FROM snapshots WHERE task_id = ? AND trigger != ? ORDER BY n DESC LIMIT 1`, taskID, string(trigger)))
func CutPoint(trigger api.SnapshotTrigger) bool {
return trigger == api.SnapshotTriggerAnswer || trigger == api.SnapshotTriggerFork
}
func (s *Store) LastReviewable(ctx context.Context, taskID string) (api.Snapshot, error) {
snap, err := scanSnapshot(s.db.QueryRowContext(ctx, `SELECT `+snapshotColumns+` FROM snapshots WHERE task_id = ? AND trigger NOT IN (?, ?) ORDER BY n DESC LIMIT 1`,
taskID, string(api.SnapshotTriggerAnswer), string(api.SnapshotTriggerFork)))
if errors.Is(err, sql.ErrNoRows) {
return snap, ErrNotFound
}
+4 -4
View File
@@ -218,8 +218,8 @@ func (s *Store) EnsureUser(ctx context.Context, login, displayName string) (api.
func (s *Store) GetUser(ctx context.Context, login string) (api.User, error) {
u := api.User{}
prefs := ""
err := s.db.QueryRowContext(ctx, `SELECT login, display_name, git_name, git_email, notification_prefs, default_model, review_model, second_review_model FROM users WHERE login = ?`, login).
Scan(&u.Login, &u.DisplayName, &u.GitName, &u.GitEmail, &prefs, &u.DefaultModel, &u.ReviewModel, &u.SecondReviewModel)
err := s.db.QueryRowContext(ctx, `SELECT login, display_name, git_name, git_email, notification_prefs, default_model, review_model, second_review_model, away FROM users WHERE login = ?`, login).
Scan(&u.Login, &u.DisplayName, &u.GitName, &u.GitEmail, &prefs, &u.DefaultModel, &u.ReviewModel, &u.SecondReviewModel, &u.Away)
if errors.Is(err, sql.ErrNoRows) {
return u, ErrNotFound
}
@@ -751,9 +751,9 @@ func (s *Store) ReadyPromptDue(ctx context.Context, id string) (bool, error) {
err := s.db.QueryRowContext(ctx, `SELECT EXISTS (
SELECT 1 FROM events e, tasks t
WHERE t.id = ? AND e.task_id = t.id AND e.seq > t.ready_prompt_seq
AND ((e.kind = 'snapshot.created' AND json_extract(e.payload, '$.trigger') != ?)
AND ((e.kind = 'snapshot.created' AND json_extract(e.payload, '$.trigger') NOT IN (?, ?))
OR (e.kind = 'user.message' AND e.actor NOT IN ('byre', ?) AND e.actor NOT LIKE '% (lead)'))
)`, id, string(api.SnapshotTriggerAnswer), agentActor).Scan(&due)
)`, id, string(api.SnapshotTriggerAnswer), string(api.SnapshotTriggerFork), agentActor).Scan(&due)
return due, err
}