import { useAtomValue } from "@effect/atom-react"; import { connectionStatusText } 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, 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 { CloudIcon, LaptopIcon, LoaderIcon, MonitorIcon, PlusIcon, RefreshCwIcon, TerminalIcon, } from "lucide-react"; import { useCallback, useMemo, useRef, useState } from "react"; import { isDesktopLocalConnectionTarget } from "../../connection/desktopLocal"; import { isElectron } from "../../env"; import { usePrimarySessionState } from "../../environments/primary"; import { useEnvironmentSettings, useUpdateEnvironmentSettings } from "../../hooks/useSettings"; 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 { canOneClickUpdateProviderCandidate, collectProviderUpdateCandidates, hasOneClickUpdateProviderCandidate, isProviderUpdateActive, type ProviderUpdateCandidate, } from "../ProviderUpdateLaunchNotification.logic"; import { Button } from "../ui/button"; import { NumberField, NumberFieldDecrement, NumberFieldGroup, NumberFieldIncrement, NumberFieldInput, } from "../ui/number-field"; import { stackedThreadToast, toastManager } from "../ui/toast"; import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; import { AddProviderInstanceDialog } from "./AddProviderInstanceDialog"; import { ProviderInstanceCard } from "./ProviderInstanceCard"; 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, } from "./settingsLayout"; import { buildProviderEnvironmentOptions, classifyProviderEnvironmentAccess, 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 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 providerEnvironmentIcon(environment: EnvironmentPresentation) { if (environment.entry.target._tag === "PrimaryConnectionTarget") return MonitorIcon; if (environment.entry.target._tag === "RelayConnectionTarget") return CloudIcon; if (environment.entry.target._tag === "SshConnectionTarget") return TerminalIcon; if (isDesktopLocalConnectionTarget(environment.entry.target)) return LaptopIcon; return CloudIcon; } 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"; } function EnvironmentUnavailableRow({ environment, access, }: { readonly environment: EnvironmentPresentation; readonly access: Exclude; }) { const isLoading = access.kind === "loading"; const title = isLoading ? "Loading provider settings" : access.kind === "error" ? "Could not connect to this device" : "Provider settings are unavailable"; const description = isLoading ? access.reason === "permissions" ? "Checking what this session is allowed to change." : `Waiting for ${environment.label}'s configuration.` : connectionStatusText(environment.connection); // No spinner: this state can persist indefinitely for a wedged device, and a // continuously repainting animation would run the whole time. return ( ); } export function ProviderSettingsPanel() { const { environments, isReady } = useEnvironments(); const primaryEnvironmentId = usePrimaryEnvironmentId(); 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( primaryEnvironmentId, ); const effectiveEnvironmentId = resolveSelectedProviderEnvironmentId( options, selectedEnvironmentId, primaryEnvironmentId, ); const selectedEnvironment = options.find((environment) => environment.environmentId === effectiveEnvironmentId) ?? null; const onlyPrimaryDevice = options.length === 1 && options[0]?.entry.target._tag === "PrimaryConnectionTarget"; return ( {!onlyPrimaryDevice ? ( {options.length === 0 ? ( // The catalog hydrates asynchronously, so an empty list before it is // ready means "not loaded yet", not "nothing is connected". ) : (
{options.map((environment) => { const Icon = providerEnvironmentIcon(environment); const selected = environment.environmentId === effectiveEnvironmentId; const statusText = connectionStatusText(environment.connection); return ( ); })}
)}
) : null} {selectedEnvironment ? ( ) : null}
); } function SelectedEnvironmentProviderSettings({ environment, }: { readonly environment: EnvironmentPresentation; }) { 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, }: { readonly environment: EnvironmentPresentation; }) { const primarySessionState = usePrimarySessionState(); const operateAccess = resolvePrimaryOperateAccess({ isPrimary: true, hasDesktopBridge: false, session: primarySessionState.data, isPending: primarySessionState.isPending, hasError: primarySessionState.error !== null, }); return ; } function RemoteSessionGatedProviderSettings({ environment, }: { readonly environment: EnvironmentPresentation; }) { const sessionState = useEnvironmentSessionState(environment.environmentId); const operateAccess = resolveRemoteOperateAccess({ session: sessionState.data, isPending: sessionState.isPending, hasError: sessionState.hasError, }); return ; } function AccessGatedProviderSettings({ environment, operateAccess, }: { readonly environment: EnvironmentPresentation; readonly operateAccess: ProviderOperateAccess; }) { 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, }: { readonly environmentId: EnvironmentId; readonly environmentLabel: string; /** * Render the full provider layout, greyed out and inert, when this session's * credential lacks `orchestration:operate` on the environment. Showing the * real configuration keeps the view honest; disabling interaction keeps * every one of its writes from being 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 [updatingProviderDrivers, setUpdatingProviderDrivers] = useState< ReadonlySet >(() => new Set()); const [openInstanceDetails, setOpenInstanceDetails] = useState>({}); const refreshingRef = useRef(false); const updatingDriversRef = useRef>(new Set()); const providerUpdateCandidates = useMemo( () => collectProviderUpdateCandidates(serverProviders), [serverProviders], ); const providerUpdateCandidateByInstanceId = useMemo( () => new Map(providerUpdateCandidates.map((candidate) => [candidate.instanceId, candidate])), [providerUpdateCandidates], ); 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: {}, }); 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: ProviderUpdateCandidate) => { // Ref-based re-entry guard, mirroring refreshProviders: a state updater // may run after this function returns, so it cannot gate the dispatch. if (updatingDriversRef.current.has(candidate.driver)) { return; } updatingDriversRef.current.add(candidate.driver); setUpdatingProviderDrivers((previous) => new Set(previous).add(candidate.driver)); 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.", }), ); } updatingDriversRef.current.delete(candidate.driver); setUpdatingProviderDrivers((previous) => { if (!previous.has(candidate.driver)) { return previous; } const next = new Set(previous); next.delete(candidate.driver); 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 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), }); }; return ( <> {!readOnly ? ( <> setIsAddInstanceDialogOpen(true)} aria-label="Add provider instance" > } /> Add provider instance void refreshProviders()} aria-label="Refresh provider status" > {isRefreshingProviders ? ( ) : ( )} } /> Refresh provider status ) : null} } > {readOnly ? ( ) : null}
Health check interval 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 availability, versions, auth state, and model metadata in the background. Set this to 0 seconds to rely on manual refreshes." resetAction={ providerHealthRefreshIntervalSeconds !== defaultProviderHealthRefreshIntervalSeconds ? ( updateSettings( backgroundActivityOverrideSettings( settings.backgroundActivity, resolvedBackgroundActivity, { providerHealthRefreshInterval: undefined, }, ), ) } /> ) : null } control={
updateSettings( backgroundActivityOverrideSettings( settings.backgroundActivity, resolvedBackgroundActivity, { providerHealthRefreshInterval: Duration.seconds( normalizeIntervalSeconds(value), ), }, ), ) } > seconds
} /> {rows.map((row) => { const driverOption = getDriverOption(row.driver); const liveProvider = serverProviders.find( (candidate) => candidate.instanceId === row.instanceId, ); const updateCandidate = liveProvider ? providerUpdateCandidateByInstanceId.get(liveProvider.instanceId) : undefined; const isDriverUpdateRunning = updateCandidate !== undefined && (updatingProviderDrivers.has(updateCandidate.driver) || serverProviders.some( (provider) => provider.driver === updateCandidate.driver && isProviderUpdateActive(provider), )); const showInlineUpdateButton = updateCandidate !== undefined && hasOneClickUpdateProviderCandidate(updateCandidate, serverProviders); const canRunInlineUpdate = updateCandidate !== undefined && canOneClickUpdateProviderCandidate(updateCandidate, serverProviders) && !updatingProviderDrivers.has(updateCandidate.driver); 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); const headerAction = row.isDefault && row.isDirty ? ( resetDefaultInstance(row.driver)} /> ) : null; return ( setOpenInstanceDetails((existing) => ({ ...existing, [row.instanceId]: open, })) } onUpdate={(next) => { const wasEnabled = resolveProviderInstanceEnabled(row.instance); const isDisabling = next.enabled === false && wasEnabled; const shouldClearTextGen = isDisabling && textGenInstanceId === row.instanceId; if (shouldClearTextGen) { updateProviderInstance(row, next, { textGenerationModelSelection: DEFAULT_UNIFIED_SETTINGS.textGenerationModelSelection, }); } else { updateProviderInstance(row, next); } }} onDelete={row.isDefault ? undefined : () => deleteProviderInstance(row.instanceId)} headerAction={headerAction} hiddenModels={modelPreferences.hiddenModels} favoriteModels={favoriteModels} modelOrder={modelPreferences.modelOrder} onHiddenModelsChange={(hiddenModels) => updateProviderModelPreferences(row.instanceId, { ...modelPreferences, hiddenModels, }) } onFavoriteModelsChange={(favoriteModels) => updateProviderFavoriteModels(row.instanceId, favoriteModels) } onModelOrderChange={(modelOrder) => updateProviderModelPreferences(row.instanceId, { ...modelPreferences, modelOrder, }) } onRunUpdate={ showInlineUpdateButton && updateCandidate ? () => { if (!canRunInlineUpdate) { return; } void runProviderUpdate(updateCandidate); } : undefined } isUpdating={showInlineUpdateButton ? isDriverUpdateRunning : undefined} /> ); })}
{isAddInstanceDialogOpen ? ( ) : null} ); }