From ccaaf557f24f8f22b5a3390d06a2691b1b9dea31 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 24 Aug 2026 10:06:42 -0700 Subject: [PATCH 1/3] fix(vllm): support LM Studio endpoints --- .../docs/en/platform/self-hosting/docker.mdx | 20 ++++++ .../self-hosting/environment-variables.mdx | 4 +- .../docs/en/platform/self-hosting/index.mdx | 3 +- .../platform/self-hosting/troubleshooting.mdx | 15 +++++ apps/sim/.env.example | 4 +- .../api/providers/vllm/models/route.test.ts | 65 +++++++++++++++++++ .../app/api/providers/vllm/models/route.ts | 6 +- .../providers/openai-compat/base-url.test.ts | 13 ++++ apps/sim/providers/openai-compat/base-url.ts | 7 ++ apps/sim/providers/vllm/index.test.ts | 33 +++++++++- apps/sim/providers/vllm/index.ts | 15 +++-- docker-compose.ollama.yml | 3 + 12 files changed, 173 insertions(+), 15 deletions(-) create mode 100644 apps/sim/app/api/providers/vllm/models/route.test.ts create mode 100644 apps/sim/providers/openai-compat/base-url.test.ts create mode 100644 apps/sim/providers/openai-compat/base-url.ts diff --git a/apps/docs/content/docs/en/platform/self-hosting/docker.mdx b/apps/docs/content/docs/en/platform/self-hosting/docker.mdx index 0974cfb8e41..0343aee10c8 100644 --- a/apps/docs/content/docs/en/platform/self-hosting/docker.mdx +++ b/apps/docs/content/docs/en/platform/self-hosting/docker.mdx @@ -134,6 +134,26 @@ OLLAMA_URL=http://192.168.1.100:11434 docker compose -f docker-compose.prod.yml Inside Docker, `localhost` refers to the container, not your host. Use `host.docker.internal` or your host's IP. +### LM Studio + +[LM Studio exposes an OpenAI-compatible API](https://lmstudio.ai/docs/developer/openai-compat). Start its local server, load a model, and enable **Serve on Local Network** so the Docker container can reach it. [Enable API authentication](https://lmstudio.ai/docs/developer/core/authentication), then set the endpoint and token in the `.env` file next to your Compose file: + +```bash +# macOS/Windows +VLLM_BASE_URL=http://host.docker.internal:1234 + +# Linux - use your host IP instead +# VLLM_BASE_URL=http://192.168.1.100:1234 + +VLLM_API_KEY=your_lm_studio_api_token +``` + +Both the server root shown above and a URL ending in `/v1` are accepted. After recreating the `simstudio` service, its models appear in the model picker with a `vllm/` prefix; Sim removes that prefix before sending the model identifier to LM Studio. + +```bash +docker compose -f docker-compose.ollama.yml up -d --force-recreate simstudio +``` + ## Commands ```bash diff --git a/apps/docs/content/docs/en/platform/self-hosting/environment-variables.mdx b/apps/docs/content/docs/en/platform/self-hosting/environment-variables.mdx index 35f9162f061..b90835505b2 100644 --- a/apps/docs/content/docs/en/platform/self-hosting/environment-variables.mdx +++ b/apps/docs/content/docs/en/platform/self-hosting/environment-variables.mdx @@ -81,8 +81,8 @@ import { Callout } from 'fumadocs-ui/components/callout' | Variable | Description | |----------|-------------| -| `VLLM_BASE_URL` | vLLM server URL, **without** a `/v1` suffix (e.g. `http://localhost:8000`) — Sim appends `/v1` itself | -| `VLLM_API_KEY` | Optional bearer token for vLLM | +| `VLLM_BASE_URL` | OpenAI-compatible vLLM or LM Studio URL. Both the server root (`http://localhost:8000`) and versioned API URL (`http://localhost:8000/v1`) are accepted | +| `VLLM_API_KEY` | Optional bearer token for the vLLM or LM Studio endpoint | | `LITELLM_BASE_URL` | LiteLLM proxy base URL | | `LITELLM_API_KEY` | Optional bearer token for LiteLLM | diff --git a/apps/docs/content/docs/en/platform/self-hosting/index.mdx b/apps/docs/content/docs/en/platform/self-hosting/index.mdx index 3e7af31abca..287de10dde9 100644 --- a/apps/docs/content/docs/en/platform/self-hosting/index.mdx +++ b/apps/docs/content/docs/en/platform/self-hosting/index.mdx @@ -116,7 +116,7 @@ Sim is self-contained for the core editor and execution engine. A few features r | Feature | Requires | Notes | |---|---|---| | **Knowledge bases** | An OpenAI, Azure OpenAI, or Gemini API key | Embeddings are generated by a hosted provider, selected with `KB_EMBEDDING_MODEL` (`text-embedding-3-small` by default). There is no local embedding backend — knowledge bases are unavailable without one of these keys. | -| **Agent blocks** | An API key for at least one model provider | Or a self-hosted OpenAI-compatible endpoint: Ollama, vLLM, or LiteLLM. | +| **Agent blocks** | An API key for at least one model provider | Or a self-hosted OpenAI-compatible endpoint: Ollama, vLLM, LM Studio, or LiteLLM. | | **Chat module** | `COPILOT_API_KEY` from sim.ai | Set `NEXT_PUBLIC_CHAT_DISABLED=true` to hide the module instead. | | **Integrations** | Your own OAuth app per service | See [Integrations & OAuth](/platform/self-hosting/integrations-oauth). | | **Remote Function / Pi execution** | Optional E2B or Daytona key | Without one, JavaScript Function code that has no `import` or `require` still runs in the in-process isolated VM. Python, Shell, JavaScript with external imports, custom Function Sandboxes, and Pi require a configured remote provider. See [Security](/platform/self-hosting/security). | @@ -126,4 +126,3 @@ Sim is self-contained for the core editor and execution engine. A few features r { question: "What are the required environment variables for production?", answer: "Three secrets are required: BETTER_AUTH_SECRET (authentication), ENCRYPTION_KEY (data encryption), and INTERNAL_API_SECRET (service-to-service auth). Generate each with openssl rand -hex 32. You also need to set NEXT_PUBLIC_APP_URL and BETTER_AUTH_URL to your domain."}, { question: "Can I use Sim with local AI models?", answer: "Yes. Sim supports Ollama for local model inference. Use docker-compose.ollama.yml instead of docker-compose.prod.yml. It offers both GPU (with NVIDIA support) and CPU-only profiles, and automatically pulls gemma3:4b as a starter model." }, ]} /> - diff --git a/apps/docs/content/docs/en/platform/self-hosting/troubleshooting.mdx b/apps/docs/content/docs/en/platform/self-hosting/troubleshooting.mdx index c4b8406ad5d..6e00170b57f 100644 --- a/apps/docs/content/docs/en/platform/self-hosting/troubleshooting.mdx +++ b/apps/docs/content/docs/en/platform/self-hosting/troubleshooting.mdx @@ -25,6 +25,21 @@ OLLAMA_URL=http://host.docker.internal:11434 # macOS/Windows OLLAMA_URL=http://192.168.1.x:11434 # Linux (use actual IP) ``` +## LM Studio Requests Route to Ollama + +Sim identifies dynamically discovered LM Studio and vLLM models by their `vllm/` prefix. If the endpoint is unavailable and you manually enter the raw LM Studio model identifier, Sim treats that unknown identifier as an Ollama model. + +1. Confirm `VLLM_BASE_URL` is available inside the app container: + + ```bash + docker compose -f docker-compose.ollama.yml exec simstudio printenv VLLM_BASE_URL + ``` + +2. In LM Studio, enable **Serve on Local Network** and API authentication so the container can connect safely. +3. From Docker on macOS or Windows, use `http://host.docker.internal:1234` rather than `localhost`. On Linux, use the host IP. +4. The server root and a URL ending in `/v1` are both accepted. +5. Recreate `simstudio`, reload the workspace, and select the discovered `vllm/` option from the model picker. + ## WebSocket/Realtime Not Working 1. Verify reverse proxy routes `/socket.io` to the realtime service (default port 3002). `NEXT_PUBLIC_SOCKET_URL` is only needed if realtime is on a separate host. diff --git a/apps/sim/.env.example b/apps/sim/.env.example index c7313cbaa07..0f71427e700 100644 --- a/apps/sim/.env.example +++ b/apps/sim/.env.example @@ -90,8 +90,8 @@ CRON_SECRET=your_cron_secret # Use `openssl rand -hex 32` to generate. Authentic # Local AI Models (Optional) # OLLAMA_URL=http://localhost:11434 # URL for local Ollama server - uncomment if using local models -# VLLM_BASE_URL=http://localhost:8000 # Base URL for your self-hosted vLLM (OpenAI-compatible) -# VLLM_API_KEY= # Optional bearer token if your vLLM instance requires auth +# VLLM_BASE_URL=http://localhost:8000 # vLLM or LM Studio OpenAI-compatible URL; a trailing /v1 is optional +# VLLM_API_KEY= # Optional bearer token if the endpoint requires auth # LITELLM_BASE_URL=http://localhost:4000 # Base URL for your LiteLLM proxy (OpenAI-compatible) # LITELLM_API_KEY= # Optional bearer token if your LiteLLM proxy requires auth # OPENROUTER_API_KEY= # Optional self-hosted fallback for OpenAI knowledge-base embeddings diff --git a/apps/sim/app/api/providers/vllm/models/route.test.ts b/apps/sim/app/api/providers/vllm/models/route.test.ts new file mode 100644 index 00000000000..20bc8112f05 --- /dev/null +++ b/apps/sim/app/api/providers/vllm/models/route.test.ts @@ -0,0 +1,65 @@ +/** + * @vitest-environment node + */ +import { createMockRequest, resetEnvMock, setEnv } from '@sim/testing' +import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest' + +const { mockFetch, mockFilterBlacklistedModels, mockIsProviderBlacklisted } = vi.hoisted(() => ({ + mockFetch: vi.fn(), + mockFilterBlacklistedModels: vi.fn((models: string[]) => models), + mockIsProviderBlacklisted: vi.fn(() => false), +})) + +vi.mock('@/providers/utils', () => ({ + filterBlacklistedModels: mockFilterBlacklistedModels, + isProviderBlacklisted: mockIsProviderBlacklisted, +})) + +import { GET } from '@/app/api/providers/vllm/models/route' + +const request = () => createMockRequest('GET') + +describe('vLLM models route', () => { + beforeEach(() => { + vi.clearAllMocks() + mockFilterBlacklistedModels.mockImplementation((models: string[]) => models) + mockIsProviderBlacklisted.mockReturnValue(false) + mockFetch.mockResolvedValue({ + ok: true, + json: async () => ({ data: [{ id: 'local-model' }] }), + }) + vi.stubGlobal('fetch', mockFetch) + setEnv({ VLLM_BASE_URL: 'http://localhost:8000', VLLM_API_KEY: undefined }) + }) + + afterAll(() => { + vi.unstubAllGlobals() + resetEnvMock() + }) + + it('discovers and prefixes models from a server-root URL', async () => { + const response = await GET(request()) + + await expect(response.json()).resolves.toEqual({ models: ['vllm/local-model'] }) + expect(mockFetch).toHaveBeenCalledWith( + 'http://localhost:8000/v1/models', + expect.objectContaining({ headers: { 'Content-Type': 'application/json' } }) + ) + }) + + it('uses an existing /v1 prefix once and forwards bearer authentication', async () => { + setEnv({ VLLM_BASE_URL: 'http://localhost:1234/v1', VLLM_API_KEY: 'lm-token' }) + + await GET(request()) + + expect(mockFetch).toHaveBeenCalledWith( + 'http://localhost:1234/v1/models', + expect.objectContaining({ + headers: { + Authorization: 'Bearer lm-token', + 'Content-Type': 'application/json', + }, + }) + ) + }) +}) diff --git a/apps/sim/app/api/providers/vllm/models/route.ts b/apps/sim/app/api/providers/vllm/models/route.ts index 6e2e167220e..4dedf92fe96 100644 --- a/apps/sim/app/api/providers/vllm/models/route.ts +++ b/apps/sim/app/api/providers/vllm/models/route.ts @@ -7,6 +7,7 @@ import { } from '@/lib/api/contracts/providers' import { env } from '@/lib/core/config/env' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { getOpenAICompatibleApiBaseUrl } from '@/providers/openai-compat/base-url' import { filterBlacklistedModels, isProviderBlacklisted } from '@/providers/utils' const logger = createLogger('VLLMModelsAPI') @@ -20,12 +21,13 @@ export const GET = withRouteHandler(async (_request: NextRequest) => { return NextResponse.json({ models: [] }) } - const baseUrl = (env.VLLM_BASE_URL || '').replace(/\/$/, '') + const baseUrl = env.VLLM_BASE_URL?.trim() if (!baseUrl) { logger.info('VLLM_BASE_URL not configured') return NextResponse.json({ models: [] }) } + const apiBaseUrl = getOpenAICompatibleApiBaseUrl(baseUrl) try { logger.info('Fetching vLLM models', { @@ -40,7 +42,7 @@ export const GET = withRouteHandler(async (_request: NextRequest) => { headers.Authorization = `Bearer ${env.VLLM_API_KEY}` } - const response = await fetch(`${baseUrl}/v1/models`, { + const response = await fetch(`${apiBaseUrl}/models`, { headers, next: { revalidate: 60 }, }) diff --git a/apps/sim/providers/openai-compat/base-url.test.ts b/apps/sim/providers/openai-compat/base-url.test.ts new file mode 100644 index 00000000000..f26a5d0843e --- /dev/null +++ b/apps/sim/providers/openai-compat/base-url.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest' +import { getOpenAICompatibleApiBaseUrl } from '@/providers/openai-compat/base-url' + +describe('getOpenAICompatibleApiBaseUrl', () => { + it.each([ + ['http://localhost:8000', 'http://localhost:8000/v1'], + ['http://localhost:1234/v1', 'http://localhost:1234/v1'], + ['https://models.example.com/gateway/', 'https://models.example.com/gateway/v1'], + ['https://models.example.com/gateway/v1/', 'https://models.example.com/gateway/v1'], + ])('normalizes %s to %s', (input, expected) => { + expect(getOpenAICompatibleApiBaseUrl(input)).toBe(expected) + }) +}) diff --git a/apps/sim/providers/openai-compat/base-url.ts b/apps/sim/providers/openai-compat/base-url.ts new file mode 100644 index 00000000000..b4003bacf11 --- /dev/null +++ b/apps/sim/providers/openai-compat/base-url.ts @@ -0,0 +1,7 @@ +/** + * Normalizes a server root or versioned OpenAI-compatible URL to the `/v1` API base. + */ +export function getOpenAICompatibleApiBaseUrl(baseUrl: string): string { + const normalized = baseUrl.trim().replace(/\/+$/, '') + return normalized.endsWith('/v1') ? normalized : `${normalized}/v1` +} diff --git a/apps/sim/providers/vllm/index.test.ts b/apps/sim/providers/vllm/index.test.ts index 85ac6e80f1c..3c07971743b 100644 --- a/apps/sim/providers/vllm/index.test.ts +++ b/apps/sim/providers/vllm/index.test.ts @@ -166,6 +166,18 @@ describe('vllmProvider', () => { expect(openAIArgs[0].fetch).toBeUndefined() }) + it('does not duplicate an existing /v1 API prefix', async () => { + setEnv({ VLLM_BASE_URL: 'http://localhost:1234/v1', VLLM_API_KEY: undefined }) + mockCreate.mockResolvedValueOnce(chatResponse('hi')) + + await vllmProvider.executeRequest({ + model: 'vllm/lmstudio-model', + messages: [{ role: 'user', content: 'hi' }], + }) + + expect(openAIArgs[0].baseURL).toBe('http://localhost:1234/v1') + }) + it('validates a user-supplied endpoint and pins the connection to the resolved IP', async () => { mockCreate.mockResolvedValueOnce(chatResponse('hi')) @@ -185,6 +197,24 @@ describe('vllmProvider', () => { expect(openAIArgs[0].fetch).toBe(pinnedFetchFn) }) + it('preserves an existing /v1 prefix on a user-supplied endpoint', async () => { + mockCreate.mockResolvedValueOnce(chatResponse('hi')) + + await vllmProvider.executeRequest({ + model: 'vllm/llama-3', + messages: [{ role: 'user', content: 'hi' }], + azureEndpoint: 'https://my-vllm.example.com/v1', + }) + + expect(mockValidateUrlWithDNS).toHaveBeenCalledWith( + 'https://my-vllm.example.com/v1', + 'vLLM endpoint', + { allowHttp: true } + ) + expect(openAIArgs[0].baseURL).toBe('https://my-vllm.example.com/v1') + expect(openAIArgs[0].fetch).toBe(pinnedFetchFn) + }) + it('rejects a user-supplied endpoint that fails SSRF validation without issuing a request', async () => { mockValidateUrlWithDNS.mockResolvedValueOnce({ isValid: false, @@ -236,7 +266,8 @@ describe('vllmProvider', () => { const payload = createPayload(0) expect(payload.model).toBe('llama-3') expect(payload.temperature).toBe(0.7) - expect(payload.max_completion_tokens).toBe(256) + expect(payload.max_tokens).toBe(256) + expect(payload.max_completion_tokens).toBeUndefined() expect(payload.messages.map((m: { role: string }) => m.role)).toEqual([ 'system', 'user', diff --git a/apps/sim/providers/vllm/index.ts b/apps/sim/providers/vllm/index.ts index 8c75e631723..eadb5b7af59 100644 --- a/apps/sim/providers/vllm/index.ts +++ b/apps/sim/providers/vllm/index.ts @@ -11,6 +11,7 @@ import { formatMessagesForProvider } from '@/providers/attachments' import { getCachedProviderClient } from '@/providers/client-cache' import { getProviderDefaultModel, getProviderModels } from '@/providers/models' import { createOpenAICompatAssistantHistory } from '@/providers/openai-compat/assistant-history' +import { getOpenAICompatibleApiBaseUrl } from '@/providers/openai-compat/base-url' import { executeProviderTool } from '@/providers/runtime-context' import { createSettledAgentEventStream } from '@/providers/stream-events' import { createStreamingExecution } from '@/providers/streaming-execution' @@ -53,11 +54,12 @@ export const vllmProvider: ProviderConfig = { return } - const baseUrl = (env.VLLM_BASE_URL || '').replace(/\/$/, '') + const baseUrl = env.VLLM_BASE_URL?.trim() if (!baseUrl) { logger.info('VLLM_BASE_URL not configured, skipping initialization') return } + const apiBaseUrl = getOpenAICompatibleApiBaseUrl(baseUrl) try { const headers: Record = { @@ -68,7 +70,7 @@ export const vllmProvider: ProviderConfig = { headers.Authorization = `Bearer ${env.VLLM_API_KEY}` } - const response = await fetch(`${baseUrl}/v1/models`, { headers }) + const response = await fetch(`${apiBaseUrl}/models`, { headers }) if (!response.ok) { await response.text().catch(() => {}) useProvidersStore.getState().setProviderModels('vllm', []) @@ -105,10 +107,11 @@ export const vllmProvider: ProviderConfig = { const userProvidedEndpoint = request.azureEndpoint - const baseUrl = (userProvidedEndpoint || env.VLLM_BASE_URL || '').replace(/\/$/, '') + const baseUrl = (userProvidedEndpoint || env.VLLM_BASE_URL)?.trim() if (!baseUrl) { throw new Error('VLLM_BASE_URL is required for vLLM provider') } + const apiBaseUrl = getOpenAICompatibleApiBaseUrl(baseUrl) /** * A user-supplied endpoint is attacker-controlled: validate it against the @@ -142,12 +145,12 @@ export const vllmProvider: ProviderConfig = { const apiKey = request.apiKey || env.VLLM_API_KEY || 'empty' const vllm = getCachedProviderClient( - `vllm::${apiKey}::${baseUrl}::${pinnedIP ?? 'no-pin'}`, + `vllm::${apiKey}::${apiBaseUrl}::${pinnedIP ?? 'no-pin'}`, () => new OpenAI({ ...openAICompatTransport(), apiKey, - baseURL: `${baseUrl}/v1`, + baseURL: apiBaseUrl, ...(pinnedFetch ? { fetch: pinnedFetch } : {}), }) ) @@ -183,7 +186,7 @@ export const vllmProvider: ProviderConfig = { } if (request.temperature !== undefined) payload.temperature = request.temperature - if (request.maxTokens != null) payload.max_completion_tokens = request.maxTokens + if (request.maxTokens != null) payload.max_tokens = request.maxTokens if (request.responseFormat) { payload.response_format = { diff --git a/docker-compose.ollama.yml b/docker-compose.ollama.yml index 208876f3539..2f595b92ead 100644 --- a/docker-compose.ollama.yml +++ b/docker-compose.ollama.yml @@ -3,6 +3,9 @@ name: sim-with-ollama services: # Main Sim Application simstudio: + env_file: + - path: .env + required: false build: context: . dockerfile: docker/app.Dockerfile From 1505233647265c742f712eb46e4ad088b34ef878 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 24 Aug 2026 10:13:10 -0700 Subject: [PATCH 2/3] fix(vllm): validate compatible base URLs --- apps/sim/providers/openai-compat/base-url.test.ts | 9 +++++++++ apps/sim/providers/openai-compat/base-url.ts | 12 ++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/sim/providers/openai-compat/base-url.test.ts b/apps/sim/providers/openai-compat/base-url.test.ts index f26a5d0843e..eef9be5574b 100644 --- a/apps/sim/providers/openai-compat/base-url.test.ts +++ b/apps/sim/providers/openai-compat/base-url.test.ts @@ -10,4 +10,13 @@ describe('getOpenAICompatibleApiBaseUrl', () => { ])('normalizes %s to %s', (input, expected) => { expect(getOpenAICompatibleApiBaseUrl(input)).toBe(expected) }) + + it.each(['http://localhost:8000?token=value', 'http://localhost:8000#models'])( + 'rejects unsupported URL components in %s', + (input) => { + expect(() => getOpenAICompatibleApiBaseUrl(input)).toThrow( + 'OpenAI-compatible base URL must not include query parameters or a fragment' + ) + } + ) }) diff --git a/apps/sim/providers/openai-compat/base-url.ts b/apps/sim/providers/openai-compat/base-url.ts index b4003bacf11..f8ab77c2830 100644 --- a/apps/sim/providers/openai-compat/base-url.ts +++ b/apps/sim/providers/openai-compat/base-url.ts @@ -1,7 +1,15 @@ /** * Normalizes a server root or versioned OpenAI-compatible URL to the `/v1` API base. + * + * @throws When the URL contains query parameters or a fragment. */ export function getOpenAICompatibleApiBaseUrl(baseUrl: string): string { - const normalized = baseUrl.trim().replace(/\/+$/, '') - return normalized.endsWith('/v1') ? normalized : `${normalized}/v1` + const url = new URL(baseUrl.trim()) + if (url.search || url.hash) { + throw new Error('OpenAI-compatible base URL must not include query parameters or a fragment') + } + + const pathname = url.pathname.replace(/\/+$/, '') + url.pathname = pathname.endsWith('/v1') ? pathname : `${pathname}/v1` + return url.toString() } From e5a7cdcc7d7a188bf1c6577803ff77e28e156e2f Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 24 Aug 2026 10:19:41 -0700 Subject: [PATCH 3/3] fix(vllm): guard discovery URL validation --- apps/sim/app/api/providers/vllm/models/route.test.ts | 9 +++++++++ apps/sim/app/api/providers/vllm/models/route.ts | 2 +- apps/sim/providers/vllm/index.ts | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/api/providers/vllm/models/route.test.ts b/apps/sim/app/api/providers/vllm/models/route.test.ts index 20bc8112f05..48cc94eb65d 100644 --- a/apps/sim/app/api/providers/vllm/models/route.test.ts +++ b/apps/sim/app/api/providers/vllm/models/route.test.ts @@ -62,4 +62,13 @@ describe('vLLM models route', () => { }) ) }) + + it('returns an empty model list when the configured base URL is unsupported', async () => { + setEnv({ VLLM_BASE_URL: 'http://localhost:1234?token=value' }) + + const response = await GET(request()) + + await expect(response.json()).resolves.toEqual({ models: [] }) + expect(mockFetch).not.toHaveBeenCalled() + }) }) diff --git a/apps/sim/app/api/providers/vllm/models/route.ts b/apps/sim/app/api/providers/vllm/models/route.ts index 4dedf92fe96..05939b4862c 100644 --- a/apps/sim/app/api/providers/vllm/models/route.ts +++ b/apps/sim/app/api/providers/vllm/models/route.ts @@ -27,9 +27,9 @@ export const GET = withRouteHandler(async (_request: NextRequest) => { logger.info('VLLM_BASE_URL not configured') return NextResponse.json({ models: [] }) } - const apiBaseUrl = getOpenAICompatibleApiBaseUrl(baseUrl) try { + const apiBaseUrl = getOpenAICompatibleApiBaseUrl(baseUrl) logger.info('Fetching vLLM models', { baseUrl, }) diff --git a/apps/sim/providers/vllm/index.ts b/apps/sim/providers/vllm/index.ts index eadb5b7af59..e2fb433403a 100644 --- a/apps/sim/providers/vllm/index.ts +++ b/apps/sim/providers/vllm/index.ts @@ -59,9 +59,9 @@ export const vllmProvider: ProviderConfig = { logger.info('VLLM_BASE_URL not configured, skipping initialization') return } - const apiBaseUrl = getOpenAICompatibleApiBaseUrl(baseUrl) try { + const apiBaseUrl = getOpenAICompatibleApiBaseUrl(baseUrl) const headers: Record = { 'Content-Type': 'application/json', }