feat(auto): multi-model orchestration of coding agents#137
Merged
Conversation
refractor@3 returns Array<Node>; hast-util-to-jsx-runtime expects a Root. Without the wrap, fenced code blocks rendered as empty boxes while inline code worked fine.
- P7 Resume: hydrate AutoRun panel from DB snapshot; approve/cancel awaiting_approval runs after restart via agent_resume_auto_turn. - P8 Cross-provider: worker pool dispatches each model to its own provider via build_worker_llm_configs (fail-fast on missing provider or duplicate model names). Removes the orchestrator-config-shared- with-workers v1 limitation. - P9a Capped LLM retries in workers (RetryConfig::auto_worker, max_retries=1) so transient endpoint failures surface fast. - P9b Replan budget setting removed (AUTO_REPLAN_BUDGET=0 hardcoded); user is the budget via P9c. - P9c Pause on hard worker failure: new AwaitingFailureDecision status + WorkerFailureContext + pending_failure DB column. Surfaces Retry / Replan / Cancel in an amber banner; survives restart via reaper skip. Cancel emits agent:auto_failed directly so the panel transitions without a reload. Plus: serialized DbAutoStateListener writes (race fix), tolerant plan parsing (stringified plan + missing see_prior default), tool list tail-5 + collapse on RunningWorkerCard.
Three product-polish gaps closed before the merge to main plus a handful of review fixes that landed alongside them. - Mode gating: Auto is scoped to Code mode. ModelPicker hides the Auto entry outside coding; AgentInput.handleModeChange silently reverts the model when the user switches away from Code with Auto still selected. resolve_session_auto_mode enforces the same constraint at the backend as a backstop. Auto-sentinel capability is short-circuited in agentSlice so the + attach button and context bar stay visible with Auto picked. - Title generation: run_auto_turn now runs the same substring fallback + LLM few-shot title flow as run_agent_turn. Title model falls back to the orchestrator's provider when no dedicated title model is configured. spawn_title_generation, read_selection and resolve_ref exposed pub(crate) for the cross-module call. The few-shot prompt was hardened after haiku refused to title "list top-level files" as a real request: user messages are wrapped in <first_message> tags and the system prompt names the specific failure modes to avoid. Adds [title-gen] telemetry. - Cancel summary: AutoResult::Cancelled now carries a phase string captured at each finalize_cancelled call site (Planning vN, Replanning vN, Approval for plan vN, Worker wN (model)). The Tauri layer renders a structured markdown summary including completed workers so the persisted assistant message stays useful for the next LLM turn instead of "Auto run interrupted by user". Also folded in from the pre-merge review pass: - LlmClientConfig has a manual Debug impl that redacts api_key. - PendingFailureBanner clears submitting in a finally block so a crash between resolve_worker_failure success and the next event can't strand the buttons disabled. - Adds AwaitingFailureDecision to the AutoStatus DB roundtrip test. 52/52 backend auto tests pass (added cancel_during_second_worker_preserves_prior_success).
Close four bugs in the P9c pause-on-failure flow before merging to main.
1. Race: finalize_awaiting_failure_decision persisted the AutoRun via a
fire-and-forget mpsc + spawn_blocking, then emitted AutoFailed. The
frontend refetched the snapshot to check pending_failure, but the
read and the write both contended for the same Mutex<Connection>
and could arrive out of order — when the read won, pending_failure
was null in the returned snapshot, the recovery branch didn't fire,
and the panel stayed permanently on the red terminal banner with no
Retry/Replan/Cancel controls. Fix: new AgentEvent variant
AutoAwaitingFailureDecision carries the WorkerFailureContext inline,
so the frontend can transition straight to the amber banner with no
DB round-trip.
2. useAgentEvents' getAutoRun call swallowed any IPC/DB error in a
.catch(warn). Removing the refetch entirely closes this.
3. setAutoFailed unconditionally wrote status='failed' before the
async correction landed, causing a visible red-flash on every hard
failure. The new reducer setAutoAwaitingFailureDecision writes
'awaiting_failure_decision' + pendingFailure atomically from the
event payload — no intermediate state.
4. resume_auto_turn never called db.set_session_status(sid, "active"),
so resumed runs (Retry / Replan / restart-resume) executed with
the sidebar showing "idle". Mirror run_auto_turn and flip to
"active" after acquiring the folder lock.
Executor return value (AutoResult::Failed { reason, run }) is
unchanged; only the event channel differs. Terminal-event drain
helper updated to treat AutoAwaitingFailureDecision as terminal
alongside AutoDone / AutoFailed. Existing budget-exhaustion test
updated to assert the new event variant.
Verified: cargo test -p agent (498 passed), cargo check
(agent + tauri), tsc --noEmit (desktop frontend).
…ed plan Previously if the user clicked Retry and the target worker id somehow wasn't in the saved plan, `position(...).unwrap_or(0)` silently restarted the run from index 0 — replaying every already-completed worker while showing no indication that anything was wrong. That masks a real data-integrity bug (plan and pending_failure out of sync) as a confusing UX one. Return AutoResult::Failed with a diagnostic that names the missing id and lists the plan's actual worker ids so it's obvious what happened. Test added to pin the behavior.
Each worker pool entry stored a provider_id (v4 UUID) and the row
rendered it verbatim, so users saw a cryptographic string under each
model name. Look up the provider from the store and render the same
friendly label the ModelPicker uses ("OpenAI" / "Anthropic" / custom
label / base URL host). Falls back to a truncated marker with the raw
id when the underlying provider was deleted after the pool entry was
added — the run-time validator still fail-fasts that case with a
clear error.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces Auto mode — an orchestrator-of-workers coding agent for SuperCoder. The user's task is handed to a planning LLM that decomposes it into a sequence of sub-tasks, each dispatched to a fresh AgentLoop running a model chosen from a user-curated worker pool. Different sub-tasks can run on different models across different providers in a single plan.
How Auto Mode Works
1. Worker Pool
User-curated, in Settings → Auto. Each pool entry is
{provider_id, model, description}. The description is a free-text hint the user writes: "cheap exploration", "strong on multi-file edits", "fast codebase reading", etc. Pool can mix providers freely — Anthropic + OpenRouter + OpenAI in the same plan.2. Planning
On each Auto turn the orchestrator LLM receives the user's task, the full pool listing (models + descriptions), and any prior worker outputs. It emits a plan via a forced
submit_plantool call — a strictly-typed JSON object containing:reasoning: 1–3 sentences explaining the decompositionplan: ordered list of 1–10 workers, each{id, model, prompt, see_prior}The orchestrator never executes work itself — the sole allowed action is emitting the plan.
3. Approval
The plan card renders in the chat with each worker's model + prompt visible. User clicks Run to proceed or Cancel to reject.
4. Sequential Worker Execution
Workers run one at a time, top-to-bottom. Each worker is a fresh full-featured AgentLoop with the standard coding toolkit (read/edit/bash/grep/glob/write/…) running in the user's working directory. Workers share the file system but not conversation history — w2 can read files w1 created, but only sees w1's final summary if
see_priorallows.see_priorgates upstream context per-worker:Cheap models on the bookends, expensive models on the design + edit core.