Remove automatic provider failover - #747
Conversation
TheGreatAxios
left a comment
There was a problem hiding this comment.
Self-review · clean
This PR removes implicit cross-provider failover and surfaces safe provider-failure guidance across TUI, exec, and subagent paths.
src/config/inference-sources.ts:160keeps main and subagent source bundles on the explicitly selected provider/model.src/tui/stream-event-map.ts:460replaces the director-resolved raw failure reply once and resets state for later inference.src/subagent/task-tool.ts:857clears retry state so unrelated failures remain distinct.tests/unit/inference-sources.test.ts:122andsrc/subagent/index.test.ts:1203pin the no-fallback and retry-state contracts.
Verdict: no blocking findings. bun run check passes with 5,729 tests and 0 failures.
TheGreatAxios
left a comment
There was a problem hiding this comment.
Correctness review · request changes
- Blocking —
src/exec/runner.ts:137:inferenceStartedis treated as proof that every later exception is a provider failure. Since it is set beforeactiveAgent.send()atsrc/exec/runner.ts:774, a director or context-store exception such asdisk fullis replaced with the provider-switch message instead of remaining distinct. Please classify an observed provider/OAuth failure rather than all post-start exceptions, and retain a regression test for a non-provider send failure. - Blocking —
src/tui/runner.ts:2144: every non-abortagentProxy.send()rejection is surfaced as a provider failure. For example, a rebuild failure rethrown atsrc/tui/runner.ts:1804occurs before inference but still tells the operator to switch providers. Please preserve unrelated rebuild/director errors and add a test alongside the provider-failure path. - Should-fix —
src/subagent/agent-fleet.ts:789: split-fleet failures forward the ID-only message created atsrc/subagent/run.ts:1119. With provider IDcodex/workand display nameCodex,wait_agentssayscodex/work Provider failed...while fused task, TUI, and exec sayCodex Provider failed.... Please apply the configured display label and pin that case insrc/subagent/run-resolved-provider-failure.test.ts:152.
TheGreatAxios
left a comment
There was a problem hiding this comment.
Architecture review · revise
The selected-source invariant is owned at the right boundary: src/config/inference-sources.ts:159 builds one source for both main and subagent sessions, and same-provider retry remains runtime-owned.
- High:
src/subagent/run.ts:1117reads stream-derivedterminalProviderDiagnosticimmediately afteragent.send()resolves. The stream consumer can lag the send promise, so DefaultDirector’s raw resolved reply can be accepted as a successful report beforeinference.erroris observed. The retained-worker path has the same race atsrc/subagent/run.ts:1055. - High:
src/subagent/agent-fleet.ts:784sanitizes only branded resolved failures and recognized auth errors. The fused path tracksinference.erroratsrc/subagent/task-tool.ts:857, but the split fleet path does not. A provider failure that emitsinference.errorand then rejects can therefore expose its diagnostic throughwait_agents. - Medium:
src/tui/runner.ts:2157attributes send failure to the current mutable provider, which live switching replaces atsrc/tui/runner.ts:2376. An in-flight request that rejects after/modelswitches can blame the newly selected provider. - Medium:
src/exec/runner.ts:137classifies every exception after inference starts as a provider failure, hiding local director, context, stream, or teardown failures behind misleading provider copy.
Provider-failure settlement should produce one structured outcome at the run boundary, carrying immutable attempt identity and the raw diagnostic. Entry points can then expose the shared safe message without duplicating event-state machines.
TheGreatAxios
left a comment
There was a problem hiding this comment.
Hygiene review · request changes
Should fix:
src/subagent/task-tool.ts:1145andsrc/subagent/agent-fleet.ts:795persist raw provider diagnostics throughsessions.fail().src/subagent/session-store.ts:915converts that value into a transcript report, andsrc/tui/runner-host.ts:185renders it verbatim. Keep diagnostics in non-rendered observability and use safe text for transcript entries.src/session/run-sink.test.ts:177andsrc/session/run-sink.test.ts:206retain model/provider-switch fixtures under “retry” terminology, whiledocs/TELEMETRY.md:172implies a retry can require unknown-provider attribution. Make these fixtures describe actual same-provider retry behavior or explicitly defensive mismatched attribution.src/tui/runner.ts:1510andsrc/exec/runner.ts:617retain dead multi-candidatebuildInitialSourceFallback()machinery althoughsrc/config/inference-sources.ts:160now guarantees exactly one selected source. Remove the unreachable fallback constructors and branches.
Optional cleanup:
src/subagent/agent-fleet.ts:789uses provider ID while fused task uses the configured display label; use one presentation path.src/subagent/task-tool.ts:439recognizes provider failure by duplicating the exact English suffix; carry structured failure metadata or centralize the predicate.src/subagent/run-resolved-provider-failure.test.ts:41leaks temporary directories and uses a fixed sleep; add cleanup and deterministic synchronization.
TheGreatAxios
left a comment
There was a problem hiding this comment.
Cleanup review · clean
This follow-up resolves the correctness, architecture, and hygiene review findings without restoring cross-provider failover.
src/exec/runner.ts:140classifies observed/typed provider failures precisely while preserving unrelated post-start errors.src/tui/runner.ts:600uses immutable attempt identity and keeps unrelated send/rebuild failures distinct.src/subagent/run-event-settlement.ts:19coordinates stream settlement deterministically for initial and retained-worker replies.src/subagent/agent-fleet.ts:808applies configured display labels, whilesrc/subagent/agent-fleet.ts:938carries structured provider-failure metadata instead of matching English text.src/inference-error-message.ts:95centralizes safe provider presentation and avoids duplicatedProvidersuffixes.
Verdict: no blocking findings remain. Independent verification passes: 217 focused tests, 5,733 full-suite tests, git diff --check, and bun run check.
The fused task wrapper is gone, so wait_agents is a long-lived parent tool and spawn_agent progress lasts the worker lifetime. Exec overlay tests now pin that mountFleet:false drops fleet verbs, not merely the old task name.
resume_agent marks the followup in flight before the session flips off completed, so the first wait_agents collect could return the prior stamp. Treat in-flight completed and interrupted as wait-running, and omit a leftover report from a failed wait result.
Auth and OAuth-refresh send failures were still suggesting /model. Keep that copy on login, drop the fused task coverage after spawn/wait became the only path, and document the no-failover behavior.
1ad4b55 to
73098c4
Compare
Summary
/modelguidance for terminal provider failures while retaining raw diagnostics in non-rendered observabilityVerification
bun run checkpasses