Files
NetMesh/infrastructure/ai/types.test.ts

244 lines
8.8 KiB
TypeScript
Raw Normal View History

import test from 'node:test';
import assert from 'node:assert/strict';
import {
CLAUDE_MODEL_PRESETS,
CODEBUDDY_MODEL_PRESETS,
CODEX_GPT_5_6_MIN_CLI_VERSION,
CODEX_MODEL_PRESETS,
CURSOR_MODEL_PRESETS,
GROK_MODEL_PRESETS,
extractCliSemver,
filterAgentModelPresetsForCliVersion,
getAgentModelPresets,
resolveAgentCliVersion,
resolveAgentModelSelection,
resolveDiscoveredAgentCliVersion,
} from './types';
test('Claude presets advertise effort levels separately from the model id', () => {
for (const preset of CLAUDE_MODEL_PRESETS) {
assert.deepEqual(preset.thinkingLevels, ['low', 'medium', 'high', 'max']);
assert.ok(preset.defaultThinkingLevel);
}
assert.equal(resolveAgentModelSelection(CLAUDE_MODEL_PRESETS[0]!), 'default/medium');
});
test('getAgentModelPresets returns CodeBuddy fallback models for command paths', () => {
assert.deepEqual(
getAgentModelPresets('/opt/homebrew/bin/codebuddy'),
CODEBUDDY_MODEL_PRESETS,
);
assert.ok(CODEBUDDY_MODEL_PRESETS.some((model) => model.id === 'deepseek-v4-pro'));
});
test('getAgentModelPresets returns Cursor presets for cursor-agent paths and sdkBackend', () => {
assert.deepEqual(getAgentModelPresets('/Users/me/.local/bin/cursor-agent', 'cursor'), CURSOR_MODEL_PRESETS);
assert.deepEqual(getAgentModelPresets('/usr/bin/cursor-agent'), CURSOR_MODEL_PRESETS);
// Bare `agent` is no longer treated as Cursor without an explicit sdkBackend.
assert.deepEqual(getAgentModelPresets('/Users/me/.local/bin/agent'), []);
assert.equal(getAgentModelPresets('/Users/me/.local/bin/agent', 'cursor')[0]?.id, 'auto');
assert.deepEqual(
getAgentModelPresets(undefined, 'cursor').find((model) => model.id === 'gpt-5.5')?.thinkingLevels,
['low', 'medium', 'high'],
);
assert.deepEqual(
getAgentModelPresets(undefined, 'codebuddy')[0]?.thinkingLevels,
['low', 'medium', 'high', 'xhigh'],
);
});
test('getAgentModelPresets keeps Codex presets separate from CodeBuddy presets', () => {
assert.deepEqual(getAgentModelPresets('codex'), CODEX_MODEL_PRESETS);
assert.notDeepEqual(CODEBUDDY_MODEL_PRESETS, CODEX_MODEL_PRESETS);
});
test('getAgentModelPresets returns curated Grok fallback when runtime catalog is empty', () => {
assert.ok(GROK_MODEL_PRESETS.length > 0);
assert.deepEqual(getAgentModelPresets(undefined, 'grok'), GROK_MODEL_PRESETS);
assert.deepEqual(getAgentModelPresets('/usr/local/bin/grok'), GROK_MODEL_PRESETS);
assert.deepEqual(getAgentModelPresets('C:\\\\Tools\\\\grok.exe', 'grok'), GROK_MODEL_PRESETS);
assert.equal(getAgentModelPresets(undefined, 'grok')[0]?.id, 'grok-4.5');
assert.deepEqual(getAgentModelPresets(undefined, 'grok')[0]?.thinkingLevels, [
'high',
'medium',
'low',
]);
assert.equal(getAgentModelPresets(undefined, 'grok')[0]?.defaultThinkingLevel, 'high');
assert.deepEqual(getAgentModelPresets(undefined, 'grok')[1], {
id: 'grok-4.6',
name: 'Grok 4.6',
thinkingLevels: ['xhigh', 'high', 'medium', 'low'],
defaultThinkingLevel: 'high',
});
// Empty/failed runtime catalog path: shared resolver still yields a non-empty list.
const runtimeCatalog: Array<{ id: string; name: string }> = [];
const resolved = runtimeCatalog.length > 0
? runtimeCatalog
: getAgentModelPresets('grok', 'grok');
assert.ok(resolved.length > 0);
assert.deepEqual(resolved, GROK_MODEL_PRESETS);
});
test('CODEX_MODEL_PRESETS lists GPT-5.6 Sol/Terra/Luna with official reasoning levels', () => {
const byId = Object.fromEntries(CODEX_MODEL_PRESETS.map((model) => [model.id, model]));
assert.deepEqual(
CODEX_MODEL_PRESETS.map((model) => model.id),
[
'gpt-5.6-sol',
'gpt-5.6-terra',
'gpt-5.6-luna',
'gpt-5.5',
'gpt-5.4',
'gpt-5.4-mini',
'gpt-5.2',
],
);
assert.equal(byId['gpt-5.6-sol']?.description, 'Latest');
assert.equal(byId['gpt-5.6-sol']?.defaultThinkingLevel, 'low');
assert.equal(byId['gpt-5.6-terra']?.defaultThinkingLevel, 'medium');
assert.equal(byId['gpt-5.6-luna']?.defaultThinkingLevel, 'medium');
assert.deepEqual(byId['gpt-5.6-sol']?.thinkingLevels, [
'low',
'medium',
'high',
'xhigh',
'max',
'ultra',
]);
assert.deepEqual(byId['gpt-5.6-terra']?.thinkingLevels, [
'low',
'medium',
'high',
'xhigh',
'max',
'ultra',
]);
// Luna omits ultra per openai/codex models-manager catalog (+ lobehub).
assert.deepEqual(byId['gpt-5.6-luna']?.thinkingLevels, [
'low',
'medium',
'high',
'xhigh',
'max',
]);
assert.deepEqual(byId['gpt-5.5']?.thinkingLevels, ['low', 'medium', 'high', 'xhigh']);
assert.deepEqual(byId['gpt-5.4']?.thinkingLevels, ['low', 'medium', 'high', 'xhigh']);
assert.deepEqual(byId['gpt-5.4-mini']?.thinkingLevels, ['low', 'medium', 'high', 'xhigh']);
assert.deepEqual(byId['gpt-5.2']?.thinkingLevels, ['low', 'medium', 'high', 'xhigh']);
});
test('resolveAgentModelSelection uses catalog default effort, not last array entry', () => {
assert.equal(resolveAgentModelSelection(CODEX_MODEL_PRESETS[0]!), 'gpt-5.6-sol/low');
assert.equal(
resolveAgentModelSelection(CODEX_MODEL_PRESETS.find((m) => m.id === 'gpt-5.6-terra')!),
'gpt-5.6-terra/medium',
);
assert.equal(
resolveAgentModelSelection({
id: 'custom',
name: 'Custom',
thinkingLevels: ['low', 'high'],
}),
'custom/low',
);
assert.equal(
resolveAgentModelSelection({ id: 'plain', name: 'Plain' }),
'plain',
);
assert.equal(
resolveAgentModelSelection({
id: 'glm-5.1',
name: 'GLM 5.1',
thinkingLevels: ['low', 'medium', 'high'],
defaultThinkingLevel: 'medium',
encodeDefaultThinking: false,
}),
'glm-5.1',
);
});
test('filterAgentModelPresetsForCliVersion gates GPT-5.6 on CLI < 0.144.0', () => {
assert.equal(extractCliSemver('codex-cli 0.136.0'), '0.136.0');
assert.equal(CODEX_GPT_5_6_MIN_CLI_VERSION, '0.144.0');
const oldCli = filterAgentModelPresetsForCliVersion(CODEX_MODEL_PRESETS, '0.136.0');
assert.deepEqual(
oldCli.map((model) => model.id),
['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.2'],
);
assert.equal(resolveAgentModelSelection(oldCli[0]!), 'gpt-5.5/medium');
const newCli = filterAgentModelPresetsForCliVersion(CODEX_MODEL_PRESETS, 'codex-cli 0.144.1');
assert.equal(newCli[0]?.id, 'gpt-5.6-sol');
// Unknown version: hide version-gated models so pre-discovery cannot
// auto-default old installs onto Sol. Ungated presets keep the picker usable.
assert.deepEqual(
filterAgentModelPresetsForCliVersion(CODEX_MODEL_PRESETS, undefined).map((m) => m.id),
['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.2'],
);
});
test('resolveDiscoveredAgentCliVersion matches command path or sdk backend', () => {
assert.equal(
resolveDiscoveredAgentCliVersion(
{ command: '/usr/local/bin/codex', sdkBackend: 'codex' },
[{ command: 'codex', path: '/usr/local/bin/codex', binPath: '/usr/local/bin/codex', sdkBackend: 'codex', version: '0.144.1' }],
),
'0.144.1',
);
// Manual path must not inherit PATH discovery version for a different binary.
assert.equal(
resolveDiscoveredAgentCliVersion(
{ command: '/opt/old/codex', sdkBackend: 'codex' },
[{ command: 'codex', path: '/usr/local/bin/codex', binPath: '/usr/local/bin/codex', sdkBackend: 'codex', version: '0.144.1' }],
),
undefined,
);
assert.equal(
resolveDiscoveredAgentCliVersion(
{ command: 'codex', sdkBackend: 'codex' },
[{ command: 'claude', path: '/bin/claude', binPath: '/bin/claude', sdkBackend: 'claude', version: '1.0.0' }],
),
undefined,
);
assert.equal(
resolveDiscoveredAgentCliVersion(
{ command: 'codex', sdkBackend: 'codex' },
[{ command: 'codex', path: '/usr/local/bin/codex', binPath: '/usr/local/bin/codex', sdkBackend: 'codex', version: '0.144.1' }],
),
'0.144.1',
);
});
test('resolveAgentCliVersion prefers stored cliVersion over discovery', () => {
assert.equal(
resolveAgentCliVersion(
{ command: '/opt/custom/codex', sdkBackend: 'codex', cliVersion: 'codex-cli 0.144.3' },
[{ command: 'codex', path: '/usr/local/bin/codex', binPath: '/usr/local/bin/codex', sdkBackend: 'codex', version: '0.136.0' }],
),
'codex-cli 0.144.3',
);
// Custom path with stored probe unlocks GPT-5.6 even when not on PATH.
const gated = filterAgentModelPresetsForCliVersion(
CODEX_MODEL_PRESETS,
resolveAgentCliVersion(
{ command: '/opt/custom/codex', sdkBackend: 'codex', cliVersion: '0.144.0' },
[],
),
);
assert.equal(gated[0]?.id, 'gpt-5.6-sol');
});
test('getAgentModelPresets resolves Windows command paths with backslashes', () => {
assert.deepEqual(
getAgentModelPresets('C\\Users\\foo\\AppData\\Roaming\\npm\\codex.cmd'),
CODEX_MODEL_PRESETS,
);
assert.deepEqual(
getAgentModelPresets('C\\Program Files\\nodejs\\claude.exe'),
CLAUDE_MODEL_PRESETS,
);
});