fix(#2601): config-set-model-profile now accepts 'inherit' value (#2707)

VALID_PROFILES was derived solely from Object.keys(MODEL_PROFILES['gsd-planner']),
which only contained the named tiers (quality/balanced/budget/adaptive). The
cmdConfigSetModelProfile validator rejected 'inherit' even though the runtime has
supported it since #1829. Fix: append 'inherit' to VALID_PROFILES and handle it
in getAgentToModelMapForProfile so the agent→model table shows 'inherit' instead
of undefined.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-25 12:09:27 -04:00
committed by GitHub
parent b7ff14fe51
commit 8393f4b355
3 changed files with 60 additions and 6 deletions

View File

@@ -26,7 +26,7 @@ const MODEL_PROFILES = {
'gsd-doc-writer': { quality: 'opus', balanced: 'sonnet', budget: 'haiku', adaptive: 'sonnet' },
'gsd-doc-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'haiku' },
};
const VALID_PROFILES = Object.keys(MODEL_PROFILES['gsd-planner']);
const VALID_PROFILES = [...Object.keys(MODEL_PROFILES['gsd-planner']), 'inherit'];
/**
* Formats the agent-to-model mapping as a human-readable table (in string format).
@@ -58,7 +58,9 @@ function formatAgentToModelMapAsTable(agentToModelMap) {
function getAgentToModelMapForProfile(normalizedProfile) {
const agentToModelMap = {};
for (const [agent, profileToModelMap] of Object.entries(MODEL_PROFILES)) {
agentToModelMap[agent] = profileToModelMap[normalizedProfile];
agentToModelMap[agent] = normalizedProfile === 'inherit'
? 'inherit'
: profileToModelMap[normalizedProfile];
}
return agentToModelMap;
}

View File

@@ -0,0 +1,49 @@
'use strict';
/**
* Regression tests for bug #2601
*
* `config-set-model-profile inherit` (and `config-set model_profile inherit`)
* was rejected by the validator even though the runtime accepts 'inherit' as a
* valid model_profile value meaning "inherit from parent configuration".
*
* Root cause: VALID_PROFILES in model-profiles.cjs is derived from
* Object.keys(MODEL_PROFILES['gsd-planner']), which does not include 'inherit'.
* cmdConfigSetModelProfile() rejects any value not in VALID_PROFILES.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
describe('bug #2601: config-set-model-profile accepts inherit', () => {
test('config-set-model-profile inherit succeeds', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(['config-set-model-profile', 'inherit'], tmpDir);
assert.ok(result.success, `should accept inherit: ${result.error}`);
});
test('config-set model_profile inherit succeeds', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(['config-set', 'model_profile', 'inherit'], tmpDir);
assert.ok(result.success, `config-set model_profile inherit should succeed: ${result.error}`);
});
test('config-set-model-profile inherit writes inherit to config', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
runGsdTools(['config-set-model-profile', 'inherit'], tmpDir);
const getResult = runGsdTools(['config-get', 'model_profile'], tmpDir);
assert.ok(getResult.success, `config-get should succeed: ${getResult.error}`);
assert.strictEqual(JSON.parse(getResult.output), 'inherit');
});
test('config-set-model-profile still rejects truly invalid profiles', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(['config-set-model-profile', 'not-a-real-profile'], tmpDir);
assert.ok(!result.success, 'should reject invalid profiles');
});
});

View File

@@ -65,13 +65,16 @@ describe('MODEL_PROFILES', () => {
// ─── VALID_PROFILES ───────────────────────────────────────────────────────────
describe('VALID_PROFILES', () => {
test('contains quality, balanced, and budget', () => {
assert.deepStrictEqual(VALID_PROFILES.sort(), ['adaptive', 'balanced', 'budget', 'quality']);
test('contains quality, balanced, budget, adaptive, and inherit', () => {
assert.deepStrictEqual(VALID_PROFILES.sort(), ['adaptive', 'balanced', 'budget', 'inherit', 'quality']);
});
test('is derived from MODEL_PROFILES keys', () => {
test('includes all MODEL_PROFILES keys plus inherit', () => {
const fromData = Object.keys(MODEL_PROFILES['gsd-planner']);
assert.deepStrictEqual(VALID_PROFILES.sort(), fromData.sort());
for (const profile of fromData) {
assert.ok(VALID_PROFILES.includes(profile), `VALID_PROFILES should include ${profile}`);
}
assert.ok(VALID_PROFILES.includes('inherit'), 'VALID_PROFILES should include inherit');
});
});