Skip to content

[1/N] Initial Implementation of Parser for ResponsesAPI#32712

Merged
chaunceyjiang merged 14 commits intovllm-project:mainfrom
qandrew:parser
Feb 4, 2026
Merged

[1/N] Initial Implementation of Parser for ResponsesAPI#32712
chaunceyjiang merged 14 commits intovllm-project:mainfrom
qandrew:parser

Conversation

@qandrew
Copy link
Copy Markdown
Contributor

@qandrew qandrew commented Jan 20, 2026

Purpose

Initial Implementation of #32713. This PR introduces

  • the concept of a Parser class to consolidate reasoning / tool calling, a ParserManager, with the first example being the MinimaxM2 parser.
  • hook up the Parser into responsesAPI.
  • parser manager lazy loads, similar to [Refactor] Lazy-loaded reasoning_parser #28092
  • No functional changes expected, just refactors.

Future goals

  • hook up GPT-OSS to use parser
  • have parser be used in ChatCompletions

Test Plan

vllm serve MiniMaxAI/MiniMax-M2   --tensor-parallel-size 4   --tool-call-parser minimax_m2   --reasoning-parser minimax_m2    --enable-auto-tool-choice --trust-remote-code
 curl -X POST "http://localhost:8000/v1/responses" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer dummy-api-key" \
    -d '{
      "model": "MiniMaxAI/MiniMax-M2",
      "input": "What is the weather in Paris in Celsius today?",
      "tools": [
        {
          "type": "function",
          "name": "get_weather",
          "description": "Get the current weather in a given location.",
          "parameters": {
            "type": "object",
            "properties": {
              "location": { "type": "string" },
              "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
            },
            "required": ["location", "unit"]
          }
        }
      ]
    }' | jq

Test Result


Essential Elements of an Effective PR Description Checklist
  • The purpose of the PR, such as "Fix some issue (link existing issues this PR will resolve)".
  • 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.
  • (Optional) Release notes update. If your change is user facing, please update the release notes draft in the Google Doc.

@mergify mergify bot added the frontend label Jan 20, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new abstraction layer for unifying reasoning and tool parsing, which is a significant architectural improvement. The Parser abstract class, DelegatingParser, and ParserManager provide a modular and extensible system for handling different parsing strategies. The integration into serving.py and responses/serving.py correctly utilizes this new abstraction. Type hints and docstrings are well-maintained, contributing to code clarity and maintainability.

Andrew Xia added 5 commits January 21, 2026 19:33
Signed-off-by: Andrew Xia <axia@fb.com>
Signed-off-by: Andrew Xia <axia@fb.com>
Signed-off-by: Andrew Xia <axia@fb.com>
Signed-off-by: Andrew Xia <axia@fb.com>
Signed-off-by: Andrew Xia <axia@fb.com>
@mergify
Copy link
Copy Markdown

mergify bot commented Jan 22, 2026

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @qandrew.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify bot added the needs-rebase label Jan 22, 2026
@qandrew qandrew changed the title [WIP] Parser Initial Implementation of Parser for ResponsesAPI Jan 22, 2026
Andrew Xia added 2 commits January 22, 2026 09:47
Signed-off-by: Andrew Xia <axia@fb.com>
Signed-off-by: Andrew Xia <axia@fb.com>
@qandrew qandrew marked this pull request as ready for review January 22, 2026 17:58
@mergify mergify bot removed the needs-rebase label Jan 22, 2026
@mergify
Copy link
Copy Markdown

mergify bot commented Jan 22, 2026

Hi @qandrew, the pre-commit checks have failed. Please run:

uv pip install pre-commit
pre-commit install
pre-commit run --all-files

Then, commit the changes and push to your branch.

For future commits, pre-commit will run automatically on changed files before each commit.

Tip

Is mypy or markdownlint failing?
mypy and markdownlint are run differently in CI. If the failure is related to either of these checks, please use the following commands to run them locally:
# For mypy (substitute "3.10" with the failing version if needed)
pre-commit run --hook-stage manual mypy-3.10
# For markdownlint
pre-commit run --hook-stage manual markdownlint

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

_WrappedParser.reasoning_parser_cls = reasoning_parser_cls
_WrappedParser.tool_parser_cls = tool_parser_cls

return _WrappedParser
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Global class attribute mutation causes shared state bug

Medium Severity

The _get_parser method modifies class-level attributes on the globally-shared _WrappedParser class (reasoning_parser_cls and tool_parser_cls). Since _WrappedParser is imported from a module, these attributes are shared across all usages. If multiple OpenAIServingResponses instances are created with different parser configurations (e.g., in tests, multi-model deployments, or configuration changes), later instances will overwrite the class attributes, affecting all previous instances that reference _WrappedParser.

Fix in Cursor Fix in Web

)
return parser
except KeyError:
pass
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Strategy 2 silently overrides user's explicit parser choices

Medium Severity

Strategy 2 in _get_parser can silently override the user's explicit parser configuration. When a user specifies different parsers for tools and reasoning (e.g., --tool-call-parser hermes --reasoning-parser minimax_m2), Strategy 2 iterates through both names and returns the first unified parser found. If "minimax_m2" has a unified parser registered, the user's explicit "hermes" tool parser choice is silently ignored and MinimaxM2ToolParser is used instead. This contradicts the PR's stated intent of "No functional changes expected."

Fix in Cursor Fix in Web

reasoning_parser_cls=self.reasoning_parser,
reasoning_parser_cls=self.parser.reasoning_parser_cls
if self.parser
else None,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing null check causes crash with ParsableContext

Medium Severity

When VLLM_USE_EXPERIMENTAL_PARSER_CONTEXT=True, the code passes self.parser.reasoning_parser_cls to ParsableContext, but only checks if self.parser is not None. If a user configures only a tool parser (no reasoning parser), self.parser will be _WrappedParser with reasoning_parser_cls = None. This passes None to ParsableContext, which raises ValueError("reasoning_parser_cls must be provided.") at runtime. The check needs to verify that reasoning_parser_cls is also not None before using ParsableContext.

Fix in Cursor Fix in Web

@mergify
Copy link
Copy Markdown

mergify bot commented Jan 28, 2026

Hi @qandrew, the pre-commit checks have failed. Please run:

uv pip install pre-commit
pre-commit install
pre-commit run --all-files

Then, commit the changes and push to your branch.

For future commits, pre-commit will run automatically on changed files before each commit.

Tip

Is mypy or markdownlint failing?
mypy and markdownlint are run differently in CI. If the failure is related to either of these checks, please use the following commands to run them locally:
# For mypy (substitute "3.10" with the failing version if needed)
pre-commit run --hook-stage manual mypy-3.10
# For markdownlint
pre-commit run --hook-stage manual markdownlint

Signed-off-by: Andrew Xia <axia@fb.com>
@mergify
Copy link
Copy Markdown

mergify bot commented Jan 28, 2026

Hi @qandrew, the pre-commit checks have failed. Please run:

uv pip install pre-commit
pre-commit install
pre-commit run --all-files

Then, commit the changes and push to your branch.

For future commits, pre-commit will run automatically on changed files before each commit.

Tip

Is mypy or markdownlint failing?
mypy and markdownlint are run differently in CI. If the failure is related to either of these checks, please use the following commands to run them locally:
# For mypy (substitute "3.10" with the failing version if needed)
pre-commit run --hook-stage manual mypy-3.10
# For markdownlint
pre-commit run --hook-stage manual markdownlint

@qandrew qandrew changed the title Initial Implementation of Parser for ResponsesAPI [1/N] Initial Implementation of Parser for ResponsesAPI Jan 28, 2026
Copy link
Copy Markdown
Collaborator

@chaunceyjiang chaunceyjiang left a comment

Choose a reason for hiding this comment

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

Thank you. I will research this issue in the coming days.
Also worth mentioning is that over the past two days, while looking into #33215, I've noticed some limitations in the current design of the ReasoningParser.
It might require a refactoring.

logger = init_logger(__name__)


@ParserManager.register_module("minimax_m2")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't really recommend adding another ParserManager.
Is it possible to have a self-contained mechanism to handle these tasks?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i would ideally like to merge reasoning parser and tool calling parser managers into a single ParserManager, then we can deprecate ReasoningManager / ToolCallingManager. would you have thoughts on this?

@qandrew
Copy link
Copy Markdown
Contributor Author

qandrew commented Jan 30, 2026

Thank you. I will research this issue in the coming days. Also worth mentioning is that over the past two days, while looking into #33215, I've noticed some limitations in the current design of the ReasoningParser. It might require a refactoring.

i'd be curious on your thoughts for ReasoningParser refactor and seeing how we could put it inside Parser :)

@mergify
Copy link
Copy Markdown

mergify bot commented Jan 31, 2026

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @qandrew.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify bot added the needs-rebase label Jan 31, 2026
@chaunceyjiang
Copy link
Copy Markdown
Collaborator

i'd be curious on your thoughts for ReasoningParser refactor and seeing how we could put it inside Parser :)

I’m not quite sure why this needs to be placed in a parser.

For some older models that don’t have reasoning, how are you planning to handle them?

@qandrew
Copy link
Copy Markdown
Contributor Author

qandrew commented Feb 2, 2026

i'd be curious on your thoughts for ReasoningParser refactor and seeing how we could put it inside Parser :)

I’m not quite sure why this needs to be placed in a parser.

For some older models that don’t have reasoning, how are you planning to handle them?

if there's no reasoning parser, there will be no parser, and the behavior will not be changed
https://github.com/vllm-project/vllm/pull/32712/changes#diff-56ef3613a051485ec100a639ae3964f0ba1a1897372186cd79826f7a390c13ddR335

Signed-off-by: Andrew Xia <axia@fb.com>
@mergify mergify bot removed the needs-rebase label Feb 2, 2026
@mergify
Copy link
Copy Markdown

mergify bot commented Feb 2, 2026

Hi @qandrew, the pre-commit checks have failed. Please run:

uv pip install pre-commit
pre-commit install
pre-commit run --all-files

Then, commit the changes and push to your branch.

For future commits, pre-commit will run automatically on changed files before each commit.

Tip

Is mypy or markdownlint failing?
mypy and markdownlint are run differently in CI. If the failure is related to either of these checks, please use the following commands to run them locally:
# For mypy (substitute "3.10" with the failing version if needed)
pre-commit run --hook-stage manual mypy-3.10
# For markdownlint
pre-commit run --hook-stage manual markdownlint

Signed-off-by: Andrew Xia <axia@fb.com>
@mergify
Copy link
Copy Markdown

mergify bot commented Feb 3, 2026

Hi @qandrew, the pre-commit checks have failed. Please run:

uv pip install pre-commit
pre-commit install
pre-commit run --all-files

Then, commit the changes and push to your branch.

For future commits, pre-commit will run automatically on changed files before each commit.

Tip

Is mypy or markdownlint failing?
mypy and markdownlint are run differently in CI. If the failure is related to either of these checks, please use the following commands to run them locally:
# For mypy (substitute "3.10" with the failing version if needed)
pre-commit run --hook-stage manual mypy-3.10
# For markdownlint
pre-commit run --hook-stage manual markdownlint

@qandrew qandrew requested a review from chaunceyjiang February 3, 2026 04:42
Copy link
Copy Markdown
Collaborator

@chaunceyjiang chaunceyjiang left a comment

Choose a reason for hiding this comment

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

Thanks to @qandrew for the patience and for walking me through the design in detail.

I think it makes sense to unify the tool parser and reasoning.

For this PR, I’d suggest starting by introducing get_parser, class Parser, and class WrappedParser.

ParserManager and MiniMaxM2Parser can be introduced in a separate PR(ParserManager hasn’t been invoked yet.
).

# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

"""
MiniMax M2 Parser - A unified parser for MiniMax M2 models.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As we discussed offline, this is just an example. We can add it in a separate PR.

Signed-off-by: Andrew Xia <axia@fb.com>
@mergify
Copy link
Copy Markdown

mergify bot commented Feb 3, 2026

Hi @qandrew, the pre-commit checks have failed. Please run:

uv pip install pre-commit
pre-commit install
pre-commit run --all-files

Then, commit the changes and push to your branch.

For future commits, pre-commit will run automatically on changed files before each commit.

Tip

Is mypy or markdownlint failing?
mypy and markdownlint are run differently in CI. If the failure is related to either of these checks, please use the following commands to run them locally:
# For mypy (substitute "3.10" with the failing version if needed)
pre-commit run --hook-stage manual mypy-3.10
# For markdownlint
pre-commit run --hook-stage manual markdownlint

@luccafong luccafong added the ready ONLY add when PR is ready to merge/full CI is needed label Feb 3, 2026
fix
Signed-off-by: Andrew Xia <axia@fb.com>
@mergify
Copy link
Copy Markdown

mergify bot commented Feb 3, 2026

Hi @qandrew, the pre-commit checks have failed. Please run:

uv pip install pre-commit
pre-commit install
pre-commit run --all-files

Then, commit the changes and push to your branch.

For future commits, pre-commit will run automatically on changed files before each commit.

Tip

Is mypy or markdownlint failing?
mypy and markdownlint are run differently in CI. If the failure is related to either of these checks, please use the following commands to run them locally:
# For mypy (substitute "3.10" with the failing version if needed)
pre-commit run --hook-stage manual mypy-3.10
# For markdownlint
pre-commit run --hook-stage manual markdownlint

Signed-off-by: Andrew Xia <axia@fb.com>
Copy link
Copy Markdown
Collaborator

@chaunceyjiang chaunceyjiang left a comment

Choose a reason for hiding this comment

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

Thanks~

except KeyError:
pass

# Strategy 3: Create a DelegatingParser with the individual parser classes
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

To be honest, personally I tend to keep only Strategy 3. I’d prefer to drop Strategy 1 and Strategy 2.

We can use a single Parser to unify the interface, but still keep the implementations of reasoning_parser and tool_parser separate. Basically, keep the current structure.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is also why I’d like you to remove vllm/parser/minimax_m2_parser.py.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Given that this PR is fairly urgent for you right now, I’m okay with merging it first, and we can discuss this part afterward.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

sounds good, appreciate the help! let me follow up with cleaning up minimax_m2_parser. It might be more clear to motivate strategy 1 through GPTOSS harmony parser, or if we want to support models that do interleaved reasoning :)

i think i'd prefer to move reasoning_parser / tool_parser into parser, but happy to chat about that more

@chaunceyjiang chaunceyjiang merged commit e1bf04b into vllm-project:main Feb 4, 2026
43 of 44 checks passed
gameofdimension pushed a commit to gameofdimension/vllm that referenced this pull request Feb 5, 2026
…#32712)

Signed-off-by: Andrew Xia <axia@fb.com>
Co-authored-by: Andrew Xia <axia@fb.com>
Signed-off-by: felix01.yu <felix01.yu@vipshop.com>
ItzDEXX pushed a commit to ItzDEXX/vllm that referenced this pull request Feb 19, 2026
…#32712)

Signed-off-by: Andrew Xia <axia@fb.com>
Co-authored-by: Andrew Xia <axia@fb.com>
liuchenbing2026 pushed a commit to liuchenbing2026/vllm that referenced this pull request Apr 4, 2026
…#32712)

Signed-off-by: Andrew Xia <axia@fb.com>
Co-authored-by: Andrew Xia <axia@fb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants