feat: dynamic model loading with provider search#37
Conversation
…rch functionality; update AI provider presets with model URLs
There was a problem hiding this comment.
Pull request overview
This PR improves the AI provider/model settings UX in the project sidebar by adding dynamic model loading (based on provider + API key) and a searchable model dropdown, plus some supporting refactors in the AI settings module and README updates.
Changes:
- Add per-provider
modelUrlsupport and fetch models dynamically with hardcoded fallbacks. - Add a model search bar inside the model dropdown in the sidebar settings UI.
- Update docs to mention dynamic model fetching and model search.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
lib/ai-settings.ts |
Adds modelUrl to provider presets and introduces async model fetching + hardcoded fallback helpers; updates settings hook behavior. |
components/project-sidebar.tsx |
Fetches models dynamically in settings UI and adds model search in the dropdown; refactors UI code formatting. |
README.md |
Documents dynamic model fetching and the model dropdown search bar. |
Comments suppressed due to low confidence (1)
lib/ai-settings.ts:299
loadAIConfig()now looks up the selected model only in the hardcoded lists and falls back tomodels[0].idwhen it can’t finds.modelId. With dynamic model loading, this will silently switch users to the first hardcoded model whenever they pick a model not present inAI_MODELS/OPENAI_MODELS/ZAI_MODELS(e.g. most OpenRouter models), causing requests to use a different model than the UI selection. Preserves.modelIdwhen it’s not in the hardcoded list, and only normalize IDs for the specific provider-switch case (like stripping anopenai/prefix when provider isopenai).
const models = getHardcodedModelsForProvider(s.provider)
const model = models.find(m => m.id === s.modelId)
// Use the matched model's id if found; otherwise fall back to the first model
// for this provider. This handles the case where localStorage still holds an
// OpenRouter-prefixed id (e.g. "openai/gpt-4o") after switching to OpenAI —
// that string won't match any entry in OPENAI_MODELS so we fall back to "gpt-4o".
const modelId = model?.id ?? models[0]?.id ?? s.modelId ?? DEFAULT_MODEL_ID
// Z.ai does not support grounding; only openrouter and openai do
const supportsGrounding =
(s.provider === "openrouter" || s.provider === "openai") &&
s.webGrounding &&
(model?.supportsGrounding ?? false)
return { apiKey: s.apiKey, modelId, supportsGrounding, provider: s.provider, customBaseUrl: s.customBaseUrl }
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| {/* Model Selector */} | ||
| <div className="flex flex-col gap-2"> | ||
| <label className="font-mono text-[9px] font-bold uppercase tracking-[0.2em] text-muted-foreground"> | ||
| Model | ||
| </label> | ||
| {models.length === 0 ? ( | ||
| <div className="flex items-center gap-2 rounded-md border border-white/10 bg-white/[0.04] px-2.5 py-2 focus-within:border-primary/50 transition-colors"> | ||
| <input | ||
| type="text" | ||
| value={draft.modelId} | ||
| onChange={e => setDraft(d => ({ ...d, modelId: e.target.value }))} | ||
| onChange={(e) => | ||
| setDraft((d) => ({ ...d, modelId: e.target.value })) | ||
| } | ||
| placeholder="e.g. gpt-4o, claude-3-opus-20240229" | ||
| className="flex-1 bg-transparent font-mono text-[11px] text-foreground outline-none placeholder:text-muted-foreground/40" | ||
| autoComplete="off" | ||
| spellCheck={false} | ||
| /> | ||
| </div> | ||
| ) : ( | ||
| <div className="relative"> | ||
| <button |
There was a problem hiding this comment.
Because models always falls back to getHardcodedModelsForProvider(draft.provider) when dynamic loading returns an empty list, models.length === 0 is effectively unreachable (the hardcoded lists are non-empty). This removes the UI path for manually entering a custom modelId, which is important when customBaseUrl points at an OpenAI-compatible endpoint with its own model names. Consider always providing a “Custom model…” option or keeping a text input available even when the dropdown is populated.
This pull request enhances the project sidebar and model selection experience, especially around provider/model management and searchability. The main improvements include dynamically fetching available models after entering an API key, adding a search bar to filter models, and refactoring the code for clarity and maintainability.
Enhancements to provider/model selection and settings:
These changes make it easier for users to manage AI providers and models, streamline the model selection process, and improve the overall codebase quality.