mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
feat(model-profiles): add adaptive preset with role-based model assignment (#1806)
Add a fourth model profile preset that assigns models by agent role: opus for planning and debugging (reasoning-critical), sonnet for execution and research (follows instructions), haiku for mapping and checking (high volume, structured output). This gives solo developers on paid API tiers a cost-effective middle ground — quality where it matters most (planning) without overspending on mechanical tasks (mapping, checking). Per-agent overrides via model_overrides continue to take precedence over any profile preset, including adaptive. Closes #1713 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,23 +7,23 @@
|
||||
* would be faster, use fewer tokens, and be less error-prone).
|
||||
*/
|
||||
const MODEL_PROFILES = {
|
||||
'gsd-planner': { quality: 'opus', balanced: 'opus', budget: 'sonnet' },
|
||||
'gsd-roadmapper': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
|
||||
'gsd-executor': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
|
||||
'gsd-phase-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-project-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-research-synthesizer': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-debugger': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
|
||||
'gsd-codebase-mapper': { quality: 'sonnet', balanced: 'haiku', budget: 'haiku' },
|
||||
'gsd-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-plan-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-integration-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-nyquist-auditor': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-ui-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-ui-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-ui-auditor': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-doc-writer': { quality: 'opus', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-doc-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
||||
'gsd-planner': { quality: 'opus', balanced: 'opus', budget: 'sonnet', adaptive: 'opus' },
|
||||
'gsd-roadmapper': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet', adaptive: 'sonnet' },
|
||||
'gsd-executor': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet', adaptive: 'sonnet' },
|
||||
'gsd-phase-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku', adaptive: 'sonnet' },
|
||||
'gsd-project-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku', adaptive: 'sonnet' },
|
||||
'gsd-research-synthesizer': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'haiku' },
|
||||
'gsd-debugger': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet', adaptive: 'opus' },
|
||||
'gsd-codebase-mapper': { quality: 'sonnet', balanced: 'haiku', budget: 'haiku', adaptive: 'haiku' },
|
||||
'gsd-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'sonnet' },
|
||||
'gsd-plan-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'haiku' },
|
||||
'gsd-integration-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'haiku' },
|
||||
'gsd-nyquist-auditor': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'haiku' },
|
||||
'gsd-ui-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku', adaptive: 'sonnet' },
|
||||
'gsd-ui-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'haiku' },
|
||||
'gsd-ui-auditor': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', adaptive: 'haiku' },
|
||||
'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']);
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ Task(
|
||||
|
||||
**Note:** Opus-tier agents resolve to `"inherit"` (not `"opus"`). This causes the agent to use the parent session's model, avoiding conflicts with organization policies that may block specific opus versions.
|
||||
|
||||
If `model_profile` is `"adaptive"`, agents resolve to role-based assignments (opus/sonnet/haiku based on agent type).
|
||||
|
||||
If `model_profile` is `"inherit"`, all agents resolve to `"inherit"` (useful for OpenCode `/model`).
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -4,20 +4,20 @@ Model profiles control which Claude model each GSD agent uses. This allows balan
|
||||
|
||||
## Profile Definitions
|
||||
|
||||
| Agent | `quality` | `balanced` | `budget` | `inherit` |
|
||||
|-------|-----------|------------|----------|-----------|
|
||||
| gsd-planner | opus | opus | sonnet | inherit |
|
||||
| gsd-roadmapper | opus | sonnet | sonnet | inherit |
|
||||
| gsd-executor | opus | sonnet | sonnet | inherit |
|
||||
| gsd-phase-researcher | opus | sonnet | haiku | inherit |
|
||||
| gsd-project-researcher | opus | sonnet | haiku | inherit |
|
||||
| gsd-research-synthesizer | sonnet | sonnet | haiku | inherit |
|
||||
| gsd-debugger | opus | sonnet | sonnet | inherit |
|
||||
| gsd-codebase-mapper | sonnet | haiku | haiku | inherit |
|
||||
| gsd-verifier | sonnet | sonnet | haiku | inherit |
|
||||
| gsd-plan-checker | sonnet | sonnet | haiku | inherit |
|
||||
| gsd-integration-checker | sonnet | sonnet | haiku | inherit |
|
||||
| gsd-nyquist-auditor | sonnet | sonnet | haiku | inherit |
|
||||
| Agent | `quality` | `balanced` | `budget` | `adaptive` | `inherit` |
|
||||
|-------|-----------|------------|----------|------------|-----------|
|
||||
| gsd-planner | opus | opus | sonnet | opus | inherit |
|
||||
| gsd-roadmapper | opus | sonnet | sonnet | sonnet | inherit |
|
||||
| gsd-executor | opus | sonnet | sonnet | sonnet | inherit |
|
||||
| gsd-phase-researcher | opus | sonnet | haiku | sonnet | inherit |
|
||||
| gsd-project-researcher | opus | sonnet | haiku | sonnet | inherit |
|
||||
| gsd-research-synthesizer | sonnet | sonnet | haiku | haiku | inherit |
|
||||
| gsd-debugger | opus | sonnet | sonnet | opus | inherit |
|
||||
| gsd-codebase-mapper | sonnet | haiku | haiku | haiku | inherit |
|
||||
| gsd-verifier | sonnet | sonnet | haiku | sonnet | inherit |
|
||||
| gsd-plan-checker | sonnet | sonnet | haiku | haiku | inherit |
|
||||
| gsd-integration-checker | sonnet | sonnet | haiku | haiku | inherit |
|
||||
| gsd-nyquist-auditor | sonnet | sonnet | haiku | haiku | inherit |
|
||||
|
||||
## Profile Philosophy
|
||||
|
||||
@@ -37,6 +37,12 @@ Model profiles control which Claude model each GSD agent uses. This allows balan
|
||||
- Haiku for research and verification
|
||||
- Use when: conserving quota, high-volume work, less critical phases
|
||||
|
||||
**adaptive** — Role-based cost optimization
|
||||
- Opus for planning and debugging (where reasoning quality has highest impact)
|
||||
- Sonnet for execution, research, and verification (follows explicit instructions)
|
||||
- Haiku for mapping, checking, and auditing (high volume, structured output)
|
||||
- Use when: optimizing cost without sacrificing plan quality, solo development on paid API tiers
|
||||
|
||||
**inherit** - Follow the current session model
|
||||
- All agents resolve to `inherit`
|
||||
- Best when you switch models interactively (for example OpenCode or Kilo `/model`)
|
||||
|
||||
@@ -174,7 +174,7 @@ Merge new settings into existing config.json:
|
||||
```json
|
||||
{
|
||||
...existing_config,
|
||||
"model_profile": "quality" | "balanced" | "budget" | "inherit",
|
||||
"model_profile": "quality" | "balanced" | "budget" | "adaptive" | "inherit",
|
||||
"workflow": {
|
||||
"research": true/false,
|
||||
"plan_check": true/false,
|
||||
|
||||
@@ -31,11 +31,12 @@ describe('MODEL_PROFILES', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('every agent has quality, balanced, and budget profiles', () => {
|
||||
test('every agent has quality, balanced, budget, and adaptive profiles', () => {
|
||||
for (const [agent, profiles] of Object.entries(MODEL_PROFILES)) {
|
||||
assert.ok(profiles.quality, `${agent} missing quality profile`);
|
||||
assert.ok(profiles.balanced, `${agent} missing balanced profile`);
|
||||
assert.ok(profiles.budget, `${agent} missing budget profile`);
|
||||
assert.ok(profiles.adaptive, `${agent} missing adaptive profile`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -65,7 +66,7 @@ describe('MODEL_PROFILES', () => {
|
||||
|
||||
describe('VALID_PROFILES', () => {
|
||||
test('contains quality, balanced, and budget', () => {
|
||||
assert.deepStrictEqual(VALID_PROFILES.sort(), ['balanced', 'budget', 'quality']);
|
||||
assert.deepStrictEqual(VALID_PROFILES.sort(), ['adaptive', 'balanced', 'budget', 'quality']);
|
||||
});
|
||||
|
||||
test('is derived from MODEL_PROFILES keys', () => {
|
||||
@@ -96,6 +97,24 @@ describe('getAgentToModelMapForProfile', () => {
|
||||
assert.strictEqual(map['gsd-executor'], 'opus');
|
||||
});
|
||||
|
||||
test('returns correct models for adaptive profile', () => {
|
||||
const map = getAgentToModelMapForProfile('adaptive');
|
||||
assert.strictEqual(map['gsd-planner'], 'opus', 'planner should use opus in adaptive');
|
||||
assert.strictEqual(map['gsd-debugger'], 'opus', 'debugger should use opus in adaptive');
|
||||
assert.strictEqual(map['gsd-executor'], 'sonnet', 'executor should use sonnet in adaptive');
|
||||
assert.strictEqual(map['gsd-codebase-mapper'], 'haiku', 'mapper should use haiku in adaptive');
|
||||
assert.strictEqual(map['gsd-plan-checker'], 'haiku', 'checker should use haiku in adaptive');
|
||||
});
|
||||
|
||||
test('resolution order: override > profile > default', () => {
|
||||
// This tests the conceptual resolution — actual runtime test is in resolveModelInternal
|
||||
const map = getAgentToModelMapForProfile('adaptive');
|
||||
// Profile gives planner opus
|
||||
assert.strictEqual(map['gsd-planner'], 'opus');
|
||||
// An override would take precedence (tested via resolveModelInternal in model-alias-map tests)
|
||||
// Default fallback is 'sonnet' (core.cjs line 1320)
|
||||
});
|
||||
|
||||
test('returns all agents in the map', () => {
|
||||
const map = getAgentToModelMapForProfile('balanced');
|
||||
const agentCount = Object.keys(MODEL_PROFILES).length;
|
||||
|
||||
Reference in New Issue
Block a user