Skip to content

Commit 4b2a54e

Browse files
authored
Allow manually selecting a model in the model picker (#1809)
1 parent b83c0b3 commit 4b2a54e

File tree

18 files changed

+145
-19
lines changed

18 files changed

+145
-19
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Allow manually selecting a model in the model picker

webview-ui/src/components/settings/ModelPicker.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,17 @@ export const ModelPicker = ({
6868
[apiConfiguration],
6969
)
7070

71-
const [searchValue, setSearchValue] = useState(selectedModelId)
71+
const [searchValue, setSearchValue] = useState(selectedModelId || "")
7272

7373
const onSelect = useCallback(
7474
(modelId: string) => {
75+
if (!modelId) return
76+
7577
setOpen(false)
7678
const modelInfo = models?.[modelId]
7779
setApiConfigurationField(modelIdKey, modelId)
7880
setApiConfigurationField(modelInfoKey, modelInfo ?? defaultModelInfo)
81+
7982
// Delay to ensure the popover is closed before setting the search value.
8083
setTimeout(() => setSearchValue(modelId), 100)
8184
},
@@ -112,7 +115,7 @@ export const ModelPicker = ({
112115
return (
113116
<>
114117
<div>
115-
<label className="block font-medium mb-1">Model</label>
118+
<label className="block font-medium mb-1">{t("settings:modelPicker.label")}</label>
116119
<Popover open={open} onOpenChange={onOpenChange}>
117120
<PopoverTrigger asChild>
118121
<Button
@@ -131,7 +134,7 @@ export const ModelPicker = ({
131134
ref={searchInputRef}
132135
value={searchValue}
133136
onValueChange={setSearchValue}
134-
placeholder="Search"
137+
placeholder={t("settings:modelPicker.searchPlaceholder")}
135138
className="h-9 mr-4"
136139
data-testid="model-input"
137140
/>
@@ -145,7 +148,13 @@ export const ModelPicker = ({
145148
)}
146149
</div>
147150
<CommandList>
148-
<CommandEmpty>No model found.</CommandEmpty>
151+
<CommandEmpty>
152+
{searchValue && (
153+
<div className="py-2 px-1 text-sm">
154+
{t("settings:modelPicker.noMatchFound")}
155+
</div>
156+
)}
157+
</CommandEmpty>
149158
<CommandGroup>
150159
{modelIds.map((model) => (
151160
<CommandItem key={model} value={model} onSelect={onSelect}>
@@ -160,6 +169,13 @@ export const ModelPicker = ({
160169
))}
161170
</CommandGroup>
162171
</CommandList>
172+
{searchValue && !modelIds.includes(searchValue) && (
173+
<div className="p-1 border-t border-vscode-input-border">
174+
<CommandItem data-testid="use-custom-model" value={searchValue} onSelect={onSelect}>
175+
{t("settings:modelPicker.useCustomModel", { modelId: searchValue })}
176+
</CommandItem>
177+
</div>
178+
)}
163179
</Command>
164180
</PopoverContent>
165181
</Popover>

webview-ui/src/components/settings/__tests__/ModelPicker.test.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,49 @@ describe("ModelPicker", () => {
8686
expect(mockSetApiConfigurationField).toHaveBeenCalledWith(defaultProps.modelIdKey, "model2")
8787
expect(mockSetApiConfigurationField).toHaveBeenCalledWith(defaultProps.modelInfoKey, mockModels.model2)
8888
})
89+
90+
it("allows setting a custom model ID that's not in the predefined list", async () => {
91+
await act(async () => {
92+
render(<ModelPicker {...defaultProps} />)
93+
})
94+
95+
await act(async () => {
96+
// Open the popover by clicking the button.
97+
const button = screen.getByRole("combobox")
98+
fireEvent.click(button)
99+
})
100+
101+
// Wait for popover to open and animations to complete.
102+
await act(async () => {
103+
await new Promise((resolve) => setTimeout(resolve, 100))
104+
})
105+
106+
const customModelId = "custom-model-id"
107+
108+
await act(async () => {
109+
// Find and set the input value to a custom model ID
110+
const modelInput = screen.getByTestId("model-input")
111+
fireEvent.input(modelInput, { target: { value: customModelId } })
112+
})
113+
114+
// Wait for the UI to update
115+
await act(async () => {
116+
await new Promise((resolve) => setTimeout(resolve, 100))
117+
})
118+
119+
// Find and click the "Use custom" option
120+
await act(async () => {
121+
// Look for text containing our custom model ID
122+
const customOption = screen.getByTestId("use-custom-model")
123+
fireEvent.click(customOption)
124+
})
125+
126+
// Verify the API config was updated with the custom model ID
127+
expect(mockSetApiConfigurationField).toHaveBeenCalledWith(defaultProps.modelIdKey, customModelId)
128+
// The model info should be set to the default since this is a custom model
129+
expect(mockSetApiConfigurationField).toHaveBeenCalledWith(
130+
defaultProps.modelInfoKey,
131+
defaultProps.defaultModelInfo,
132+
)
133+
})
89134
})

webview-ui/src/i18n/locales/ca/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,11 @@
353353
"azureApiVersion": "Establir versió de l'API d'Azure"
354354
},
355355
"modelPicker": {
356-
"automaticFetch": "L'extensió obté automàticament la llista més recent de models disponibles a <serviceLink>{{serviceName}}</serviceLink>. Si no esteu segur de quin model triar, Roo Code funciona millor amb <defaultModelLink>{{defaultModelId}}</defaultModelLink>. També podeu cercar \"free\" per a opcions gratuïtes actualment disponibles."
356+
"automaticFetch": "L'extensió obté automàticament la llista més recent de models disponibles a <serviceLink>{{serviceName}}</serviceLink>. Si no esteu segur de quin model triar, Roo Code funciona millor amb <defaultModelLink>{{defaultModelId}}</defaultModelLink>. També podeu cercar \"free\" per a opcions gratuïtes actualment disponibles.",
357+
"label": "Model",
358+
"searchPlaceholder": "Cerca",
359+
"noMatchFound": "No s'ha trobat cap coincidència",
360+
"useCustomModel": "Utilitzar personalitzat: {{modelId}}"
357361
},
358362
"footer": {
359363
"feedback": "Si teniu qualsevol pregunta o comentari, no dubteu a obrir un issue a <githubLink>github.com/RooVetGit/Roo-Code</githubLink> o unir-vos a <redditLink>reddit.com/r/RooCode</redditLink> o <discordLink>discord.gg/roocode</discordLink>",

webview-ui/src/i18n/locales/de/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,11 @@
353353
}
354354
},
355355
"modelPicker": {
356-
"automaticFetch": "Die Erweiterung ruft automatisch die neueste Liste der verfügbaren Modelle von <serviceLink>{{serviceName}}</serviceLink> ab. Wenn Sie sich nicht sicher sind, welches Modell Sie wählen sollen, funktioniert Roo Code am besten mit <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Sie können auch nach \"free\" suchen, um derzeit verfügbare kostenlose Optionen zu finden."
356+
"automaticFetch": "Die Erweiterung ruft automatisch die neueste Liste der verfügbaren Modelle von <serviceLink>{{serviceName}}</serviceLink> ab. Wenn Sie sich nicht sicher sind, welches Modell Sie wählen sollen, funktioniert Roo Code am besten mit <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Sie können auch nach \"free\" suchen, um derzeit verfügbare kostenlose Optionen zu finden.",
357+
"label": "Modell",
358+
"searchPlaceholder": "Suchen",
359+
"noMatchFound": "Keine Übereinstimmung gefunden",
360+
"useCustomModel": "Benutzerdefiniert verwenden: {{modelId}}"
357361
},
358362
"footer": {
359363
"feedback": "Wenn Sie Fragen oder Feedback haben, können Sie gerne ein Issue auf <githubLink>github.com/RooVetGit/Roo-Code</githubLink> öffnen oder <redditLink>reddit.com/r/RooCode</redditLink> oder <discordLink>discord.gg/roocode</discordLink> beitreten",

webview-ui/src/i18n/locales/en/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,11 @@
353353
}
354354
},
355355
"modelPicker": {
356-
"automaticFetch": "The extension automatically fetches the latest list of models available on <serviceLink>{{serviceName}}</serviceLink>. If you're unsure which model to choose, Roo Code works best with <defaultModelLink>{{defaultModelId}}</defaultModelLink>. You can also try searching \"free\" for no-cost options currently available."
356+
"automaticFetch": "The extension automatically fetches the latest list of models available on <serviceLink>{{serviceName}}</serviceLink>. If you're unsure which model to choose, Roo Code works best with <defaultModelLink>{{defaultModelId}}</defaultModelLink>. You can also try searching \"free\" for no-cost options currently available.",
357+
"label": "Model",
358+
"searchPlaceholder": "Search",
359+
"noMatchFound": "No match found",
360+
"useCustomModel": "Use custom: {{modelId}}"
357361
},
358362
"footer": {
359363
"feedback": "If you have any questions or feedback, feel free to open an issue at <githubLink>github.com/RooVetGit/Roo-Code</githubLink> or join <redditLink>reddit.com/r/RooCode</redditLink> or <discordLink>discord.gg/roocode</discordLink>",

webview-ui/src/i18n/locales/es/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,11 @@
353353
}
354354
},
355355
"modelPicker": {
356-
"automaticFetch": "La extensión obtiene automáticamente la lista más reciente de modelos disponibles en <serviceLink>{{serviceName}}</serviceLink>. Si no está seguro de qué modelo elegir, Roo Code funciona mejor con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. También puede buscar \"free\" para opciones sin costo actualmente disponibles."
356+
"automaticFetch": "La extensión obtiene automáticamente la lista más reciente de modelos disponibles en <serviceLink>{{serviceName}}</serviceLink>. Si no está seguro de qué modelo elegir, Roo Code funciona mejor con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. También puede buscar \"free\" para opciones sin costo actualmente disponibles.",
357+
"label": "Modelo",
358+
"searchPlaceholder": "Buscar",
359+
"noMatchFound": "No se encontraron coincidencias",
360+
"useCustomModel": "Usar personalizado: {{modelId}}"
357361
},
358362
"footer": {
359363
"feedback": "Si tiene alguna pregunta o comentario, no dude en abrir un issue en <githubLink>github.com/RooVetGit/Roo-Code</githubLink> o unirse a <redditLink>reddit.com/r/RooCode</redditLink> o <discordLink>discord.gg/roocode</discordLink>",

webview-ui/src/i18n/locales/fr/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,11 @@
353353
}
354354
},
355355
"modelPicker": {
356-
"automaticFetch": "L'extension récupère automatiquement la liste la plus récente des modèles disponibles sur <serviceLink>{{serviceName}}</serviceLink>. Si vous ne savez pas quel modèle choisir, Roo Code fonctionne mieux avec <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Vous pouvez également rechercher \"free\" pour les options gratuites actuellement disponibles."
356+
"automaticFetch": "L'extension récupère automatiquement la liste la plus récente des modèles disponibles sur <serviceLink>{{serviceName}}</serviceLink>. Si vous ne savez pas quel modèle choisir, Roo Code fonctionne mieux avec <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Vous pouvez également rechercher \"free\" pour les options gratuites actuellement disponibles.",
357+
"label": "Modèle",
358+
"searchPlaceholder": "Rechercher",
359+
"noMatchFound": "Aucune correspondance trouvée",
360+
"useCustomModel": "Utiliser personnalisé : {{modelId}}"
357361
},
358362
"footer": {
359363
"feedback": "Si vous avez des questions ou des commentaires, n'hésitez pas à ouvrir un problème sur <githubLink>github.com/RooVetGit/Roo-Code</githubLink> ou à rejoindre <redditLink>reddit.com/r/RooCode</redditLink> ou <discordLink>discord.gg/roocode</discordLink>",

webview-ui/src/i18n/locales/hi/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,11 @@
353353
}
354354
},
355355
"modelPicker": {
356-
"automaticFetch": "एक्सटेंशन <serviceLink>{{serviceName}}</serviceLink> पर उपलब्ध मॉडलों की नवीनतम सूची स्वचालित रूप से प्राप्त करता है। यदि आप अनिश्चित हैं कि कौन सा मॉडल चुनना है, तो Roo Code <defaultModelLink>{{defaultModelId}}</defaultModelLink> के साथ सबसे अच्छा काम करता है। आप वर्तमान में उपलब्ध निःशुल्क विकल्पों के लिए \"free\" भी खोज सकते हैं।"
356+
"automaticFetch": "एक्सटेंशन <serviceLink>{{serviceName}}</serviceLink> पर उपलब्ध मॉडलों की नवीनतम सूची स्वचालित रूप से प्राप्त करता है। यदि आप अनिश्चित हैं कि कौन सा मॉडल चुनना है, तो Roo Code <defaultModelLink>{{defaultModelId}}</defaultModelLink> के साथ सबसे अच्छा काम करता है। आप वर्तमान में उपलब्ध निःशुल्क विकल्पों के लिए \"free\" भी खोज सकते हैं।",
357+
"label": "मॉडल",
358+
"searchPlaceholder": "खोजें",
359+
"noMatchFound": "कोई मिलान नहीं मिला",
360+
"useCustomModel": "कस्टम उपयोग करें: {{modelId}}"
357361
},
358362
"footer": {
359363
"feedback": "यदि आपके कोई प्रश्न या प्रतिक्रिया है, तो <githubLink>github.com/RooVetGit/Roo-Code</githubLink> पर एक मुद्दा खोलने या <redditLink>reddit.com/r/RooCode</redditLink> या <discordLink>discord.gg/roocode</discordLink> में शामिल होने में संकोच न करें",

webview-ui/src/i18n/locales/it/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,11 @@
353353
}
354354
},
355355
"modelPicker": {
356-
"automaticFetch": "L'estensione recupera automaticamente l'elenco più recente dei modelli disponibili su <serviceLink>{{serviceName}}</serviceLink>. Se non sei sicuro di quale modello scegliere, Roo Code funziona meglio con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Puoi anche cercare \"free\" per opzioni gratuite attualmente disponibili."
356+
"automaticFetch": "L'estensione recupera automaticamente l'elenco più recente dei modelli disponibili su <serviceLink>{{serviceName}}</serviceLink>. Se non sei sicuro di quale modello scegliere, Roo Code funziona meglio con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Puoi anche cercare \"free\" per opzioni gratuite attualmente disponibili.",
357+
"label": "Modello",
358+
"searchPlaceholder": "Cerca",
359+
"noMatchFound": "Nessuna corrispondenza trovata",
360+
"useCustomModel": "Usa personalizzato: {{modelId}}"
357361
},
358362
"footer": {
359363
"feedback": "Se hai domande o feedback, sentiti libero di aprire un issue su <githubLink>github.com/RooVetGit/Roo-Code</githubLink> o unirti a <redditLink>reddit.com/r/RooCode</redditLink> o <discordLink>discord.gg/roocode</discordLink>",

0 commit comments

Comments
 (0)