mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com> Co-authored-by: Daniel Riccio <ricciodaniel98@gmail.com>
This commit is contained in:
parent
74672fafcb
commit
1a013b4416
12 changed files with 223 additions and 32 deletions
|
|
@ -118,7 +118,7 @@ describe("LMStudio Fetcher", () => {
|
|||
expect(MockedLMStudioClientConstructor).toHaveBeenCalledWith({ baseUrl: lmsUrl })
|
||||
expect(mockListDownloadedModels).toHaveBeenCalledTimes(1)
|
||||
expect(mockListDownloadedModels).toHaveBeenCalledWith("llm")
|
||||
expect(mockListLoaded).not.toHaveBeenCalled()
|
||||
expect(mockListLoaded).toHaveBeenCalled() // we now call it to get context data
|
||||
|
||||
const expectedParsedModel = parseLMStudioModel(mockLLMInfo)
|
||||
expect(result).toEqual({ [mockLLMInfo.path]: expectedParsedModel })
|
||||
|
|
|
|||
|
|
@ -1,6 +1,38 @@
|
|||
import { ModelInfo, lMStudioDefaultModelInfo } from "@roo-code/types"
|
||||
import { LLM, LLMInfo, LLMInstanceInfo, LMStudioClient } from "@lmstudio/sdk"
|
||||
import axios from "axios"
|
||||
import { flushModels, getModels } from "./modelCache"
|
||||
|
||||
const modelsWithLoadedDetails = new Set<string>()
|
||||
|
||||
export const hasLoadedFullDetails = (modelId: string): boolean => {
|
||||
return modelsWithLoadedDetails.has(modelId)
|
||||
}
|
||||
|
||||
export const forceFullModelDetailsLoad = async (baseUrl: string, modelId: string): Promise<void> => {
|
||||
try {
|
||||
// test the connection to LM Studio first
|
||||
// errors will be caught further down
|
||||
await axios.get(`${baseUrl}/v1/models`)
|
||||
const lmsUrl = baseUrl.replace(/^http:\/\//, "ws://").replace(/^https:\/\//, "wss://")
|
||||
|
||||
const client = new LMStudioClient({ baseUrl: lmsUrl })
|
||||
await client.llm.model(modelId)
|
||||
await flushModels("lmstudio")
|
||||
await getModels({ provider: "lmstudio" }) // force cache update now
|
||||
|
||||
// Mark this model as having full details loaded
|
||||
modelsWithLoadedDetails.add(modelId)
|
||||
} catch (error) {
|
||||
if (error.code === "ECONNREFUSED") {
|
||||
console.warn(`Error connecting to LMStudio at ${baseUrl}`)
|
||||
} else {
|
||||
console.error(
|
||||
`Error refreshing LMStudio model details: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const parseLMStudioModel = (rawModel: LLMInstanceInfo | LLMInfo): ModelInfo => {
|
||||
// Handle both LLMInstanceInfo (from loaded models) and LLMInfo (from downloaded models)
|
||||
|
|
@ -19,6 +51,8 @@ export const parseLMStudioModel = (rawModel: LLMInstanceInfo | LLMInfo): ModelIn
|
|||
}
|
||||
|
||||
export async function getLMStudioModels(baseUrl = "http://localhost:1234"): Promise<Record<string, ModelInfo>> {
|
||||
// clear the set of models that have full details loaded
|
||||
modelsWithLoadedDetails.clear()
|
||||
// clearing the input can leave an empty string; use the default in that case
|
||||
baseUrl = baseUrl === "" ? "http://localhost:1234" : baseUrl
|
||||
|
||||
|
|
@ -46,15 +80,15 @@ export async function getLMStudioModels(baseUrl = "http://localhost:1234"): Prom
|
|||
}
|
||||
} catch (error) {
|
||||
console.warn("Failed to list downloaded models, falling back to loaded models only")
|
||||
}
|
||||
// We want to list loaded models *anyway* since they provide valuable extra info (context size)
|
||||
const loadedModels = (await client.llm.listLoaded().then((models: LLM[]) => {
|
||||
return Promise.all(models.map((m) => m.getModelInfo()))
|
||||
})) as Array<LLMInstanceInfo>
|
||||
|
||||
// Fall back to listing only loaded models
|
||||
const loadedModels = (await client.llm.listLoaded().then((models: LLM[]) => {
|
||||
return Promise.all(models.map((m) => m.getModelInfo()))
|
||||
})) as Array<LLMInstanceInfo>
|
||||
|
||||
for (const lmstudioModel of loadedModels) {
|
||||
models[lmstudioModel.modelKey] = parseLMStudioModel(lmstudioModel)
|
||||
}
|
||||
for (const lmstudioModel of loadedModels) {
|
||||
models[lmstudioModel.modelKey] = parseLMStudioModel(lmstudioModel)
|
||||
modelsWithLoadedDetails.add(lmstudioModel.modelKey)
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === "ECONNREFUSED") {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ async function readModels(router: RouterName): Promise<ModelRecord | undefined>
|
|||
*/
|
||||
export const getModels = async (options: GetModelsOptions): Promise<ModelRecord> => {
|
||||
const { provider } = options
|
||||
let models = memoryCache.get<ModelRecord>(provider)
|
||||
let models = getModelsFromCache(provider)
|
||||
if (models) {
|
||||
return models
|
||||
}
|
||||
|
|
@ -113,3 +113,7 @@ export const getModels = async (options: GetModelsOptions): Promise<ModelRecord>
|
|||
export const flushModels = async (router: RouterName) => {
|
||||
memoryCache.del(router)
|
||||
}
|
||||
|
||||
export function getModelsFromCache(provider: string) {
|
||||
return memoryCache.get<ModelRecord>(provider)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { ApiStream } from "../transform/stream"
|
|||
|
||||
import { BaseProvider } from "./base-provider"
|
||||
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
|
||||
import { getModels, getModelsFromCache } from "./fetchers/modelCache"
|
||||
|
||||
export class LmStudioHandler extends BaseProvider implements SingleCompletionHandler {
|
||||
protected options: ApiHandlerOptions
|
||||
|
|
@ -131,9 +132,17 @@ export class LmStudioHandler extends BaseProvider implements SingleCompletionHan
|
|||
}
|
||||
|
||||
override getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
id: this.options.lmStudioModelId || "",
|
||||
info: openAiModelInfoSaneDefaults,
|
||||
const models = getModelsFromCache("lmstudio")
|
||||
if (models && this.options.lmStudioModelId && models[this.options.lmStudioModelId]) {
|
||||
return {
|
||||
id: this.options.lmStudioModelId,
|
||||
info: models[this.options.lmStudioModelId],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
id: this.options.lmStudioModelId || "",
|
||||
info: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ import { WebviewMessage } from "../../shared/WebviewMessage"
|
|||
import { EMBEDDING_MODEL_PROFILES } from "../../shared/embeddingModels"
|
||||
import { ProfileValidator } from "../../shared/ProfileValidator"
|
||||
import { getWorkspaceGitInfo } from "../../utils/git"
|
||||
import { forceFullModelDetailsLoad, hasLoadedFullDetails } from "../../api/providers/fetchers/lmstudio"
|
||||
|
||||
/**
|
||||
* https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
|
||||
|
|
@ -163,6 +164,9 @@ export class ClineProvider
|
|||
// Add this cline instance into the stack that represents the order of all the called tasks.
|
||||
this.clineStack.push(cline)
|
||||
|
||||
// Perform special setup provider specific tasks
|
||||
await this.performPreparationTasks(cline)
|
||||
|
||||
// Ensure getState() resolves correctly.
|
||||
const state = await this.getState()
|
||||
|
||||
|
|
@ -171,6 +175,23 @@ export class ClineProvider
|
|||
}
|
||||
}
|
||||
|
||||
async performPreparationTasks(cline: Task) {
|
||||
// LMStudio: we need to force model loading in order to read its context size; we do it now since we're starting a task with that model selected
|
||||
if (cline.apiConfiguration && cline.apiConfiguration.apiProvider === "lmstudio") {
|
||||
try {
|
||||
if (!hasLoadedFullDetails(cline.apiConfiguration.lmStudioModelId!)) {
|
||||
await forceFullModelDetailsLoad(
|
||||
cline.apiConfiguration.lmStudioBaseUrl ?? "http://localhost:1234",
|
||||
cline.apiConfiguration.lmStudioModelId!,
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
this.log(`Failed to load full model details for LM Studio: ${error}`)
|
||||
vscode.window.showErrorMessage(error.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Removes and destroys the top Cline instance (the current finished task),
|
||||
// activating the previous one (resuming the parent task).
|
||||
async removeClineFromStack() {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { Task, TaskOptions } from "../../task/Task"
|
|||
import { safeWriteJson } from "../../../utils/safeWriteJson"
|
||||
|
||||
import { ClineProvider } from "../ClineProvider"
|
||||
import { AsyncInvokeOutputDataConfig } from "@aws-sdk/client-bedrock-runtime"
|
||||
|
||||
// Mock setup must come before imports
|
||||
vi.mock("../../prompts/sections/custom-instructions")
|
||||
|
|
@ -2840,6 +2841,33 @@ describe("ClineProvider - Router Models", () => {
|
|||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("handles requestLmStudioModels with proper response", async () => {
|
||||
await provider.resolveWebviewView(mockWebviewView)
|
||||
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]
|
||||
|
||||
vi.spyOn(provider, "getState").mockResolvedValue({
|
||||
apiConfiguration: {
|
||||
lmStudioModelId: "model-1",
|
||||
lmStudioBaseUrl: "http://localhost:1234",
|
||||
},
|
||||
} as any)
|
||||
|
||||
const mockModels = {
|
||||
"model-1": { maxTokens: 4096, contextWindow: 8192, description: "Test model", supportsPromptCache: false },
|
||||
}
|
||||
const { getModels } = await import("../../../api/providers/fetchers/modelCache")
|
||||
vi.mocked(getModels).mockResolvedValue(mockModels)
|
||||
|
||||
await messageHandler({
|
||||
type: "requestLmStudioModels",
|
||||
})
|
||||
|
||||
expect(getModels).toHaveBeenCalledWith({
|
||||
provider: "lmstudio",
|
||||
baseUrl: "http://localhost:1234",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
|
||||
|
|
|
|||
|
|
@ -94,6 +94,48 @@ vi.mock("../../../utils/fs")
|
|||
vi.mock("../../../utils/path")
|
||||
vi.mock("../../../utils/globalContext")
|
||||
|
||||
describe("webviewMessageHandler - requestLmStudioModels", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockClineProvider.getState = vi.fn().mockResolvedValue({
|
||||
apiConfiguration: {
|
||||
lmStudioModelId: "model-1",
|
||||
lmStudioBaseUrl: "http://localhost:1234",
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("successfully fetches models from LMStudio", async () => {
|
||||
const mockModels: ModelRecord = {
|
||||
"model-1": {
|
||||
maxTokens: 4096,
|
||||
contextWindow: 8192,
|
||||
supportsPromptCache: false,
|
||||
description: "Test model 1",
|
||||
},
|
||||
"model-2": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 16384,
|
||||
supportsPromptCache: false,
|
||||
description: "Test model 2",
|
||||
},
|
||||
}
|
||||
|
||||
mockGetModels.mockResolvedValue(mockModels)
|
||||
|
||||
await webviewMessageHandler(mockClineProvider, {
|
||||
type: "requestLmStudioModels",
|
||||
})
|
||||
|
||||
expect(mockGetModels).toHaveBeenCalledWith({ provider: "lmstudio", baseUrl: "http://localhost:1234" })
|
||||
|
||||
expect(mockClineProvider.postMessageToWebview).toHaveBeenCalledWith({
|
||||
type: "lmStudioModels",
|
||||
lmStudioModels: mockModels,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("webviewMessageHandler - requestRouterModels", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
|
|
|||
|
|
@ -584,7 +584,7 @@ export const webviewMessageHandler = async (
|
|||
} else if (routerName === "lmstudio" && Object.keys(result.value.models).length > 0) {
|
||||
provider.postMessageToWebview({
|
||||
type: "lmStudioModels",
|
||||
lmStudioModels: Object.keys(result.value.models),
|
||||
lmStudioModels: result.value.models,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
|
@ -648,7 +648,7 @@ export const webviewMessageHandler = async (
|
|||
if (Object.keys(lmStudioModels).length > 0) {
|
||||
provider.postMessageToWebview({
|
||||
type: "lmStudioModels",
|
||||
lmStudioModels: Object.keys(lmStudioModels),
|
||||
lmStudioModels: lmStudioModels,
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { GitCommit } from "../utils/git"
|
|||
|
||||
import { McpServer } from "./mcp"
|
||||
import { Mode } from "./modes"
|
||||
import { RouterModels } from "./api"
|
||||
import { ModelRecord, RouterModels } from "./api"
|
||||
import type { MarketplaceItem } from "@roo-code/types"
|
||||
|
||||
// Command interface for frontend/backend communication
|
||||
|
|
@ -146,7 +146,7 @@ export interface ExtensionMessage {
|
|||
routerModels?: RouterModels
|
||||
openAiModels?: string[]
|
||||
ollamaModels?: string[]
|
||||
lmStudioModels?: string[]
|
||||
lmStudioModels?: ModelRecord
|
||||
vsCodeLmModels?: { vendor?: string; family?: string; version?: string; id?: string }[]
|
||||
huggingFaceModels?: Array<{
|
||||
id: string
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { useRouterModels } from "@src/components/ui/hooks/useRouterModels"
|
|||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
import { inputEventTransform } from "../transforms"
|
||||
import { ModelRecord } from "@roo/api"
|
||||
|
||||
type LMStudioProps = {
|
||||
apiConfiguration: ProviderSettings
|
||||
|
|
@ -21,7 +22,7 @@ type LMStudioProps = {
|
|||
export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudioProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const [lmStudioModels, setLmStudioModels] = useState<string[]>([])
|
||||
const [lmStudioModels, setLmStudioModels] = useState<ModelRecord>({})
|
||||
const routerModels = useRouterModels()
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
|
|
@ -41,7 +42,7 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
|
|||
switch (message.type) {
|
||||
case "lmStudioModels":
|
||||
{
|
||||
const newModels = message.lmStudioModels ?? []
|
||||
const newModels = message.lmStudioModels ?? {}
|
||||
setLmStudioModels(newModels)
|
||||
}
|
||||
break
|
||||
|
|
@ -62,7 +63,7 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
|
|||
if (!selectedModel) return false
|
||||
|
||||
// Check if model exists in local LM Studio models
|
||||
if (lmStudioModels.length > 0 && lmStudioModels.includes(selectedModel)) {
|
||||
if (Object.keys(lmStudioModels).length > 0 && selectedModel in lmStudioModels) {
|
||||
return false // Model is available locally
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +84,7 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
|
|||
if (!draftModel) return false
|
||||
|
||||
// Check if model exists in local LM Studio models
|
||||
if (lmStudioModels.length > 0 && lmStudioModels.includes(draftModel)) {
|
||||
if (Object.keys(lmStudioModels).length > 0 && draftModel in lmStudioModels) {
|
||||
return false // Model is available locally
|
||||
}
|
||||
|
||||
|
|
@ -125,15 +126,15 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{lmStudioModels.length > 0 && (
|
||||
{Object.keys(lmStudioModels).length > 0 && (
|
||||
<VSCodeRadioGroup
|
||||
value={
|
||||
lmStudioModels.includes(apiConfiguration?.lmStudioModelId || "")
|
||||
(apiConfiguration?.lmStudioModelId || "") in lmStudioModels
|
||||
? apiConfiguration?.lmStudioModelId
|
||||
: ""
|
||||
}
|
||||
onChange={handleInputChange("lmStudioModelId")}>
|
||||
{lmStudioModels.map((model) => (
|
||||
{Object.keys(lmStudioModels).map((model) => (
|
||||
<VSCodeRadio key={model} value={model} checked={apiConfiguration?.lmStudioModelId === model}>
|
||||
{model}
|
||||
</VSCodeRadio>
|
||||
|
|
@ -175,23 +176,23 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
{lmStudioModels.length > 0 && (
|
||||
{Object.keys(lmStudioModels).length > 0 && (
|
||||
<>
|
||||
<div className="font-medium">{t("settings:providers.lmStudio.selectDraftModel")}</div>
|
||||
<VSCodeRadioGroup
|
||||
value={
|
||||
lmStudioModels.includes(apiConfiguration?.lmStudioDraftModelId || "")
|
||||
(apiConfiguration?.lmStudioDraftModelId || "") in lmStudioModels
|
||||
? apiConfiguration?.lmStudioDraftModelId
|
||||
: ""
|
||||
}
|
||||
onChange={handleInputChange("lmStudioDraftModelId")}>
|
||||
{lmStudioModels.map((model) => (
|
||||
{Object.keys(lmStudioModels).map((model) => (
|
||||
<VSCodeRadio key={`draft-${model}`} value={model}>
|
||||
{model}
|
||||
</VSCodeRadio>
|
||||
))}
|
||||
</VSCodeRadioGroup>
|
||||
{lmStudioModels.length === 0 && (
|
||||
{Object.keys(lmStudioModels).length === 0 && (
|
||||
<div
|
||||
className="text-sm rounded-xs p-2"
|
||||
style={{
|
||||
|
|
|
|||
39
webview-ui/src/components/ui/hooks/useLmStudioModels.ts
Normal file
39
webview-ui/src/components/ui/hooks/useLmStudioModels.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
import { ModelRecord } from "@roo/api"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
const getLmStudioModels = async () =>
|
||||
new Promise<ModelRecord>((resolve, reject) => {
|
||||
const cleanup = () => {
|
||||
window.removeEventListener("message", handler)
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
cleanup()
|
||||
reject(new Error("LM Studio models request timed out"))
|
||||
}, 10000)
|
||||
|
||||
const handler = (event: MessageEvent) => {
|
||||
const message: ExtensionMessage = event.data
|
||||
|
||||
if (message.type === "lmStudioModels") {
|
||||
clearTimeout(timeout)
|
||||
cleanup()
|
||||
|
||||
if (message.lmStudioModels) {
|
||||
resolve(message.lmStudioModels)
|
||||
} else {
|
||||
reject(new Error("No LMStudio models in response"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("message", handler)
|
||||
vscode.postMessage({ type: "requestLmStudioModels" })
|
||||
})
|
||||
|
||||
export const useLmStudioModels = (modelId?: string) =>
|
||||
useQuery({ queryKey: ["lmStudioModels"], queryFn: () => (modelId ? getLmStudioModels() : {}) })
|
||||
|
|
@ -40,20 +40,24 @@ import {
|
|||
doubaoDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import type { ModelRecord, RouterModels } from "@roo/api"
|
||||
|
||||
import { useRouterModels } from "./useRouterModels"
|
||||
import { useOpenRouterModelProviders } from "./useOpenRouterModelProviders"
|
||||
import { useLmStudioModels } from "./useLmStudioModels"
|
||||
|
||||
export const useSelectedModel = (apiConfiguration?: ProviderSettings) => {
|
||||
const provider = apiConfiguration?.apiProvider || "anthropic"
|
||||
const openRouterModelId = provider === "openrouter" ? apiConfiguration?.openRouterModelId : undefined
|
||||
const lmStudioModelId = provider === "lmstudio" ? apiConfiguration?.lmStudioModelId : undefined
|
||||
|
||||
const routerModels = useRouterModels()
|
||||
const openRouterModelProviders = useOpenRouterModelProviders(openRouterModelId)
|
||||
const lmStudioModels = useLmStudioModels(lmStudioModelId)
|
||||
|
||||
const { id, info } =
|
||||
apiConfiguration &&
|
||||
(typeof lmStudioModelId === "undefined" || typeof lmStudioModels.data !== "undefined") &&
|
||||
typeof routerModels.data !== "undefined" &&
|
||||
typeof openRouterModelProviders.data !== "undefined"
|
||||
? getSelectedModel({
|
||||
|
|
@ -61,6 +65,7 @@ export const useSelectedModel = (apiConfiguration?: ProviderSettings) => {
|
|||
apiConfiguration,
|
||||
routerModels: routerModels.data,
|
||||
openRouterModelProviders: openRouterModelProviders.data,
|
||||
lmStudioModels: lmStudioModels.data,
|
||||
})
|
||||
: { id: anthropicDefaultModelId, info: undefined }
|
||||
|
||||
|
|
@ -68,8 +73,14 @@ export const useSelectedModel = (apiConfiguration?: ProviderSettings) => {
|
|||
provider,
|
||||
id,
|
||||
info,
|
||||
isLoading: routerModels.isLoading || openRouterModelProviders.isLoading,
|
||||
isError: routerModels.isError || openRouterModelProviders.isError,
|
||||
isLoading:
|
||||
routerModels.isLoading ||
|
||||
openRouterModelProviders.isLoading ||
|
||||
(apiConfiguration?.lmStudioModelId && lmStudioModels!.isLoading),
|
||||
isError:
|
||||
routerModels.isError ||
|
||||
openRouterModelProviders.isError ||
|
||||
(apiConfiguration?.lmStudioModelId && lmStudioModels!.isError),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,11 +89,13 @@ function getSelectedModel({
|
|||
apiConfiguration,
|
||||
routerModels,
|
||||
openRouterModelProviders,
|
||||
lmStudioModels,
|
||||
}: {
|
||||
provider: ProviderName
|
||||
apiConfiguration: ProviderSettings
|
||||
routerModels: RouterModels
|
||||
openRouterModelProviders: Record<string, ModelInfo>
|
||||
lmStudioModels: ModelRecord | undefined
|
||||
}): { id: string; info: ModelInfo | undefined } {
|
||||
// the `undefined` case are used to show the invalid selection to prevent
|
||||
// users from seeing the default model if their selection is invalid
|
||||
|
|
@ -213,7 +226,7 @@ function getSelectedModel({
|
|||
}
|
||||
case "lmstudio": {
|
||||
const id = apiConfiguration.lmStudioModelId ?? ""
|
||||
const info = routerModels.lmstudio && routerModels.lmstudio[id]
|
||||
const info = lmStudioModels && lmStudioModels[apiConfiguration.lmStudioModelId!]
|
||||
return {
|
||||
id,
|
||||
info: info || undefined,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue