authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-09-06 02:56:28-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-06 02:56:28-07:00
log62f568b88b58e1e7cf422c21ee2e08f10977b714
treefa5776a23aa6a8a1dd0183cfc897893a0c79e6fc
parenteb8ed80300bd719b49fc80ad8708f9839bb48c92
signature Signed by PGP key B5690EEEBB952194

fix(server): skip disabled provider instances for text generation fallback (#10346)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>

2 files changed, 26 insertions(+), 1 deletions(-)

apps/server/src/serverSettings.test.ts+18
......@@ -656,6 +656,24 @@ it.layer(NodeServices.layer)("server settings", (it) => {
656656 }).pipe(Effect.provide(makeServerSettingsLayer())),
657657 );
658658
659 it.effect("skips a disabled provider instance when picking the text generation fallback", () =>
660 Effect.gen(function* () {
661 const serverConfig = yield* ServerConfig.ServerConfig;
662 const fileSystem = yield* FileSystem.FileSystem;
663 const serverSettings = yield* ServerSettingsModule.ServerSettingsService;
664 // The Providers UI writes providerInstances only, so the legacy providers
665 // map decodes to defaults where codex is enabled and listed first.
666 yield* fileSystem.writeFileString(
667 serverConfig.settingsPath,
668 '{"providerInstances":{"codex":{"driver":"codex","enabled":false,"config":{}}}}',
669 );
670
671 const settings = yield* serverSettings.getSettings;
672
673 assert.equal(settings.textGenerationModelSelection.instanceId, "claudeAgent");
674 }).pipe(Effect.provide(makeServerSettingsLayer())),
675 );
676
659677 it.effect("keeps unused providers disabled in existing sparse settings files", () =>
660678 Effect.gen(function* () {
661679 const serverConfig = yield* ServerConfig.ServerConfig;
apps/server/src/serverSettings.ts+8-1
......@@ -21,6 +21,7 @@ import {
2121 type UsageLimitSourceConfig,
2222 ProviderDriverKind,
2323 ProviderInstanceId,
24 resolveProviderInstanceEnabled,
2425 ServerSettings,
2526 ServerSettingsError,
2627 type ServerSettingsPatch,
......@@ -321,7 +322,13 @@ function resolveTextGenerationProvider(settings: ServerSettings): ServerSettings
321322}
322323
323324function fallbackTextGenerationProvider(settings: ServerSettings): ServerSettings {
324 const fallbackEntry = Object.entries(settings.providers).find(([, provider]) => provider.enabled);
325 // Same precedence as isModelSelectionProviderEnabled: an explicit provider
326 // instance wins over the legacy providers map, which decodes to defaults
327 // (codex enabled) when the Providers UI has only written providerInstances.
328 const fallbackEntry = Object.entries(settings.providers).find(([driver, provider]) => {
329 const instance = settings.providerInstances[ProviderInstanceId.make(driver)];
330 return instance === undefined ? provider.enabled : resolveProviderInstanceEnabled(instance);
331 });
325332 const fallback = fallbackEntry ? ProviderDriverKind.make(fallbackEntry[0]) : undefined;
326333 if (!fallback) {
327334 return settings;