diff options
| -rw-r--r-- | internal/executor/executor.go | 6 | ||||
| -rw-r--r-- | internal/storage/db.go | 12 | ||||
| -rw-r--r-- | web/app.js | 11 |
3 files changed, 26 insertions, 3 deletions
diff --git a/internal/executor/executor.go b/internal/executor/executor.go index bf209b7..475d150 100644 --- a/internal/executor/executor.go +++ b/internal/executor/executor.go @@ -28,6 +28,7 @@ type Store interface { UpdateTaskQuestion(taskID, questionJSON string) error UpdateTaskSummary(taskID, summary string) error AppendTaskInteraction(taskID string, interaction task.Interaction) error + UpdateTaskAgent(id string, agent task.AgentConfig) error } // LogPather is an optional interface runners can implement to provide the log @@ -435,6 +436,11 @@ func (p *Pool) execute(ctx context.Context, t *task.Task) { } } + // Persist the assigned agent (and model) to the database before running. + if err := p.store.UpdateTaskAgent(t.ID, t.Agent); err != nil { + p.logger.Error("failed to persist agent config", "error", err, "taskID", t.ID) + } + agentType := t.Agent.Type if agentType == "" { agentType = "claude" diff --git a/internal/storage/db.go b/internal/storage/db.go index b8a7085..043009c 100644 --- a/internal/storage/db.go +++ b/internal/storage/db.go @@ -251,6 +251,18 @@ func (s *DB) ResetTaskForRetry(id string) (*task.Task, error) { return t, nil } +// UpdateTaskAgent updates only the agent configuration of a task. +func (s *DB) UpdateTaskAgent(id string, agent task.AgentConfig) error { + configJSON, err := json.Marshal(agent) + if err != nil { + return fmt.Errorf("marshaling agent config: %w", err) + } + now := time.Now().UTC() + _, err = s.db.Exec(`UPDATE tasks SET config_json = ?, updated_at = ? WHERE id = ?`, + string(configJSON), now, id) + return err +} + // RejectTask sets a task's state to PENDING and stores the rejection comment. func (s *DB) RejectTask(id, comment string) error { now := time.Now().UTC() @@ -456,8 +456,11 @@ function renderAllPanel(tasks) { // ── Run action ──────────────────────────────────────────────────────────────── -async function runTask(taskId) { - const res = await fetch(`${API_BASE}/api/tasks/${taskId}/run`, { method: 'POST' }); +async function runTask(taskId, agent) { + const url = agent && agent !== 'auto' + ? `${API_BASE}/api/tasks/${taskId}/run?agent=${agent}` + : `${API_BASE}/api/tasks/${taskId}/run`; + const res = await fetch(url, { method: 'POST' }); if (!res.ok) { let msg = `HTTP ${res.status}`; try { const body = await res.json(); msg = body.error || body.message || msg; } catch {} @@ -467,6 +470,8 @@ async function runTask(taskId) { } async function handleRun(taskId, btn, footer) { + const agentSelector = document.getElementById('select-agent'); + const agent = agentSelector ? agentSelector.value : 'auto'; btn.disabled = true; btn.textContent = 'Queuing…'; @@ -475,7 +480,7 @@ async function handleRun(taskId, btn, footer) { if (prev) prev.remove(); try { - await runTask(taskId); + await runTask(taskId, agent); // Refresh active panel so state flips to QUEUED await poll(); } catch (err) { |
