Makelore 2.0 initial clean snapshot
This commit is contained in:
329
tests/unit/model-options.test.ts
Normal file
329
tests/unit/model-options.test.ts
Normal file
@@ -0,0 +1,329 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
buildConfiguredModelOptions,
|
||||
buildRuntimeProviderOptions,
|
||||
formatModelRefLabel,
|
||||
getConfiguredModelCapabilityLabel,
|
||||
resolveRuntimeProviderKey,
|
||||
} from '../../src/lib/model-options';
|
||||
import type { ProviderAccount, ProviderVendorInfo, ProviderWithKeyInfo } from '../../src/lib/providers';
|
||||
import type { OpencodeRuntimeConfigSummary } from '../../src/types/opencode';
|
||||
|
||||
const now = '2026-04-28T00:00:00.000Z';
|
||||
|
||||
function account(overrides: Partial<ProviderAccount>): ProviderAccount {
|
||||
return {
|
||||
id: 'custom-alpha1234',
|
||||
vendorId: 'custom',
|
||||
label: 'Alpha',
|
||||
authMode: 'api_key',
|
||||
model: 'model-alpha',
|
||||
enabled: true,
|
||||
isDefault: false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
...overrides,
|
||||
} as ProviderAccount;
|
||||
}
|
||||
|
||||
function status(id: string, hasKey = true): ProviderWithKeyInfo {
|
||||
return {
|
||||
id,
|
||||
type: 'custom',
|
||||
name: id,
|
||||
enabled: true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
hasKey,
|
||||
keyMasked: hasKey ? 'sk-***' : null,
|
||||
} as ProviderWithKeyInfo;
|
||||
}
|
||||
|
||||
function vendor(id: ProviderVendorInfo['id'], name = id): ProviderVendorInfo {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
icon: '',
|
||||
placeholder: '',
|
||||
requiresApiKey: true,
|
||||
category: id === 'custom' ? 'custom' : 'official',
|
||||
supportedAuthModes: ['api_key'],
|
||||
defaultAuthMode: 'api_key',
|
||||
supportsMultipleAccounts: true,
|
||||
} as ProviderVendorInfo;
|
||||
}
|
||||
|
||||
describe('model option helpers', () => {
|
||||
it('formats model refs using only the text after the provider prefix', () => {
|
||||
expect(formatModelRefLabel('openrouter/openai/gpt-5.4')).toBe('openai/gpt-5.4');
|
||||
expect(formatModelRefLabel('custom-alpha1234/model-alpha')).toBe('model-alpha');
|
||||
});
|
||||
|
||||
it('builds one configured custom model option per account', () => {
|
||||
const options = buildConfiguredModelOptions(
|
||||
[
|
||||
account({ id: 'alpha1234', model: 'model-alpha', updatedAt: '2026-04-03T00:00:00.000Z' }),
|
||||
account({ id: 'beta5678', label: 'Beta', model: 'provider/model-beta', updatedAt: '2026-04-02T00:00:00.000Z' }),
|
||||
],
|
||||
[status('alpha1234'), status('beta5678')],
|
||||
'alpha1234',
|
||||
);
|
||||
|
||||
expect(options).toEqual([
|
||||
{
|
||||
modelRef: 'alpha1234/model-alpha',
|
||||
label: 'model-alpha',
|
||||
runtimeProviderKey: 'alpha1234',
|
||||
accountId: 'alpha1234',
|
||||
capability: 'text',
|
||||
},
|
||||
{
|
||||
modelRef: 'beta5678/provider/model-beta',
|
||||
label: 'provider/model-beta',
|
||||
runtimeProviderKey: 'beta5678',
|
||||
accountId: 'beta5678',
|
||||
capability: 'text',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('expands configured fallback models into selectable options for the same runtime provider', () => {
|
||||
const options = buildConfiguredModelOptions(
|
||||
[
|
||||
account({
|
||||
id: 'niancode-user-models',
|
||||
label: 'Makelore Models',
|
||||
model: 'gpt-4.1-mini',
|
||||
fallbackModels: ['gpt-4o-mini', 'qwen3-coder', 'gpt-4o-mini'],
|
||||
}),
|
||||
],
|
||||
[status('niancode-user-models')],
|
||||
'niancode-user-models',
|
||||
);
|
||||
|
||||
expect(options).toEqual([
|
||||
{
|
||||
modelRef: 'niancode-user-models/gpt-4.1-mini',
|
||||
label: 'gpt-4.1-mini',
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
capability: 'text',
|
||||
},
|
||||
{
|
||||
modelRef: 'niancode-user-models/gpt-4o-mini',
|
||||
label: 'gpt-4o-mini',
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
capability: 'text',
|
||||
},
|
||||
{
|
||||
modelRef: 'niancode-user-models/qwen3-coder',
|
||||
label: 'qwen3-coder',
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
capability: 'text',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('marks known imported image-input models as multimodal options', () => {
|
||||
const options = buildConfiguredModelOptions(
|
||||
[
|
||||
account({
|
||||
id: 'niancode-user-models',
|
||||
label: 'Makelore Models',
|
||||
model: 'qwen3.6-plus',
|
||||
fallbackModels: ['deepseek-chat'],
|
||||
}),
|
||||
],
|
||||
[status('niancode-user-models')],
|
||||
'niancode-user-models',
|
||||
);
|
||||
|
||||
expect(options).toMatchObject([
|
||||
{ label: 'qwen3.6-plus', capability: 'multimodal' },
|
||||
{ label: 'deepseek-chat', capability: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('falls back to known model capability when runtime summaries omit image metadata', () => {
|
||||
const [option] = buildConfiguredModelOptions(
|
||||
[
|
||||
account({
|
||||
id: 'niancode-user-models',
|
||||
label: 'Makelore Models',
|
||||
model: 'qwen3.6-plus',
|
||||
}),
|
||||
],
|
||||
[status('niancode-user-models')],
|
||||
'niancode-user-models',
|
||||
);
|
||||
const runtimeSummary: OpencodeRuntimeConfigSummary = {
|
||||
model: 'niancode-user-models/qwen3.6-plus',
|
||||
smallModel: null,
|
||||
providerIds: ['niancode-user-models'],
|
||||
providerCount: 1,
|
||||
providers: [
|
||||
{
|
||||
id: 'niancode-user-models',
|
||||
name: 'Makelore Models',
|
||||
modelIds: ['qwen3.6-plus'],
|
||||
hasApiKey: true,
|
||||
headerNames: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(getConfiguredModelCapabilityLabel(option, runtimeSummary)).toBe('多模态');
|
||||
});
|
||||
|
||||
it('exposes only imported Works Square models when that account is available', () => {
|
||||
const options = buildConfiguredModelOptions(
|
||||
[
|
||||
account({
|
||||
id: 'openai',
|
||||
vendorId: 'openai',
|
||||
label: 'OpenAI',
|
||||
model: 'gpt-5.4',
|
||||
}),
|
||||
account({
|
||||
id: 'niancode-user-models',
|
||||
label: 'Makelore Models',
|
||||
model: 'gpt-4.1-mini',
|
||||
fallbackModels: ['gpt-4o-mini'],
|
||||
}),
|
||||
],
|
||||
[status('openai'), status('niancode-user-models')],
|
||||
'openai',
|
||||
);
|
||||
|
||||
expect(options).toEqual([
|
||||
{
|
||||
modelRef: 'niancode-user-models/gpt-4.1-mini',
|
||||
label: 'gpt-4.1-mini',
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
capability: 'text',
|
||||
},
|
||||
{
|
||||
modelRef: 'niancode-user-models/gpt-4o-mini',
|
||||
label: 'gpt-4o-mini',
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
capability: 'text',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('exposes only the imported Works Square runtime provider when that account is available', () => {
|
||||
const options = buildRuntimeProviderOptions(
|
||||
[
|
||||
account({
|
||||
id: 'openai',
|
||||
vendorId: 'openai',
|
||||
label: 'OpenAI',
|
||||
model: 'gpt-5.4',
|
||||
}),
|
||||
account({
|
||||
id: 'niancode-user-models',
|
||||
label: 'Makelore Models',
|
||||
model: 'gpt-4.1-mini',
|
||||
}),
|
||||
],
|
||||
[status('openai'), status('niancode-user-models')],
|
||||
[vendor('openai', 'OpenAI'), vendor('custom', 'Custom')],
|
||||
'openai',
|
||||
);
|
||||
|
||||
expect(options).toEqual([
|
||||
{
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
label: 'Makelore Models (Custom)',
|
||||
modelIdPlaceholder: undefined,
|
||||
configuredModelId: 'gpt-4.1-mini',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not expose fallback configured models when the imported Works Square account exists', () => {
|
||||
const options = buildConfiguredModelOptions(
|
||||
[
|
||||
account({
|
||||
id: 'openai',
|
||||
vendorId: 'openai',
|
||||
label: 'OpenAI',
|
||||
model: 'gpt-5.4',
|
||||
}),
|
||||
account({
|
||||
id: 'niancode-user-models',
|
||||
label: 'Makelore Models',
|
||||
model: 'gpt-4.1-mini',
|
||||
enabled: false,
|
||||
}),
|
||||
],
|
||||
[status('openai'), status('niancode-user-models')],
|
||||
'openai',
|
||||
);
|
||||
|
||||
expect(options).toEqual([]);
|
||||
});
|
||||
|
||||
it('keeps prefixed account models intact and skips accounts without credentials', () => {
|
||||
const runtimeKey = resolveRuntimeProviderKey(account({ id: 'gamma9012' }));
|
||||
const options = buildConfiguredModelOptions(
|
||||
[
|
||||
account({ id: 'gamma9012', model: `${runtimeKey}/model-gamma` }),
|
||||
account({ id: 'delta3456', label: 'Delta', model: 'model-delta' }),
|
||||
],
|
||||
[status('gamma9012'), status('delta3456', false)],
|
||||
null,
|
||||
);
|
||||
|
||||
expect(options).toHaveLength(1);
|
||||
expect(options[0].modelRef).toBe('gamma9012/model-gamma');
|
||||
expect(options[0].label).toBe('model-gamma');
|
||||
});
|
||||
|
||||
it('strips DeepSeek routing prefixes from imported Works Square models', () => {
|
||||
const options = buildConfiguredModelOptions(
|
||||
[
|
||||
account({
|
||||
id: 'niancode-user-models',
|
||||
label: 'Makelore Models',
|
||||
model: 'deepseek/deepseek-v4-pro',
|
||||
fallbackModels: ['deepseek/deepseek-chat'],
|
||||
}),
|
||||
],
|
||||
[status('niancode-user-models')],
|
||||
'niancode-user-models',
|
||||
);
|
||||
|
||||
expect(options).toEqual([
|
||||
{
|
||||
modelRef: 'niancode-user-models/deepseek-v4-pro',
|
||||
label: 'deepseek-v4-pro',
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
capability: 'text',
|
||||
},
|
||||
{
|
||||
modelRef: 'niancode-user-models/deepseek-chat',
|
||||
label: 'deepseek-chat',
|
||||
runtimeProviderKey: 'niancode-user-models',
|
||||
accountId: 'niancode-user-models',
|
||||
capability: 'text',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('treats malformed provider snapshots as empty options', () => {
|
||||
expect(
|
||||
buildConfiguredModelOptions(
|
||||
{} as ProviderAccount[],
|
||||
{} as ProviderWithKeyInfo[],
|
||||
null,
|
||||
),
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user