Repository navigation
feat(fx): choose a backend per thread - #26994
jakeleventhal wants to merge 2 commits into
Conversation
fx can run on Vercel AI Gateway, a Codex or Grok subscription, or a configured OpenAI-compatible endpoint, but T3 Code only offered the backend `fx provider` had set, so switching meant a terminal. The fx snapshot now probes every backend with `FX_PROVIDER` (`fx status` for sign-in, `fx models` for its catalog) and lists models as `<backend>:<model>`. A new `subProviders` field on the provider snapshot lets the web picker and the mobile thread settings group them under collapsible backend headings; signed-out backends stay listed as unavailable with the `fx login` command to run. The adapter writes fx's per-session `provider` option before `model`, so each thread keeps its own backend without touching fx's global default. "Default" now resolves with `fx status` in the thread's folder, so a model fx's settings give one project is picked up there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR requires human approval — The picker adds explicit, session-local fx backend selection. Default also changes to use the project's backend and model settings, so existing Default threads may route differently; that behavior change needs human confirmation. Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
…n one Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Sub-provider contract and grouping packages/contracts/src/server.ts, packages/client-runtime/src/providerSubProviders.ts, packages/client-runtime/package.json, apps/mobile/src/lib/modelOptions.ts, apps/mobile/src/lib/modelOptions.test.ts |
The server contract adds ordered sub-provider metadata. Client utilities group models by sub-provider, and mobile model options carry that metadata. |
Backend status and default discovery packages/provider-fx/src/server/status.ts, packages/provider-fx/src/server/status.test.ts, packages/provider-fx/src/server/driver.ts |
The status check reads configured backends, probes their status and model listings, and creates backend-qualified model entries with availability details. It also reads a default backend and model in a specified working directory. |
Backend-aware model selection packages/provider-fx/src/server/acpSupport.ts, packages/provider-fx/src/server/adapter.ts, packages/provider-fx/src/server/driver.ts, apps/server/src/orchestration-v2/Adapters/FxAdapterV2.test.ts, docs/user/providers-fx.md |
Model selection accepts backend-qualified choices and applies the provider before the model. The adapter resolves defaults by runtime working directory. Tests cover backend changes, and the documentation describes the selection behavior. |
Sub-provider picker sections apps/web/src/components/chat/ModelPickerContent.tsx, apps/web/src/components/chat/modelPickerKeys.ts, apps/mobile/src/features/threads/ThreadSettingsSheet.tsx |
The web and mobile pickers group models under collapsible backend headings. They retain flat Search and Favorites views, and show unavailable reasons for unavailable backends. |
Priority:
Estimated code review effort: 4 (Complex) | ~45 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
participant FxDriver
participant checkFxProviderStatus
participant FxCLI
participant ProviderSnapshot
FxDriver->>checkFxProviderStatus: Request provider status
checkFxProviderStatus->>FxCLI: Probe each backend status and models
FxCLI-->>checkFxProviderStatus: Return backend status and model listings
checkFxProviderStatus->>ProviderSnapshot: Build models and availability metadata
Possibly related PRs
- pingdotgg/t3code#18277: Introduces the fx provider and its status probes, model selection, and ACP adapter, which this change extends with multiple backends.
- pingdotgg/t3code#25914: Changes model-row rendering for sub-provider data, which relates to the grouped model presentation added here.
Suggested reviewers: agadzik, maria-rcks, juliusmarminge
Merge Risk: 
Minimal · up to 5a446
-
No actionable merge-blocking issue is established. The remaining backend-compatibility uncertainty can be checked during normal validation.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description clearly covers the problem, implementation, affected clients, evidence, tests, limitations, and known unrelated failures. It omits the template's explicit Scope and approval section, but the substantive description is mostly complete.
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
|
closing at @StiensWout's request under Solve one underlying problem per PR. The fx backend picker also repairs the independent folder-aware Default-model resolution, and its changed mobile picker has no visual verification. The supplied web images show only the new UI. Separate the folder-aware Default-model repair from backend selection/grouping, or establish their necessary causal relationship. Supply clear before/after visual evidence for the changed web and native mobile picker states, including signed-out and expanded backend behavior; preserve the reported inability to choose an fx backend in T3. thanks for trying to help improve t3 code. if you think this closure was a mistake, please open a fresh pr addressing the requirement above, and link back to this one. |
|
Note 🤖 GPT-6.1 Sol responding on behalf of Jake Continued in #29388 for reconsideration of the closure. GitHub refused to reopen this PR through GraphQL and REST because the branch was force-pushed or recreated; restoring its closing head also failed. The replacement preserves this history and all evidence links. The underlying problem remains: upstream offers only the machine-default fx backend. Backend switching and resetting Default belong together because the adapter must restore a valid backend/model pair. A thread switched to Codex cannot safely reset to a Gateway default by writing only the model; the provider must change first. The adapter replay tests exercise that ordering and switching within one session. Folder-aware Default lookup can be separated technically. I am retaining it in the same default-resolution path and requesting reconsideration of that combined scope; I am not claiming it is required for grouping or that maintainers approved it. The description preserves all four prior fake-fx web captures and the reported real fx 0.0.15 probes and prior successful CI. It labels them historical. There is still no before screenshot, native capture, or interaction recording, and no fresh UI or real-provider runtime claim. The rebase preserves upstream picker, mobile policy/animation, and probe-timeout changes, plus the final auth fallback fix. |
Continued in #29388. GitHub refused reopening this PR after the branch rebase, including after restoring its closing head. The replacement carries the validated rebased head, this history, and all prior evidence links.
fx can run on Vercel AI Gateway, a Codex or Grok subscription, or a configured OpenAI-compatible endpoint, but T3 Code only offers the machine's active backend. This adds per-thread backend selection and restores Default as a valid backend/model pair, using the thread's folder configuration.
Scope and reconsideration
Reconsidering the closure explanation and closed event 34691805908. Upstream still exposes only the machine-default fx backend; per-backend catalogs, grouping, switching, and folder-aware Default remain absent.
Backend selection and resetting Default share a concrete invariant: restore a backend and a model that belong together. After a thread switches from Gateway to Codex, selecting Default must restore the default backend before its model; writing the Gateway model on Codex can fail or leave the previous model running. The adapter replay test covers both switching backends in one session and restoring a loaded session to the default backend, with the provider write before the model write.
Folder-aware lookup is independently separable. It is retained here deliberately because the same Default resolution path returns that backend/model pair in the thread's folder; it is not a required technical dependency of backend grouping. This is a request to reconsider the combined scope, not a claim that maintainers approved it. The closure's missing before/native visual evidence remains a limitation, explicitly recorded below.
The rebase preserves upstream's compact picker, trailing Show more/less control, effort column and IME handling (#28057/#28076/#28409), mobile policy and reduced-motion behavior, and the longer fx version-probe timeout (#28400). It also retains the final auth fallback correction: unknown Gateway sign-in cannot hide a signed-in Codex backend.
Fix
fx status --json(sign-in) andfx models --json(catalog) once per backend withFX_PROVIDER. Custom endpoints come from theproviderskeys in~/.fx/settings.json. Nothing opens an ACP session, which fx would save. Models are listed as<backend>:<model>(fx backend ids never contain:).ServerProvider.subProviders(name plus optionalunavailableReason) tells clients how to group a provider's models bysubProvider. Only fx sets it, so other providers are unchanged.fx login <backend>hint. Search and Favorites stay flat, retaining upstream's compact rows and inline backend labels.client-runtimeis shared with web.provideroption beforemodel, so each thread keeps its own backend and fx's global default is never changed. Logins stay machine-wide, which is why signed-out backends show as unavailable everywhere. A model id with no backend prefix (existing threads) still runs on the session's current backend.fx status --jsonrun in the thread's folder, so a per-project model in fx's settings is used there. On a session that is on another backend, Default now moves it to the default backend rather than staying put.docs/user/providers-fx.mdis updated.Prior visual evidence (2026-10-29)
These are historical captures of the original implementation, before upstream's later compact picker changes; they are not refreshed screenshots of this rebased head. Web, against a scripted fake
fx(Codex and Gateway signed in, Grok signed out).Before: the fx tab was a flat list of Default plus the models of the machine's active backend, with no way to switch backends.
Picker open, Grok signed out:
Switching backend: open Vercel AI Gateway from a thread on Codex:
The same thread ran one turn on Codex and the next on the gateway (the fake echoes the backend and model the session ran on):
Search across backends:
There is no before screenshot or interaction recording in the prior evidence. Mobile has no device capture: the remote iOS simulators were either owned by other sessions or stuck on the dev client's "Open in" prompt. The mobile grouping is covered by a unit test and typecheck only.
Prior validation
Original implementation attribution: Claude Opus 5.5 in Claude Code. This revival and rebase used GPT-6.1 Sol through Codex.
5a4461a033b56a3b866e6a6d9bfb14e593ad3e6a. CI run 40894823238 completed successfully on that head; this is prior CI, not a result for the rebased head.FX_PROVIDER/FX_MODEL, a custom endpoint, and a per-folder model. Those probes were not rerun during revival.check:changedreport noted unrelated macOS/varversus/private/varfailures inServerEnvironment.test.tsandbuild-npm-launcher.test.ts. Current results are listed separately below.Current validation
ac8dce0cc3abd8a337f2d806b5082a6834b9b81a.vp test run packages/provider-fx/src/server/status.test.ts apps/server/src/orchestration-v2/Adapters/FxAdapterV2.test.ts apps/mobile/src/lib/modelOptions.test.ts: 43 tests passed across three files. Covers per-backend catalogs/auth, unreadable-sign-in fallback, folder-aware defaults, provider-before-model writes, same-session backend switching, loaded-session Default reset, and grouping with a signed-out backend. The upstream six-second/hung-version probe cases are preserved using TestClock.vp run check:changed upstream/main --concurrency 2: passed. Format, lint, unused patches, both knip passes, GraphQL generation, 39 selected package typechecks, 54 tests in seven adjacent files, and nine selected React Compiler cases for four changed client files passed. CI still owns the full suites, builds, Rust, and release smoke.git diff --check: passed.GPT-6.1 Sol through Codex.