fix(extended-context): never write [1m] into the Fable tier key

Claude Code resolves ANTHROPIC_DEFAULT_FABLE_MODEL through a resolver that
strips the [1m] suffix before use, unlike the opus/sonnet resolvers which
pass their env value through untouched. The stripped value is then treated
as an env-supplied default and held to the standard 200k window instead of
the model's native 1M, so writing [1m] into that key costs the long context
window rather than granting it.

Measured against a Claude Code 2.1.259 session (`/context` on a live proxy
endpoint):

  ANTHROPIC_MODEL=claude-fable-5-1[1m]               -> 1m window
  ANTHROPIC_MODEL=claude-fable-5-1                   -> 200k window
  ANTHROPIC_DEFAULT_FABLE_MODEL=claude-fable-5-1[1m] -> 200k window

The fix is key-scoped rather than model-scoped, since the suffix is what
grants 1M on every other key. Adds envKeyAcceptsExtendedContextSuffix() as
the single place recording which keys reject the suffix, enforces it as a
floor inside applyExtendedContextPreferenceToAnthropicModels() so no caller
can bypass it, and strips a previously saved suffix from that key on the
next launch through the auto path.

Also extends the preference to CLAUDE_CODE_SUBAGENT_MODEL. Subagent windows
come from the same resolver as the main loop (the Explore inheritCap bounds
the model tier, not the context window), so a bare subagent model id sits at
200k while the suffixed form gets 1M. The new key list is kept separate from
ANTHROPIC_MODEL_ENV_KEYS, which also drives routing, model-id normalization
and profile validation.

Claude-Session: https://claude.ai/code/session_01NPkafQjVf4pSwPBwBistGk
This commit is contained in:
Kenneth Wong committed 2026-09-03 17:08:23 +08:00
1 parent 3583b544d0
commit 2b780ceae3
6 files changed
+179 -9

No files matched your search

@@ -12,7 +12,7 @@ import type { ProviderCatalog } from '../provider-model-selector';
import {
applyExtendedContextPreferenceToAnthropicModels,
hasAnthropicExtendedContextEnabled,
isAnthropicModelEnvKey,
isExtendedContextModelEnvKey,
} from '@/lib/extended-context-utils';
import { supportsExtendedContext } from '@/lib/model-catalogs';
import { isValidProvider } from '@/lib/provider-config';
@@ -104,7 +104,7 @@ export function useProviderEditor(
const updateEnvValue = useCallback(
(key: string, value: string) => {
const newEnv = { ...(currentSettings?.env || {}), [key]: value };
const envWithIntent = isAnthropicModelEnvKey(key)
const envWithIntent = isExtendedContextModelEnvKey(key)
? applySavedLongContextIntent(newEnv, extendedContextEnabled)
: newEnv;
delete envWithIntent['CCS_EXTENDED_CONTEXT'];
@@ -132,7 +132,7 @@ export function useProviderEditor(
const updateEnvValues = useCallback(
(updates: Record<string, string>) => {
const newEnv = { ...(currentSettings?.env || {}), ...updates };
const touchesAnthropicModel = Object.keys(updates).some(isAnthropicModelEnvKey);
const touchesAnthropicModel = Object.keys(updates).some(isExtendedContextModelEnvKey);
const envWithIntent = touchesAnthropicModel
? applySavedLongContextIntent(newEnv, extendedContextEnabled)
: newEnv;
+4
View File
@@ -4,10 +4,14 @@
export {
ANTHROPIC_MODEL_ENV_KEYS,
EXTENDED_CONTEXT_MODEL_ENV_KEYS,
EXTENDED_CONTEXT_SUFFIX,
EXTRA_EXTENDED_CONTEXT_MODEL_ENV_KEYS,
applyExtendedContextPreferenceToAnthropicModels,
envKeyAcceptsExtendedContextSuffix,
isNativeGeminiModel,
isAnthropicModelEnvKey,
isExtendedContextModelEnvKey,
hasAnthropicExtendedContextEnabled,
hasExtendedContextSuffix,
applyExtendedContextSuffix,