| |
| |
| |
| |
| |
| |
|
|
| import type { NextRequest } from 'next/server'; |
| import { getModel, parseModelString, type ModelWithInfo } from '@/lib/ai/providers'; |
| import type { ThinkingConfig } from '@/lib/types/provider'; |
| import { resolveApiKey, resolveBaseUrl, resolveProxy } from '@/lib/server/provider-config'; |
| import { validateUrlForSSRF } from '@/lib/server/ssrf-guard'; |
|
|
| export interface ResolvedModel extends ModelWithInfo { |
| |
| modelString: string; |
| |
| providerId: string; |
| |
| apiKey: string; |
| |
| thinkingConfig?: ThinkingConfig; |
| } |
|
|
| |
| |
| |
| |
| |
| export async function resolveModel(params: { |
| modelString?: string; |
| apiKey?: string; |
| baseUrl?: string; |
| providerType?: string; |
| thinkingConfig?: ThinkingConfig; |
| }): Promise<ResolvedModel> { |
| const modelString = params.modelString || process.env.DEFAULT_MODEL || 'gpt-5.4-mini'; |
| const { providerId, modelId } = parseModelString(modelString); |
|
|
| |
| |
| |
| const clientBaseUrl = params.baseUrl || undefined; |
| if (clientBaseUrl && process.env.NODE_ENV === 'production') { |
| const ssrfError = await validateUrlForSSRF(clientBaseUrl); |
| if (ssrfError) { |
| throw new Error(ssrfError); |
| } |
| } |
|
|
| const apiKey = clientBaseUrl |
| ? params.apiKey || '' |
| : resolveApiKey(providerId, params.apiKey || ''); |
| const baseUrl = clientBaseUrl ? clientBaseUrl : resolveBaseUrl(providerId, params.baseUrl); |
| const proxy = resolveProxy(providerId); |
| const { model, modelInfo } = getModel({ |
| providerId, |
| modelId, |
| apiKey, |
| baseUrl, |
| proxy, |
| providerType: params.providerType as 'openai' | 'anthropic' | 'google' | undefined, |
| }); |
|
|
| return { |
| model, |
| modelInfo, |
| modelString, |
| providerId, |
| apiKey, |
| thinkingConfig: params.thinkingConfig, |
| }; |
| } |
|
|
| function getThinkingConfigFromBody(body: unknown): ThinkingConfig | undefined { |
| if (!body || typeof body !== 'object') return undefined; |
| const record = body as { thinkingConfig?: unknown; thinking?: unknown }; |
| const config = record.thinkingConfig ?? record.thinking; |
| return config && typeof config === 'object' ? (config as ThinkingConfig) : undefined; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export async function resolveModelFromHeaders(req: NextRequest): Promise<ResolvedModel> { |
| return resolveModel({ |
| modelString: req.headers.get('x-model') || undefined, |
| apiKey: req.headers.get('x-api-key') || undefined, |
| baseUrl: req.headers.get('x-base-url') || undefined, |
| providerType: req.headers.get('x-provider-type') || undefined, |
| }); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export async function resolveModelFromRequest( |
| req: NextRequest, |
| body: unknown, |
| ): Promise<ResolvedModel> { |
| const resolved = await resolveModelFromHeaders(req); |
| return { |
| ...resolved, |
| thinkingConfig: getThinkingConfigFromBody(body) ?? resolved.thinkingConfig, |
| }; |
| } |
|
|