mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-11 03:00:26 +01:00
fix(models): allowlist routing for model-pinned Claude families (W1)
resolveModel lowercases input and strips one trailing [...] context marker. Opus 4.7, Opus 4.8 and Sonnet 5 keep their pinned overlay only for the bare ID, the bare ID plus an 8-digit date, and the bare ID plus -latest; any other suffix (point releases such as claude-sonnet-5-5, claude-opus-4-7-1) falls to the generic claude overlay. claude-opus-5-5 routes to claude explicitly (no new overlay, no new ALL_MODEL_NAMES entry). Fable keeps its prefix match while CLAUDE_FRONTIER_EVAL_MODEL is claude-fable-5-1, guarded by a test. Tests: one test/model-overlays.test.ts case per shape in the plan, plus the lowercase / [1m] marker / family-name cases and the Fable guard.
This commit is contained in:
1 parent
f30b7b788a
commit
2d9d155dd5
2 files changed
+65
-5
No files matched your search
@@ -10,6 +10,7 @@ import type { TemplateContext } from '../scripts/resolvers/types';
|
||||
import { HOST_PATHS } from '../scripts/resolvers/types';
|
||||
import { generateModelOverlay } from '../scripts/resolvers/model-overlay';
|
||||
import { resolveModel } from '../scripts/models';
|
||||
import { CLAUDE_FRONTIER_EVAL_MODEL } from '../lib/eval-model';
|
||||
import { readOverlay } from '../scripts/resolvers/model-overlay';
|
||||
import { generateCompletenessSection } from '../scripts/resolvers/preamble/generate-completeness-section';
|
||||
import { generateSetupCommand } from '../scripts/resolvers/utility';
|
||||
@@ -368,3 +369,47 @@ describe('Sonnet 5 overlay — family nudges', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('model-routing-claude', () => {
|
||||
test.each([
|
||||
['claude-opus-4-7', 'opus-4-7'],
|
||||
['claude-opus-4-7-20260416', 'opus-4-7'],
|
||||
['claude-opus-4-7-latest', 'opus-4-7'],
|
||||
['claude-opus-4-7-1', 'claude'],
|
||||
['claude-opus-4-7-1-20260601', 'claude'],
|
||||
['claude-opus-4-8', 'opus-4-8'],
|
||||
['claude-opus-4-8-20260701', 'opus-4-8'],
|
||||
['claude-opus-4-8-latest', 'opus-4-8'],
|
||||
['claude-opus-4-8-1', 'claude'],
|
||||
['claude-sonnet-5', 'sonnet-5'],
|
||||
['claude-sonnet-5-20260115', 'sonnet-5'],
|
||||
['claude-sonnet-5-latest', 'sonnet-5'],
|
||||
['claude-sonnet-5-5', 'claude'],
|
||||
['claude-sonnet-5-5-20261001', 'claude'],
|
||||
['claude-sonnet-5-10', 'claude'],
|
||||
['claude-sonnet-5-latest-20260101', 'claude'],
|
||||
['claude-opus-5-5', 'claude'],
|
||||
['claude-fable-5', 'fable-5'],
|
||||
['claude-fable-5-1', 'fable-5'],
|
||||
])('%s routes to %s', (input, expected) => {
|
||||
expect(resolveModel(input)).toBe(expected);
|
||||
});
|
||||
|
||||
test('input is lowercased and one trailing [...] marker is stripped', () => {
|
||||
expect(resolveModel('CLAUDE-SONNET-5')).toBe('sonnet-5');
|
||||
expect(resolveModel('claude-sonnet-5[1m]')).toBe('sonnet-5');
|
||||
expect(resolveModel('claude-opus-5-5[1m]')).toBe('claude');
|
||||
});
|
||||
|
||||
test('family names force the pinned profile', () => {
|
||||
expect(resolveModel('opus-4-7')).toBe('opus-4-7');
|
||||
expect(resolveModel('opus-4-8')).toBe('opus-4-8');
|
||||
expect(resolveModel('sonnet-5')).toBe('sonnet-5');
|
||||
});
|
||||
|
||||
test('Fable prefix exception holds only while the frontier eval model is a Fable 5 point release', () => {
|
||||
if (resolveModel('claude-fable-5-99') === 'fable-5') {
|
||||
expect(CLAUDE_FRONTIER_EVAL_MODEL.startsWith('claude-fable-5-')).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user