mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 12:09:03 +00:00
The previous commit assumed Claude Code's fable resolver strips [1m] and therefore never wrote the suffix into ANTHROPIC_DEFAULT_FABLE_MODEL. That premise only holds when ANTHROPIC_BASE_URL is unset or points at api.anthropic.com. Behind a proxy (CLIProxy, headroom, ...) Claude Code 2.1.259 does the opposite: - the fable alias resolver passes the env value through untouched, so a saved `claude-fable-5-1[1m]` reaches the model picker as-is; - the context-window resolver grants 1M unconditionally when the model id carries [1m], and otherwise trusts a natively-1M model only when the base URL is first-party. Bare `claude-fable-5-1` via 127.0.0.1 is clamped to 200k even though CLIProxy's /v1/models advertises max_input_tokens 1M. So the suffix is the only thing that turns the long window on for CCS, and stripping it from the Fable key is what kept `ccs claude --model fable` at 200k. A headroom settings profile with the suffix saved on that key showed the 1M window in the same Claude Code build, which is how the inversion was caught. Changes: - Drop the suffix-stripping key guard; ANTHROPIC_DEFAULT_FABLE_MODEL now receives and keeps [1m] exactly like the opus/sonnet tiers. - On a long-context launch (explicit --1m, or a saved [1m] on any Anthropic tier key) fill a missing Fable tier with the catalog Fable model plus [1m]. The model-neutral claude profile pins no Fable model, so `--model fable` used to fall back to Claude Code's bare default and lose the window even when every other tier asked for 1M. An explicit mapping always wins, --no-1m never fills, and providers without a catalog Fable model are left alone. - Add getDefaultFableTierModel() to the model catalog for that default. Verified with a stub Claude binary that dumps its environment: ccs claude --model fable -> ANTHROPIC_DEFAULT_FABLE_MODEL=claude-fable-5-1[1m] ccs claude --1m -> ANTHROPIC_DEFAULT_FABLE_MODEL=claude-fable-5-1[1m] ccs claude --no-1m --model fable -> no Fable tier written, ANTHROPIC_MODEL stripped
118 lines
3.9 KiB
TypeScript
118 lines
3.9 KiB
TypeScript
import { describe, expect, it } from 'bun:test';
|
|
|
|
import { applyExtendedContextConfig } from '../../../src/cliproxy/config/extended-context-config';
|
|
|
|
describe('applyExtendedContextConfig', () => {
|
|
it('keeps a saved [1m] on the fable tier key in auto mode', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-5[1m]',
|
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1[1m]',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude');
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1[1m]');
|
|
expect(env.ANTHROPIC_MODEL).toBe('claude-opus-5[1m]');
|
|
});
|
|
|
|
it('suffixes the fable tier key like every other tier when forced on', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-fable-5-1',
|
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1',
|
|
CLAUDE_CODE_SUBAGENT_MODEL: 'claude-fable-5-1',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude', true);
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1[1m]');
|
|
expect(env.ANTHROPIC_MODEL).toBe('claude-fable-5-1[1m]');
|
|
expect(env.CLAUDE_CODE_SUBAGENT_MODEL).toBe('claude-fable-5-1[1m]');
|
|
});
|
|
|
|
it('strips the fable tier key with the others when forced off', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-5[1m]',
|
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1[1m]',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude', false);
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1');
|
|
expect(env.ANTHROPIC_MODEL).toBe('claude-opus-5');
|
|
});
|
|
|
|
describe('fable tier default on the claude provider', () => {
|
|
it('fills a missing fable tier with the catalog Fable model plus [1m] when a saved tier carries [1m]', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-5[1m]',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude');
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1[1m]');
|
|
});
|
|
|
|
it('fills a missing fable tier when --1m is passed', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-5',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude', true);
|
|
|
|
expect(env.ANTHROPIC_MODEL).toBe('claude-opus-5[1m]');
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1[1m]');
|
|
});
|
|
|
|
it('fills a missing fable tier on a model-neutral claude launch when --1m is passed', () => {
|
|
const env: NodeJS.ProcessEnv = {};
|
|
|
|
applyExtendedContextConfig(env, 'claude', true);
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1[1m]');
|
|
expect(Object.keys(env)).toEqual(['ANTHROPIC_DEFAULT_FABLE_MODEL']);
|
|
});
|
|
|
|
it('leaves the fable tier alone when no long-context intent exists', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-5',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude');
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBeUndefined();
|
|
});
|
|
|
|
it('leaves the fable tier alone when --no-1m is passed', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-5[1m]',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude', false);
|
|
|
|
expect(env.ANTHROPIC_MODEL).toBe('claude-opus-5');
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBeUndefined();
|
|
});
|
|
|
|
it('never overrides an explicit fable tier mapping', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-5[1m]',
|
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5[1m]',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'claude');
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5[1m]');
|
|
});
|
|
|
|
it('does not invent a fable tier for providers without Fable models', () => {
|
|
const env: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'gpt-5.4[1m]',
|
|
};
|
|
|
|
applyExtendedContextConfig(env, 'codex');
|
|
|
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBeUndefined();
|
|
});
|
|
});
|
|
});
|