From 8f115e6031679408dd530b25186ae3fbd7df0063 Mon Sep 17 00:00:00 2001 From: rekram1-node Date: Sat, 4 Oct 2025 23:07:06 -0500 Subject: [PATCH 1/4] fix: max output tokens if using entire thinking budget --- packages/opencode/src/provider/transform.ts | 24 ++++++++++++++------- packages/opencode/src/session/prompt.ts | 9 ++++++-- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 3232a5f1788a..c6ca0fe6c97d 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -105,18 +105,26 @@ export namespace ProviderTransform { return result } - export function maxOutputTokens(providerID: string, outputLimit: number, options: Record): number { + export function maxOutputTokens( + providerID: string, + options: Record, + modelLimit: number, + globalLimit: number, + ): number { + const modelCap = modelLimit || globalLimit + const limit = Math.min(modelCap, globalLimit) + if (providerID === "anthropic") { - const thinking = options["thinking"] - if (typeof thinking === "object" && thinking !== null) { - const type = thinking["type"] - const budgetTokens = thinking["budgetTokens"] - if (type === "enabled" && typeof budgetTokens === "number" && budgetTokens > 0) { - return outputLimit - budgetTokens + const budgetTokens = options?.["thinking"]?.["budgetTokens"] + if (options?.["thinking"]?.["type"] === "enabled" && budgetTokens > 0) { + if (modelCap > globalLimit && limit + budgetTokens > globalLimit) { + return modelCap - budgetTokens } + return limit - budgetTokens } } - return outputLimit + + return limit } export function schema(_providerID: string, _modelID: string, schema: JSONSchema.BaseSchema) { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 8e7cf57f058e..a9b51a377a0e 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -159,7 +159,7 @@ export namespace SessionPrompt { agent, model: input.model, }).then((x) => Provider.getModel(x.providerID, x.modelID)) - const outputLimit = Math.min(model.info.limit.output, OUTPUT_TOKEN_MAX) || OUTPUT_TOKEN_MAX + using abort = lock(input.sessionID) const system = await resolveSystemPrompt({ @@ -266,7 +266,12 @@ export namespace SessionPrompt { : undefined, maxRetries: 10, activeTools: Object.keys(tools).filter((x) => x !== "invalid"), - maxOutputTokens: ProviderTransform.maxOutputTokens(model.providerID, outputLimit, params.options), + maxOutputTokens: ProviderTransform.maxOutputTokens( + model.providerID, + params.options, + model.info.limit.output || OUTPUT_TOKEN_MAX, + OUTPUT_TOKEN_MAX, + ), abortSignal: abort.signal, providerOptions: { [model.npm === "@ai-sdk/openai" ? "openai" : model.providerID]: params.options, From 95583b82eb94ad6c42e2e3a1bb4e8bbbe36de9b6 Mon Sep 17 00:00:00 2001 From: rekram1-node Date: Sat, 4 Oct 2025 23:07:25 -0500 Subject: [PATCH 2/4] fix --- packages/opencode/src/session/prompt.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index a9b51a377a0e..f0be55330f3f 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -269,7 +269,7 @@ export namespace SessionPrompt { maxOutputTokens: ProviderTransform.maxOutputTokens( model.providerID, params.options, - model.info.limit.output || OUTPUT_TOKEN_MAX, + model.info.limit.output, OUTPUT_TOKEN_MAX, ), abortSignal: abort.signal, From 2e05c1060a687833f1b1790d6800e988e120c204 Mon Sep 17 00:00:00 2001 From: rekram1-node Date: Sat, 4 Oct 2025 23:34:57 -0500 Subject: [PATCH 3/4] fix --- packages/opencode/src/provider/transform.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index c6ca0fe6c97d..c8401847a91a 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -112,19 +112,20 @@ export namespace ProviderTransform { globalLimit: number, ): number { const modelCap = modelLimit || globalLimit - const limit = Math.min(modelCap, globalLimit) + const textDefault = Math.min(modelCap, globalLimit) if (providerID === "anthropic") { - const budgetTokens = options?.["thinking"]?.["budgetTokens"] - if (options?.["thinking"]?.["type"] === "enabled" && budgetTokens > 0) { - if (modelCap > globalLimit && limit + budgetTokens > globalLimit) { - return modelCap - budgetTokens - } - return limit - budgetTokens + const thinking = options?.["thinking"] + const budgetTokens = typeof thinking?.["budgetTokens"] === "number" ? thinking["budgetTokens"] : 0 + const enabled = thinking?.["type"] === "enabled" + if (enabled && budgetTokens > 0) { + // Return text tokens so that text + thinking <= model cap, preferring 32k text when possible. + if (budgetTokens + textDefault <= modelCap) return textDefault + return modelCap - budgetTokens } } - return limit + return textDefault } export function schema(_providerID: string, _modelID: string, schema: JSONSchema.BaseSchema) { From 6b158e18d0375a54d79c57f6ee9a67ef06fb11cf Mon Sep 17 00:00:00 2001 From: rekram1-node Date: Sat, 4 Oct 2025 23:36:31 -0500 Subject: [PATCH 4/4] fix --- packages/opencode/src/provider/transform.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index c8401847a91a..92001814aff4 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -112,7 +112,7 @@ export namespace ProviderTransform { globalLimit: number, ): number { const modelCap = modelLimit || globalLimit - const textDefault = Math.min(modelCap, globalLimit) + const standardLimit = Math.min(modelCap, globalLimit) if (providerID === "anthropic") { const thinking = options?.["thinking"] @@ -120,12 +120,14 @@ export namespace ProviderTransform { const enabled = thinking?.["type"] === "enabled" if (enabled && budgetTokens > 0) { // Return text tokens so that text + thinking <= model cap, preferring 32k text when possible. - if (budgetTokens + textDefault <= modelCap) return textDefault + if (budgetTokens + standardLimit <= modelCap) { + return standardLimit + } return modelCap - budgetTokens } } - return textDefault + return standardLimit } export function schema(_providerID: string, _modelID: string, schema: JSONSchema.BaseSchema) {