Changeset 0.28.0.9 (#181)

This commit is contained in:
2026-03-13 00:31:05 +00:00
parent aa870f1040
commit 33d76e59ab
13 changed files with 244 additions and 125 deletions

View File

@@ -54,15 +54,14 @@ describe('GET /admin/users response contract', () => {
});
// ── /models/enabled response ─────────────────
// Bug: 500 from ambiguous SQL columns in JOIN
// After fix: returns {models: [...]}
// Returns {data: [...], default_model: "..."}
describe('GET /models/enabled response contract', () => {
// ACTUAL backend UserModel struct sends BOTH provider_config_id AND config_id.
// Mock uses provider_config_id as primary (Go struct canonical name)
// and config_id as the alias (populated by resolver for frontend compat).
const backendResponse = {
models: [
data: [
{
id: 'cfg1:gpt-4o',
model_id: 'gpt-4o',
@@ -77,21 +76,22 @@ describe('GET /models/enabled response contract', () => {
pricing: {},
},
],
default_model: '',
};
it('response has "models" array', () => {
assert.ok(Array.isArray(backendResponse.models));
it('response has "data" array', () => {
assert.ok(Array.isArray(backendResponse.data));
});
it('each model has required fields for selector', () => {
for (const m of backendResponse.models) {
for (const m of backendResponse.data) {
assert.ok(m.model_id || m.id, 'must have model_id or id');
assert.ok(m.display_name || m.model_id, 'must have display_name or model_id');
}
});
it('catalog models have provider_config_id (backend canonical)', () => {
const catalogModels = backendResponse.models.filter(m => m.source === 'catalog');
const catalogModels = backendResponse.data.filter(m => m.source === 'catalog');
for (const m of catalogModels) {
assert.ok(m.provider_config_id,
'catalog model must have provider_config_id (Go struct canonical name)');
@@ -99,7 +99,7 @@ describe('GET /models/enabled response contract', () => {
});
it('catalog models have config_id alias matching provider_config_id', () => {
const catalogModels = backendResponse.models.filter(m => m.source === 'catalog');
const catalogModels = backendResponse.data.filter(m => m.source === 'catalog');
for (const m of catalogModels) {
assert.ok(m.config_id,
'catalog model must have config_id (frontend alias)');
@@ -109,7 +109,7 @@ describe('GET /models/enabled response contract', () => {
});
it('capabilities is an object (not null)', () => {
for (const m of backendResponse.models) {
for (const m of backendResponse.data) {
assert.equal(typeof m.capabilities, 'object');
assert.notEqual(m.capabilities, null);
}
@@ -421,9 +421,9 @@ describe('Response shape consistency', () => {
assert.ok('data' in shape, 'teams/members uses "data" key');
});
it('models/enabled uses {models:[]}', () => {
const shape = { models: [] };
assert.ok('models' in shape);
it('models/enabled uses {data:[]}', () => {
const shape = { data: [] };
assert.ok('data' in shape);
});
it('admin/models uses {models:[]}', () => {

View File

@@ -128,7 +128,7 @@ function loadAppModules(overrides = {}) {
* v0.22.8: unified persona naming — no more preset aliases.
*/
function processModelsResponse(data, hiddenModels = new Set()) {
return (data.models || []).map(m => {
return (data.data || data.models || []).map(m => {
const isPersona = !!m.is_persona;
const baseModelId = m.model_id || m.id;
const cfgId = m.config_id || m.provider_config_id || '';