highlight active subagents

This commit is contained in:
Ian Gulliver
2026-10-17 08:21:11 -07:00
parent 53699cc579
commit b43cffab6d
13 changed files with 374 additions and 235 deletions
+31 -2
View File
@@ -464,6 +464,8 @@ ALTER TABLE tasks ADD COLUMN merge_after_review_target TEXT NOT NULL DEFAULT '';
ALTER TABLE inbox_responses ADD COLUMN images TEXT NOT NULL DEFAULT '[]';
`}, {"add-lead-note-projects", `
ALTER TABLE lead_notes ADD COLUMN project_id TEXT NOT NULL DEFAULT '';
`}, {"add-session-subagents", `
ALTER TABLE agent_sessions ADD COLUMN subagents INTEGER NOT NULL DEFAULT 0;
`}}
const (
@@ -1604,6 +1606,32 @@ func (s *Store) transitionSession(ctx context.Context, id string, from *api.Agen
})
}
func (s *Store) SessionsWithSubagents(ctx context.Context) ([]api.AgentSession, error) {
return s.querySessions(ctx, `SELECT `+sessionColumns+` FROM agent_sessions WHERE subagents > 0`)
}
func (s *Store) SetSubagents(ctx context.Context, id string, n int, actor string) error {
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
taskID := ""
projectID := ""
owner := ""
err := tx.QueryRowContext(ctx, `
SELECT coalesce(t.id, ''), coalesce(t.project_id, ''), s.owner FROM agent_sessions s LEFT JOIN tasks t ON t.id = s.task_id WHERE s.id = ?
`, id).Scan(&taskID, &projectID, &owner)
if errors.Is(err, sql.ErrNoRows) {
return ErrNotFound
}
if err != nil {
return err
}
_, err = tx.ExecContext(ctx, `UPDATE agent_sessions SET subagents = ? WHERE id = ?`, n, id)
if err != nil {
return err
}
return emit(sessionEvent("session.subagents", projectID, taskID, owner, id, actor, map[string]any{"subagents": n}))
})
}
func (s *Store) SessionStarted(ctx context.Context, sessionID string) (bool, error) {
started := false
err := s.db.QueryRowContext(ctx, `SELECT EXISTS (SELECT 1 FROM events WHERE agent_session_id = ? AND kind = 'user.message')`, sessionID).Scan(&started)
@@ -1791,6 +1819,7 @@ const taskStateExpr = `CASE
ELSE coalesce((
SELECT CASE
WHEN s.state != 'idle' THEN s.state
WHEN s.subagents > 0 THEN 'running'
WHEN EXISTS (SELECT 1 FROM reviews r WHERE r.task_id = tasks.id AND r.state = 'running') THEN 'reviewing'
WHEN tasks.review_requests > 0 THEN 'review_pending'
ELSE 'idle'
@@ -1856,7 +1885,7 @@ const projectColumns = `id, name, repo_path, default_branch, remote, created_by,
const taskColumns = `id, project_id, title, merge_title, branch, worktree_path, base_ref, port_base, color, status, created_by, created_at, closed_at, merge_commit, todo_item, forked_from, forked_at, merge_queued_at, workflow_name, workflow_run, workflow_stage, parent_task_id, parent_merge_by, merge_after_review_by != '', state, merging_by != '' OR finalizing != '', discard_state != '' AND status = 'active', (SELECT coalesce(max(seq), 0) FROM events WHERE events.task_id = tasks.id AND kind = 'turn.ended' AND json_extract(payload, '$.summary') = 1)`
const sessionColumns = `id, coalesce(task_id, ''), owner, vendor, model, vendor_session_id, state, role, created_by, created_at, forked_from, forked_at`
const sessionColumns = `id, coalesce(task_id, ''), owner, vendor, model, vendor_session_id, state, role, created_by, created_at, forked_from, forked_at, subagents`
type scanner interface {
Scan(dest ...any) error
@@ -1946,7 +1975,7 @@ func scanSession(row scanner) (api.AgentSession, error) {
createdAt := ""
forkedFrom := ""
forkedAt := ""
err := row.Scan(&sess.Id, &sess.TaskId, &sess.Owner, &vendor, &sess.Model, &sess.VendorSessionId, &state, &role, &sess.CreatedBy, &createdAt, &forkedFrom, &forkedAt)
err := row.Scan(&sess.Id, &sess.TaskId, &sess.Owner, &vendor, &sess.Model, &sess.VendorSessionId, &state, &role, &sess.CreatedBy, &createdAt, &forkedFrom, &forkedAt, &sess.Subagents)
if err != nil {
return sess, err
}