From 49403a554f36b0fdbe63f5c350e69380bdf455f7 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:49:05 -0500 Subject: [PATCH] feat(core): cap requested output tokens at 256k (#51962) --- packages/core/src/session/model-request.ts | 4 +++- packages/core/test/session-runner.test.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/core/src/session/model-request.ts b/packages/core/src/session/model-request.ts index b8f1d0edf52..a282d5c4a3c 100644 --- a/packages/core/src/session/model-request.ts +++ b/packages/core/src/session/model-request.ts @@ -46,6 +46,8 @@ const IMAGE_REMOVED = const GENERATION_KEYS = new Set(Object.keys(GenerationOptions.fields)) // Used when the catalog has no output limit for the model. const OUTPUT_TOKEN_FALLBACK = 32_000 +// No reply needs more, however much the model allows. +const OUTPUT_TOKEN_MAX = 256_000 // A summary never needs more, and a request asking for more cannot be shrunk to fit a window the catalog overstates. const SUMMARY_OUTPUT_MAX = 32_000 // Prompt text is estimated at about 4 characters per token, which can run low on dense text such as code. @@ -87,7 +89,7 @@ const outputLimit = ( kind: "primary" | "compaction", inputTokens?: Input["inputTokens"], ) => { - const model = limit.output > 0 ? limit.output : OUTPUT_TOKEN_FALLBACK + const model = Math.min(limit.output > 0 ? limit.output : OUTPUT_TOKEN_FALLBACK, OUTPUT_TOKEN_MAX) const requested = kind === "compaction" ? Math.min(model, SUMMARY_OUTPUT_MAX) : model if (inputTokens === undefined || limit.context <= 0) return requested const room = limit.context - inputTokens.measured - Math.ceil(inputTokens.estimated * (1 + ESTIMATE_ERROR)) diff --git a/packages/core/test/session-runner.test.ts b/packages/core/test/session-runner.test.ts index 93cf1ea8227..baede7cf602 100644 --- a/packages/core/test/session-runner.test.ts +++ b/packages/core/test/session-runner.test.ts @@ -128,6 +128,7 @@ const undersizedContextModel = testModel("undersized-context", { context: 1, out const recoveryModel = testModel("recovery", { context: 200_000, output: 1_000 }) const fittedOutputModel = testModel("fitted-output", { context: 100_000, output: 64_000 }) const smallWindowModel = testModel("small-window", { context: 64_000, output: 16_000 }) +const largeOutputModel = testModel("large-output", { context: 1_000_000, output: 1_000_000 }) test("calculates step cost using the matching context tier", () => { expect( @@ -3424,6 +3425,14 @@ describe("SessionRunnerLLM", () => { expect(s.requests[1]?.generation?.maxTokens).toBeGreaterThan(100_000 - 50_000 - 200) }) + scenario("caps the output limit a large model advertises", function* (s) { + s.currentModel = largeOutputModel + yield* s.llm.push(TestLLM.text("Answer", "text-large-output")) + yield* s.runPrompt("Question") + + expect(s.requests[0]?.generation?.maxTokens).toBe(256_000) + }) + scenario("gives the summary its full output limit when the conversation overshot the threshold", function* (s) { // The conversation overshot the threshold, so the prepared summary request exceeds the budget and `deliver` // shrinks it before sending. The output limit must follow the budget, not the oversized prepared request.