mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 03:13:12 +00:00
fix(extended-context): suffix the Fable tier and default it on 1M launches
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
This commit is contained in:
1 parent
2b780ceae3
commit
02c45e088a
6 files changed
+162
-44
No files matched your search
@@ -10,13 +10,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { CLIProxyProvider } from '../types';
|
import type { CLIProxyProvider } from '../types';
|
||||||
import { supportsExtendedContext } from '../model-catalog';
|
import { getDefaultFableTierModel, supportsExtendedContext } from '../model-catalog';
|
||||||
import { warn } from '../../utils/ui';
|
import { warn } from '../../utils/ui';
|
||||||
import {
|
import {
|
||||||
|
ANTHROPIC_MODEL_ENV_KEYS,
|
||||||
EXTENDED_CONTEXT_MODEL_ENV_KEYS,
|
EXTENDED_CONTEXT_MODEL_ENV_KEYS,
|
||||||
applyExtendedContextPreferenceToAnthropicModels,
|
applyExtendedContextPreferenceToAnthropicModels,
|
||||||
applyExtendedContextSuffix as applyExtendedContextSuffixShared,
|
applyExtendedContextSuffix as applyExtendedContextSuffixShared,
|
||||||
envKeyAcceptsExtendedContextSuffix,
|
|
||||||
hasExtendedContextSuffix,
|
hasExtendedContextSuffix,
|
||||||
isNativeGeminiModel,
|
isNativeGeminiModel,
|
||||||
stripExtendedContextSuffix,
|
stripExtendedContextSuffix,
|
||||||
@@ -64,6 +64,39 @@ export function shouldApplyExtendedContext(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a saved Anthropic tier mapping still carries a [1m] suffix after the
|
||||||
|
* per-key pass, i.e. the launch is a long-context launch.
|
||||||
|
*/
|
||||||
|
function hasSavedLongContextTier(envVars: NodeJS.ProcessEnv): boolean {
|
||||||
|
return ANTHROPIC_MODEL_ENV_KEYS.some((key) => {
|
||||||
|
const value = envVars[key];
|
||||||
|
return typeof value === 'string' && hasExtendedContextSuffix(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give a long-context launch a fable tier when the profile does not map one.
|
||||||
|
*
|
||||||
|
* Claude Code falls back to its own bare Fable id for `--model fable` / the
|
||||||
|
* fable tier, and behind a proxy base URL a bare natively-1M id is clamped to
|
||||||
|
* the standard 200k window. Only the [1m] suffix lifts that clamp, so a
|
||||||
|
* model-neutral claude profile that asked for 1M elsewhere would otherwise get
|
||||||
|
* a 200k Fable. An explicit mapping (dashboard "fable tier" field or settings
|
||||||
|
* file) always wins; providers without a catalog Fable model are untouched.
|
||||||
|
*/
|
||||||
|
function fillFableTierForLongContext(envVars: NodeJS.ProcessEnv, provider: CLIProxyProvider): void {
|
||||||
|
const existing = envVars.ANTHROPIC_DEFAULT_FABLE_MODEL;
|
||||||
|
if (typeof existing === 'string' && existing.trim().length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fableModel = getDefaultFableTierModel(provider);
|
||||||
|
if (!fableModel || !supportsExtendedContext(provider, fableModel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
envVars.ANTHROPIC_DEFAULT_FABLE_MODEL = applyExtendedContextSuffixShared(fableModel);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply extended context configuration to env vars.
|
* Apply extended context configuration to env vars.
|
||||||
* Modifies ANTHROPIC_MODEL and tier models with [1m] suffix.
|
* Modifies ANTHROPIC_MODEL and tier models with [1m] suffix.
|
||||||
@@ -89,6 +122,9 @@ export function applyExtendedContextConfig(
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
if (extendedContextOverride) {
|
||||||
|
fillFableTierForLongContext(envVars, provider);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,13 +139,6 @@ export function applyExtendedContextConfig(
|
|||||||
}
|
}
|
||||||
const modelId = stripModelConfigurationSuffixes(value);
|
const modelId = stripModelConfigurationSuffixes(value);
|
||||||
|
|
||||||
// Keys whose resolver strips [1m] must never keep a saved suffix: the
|
|
||||||
// stripped value loses the model's native long context window.
|
|
||||||
if (!envKeyAcceptsExtendedContextSuffix(key)) {
|
|
||||||
envVars[key] = stripExtendedContextSuffix(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNativeGeminiModel(modelId)) {
|
if (isNativeGeminiModel(modelId)) {
|
||||||
envVars[key] = supportsExtendedContext(provider, modelId)
|
envVars[key] = supportsExtendedContext(provider, modelId)
|
||||||
? applyExtendedContextSuffixShared(value)
|
? applyExtendedContextSuffixShared(value)
|
||||||
@@ -121,4 +150,8 @@ export function applyExtendedContextConfig(
|
|||||||
envVars[key] = stripExtendedContextSuffix(value);
|
envVars[key] = stripExtendedContextSuffix(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasSavedLongContextTier(envVars)) {
|
||||||
|
fillFableTierForLongContext(envVars, provider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -866,6 +866,17 @@ export function supportsExtendedContext(provider: CLIProxyProvider, modelId: str
|
|||||||
return model?.extendedContext === true;
|
return model?.extendedContext === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Catalog model that backs the Claude Code `fable` tier for a provider.
|
||||||
|
* The catalog lists the newest Fable first, so the first match is the default.
|
||||||
|
* Returns undefined for providers that serve no Fable model.
|
||||||
|
*/
|
||||||
|
export function getDefaultFableTierModel(provider: CLIProxyProvider): string | undefined {
|
||||||
|
const catalog = MODEL_CATALOG[provider];
|
||||||
|
if (!catalog) return undefined;
|
||||||
|
return catalog.models.find((model) => model.id.toLowerCase().startsWith('claude-fable-'))?.id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a model can read image inputs natively.
|
* Check if a model can read image inputs natively.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -34,21 +34,15 @@ const ANTHROPIC_MODEL_ENV_KEY_SET = new Set<string>(ANTHROPIC_MODEL_ENV_KEYS);
|
|||||||
|
|
||||||
const EXTENDED_CONTEXT_MODEL_ENV_KEY_SET = new Set<string>(EXTENDED_CONTEXT_MODEL_ENV_KEYS);
|
const EXTENDED_CONTEXT_MODEL_ENV_KEY_SET = new Set<string>(EXTENDED_CONTEXT_MODEL_ENV_KEYS);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Keys whose value Claude Code resolves through a resolver that removes [1m]
|
* Why every key, including ANTHROPIC_DEFAULT_FABLE_MODEL, carries the suffix:
|
||||||
* before use. ANTHROPIC_DEFAULT_FABLE_MODEL is the only one today: its resolver
|
* Claude Code only grants a natively-1M model (Fable, Opus 5) its full window
|
||||||
* strips the suffix (unlike the opus/sonnet resolvers, which pass the value
|
* without the suffix when ANTHROPIC_BASE_URL is unset or points at
|
||||||
* through), and the stripped env-supplied default is then held to the standard
|
* api.anthropic.com. Behind any proxy (CLIProxy, headroom, ...) a bare id is
|
||||||
* 200k window instead of the model's native 1M. Writing [1m] here therefore
|
* clamped to 200k even when the backend advertises 1M, and the fable alias
|
||||||
* costs the long context window rather than granting it, and Fable models are
|
* resolver passes the env value through untouched in that case. The [1m]
|
||||||
* natively 1M, so the suffix is never needed on this key.
|
* suffix is therefore the only thing that turns the long window on for CCS.
|
||||||
*/
|
*/
|
||||||
const SUFFIX_STRIPPING_MODEL_ENV_KEYS = new Set<string>(['ANTHROPIC_DEFAULT_FABLE_MODEL']);
|
|
||||||
|
|
||||||
/** True when writing an explicit [1m] suffix into this env key is meaningful. */
|
|
||||||
export function envKeyAcceptsExtendedContextSuffix(key: string): boolean {
|
|
||||||
return !SUFFIX_STRIPPING_MODEL_ENV_KEYS.has(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if model is a native Gemini model (auto-enabled behavior). */
|
/** Check if model is a native Gemini model (auto-enabled behavior). */
|
||||||
export function isNativeGeminiModel(modelId: string): boolean {
|
export function isNativeGeminiModel(modelId: string): boolean {
|
||||||
@@ -117,9 +111,7 @@ export function applyExtendedContextPreferenceToAnthropicModels<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const modelId = stripModelConfigurationSuffixes(value);
|
const modelId = stripModelConfigurationSuffixes(value);
|
||||||
const supported =
|
const supported = options.supportsExtendedContext?.(modelId, key) ?? true;
|
||||||
envKeyAcceptsExtendedContextSuffix(key) &&
|
|
||||||
(options.supportsExtendedContext?.(modelId, key) ?? true);
|
|
||||||
nextEnv[key] =
|
nextEnv[key] =
|
||||||
enabled && supported ? applyExtendedContextSuffix(value) : stripExtendedContextSuffix(value);
|
enabled && supported ? applyExtendedContextSuffix(value) : stripExtendedContextSuffix(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { describe, expect, it } from 'bun:test';
|
|||||||
import { applyExtendedContextConfig } from '../../../src/cliproxy/config/extended-context-config';
|
import { applyExtendedContextConfig } from '../../../src/cliproxy/config/extended-context-config';
|
||||||
|
|
||||||
describe('applyExtendedContextConfig', () => {
|
describe('applyExtendedContextConfig', () => {
|
||||||
it('strips a saved [1m] from the fable tier key in auto mode', () => {
|
it('keeps a saved [1m] on the fable tier key in auto mode', () => {
|
||||||
const env: NodeJS.ProcessEnv = {
|
const env: NodeJS.ProcessEnv = {
|
||||||
ANTHROPIC_MODEL: 'claude-opus-5[1m]',
|
ANTHROPIC_MODEL: 'claude-opus-5[1m]',
|
||||||
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1[1m]',
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1[1m]',
|
||||||
@@ -11,11 +11,11 @@ describe('applyExtendedContextConfig', () => {
|
|||||||
|
|
||||||
applyExtendedContextConfig(env, 'claude');
|
applyExtendedContextConfig(env, 'claude');
|
||||||
|
|
||||||
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1');
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1[1m]');
|
||||||
expect(env.ANTHROPIC_MODEL).toBe('claude-opus-5[1m]');
|
expect(env.ANTHROPIC_MODEL).toBe('claude-opus-5[1m]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps the fable tier key plain when extended context is forced on', () => {
|
it('suffixes the fable tier key like every other tier when forced on', () => {
|
||||||
const env: NodeJS.ProcessEnv = {
|
const env: NodeJS.ProcessEnv = {
|
||||||
ANTHROPIC_MODEL: 'claude-fable-5-1',
|
ANTHROPIC_MODEL: 'claude-fable-5-1',
|
||||||
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1',
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1',
|
||||||
@@ -24,8 +24,94 @@ describe('applyExtendedContextConfig', () => {
|
|||||||
|
|
||||||
applyExtendedContextConfig(env, 'claude', true);
|
applyExtendedContextConfig(env, 'claude', true);
|
||||||
|
|
||||||
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1');
|
expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL).toBe('claude-fable-5-1[1m]');
|
||||||
expect(env.ANTHROPIC_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]');
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
ANTHROPIC_MODEL_ENV_KEYS,
|
ANTHROPIC_MODEL_ENV_KEYS,
|
||||||
EXTENDED_CONTEXT_MODEL_ENV_KEYS,
|
EXTENDED_CONTEXT_MODEL_ENV_KEYS,
|
||||||
applyExtendedContextPreferenceToAnthropicModels,
|
applyExtendedContextPreferenceToAnthropicModels,
|
||||||
envKeyAcceptsExtendedContextSuffix,
|
|
||||||
hasAnthropicExtendedContextEnabled,
|
hasAnthropicExtendedContextEnabled,
|
||||||
isAnthropicModelEnvKey,
|
isAnthropicModelEnvKey,
|
||||||
isExtendedContextModelEnvKey,
|
isExtendedContextModelEnvKey,
|
||||||
@@ -37,22 +36,17 @@ describe('extended-context model env keys', () => {
|
|||||||
expect(isExtendedContextModelEnvKey('CLAUDE_CODE_SUBAGENT_MODEL')).toBe(true);
|
expect(isExtendedContextModelEnvKey('CLAUDE_CODE_SUBAGENT_MODEL')).toBe(true);
|
||||||
expect(isAnthropicModelEnvKey('CLAUDE_CODE_SUBAGENT_MODEL')).toBe(false);
|
expect(isAnthropicModelEnvKey('CLAUDE_CODE_SUBAGENT_MODEL')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('marks the fable tier key as suffix-stripping', () => {
|
|
||||||
expect(envKeyAcceptsExtendedContextSuffix('ANTHROPIC_DEFAULT_FABLE_MODEL')).toBe(false);
|
|
||||||
expect(envKeyAcceptsExtendedContextSuffix('ANTHROPIC_MODEL')).toBe(true);
|
|
||||||
expect(envKeyAcceptsExtendedContextSuffix('ANTHROPIC_DEFAULT_OPUS_MODEL')).toBe(true);
|
|
||||||
expect(envKeyAcceptsExtendedContextSuffix('CLAUDE_CODE_SUBAGENT_MODEL')).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('applyExtendedContextPreferenceToAnthropicModels', () => {
|
describe('applyExtendedContextPreferenceToAnthropicModels', () => {
|
||||||
it('never writes [1m] into the fable tier key and strips a saved one', () => {
|
it('writes [1m] into every managed key, the fable tier included', () => {
|
||||||
|
// Behind a proxy base URL Claude Code clamps a bare Fable id to 200k, so the
|
||||||
|
// fable tier needs the suffix exactly like the opus/sonnet tiers do.
|
||||||
const env = applyExtendedContextPreferenceToAnthropicModels(
|
const env = applyExtendedContextPreferenceToAnthropicModels(
|
||||||
{
|
{
|
||||||
ANTHROPIC_MODEL: 'claude-fable-5-1',
|
ANTHROPIC_MODEL: 'claude-fable-5-1',
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-5',
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-5',
|
||||||
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1[1m]',
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1',
|
||||||
CLAUDE_CODE_SUBAGENT_MODEL: 'claude-fable-5-1',
|
CLAUDE_CODE_SUBAGENT_MODEL: 'claude-fable-5-1',
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
@@ -61,7 +55,7 @@ describe('applyExtendedContextPreferenceToAnthropicModels', () => {
|
|||||||
expect(env).toEqual({
|
expect(env).toEqual({
|
||||||
ANTHROPIC_MODEL: 'claude-fable-5-1[1m]',
|
ANTHROPIC_MODEL: 'claude-fable-5-1[1m]',
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-5[1m]',
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-5[1m]',
|
||||||
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1',
|
ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1[1m]',
|
||||||
CLAUDE_CODE_SUBAGENT_MODEL: 'claude-fable-5-1[1m]',
|
CLAUDE_CODE_SUBAGENT_MODEL: 'claude-fable-5-1[1m]',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -83,7 +77,7 @@ describe('applyExtendedContextPreferenceToAnthropicModels', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('honors a caller compatibility predicate on top of the key guard', () => {
|
it('honors a caller compatibility predicate', () => {
|
||||||
const env = applyExtendedContextPreferenceToAnthropicModels(
|
const env = applyExtendedContextPreferenceToAnthropicModels(
|
||||||
{
|
{
|
||||||
ANTHROPIC_MODEL: 'claude-opus-5',
|
ANTHROPIC_MODEL: 'claude-opus-5',
|
||||||
@@ -99,10 +93,13 @@ describe('applyExtendedContextPreferenceToAnthropicModels', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reads saved intent from the subagent key too', () => {
|
it('reads saved intent from any managed key', () => {
|
||||||
expect(
|
expect(
|
||||||
hasAnthropicExtendedContextEnabled({ CLAUDE_CODE_SUBAGENT_MODEL: 'claude-fable-5-1[1m]' })
|
hasAnthropicExtendedContextEnabled({ CLAUDE_CODE_SUBAGENT_MODEL: 'claude-fable-5-1[1m]' })
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
hasAnthropicExtendedContextEnabled({ ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1[1m]' })
|
||||||
|
).toBe(true);
|
||||||
expect(
|
expect(
|
||||||
hasAnthropicExtendedContextEnabled({ ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1' })
|
hasAnthropicExtendedContextEnabled({ ANTHROPIC_DEFAULT_FABLE_MODEL: 'claude-fable-5-1' })
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export {
|
|||||||
EXTENDED_CONTEXT_SUFFIX,
|
EXTENDED_CONTEXT_SUFFIX,
|
||||||
EXTRA_EXTENDED_CONTEXT_MODEL_ENV_KEYS,
|
EXTRA_EXTENDED_CONTEXT_MODEL_ENV_KEYS,
|
||||||
applyExtendedContextPreferenceToAnthropicModels,
|
applyExtendedContextPreferenceToAnthropicModels,
|
||||||
envKeyAcceptsExtendedContextSuffix,
|
|
||||||
isNativeGeminiModel,
|
isNativeGeminiModel,
|
||||||
isAnthropicModelEnvKey,
|
isAnthropicModelEnvKey,
|
||||||
isExtendedContextModelEnvKey,
|
isExtendedContextModelEnvKey,
|
||||||
|
|||||||
Reference in new issue
Block a user