import { RefreshIcon } from "~/components/ui/refresh-icon"; import { useAtomValue } from "@effect/atom-react"; import { connectionStatusTitle } from "@t3tools/client-runtime/connection"; import { safeErrorLogAttributes } from "@t3tools/client-runtime/errors"; import { isAtomCommandInterrupted, squashAtomCommandFailure, } from "@t3tools/client-runtime/state/runtime"; import { defaultInstanceIdForDriver, type EnvironmentId, PROVIDER_DISPLAY_NAMES, ProviderDriverKind, type ProviderInstanceConfig, type ProviderInstanceId, resolveEnvironmentMachineKind, resolveProviderInstanceEnabled, } from "@t3tools/contracts"; import { DEFAULT_UNIFIED_SETTINGS } from "@t3tools/contracts/settings"; import { getBackgroundActivityPresetSettings, resolveServerBackgroundActivitySettings, } from "@t3tools/shared/backgroundActivitySettings"; import * as Arr from "effect/Array"; import * as Duration from "effect/Duration"; import * as Equal from "effect/Equal"; import * as Result from "effect/Result"; import { PlusIcon } from "lucide-react"; import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; import { isDesktopLocalConnectionTarget } from "../../connection/desktopLocal"; import { isElectron } from "../../env"; import { usePrimarySessionState } from "../../environments/primary"; import { useEnvironmentSettings, useUpdateEnvironmentSettings } from "../../hooks/useSettings"; import { EnvironmentMachineIcon } from "../EnvironmentMachineIcon"; import { cn } from "../../lib/utils"; import { resolveAppModelSelectionState } from "../../modelSelection"; import { useEnvironments, usePrimaryEnvironmentId, type EnvironmentPresentation, } from "../../state/environments"; import { EMPTY_SERVER_PROVIDERS, serverEnvironment } from "../../state/server"; import { useEnvironmentSessionState } from "../../state/session"; import { useAtomCommand } from "../../state/use-atom-command"; import { getRelativeTimeState } from "../../timestampFormat"; import { ConnectionStatusDot, connectionPhaseDotClassName, connectionPhasePingClassName, } from "../ConnectionStatusDot"; import { isProviderSettingsUpdateCandidate, isProviderUpdateActive, type ProviderSettingsUpdateCandidate, } from "../ProviderUpdateLaunchNotification.logic"; import { Button } from "../ui/button"; import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, } from "../ui/empty"; import { NumberField, NumberFieldDecrement, NumberFieldGroup, NumberFieldIncrement, NumberFieldInput, } from "../ui/number-field"; import { ScrollArea } from "../ui/scroll-area"; import { Toggle, ToggleGroup } from "../ui/toggle-group"; import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; import { stackedThreadToast, toastManager } from "../ui/toast"; import { AddProviderInstanceDialog } from "./AddProviderInstanceDialog"; import { ExpandableText } from "./ExpandableText"; import { ProviderInstanceCard } from "./ProviderInstanceCard"; import { UsageProviderSettings } from "./UsageProviderSettings"; import { ProviderSetupSection, readAntigravityAuthMethod } from "./ProviderSetupSection"; import { DRIVER_OPTIONS, getDriverOption } from "./providerDriverMeta"; import { searchableSetting } from "./settingsSearch"; import { backgroundActivityOverrideSettings, buildProviderInstanceUpdatePatch, durationToSeconds, normalizeIntervalSeconds, PROVIDER_HEALTH_INTERVAL_STEP_SECONDS, } from "./SettingsPanels.logic"; import { PolicyTooltip, SettingResetButton, SettingsPageContainer, SettingsRow, SettingsSection, useRelativeTimeTick, useSettingsSearchTargetId, } from "./settingsLayout"; import { buildProviderEnvironmentOptions, classifyProviderEnvironmentAccess, isProviderSettingsEnvironmentAvailable, type ProviderEnvironmentAccess, type ProviderOperateAccess, resolvePrimaryOperateAccess, resolveRemoteOperateAccess, resolveSelectedProviderEnvironmentId, } from "./ProviderSettingsPanel.logic"; function withoutProviderInstanceKey( record: Readonly> | undefined, key: ProviderInstanceId, ): Record { const next = { ...record } as Record; delete next[key]; return next; } function withoutProviderInstanceFavorites( favorites: ReadonlyArray<{ readonly provider: ProviderInstanceId; readonly model: string }>, instanceId: ProviderInstanceId, ) { return favorites.filter((favorite) => favorite.provider !== instanceId); } const PROVIDER_SETTINGS = DRIVER_OPTIONS.map((definition) => ({ provider: definition.value, })); function configuredBinaryPath(config: unknown): string { if (config === null || typeof config !== "object" || !("binaryPath" in config)) return ""; return typeof config.binaryPath === "string" ? config.binaryPath.trim() : ""; } function ProviderLastChecked({ lastCheckedAt }: { lastCheckedAt: string | null }) { useRelativeTimeTick(); const lastCheckedRelative = getRelativeTimeState(lastCheckedAt); if (lastCheckedRelative.status === "missing") { return null; } if (lastCheckedRelative.status === "invalid") { return Checked unavailable; } return ( {lastCheckedRelative.suffix ? ( <> Checked {lastCheckedRelative.value}{" "} {lastCheckedRelative.suffix} ) : ( <>Checked {lastCheckedRelative.value} )} ); } function providerEnvironmentDetail(environment: EnvironmentPresentation): string { if (environment.entry.target._tag === "PrimaryConnectionTarget") return "Primary device"; if (environment.relayManaged) return "T3 Connect"; if (environment.entry.target._tag === "SshConnectionTarget") return "SSH"; if (isDesktopLocalConnectionTarget(environment.entry.target)) return "Local device"; return environment.displayUrl ?? "Remote device"; } const providerCardClassName = "rounded-xl border border-border/60 bg-card/40 shadow-xs/5"; // Shared by the editor grid and the placeholder states so switching devices // never changes the card's footprint. const providerCardHeightClassName = "lg:h-[min(44rem,calc(100dvh-11rem))] lg:min-h-[32rem]"; /** * Same chrome as the provider editor (section heading, floating device tabs, * tall card) for states that cannot render provider settings yet. */ function ProviderSettingsPlaceholder({ deviceTabs, icon, title, description, children, }: { readonly deviceTabs?: ReactNode; readonly icon: ReactNode; readonly title: string; readonly description: string; readonly children?: ReactNode; }) { return ( {deviceTabs ? (
{deviceTabs}
) : null}
{icon} {title} {description} {children ? {children} : null}
); } function EnvironmentUnavailablePlaceholder({ environment, access, deviceTabs, }: { readonly environment: EnvironmentPresentation; readonly access: Exclude; readonly deviceTabs?: ReactNode; }) { const isLoading = access.kind === "loading"; const title = isLoading ? "Loading provider settings" : access.kind === "error" ? "Could not connect to this device" : "Provider settings are unavailable"; // Keep the description to a short status; the raw failure can be a // multi-paragraph CLI dump, so it goes below, clamped and expandable. const description = isLoading ? access.reason === "permissions" ? "Checking what this session is allowed to change." : `Waiting for ${environment.label}'s configuration.` : connectionStatusTitle(environment.connection); const error = isLoading ? null : environment.connection.error; // No spinner: this state can persist indefinitely for a wedged device, and a // continuously repainting animation would run the whole time. return ( } title={title} description={description} > {error ? ( ) : null} ); } interface ProviderSettingsTarget { readonly environmentId?: EnvironmentId; readonly instanceId?: ProviderInstanceId; } export function ProviderSettingsPanel(target: ProviderSettingsTarget) { return ( ); } function ProviderSettingsPanelContent(target: ProviderSettingsTarget) { const { environments, isReady } = useEnvironments(); const primaryEnvironmentId = usePrimaryEnvironmentId(); const searchTargetId = useSettingsSearchTargetId(); const options = useMemo( () => buildProviderEnvironmentOptions(environments, primaryEnvironmentId), [environments, primaryEnvironmentId], ); // Raw user intent; the effective selection is re-derived every render so a // device that drops out of the catalog falls back without erasing the pick — // if it reappears (e.g. after a reconnect) the selection is restored. const [selectedEnvironmentId, setSelectedEnvironmentId] = useState( target.environmentId ?? primaryEnvironmentId, ); const targetEnvironmentMissing = target.environmentId !== undefined && selectedEnvironmentId === target.environmentId && !options.some((environment) => environment.environmentId === target.environmentId); const effectiveEnvironmentId = targetEnvironmentMissing ? target.environmentId : resolveSelectedProviderEnvironmentId(options, selectedEnvironmentId, primaryEnvironmentId); const selectedEnvironment = options.find((environment) => environment.environmentId === effectiveEnvironmentId) ?? null; const selectedEnvironmentCanRenderSettings = selectedEnvironment !== null && isProviderSettingsEnvironmentAvailable({ connectionPhase: selectedEnvironment.connection.phase, hasServerConfig: selectedEnvironment.serverConfig !== null, }); const searchableEnvironmentId = options.find((environment) => isProviderSettingsEnvironmentAvailable({ connectionPhase: environment.connection.phase, hasServerConfig: environment.serverConfig !== null, }), )?.environmentId; useEffect(() => { if ( (searchTargetId === searchableSetting("provider-health-check-interval").id || searchTargetId === searchableSetting("usage-providers").id) && !selectedEnvironmentCanRenderSettings && searchableEnvironmentId !== undefined ) { setSelectedEnvironmentId(searchableEnvironmentId); } }, [searchTargetId, searchableEnvironmentId, selectedEnvironmentCanRenderSettings]); const onlyPrimaryDevice = options.length === 1 && options[0]?.entry.target._tag === "PrimaryConnectionTarget"; const deviceTabs = !onlyPrimaryDevice && options.length > 0 ? ( { const environment = options.find((option) => option.environmentId === next[0]); if (environment) setSelectedEnvironmentId(environment.environmentId); }} > {options.map((environment) => { const machine = resolveEnvironmentMachineKind(environment.serverConfig); const detail = providerEnvironmentDetail(environment); const statusText = connectionStatusTitle(environment.connection); return ( {environment.label} {environment.connection.phase !== "connected" ? ( ) : null} {detail}, {statusText} } /> {detail} · {statusText} ); })} ) : null; return ( <> {targetEnvironmentMissing ? ( } title="Device unavailable" description="Reconnect this device to set up its provider, or select another device." /> ) : null} {options.length === 0 && !targetEnvironmentMissing ? ( } title={isReady ? "No connected devices" : "Loading devices"} description={ isReady ? "Connect an execution environment before configuring providers." : "Reading connected execution environments." } /> ) : null} {selectedEnvironment ? ( ) : null} ); } function SelectedEnvironmentProviderSettings({ environment, deviceTabs, targetInstanceId, }: { readonly environment: EnvironmentPresentation; readonly deviceTabs?: ReactNode; readonly targetInstanceId?: ProviderInstanceId | undefined; }) { const isPrimary = environment.entry.target._tag === "PrimaryConnectionTarget"; if (isPrimary) { // The desktop app owns its primary server outright; a browser session // checks the scopes its cookie session was granted. if (isElectron) { return ( ); } return ( ); } return ( ); } function PrimarySessionGatedProviderSettings({ environment, deviceTabs, targetInstanceId, }: { readonly environment: EnvironmentPresentation; readonly deviceTabs?: ReactNode; readonly targetInstanceId?: ProviderInstanceId | undefined; }) { const primarySessionState = usePrimarySessionState(); const operateAccess = resolvePrimaryOperateAccess({ isPrimary: true, hasDesktopBridge: false, session: primarySessionState.data, isPending: primarySessionState.isPending, hasError: primarySessionState.error !== null, }); return ( ); } function RemoteSessionGatedProviderSettings({ environment, deviceTabs, targetInstanceId, }: { readonly environment: EnvironmentPresentation; readonly deviceTabs?: ReactNode; readonly targetInstanceId?: ProviderInstanceId | undefined; }) { const sessionState = useEnvironmentSessionState(environment.environmentId); const operateAccess = resolveRemoteOperateAccess({ session: sessionState.data, isPending: sessionState.isPending, hasError: sessionState.hasError, }); return ( ); } function AccessGatedProviderSettings({ environment, operateAccess, deviceTabs, targetInstanceId, }: { readonly environment: EnvironmentPresentation; readonly operateAccess: ProviderOperateAccess; readonly deviceTabs?: ReactNode; readonly targetInstanceId?: ProviderInstanceId | undefined; }) { const access = classifyProviderEnvironmentAccess({ connectionPhase: environment.connection.phase, hasServerConfig: environment.serverConfig !== null, operateAccess, }); if (access.kind !== "editable" && access.kind !== "read-only") { return ( ); } return ( ); } export function EnvironmentProviderSettings({ environmentId, environmentLabel, readOnly = false, deviceTabs, targetInstanceId, }: { readonly environmentId: EnvironmentId; readonly environmentLabel: string; readonly deviceTabs?: ReactNode; readonly targetInstanceId?: ProviderInstanceId | undefined; /** * Grey out and freeze every write control when this session's credential * lacks `orchestration:operate` on the environment. Selecting providers * still works so the real configuration stays readable; switches, forms, * and the health interval are inert so no write is offered and then rejected. */ readonly readOnly?: boolean; }) { const settings = useEnvironmentSettings(environmentId); const updateSettings = useUpdateEnvironmentSettings(environmentId); const serverProviders = useAtomValue(serverEnvironment.providersValueAtom(environmentId)) ?? EMPTY_SERVER_PROVIDERS; const refreshServerProviders = useAtomCommand(serverEnvironment.refreshProviders, { reportFailure: false, }); const updateProvider = useAtomCommand(serverEnvironment.updateProvider, { reportFailure: false, }); const [isRefreshingProviders, setIsRefreshingProviders] = useState(false); const [isAddInstanceDialogOpen, setIsAddInstanceDialogOpen] = useState(false); const [selectedInstanceId, setSelectedInstanceId] = useState( targetInstanceId ?? null, ); const [updatingProviderInstanceIds, setUpdatingProviderInstanceIds] = useState< ReadonlySet >(() => new Set()); const refreshingRef = useRef(false); const updatingInstanceIdsRef = useRef>(new Set()); const providerUpdateCandidateByInstanceId = useMemo( () => new Map( serverProviders .filter(isProviderSettingsUpdateCandidate) .map((candidate) => [candidate.instanceId, candidate]), ), [serverProviders], ); const visibleProviderSettings = PROVIDER_SETTINGS.filter( (providerSettings) => providerSettings.provider !== "cursor" || serverProviders.some( (provider) => provider.instanceId === defaultInstanceIdForDriver(ProviderDriverKind.make("cursor")), ), ); const textGenerationModelSelection = resolveAppModelSelectionState(settings, serverProviders); const textGenInstanceId = textGenerationModelSelection.instanceId; const resolvedBackgroundActivity = resolveServerBackgroundActivitySettings(settings); const providerHealthPreset = getBackgroundActivityPresetSettings( resolvedBackgroundActivity.profile, ).providerHealthRefreshInterval; const providerHealthRefreshIntervalSeconds = durationToSeconds( resolvedBackgroundActivity.providerHealthRefreshInterval, ); const defaultProviderHealthRefreshIntervalSeconds = durationToSeconds(providerHealthPreset); const lastCheckedAt = serverProviders.length > 0 ? serverProviders.reduce( (latest, provider) => (provider.checkedAt > latest ? provider.checkedAt : latest), serverProviders[0]!.checkedAt, ) : null; const refreshProviders = useCallback(() => { if (refreshingRef.current) return; refreshingRef.current = true; setIsRefreshingProviders(true); void (async () => { const result = await refreshServerProviders({ environmentId, input: { refreshModels: true }, }); refreshingRef.current = false; setIsRefreshingProviders(false); if (result._tag === "Failure" && !isAtomCommandInterrupted(result)) { console.warn("Failed to refresh providers", { operation: "refresh-providers", environmentId, ...safeErrorLogAttributes(squashAtomCommandFailure(result)), }); } })(); }, [environmentId, refreshServerProviders]); const runProviderUpdate = useCallback( async (candidate: ProviderSettingsUpdateCandidate) => { // Ref-based re-entry guard, mirroring refreshProviders: a state updater // may run after this function returns, so it cannot gate the dispatch. if (updatingInstanceIdsRef.current.has(candidate.instanceId)) { return; } updatingInstanceIdsRef.current.add(candidate.instanceId); setUpdatingProviderInstanceIds((previous) => new Set(previous).add(candidate.instanceId)); const result = await updateProvider({ environmentId, input: { provider: candidate.driver, instanceId: candidate.instanceId, }, }); if (result._tag === "Failure" && !isAtomCommandInterrupted(result)) { const error = squashAtomCommandFailure(result); toastManager.add( stackedThreadToast({ type: "error", title: `Could not update ${PROVIDER_DISPLAY_NAMES[candidate.driver] ?? candidate.driver}`, description: error instanceof Error ? error.message : "The provider update command could not be started.", }), ); } updatingInstanceIdsRef.current.delete(candidate.instanceId); setUpdatingProviderInstanceIds((previous) => { if (!previous.has(candidate.instanceId)) { return previous; } const next = new Set(previous); next.delete(candidate.instanceId); return next; }); }, [environmentId, updateProvider], ); interface InstanceRow { readonly instanceId: ProviderInstanceId; readonly instance: ProviderInstanceConfig; readonly driver: ProviderDriverKind; readonly isDefault: boolean; readonly isDirty?: boolean; } const instancesByDriver = new Map< ProviderDriverKind, Array<[ProviderInstanceId, ProviderInstanceConfig]> >(); for (const [rawId, instance] of Object.entries(settings.providerInstances ?? {})) { const driver = instance.driver; const list = instancesByDriver.get(driver) ?? []; list.push([rawId as ProviderInstanceId, instance]); instancesByDriver.set(driver, list); } const defaultSlotIdsBySource = new Set( visibleProviderSettings.map((providerSettings) => String(defaultInstanceIdForDriver(providerSettings.provider)), ), ); const rows: InstanceRow[] = []; const visibleDriverKinds = new Set( visibleProviderSettings.map((providerSettings) => providerSettings.provider), ); for (const providerSettings of visibleProviderSettings) { type LegacyProviderSettings = (typeof settings.providers)[keyof typeof settings.providers]; const legacyProviders = settings.providers as Record; const defaultLegacyProviders = DEFAULT_UNIFIED_SETTINGS.providers as Record< string, LegacyProviderSettings >; const driver = providerSettings.provider; const defaultInstanceId = defaultInstanceIdForDriver(driver); const explicitInstance = settings.providerInstances?.[defaultInstanceId]; // A remote device may run a server version whose settings predate this // driver, so the legacy mirror can be absent. Without either an explicit // instance or a legacy blob there is nothing to render for the slot. const legacyConfig = legacyProviders[providerSettings.provider]; const defaultLegacyConfig = defaultLegacyProviders[providerSettings.provider]; // The envelope is the single enabled flag: keep the legacy in-config // flag out of the synthesized blob, or an explicit `enabled: false` // would keep winning over the envelope and the Switch could never // turn a default-off provider on. const synthesizedInstance = (): ProviderInstanceConfig | undefined => { if (legacyConfig === undefined) { return undefined; } const { enabled: legacyEnabled, ...legacyConfigRest } = legacyConfig; return { driver, enabled: legacyEnabled, config: legacyConfigRest, } satisfies ProviderInstanceConfig; }; const effectiveInstance: ProviderInstanceConfig | undefined = explicitInstance ?? synthesizedInstance(); // Only the default slot depends on the legacy blob; custom instances for // the driver must still render even when the slot has nothing to show. if (effectiveInstance !== undefined) { const isDirty = explicitInstance !== undefined || !Equal.equals(legacyConfig, defaultLegacyConfig); rows.push({ instanceId: defaultInstanceId, instance: effectiveInstance, driver, isDefault: true, isDirty, }); } for (const [id, instance] of instancesByDriver.get(providerSettings.provider) ?? []) { if (id === defaultInstanceId) continue; rows.push({ instanceId: id, instance, driver: instance.driver, isDefault: false }); } } for (const [driver, list] of instancesByDriver) { if (visibleDriverKinds.has(driver)) continue; for (const [id, instance] of list) { rows.push({ instanceId: id, instance, driver: instance.driver, isDefault: defaultSlotIdsBySource.has(String(id)), }); } } const targetInstanceMissing = targetInstanceId !== undefined && selectedInstanceId === targetInstanceId && !rows.some((row) => row.instanceId === targetInstanceId); const selectedRow = rows.find((row) => row.instanceId === selectedInstanceId) ?? (targetInstanceMissing ? null : (rows[0] ?? null)); const updateProviderInstance = ( row: InstanceRow, next: ProviderInstanceConfig, options?: { readonly textGenerationModelSelection?: Parameters< typeof buildProviderInstanceUpdatePatch >[0]["textGenerationModelSelection"]; }, ) => { updateSettings( buildProviderInstanceUpdatePatch({ settings, instanceId: row.instanceId, instance: next, driver: row.driver, isDefault: row.isDefault, textGenerationModelSelection: options?.textGenerationModelSelection, }), ); }; const deleteProviderInstance = (id: ProviderInstanceId) => { updateSettings({ providerInstances: withoutProviderInstanceKey(settings.providerInstances, id), }); }; const updateProviderModelPreferences = ( instanceId: ProviderInstanceId, next: { readonly hiddenModels: ReadonlyArray; readonly modelOrder: ReadonlyArray; }, ) => { const hiddenModels = [...new Set(next.hiddenModels.filter((slug) => slug.trim().length > 0))]; const modelOrder = [...new Set(next.modelOrder.filter((slug) => slug.trim().length > 0))]; const rest = withoutProviderInstanceKey(settings.providerModelPreferences, instanceId); updateSettings({ providerModelPreferences: hiddenModels.length === 0 && modelOrder.length === 0 ? rest : { ...rest, [instanceId]: { hiddenModels, modelOrder, }, }, }); }; const updateProviderFavoriteModels = ( instanceId: ProviderInstanceId, nextFavoriteModels: ReadonlyArray, ) => { const favoriteModels = [ ...new Set( Arr.filterMap(nextFavoriteModels, (slug) => { const trimmedSlug = slug.trim(); return trimmedSlug.length > 0 ? Result.succeed(trimmedSlug) : Result.failVoid; }), ), ]; updateSettings({ favorites: [ ...withoutProviderInstanceFavorites(settings.favorites ?? [], instanceId), ...favoriteModels.map((model) => ({ provider: instanceId, model })), ], }); }; const resetDefaultInstance = (driverKind: ProviderDriverKind) => { type LegacyProviderSettings = (typeof settings.providers)[keyof typeof settings.providers]; const defaultLegacyProviders = DEFAULT_UNIFIED_SETTINGS.providers as Record< string, LegacyProviderSettings | undefined >; const defaultInstanceId = defaultInstanceIdForDriver(driverKind); const defaultLegacyProvider = defaultLegacyProviders[driverKind]; if (defaultLegacyProvider === undefined) return; updateSettings({ providers: { ...settings.providers, [driverKind]: defaultLegacyProvider, } as typeof settings.providers, providerInstances: withoutProviderInstanceKey(settings.providerInstances, defaultInstanceId), }); }; const renderProviderInstance = (row: InstanceRow, mode: "list" | "editor") => { const driverOption = getDriverOption(row.driver); const liveProvider = serverProviders.find( (candidate) => candidate.instanceId === row.instanceId, ); const updateCandidate = providerUpdateCandidateByInstanceId.get(row.instanceId); const isInstanceUpdateRunning = updateCandidate !== undefined && (updatingProviderInstanceIds.has(updateCandidate.instanceId) || isProviderUpdateActive(updateCandidate)); const showInlineUpdateButton = updateCandidate !== undefined; const canRunInlineUpdate = updateCandidate !== undefined && !isInstanceUpdateRunning; const modelPreferences = settings.providerModelPreferences?.[row.instanceId] ?? { hiddenModels: [], modelOrder: [], }; const favoriteModels = Arr.filterMap(settings.favorites ?? [], (favorite) => favorite.provider === row.instanceId ? Result.succeed(favorite.model) : Result.failVoid, ); const resetLabel = driverOption?.label ?? String(row.driver); return ( setSelectedInstanceId(row.instanceId) : undefined} readOnly={readOnly} setup={ mode === "editor" && row.driver === "antigravity" ? ( updateProviderInstance(row, { ...row.instance, enabled: true })} /> ) : null } onUpdate={(next) => { const wasEnabled = resolveProviderInstanceEnabled(row.instance); const isDisabling = next.enabled === false && wasEnabled; const shouldClearTextGen = isDisabling && textGenInstanceId === row.instanceId; updateProviderInstance( row, next, shouldClearTextGen ? { textGenerationModelSelection: DEFAULT_UNIFIED_SETTINGS.textGenerationModelSelection, } : undefined, ); }} onDelete={ mode === "editor" && !row.isDefault ? () => deleteProviderInstance(row.instanceId) : undefined } headerAction={ mode === "editor" && row.isDefault && row.isDirty ? ( resetDefaultInstance(row.driver)} /> ) : null } hiddenModels={modelPreferences.hiddenModels} favoriteModels={favoriteModels} modelOrder={modelPreferences.modelOrder} onHiddenModelsChange={(hiddenModels) => updateProviderModelPreferences(row.instanceId, { ...modelPreferences, hiddenModels, }) } onFavoriteModelsChange={(next) => updateProviderFavoriteModels(row.instanceId, next)} onModelOrderChange={(modelOrder) => updateProviderModelPreferences(row.instanceId, { ...modelPreferences, modelOrder, }) } onRunUpdate={ mode === "editor" && showInlineUpdateButton && updateCandidate ? () => { if (canRunInlineUpdate) void runProviderUpdate(updateCandidate); } : undefined } isUpdating={ mode === "editor" && showInlineUpdateButton ? isInstanceUpdateRunning : undefined } /> ); }; return ( <>
{deviceTabs}
{readOnly ? ( ) : ( <> void refreshProviders()} > Refresh provider status {isRefreshingProviders ? ( "Refreshing providers" ) : ( )} } /> Refresh provider status setIsAddInstanceDialogOpen(true)} aria-label="Add provider" > } /> Add provider )}
{readOnly ? (
) : null}
{rows.map((row) => renderProviderInstance(row, "list"))}
{selectedRow ? (
{renderProviderInstance(selectedRow, "editor")}
) : (
{targetInstanceMissing ? "This provider instance is no longer available on this device." : "No providers configured."}
)}
{searchableSetting("provider-health-check-interval").title} This interval is configured here, then the shared Background activity policy decides whether provider probes may run when the timer fires. Custom intervals appear as Advanced in General settings. } description="Refresh provider status, versions, and models in the background. Set to 0 to disable." resetAction={ providerHealthRefreshIntervalSeconds !== defaultProviderHealthRefreshIntervalSeconds ? ( updateSettings( backgroundActivityOverrideSettings( settings.backgroundActivity, resolvedBackgroundActivity, { providerHealthRefreshInterval: undefined }, ), ) } /> ) : null } control={
updateSettings( backgroundActivityOverrideSettings( settings.backgroundActivity, resolvedBackgroundActivity, { providerHealthRefreshInterval: Duration.seconds( normalizeIntervalSeconds(value), ), }, ), ) } > seconds
} />
{isAddInstanceDialogOpen ? ( ) : null} ); }