Skip to content

Commit efd8357

Browse files
committed
feat: add model availability checks for LMStudio and Ollama components
1 parent 9b38f80 commit efd8357

File tree

3 files changed

+103
-6
lines changed

3 files changed

+103
-6
lines changed

webview-ui/src/components/settings/providers/LMStudio.tsx

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useState } from "react"
1+
import { useCallback, useState, useMemo } from "react"
22
import { useEvent } from "react-use"
33
import { Trans } from "react-i18next"
44
import { Checkbox } from "vscrui"
@@ -8,6 +8,7 @@ import type { ProviderSettings } from "@roo-code/types"
88

99
import { useAppTranslation } from "@src/i18n/TranslationContext"
1010
import { ExtensionMessage } from "@roo/ExtensionMessage"
11+
import { useRouterModels } from "@src/components/ui/hooks/useRouterModels"
1112

1213
import { inputEventTransform } from "../transforms"
1314

@@ -20,6 +21,7 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
2021
const { t } = useAppTranslation()
2122

2223
const [lmStudioModels, setLmStudioModels] = useState<string[]>([])
24+
const routerModels = useRouterModels()
2325

2426
const handleInputChange = useCallback(
2527
<K extends keyof ProviderSettings, E>(
@@ -47,6 +49,48 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
4749

4850
useEvent("message", onMessage)
4951

52+
// Check if the selected model exists in the fetched models
53+
const modelNotAvailable = useMemo(() => {
54+
const selectedModel = apiConfiguration?.lmStudioModelId
55+
if (!selectedModel) return false
56+
57+
// Check if model exists in local LM Studio models
58+
if (lmStudioModels.length > 0 && lmStudioModels.includes(selectedModel)) {
59+
return false // Model is available locally
60+
}
61+
62+
// If we have router models data for LM Studio
63+
if (routerModels.data?.lmstudio) {
64+
const availableModels = Object.keys(routerModels.data.lmstudio)
65+
// Show warning if model is not in the list (regardless of how many models there are)
66+
return !availableModels.includes(selectedModel)
67+
}
68+
69+
// If neither source has loaded yet, don't show warning
70+
return false
71+
}, [apiConfiguration?.lmStudioModelId, routerModels.data, lmStudioModels])
72+
73+
// Check if the draft model exists
74+
const draftModelNotAvailable = useMemo(() => {
75+
const draftModel = apiConfiguration?.lmStudioDraftModelId
76+
if (!draftModel) return false
77+
78+
// Check if model exists in local LM Studio models
79+
if (lmStudioModels.length > 0 && lmStudioModels.includes(draftModel)) {
80+
return false // Model is available locally
81+
}
82+
83+
// If we have router models data for LM Studio
84+
if (routerModels.data?.lmstudio) {
85+
const availableModels = Object.keys(routerModels.data.lmstudio)
86+
// Show warning if model is not in the list (regardless of how many models there are)
87+
return !availableModels.includes(draftModel)
88+
}
89+
90+
// If neither source has loaded yet, don't show warning
91+
return false
92+
}, [apiConfiguration?.lmStudioDraftModelId, routerModels.data, lmStudioModels])
93+
5094
return (
5195
<>
5296
<VSCodeTextField
@@ -64,6 +108,16 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
64108
className="w-full">
65109
<label className="block font-medium mb-1">{t("settings:providers.lmStudio.modelId")}</label>
66110
</VSCodeTextField>
111+
{modelNotAvailable && (
112+
<div className="flex flex-col gap-2 text-vscode-errorForeground text-sm">
113+
<div className="flex flex-row items-center gap-1">
114+
<div className="codicon codicon-close" />
115+
<div>
116+
{t("settings:validation.modelAvailability", { modelId: apiConfiguration?.lmStudioModelId })}
117+
</div>
118+
</div>
119+
</div>
120+
)}
67121
{lmStudioModels.length > 0 && (
68122
<VSCodeRadioGroup
69123
value={
@@ -101,6 +155,18 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
101155
<div className="text-sm text-vscode-descriptionForeground">
102156
{t("settings:providers.lmStudio.draftModelDesc")}
103157
</div>
158+
{draftModelNotAvailable && (
159+
<div className="flex flex-col gap-2 text-vscode-errorForeground text-sm mt-2">
160+
<div className="flex flex-row items-center gap-1">
161+
<div className="codicon codicon-close" />
162+
<div>
163+
{t("settings:validation.modelAvailability", {
164+
modelId: apiConfiguration?.lmStudioDraftModelId,
165+
})}
166+
</div>
167+
</div>
168+
</div>
169+
)}
104170
</div>
105171
{lmStudioModels.length > 0 && (
106172
<>

webview-ui/src/components/settings/providers/Ollama.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useCallback } from "react"
1+
import { useState, useCallback, useMemo } from "react"
22
import { useEvent } from "react-use"
33
import { VSCodeTextField, VSCodeRadioGroup, VSCodeRadio } from "@vscode/webview-ui-toolkit/react"
44

@@ -7,6 +7,7 @@ import type { ProviderSettings } from "@roo-code/types"
77
import { ExtensionMessage } from "@roo/ExtensionMessage"
88

99
import { useAppTranslation } from "@src/i18n/TranslationContext"
10+
import { useRouterModels } from "@src/components/ui/hooks/useRouterModels"
1011

1112
import { inputEventTransform } from "../transforms"
1213

@@ -19,6 +20,7 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro
1920
const { t } = useAppTranslation()
2021

2122
const [ollamaModels, setOllamaModels] = useState<string[]>([])
23+
const routerModels = useRouterModels()
2224

2325
const handleInputChange = useCallback(
2426
<K extends keyof ProviderSettings, E>(
@@ -46,6 +48,27 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro
4648

4749
useEvent("message", onMessage)
4850

51+
// Check if the selected model exists in the fetched models
52+
const modelNotAvailable = useMemo(() => {
53+
const selectedModel = apiConfiguration?.ollamaModelId
54+
if (!selectedModel) return false
55+
56+
// Check if model exists in local ollama models
57+
if (ollamaModels.length > 0 && ollamaModels.includes(selectedModel)) {
58+
return false // Model is available locally
59+
}
60+
61+
// If we have router models data for Ollama
62+
if (routerModels.data?.ollama) {
63+
const availableModels = Object.keys(routerModels.data.ollama)
64+
// Show warning if model is not in the list (regardless of how many models there are)
65+
return !availableModels.includes(selectedModel)
66+
}
67+
68+
// If neither source has loaded yet, don't show warning
69+
return false
70+
}, [apiConfiguration?.ollamaModelId, routerModels.data, ollamaModels])
71+
4972
return (
5073
<>
5174
<VSCodeTextField
@@ -63,6 +86,16 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro
6386
className="w-full">
6487
<label className="block font-medium mb-1">{t("settings:providers.ollama.modelId")}</label>
6588
</VSCodeTextField>
89+
{modelNotAvailable && (
90+
<div className="flex flex-col gap-2 text-vscode-errorForeground text-sm">
91+
<div className="flex flex-row items-center gap-1">
92+
<div className="codicon codicon-close" />
93+
<div>
94+
{t("settings:validation.modelAvailability", { modelId: apiConfiguration?.ollamaModelId })}
95+
</div>
96+
</div>
97+
</div>
98+
)}
6699
{ollamaModels.length > 0 && (
67100
<VSCodeRadioGroup
68101
value={

webview-ui/src/components/ui/hooks/useSelectedModel.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ import {
3030
glamaDefaultModelId,
3131
unboundDefaultModelId,
3232
litellmDefaultModelId,
33-
lMStudioDefaultModelInfo,
34-
ollamaDefaultModelInfo,
3533
} from "@roo-code/types"
3634

3735
import type { RouterModels } from "@roo/api"
@@ -182,15 +180,15 @@ function getSelectedModel({
182180
const info = routerModels.ollama && routerModels.ollama[id]
183181
return {
184182
id,
185-
info: info ? info : ollamaDefaultModelInfo,
183+
info: info || undefined,
186184
}
187185
}
188186
case "lmstudio": {
189187
const id = apiConfiguration.lmStudioModelId ?? ""
190188
const info = routerModels.lmstudio && routerModels.lmstudio[id]
191189
return {
192190
id,
193-
info: info ? info : lMStudioDefaultModelInfo,
191+
info: info || undefined,
194192
}
195193
}
196194
case "vscode-lm": {

0 commit comments

Comments
 (0)