Skip to content

max_tokens does not bound reasoning tokens for bytedance-seed/seed-2.0-mini (billed 2127 tokens for max_tokens=20) #44

Description

@hibestnick

Summary

For bytedance-seed/seed-2.0-mini (provider: Seed), max_tokens only caps the visible completion.
Reasoning tokens are generated on top of the limit, uncapped. Since reasoning tokens are billed as
output tokens, max_tokens provides no cost ceiling: a request with max_tokens: 20 was billed for
2,127 completion tokens.

The model's /endpoints metadata advertises max_tokens in supported_parameters.

Reproduction

Prompt: "Write a 500-word essay about the ocean.", no reasoning parameter.

max_tokens completion_tokens (billed) reasoning_tokens visible (= completion − reasoning) finish_reason
20 2127 2108 19 length
100 2798 2699 99 length
600 3660 3061 599 length

Visible output tracks max_tokens almost exactly (19 / 99 / 599). Reasoning is unbounded.

With reasoning explicitly disabled, the limit is honored exactly:

request completion_tokens reasoning_tokens
max_tokens: 20, reasoning: {"enabled": false} 20 0

A shorter prompt shows the cap being exceeded even when the model stops naturally:

POST /api/v1/chat/completions
{"model":"bytedance-seed/seed-2.0-mini","max_tokens":20,
 "messages":[{"role":"user","content":"What is 2+2? Answer with just the number."}]}

-> finish_reason: "stop"
   completion_tokens: 53      <-- exceeds max_tokens: 20
   reasoning_tokens:  52
   content: "4"

Control — google/gemini-3.1-flash-lite, same request, behaves as expected
(completion_tokens: 1, reasoning_tokens: 0).

Expected

max_tokens should bound total completion tokens, including reasoning.

The reasoning docs state "Reasoning tokens are considered output tokens and charged accordingly",
and for Anthropic models: "max_tokens must be strictly higher than the reasoning budget to ensure
there are tokens available for the final response after thinking."
Both imply max_tokens is the
total pool that reasoning draws from — which is also the OpenAI semantics OpenRouter mirrors.

Impact

max_tokens is the standard lever for bounding per-request cost. For this model it silently fails:
the caller is billed for up to ~100× the requested ceiling, with finish_reason: "stop" giving no
indication that anything was truncated or exceeded.

Callers who set max_tokens as a cost guard (e.g. benchmark harnesses, batch pipelines) have no way
to detect this short of inspecting completion_tokens_details.reasoning_tokens on every response.

Asks

  1. Is this intended behavior for this provider? If so, please document that max_tokens bounds only
    visible output for models where reasoning is enabled by default.
  2. If not intended, max_tokens should be normalized to bound total completion tokens.
  3. Either way, it would help to surface this in /endpoints metadata — currently max_tokens appears
    in supported_parameters with no indication that its semantics differ from other models.

Environment

  • Discovered while benchmarking streaming latency across 13 targets; this model's completion_tokens
    were 10× the configured cap, which invalidated cross-model throughput comparisons until excluded.
  • Date: 2026-07-10

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions