Skip to content

feat(ai-providers): multi-model discovery, OpenRouter or/ prefix routing, LiteLLM redesign, theme icons, disabled-provider reconciliation - #396

Open
Fork-You-Later wants to merge 19 commits into
Natively-AI-assistant:mainfrom
Fork-You-Later:fix/answer-policy-engine
Open

feat(ai-providers): multi-model discovery, OpenRouter or/ prefix routing, LiteLLM redesign, theme icons, disabled-provider reconciliation#396
Fork-You-Later wants to merge 19 commits into
Natively-AI-assistant:mainfrom
Fork-You-Later:fix/answer-policy-engine

Conversation

@Fork-You-Later

@Fork-You-Later Fork-You-Later commented Jul 26, 2026

Copy link
Copy Markdown

Summary of Changes

1. Multi-Model Discovery & Selection for Cloud Providers

  • Feature: Cloud Provider cards (Gemini, Groq, OpenAI, Claude, DeepSeek, OpenRouter) now feature a Manage Selectable Models popup — identical pattern to LiteLLM proxy, allowing multiple models per provider to be selected and surfaced in the Active Model dropdown.
  • Dynamic Model Pooling: buildAvailableModelOptions() pools standard preset models + discovered/cached models from localStorage (cached-models-*).
  • State & Encryption Persistence: Per-provider model selections are saved in encrypted credentials storage under cloudEnabledModels (Record<string, string[]>), keeping selections intact when toggling providers on or off.
  • Show Selected Only Toggle: Each provider popup has a filter toggle to show only currently enabled models.
  • Fetch Models Button: Moved inside the popup (removed from the card), keeping the card UI clean.

2. LiteLLM Proxy Card UI Redesign & Enhancements

  • Clean Configured State: Once Proxy Base URL and virtual key are saved, the input fields and Save button hide automatically.
  • Proxy Base URL Badge: Displays a clear Proxy URL: http://... indicator badge with a globe icon when configured.
  • Unified Action Row: Replaced raw buttons with the same row layout used across other Cloud Provider cards: [ Manage Models (X/Y Enabled) ▾ ] [ Connected / Test Connection ] [ 🗑️ Remove Configuration ].
  • Selected Only Filter: Added filter toggle inside the LiteLLM Manage Selectable Models modal matching other provider cards.

3. Theme-Aware Icon System (@lobehub/icons)

  • Icon Integration: Built LobeProviderIcon.tsx wrapping @lobehub/icons with fallback local SVGs/images for all providers.
  • Theme Awareness: Automatically toggles dark and light variant icons based on active color scheme.

4. Chromium Input Focus Lock Bug Fix (Windows)

  • Root Cause: Using native browser window.confirm(...) dialogs in Windows Electron locks Chromium's input focus and pointer-event subsystem when the modal closes.
  • Fix: Removed all native blocking confirm() calls from API key and configuration removal handlers. Inputs and Save buttons remain 100% focused and interactive immediately upon deletion without needing to switch focus away and back.

5. Model Selector Dropdown Window Expansion

  • Window Canvas: Expanded Electron BrowserWindow width from 140px to 350px (height 300px) in ModelSelectorWindowHelper.ts so long model names display without right-side clipping.
  • Container Sizing: Updated ModelSelectorWindow.tsx container to w-full h-[290px] and trigger button styling in NativelyInterface.tsx to min-w-[170px] max-w-[240px].

6. Popup Performance & Dark Mode Aesthetics

  • Memoized Filtering: Wrapped model list calculations in useMemo so searching and filtering run efficiently without recalculating on every mouse event.
  • Targeted CSS Transitions: Replaced CPU-heavy transition-all on list rows with lightweight transition-colors duration-150, eliminating hover lag.
  • Dark Mode Border Cleanup: Removed bright white container outlines from popup item cards in dark mode.

7. OpenRouter or/ Prefix (LiteLLM-style)

  • Unambiguous routing: Replaced the fragile slash heuristic (modelId.includes('/')) with a unique or/ prefix, matching the same pattern LiteLLM uses (litellm/). OpenRouter models are stored as or/<provider>/<model> (e.g. or/openai/gpt-4o, or/anthropic/claude-sonnet-4).
  • isOpenRouterModel() now uses modelId.startsWith('or/') — no exclusion list needed.
  • Guards added to isOpenAiModel, isClaudeModel, isGroqModel so they never match or/-prefixed models.
  • Prefix stripping at the API boundary in generateWithOpenai, streamWithOpenai, streamWithOpenaiMultimodal.
  • resolveOpenRouterModel() helper added.
  • modelFetcher.ts prefixes all fetched OpenRouter models with or/.
  • modelUtils.ts preset OpenRouter models already use or/ prefix.
  • OpenRouter preferences now use this.openrouterClient === clientOverride identity check instead of isOpenRouterModel(model) (which returned false after the stripped model name).

8. Provider Routing Order

  • OpenRouter moved after Groq in both chatWithGemini and _streamChatInner.
  • New chain: Natively → OpenAI → Claude → DeepSeek → LiteLLM → Groq → OpenRouter → Gemini fallback

9. Disabled Provider & Enabled-Model Reconciliation

  • refreshRuntimeDefaultIfUnavailable() now consults disabledProviders and cloudEnabledModels filters so disabling a provider or de-selecting a model immediately takes effect.
  • Replacement chain uses modelAvailable() instead of raw has() checks, so disabled/enabled-model filters are respected when picking a fallback.
  • set-litellm-enabled-models now calls refreshRuntimeDefaultIfUnavailable() after updating, same as set-cloud-enabled-models.
  • providerFamily() in ipcHandlers.ts recognizes or/ prefix as 'openrouter'.
  • No-available-model sentinel: When all providers are disabled, resets to 'gemini-3.6-flash' (not 'natively', which may have been disabled) so the stale model identifier is never re-activated.

10. OpenRouter Credentials & Preferences

  • setOpenrouterApiKey IPC handler persists the key and updates LLMHelper.
  • get-openrouter-key-info fetches key metadata from OpenRouter API.
  • get-openrouter-preferences / set-openrouter-preferences persist reasoning effort, provider sort, and fallback preferences.
  • OpenRouter preferences are injected into API requests via extraOpenRouterParams (reasoning effort, provider sorting).

11. Local Whisper Memory Safeguards

  • Windows DML memory guard: Validates the NATIVELY_DML_MIN_AVAIL_GB env var with Number.isFinite() and falls back to the default 8GB threshold for malformed values.

Files Changed

File Changes
electron/LLMHelper.ts OpenRouter or/ prefix routing, provider guards, prefix stripping, routing order fix
electron/ipcHandlers.ts OpenRouter key/preferences IPC, disabled/enabled-model reconciliation, sentinel fix
electron/ModelSelectorWindowHelper.ts Expanded window to 350×300
electron/preload.ts Exposed new IPC APIs
electron/services/CredentialsManager.ts Persists cloudEnabledModels, OpenRouter preferences
electron/utils/modelFetcher.ts or/ prefix on fetched OpenRouter models
electron/audio/whisper/inferenceConfig.ts DML memory threshold validation
src/components/ModelSelectorWindow.tsx Container sizing update
src/components/NativelyInterface.tsx Trigger button min/max width
src/components/settings/AIProvidersSettings.tsx LiteLLM card redesign, confirm() removal, model pooling
src/components/settings/ProviderCard.tsx Multi-model popup, memoized filtering, dark mode borders
src/components/settings/LobeProviderIcon.tsx NEW: theme-aware provider icon component
src/assets/provider-logos/ NEW: local fallback logo assets
src/utils/modelUtils.ts buildAvailableModelOptions() pooling, or/ preset models
src/types/electron.d.ts New IPC type definitions

Verification

  • npx tsc --noEmit — ✅ 0 compilation errors
  • Runtime tested: model selection popups, LiteLLM card configuration flow, focus after key deletion, overlay dropdown width

…esign, theme-aware Lobe icons, focus lock fixes & expanded dropdown width
@greptile-apps

greptile-apps Bot commented Jul 26, 2026

Copy link
Copy Markdown

Greptile Summary

This PR expands AI-provider model management and revises provider routing and runtime reconciliation.

  • Adds OpenRouter credentials, preferences, model discovery, and or/-prefixed routing across streaming and non-streaming generation.
  • Adds per-provider enabled-model persistence, provider disabling, and active-model reconciliation.
  • Redesigns provider settings and LiteLLM model management with theme-aware icons.
  • Adds Windows local-Whisper memory safeguards and enlarges the model-selector window.

Confidence Score: 3/5

The PR is not yet safe to merge because existing OpenRouter IDs can still bypass OpenRouter routing, and disabling the final provider can leave it active at runtime.

The new routing guard handles or/ identifiers but not several bare OpenRouter identifiers still supplied by the model presets and persistence path. The reconciliation function also returns without clearing or replacing the active model when no fallback exists, so a configured client can continue serving requests through a provider the user disabled.

Files Needing Attention: electron/LLMHelper.ts, electron/ipcHandlers.ts, src/utils/modelUtils.ts

Important Files Changed

Filename Overview
electron/LLMHelper.ts Adds OpenRouter client initialization, prefixed model classification, request routing, prefix removal, and preference injection.
electron/ipcHandlers.ts Adds provider configuration IPC and reconciles the runtime model against disabled-provider and enabled-model filters.
electron/services/CredentialsManager.ts Persists OpenRouter configuration and provider/model-selection state in encrypted credential storage.
electron/audio/whisper/inferenceConfig.ts Validates the Windows DML memory threshold and selects CPU inference below the configured floor.
src/components/settings/AIProvidersSettings.tsx Redesigns cloud-provider and LiteLLM configuration and model-management controls.
src/components/settings/ProviderCard.tsx Adds searchable multi-model selection with selected-only filtering and optimized row transitions.
src/utils/modelUtils.ts Pools preset and discovered models for provider selection.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  UI[Provider settings and model selector] --> IPC[Preload and IPC handlers]
  IPC --> Creds[CredentialsManager]
  IPC --> Runtime[LLMHelper active model]
  Runtime --> Native[Native cloud providers]
  Runtime --> Lite[LiteLLM proxy]
  Runtime --> OR[OpenRouter client]
  Runtime --> Gemini[Gemini fallback]
Loading

Reviews (16): Last reviewed commit: "fix(ipc): do not install any model when ..." | Re-trigger Greptile

Comment thread electron/LLMHelper.ts
Comment thread electron/ipcHandlers.ts
Comment thread electron/audio/whisper/inferenceConfig.ts Outdated
…nguage/accent, sticky keybind tabs & UI skill creator
…model reconciliation, and DirectML threshold
Comment thread electron/LLMHelper.ts Outdated
Comment thread electron/LLMHelper.ts Outdated
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

…Available check

- Replace slash heuristic with LiteLLM-style or/ prefix for OpenRouter models
- Guard isOpenAiModel/isClaudeModel/isGroqModel from matching or/ prefix
- Strip or/ prefix at API boundary (generateWithOpenai, streamWithOpenai, streamWithOpenaiMultimodal)
- Move OpenRouter check after Groq in both streaming and non-streaming paths
- Add providerFamily() recognition of or/ prefix to refreshRuntimeDefaultIfUnavailable
- Fix clientOverride identity check for OpenRouter preferences (was using isOpenRouterModel on stripped model which always returned false)
- Add resolveOpenRouterModel helper
…ter tuning, and style model manager scrollbars
…esh to LiteLLM handler

- Replacement chain now calls modelAvailable() instead of raw has() checks,
  so disabled/enabled-model filters are respected when picking a fallback
- set-litellm-enabled-models now calls refreshRuntimeDefaultIfUnavailable()
  after updating, same as set-cloud-enabled-models
When all providers are disabled or no credential is configured,
refreshRuntimeDefaultIfUnavailable now resets the persisted default
to 'natively' instead of returning null without updating state.
This prevents LLMHelper from continuing to route requests to a
stale disabled model identifier.
…odel available

The !next fallback used 'natively' as the reset sentinel, but natively
may have been explicitly disabled by the user and was already rejected
by modelAvailable() above — re-setting to it would re-activate the
disabled provider. Use 'gemini-3.6-flash' (the constant default) which
gracefully falls through to 'No AI providers configured'.
@Fork-You-Later Fork-You-Later changed the title feat(ai-providers): multi-model discovery selection, LiteLLM card redesign, theme-aware Lobe icons, focus lock fixes & expanded dropdown width feat(ai-providers): multi-model discovery, OpenRouter or/ prefix routing, LiteLLM redesign, theme icons, disabled-provider reconciliation Jul 28, 2026
The !next fallback previously installed gemini-3.6-flash as a sentinel,
but gemini-3.6-flash was already rejected by modelAvailable() above
(along with every other candidate). Persisting a rejected model
re-activates the disabled provider, which is the exact bug Greptile
flagged. Now returns null without touching the default model, so the
persisted state stays unchanged and the routing chain fails at execution
time with 'No AI providers configured'.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant