test/codex-model-catalog.test.js
Rama main · réplica de lectura del repositorio original.
var test = require('node:test');
var assert = require('node:assert/strict');
var catalog = require('../lib/yoke/codex-model-catalog');
test('catalog uses runtime model IDs, efforts and pagination without hidden duplicates', async function () {
var calls = [];
var models = await catalog.load({ send: async function (method, params) {
calls.push(params.cursor);
return params.cursor ? { data: [{ model: 'new-model', supportedReasoningEfforts: [{ reasoningEffort: 'ultra' }] }] } : {
data: [{ model: 'hidden', hidden: true }, { model: 'other', displayName: 'Other' }, { model: 'other' }], nextCursor: 'next'
};
} });
assert.deepEqual(calls, [null, 'next']);
assert.deepEqual(models.map(function (model) { return model.value; }), ['other', 'new-model']);
assert.deepEqual(models[1].supportedEffortLevels, ['ultra']);
});
test('offline and malformed catalogs retain a fresh fallback containing GPT-6.1 Sol', async function () {
for (var response of [null, {}, { data: [] }]) {
assert.deepEqual(await catalog.load({ send: async function () { return response; } }), catalog.fallback());
}
assert.deepEqual(await catalog.load({ send: async function () { throw new Error('offline'); } }), catalog.fallback());
var initial = catalog.fallback();
initial.pop();
assert.ok(catalog.fallback().includes('gpt-6.1-sol'));
assert.notDeepEqual(initial, catalog.fallback());
});
test('runtime default flags and default efforts are authoritative over the static default', async function () {
var models = await catalog.load({ send: async function () {
return { data: [
{ model: 'account-model', supportedReasoningEfforts: [{ reasoningEffort: 'low' }, { reasoningEffort: 'ultra' }], defaultReasoningEffort: 'low', isDefault: true },
{ model: 'other-model', defaultReasoningEffort: '', isDefault: false },
] };
} });
assert.deepEqual(models[0], { value: 'account-model', displayName: 'account-model', description: '', defaultReasoningEffort: 'low', isDefault: true, supportedEffortLevels: ['low', 'ultra'] });
assert.equal(models[1].isDefault, undefined);
assert.equal(models[1].defaultReasoningEffort, undefined);
assert.equal(catalog.defaultModel(models), 'account-model');
assert.equal(catalog.defaultModel(catalog.fallback()), 'gpt-6.1-sol');
assert.equal(catalog.defaultModel([{ value: 'x', isDefault: 'true' }]), 'x', 'only a boolean flag counts; unflagged lists use their first valid row');
assert.equal(catalog.defaultModel([null, { value: '' }, { value: 'custom-a' }, 'custom-b']), 'custom-a');
assert.equal(catalog.defaultModel([{ value: 'custom-a' }, { value: 'gpt-6.1-sol' }]), 'gpt-6.1-sol', 'the static default is kept when listed');
assert.equal(catalog.defaultModel([]), 'gpt-6.1-sol', 'an empty offline catalog keeps the static default');
var createAdapter = require('../lib/yoke/adapters/codex').createCodexAdapter;
var adapter = createAdapter({ cwd: process.cwd(), createAppServer: function () {
return { started: false, start: async function () { this.started = true; }, notify: function () {},
send: async function (method) { return method === 'model/list' ? { data: [{ model: 'plain' }, { model: 'flagged', isDefault: true }] } : { data: [] }; } };
} });
assert.equal((await adapter.init({})).defaultModel, 'flagged');
});
test('the offline fallback mirrors installed picker presets without retired models', function () {
// @openai/codex 0.162.1 picker-visible presets by priority; gpt-5.5 retired for
// ChatGPT sign-in on 2026-10-14 and gpt-5.2 is deprecated (learn.chatgpt.com/docs/models).
assert.deepEqual(catalog.fallback(), ['gpt-6.1-sol', 'gpt-6-astra', 'gpt-6-sol', 'gpt-6-luna', 'gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna']);
assert.equal(catalog.selectTitleModel(catalog.fallback()).model, 'gpt-6-luna');
assert.equal(catalog.selectTitleModel(['gpt-5.6-luna', 'gpt-6.1-sol']).model, 'gpt-5.6-luna');
});
test('adapter catalogs remain isolated and preserve the configured default', async function () {
var createAdapter = require('../lib/yoke/adapters/codex').createCodexAdapter;
function adapterFor(model) {
return createAdapter({ cwd: process.cwd(), createAppServer: function () {
return { started: false, start: async function () { this.started = true; }, notify: function () {},
send: async function (method) { return method === 'model/list' ? { data: [{ model: model, supportedReasoningEfforts: [{ reasoningEffort: 'high' }] }] } : { data: [] }; }
};
} });
}
var first = adapterFor('account-one-model');
var second = adapterFor('account-two-model');
assert.ok((await first.supportedModels()).includes('gpt-6.1-sol'));
var ready = await first.init({});
await second.init({});
assert.equal(ready.defaultModel, 'account-one-model', 'an unflagged runtime list never names an unlisted static default');
assert.equal((await first.supportedModels())[0].value, 'account-one-model');
assert.equal((await second.supportedModels())[0].value, 'account-two-model');
});
test('a runtime default effort reaches Default AI through the shared vendor catalog', async function () {
var createAdapter = require('../lib/yoke/adapters/codex').createCodexAdapter;
var adapter = createAdapter({ cwd: process.cwd(), createAppServer: function () {
return { started: false, start: async function () { this.started = true; }, notify: function () {},
send: async function (method) {
return method === 'model/list' ? { data: [
{ model: 'custom-a', defaultReasoningEffort: 'low', supportedReasoningEfforts: [{ reasoningEffort: 'low' }, { reasoningEffort: 'high' }] },
{ model: 'custom-b', isDefault: true, defaultReasoningEffort: 'high', supportedReasoningEfforts: [{ reasoningEffort: 'medium' }, { reasoningEffort: 'high' }] },
] } : { data: [] };
} };
} });
var sm = { sessions: new Map(), defaultModelByVendor: {}, modelsByVendor: {}, capabilitiesByVendor: {}, availableVendors: ['codex'], installedVendors: ['codex'] };
var models = require('../lib/project-models').attachModels({ cwd: process.cwd(), slug: 'catalog-default', sm: sm, sdk: {}, adapters: { codex: adapter },
sendTo: function () {}, getSessionForWs: function () { return null; }, getLinuxUserForWs: function () { return null; }, serverPort: 2633, serverTls: false, serverAuthToken: null });
var vendorCatalog = await models.getVendorCatalog({}, 'codex');
assert.equal(vendorCatalog.defaultModel, 'custom-b');
var resolved = await require('../lib/default-ai-runtime').resolveDefaultAiRuntime({
getPreference: function () { return { preference: { vendor: 'codex' } }; },
getAvailability: function () { return ['codex']; },
getCatalog: function () { return vendorCatalog; },
});
assert.equal(resolved.ready, true);
assert.equal(resolved.model, 'custom-b');
assert.equal(resolved.effort, 'high', 'the runtime default effort applies when no effort is saved');
var explicit = await require('../lib/default-ai-runtime').resolveDefaultAiRuntime({
getPreference: function () { return { preference: { vendor: 'codex', model: 'custom-a', effort: 'high' } }; },
getAvailability: function () { return ['codex']; },
getCatalog: function () { return vendorCatalog; },
});
assert.equal(explicit.effort, 'high', 'a saved effort still wins over the runtime default');
});