mirror of
https://github.com/R0m1k3/EveFlow.git
synced 2026-10-23 23:28:14 +02:00
- Menu déroulant des modèles alimenté par GET /api/model/options (tous les fournisseurs authentifiés et leurs modèles, modèle courant du serveur marqué), bouton d'actualisation (?refresh=1), saisie libre en repli quand l'endpoint n'existe pas. /v1/models ne renvoie que l'alias « hermes-agent ». - Le fournisseur choisi et l'effort de raisonnement (none, minimal, low, medium, high, xhigh, max, ultra) sont envoyés à chaque requête sur les trois transports (runs, sessions, chat completions) ; l'effort n'était transmis qu'en chat completions. - Modèle « mission » sélectionné de la même façon (modèle + fournisseur). - Tests des helpers du sélecteur ; README et feuille de route. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMpgFriwxiBgurUVb21oCE
46 lines
2.4 KiB
TypeScript
46 lines
2.4 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { flattenModelOptions, groupModelChoices, isReasoningEffort, modelChoiceValue, parseModelChoice } from '../src/lib/hermesModels';
|
|
|
|
const payload = {
|
|
model: 'claude-fable-5-1',
|
|
provider: 'anthropic',
|
|
providers: [
|
|
{ slug: 'anthropic', name: 'Anthropic', is_current: true, models: ['claude-opus-5', 'claude-fable-5-1', 'claude-opus-5'], authenticated: true },
|
|
{ slug: 'openrouter', name: 'OpenRouter', models: ['deepseek/deepseek-v4', ' '], authenticated: true },
|
|
{ slug: 'nous', name: 'Nous Portal', models: [], authenticated: false, warning: 'paste NOUS_API_KEY to activate' },
|
|
{ slug: 'custom', name: 'Custom endpoint', models: ['qwen3'], authenticated: true }
|
|
]
|
|
};
|
|
|
|
describe('flattenModelOptions', () => {
|
|
it('lists authenticated providers, current model first in its row, without duplicates or blanks', () => {
|
|
const choices = flattenModelOptions(payload);
|
|
expect(choices.map((c) => `${c.provider}/${c.model}`)).toEqual(['anthropic/claude-fable-5-1', 'anthropic/claude-opus-5', 'openrouter/deepseek/deepseek-v4', 'custom/qwen3']);
|
|
expect(choices[0].current).toBe(true);
|
|
expect(choices[1].current).toBe(false);
|
|
});
|
|
it('tolerates an empty or malformed payload', () => {
|
|
expect(flattenModelOptions(null)).toEqual([]);
|
|
expect(flattenModelOptions({ providers: [{ slug: 'x', name: 'x', models: 'nope' } as unknown as { slug: string; name: string; models: string[] }] })).toEqual([]);
|
|
});
|
|
it('groups by provider in row order', () => {
|
|
const groups = groupModelChoices(flattenModelOptions(payload));
|
|
expect(groups.map((g) => g.providerName)).toEqual(['Anthropic', 'OpenRouter', 'Custom endpoint']);
|
|
expect(groups[0].models).toHaveLength(2);
|
|
});
|
|
});
|
|
|
|
describe('model choice value', () => {
|
|
it('round-trips provider and model, including model ids containing slashes and colons', () => {
|
|
const v = modelChoiceValue('openrouter', 'deepseek/deepseek-v4:free');
|
|
expect(parseModelChoice(v)).toEqual({ provider: 'openrouter', model: 'deepseek/deepseek-v4:free' });
|
|
expect(parseModelChoice('hermes-agent')).toEqual({ provider: '', model: 'hermes-agent' });
|
|
expect(parseModelChoice('::')).toEqual({ provider: '', model: '' });
|
|
});
|
|
it('validates reasoning effort levels', () => {
|
|
expect(isReasoningEffort('xhigh')).toBe(true);
|
|
expect(isReasoningEffort('')).toBe(true);
|
|
expect(isReasoningEffort('turbo')).toBe(false);
|
|
});
|
|
});
|