authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-08-18 21:17:12-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-18 18:17:12-07:00
loge7f6a30caba5c390d5bbc9c300de89b68601c057
tree302e30d16477f6d0979f397bdc75bdcafe0dabbc
parentfe281c5408164250da6688de6fc71ac12d8a9d8f
signature Signed by PGP key B5690EEEBB952194

fix(server): stop probing Grok, Cursor, and OpenCode unless turned on (#7459)

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

12 files changed, 294 insertions(+), 31 deletions(-)

apps/server/src/provider/Layers/GrokProvider.test.ts+11-1
......@@ -23,9 +23,19 @@ describe("buildInitialGrokProviderSnapshot", () => {
2323 }),
2424 );
2525
26 it.effect("returns a pending snapshot by default", () =>
26 it.effect("returns a disabled snapshot by default — Grok is opt-in", () =>
2727 Effect.gen(function* () {
2828 const snapshot = yield* buildInitialGrokProviderSnapshot(decodeGrokSettings({}));
29 expect(snapshot.enabled).toBe(false);
30 expect(snapshot.status).toBe("disabled");
31 }),
32 );
33
34 it.effect("returns a pending snapshot when enabled", () =>
35 Effect.gen(function* () {
36 const snapshot = yield* buildInitialGrokProviderSnapshot(
37 decodeGrokSettings({ enabled: true }),
38 );
2939 expect(snapshot.enabled).toBe(true);
3040 expect(snapshot.installed).toBe(true);
3141 expect(snapshot.status).toBe("warning");
apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts+26
......@@ -223,6 +223,32 @@ describe("ProviderInstanceRegistryLive — multi-instance codex slice", () => {
223223 }).pipe(Effect.provide(testLayer)),
224224 );
225225
226 it.live("treats an explicit in-config enabled:false as disabling despite the envelope", () =>
227 Effect.gen(function* () {
228 // Old settings files can carry both flags with conflicting values.
229 // The explicit false must win so a user's disable is never undone.
230 const staleId = ProviderInstanceId.make("codex_stale");
231 const configMap: ProviderInstanceConfigMap = {
232 [staleId]: {
233 driver: ProviderDriverKind.make("codex"),
234 enabled: true,
235 config: makeCodexConfig({ enabled: false }),
236 },
237 };
238
239 const { registry } = yield* makeProviderInstanceRegistry({
240 drivers: [CodexDriver],
241 configMap,
242 });
243
244 const instance = yield* registry.getInstance(staleId);
245 expect(instance).toBeDefined();
246 expect(instance!.enabled).toBe(false);
247 const snapshot = yield* instance!.snapshot.getSnapshot;
248 expect(snapshot.enabled).toBe(false);
249 }).pipe(Effect.provide(testLayer)),
250 );
251
226252 it.live(
227253 "shadows instances whose driver is not registered in this build without failing boot",
228254 () =>
apps/server/src/provider/Layers/ProviderInstanceRegistryLive.ts+15-6
......@@ -34,6 +34,7 @@
3434 */
3535import {
3636 defaultInstanceIdForDriver,
37 providerInstanceConfigEnabledFlag,
3738 ProviderInstanceId,
3839 type ProviderInstanceConfig,
3940 type ProviderInstanceConfigMap,
......@@ -93,12 +94,20 @@ interface RegistryState {
9394const entryEqual = (a: ProviderInstanceConfig, b: ProviderInstanceConfig): boolean =>
9495 Equal.equals(a, b);
9596
96const decodedConfigEnabled = (config: unknown): boolean | undefined => {
97 if (!config || typeof config !== "object" || globalThis.Array.isArray(config)) {
98 return undefined;
97/**
98 * Resolve an entry's enabled state. An explicit false on either the
99 * envelope or the raw config blob wins (most restrictive) — old settings
100 * files can carry both flags with conflicting values, and a user's disable
101 * must never be silently undone. Otherwise the envelope flag wins, then the
102 * decoded config's flag (which carries the driver schema's default for
103 * built-ins and forks alike), then enabled by default.
104 */
105const resolveEntryEnabled = (entry: ProviderInstanceConfig, typedConfig: unknown): boolean => {
106 const rawConfigEnabled = providerInstanceConfigEnabledFlag(entry.config);
107 if (entry.enabled === false || rawConfigEnabled === false) {
108 return false;
99109 }
100 const enabled = (config as { readonly enabled?: unknown }).enabled;
101 return typeof enabled === "boolean" ? enabled : undefined;
110 return entry.enabled ?? providerInstanceConfigEnabledFlag(typedConfig) ?? true;
102111};
103112
104113/**
......@@ -171,7 +180,7 @@ const buildEntry = <R>(input: {
171180 displayName: entry.displayName,
172181 accentColor: entry.accentColor,
173182 environment: entry.environment ?? [],
174 enabled: entry.enabled ?? decodedConfigEnabled(typedConfig) ?? true,
183 enabled: resolveEntryEnabled(entry, typedConfig),
175184 config: typedConfig,
176185 })
177186 .pipe(Effect.provideService(Scope.Scope, childScope), Effect.result);
apps/server/src/serverSettings.test.ts+61-1
......@@ -487,6 +487,65 @@ it.layer(NodeServices.layer)("server settings", (it) => {
487487 }).pipe(Effect.provide(makeServerSettingsLayer())),
488488 );
489489
490 it.effect("folds a legacy in-config enabled flag into the envelope on load", () =>
491 Effect.gen(function* () {
492 const serverConfig = yield* ServerConfig.ServerConfig;
493 const fileSystem = yield* FileSystem.FileSystem;
494 const serverSettings = yield* ServerSettingsModule.ServerSettingsService;
495 // Old settings files can carry both flags with conflicting values.
496 // The explicit false must win so a user's disable sticks.
497 yield* fileSystem.writeFileString(
498 serverConfig.settingsPath,
499 '{"providerInstances":{"grok":{"driver":"grok","enabled":true,"config":{"enabled":false}},"codex_work":{"driver":"codex","config":{"enabled":true,"homePath":"~/.codex"}},"cursor":{"driver":"cursor","config":{"enabled":"nope"}}}}',
500 );
501
502 const settings = yield* serverSettings.getSettings;
503
504 const grokId = ProviderInstanceId.make("grok");
505 const codexWorkId = ProviderInstanceId.make("codex_work");
506 assert.deepEqual(settings.providerInstances[grokId], {
507 driver: ProviderDriverKind.make("grok"),
508 enabled: false,
509 config: {},
510 });
511 // A lone in-config flag is lifted to the envelope and stripped.
512 assert.deepEqual(settings.providerInstances[codexWorkId], {
513 driver: ProviderDriverKind.make("codex"),
514 enabled: true,
515 config: { homePath: "~/.codex" },
516 });
517 // A malformed flag is left alone so driver schema validation can
518 // surface it instead of the fold silently repairing the config.
519 assert.deepEqual(settings.providerInstances[ProviderInstanceId.make("cursor")], {
520 driver: ProviderDriverKind.make("cursor"),
521 config: { enabled: "nope" },
522 });
523 }).pipe(Effect.provide(makeServerSettingsLayer())),
524 );
525
526 it.effect("folds in-config enabled flags arriving through updates", () =>
527 Effect.gen(function* () {
528 const serverSettings = yield* ServerSettingsModule.ServerSettingsService;
529 const grokId = ProviderInstanceId.make("grok");
530
531 const next = yield* serverSettings.updateSettings({
532 providerInstances: {
533 [grokId]: {
534 driver: ProviderDriverKind.make("grok"),
535 enabled: true,
536 config: { enabled: false, binaryPath: "/opt/grok" },
537 },
538 },
539 });
540
541 assert.deepEqual(next.providerInstances[grokId], {
542 driver: ProviderDriverKind.make("grok"),
543 enabled: false,
544 config: { binaryPath: "/opt/grok" },
545 });
546 }).pipe(Effect.provide(makeServerSettingsLayer())),
547 );
548
490549 it.effect("trims provider path settings when updates are applied", () =>
491550 Effect.gen(function* () {
492551 const serverSettings = yield* ServerSettingsModule.ServerSettingsService;
......@@ -524,7 +583,8 @@ it.layer(NodeServices.layer)("server settings", (it) => {
524583 launchArgs: "",
525584 });
526585 assert.deepEqual(next.providers.opencode, {
527 enabled: true,
586 // OpenCode is disabled by default; this update only touches paths.
587 enabled: false,
528588 binaryPath: "/opt/homebrew/bin/opencode",
529589 serverUrl: "http://127.0.0.1:4096",
530590 serverPassword: "secret-password",
apps/server/src/serverSettings.ts+50-1
......@@ -61,11 +61,60 @@ const decodeServerSettings = Schema.decodeUnknownEffect(ServerSettings);
6161const textEncoder = new TextEncoder();
6262const textDecoder = new TextDecoder();
6363
64/**
65 * Fold the legacy in-config `enabled` flag into the envelope-level
66 * `ProviderInstanceConfig.enabled` and strip it from the config blob, so
67 * explicit provider instances carry exactly one enabled flag. Old settings
68 * files can hold both flags with conflicting values; an explicit false on
69 * either side wins so a user's disable is never silently undone. Runs on
70 * every load and update — the file converges on the next write.
71 */
72const foldProviderInstanceEnabledFlags = (settings: ServerSettings): ServerSettings => {
73 let changed = false;
74 const providerInstances: Record<string, ProviderInstanceConfig> = {};
75 for (const [instanceId, instance] of Object.entries(settings.providerInstances)) {
76 const config = instance.config;
77 // Only fold boolean flags: a malformed `enabled` (e.g. `"false"`) must
78 // stay in the blob so driver schema validation flags it instead of the
79 // fold silently repairing the config.
80 if (
81 config === null ||
82 typeof config !== "object" ||
83 Array.isArray(config) ||
84 typeof (config as { readonly enabled?: unknown }).enabled !== "boolean"
85 ) {
86 providerInstances[instanceId] = instance;
87 continue;
88 }
89 const { enabled: configEnabled, ...restConfig } = config as Record<string, unknown> & {
90 readonly enabled: boolean;
91 };
92 const resolved =
93 instance.enabled === false || configEnabled === false
94 ? false
95 : (instance.enabled ?? configEnabled);
96 changed = true;
97 providerInstances[instanceId] = {
98 ...instance,
99 enabled: resolved,
100 config: restConfig,
101 } satisfies ProviderInstanceConfig;
102 }
103 if (!changed) {
104 return settings;
105 }
106 return {
107 ...settings,
108 providerInstances: providerInstances as ServerSettings["providerInstances"],
109 };
110};
111
64112const normalizeServerSettings = (
65113 settings: ServerSettings,
66114): Effect.Effect<ServerSettings, ServerSettingsError> =>
67115 encodeServerSettings(settings).pipe(
68116 Effect.flatMap(decodeServerSettings),
117 Effect.map(foldProviderInstanceEnabledFlags),
69118 Effect.mapError(
70119 (cause) =>
71120 new ServerSettingsError({
......@@ -303,7 +352,7 @@ const make = Effect.gen(function* () {
303352 });
304353 return DEFAULT_SERVER_SETTINGS;
305354 }
306 return decoded.value;
355 return foldProviderInstanceEnabledFlags(decoded.value);
307356 });
308357
309358 const settingsCache = yield* Cache.make<typeof cacheKey, ServerSettings, ServerSettingsError>({
apps/web/src/components/settings/ProviderInstanceCard.tsx+6-7
......@@ -15,6 +15,7 @@ import * as Result from "effect/Result";
1515import { useState, type ReactNode } from "react";
1616import {
1717 isProviderDriverKind,
18 resolveProviderInstanceEnabled,
1819 type ProviderInstanceConfig,
1920 type ProviderInstanceEnvironmentVariable,
2021 type ProviderInstanceId,
......@@ -368,12 +369,10 @@ interface ProviderInstanceCardProps {
368369 * notice instead of editable fields, so fork instances round-trip
369370 * without accidentally destroying their config.
370371 * - The enabled Switch writes to the envelope's `instance.enabled`
371 * field; the server's registry consults this at `entry.enabled ?? true`
372 * before materializing the instance, and the probe also checks its
373 * driver-specific `config.enabled`. We treat the envelope flag as the
374 * single source of truth from the UI — built-in cards used to write
375 * the inner flag, but on the promotion-to-instance path every edit
376 * flows through the envelope.
372 * field, which is the single enabled flag: the server folds any legacy
373 * driver-specific `config.enabled` into the envelope on load and both
374 * sides resolve through `resolveProviderInstanceEnabled` (an explicit
375 * false wins, then envelope, then config, then the driver default).
377376 */
378377export function ProviderInstanceCard({
379378 instanceId,
......@@ -394,7 +393,7 @@ export function ProviderInstanceCard({
394393 onRunUpdate,
395394 isUpdating = false,
396395}: ProviderInstanceCardProps) {
397 const enabled = instance.enabled ?? true;
396 const enabled = resolveProviderInstanceEnabled(instance);
398397 // The server-reported status wins when present; otherwise fall back to
399398 // "disabled"/"warning" based on the local `enabled` flag so the dot
400399 // reflects the persisted intent even before the first probe completes.
apps/web/src/components/settings/ProviderSettingsPanel.tsx+18-9
......@@ -12,6 +12,7 @@ import {
1212 ProviderDriverKind,
1313 type ProviderInstanceConfig,
1414 type ProviderInstanceId,
15 resolveProviderInstanceEnabled,
1516} from "@t3tools/contracts";
1617import { DEFAULT_UNIFIED_SETTINGS } from "@t3tools/contracts/settings";
1718import {
......@@ -529,15 +530,23 @@ export function EnvironmentProviderSettings({
529530 // instance or a legacy blob there is nothing to render for the slot.
530531 const legacyConfig = legacyProviders[providerSettings.provider];
531532 const defaultLegacyConfig = defaultLegacyProviders[providerSettings.provider];
533 // The envelope is the single enabled flag: keep the legacy in-config
534 // flag out of the synthesized blob, or an explicit `enabled: false`
535 // would keep winning over the envelope and the Switch could never
536 // turn a default-off provider on.
537 const synthesizedInstance = (): ProviderInstanceConfig | undefined => {
538 if (legacyConfig === undefined) {
539 return undefined;
540 }
541 const { enabled: legacyEnabled, ...legacyConfigRest } = legacyConfig;
542 return {
543 driver,
544 enabled: legacyEnabled,
545 config: legacyConfigRest,
546 } satisfies ProviderInstanceConfig;
547 };
532548 const effectiveInstance: ProviderInstanceConfig | undefined =
533 explicitInstance ??
534 (legacyConfig !== undefined
535 ? ({
536 driver,
537 enabled: legacyConfig.enabled,
538 config: legacyConfig,
539 } satisfies ProviderInstanceConfig)
540 : undefined);
549 explicitInstance ?? synthesizedInstance();
541550 // Only the default slot depends on the legacy blob; custom instances for
542551 // the driver must still render even when the slot has nothing to show.
543552 if (effectiveInstance !== undefined) {
......@@ -838,7 +847,7 @@ export function EnvironmentProviderSettings({
838847 }))
839848 }
840849 onUpdate={(next) => {
841 const wasEnabled = row.instance.enabled ?? true;
850 const wasEnabled = resolveProviderInstanceEnabled(row.instance);
842851 const isDisabling = next.enabled === false && wasEnabled;
843852 const shouldClearTextGen = isDisabling && textGenInstanceId === row.instanceId;
844853 if (shouldClearTextGen) {
apps/web/src/providerInstances.ts+2-1
......@@ -16,6 +16,7 @@ import {
1616 DEFAULT_MODEL_BY_PROVIDER,
1717 defaultInstanceIdForDriver,
1818 PROVIDER_DISPLAY_NAMES,
19 resolveProviderInstanceEnabled,
1920 type ModelSelection,
2021 type ProviderDriverKind,
2122 ProviderInstanceId,
......@@ -220,7 +221,7 @@ export function applyProviderInstanceSettings(
220221 return entries.map((entry) => {
221222 const explicitInstance = settings.providerInstances?.[entry.instanceId];
222223 const enabled = explicitInstance
223 ? (explicitInstance.enabled ?? true)
224 ? resolveProviderInstanceEnabled(explicitInstance)
224225 : entry.isDefault
225226 ? (legacyProviders[entry.driverKind]?.enabled ?? entry.enabled)
226227 : false;
docs/user/install.md+3
......@@ -62,6 +62,9 @@ to use, then authenticate it.
6262| Grok Build | [Grok Build CLI](https://x.ai/cli) | `grok` | `grok login` |
6363| OpenCode | [OpenCode](https://opencode.ai) | `opencode` | `opencode auth login` |
6464
65Codex and Claude are on by default. Cursor, Grok Build, and OpenCode are off by default; turn
66them on in **Settings** → the provider's card when you want to use them.
67
6568Cursor is the one to watch: install Cursor CLI, which provides the `cursor-agent` binary that
6669T3 Code looks for, but authenticate with `agent login`, not `cursor-agent login`.
6770
packages/contracts/src/settings.test.ts+43-1
......@@ -1,11 +1,13 @@
11import { describe, expect, it } from "vite-plus/test";
22import * as Schema from "effect/Schema";
33
4import { ProviderInstanceId } from "./providerInstance.ts";
4import { ProviderDriverKind, ProviderInstanceId } from "./providerInstance.ts";
55import {
66 ClientSettingsSchema,
77 ClientSettingsPatch,
88 DEFAULT_SERVER_SETTINGS,
9 defaultEnabledForDriver,
10 resolveProviderInstanceEnabled,
911 ServerSettings,
1012 ServerSettingsPatch,
1113} from "./settings.ts";
......@@ -177,6 +179,46 @@ describe("ServerSettings.providerInstances (slice-2 invariant)", () => {
177179 });
178180});
179181
182describe("provider enabled defaults", () => {
183 it("enables only the stable bindings by default", () => {
184 const decoded = decodeServerSettings({});
185 expect(decoded.providers.codex.enabled).toBe(true);
186 expect(decoded.providers.claudeAgent.enabled).toBe(true);
187 expect(decoded.providers.cursor.enabled).toBe(false);
188 expect(decoded.providers.grok.enabled).toBe(false);
189 expect(decoded.providers.opencode.enabled).toBe(false);
190 });
191
192 it("derives per-driver defaults from the settings schemas", () => {
193 expect(defaultEnabledForDriver(ProviderDriverKind.make("codex"))).toBe(true);
194 expect(defaultEnabledForDriver(ProviderDriverKind.make("grok"))).toBe(false);
195 // Unknown fork drivers stay enabled; their own build decides otherwise.
196 expect(defaultEnabledForDriver(ProviderDriverKind.make("ollama"))).toBe(true);
197 });
198
199 it("resolves instance enabled state with explicit false winning", () => {
200 const grok = ProviderDriverKind.make("grok");
201 const codex = ProviderDriverKind.make("codex");
202 // No flags anywhere: driver default applies.
203 expect(resolveProviderInstanceEnabled({ driver: grok, config: {} })).toBe(false);
204 expect(resolveProviderInstanceEnabled({ driver: codex, config: {} })).toBe(true);
205 // Envelope flag wins over the driver default.
206 expect(resolveProviderInstanceEnabled({ driver: grok, enabled: true, config: {} })).toBe(true);
207 expect(resolveProviderInstanceEnabled({ driver: codex, enabled: false, config: {} })).toBe(
208 false,
209 );
210 // Legacy in-config flag fills in when the envelope is silent.
211 expect(resolveProviderInstanceEnabled({ driver: grok, config: { enabled: true } })).toBe(true);
212 // Conflicting flags: the explicit false wins, whichever side it is on.
213 expect(
214 resolveProviderInstanceEnabled({ driver: grok, enabled: true, config: { enabled: false } }),
215 ).toBe(false);
216 expect(
217 resolveProviderInstanceEnabled({ driver: codex, enabled: false, config: { enabled: true } }),
218 ).toBe(false);
219 });
220});
221
180222describe("ServerSettings worktree defaults", () => {
181223 it("defaults start-from-origin on for legacy configs", () => {
182224 expect(decodeServerSettings({}).newWorktreesStartFromOrigin).toBe(true);
packages/contracts/src/settings.ts+57-3
......@@ -18,7 +18,11 @@ import {
1818 PreviewViewportSetting,
1919 PreviewZoomFactor,
2020} from "./preview.ts";
21import { ProviderInstanceConfig, ProviderInstanceId } from "./providerInstance.ts";
21import {
22 ProviderInstanceConfig,
23 ProviderInstanceId,
24 type ProviderDriverKind,
25} from "./providerInstance.ts";
2226
2327// ── Client Settings (local-only) ───────────────────────────────
2428
......@@ -403,6 +407,8 @@ export type ClaudeSettings = typeof ClaudeSettings.Type;
403407
404408export const CursorSettings = makeProviderSettingsSchema(
405409 {
410 // Off by default (like Grok and OpenCode): the binding is not yet
411 // stable enough to probe on every install. Users opt in from Settings.
406412 enabled: Schema.Boolean.pipe(
407413 Schema.withDecodingDefault(Effect.succeed(false)),
408414 Schema.annotateKey({ providerSettingsForm: { hidden: true } }),
......@@ -438,8 +444,10 @@ export type CursorSettings = typeof CursorSettings.Type;
438444
439445export const GrokSettings = makeProviderSettingsSchema(
440446 {
447 // Off by default (like Cursor and OpenCode): the binding is not yet
448 // stable enough to probe on every install. Users opt in from Settings.
441449 enabled: Schema.Boolean.pipe(
442 Schema.withDecodingDefault(Effect.succeed(true)),
450 Schema.withDecodingDefault(Effect.succeed(false)),
443451 Schema.annotateKey({ providerSettingsForm: { hidden: true } }),
444452 ),
445453 binaryPath: makeBinaryPathSetting("grok").pipe(
......@@ -462,8 +470,10 @@ export type GrokSettings = typeof GrokSettings.Type;
462470
463471export const OpenCodeSettings = makeProviderSettingsSchema(
464472 {
473 // Off by default (like Cursor and Grok): the binding is not yet stable
474 // enough to probe on every install. Users opt in from Settings.
465475 enabled: Schema.Boolean.pipe(
466 Schema.withDecodingDefault(Effect.succeed(true)),
476 Schema.withDecodingDefault(Effect.succeed(false)),
467477 Schema.annotateKey({ providerSettingsForm: { hidden: true } }),
468478 ),
469479 binaryPath: makeBinaryPathSetting("opencode").pipe(
......@@ -667,6 +677,50 @@ export type ServerSettings = typeof ServerSettings.Type;
667677
668678export const DEFAULT_SERVER_SETTINGS: ServerSettings = Schema.decodeSync(ServerSettings)({});
669679
680/**
681 * Read the legacy `enabled` flag embedded in a provider instance config
682 * blob. The envelope-level `ProviderInstanceConfig.enabled` is the single
683 * flag going forward; this reader exists for legacy `providers.<kind>`
684 * blobs and old settings files that still carry the flag in-config.
685 */
686export const providerInstanceConfigEnabledFlag = (config: unknown): boolean | undefined => {
687 if (config === null || typeof config !== "object" || Array.isArray(config)) {
688 return undefined;
689 }
690 const enabled = (config as { readonly enabled?: unknown }).enabled;
691 return typeof enabled === "boolean" ? enabled : undefined;
692};
693
694/**
695 * Default enabled state for a built-in driver when neither the envelope nor
696 * the config blob carries a flag. Derived from the driver's settings schema
697 * through `DEFAULT_SERVER_SETTINGS`, so the schema's decoding default stays
698 * the single source of truth. Unknown (fork) drivers default to enabled.
699 */
700export const defaultEnabledForDriver = (driver: ProviderDriverKind): boolean => {
701 const legacyDefaults = DEFAULT_SERVER_SETTINGS.providers as Record<
702 string,
703 { readonly enabled?: boolean } | undefined
704 >;
705 return legacyDefaults[driver]?.enabled ?? true;
706};
707
708/**
709 * Resolve whether a configured provider instance is enabled. An explicit
710 * false on either the envelope or the in-config flag wins (most
711 * restrictive), so a user's disable is never silently undone by the other
712 * flag. Otherwise: envelope, then config, then the driver's default.
713 */
714export const resolveProviderInstanceEnabled = (
715 instance: Pick<ProviderInstanceConfig, "driver" | "enabled" | "config">,
716): boolean => {
717 const configEnabled = providerInstanceConfigEnabledFlag(instance.config);
718 if (instance.enabled === false || configEnabled === false) {
719 return false;
720 }
721 return instance.enabled ?? configEnabled ?? defaultEnabledForDriver(instance.driver);
722};
723
670724export const ServerSettingsOperation = Schema.Literals([
671725 "normalize",
672726 "check-exists",
packages/shared/src/serverSettings.ts+2-1
......@@ -1,6 +1,7 @@
11import {
22 isProviderDriverKind,
33 isProviderAvailable,
4 resolveProviderInstanceEnabled,
45 type ModelSelection,
56 type ProviderDriverKind,
67 type ServerProvider,
......@@ -36,7 +37,7 @@ export function isModelSelectionProviderEnabled(
3637): boolean {
3738 const instanceConfig = settings.providerInstances[selection.instanceId];
3839 if (instanceConfig !== undefined) {
39 return instanceConfig.enabled ?? true;
40 return resolveProviderInstanceEnabled(instanceConfig);
4041 }
4142
4243 return (