Steps to reproduce
- Click the model button in the bottom toolbar, go to model configuration.
- Select OpenAI API compatible endpoint.
- Fill in a base URL (reported against
https://openrouter.ai/api/v1/) and an API key.
- The endpoint's models are discovered and populate the dropdown.
- Pick one, save the config, close Preferences.
- Send a prompt. (In the reporter's case it failed with a provider-side 404 about
guardrail/data-policy restrictions -- expected for their key, and not the bug.)
- Reopen the model picker.
Observed: only the previously selected model is in the dropdown. Every other
discovered model is gone.
Recovery the tester found: delete the model and API key from config.json
by hand, reopen the config, paste the API key again -- the dropdown repopulates.
Expected: the list persists, or is re-fetched when the dropdown is opened.
The tester also suggested an explicit "fetch available models" button.
Cause
Discovery only ever runs from wireApiKeyValidation in
app/src/renderer/app.ts. That helper is wired to input on the API-key and
base-URL fields and change on the provider dropdown, and its validateNow()
returns early when the key field is empty:
const key = keyEl.value.trim();
if (!key) { setStatus("", ""); return; }
When Preferences reopens, loadProviderFields() deliberately does not
refill the key -- the stored credential lives in the main process, and the
renderer only knows hadKey:
prefsApiKey.value = state.typedKey; // "" for a saved-but-not-retyped key
prefsApiKey.placeholder = state.hadKey ? "leave blank to keep existing key" : "";
So no input event fires, validateNow() early-returns, no /models call
happens, and the dropdown falls back to populateModels(). For
openai-compatible the static catalog is empty:
which leaves exactly one entry -- the saved model, appended by the
(custom) fallback branch at the bottom of populateModels(). That is precisely
the reported symptom, and it also explains the workaround: retyping the key fires
input, which re-runs discovery.
Discovered models are never persisted either, so nothing survives a restart.
Notes on a fix
The renderer can't just re-run the existing call on open -- it doesn't have the
key. Either:
- add a main-process path that re-probes
/models using the stored credential
(main already reads it via secure-config), triggered on Preferences open
and/or by an explicit refresh button; or
- persist the discovered id list alongside the provider config and seed
MODELS_BY_PROVIDER["openai-compatible"] from it, re-probing in the background.
The second is cheaper; the first is more correct when the endpoint's catalog
changes. A refresh button (the tester's suggestion) is worth having either way,
since a failed probe currently leaves no way to retry without editing the key.
Related: #236 proposes deriving the picker from live /models for all
providers, which subsumes this. This issue is the narrow bug that's biting the
openai-compatible path today.
Suggested test
With a saved openai-compatible provider (stored key, no retyping), open
Preferences and assert the model dropdown contains more than just the saved
model.
Steps to reproduce
https://openrouter.ai/api/v1/) and an API key.guardrail/data-policy restrictions -- expected for their key, and not the bug.)
Observed: only the previously selected model is in the dropdown. Every other
discovered model is gone.
Recovery the tester found: delete the model and API key from
config.jsonby hand, reopen the config, paste the API key again -- the dropdown repopulates.
Expected: the list persists, or is re-fetched when the dropdown is opened.
The tester also suggested an explicit "fetch available models" button.
Cause
Discovery only ever runs from
wireApiKeyValidationinapp/src/renderer/app.ts. That helper is wired toinputon the API-key andbase-URL fields and
changeon the provider dropdown, and itsvalidateNow()returns early when the key field is empty:
When Preferences reopens,
loadProviderFields()deliberately does notrefill the key -- the stored credential lives in the main process, and the
renderer only knows
hadKey:So no
inputevent fires,validateNow()early-returns, no/modelscallhappens, and the dropdown falls back to
populateModels(). Foropenai-compatiblethe static catalog is empty:which leaves exactly one entry -- the saved model, appended by the
(custom)fallback branch at the bottom ofpopulateModels(). That is preciselythe reported symptom, and it also explains the workaround: retyping the key fires
input, which re-runs discovery.Discovered models are never persisted either, so nothing survives a restart.
Notes on a fix
The renderer can't just re-run the existing call on open -- it doesn't have the
key. Either:
/modelsusing the stored credential(main already reads it via
secure-config), triggered on Preferences openand/or by an explicit refresh button; or
MODELS_BY_PROVIDER["openai-compatible"]from it, re-probing in the background.The second is cheaper; the first is more correct when the endpoint's catalog
changes. A refresh button (the tester's suggestion) is worth having either way,
since a failed probe currently leaves no way to retry without editing the key.
Related: #236 proposes deriving the picker from live
/modelsfor allproviders, which subsumes this. This issue is the narrow bug that's biting the
openai-compatible path today.
Suggested test
With a saved openai-compatible provider (stored key, no retyping), open
Preferences and assert the model dropdown contains more than just the saved
model.