AI Provider Configuration#
AI Provider Configuration covers how users connect LobeHub to AI backends (API keys, base URLs, authentication type, model fetching options). The feature spans a Zustand store slice that manages server-fetched provider data and a React form component that lets users edit credentials and toggle behavioral flags.
Key entry points:
| Layer | Path |
|---|---|
| Store slice (actions) | src/store/aiInfra/slices/aiProvider/action.ts |
| Store slice (initial state) | src/store/aiInfra/slices/aiProvider/initialState.ts |
| Store slice (selectors) | src/store/aiInfra/slices/aiProvider/selectors.ts |
| Config UI component | src/routes/(main)/settings/provider/features/ProviderConfig/index.tsx |
| Controlled inputs | src/components/FormInput/FormPassword.tsx , src/components/FormInput/FormInput.tsx |
Store Architecture#
State Shape#
The aiProvider slice holds two parallel caches for each provider :
aiProviderDetailMap—Record<string, AiProviderDetailItem>: provider metadata, keyVaults, and settings. Populated byuseFetchAiProviderItem.aiProviderRuntimeConfig—Record<string, AiProviderRuntimeConfig>: credential values and runtime flags used by selectors at inference time. Populated byuseFetchAiProviderRuntimeState.
Loading and mutation state are tracked as ID arrays rather than per-key booleans:
aiProviderLoadingIds— providers currently being fetched or toggledaiProviderConfigUpdatingIds— providers whose config is being saved
Selectors in aiProviderSelectors derive booleans from these arrays (e.g., isAiProviderConfigLoading, isProviderConfigUpdating).
SWR Data Fetching#
Three SWR keys are used :
FETCH_AI_PROVIDER— list of all providersFETCH_AI_PROVIDER_ITEM— detail for a single provider (keyed by provider ID)FETCH_AI_PROVIDER_RUNTIME_STATE— enabled providers, models, and per-provider runtime config (keyed by login status)
refreshAiProviderRuntimeState invalidates both the logged-in and logged-out variants simultaneously .
Optimistic Updates in updateAiProviderConfig#
When a config field changes, updateAiProviderConfig follows this sequence:
- Adds the provider ID to
aiProviderConfigUpdatingIds(loading indicator). - Calls
aiProviderService.updateAiProviderConfig(network request). - Immediately patches both
aiProviderDetailMapandaiProviderRuntimeConfigin local state for instant UI feedback — no waiting for SWR revalidation . - Calls
refreshAiProviderDetailto revalidate SWR caches. - Removes the provider ID from
aiProviderConfigUpdatingIds.
Runtime State Readiness Guard#
ensureAiProviderRuntimeStateReady races the runtime state fetch against a 3-second timeout. This is a no-op when already initialized, making it safe to call from anywhere before reading model capability data.
ProviderConfig Component#
ProviderConfig is the single form component rendered for every provider in the settings panel. It is memo-wrapped and driven entirely by the Zustand store.
Store Subscription#
The component subscribes to six store values in a single useAiInfraStore selector call :
| Selector | Used for |
|---|---|
providerDetailById(id) | Form initial data |
updateAiProviderConfig | Save action |
isProviderEnabled(id) | Visual state (greyscale header) |
isAiProviderConfigLoading(id) | Show skeletons |
isProviderConfigUpdating(id) | Show inline spinner on fields |
providerConfigById(id) | Runtime credentials (preferred over detail map) |
Form Initialization Lifecycle#
Form values are set via useLayoutEffect with a lastInitializedIdRef guard . The form only reinitializes when:
- The component first mounts (
lastInitializedIdRef.current === null), or - The provider ID changes (user navigates to a different provider).
This prevents the form from resetting mid-edit during background SWR refreshes. Data from providerRuntimeConfig is merged on top of data to ensure nested config fields like enableResponseApi are correctly seeded .
Debounced onChange and Connection-Test Guard#
Every form change calls debouncedHandleValueChange with a 500 ms debounce. A isCheckingConnection ref blocks dispatch while a connection test is in progress :
- Before test: the ref is set to
true; the latest form values are force-saved. - After test: the ref is reset to
false; normal debounced saves resume.
Conditional Field Visibility#
AntdForm.useWatch tracks six credential fields (baseURL, endpoint, apiKey, accessKeyId, secretAccessKey, username, password) in real time. The Client Fetch and Responses API switches are only rendered when the relevant fields are populated . This avoids showing advanced options before a user has entered credentials.
OAuth vs. Standard Providers#
When settings.authType === 'oauthDeviceFlow', the form is replaced by the OAuthDeviceFlowAuth component and only shown again once the OAuth status query returns ACTIVE .
Permission Gating#
usePermission('manage_provider_key') gates the form's disabled prop . Non-permitted users can view but not edit provider credentials.
Controlled Input Components#
FormPassword and FormInput are thin wrappers over @lobehub/ui inputs that implement a buffer-then-flush pattern:
- Internal state holds the in-progress value without triggering
onChangeon every keystroke. onChangefires only on blur or Enter key press, reducing the number of debounced config saves.- Both components use a
useIMECompositionEventhook to suppress onChange during IME composition (CJK input), preventing partial character sequences from being saved as credentials. FormPasswordsetsautoComplete="new-password"to prevent browser autofill from overwriting API keys with saved login passwords .
These are the only input components used inside the API key and base URL form items in ProviderConfig.
Key Types and Service Layer#
| Symbol | Location | Notes |
|---|---|---|
AiProviderDetailItem | @/types/aiProvider | Full provider record including keyVaults, settings, checkModel, logo |
UpdateAiProviderConfigParams | @/types/aiProvider | Payload for config saves; includes fetchOnClient, config.enableResponseApi, and keyVaults fields |
AiProviderRuntimeConfig | @/types/aiProvider | Per-provider runtime shape stored in aiProviderRuntimeConfig |
aiProviderSelectors | @/store/aiInfra | All provider selectors; includes providerDetailById, providerConfigById, isProviderEnabled, isAiProviderConfigLoading, isProviderConfigUpdating |
aiProviderService | @/services/aiProvider | Service layer for CRUD operations; called directly from action methods |
The ProviderConfigProps interface allows per-provider customization: apiKeyItems (override default API key fields), apiKeyUrl (link to provider's key console), normalizeConfigValues (transform form values before saving), and checkErrorRender (custom connection-test error UI).