fix(config-query): thread workstream through resolveModel handler

resolveModel ignored _workstream, unlike configGet/configPath which both
forward it to planningPaths/loadConfig. Different workstreams may have
different model_profile settings.

Addresses coderabbit finding on PR #2742.
This commit is contained in:
Tom Boucher
2026-04-26 11:23:51 -04:00
parent 3a623b1117
commit cfc79d211f
2 changed files with 29 additions and 2 deletions

View File

@@ -165,6 +165,31 @@ describe('resolveModel', () => {
const data = result.data as Record<string, unknown>;
expect(data).toHaveProperty('model', '');
});
it('resolveModel uses workstream config when --ws is specified', async () => {
const { resolveModel } = await import('./config-query.js');
// Root config: balanced profile → gsd-executor resolves to 'sonnet'
await writeFile(
join(tmpDir, '.planning', 'config.json'),
JSON.stringify({ model_profile: 'balanced' }),
);
// Workstream config: quality profile → gsd-executor resolves to 'opus'
await mkdir(join(tmpDir, '.planning', 'workstreams', 'frontend'), { recursive: true });
await writeFile(
join(tmpDir, '.planning', 'workstreams', 'frontend', 'config.json'),
JSON.stringify({ model_profile: 'quality' }),
);
const rootResult = await resolveModel(['gsd-executor'], tmpDir);
const rootData = rootResult.data as Record<string, unknown>;
expect(rootData.profile).toBe('balanced');
expect(rootData.model).toBe('sonnet');
const wsResult = await resolveModel(['gsd-executor'], tmpDir, 'frontend');
const wsData = wsResult.data as Record<string, unknown>;
expect(wsData.profile).toBe('quality');
expect(wsData.model).toBe('opus');
});
});
// ─── MODEL_PROFILES ─────────────────────────────────────────────────────────

View File

@@ -144,16 +144,18 @@ export const configPath: QueryHandler = async (_args, projectDir, workstream) =>
*
* @param args - args[0] is the agent type (e.g., 'gsd-planner')
* @param projectDir - Project root directory
* @param workstream - Optional workstream name; forwarded to loadConfig so per-workstream
* model_profile settings are respected (mirrors configGet/configPath behavior)
* @returns QueryResult with { model, profile } or { model, profile, unknown_agent: true }
* @throws GSDError with Validation classification if agent type not provided
*/
export const resolveModel: QueryHandler = async (args, projectDir) => {
export const resolveModel: QueryHandler = async (args, projectDir, workstream) => {
const agentType = args[0];
if (!agentType) {
throw new GSDError('agent-type required', ErrorClassification.Validation);
}
const config = await loadConfig(projectDir);
const config = await loadConfig(projectDir, workstream);
const profile = String(config.model_profile || 'balanced').toLowerCase();
// Check per-agent override first