Skip to content

[Bugfix][Frontend] Count reasoning tokens for the Muse-Glimmer parser - #54091

Open
meghana-madhyastha wants to merge 1 commit into
vllm-project:mainfrom
meghana-madhyastha:fix/muse-glimmer-reasoning-tokens
Open

meghana-madhyastha wants to merge 1 commit into
vllm-project:mainfrom
meghana-madhyastha:fix/muse-glimmer-reasoning-tokens

Conversation

@meghana-madhyastha

@meghana-madhyastha meghana-madhyastha commented Aug 27, 2026

Copy link
Copy Markdown

The muse_glimmer reasoning parser inherited the base count_reasoning_tokens() that returns 0, so usage.completion_tokens_details.reasoning_tokens was always 0. Classify the decoded output with the parser's own logic, including the turn re-open after tool calls, and count the reasoning text.

Purpose

With --reasoning-parser muse_glimmer, chat completions always report reasoning_tokens: 0 in usage.completion_tokens_details, because the parser inherits the base count_reasoning_tokens() that returns 0. Clients that rely on the count (OpenRouter's reasoning checks, billing) see no reasoning even when the model produced a long reasoning body.

This implements count_reasoning_tokens() for the Muse-Glimmer parser: decode the generated ids, classify the bodies with the parser's existing logic, and re-encode the reasoning text to count it. Classification is done without anchoring to the current assistant turn, because after a tool call the model re-opens the turn (<|eom|><|start|>assistant to=user<|message|>) and a turn-anchored scan would drop the reasoning emitted before it.

Note: developed with AI assistance (Claude); the code and tests were reviewed and validated end-to-end by the author.

Test Plan

New unit tests in tests/reasoning/test_muse_glimmer_count_reasoning_tokens.py (reasoning only, reasoning + content, no reasoning, tool-call turn re-open, empty input).

Test Result

Before: reasoning_tokens: 0 for every request.
After: e.g. reasoning_tokens: 43 for a request with an 83-character reasoning body, 0 when the model emits none; tool-call turns count the reasoning emitted before the re-open. Unit tests pass.


Essential Elements of an Effective PR Description Checklist
  • [x ] The purpose of the PR, such as "Fix some issue (link existing issues this PR will resolve)".
  • [x ] The test plan, such as providing test command.
  • The test results, such as pasting the results comparison before and after, or e2e results
  • (Optional) The necessary documentation update, such as updating supported_models.md and examples for a new model.

The muse_glimmer reasoning parser inherited the base count_reasoning_tokens() that returns 0, so usage.completion_tokens_details.reasoning_tokens was always 0. Classify the decoded output with the parser's own logic, including the turn re-open after tool calls, and count the reasoning text.

Co-authored-by: Claude <noreply@anthropic.com>

Signed-off-by: Meghana Madhyastha <meghana.madhyastha@parasail.io>

@claude claude Bot 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.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the vLLM project.

💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in #pr-reviews, coordinate on features in #feat- channels, or join special interest groups in #sig- channels.

PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment /ci run for upstream CI or /amd-ci run for AMD CI only whenever CI signals are needed.

Once the PR is approved or has the ready label, the PR author can also use the corresponding /ci run, /ci retry, and /ci cancel commands, or their /amd-ci variants. New commits do not start upstream CI automatically.

If you have any questions, please reach out to us on Slack at https://slack.vllm.ai.

Agent Guidelines

IMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban.

🚀

@corona10

Copy link
Copy Markdown

I think that #54238 is better approach :)

corona10 added a commit to corona10/vllm that referenced this pull request Aug 29, 2026
MuseGlimmerReasoningParser inherited the base count_reasoning_tokens()
that returns 0, so usage.completion_tokens_details.reasoning_tokens was
always 0 for --reasoning-parser muse_glimmer.

The ATEM framing markers are not guaranteed to be single vocab tokens
(e.g. " to=self" is two tokens), so tokens cannot be classified by id.
Instead, decode each token once (cached per request), record its
character offset, locate to=self bodies in the decoded text, and count
the tokens starting inside those spans with bisect. This counts the
original tokens exactly rather than re-encoding the reasoning text.

The body-end rule (<|eom|> / <|eot|> / next channel header / EOF) is
factored into _body_end() and shared with _classify_bodies(), so the
streamed reasoning text and the reported count cut bodies identically.

Related: vllm-project#54091 takes the decode -> classify -> re-encode approach for
the same bug; this variant is exact at span boundaries and ~12x cheaper
per call (247us vs 2984us at 4k reasoning tokens with the real
tokenizer), which matters because chat streaming re-counts the full
token list on every delta.

Signed-off-by: Donghee Na <donghee.na92@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working tool-calling

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants