| 16 | } |
| 17 | |
| 18 | function buildModelsHandler({ anthropicProxy, openAIProxy, logger } = {}) { |
| 19 | if (typeof anthropicProxy !== 'function' || typeof openAIProxy !== 'function') { |
| 20 | throw new Error('buildModelsHandler requires anthropicProxy(path,body,opts) + openAIProxy(path,body,opts)'); |
| 21 | } |
| 22 | const log = logger || console; |
| 23 | |
| 24 | return async ({ headers }) => { |
| 25 | const inboundHeaders = headers || {}; |
| 26 | const provider = detectModelsProvider(inboundHeaders); |
| 27 | const [proxyFn, reqPath, mode] = provider === 'anthropic' |
| 28 | ? [anthropicProxy, '/v1/models', 'anthropic'] |
| 29 | : [openAIProxy, '/models', 'openai']; |
| 30 | |
| 31 | let up; |
| 32 | try { |
| 33 | up = await proxyFn(reqPath, null, { method: 'GET', inboundHeaders, upstreamMode: mode }); |
| 34 | } catch (err) { |
| 35 | const status = Number(err && err.statusCode) || 502; |
| 36 | return { status, body: { error: (err && err.message) || 'models upstream request failed' } }; |
| 37 | } |
| 38 | |
| 39 | let raw = ''; |
| 40 | try { raw = up.text ? await up.text() : ''; } catch { raw = ''; } |
| 41 | let body; |
| 42 | try { |
| 43 | body = raw ? JSON.parse(raw) : {}; |
| 44 | } catch { |
| 45 | log.warn?.(JSON.stringify({ event: 'models_fallback', reason: 'upstream_non_json', upstream_status: up.status })); |
| 46 | body = { error: raw }; |
| 47 | } |
| 48 | return { status: up.status, body }; |
| 49 | }; |
| 50 | } |
| 51 | |
| 52 | module.exports = { buildModelsHandler, detectModelsProvider }; |