Skip to content

fix(providers): don’t pick a provider just because its key is in the env - #3487

Open
meowgorithm wants to merge 3 commits into
mainfrom
undefault
Open

fix(providers): don’t pick a provider just because its key is in the env#3487
meowgorithm wants to merge 3 commits into
mainfrom
undefault

Conversation

@meowgorithm

@meowgorithm meowgorithm commented Aug 2, 2026

Copy link
Copy Markdown
Member

This fix keeps the model picker from defaulting to the first known provider it can find an find an env var for, which was usually Anthropic. This meant a couple things:

  1. If there was an error fetching the provider on startup it would pick the default model from the the first provider it had an env var for.
  2. The onboarding model picker would choose a model from the middle of the list, again usually Anthropic.

Generated notes below.


Crush would auto-select a provider based on whichever credentials happened to be sitting in your environment, walking the provider list in a fixed order — so in practice a lot of people silently ended up on Anthropic. Worse, that guess was written to your global config, so it looked like a choice you had made and it stuck.

The same code path also fired whenever a saved selection stopped resolving (provider temporarily missing an API key, a model retired from the catalog, an expired token, a bad network moment). A transient failure would therefore permanently rewrite your saved model.

What changed

  • Nothing is guessed. A model selection that is missing or no longer resolvable is dropped instead of being replaced.
  • Nothing is persisted. Startup no longer writes a corrected selection to your config, so a transient failure can't permanently change your setup. Your file is left exactly as you wrote it.
  • You get the picker instead. With no usable model, the TUI opens the model list scrolled to the top, whether that's because no provider is configured or because a provider is configured but you've never chosen a model. That's the common first-run path for anyone with an API key exported.
  • Scripts keep working. crush run and other non-interactive entry points can't prompt, so they fall back to the first available model. That fallback lives in memory only and is never saved.

Credential discovery from the environment is unchanged — that's still how providers become available. The only thing that goes away is treating "has credentials" as "user picked this".

Configs that name a model without naming a provider (models.large.model with no provider) still work: the model is matched against the providers that offer it, in a stable order.

Note

A related bug is fixed separately in #3486: a failed provider-cache write could remove Hyper from the catalog, which is the most common way a saved selection became unresolvable in the first place. These two are independent and can land in either order, but this PR is the one that makes the damage non-permanent.

💘 Generated with Crush

@meowgorithm
meowgorithm force-pushed the undefault branch 3 times, most recently from 331bbad to 26f062e Compare August 2, 2026 20:20
@meowgorithm meowgorithm changed the title fix: no longer pick a provider just because its key is in the env fix(providers): no longer pick a provider just because its key is in the env Aug 2, 2026
@meowgorithm meowgorithm changed the title fix(providers): no longer pick a provider just because its key is in the env fix(providers): don’t pick a provider just because its key is in the env Aug 2, 2026
Crush used to auto-select the first provider whose credentials happened
to be present in the environment (alphabetical-ish order, so usually
Anthropic) and persist that choice, making it look like the user had
picked it. Now an unset or stale model selection is left empty and the
model picker opens on the top of the list instead. Non-interactive runs,
which cannot prompt, fall back to the first available model without
saving it.

💘 Generated with Crush
With no model chosen yet, the model list opened with the highlight on a
provider heading rather than on a model, so the first Enter did nothing.
Now the first selectable model is highlighted.

💘 Generated with Crush
The model picker pruned the stored list of recently used models down to
whatever providers were resolvable at that moment, and saved the result.
Since a provider configured through an environment variable is only
visible when Crush is launched from a shell that exported it, opening the
picker could permanently drop history for providers that were merely
temporarily absent. Unresolvable entries are now skipped when drawing the
list and left in the config.

💘 Generated with Crush
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant