Spaces:
Runtime error
Runtime error
| import { describe, it, expect, beforeAll, beforeEach, afterEach, vi } from 'vitest'; | |
| import type { Express } from 'express'; | |
| import { createApp } from '../../app.js'; | |
| import { initDb, getDb, getUnifiedApiKey } from '../../db/index.js'; | |
| import { mintDashboardToken, isGatedApiPath } from '../helpers/auth.js'; | |
| let dashToken = ''; | |
| async function request(app: Express, method: string, path: string, body?: any, headers: Record<string, string> = {}) { | |
| const server = app.listen(0); | |
| const addr = server.address() as any; | |
| const url = `http://127.0.0.1:${addr.port}${path}`; | |
| const res = await fetch(url, { | |
| method, | |
| headers: { ...(body ? { 'Content-Type': 'application/json' } : {}), ...(isGatedApiPath(path) && !('Authorization' in headers) ? { Authorization: `Bearer ${dashToken}` } : {}), ...headers }, | |
| body: body ? JSON.stringify(body) : undefined, | |
| }); | |
| const data = await res.text(); | |
| server.close(); | |
| let json: any = null; | |
| try { json = JSON.parse(data); } catch {} | |
| return { status: res.status, body: json, headers: res.headers, raw: data }; | |
| } | |
| function authHeaders() { | |
| return { Authorization: `Bearer ${getUnifiedApiKey()}` }; | |
| } | |
| describe('Virtual "auto" model', () => { | |
| let app: Express; | |
| beforeAll(() => { | |
| process.env.ENCRYPTION_KEY = '0'.repeat(64); | |
| initDb(':memory:'); | |
| app = createApp(); | |
| dashToken = mintDashboardToken(); | |
| }); | |
| beforeEach(async () => { | |
| const db = getDb(); | |
| db.prepare('DELETE FROM api_keys').run(); | |
| db.prepare('DELETE FROM requests').run(); | |
| const addKey = await request(app, 'POST', '/api/keys', { | |
| platform: 'groq', | |
| key: 'gsk_auto_model_test', | |
| label: 'auto-model', | |
| }); | |
| expect(addKey.status).toBe(201); | |
| }); | |
| afterEach(() => { | |
| vi.restoreAllMocks(); | |
| }); | |
| it('lists "auto" as the first /v1/models entry', async () => { | |
| const { status, body } = await request(app, 'GET', '/v1/models', undefined, authHeaders()); | |
| expect(status).toBe(200); | |
| expect(body.object).toBe('list'); | |
| expect(body.data[0]).toMatchObject({ | |
| id: 'auto', | |
| object: 'model', | |
| owned_by: 'freellmapi', | |
| }); | |
| // Real catalog models still follow. | |
| expect(body.data.length).toBeGreaterThan(1); | |
| }); | |
| it('fails when authentication is missing or wrong', async () => { | |
| const { status: status1 } = await request(app, 'GET', '/v1/models'); | |
| expect(status1).toBe(401); | |
| const { status: status2 } = await request(app, 'GET', '/v1/models', undefined, { Authorization: 'Bearer wrongkey' }); | |
| expect(status2).toBe(401); | |
| }); | |
| it('returns unique model ids from /v1/models', async () => { | |
| const { status, body } = await request(app, 'GET', '/v1/models', undefined, authHeaders()); | |
| expect(status).toBe(200); | |
| const ids = body.data.map((model: { id: string }) => model.id); | |
| expect(new Set(ids).size).toBe(ids.length); | |
| }); | |
| it('treats model:"auto" as auto-route instead of a 400', async () => { | |
| const origFetch = global.fetch; | |
| vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => { | |
| const urlStr = typeof url === 'string' ? url : url.toString(); | |
| if (urlStr.includes('api.groq.com/openai/v1/chat/completions')) { | |
| return { | |
| ok: true, | |
| json: () => Promise.resolve({ | |
| id: 'chatcmpl-auto', | |
| object: 'chat.completion', | |
| created: 123, | |
| model: 'openai/gpt-oss-120b', | |
| choices: [{ | |
| index: 0, | |
| message: { role: 'assistant', content: 'routed via auto' }, | |
| finish_reason: 'stop', | |
| }], | |
| usage: { prompt_tokens: 5, completion_tokens: 3, total_tokens: 8 }, | |
| }), | |
| } as any; | |
| } | |
| return origFetch(url, init); | |
| }); | |
| const { status, body } = await request(app, 'POST', '/v1/chat/completions', { | |
| model: 'auto', | |
| messages: [{ role: 'user', content: 'hello' }], | |
| }, authHeaders()); | |
| expect(status).toBe(200); | |
| expect(body.choices[0].message.content).toBe('routed via auto'); | |
| }); | |
| it('still rejects an unknown model with model_not_found', async () => { | |
| const { status, body } = await request(app, 'POST', '/v1/chat/completions', { | |
| model: 'definitely-not-a-real-model', | |
| messages: [{ role: 'user', content: 'hello' }], | |
| }, authHeaders()); | |
| expect(status).toBe(400); | |
| expect(body.error.code).toBe('model_not_found'); | |
| }); | |
| }); | |