Merge pull request #2664 from kilhyeonjun/fix/anthropic-1m-ga-context-limit

fix(shared): respect cached model context limits for Anthropic providers post-GA
This commit is contained in:
YeonGyu-Kim
2026-03-26 08:55:04 +09:00
committed by GitHub
3 changed files with 176 additions and 10 deletions
+68 -3
View File
@@ -28,12 +28,29 @@ describe("resolveActualContextLimit", () => {
resetContextLimitEnv()
})
it("returns the default Anthropic limit when 1M mode is disabled despite a cached limit", () => {
it("returns cached limit for Anthropic 4.6 models when 1M mode is disabled (GA support)", () => {
// given
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
delete process.env[VERTEX_CONTEXT_ENV_KEY]
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 123456)
modelContextLimitsCache.set("anthropic/claude-opus-4-6", 1_000_000)
// when
const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4-6", {
anthropicContext1MEnabled: false,
modelContextLimitsCache,
})
// then — models.dev reports 1M for GA models, resolver should respect it
expect(actualLimit).toBe(1_000_000)
})
it("returns default 200K for older Anthropic models even when cached limit is higher", () => {
// given
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
delete process.env[VERTEX_CONTEXT_ENV_KEY]
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 500_000)
// when
const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-5", {
@@ -42,7 +59,38 @@ describe("resolveActualContextLimit", () => {
})
// then
expect(actualLimit).toBe(200000)
expect(actualLimit).toBe(200_000)
})
it("returns default 200K for Anthropic models without cached limit and 1M mode disabled", () => {
// given
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
delete process.env[VERTEX_CONTEXT_ENV_KEY]
// when
const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-5", {
anthropicContext1MEnabled: false,
})
// then
expect(actualLimit).toBe(200_000)
})
it("explicit 1M mode takes priority over cached limit", () => {
// given
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
delete process.env[VERTEX_CONTEXT_ENV_KEY]
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 200_000)
// when
const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-5", {
anthropicContext1MEnabled: true,
modelContextLimitsCache,
})
// then — explicit 1M flag overrides cached 200K
expect(actualLimit).toBe(1_000_000)
})
it("treats Anthropics aliases as Anthropic providers", () => {
@@ -61,6 +109,23 @@ describe("resolveActualContextLimit", () => {
expect(actualLimit).toBe(200000)
})
it("supports Anthropic 4.6 dot-version model IDs without explicit 1M mode", () => {
// given
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
delete process.env[VERTEX_CONTEXT_ENV_KEY]
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("anthropic/claude-opus-4.6", 1_000_000)
// when
const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4.6", {
anthropicContext1MEnabled: false,
modelContextLimitsCache,
})
// then
expect(actualLimit).toBe(1_000_000)
})
it("returns null for non-Anthropic providers without a cached limit", () => {
// given
delete process.env[ANTHROPIC_CONTEXT_ENV_KEY]
+17 -1
View File
@@ -1,6 +1,12 @@
import process from "node:process"
const DEFAULT_ANTHROPIC_ACTUAL_LIMIT = 200_000
const ANTHROPIC_NO_HEADER_GA_MODEL_IDS = new Set([
"claude-opus-4-6",
"claude-opus-4.6",
"claude-sonnet-4-6",
"claude-sonnet-4.6",
])
export type ContextLimitModelCacheState = {
anthropicContext1MEnabled: boolean
@@ -20,13 +26,23 @@ function getAnthropicActualLimit(modelCacheState?: ContextLimitModelCacheState):
: DEFAULT_ANTHROPIC_ACTUAL_LIMIT
}
function isAnthropicNoHeaderGaModel(modelID: string): boolean {
return ANTHROPIC_NO_HEADER_GA_MODEL_IDS.has(modelID.toLowerCase())
}
export function resolveActualContextLimit(
providerID: string,
modelID: string,
modelCacheState?: ContextLimitModelCacheState,
): number | null {
if (isAnthropicProvider(providerID)) {
return getAnthropicActualLimit(modelCacheState)
const explicit1M = getAnthropicActualLimit(modelCacheState)
if (explicit1M === 1_000_000) return explicit1M
const cachedLimit = modelCacheState?.modelContextLimitsCache?.get(`${providerID}/${modelID}`)
if (cachedLimit && isAnthropicNoHeaderGaModel(modelID)) return cachedLimit
return DEFAULT_ANTHROPIC_ACTUAL_LIMIT
}
return modelCacheState?.modelContextLimitsCache?.get(`${providerID}/${modelID}`) ?? null