fix(providers): omit model field for local OpenAI-compatible servers with no configured model - #2808
Conversation
|
@alectimison-maker is attempting to deploy a commit to the esokullu's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Reviewed this together with #2809, #2813, #2814 and #2815. Five things, roughly in order of impact. 1. Local providers now send a body with no
|
22e6ab3 to
08732e3
Compare
… for LM Studio Local OpenAI-compatible servers reject an empty model field, so sending a fabricated fallback id (previously gpt-4o) or omitting the field both fail. Mark ollama, vLLM, SGLang, LocalAI, Jan, and GPT4All as requiresModel so an empty Model field fails with a clear error instead of an opaque server 400. LM Studio (like llama.cpp) applies its own default, so it omits the field when unset. Non-local providers keep their fallback.
08732e3 to
8cc6726
Compare
|
Reworked per review. The fabricated-fallback was the real bug, but omitting the field broke Ollama/SGLang/LocalAI/Jan/GPT4All (they require it) and left New approach: mark the local servers that require a model ( The branch was also cut from a different base that bundled the Azure change — I've rebased it onto |
webbrain-one
left a comment
There was a problem hiding this comment.
Blocking local-provider coverage gap remains. Every unset local provider must avoid the cloud-model fallback, including persisted configurations that do not inherit new catalog flags.
| // Local servers that reject an empty model instead carry | ||
| // `requiresModel: true` in the catalog and throw above, so no local | ||
| // server ever receives a fabricated model id. | ||
| if (this.config.category === 'local' |
There was a problem hiding this comment.
[P2] Handle every unset local provider before cloud fallback
This only special-cases LM Studio. An unset privatemode-ai configuration is also local but lacks requiresModel, and older persisted local entries can remain empty because ProviderManager.load() carries duplicates through without merging new defaults. Both paths fall through to gpt-4o, recreating the fabricated-model failure. Handle the entire local category explicitly (omitting the field or throwing when the provider requires a model), and ensure migrated/persisted entries inherit that contract. The Firefox mirror needs the same treatment.
Summary
model: "gpt-4o"when the Model field is empty.modelgetter returnsnullforcategory === "local"with no configured model, and Chat Completions / Responses request bodies omit the field entirely (mirroringLlamaCppProvider), letting the server apply its own default.gpt-4o, orgpt-5.6-terraon the official OpenAI base URL).Motivation
Every local provider defaults to an empty Model field (
manager.js_defaultConfigs). With the field empty, requests sentmodel: "gpt-4o"to the local server, which 404s with "model 'gpt-4o' not found, try pulling it first" (Ollama) or rejects the unknown id (LM Studio / vLLM / SGLang). Onboarding connection tests failed the same way. There was no UI or agent guard preventing it, and no way to tell the server "use your default".Design
Followed the existing
LlamaCppProviderprecedent (get model()returnsconfig.model || null; body setsmodelonly when truthy).ProviderManager._createProvideralways normalizesconfig.categoryviacategoryFor, sothis.config.category === "local"is reliable for all local ids. Non-local behavior is untouched and covered by tests.Testing
node test/run.js— 1767 passed, 0 failed (2 new tests, both Chrome and Firefox providers)npm run test:security— 60/60 passednpm run test:toolbar-guard— 33 passedNew tests assert: local providers with an empty model get
model === nulland nomodelkey in_buildChatCompletionsBody; a configured local model is still sent; non-local fallbacks (openrouter→gpt-4o, official OpenAI →gpt-5.6-terra) stay on the wire.Compatibility and risks
cloudkeep the legacy fallback (existing behavior, unchanged).modelconsumers in the agent (traces, cost estimation) already useconfig.modelfallbacks orconfig-driven pricing, so anullprovider model is safe;shouldUseOpenAIResponsesApishort-circuits for non-official configs.Scope