Skip to content

Commit 475820a

Browse files
committed
fix: add frontend model discovery pipeline for litellm provider
Add API route, contract, query hook case, and ProviderModelsLoader entry so litellm models are fetched and synced to the store on workspace load, matching the vllm/ollama/openrouter/fireworks pattern. Also fixes defaultModel to empty string and adds litellm/ prefix early-return in blocks/utils.ts (reviewer feedback).
1 parent 9667e88 commit 475820a

6 files changed

Lines changed: 88 additions & 2 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { createLogger } from '@sim/logger'
2+
import { getErrorMessage } from '@sim/utils/errors'
3+
import { type NextRequest, NextResponse } from 'next/server'
4+
import {
5+
providerModelsResponseSchema,
6+
vllmUpstreamResponseSchema,
7+
} from '@/lib/api/contracts/providers'
8+
import { env } from '@/lib/core/config/env'
9+
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
10+
import { filterBlacklistedModels, isProviderBlacklisted } from '@/providers/utils'
11+
12+
const logger = createLogger('LiteLLMModelsAPI')
13+
14+
export const GET = withRouteHandler(async (_request: NextRequest) => {
15+
if (isProviderBlacklisted('litellm')) {
16+
logger.info('LiteLLM provider is blacklisted, returning empty models')
17+
return NextResponse.json({ models: [] })
18+
}
19+
20+
const baseUrl = (env.LITELLM_BASE_URL || '').replace(/\/$/, '')
21+
22+
if (!baseUrl) {
23+
logger.info('LITELLM_BASE_URL not configured')
24+
return NextResponse.json({ models: [] })
25+
}
26+
27+
try {
28+
logger.info('Fetching LiteLLM models', { baseUrl })
29+
30+
const headers: Record<string, string> = {
31+
'Content-Type': 'application/json',
32+
}
33+
34+
if (env.LITELLM_API_KEY) {
35+
headers.Authorization = `Bearer ${env.LITELLM_API_KEY}`
36+
}
37+
38+
const response = await fetch(`${baseUrl}/v1/models`, {
39+
headers,
40+
next: { revalidate: 60 },
41+
})
42+
43+
if (!response.ok) {
44+
logger.warn('LiteLLM service is not available', {
45+
status: response.status,
46+
statusText: response.statusText,
47+
})
48+
return NextResponse.json({ models: [] })
49+
}
50+
51+
const data = vllmUpstreamResponseSchema.parse(await response.json())
52+
const allModels = data.data.map((model) => `litellm/${model.id}`)
53+
const models = filterBlacklistedModels(allModels)
54+
55+
logger.info('Successfully fetched LiteLLM models', {
56+
count: models.length,
57+
filtered: allModels.length - models.length,
58+
models,
59+
})
60+
61+
return NextResponse.json(providerModelsResponseSchema.parse({ models }))
62+
} catch (error) {
63+
logger.error('Failed to fetch LiteLLM models', {
64+
error: getErrorMessage(error, 'Unknown error'),
65+
baseUrl,
66+
})
67+
68+
return NextResponse.json({ models: [] })
69+
}
70+
})

apps/sim/app/workspace/[workspaceId]/providers/provider-models-loader.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useParams } from 'next/navigation'
66
import { useProviderModels } from '@/hooks/queries/providers'
77
import {
88
updateFireworksProviderModels,
9+
updateLiteLLMProviderModels,
910
updateOllamaProviderModels,
1011
updateOpenRouterProviderModels,
1112
updateVLLMProviderModels,
@@ -32,6 +33,8 @@ function useSyncProvider(provider: ProviderName, workspaceId?: string) {
3233
updateOllamaProviderModels(data.models)
3334
} else if (provider === 'vllm') {
3435
updateVLLMProviderModels(data.models)
36+
} else if (provider === 'litellm') {
37+
updateLiteLLMProviderModels(data.models)
3538
} else if (provider === 'openrouter') {
3639
void updateOpenRouterProviderModels(data.models)
3740
if (data.modelInfo) {
@@ -61,6 +64,7 @@ export function ProviderModelsLoader() {
6164
useSyncProvider('base')
6265
useSyncProvider('ollama')
6366
useSyncProvider('vllm')
67+
useSyncProvider('litellm')
6468
useSyncProvider('openrouter')
6569
useSyncProvider('fireworks', workspaceId)
6670
return null

apps/sim/blocks/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ function shouldRequireApiKeyForModel(model: string): boolean {
160160
) {
161161
return false
162162
}
163-
if (normalizedModel.startsWith('vllm/')) {
163+
if (normalizedModel.startsWith('vllm/') || normalizedModel.startsWith('litellm/')) {
164164
return false
165165
}
166166

apps/sim/hooks/queries/providers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { requestJson } from '@/lib/api/client/request'
55
import {
66
getBaseProviderModelsContract,
77
getFireworksProviderModelsContract,
8+
getLitellmProviderModelsContract,
89
getOllamaProviderModelsContract,
910
getOpenRouterProviderModelsContract,
1011
getVllmProviderModelsContract,
@@ -54,6 +55,8 @@ async function requestProviderModels(
5455
return requestJson(getOllamaProviderModelsContract, { signal })
5556
case 'vllm':
5657
return requestJson(getVllmProviderModelsContract, { signal })
58+
case 'litellm':
59+
return requestJson(getLitellmProviderModelsContract, { signal })
5760
case 'openrouter':
5861
return requestJson(getOpenRouterProviderModelsContract, { signal })
5962
case 'fireworks':

apps/sim/lib/api/contracts/providers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,15 @@ export const getOpenRouterProviderModelsContract = defineRouteContract({
207207
},
208208
})
209209

210+
export const getLitellmProviderModelsContract = defineRouteContract({
211+
method: 'GET',
212+
path: '/api/providers/litellm/models',
213+
response: {
214+
mode: 'json',
215+
schema: providerModelsResponseSchema,
216+
},
217+
})
218+
210219
export const getFireworksProviderModelsContract = defineRouteContract({
211220
method: 'GET',
212221
path: '/api/providers/fireworks/models',

apps/sim/providers/models.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export const PROVIDER_DEFINITIONS: Record<string, ProviderDefinition> = {
131131
name: 'LiteLLM',
132132
icon: LitellmIcon,
133133
description: 'LiteLLM proxy with an OpenAI-compatible API',
134-
defaultModel: 'litellm/generic',
134+
defaultModel: '',
135135
modelPatterns: [/^litellm\//],
136136
capabilities: {
137137
temperature: { min: 0, max: 2 },

0 commit comments

Comments
 (0)