mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-28 14:59:47 +00:00
Setting `models.tier.deep anthropic:claude-opus-4-8` silently disabled think and auto_think: the Anthropic recipe's chat allowlist stopped at Opus 4.7, the tier-resolved model never joined the extended set that assertTouchpoint's contract promises for config-chosen models, and the resulting probe failure was stamped NO_ANTHROPIC_API_KEY — sending the operator to debug env/keychain when the fix was the model id. Three fixes, one per layer: - recipes/anthropic.ts: add claude-fable-5, claude-opus-4-8, and claude-sonnet-5 to chat models; claude-sonnet-5 to expansion models. - gateway.ts reconfigureGatewayWithEngine: resolve all four tiers and register the results as extended models, honoring the documented contract for models.default / models.tier.* (model-resolver.ts docstring). A tier-only model now validates like a chat/expansion one. - think/index.ts: when the gateway client can't be built, re-probe and label honestly — MODEL_NOT_USABLE:<reason> for unknown_model / unknown_provider, NO_ANTHROPIC_API_KEY only for the actual missing-key case; the stub answer carries the probe detail and fix hint. Tests: recipe-list presence pins; a new gateway-tier-extended-models suite proving a fictional tier model validates post-reconfigure (and an unconfigured one still doesn't); think-pipeline coverage for the honest label (unknown_model beats missing-key even keyless); the existing non-explicit bogus-provider test updated from the old catch-all label to the honest one (no-throw contract unchanged). Verified live: a brain with tier.deep=claude-opus-4-8 had think degrade to gather-only with the misleading key warning; with this change the probe passes and synthesis runs. Co-authored-by: Paolo Belcastro <p3ob7o@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
63 lines
2.8 KiB
TypeScript
63 lines
2.8 KiB
TypeScript
import { describe, it, expect } from 'bun:test';
|
|
import { anthropic } from '../src/core/ai/recipes/anthropic.ts';
|
|
|
|
describe('Anthropic recipe model IDs', () => {
|
|
it('chat models use canonical Anthropic API IDs (no phantom dates)', () => {
|
|
const chatModels = anthropic.touchpoints?.chat?.models ?? [];
|
|
// claude-sonnet-4-6 is the correct API ID per Anthropic docs.
|
|
// The dated form claude-sonnet-4-6-20250929 returns 404 on the API.
|
|
expect(chatModels).toContain('claude-sonnet-4-6');
|
|
expect(chatModels).not.toContain('claude-sonnet-4-6-20250929');
|
|
});
|
|
|
|
it('expansion models use canonical IDs', () => {
|
|
const expansionModels = anthropic.touchpoints?.expansion?.models ?? [];
|
|
expect(expansionModels).toContain('claude-sonnet-4-6');
|
|
expect(expansionModels).not.toContain('claude-sonnet-4-6-20250929');
|
|
});
|
|
|
|
it('does not forward-alias dateless 4.6+ models (they ARE the canonical ID)', () => {
|
|
// Starting with Claude 4.6, Anthropic API IDs are dateless and pinned.
|
|
// No forward alias needed — the dateless form IS the model ID.
|
|
expect(anthropic.aliases?.['claude-sonnet-4-6']).toBeUndefined();
|
|
expect(anthropic.aliases?.['claude-opus-4-7']).toBeUndefined();
|
|
});
|
|
|
|
it('pre-4.6 models still have date-based aliases', () => {
|
|
// Haiku 4.5 predates the dateless convention, keeps its alias
|
|
expect(anthropic.aliases?.['claude-haiku-4-5']).toBe('claude-haiku-4-5-20251001');
|
|
});
|
|
|
|
it('reverse-alias rescues stale broken Sonnet 4.6 ID', () => {
|
|
// v0.31.6 shipped 'claude-sonnet-4-6-20250929' as a hardcoded default.
|
|
// Users with stale config (models.dream.synthesize, facts.extraction_model)
|
|
// must keep working — the reverse alias rewrites broken → canonical.
|
|
expect(anthropic.aliases?.['claude-sonnet-4-6-20250929']).toBe('claude-sonnet-4-6');
|
|
});
|
|
|
|
it('current-generation models are listed for chat (Fable 5 / Opus 4.8 / Sonnet 5)', () => {
|
|
// Regression guard for the tier-config incident: a brain with
|
|
// `models.tier.deep = anthropic:claude-opus-4-8` had think/auto_think
|
|
// silently degrade because the recipe list stopped at Opus 4.7.
|
|
const chatModels = anthropic.touchpoints?.chat?.models ?? [];
|
|
expect(chatModels).toContain('claude-fable-5');
|
|
expect(chatModels).toContain('claude-opus-4-8');
|
|
expect(chatModels).toContain('claude-sonnet-5');
|
|
});
|
|
|
|
it('Sonnet 5 is listed for expansion', () => {
|
|
expect(anthropic.touchpoints?.expansion?.models ?? []).toContain('claude-sonnet-5');
|
|
});
|
|
|
|
it('all listed models follow naming conventions', () => {
|
|
const allModels = [
|
|
...(anthropic.touchpoints?.chat?.models ?? []),
|
|
...(anthropic.touchpoints?.expansion?.models ?? []),
|
|
];
|
|
for (const m of allModels) {
|
|
// No model should contain a date that doesn't exist on the Anthropic API
|
|
expect(m).not.toMatch(/claude-sonnet-4-6-\d{8}/);
|
|
}
|
|
});
|
|
});
|