diff --git a/packages/core/src/sync/providers/cloudflare-workers-ai.ts b/packages/core/src/sync/providers/cloudflare-workers-ai.ts index 0ed0e391513..04cce9d3723 100644 --- a/packages/core/src/sync/providers/cloudflare-workers-ai.ts +++ b/packages/core/src/sync/providers/cloudflare-workers-ai.ts @@ -18,6 +18,13 @@ const ENABLE_THINKING_MODELS = new Set([ "@cf/zai-org/glm-4.7-flash", "@cf/zai-org/glm-5.2", ]); +// Search and the model pages report 1,310,720 for these, but the serving backend rejects any request over 1,048,576 +// tokens. The sync re-derives context from search, so the served window is pinned here. It only ever lowers a window. +const SERVED_CONTEXT = new Map([ + ["@cf/zai-org/glm-5.3", 1_048_576], + ["@cf/zai-org/glm-5.3-flash", 1_048_576], + ["@cf/deepseek-ai/deepseek-v4-flash-0731", 1_048_576], +]); const ROOT_DIR = path.join(import.meta.dirname, "..", "..", "..", "..", ".."); const MODELS_DIR = path.join(ROOT_DIR, "models"); const metadataFilesByPublisher = new Map(); @@ -172,8 +179,10 @@ export function buildWorkersAiModel( const reasoning = reasoningOptions !== undefined ? true : existing?.reasoning ?? hasReasoning(model); + const context = Math.min(model.context_length, SERVED_CONTEXT.get(model.id) ?? model.context_length); const source = { ...model, + context_length: context, reasoning: undefined, supported_parameters: [ ...model.supported_parameters.filter((parameter) => !["reasoning", "include_reasoning"].includes(parameter)), @@ -182,6 +191,7 @@ export function buildWorkersAiModel( name: existing?.name ?? model.name, top_provider: { ...model.top_provider, + context_length: context, max_completion_tokens: existing?.limit?.output ?? model.top_provider.max_completion_tokens, }, }; diff --git a/packages/core/test/cloudflare-workers-ai.test.ts b/packages/core/test/cloudflare-workers-ai.test.ts index e15416cb7ec..3165f1c33b8 100644 --- a/packages/core/test/cloudflare-workers-ai.test.ts +++ b/packages/core/test/cloudflare-workers-ai.test.ts @@ -54,3 +54,43 @@ test("preserves OpenRouter pricing overrides as context tiers", () => { }], }); }); + +function searchRow(id: string, context: number) { + return { + id: `workers-ai/${id}`, + name: "Served Window", + created: 1_782_777_600, + hugging_face_id: null, + knowledge_cutoff: null, + context_length: context, + architecture: { + input_modalities: ["text"], + output_modalities: ["text"], + }, + pricing: { prompt: "0.000001", completion: "0.000002" }, + top_provider: { + context_length: context, + max_completion_tokens: context, + }, + supported_parameters: [], + }; +} + +function translatedContext(id: string, context: number) { + const [source] = cloudflareWorkersAi.parseModels({ result: { data: [searchRow(id, context)] } }); + return cloudflareWorkersAi.translateModel(source!, { + existing: () => undefined, + authored: () => undefined, + }).model.limit?.context; +} + +test("pins the served context window when search reports a larger one", () => { + expect(translatedContext("@cf/zai-org/glm-5.3", 1_310_720)).toBe(1_048_576); + expect(translatedContext("@cf/zai-org/glm-5.3-flash", 1_310_720)).toBe(1_048_576); + expect(translatedContext("@cf/deepseek-ai/deepseek-v4-flash-0731", 1_310_720)).toBe(1_048_576); +}); + +test("never raises a context window or pins other models", () => { + expect(translatedContext("@cf/zai-org/glm-5.3", 262_144)).toBe(262_144); + expect(translatedContext("@cf/test/unpinned", 1_310_720)).toBe(1_310_720); +}); diff --git a/providers/cloudflare-ai-gateway/curation.toml b/providers/cloudflare-ai-gateway/curation.toml index b49e5a8d3dd..ed46d9357cd 100644 --- a/providers/cloudflare-ai-gateway/curation.toml +++ b/providers/cloudflare-ai-gateway/curation.toml @@ -84,7 +84,6 @@ reasoning_options = [{ type = "effort", values = ["low", "medium", "high", "xhig [models."anthropic/claude-sonnet-4.5"] structured_output = true -limit = { context = 1000000 } reasoning_options = [{ type = "budget_tokens", min = 1024 }] [models."anthropic/claude-sonnet-4.6"] diff --git a/providers/cloudflare-ai-gateway/models/anthropic/claude-sonnet-4.5.toml b/providers/cloudflare-ai-gateway/models/anthropic/claude-sonnet-4.5.toml index bcfe7fc5bfe..706b5967816 100644 --- a/providers/cloudflare-ai-gateway/models/anthropic/claude-sonnet-4.5.toml +++ b/providers/cloudflare-ai-gateway/models/anthropic/claude-sonnet-4.5.toml @@ -12,7 +12,7 @@ cache_read = 0.3 cache_write = 3.75 [limit] -context = 1_000_000 +context = 200_000 [provider] npm = "@ai-sdk/anthropic" diff --git a/providers/cloudflare-workers-ai/models/@cf/deepseek-ai/deepseek-v4-flash-0731.toml b/providers/cloudflare-workers-ai/models/@cf/deepseek-ai/deepseek-v4-flash-0731.toml index 48cdf638dfe..2385a1bc60b 100644 --- a/providers/cloudflare-workers-ai/models/@cf/deepseek-ai/deepseek-v4-flash-0731.toml +++ b/providers/cloudflare-workers-ai/models/@cf/deepseek-ai/deepseek-v4-flash-0731.toml @@ -16,5 +16,5 @@ output = 1.32 cache_read = 0.014 [limit] -context = 1_310_720 +context = 1_048_576 output = 1_048_576 diff --git a/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3-flash.toml b/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3-flash.toml index 13c5aacae4c..83a85d6c195 100644 --- a/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3-flash.toml +++ b/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3-flash.toml @@ -16,7 +16,7 @@ output = 0.5 cache_read = 0.03 [limit] -context = 1_310_720 +context = 1_048_576 output = 1_048_576 [modalities] diff --git a/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3.toml b/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3.toml index 456f1fb0549..a66154848f3 100644 --- a/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3.toml +++ b/providers/cloudflare-workers-ai/models/@cf/zai-org/glm-5.3.toml @@ -16,5 +16,5 @@ output = 4.4 cache_read = 0.26 [limit] -context = 1_310_720 +context = 1_048_576 output = 1_048_576