Skip to content

fix: cap thinking.budget_tokens when >= max_tokens#143

Open
flwrenn wants to merge 1 commit into
griffinmartin:mainfrom
flwrenn:fix/cap-thinking-budget-tokens
Open

fix: cap thinking.budget_tokens when >= max_tokens#143
flwrenn wants to merge 1 commit into
griffinmartin:mainfrom
flwrenn:fix/cap-thinking-budget-tokens

Conversation

@flwrenn

@flwrenn flwrenn commented Apr 7, 2026

Copy link
Copy Markdown

Summary

  • Cap thinking.budget_tokens to 80% of max_tokens when OpenCode sends budget_tokens >= max_tokens, which the Anthropic API rejects with a 400 error
  • Affects custom models (e.g. claude-opus-4-6) not in OpenCode's built-in registry, where max_tokens and budget_tokens may be set to the same value
  • Follows the same defensive-fix pattern as the existing haiku effort stripping in transformBody

Problem

When using claude-opus-4-6 (or other custom model IDs) through OpenCode, the Go binary may set thinking.budget_tokens equal to max_tokens. The Anthropic API requires strict inequality (max_tokens > thinking.budget_tokens) and rejects these requests:

opencode-claude-auth: API 400 for claude-opus-4-6: `max_tokens` must be greater than
`thinking.budget_tokens`. Please consult our documentation at
https://docs.claude.com/en/docs/build-with-claude/extended-thinking#max-tokens-and-context-window-size

Fix

In transformBody, after the existing model override logic, check if budget_tokens >= max_tokens and cap it to Math.floor(max_tokens * 0.8). The 0.8 ratio matches what OpenCode's own Anthropic provider uses when it correctly configures thinking for built-in models.

Tests

Three new test cases covering:

  • budget_tokens == max_tokens (the observed failure case)
  • budget_tokens > max_tokens
  • budget_tokens < max_tokens (no-op, left unchanged)

OpenCode may set thinking.budget_tokens equal to (or greater than)
max_tokens for custom models that aren't in its built-in registry.
The Anthropic API requires max_tokens > thinking.budget_tokens and
rejects such requests with a 400 error.

Cap budget_tokens to 80% of max_tokens when the constraint is
violated, matching the ratio used by OpenCode's own Anthropic
provider when it correctly configures thinking.
Copilot AI review requested due to automatic review settings April 7, 2026 08:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a defensive transformation to avoid Anthropic API 400s when thinking.budget_tokens is configured to be greater than or equal to max_tokens (a situation observed with custom model IDs outside OpenCode’s built-in model registry).

Changes:

  • Parse and surface max_tokens in transformBody’s request-body shape.
  • Cap thinking.budget_tokens to Math.floor(max_tokens * 0.8) when budget_tokens >= max_tokens to satisfy the API’s strict inequality requirement.
  • Add three unit tests covering equal/greater-than/no-op scenarios for the cap logic.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/transforms.ts Adds runtime guard to ensure max_tokens > thinking.budget_tokens by capping the budget when invalid.
src/transforms.test.ts Adds targeted regression tests for the new capping behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@griffinmartin

Copy link
Copy Markdown
Owner

Thanks, will try to take a look at this tonight.

@griffinmartin

Copy link
Copy Markdown
Owner

@greptileai

@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown

Greptile Summary

PR #143 reviewed. One P2 finding: Math.floor(max_tokens * 0.8) can produce a budget_tokens value below the Anthropic API's 1024-token minimum when max_tokens < 1280, meaning the request would still 400 for a different reason. Suggested fix: Math.max(1024, Math.floor(max_tokens * 0.8)). Otherwise the change is clean, well-tested, and safe to merge.

Confidence Score: 4/5

Safe to merge; the guard correctly eliminates the observed 400 error for custom models and is well-tested.

The fix is minimal and targeted. The only gap is that Math.floor(max_tokens * 0.8) can fall below the Anthropic API 1024-token floor for budget_tokens when max_tokens is very small, though any request with extended thinking and such a low max_tokens would fail regardless.

Files Needing Attention: No files require special attention; the edge-case note on transforms.ts line 187 is a minor hardening opportunity, not a regression.

Important Files Changed

Filename Overview
src/transforms.ts Adds a guard that caps thinking.budget_tokens to 80% of max_tokens when the pair would violate the Anthropic API's strict-inequality requirement; edge case where max_tokens < 1280 can still produce an out-of-range budget_tokens, though this is unlikely in practice.
src/transforms.test.ts Adds three focused tests covering the equal, greater-than, and less-than cases for budget_tokens vs max_tokens; all cases are well-asserted and use realistic token values.

Fix All in Cursor Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/transforms.ts:187
**Potential sub-1024 `budget_tokens` after cap**

The Anthropic API requires `budget_tokens >= 1024` for extended thinking to be valid, in addition to the `max_tokens > budget_tokens` constraint. If `max_tokens` is between 1 and 1279, `Math.floor(max_tokens * 0.8)` yields a value below 1024, so the request would still get a 400 error — just for a different reason. Adding a lower bound guard (e.g., `Math.max(1024, Math.floor(max_tokens * 0.8))`) would make the invariant complete.

Reviews (1): Last reviewed commit: "fix: cap thinking.budget_tokens when >= ..." | Re-trigger Greptile

Comment thread src/transforms.ts
typeof parsed.max_tokens === "number" &&
parsed.max_tokens <= parsed.thinking.budget_tokens
) {
parsed.thinking.budget_tokens = Math.floor(parsed.max_tokens * 0.8)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Potential sub-1024 budget_tokens after cap

The Anthropic API requires budget_tokens >= 1024 for extended thinking to be valid, in addition to the max_tokens > budget_tokens constraint. If max_tokens is between 1 and 1279, Math.floor(max_tokens * 0.8) yields a value below 1024, so the request would still get a 400 error — just for a different reason. Adding a lower bound guard (e.g., Math.max(1024, Math.floor(max_tokens * 0.8))) would make the invariant complete.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/transforms.ts
Line: 187

Comment:
**Potential sub-1024 `budget_tokens` after cap**

The Anthropic API requires `budget_tokens >= 1024` for extended thinking to be valid, in addition to the `max_tokens > budget_tokens` constraint. If `max_tokens` is between 1 and 1279, `Math.floor(max_tokens * 0.8)` yields a value below 1024, so the request would still get a 400 error — just for a different reason. Adding a lower bound guard (e.g., `Math.max(1024, Math.floor(max_tokens * 0.8))`) would make the invariant complete.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants