From cd240325ce7ecad51b4994e427329a40841464ae Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Mon, 7 Jul 2025 12:08:29 -0500 Subject: [PATCH] fix: normalize base URL in LM Studio embedder and improve error logging --- src/services/code-index/embedders/lmstudio.ts | 18 ++++-- .../settings/providers/LMStudio.tsx | 63 ++++++++----------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/services/code-index/embedders/lmstudio.ts b/src/services/code-index/embedders/lmstudio.ts index 25d6ef07fa..bbcdd56835 100644 --- a/src/services/code-index/embedders/lmstudio.ts +++ b/src/services/code-index/embedders/lmstudio.ts @@ -23,9 +23,16 @@ export class CodeIndexLmStudioEmbedder implements IEmbedder { */ constructor(options: ApiHandlerOptions & { embeddingModelId?: string }) { this.options = options + + // Normalize base URL to prevent duplicate /v1 if user already provided it + let baseUrl = this.options.lmStudioBaseUrl || "http://localhost:1234" + if (!baseUrl.endsWith("/v1")) { + baseUrl = baseUrl + "/v1" + } + this.embeddingsClient = new OpenAI({ - baseURL: (this.options.lmStudioBaseUrl || "http://localhost:1234") + "/v1", - apiKey: "noop", // LM Studio doesn't require a real API key + baseURL: baseUrl, + apiKey: "noop", // API key is intentionally hardcoded to "noop" because LM Studio does not require authentication }) this.defaultModelId = options.embeddingModelId || "text-embedding-nomic-embed-text-v1.5@f16" } @@ -81,8 +88,11 @@ export class CodeIndexLmStudioEmbedder implements IEmbedder { usage.promptTokens += batchResult.usage.promptTokens usage.totalTokens += batchResult.usage.totalTokens } catch (error) { - console.error("Failed to process batch:", error) - throw new Error("Failed to create embeddings: batch processing error") + const batchInfo = `batch of ${currentBatch.length} documents (indices: ${processedIndices.join(", ")})` + console.error(`Failed to process ${batchInfo}:`, error) + throw new Error( + `Failed to create embeddings for ${batchInfo}: ${error instanceof Error ? error.message : "batch processing error"}`, + ) } } } diff --git a/webview-ui/src/components/settings/providers/LMStudio.tsx b/webview-ui/src/components/settings/providers/LMStudio.tsx index a907e43e1b..f0167508ff 100644 --- a/webview-ui/src/components/settings/providers/LMStudio.tsx +++ b/webview-ui/src/components/settings/providers/LMStudio.tsx @@ -56,47 +56,38 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi vscode.postMessage({ type: "requestLmStudioModels" }) }, []) + // Reusable function to check if a model is available + const checkModelAvailability = useCallback( + (modelId: string | undefined): boolean => { + if (!modelId) return false + + // Check if model exists in local LM Studio models + if (lmStudioModels.length > 0 && lmStudioModels.includes(modelId)) { + return false // Model is available locally + } + + // If we have router models data for LM Studio + if (routerModels.data?.lmstudio) { + const availableModels = Object.keys(routerModels.data.lmstudio) + // Show warning if model is not in the list (regardless of how many models there are) + return !availableModels.includes(modelId) + } + + // If neither source has loaded yet, don't show warning + return false + }, + [lmStudioModels, routerModels.data], + ) + // Check if the selected model exists in the fetched models const modelNotAvailable = useMemo(() => { - const selectedModel = apiConfiguration?.lmStudioModelId - if (!selectedModel) return false - - // Check if model exists in local LM Studio models - if (lmStudioModels.length > 0 && lmStudioModels.includes(selectedModel)) { - return false // Model is available locally - } - - // If we have router models data for LM Studio - if (routerModels.data?.lmstudio) { - const availableModels = Object.keys(routerModels.data.lmstudio) - // Show warning if model is not in the list (regardless of how many models there are) - return !availableModels.includes(selectedModel) - } - - // If neither source has loaded yet, don't show warning - return false - }, [apiConfiguration?.lmStudioModelId, routerModels.data, lmStudioModels]) + return checkModelAvailability(apiConfiguration?.lmStudioModelId) + }, [apiConfiguration?.lmStudioModelId, checkModelAvailability]) // Check if the draft model exists const draftModelNotAvailable = useMemo(() => { - const draftModel = apiConfiguration?.lmStudioDraftModelId - if (!draftModel) return false - - // Check if model exists in local LM Studio models - if (lmStudioModels.length > 0 && lmStudioModels.includes(draftModel)) { - return false // Model is available locally - } - - // If we have router models data for LM Studio - if (routerModels.data?.lmstudio) { - const availableModels = Object.keys(routerModels.data.lmstudio) - // Show warning if model is not in the list (regardless of how many models there are) - return !availableModels.includes(draftModel) - } - - // If neither source has loaded yet, don't show warning - return false - }, [apiConfiguration?.lmStudioDraftModelId, routerModels.data, lmStudioModels]) + return checkModelAvailability(apiConfiguration?.lmStudioDraftModelId) + }, [apiConfiguration?.lmStudioDraftModelId, checkModelAvailability]) return ( <>