Add EBNF and Lark sampling temperature support - #730
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end support for rule-scoped sampling temperatures in Lark grammars, surfaces the effective temperature through matcher APIs (single, batch, and speculative draft-tree traversal), and preserves the metadata through grammar transformations, printing/parsing, and JSON serialization.
Changes:
- Add
[temperature=VALUE]attributes for eligible Lark rules/subgrammars and propagate “active temperature” through the Earley parsing state. - Expose effective temperatures via
GrammarMatcher.temperature, return temperatures fromBatchGrammarMatcher.batch_fill_next_token_bitmask, and optionally fill per-node temperatures inGrammarMatcher.traverse_draft_tree. - Persist temperature through grammar transforms + EBNF printing/parsing + JSON serialization, with new docs and focused Python tests.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/python/test_temperature.py | Adds focused tests for default/override/ambiguity behavior, batch API return values, traversal temperature filling, and validation. |
| tests/python/test_serialization.py | Updates expected serialized rules shape to include the new temperature field. |
| python/xgrammar/matcher.py | Adds default_temperature, temperature property, traversal temperatures output tensor, and batch API return value. |
| include/xgrammar/matcher.h | Extends C++ matcher APIs with default_temperature, GetTemperature, traversal temperatures, and batch-return temperatures. |
| docs/defining_structures/lark_grammar.md | Documents %json/%lark and adds new “Sampling Temperature” rule option documentation. |
| cpp/tvm_ffi/tvm_ffi.cc | Adds optional-float marshaling, threads temperature data through FFI, and returns temperatures from batch bitmask fill. |
| cpp/lark_converter.cc | Parses temperature rule attributes, restricts applicability, and persists per-rule temperature into the grammar builder. |
| cpp/grammar_printer.cc | Prints [temperature=...] on rules with temperature, using a precise float representation. |
| cpp/grammar_parser.h | Adds FloatLiteral token type to support parsing printed temperatures. |
| cpp/grammar_parser.cc | Extends lexer/parser to read rule attributes and float literals; persists parsed temperature into the builder. |
| cpp/grammar_matcher.cc | Stores default_temperature, tracks active_temperature_rule_id through parsing, computes max temperature across ambiguous scan states, returns temperatures from batch fill, and fills traversal temperatures. |
| cpp/grammar_impl.h | Adds temperature to rule metadata and includes it in reflection-based serialization. |
| cpp/grammar_functor.h | Preserves rule temperature during grammar functor transformations. |
| cpp/grammar_functor.cc | Preserves rule temperature across multiple grammar mutators/transformers and avoids inlining/optimizations that would lose it. |
| cpp/grammar_builder.h | Adds UpdateRuleTemperature API. |
| cpp/grammar_builder.cc | Implements UpdateRuleTemperature. |
| cpp/earley_parser.h | Adds active_temperature_rule_id to parser state and introduces resolver for inherited temperature. |
| cpp/earley_parser.cc | Propagates active_temperature_rule_id through rule expansion/completion/prediction to support correct runtime temperature reporting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+391
to
+394
| temperatures : Optional[torch.Tensor], default: None | ||
| Optional 1D float32 CPU tensor with one element per node. It is filled with the | ||
| effective temperature for each visited node. ``NaN`` means that no temperature | ||
| is configured. |
Comment on lines
+133
to
+134
| * \param temperatures Optional DLTensor to store the effective temperature for each node | ||
| * (1D float32 with num_nodes elements). NaN represents no effective temperature. |
| serialized = grammar.serialize_json() | ||
| expected_json = { | ||
| "rules": [["rule1", 4, -1, False], ["root", 8, -1, False]], | ||
| "rules": [["rule1", 4, -1, False, None], ["root", 8, -1, False, None]], |
Propagate rule-level sampling temperatures through matching so single, batched, and speculative decoding callers can apply the effective value.
Group embedded grammar directives with the other directives and present their examples directly as Lark source.
Make ambiguous temperature selection visible while retaining LLGuidance-compatible maximum-value behavior without repeated warnings.
Keep batch bitmask filling focused on mask generation and expose temperatures through an explicit batch query without repeated Python-to-C++ calls.
Expose the native EBNF rule-option syntax and cover its runtime behavior and validation directly in Python tests.
Rely on the built-in standard-library type traits for optional temperatures and batch results, removing manual Any conversion helpers.
Ubospica
force-pushed
the
feat/lark-temperature
branch
from
July 26, 2026 20:28
01e8dbc to
a186cc6
Compare
Seven-Streams
approved these changes
Jul 28, 2026
Contributor
|
Hi, I think the |
15 tasks
Seven-Streams
pushed a commit
that referenced
this pull request
Aug 5, 2026
Fix #756. The root cause of the syntax error is that `apache-tvm-ffi<=0.1.9` does not correctly convert the `std::optional<T>` types (newly added in temperature support #730) into python `Optional[T]` type hints. The type mapping issue was fixed in `apache-tvm-ffi==0.1.10`. Signed-off-by: cjackal <44624812+cjackal@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
[temperature=VALUE]attributes for Lark terminals and subgrammars, including nested override and ambiguous-path handlingGrammarMatcher,BatchGrammarMatcher, and draft-tree traversal APIsTest plan
pre-commit run --all-filesruff check python/xgrammar/matcher.py tests/python/test_temperature.py tests/python/test_serialization.pyHF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 pytest -q tests/python/test_temperature.py tests/python/test_lark.py tests/python/test_grammar_matcher_basic.py tests/python/test_speculative_decoding.py tests/python/test_serialization.py tests/python/test_grammar_parser.py(349 passed)