Two things in the copilot both used to hinge on the same wrong check,
isInternalProvider(provider) - a plain string comparison - instead of
what the backend's /llm/providers catalog already publishes:
- providerNeedsCredential decided whether to show the credential picker
by name, so a credential-free provider under any name other than
"InternalOllama" - a remote Ollama with no key, say - was told it
needed a credential anyway. It now reads requiresCredential from the
catalog.
- The "Add credential" dialog had no endpoint field at all. It now
shows one, built the same way llm-descriptor-settings.ts already
rebuilds its model field when the provider changes: onValuesChange
recomputes the field list from the current draft, so choosing a
provider that requiresEndpoint adds the field, and choosing one back
away removes it, without closing the dialog.
Both read the same LlmProviderService the execution viewer already uses,
loaded once and cached in llmProviderCapabilities. It has to be loaded
eagerly now, not only when the dialog opens: providerNeedsCredential is a
computed() signal that gates whether the configuration is valid to save,
so it cannot wait for a promise nothing has awaited yet. Bootstrap now
kicks that load off in the background; the dialog's own lazy load stays
too, in case bootstrap has not resolved by the time it opens.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>