mudler / mudler/vllm.cpp

port(TOOLS-STRUCTURED-CORE): a grammar masks the tokenizer EOS only, so a request stop token can end a structured generation mid-grammar

Open
#2,683 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
423
Forks
53
Avg merge
20h 26m
Merged PRs (30d)
310

Description

Row: TOOLS-STRUCTURED-CORE

Found by wave PORTQ-4 (#2680)
re-deriving PORT-NOW entry 124 of 5559679229..e126687a9a, upstream
05f0a80016 vllm#49227,
against this tree.

What is wrong

A grammar masks the tokenizer EOS only, never the request's own stop tokens,
so a request with stop_token_ids can terminate a structured-output generation
before the grammar reaches an accepting state.

The masking mechanism is here and is correct:

src/vllm/v1/structured_output/backend_native.cpp:1258-1261
  // EOS/stop tokens are allowed iff the grammar is at an accepting state.
  if (IsAccepting(cur.state)) {
    for (const int32_t sid : shared_->stop_token_ids) set_bit(sid);
  }

What is missing is the plumbing. shared_->stop_token_ids is engine-wide and
fixed at backend construction
(backend_native.cpp:1314-1325), and the only
production wiring passes no stop ids at all — MakeNativeBackendFactory(tokenizer_, vocab_size) at src/vllm/entrypoints/model_loader.cpp:2228-2229 leaves the third
parameter defaulted. The compile seam carries no stop parameter on either side:
include/vllm/v1/structured_output/backend_types.h:141-143 is a two-parameter
pure virtual, and src/vllm/v1/structured_output/manager.cpp:41-48 never reads the
request's sampling params.

The source field the fix needs already exists and is already populated:
SamplingParams::all_stop_token_ids at include/vllm/sampling_params.h:263, filled
at src/vllm/sampling_params.cpp:256 and
src/vllm/v1/engine/input_processor.cpp:161-184. Today its only consumer is the
min-tokens masker (src/vllm/v1/worker/gpu/input_batch.cpp:273-279).

Size, and why it is larger than upstream's nine lines

Add a stop-id parameter to the compile_grammar virtual and both overrides, read
all_stop_token_ids in manager.cpp, and move the stop set from
NativeBackendShared to per-NativeGrammar state.

One interaction needs a decision. This tree also excludes stop tokens from the
shared token-byte trie at construction (backend_native.cpp:1327-1340). A
per-request stop id that is in the trie would still be matchable mid-derivation, so
the exclusion cannot stay construction-time if the set becomes per-request. Estimate
~60-120 lines over five files plus a red-first test.

Adjacent, not this issue

.agents/engine-matrix.md:161 lists model_loader.cpp production wiring as a
TOOLS-XGRAMMAR W2 residual, and model_loader.cpp:2228 confirms production still
builds the native backend. So auto to xgrammar selection is real code nothing
served reaches. Whoever ports this will meet that; it is a pre-existing reachability
gap and belongs to that row.

Verification state

Nothing was executed — no build, no test run, no GPU, no lease. Every path:line
above was printed from the tree at a700e8da6 and re-read by the wave operator.
05f0a80016 is not an ancestor of the pin, and compile_grammar at the pin took
(request_type, grammar_spec) only, which is exactly what this tree mirrors — so
this is a genuine post-pin forward-port, not a pre-pin hole.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with compile_grammar in include/vllm/v1/structured_output/backend_types.h and its implementations, then trace request sampling params through src/vllm/v1/structured_output/manager.cpp. Inspect all_stop_token_ids and the NativeBackendShared trie setup in backend_native.cpp; done means request stop tokens are handled per request and cannot end generation before an accepting grammar state.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.