Spaces:
Runtime error
Runtime error
File size: 4,411 Bytes
077865a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | 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');
});
});
|