d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
import { createLogger } from '@sim/logger'
|
|
import { getErrorMessage } from '@sim/utils/errors'
|
|
import { type NextRequest, NextResponse } from 'next/server'
|
|
import {
|
|
openRouterUpstreamResponseSchema,
|
|
providerModelsResponseSchema,
|
|
} from '@/lib/api/contracts/providers'
|
|
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
|
import { filterBlacklistedModels, isProviderBlacklisted } from '@/providers/utils'
|
|
|
|
const logger = createLogger('OpenRouterModelsAPI')
|
|
|
|
interface OpenRouterModel {
|
|
id: string
|
|
context_length?: number
|
|
supported_parameters?: string[]
|
|
pricing?: {
|
|
prompt?: string
|
|
completion?: string
|
|
}
|
|
}
|
|
|
|
interface OpenRouterResponse {
|
|
data: OpenRouterModel[]
|
|
}
|
|
|
|
export interface OpenRouterModelInfo {
|
|
id: string
|
|
contextLength?: number
|
|
supportsStructuredOutputs?: boolean
|
|
supportsTools?: boolean
|
|
pricing?: {
|
|
input: number
|
|
output: number
|
|
}
|
|
}
|
|
|
|
export const GET = withRouteHandler(async (_request: NextRequest) => {
|
|
if (isProviderBlacklisted('openrouter')) {
|
|
logger.info('OpenRouter provider is blacklisted, returning empty models')
|
|
return NextResponse.json({ models: [], modelInfo: {} })
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('https://openrouter.ai/api/v1/models', {
|
|
headers: { 'Content-Type': 'application/json' },
|
|
next: { revalidate: 300 },
|
|
})
|
|
|
|
if (!response.ok) {
|
|
logger.warn('Failed to fetch OpenRouter models', {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
})
|
|
return NextResponse.json({ models: [], modelInfo: {} })
|
|
}
|
|
|
|
const data: OpenRouterResponse = openRouterUpstreamResponseSchema.parse(await response.json())
|
|
|
|
const modelInfo: Record<string, OpenRouterModelInfo> = {}
|
|
const allModels: string[] = []
|
|
|
|
for (const model of data.data ?? []) {
|
|
const modelId = `openrouter/${model.id}`
|
|
allModels.push(modelId)
|
|
|
|
const supportedParams = model.supported_parameters ?? []
|
|
modelInfo[modelId] = {
|
|
id: modelId,
|
|
contextLength: model.context_length,
|
|
supportsStructuredOutputs: supportedParams.includes('structured_outputs'),
|
|
supportsTools: supportedParams.includes('tools'),
|
|
pricing: model.pricing
|
|
? {
|
|
input: Number.parseFloat(model.pricing.prompt ?? '0') * 1000000,
|
|
output: Number.parseFloat(model.pricing.completion ?? '0') * 1000000,
|
|
}
|
|
: undefined,
|
|
}
|
|
}
|
|
|
|
const uniqueModels = Array.from(new Set(allModels))
|
|
const models = filterBlacklistedModels(uniqueModels)
|
|
|
|
const structuredOutputCount = Object.values(modelInfo).filter(
|
|
(m) => m.supportsStructuredOutputs
|
|
).length
|
|
|
|
logger.info('Successfully fetched OpenRouter models', {
|
|
count: models.length,
|
|
filtered: uniqueModels.length - models.length,
|
|
withStructuredOutputs: structuredOutputCount,
|
|
})
|
|
|
|
return NextResponse.json(providerModelsResponseSchema.parse({ models, modelInfo }))
|
|
} catch (error) {
|
|
logger.error('Error fetching OpenRouter models', {
|
|
error: getErrorMessage(error, 'Unknown error'),
|
|
})
|
|
return NextResponse.json({ models: [], modelInfo: {} })
|
|
}
|
|
})
|