FreeLLMAPI / server /src /__tests__ /routes /proxy-vision.test.ts
Nryn215's picture
Upload folder using huggingface_hub
077865a verified
Raw
History Blame Contribute Delete
3.71 kB
import { describe, it, expect, beforeAll } from 'vitest';
import type { Express } from 'express';
import { createApp } from '../../app.js';
import { initDb, getDb, getUnifiedApiKey } from '../../db/index.js';
async function post(app: Express, path: string, body: any, key: string) {
const server = app.listen(0);
const addr = server.address() as any;
const res = await fetch(`http://127.0.0.1:${addr.port}${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },
body: JSON.stringify(body),
});
const text = await res.text();
server.close();
let json: any = null;
try { json = JSON.parse(text); } catch {}
return { status: res.status, body: json };
}
const IMAGE_MESSAGE = {
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'what is in this image?' },
{ type: 'image_url', image_url: { url: 'data:image/png;base64,iVBORw0KGgo=' } },
],
}],
};
describe('Vision-aware routing (#118, #125)', () => {
let app: Express;
let key: string;
beforeAll(() => {
process.env.ENCRYPTION_KEY = '0'.repeat(64);
initDb(':memory:');
app = createApp();
key = getUnifiedApiKey();
});
it('seeds supports_vision: true for vision models, false for text-only', () => {
const db = getDb();
const vision = db.prepare("SELECT supports_vision FROM models WHERE model_id = 'gemini-2.5-flash'").get() as { supports_vision: number };
expect(vision.supports_vision).toBe(1);
// The known vision set is flagged; plenty of text-only models remain at 0.
const visionCount = (db.prepare('SELECT COUNT(*) c FROM models WHERE supports_vision = 1').get() as { c: number }).c;
const textCount = (db.prepare('SELECT COUNT(*) c FROM models WHERE supports_vision = 0').get() as { c: number }).c;
expect(visionCount).toBeGreaterThanOrEqual(4);
expect(textCount).toBeGreaterThan(0);
});
it('lets an image request through routing when a vision model is enabled (no 422)', async () => {
// Seed has Gemini/Llama-4 vision models enabled but no provider keys, so
// routing exhausts → 429. The point: it is NOT the 422 "no vision model"
// error, proving the precheck passed and routing was attempted.
const { status, body } = await post(app, '/v1/chat/completions', IMAGE_MESSAGE, key);
expect(status).not.toBe(422);
expect(body?.error?.code).not.toBe('no_vision_model');
});
it('rejects an image request with a clear 422 when no vision model is enabled', async () => {
// Disable every vision-capable model in the chain.
getDb().prepare('UPDATE models SET enabled = 0 WHERE supports_vision = 1').run();
const { status, body } = await post(app, '/v1/chat/completions', IMAGE_MESSAGE, key);
expect(status).toBe(422);
expect(body.error.code).toBe('no_vision_model');
expect(body.error.type).toBe('invalid_request_error');
// Restore so we don't leak state to other expectations.
getDb().prepare('UPDATE models SET enabled = 1 WHERE supports_vision = 1').run();
});
it('does not apply the vision gate to a text-only request', async () => {
// Disable all vision models; a plain text request must still route normally
// (it 429s on exhaustion here, but never the 422 vision error).
getDb().prepare('UPDATE models SET enabled = 0 WHERE supports_vision = 1').run();
const { status, body } = await post(app, '/v1/chat/completions', {
messages: [{ role: 'user', content: 'hello' }],
}, key);
expect(status).not.toBe(422);
expect(body?.error?.code).not.toBe('no_vision_model');
getDb().prepare('UPDATE models SET enabled = 1 WHERE supports_vision = 1').run();
});
});