SIGN IN SIGN UP

fix(models): keep a restricted model visible and name it in the runtime error (#14697)

* fix(models): keep a restricted model visible and name it in the runtime error

A model that an administrator restricted after it was selected (hidden by
the model allowlist, or its whole provider revoked) disappeared from the
builder's seat: the Language Model field read "Select a model" — or showed
the first model of some other provider — and, with other models enabled,
the auto-select silently swapped the saved value for one of them. Running
the flow then surfaced `ModelProviderPolicyError Code: policy_blocked`,
the Python class name and a reason code, with nothing about what was
blocked or who to ask (LE-1960; Enterprise QA BUG-02 / BUG-03).

Frontend (ModelInput):
- New `isSavedModelUnavailable` helper tells "restricted / no longer
  offered" apart from "not enabled locally" and "deactivated": the saved
  provider is absent from /models entirely, or it is configured but neither
  its catalog nor the user's enabled-models map knows the model. Nothing is
  judged until both server views have settled.
- `deriveSelectedModel` keeps naming the saved model and flags it
  `unavailable` instead of falling back to flatOptions[0]; the trigger
  renders a "Not available" marker with an explanation aligned with the
  runtime error. The backend-injected `not_enabled_locally` tag is dropped
  on that branch so the configure wrench (which has nothing to configure)
  does not render.
- `useAutoSelectModel` no longer replaces a restricted model; lifting the
  restriction restores the saved selection. Disconnected providers and
  locally deactivated models keep their existing swap behaviour.

Backend (lfx):
- `ModelProviderPolicyError` names the blocked model and provider and tells
  the builder to ask an administrator. The provider-level message is
  unchanged.
- `ErrorMessage` renders the human message of a reason-coded exception
  (message + code) instead of the class name and `Code: …` alone; coded
  exceptions without a message keep the previous rendering.

* fix(models): treat a settled empty provider list as "not offered" and keep an unavailable model over the setup CTA

CodeRabbit on #14697: a settled, empty /models response is a verdict (no
provider is offered to this user — an Enterprise install that starts
closed), not a still-loading gap, so a saved model is unavailable there
like any other missing provider; and the trigger's "Setup Provider" branch
must not replace a selected-but-unavailable model, which would hide both
the saved selection and the reason it cannot be used (the popover footer
still offers provider management).
E
Eric Hare committed
12efda24446d8dc7e820aaa9e1b2cd038ff008e2
Parent: 4f3b9f3
Committed by GitHub <noreply@github.com> on 8/21/2026, 4:28:01 PM