llguidance 0.7.20__tar.gz → 0.7.22__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. {llguidance-0.7.20 → llguidance-0.7.22}/CHANGELOG.md +10 -0
  2. {llguidance-0.7.20 → llguidance-0.7.22}/Cargo.lock +5 -5
  3. {llguidance-0.7.20 → llguidance-0.7.22}/PKG-INFO +3 -1
  4. {llguidance-0.7.20 → llguidance-0.7.22}/README.md +2 -0
  5. {llguidance-0.7.20 → llguidance-0.7.22}/parser/Cargo.toml +1 -1
  6. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/constraint.rs +10 -4
  7. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/parser.rs +6 -0
  8. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/formats.rs +9 -3
  9. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/matcher.rs +8 -3
  10. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/tokenparser.rs +39 -1
  11. {llguidance-0.7.20 → llguidance-0.7.22}/pyproject.toml +1 -1
  12. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/_tokenizer.py +1 -8
  13. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/cli.py +1 -1
  14. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/hf.py +3 -3
  15. {llguidance-0.7.20 → llguidance-0.7.22}/python/torch_tests/test_hf.py +1 -1
  16. {llguidance-0.7.20 → llguidance-0.7.22}/python_ext/Cargo.toml +1 -1
  17. {llguidance-0.7.20 → llguidance-0.7.22}/python_ext/src/py.rs +0 -7
  18. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/tests/test_lark.rs +34 -0
  19. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/tests/test_raw_parser.rs +62 -1
  20. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/install-deps.sh +1 -1
  21. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/Cargo.toml +1 -1
  22. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/src/toktree.rs +12 -10
  23. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie_hf_downloader/Cargo.toml +1 -1
  24. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie_hf_tokenizers/Cargo.toml +1 -1
  25. {llguidance-0.7.20 → llguidance-0.7.22}/.github/workflows/rust.yml +0 -0
  26. {llguidance-0.7.20 → llguidance-0.7.22}/.github/workflows/wheels.yml +0 -0
  27. {llguidance-0.7.20 → llguidance-0.7.22}/.gitignore +0 -0
  28. {llguidance-0.7.20 → llguidance-0.7.22}/CODE_OF_CONDUCT.md +0 -0
  29. {llguidance-0.7.20 → llguidance-0.7.22}/Cargo.toml +0 -0
  30. {llguidance-0.7.20 → llguidance-0.7.22}/LICENSE +0 -0
  31. {llguidance-0.7.20 → llguidance-0.7.22}/SECURITY.md +0 -0
  32. {llguidance-0.7.20 → llguidance-0.7.22}/SUPPORT.md +0 -0
  33. {llguidance-0.7.20 → llguidance-0.7.22}/c_sample/Makefile +0 -0
  34. {llguidance-0.7.20 → llguidance-0.7.22}/c_sample/README.md +0 -0
  35. {llguidance-0.7.20 → llguidance-0.7.22}/c_sample/c_sample.cpp +0 -0
  36. {llguidance-0.7.20 → llguidance-0.7.22}/docs/fast_forward.md +0 -0
  37. {llguidance-0.7.20 → llguidance-0.7.22}/docs/json_schema.md +0 -0
  38. {llguidance-0.7.20 → llguidance-0.7.22}/docs/mask_plot.png +0 -0
  39. {llguidance-0.7.20 → llguidance-0.7.22}/docs/optimizations.md +0 -0
  40. {llguidance-0.7.20 → llguidance-0.7.22}/docs/special_tokens.md +0 -0
  41. {llguidance-0.7.20 → llguidance-0.7.22}/docs/syntax.md +0 -0
  42. {llguidance-0.7.20 → llguidance-0.7.22}/docs/toktrie.md +0 -0
  43. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/Cargo.toml +0 -0
  44. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/expected_maskbench.json +0 -0
  45. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/jstats.sh +0 -0
  46. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/scripts/split-stats.sh +0 -0
  47. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/scripts/split_plot.py +0 -0
  48. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/src/json_stats.rs +0 -0
  49. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/src/lib.rs +0 -0
  50. {llguidance-0.7.20 → llguidance-0.7.22}/json_stats/src/stats.rs +0 -0
  51. {llguidance-0.7.20 → llguidance-0.7.22}/parser/LICENSE +0 -0
  52. {llguidance-0.7.20 → llguidance-0.7.22}/parser/README.md +0 -0
  53. {llguidance-0.7.20 → llguidance-0.7.22}/parser/build.rs +0 -0
  54. {llguidance-0.7.20 → llguidance-0.7.22}/parser/cbindgen.toml +0 -0
  55. {llguidance-0.7.20 → llguidance-0.7.22}/parser/grammars/character.json +0 -0
  56. {llguidance-0.7.20 → llguidance-0.7.22}/parser/grammars/json.json +0 -0
  57. {llguidance-0.7.20 → llguidance-0.7.22}/parser/llguidance.h +0 -0
  58. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/api.rs +0 -0
  59. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/from_guidance.rs +0 -0
  60. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/grammar.rs +0 -0
  61. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/lexer.rs +0 -0
  62. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/lexerspec.rs +0 -0
  63. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/mod.rs +0 -0
  64. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/perf.rs +0 -0
  65. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/regexvec.rs +0 -0
  66. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/earley/slicer.rs +0 -0
  67. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/factory.rs +0 -0
  68. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/ffi.rs +0 -0
  69. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/ffi_par.rs +0 -0
  70. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/grammar_builder.rs +0 -0
  71. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/README.md +0 -0
  72. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/compiler.rs +0 -0
  73. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/context_ref.rs +0 -0
  74. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/context_simple/context.rs +0 -0
  75. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/context_simple/draft.rs +0 -0
  76. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/context_simple/mod.rs +0 -0
  77. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/mod.rs +0 -0
  78. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/numeric.rs +0 -0
  79. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/schema.rs +0 -0
  80. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json/shared_context.rs +0 -0
  81. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/json_validation.rs +0 -0
  82. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lark/README.md +0 -0
  83. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lark/ast.rs +0 -0
  84. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lark/common.rs +0 -0
  85. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lark/compiler.rs +0 -0
  86. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lark/lexer.rs +0 -0
  87. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lark/mod.rs +0 -0
  88. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lark/parser.rs +0 -0
  89. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/lib.rs +0 -0
  90. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/logging.rs +0 -0
  91. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/output.rs +0 -0
  92. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/panic_utils.rs +0 -0
  93. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/regex_rewrite.rs +0 -0
  94. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/stop_controller.rs +0 -0
  95. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/substring.rs +0 -0
  96. {llguidance-0.7.20 → llguidance-0.7.22}/parser/src/tokenizer_json.rs +0 -0
  97. {llguidance-0.7.20 → llguidance-0.7.22}/plan.md +0 -0
  98. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/__init__.py +0 -0
  99. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/_grammar_from.py +0 -0
  100. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/_lib.pyi +0 -0
  101. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/_struct_tag.py +0 -0
  102. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/_util.py +0 -0
  103. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/gbnf_to_lark.py +0 -0
  104. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/mlx.py +0 -0
  105. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/numpy.py +0 -0
  106. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/py.typed +0 -0
  107. {llguidance-0.7.20 → llguidance-0.7.22}/python/llguidance/torch.py +0 -0
  108. {llguidance-0.7.20 → llguidance-0.7.22}/python/mypy.ini +0 -0
  109. {llguidance-0.7.20 → llguidance-0.7.22}/python/torch_tests/__init__.py +0 -0
  110. {llguidance-0.7.20 → llguidance-0.7.22}/python/torch_tests/test_bitmask.py +0 -0
  111. {llguidance-0.7.20 → llguidance-0.7.22}/python/torch_tests/test_matcher.py +0 -0
  112. {llguidance-0.7.20 → llguidance-0.7.22}/python_ext/src/lib.rs +0 -0
  113. {llguidance-0.7.20 → llguidance-0.7.22}/python_ext/src/llinterpreter.rs +0 -0
  114. {llguidance-0.7.20 → llguidance-0.7.22}/python_ext/src/llmatcher.rs +0 -0
  115. {llguidance-0.7.20 → llguidance-0.7.22}/python_ext/src/parserlimits.rs +0 -0
  116. {llguidance-0.7.20 → llguidance-0.7.22}/python_ext/src/pyjson.rs +0 -0
  117. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/Cargo.toml +0 -0
  118. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/README.md +0 -0
  119. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/cli.sh +0 -0
  120. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/blog.sample.json +0 -0
  121. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/blog.schema.json +0 -0
  122. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/blog.schema.ll.json +0 -0
  123. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/README.md +0 -0
  124. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/arithmetic.gbnf +0 -0
  125. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/c.gbnf +0 -0
  126. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/chess.gbnf +0 -0
  127. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/english.gbnf +0 -0
  128. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/japanese.gbnf +0 -0
  129. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/json.gbnf +0 -0
  130. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/json_arr.gbnf +0 -0
  131. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/list.gbnf +0 -0
  132. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/from-llama.cpp/vllm-sql.gbnf +0 -0
  133. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/lark.lark +0 -0
  134. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/rfc.lark +0 -0
  135. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/rfc.xml +0 -0
  136. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/data/ulysses.md +0 -0
  137. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/gtest.sh +0 -0
  138. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/lark.sh +0 -0
  139. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/run.sh +0 -0
  140. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/src/lib.rs +0 -0
  141. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/src/minimal.rs +0 -0
  142. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/src/sample_parser.rs +0 -0
  143. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/tests/test_ll.rs +0 -0
  144. {llguidance-0.7.20 → llguidance-0.7.22}/sample_parser/tests/test_stop.rs +0 -0
  145. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/annotate_asm.js +0 -0
  146. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/bump.py +0 -0
  147. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/cbindgen.sh +0 -0
  148. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/checklinks.py +0 -0
  149. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/checklinks.sh +0 -0
  150. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/ci-publish.py +0 -0
  151. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/disasm.sh +0 -0
  152. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/gbnf_to_lark.py +0 -0
  153. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/gen-testcase.py +0 -0
  154. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/git-version.sh +0 -0
  155. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/jsonschema-stats.js +0 -0
  156. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/remote-guidance-test.sh +0 -0
  157. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/rust-size.js +0 -0
  158. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/rust_size.py +0 -0
  159. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/test-guidance.sh +0 -0
  160. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/tokenizer_test.py +0 -0
  161. {llguidance-0.7.20 → llguidance-0.7.22}/scripts/update-git.py +0 -0
  162. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/LICENSE +0 -0
  163. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/README.md +0 -0
  164. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/src/bytes.rs +0 -0
  165. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/src/lib.rs +0 -0
  166. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/src/recognizer.rs +0 -0
  167. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/src/rng.rs +0 -0
  168. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/src/svob.rs +0 -0
  169. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/src/tokenv.rs +0 -0
  170. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie/tests/test_svob.rs +0 -0
  171. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie_hf_downloader/LICENSE +0 -0
  172. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie_hf_downloader/src/lib.rs +0 -0
  173. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie_hf_tokenizers/LICENSE +0 -0
  174. {llguidance-0.7.20 → llguidance-0.7.22}/toktrie_hf_tokenizers/src/lib.rs +0 -0
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  If a release doesn't introduce any interesting changes (build fixes etc.), it's skipped.
6
6
 
7
+ #### [0.7.22](https://github.com/guidance-ai/llguidance/compare/v0.7.21...0.7.22) 2025-05-21
8
+
9
+ - Keep EOS token bytes in `TokenizerWrapper` [`#178`](https://github.com/guidance-ai/llguidance/pull/178)
10
+ - Stop using prefix/sentinel strings for `TokenizerWrapper` [`#175`](https://github.com/guidance-ai/llguidance/pull/175)
11
+ - avoid taking poisoned locks, see [`#174`](https://github.com/guidance-ai/llguidance/issues/174) [`d41aa9a`](https://github.com/guidance-ai/llguidance/commit/d41aa9a4427967708a951506b2bc0e395871b6c8); thanks [@g-eoj](https://github.com/g-eoj)
12
+
13
+ #### [0.7.21](https://github.com/guidance-ai/llguidance/compare/v0.7.20...0.7.21) 2025-05-20
14
+
15
+ - include parser state in errors [`82e34da`](https://github.com/guidance-ai/llguidance/commit/82e34da704d22f04979d8cbc54a0ac00885a277d)
16
+ - tighten email format in JSON schema [`7454ea9`](https://github.com/guidance-ai/llguidance/commit/7454ea9df958f8bcc42e6bb986d6de397de65b3e)
7
17
 
8
18
  #### [0.7.20](https://github.com/guidance-ai/llguidance/compare/v0.7.19...0.7.20) 2025-05-15
9
19
 
@@ -1174,7 +1174,7 @@ checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
1174
1174
 
1175
1175
  [[package]]
1176
1176
  name = "llguidance"
1177
- version = "0.7.20"
1177
+ version = "0.7.22"
1178
1178
  dependencies = [
1179
1179
  "anyhow",
1180
1180
  "derivre",
@@ -1193,7 +1193,7 @@ dependencies = [
1193
1193
 
1194
1194
  [[package]]
1195
1195
  name = "llguidance_py"
1196
- version = "0.7.20"
1196
+ version = "0.7.22"
1197
1197
  dependencies = [
1198
1198
  "anyhow",
1199
1199
  "bytemuck",
@@ -2336,7 +2336,7 @@ dependencies = [
2336
2336
 
2337
2337
  [[package]]
2338
2338
  name = "toktrie"
2339
- version = "0.7.20"
2339
+ version = "0.7.22"
2340
2340
  dependencies = [
2341
2341
  "anyhow",
2342
2342
  "bytemuck",
@@ -2347,7 +2347,7 @@ dependencies = [
2347
2347
 
2348
2348
  [[package]]
2349
2349
  name = "toktrie_hf_downloader"
2350
- version = "0.7.20"
2350
+ version = "0.7.22"
2351
2351
  dependencies = [
2352
2352
  "anyhow",
2353
2353
  "hf-hub",
@@ -2358,7 +2358,7 @@ dependencies = [
2358
2358
 
2359
2359
  [[package]]
2360
2360
  name = "toktrie_hf_tokenizers"
2361
- version = "0.7.20"
2361
+ version = "0.7.22"
2362
2362
  dependencies = [
2363
2363
  "anyhow",
2364
2364
  "log",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llguidance
3
- Version: 0.7.20
3
+ Version: 0.7.22
4
4
  License-File: LICENSE
5
5
  Summary: Bindings for the Low-level Guidance (llguidance) Rust library for use within Guidance
6
6
  Author: Michal Moskal
@@ -20,6 +20,7 @@ Project-URL: issue_tracker, https://github.com/microsoft/llguidance/issues
20
20
 
21
21
  ---
22
22
 
23
+ * 2025-05-20 LLGuidance [shipped](https://x.com/OpenAIDevs/status/1924915341052019166) in [OpenAI](https://x.com/OpenAIDevs/status/1924915343677653014) for JSON Schema
23
24
  * 2025-04-11 integration [merged](https://github.com/chromium/chromium/commit/07ca6337c2f714ba0477202414bd2b1692e70594) into Chromium
24
25
  * 2025-03-25 integration [merged](https://github.com/vllm-project/vllm/pull/14779) into vLLM (v0.8.2)
25
26
  * 2025-02-26 integration [merged](https://github.com/sgl-project/sglang/pull/3298) into SGLang (v0.4.4)
@@ -59,6 +60,7 @@ The library can be used from:
59
60
 
60
61
  The library is currently integrated in:
61
62
  - [Guidance](https://github.com/guidance-ai/guidance) - library for interacting with LLMs
63
+ - [OpenAI models](https://x.com/OpenAIDevs/status/1924915343677653014) - LLGuidance powers [Structured Output](https://platform.openai.com/docs/guides/structured-outputs) (JSON Schema only)
62
64
  - [llama.cpp](https://github.com/ggerganov/llama.cpp/pull/10224) -
63
65
  available via `-DLLAMA_LLGUIDANCE=ON` option for `cmake`;
64
66
  llama.cpp can be also used Guidance Python package
@@ -8,6 +8,7 @@
8
8
 
9
9
  ---
10
10
 
11
+ * 2025-05-20 LLGuidance [shipped](https://x.com/OpenAIDevs/status/1924915341052019166) in [OpenAI](https://x.com/OpenAIDevs/status/1924915343677653014) for JSON Schema
11
12
  * 2025-04-11 integration [merged](https://github.com/chromium/chromium/commit/07ca6337c2f714ba0477202414bd2b1692e70594) into Chromium
12
13
  * 2025-03-25 integration [merged](https://github.com/vllm-project/vllm/pull/14779) into vLLM (v0.8.2)
13
14
  * 2025-02-26 integration [merged](https://github.com/sgl-project/sglang/pull/3298) into SGLang (v0.4.4)
@@ -47,6 +48,7 @@ The library can be used from:
47
48
 
48
49
  The library is currently integrated in:
49
50
  - [Guidance](https://github.com/guidance-ai/guidance) - library for interacting with LLMs
51
+ - [OpenAI models](https://x.com/OpenAIDevs/status/1924915343677653014) - LLGuidance powers [Structured Output](https://platform.openai.com/docs/guides/structured-outputs) (JSON Schema only)
50
52
  - [llama.cpp](https://github.com/ggerganov/llama.cpp/pull/10224) -
51
53
  available via `-DLLAMA_LLGUIDANCE=ON` option for `cmake`;
52
54
  llama.cpp can be also used Guidance Python package
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "llguidance"
3
- version = "0.7.20"
3
+ version = "0.7.22"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  description = "Super-fast Structured Outputs"
@@ -137,7 +137,7 @@ impl Constraint {
137
137
  /// The splice is never returned when ff_tokens are disabled in InferenceCapabilities.
138
138
  /// After this returns, commit_token() must be called with the sampled token if any.
139
139
  pub fn compute_mask(&mut self) -> Result<&StepResult> {
140
- panic_utils::catch_unwind(std::panic::AssertUnwindSafe(|| self.compute_mask_inner()))
140
+ self.catch_unwind(|s| s.compute_mask_inner())
141
141
  .map(|_| &self.last_res)
142
142
  }
143
143
 
@@ -185,6 +185,14 @@ impl Constraint {
185
185
  self.parser.validate_tokens_raw(tokens)
186
186
  }
187
187
 
188
+ fn catch_unwind<F, R>(&mut self, f: F) -> Result<R>
189
+ where
190
+ F: FnOnce(&mut Self) -> Result<R>,
191
+ {
192
+ panic_utils::catch_unwind(std::panic::AssertUnwindSafe(|| f(self)))
193
+ .map_err(|e| anyhow::anyhow!(self.parser.augment_err(e)))
194
+ }
195
+
188
196
  /// commit_token() is a top-level method in this file and is called by
189
197
  /// the LLInterpreter::commit_token().
190
198
  ///
@@ -194,9 +202,7 @@ impl Constraint {
194
202
  /// It only returns 'STOP' if previous compute_mask() already returned 'STOP'
195
203
  /// (in which case there's little point calling commit_token()).
196
204
  pub fn commit_token(&mut self, sampled_token: Option<TokenId>) -> Result<CommitResult> {
197
- panic_utils::catch_unwind(std::panic::AssertUnwindSafe(|| {
198
- self.commit_token_inner(sampled_token)
199
- }))
205
+ self.catch_unwind(|s| s.commit_token_inner(sampled_token))
200
206
  }
201
207
 
202
208
  fn commit_token_inner(&mut self, sampled_token: Option<TokenId>) -> Result<CommitResult> {
@@ -2827,4 +2827,10 @@ impl Parser {
2827
2827
  copy.shared = Arc::new(Mutex::new(shared.clone()));
2828
2828
  copy
2829
2829
  }
2830
+
2831
+ pub fn test_trigger_lexer_error(&mut self) -> Result<()> {
2832
+ self.with_shared(|_state| {
2833
+ panic!("synthetic error");
2834
+ })
2835
+ }
2830
2836
  }
@@ -27,9 +27,15 @@ pub fn lookup_format(name: &str) -> Option<&str> {
27
27
  "duration" => {
28
28
  r"P(?:(?P<dur_date>(?:(?P<dur_year>[0-9]+Y(?:[0-9]+M(?:[0-9]+D)?)?)|(?P<dur_month>[0-9]+M(?:[0-9]+D)?)|(?P<dur_day>[0-9]+D))(?:T(?:(?P<dur_hour>[0-9]+H(?:[0-9]+M(?:[0-9]+S)?)?)|(?P<dur_minute>[0-9]+M(?:[0-9]+S)?)|(?P<dur_second>[0-9]+S)))?)|(?P<dur_time>T(?:(?P<dur_hour2>[0-9]+H(?:[0-9]+M(?:[0-9]+S)?)?)|(?P<dur_minute2>[0-9]+M(?:[0-9]+S)?)|(?P<dur_second2>[0-9]+S)))|(?P<dur_week>[0-9]+W))"
29
29
  }
30
- "email" => {
31
- r"(?P<local_part>(?P<dot_string>[^\s@\.]+(\.[^\s@\.]+)*))@((?P<domain>(?P<sub_domain>[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)(\.(?P<sub_domain2>[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?))*)|\[(?P<ipv4>((([0-9])|(([1-9])[0-9]|(25[0-5]|(2[0-4]|(1)[0-9])[0-9])))\.){3}(([0-9])|(([1-9])[0-9]|(25[0-5]|(2[0-4]|(1)[0-9])[0-9]))))\])"
32
- }
30
+ // https://www.rfc-editor.org/rfc/inline-errata/rfc5321.html 4.1.2 -> Mailbox
31
+ "email" => concat!(
32
+ r"(?P<local_part>(?P<dot_string>[a-zA-Z0-9!#$%&'*+\-/=?\^_`{|}~]+(\.[a-zA-Z0-9!#$%&'*+\-/=?\^_`{|}~]+)*))",
33
+ r"@(",
34
+ r"(?P<domain>(?P<sub_domain>[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)(\.(?P<sub_domain2>[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?))*)",
35
+ r"|",
36
+ r"\[(?P<ipv4>((([0-9])|(([1-9])[0-9]|(25[0-5]|(2[0-4]|(1)[0-9])[0-9])))\.){3}(([0-9])|(([1-9])[0-9]|(25[0-5]|(2[0-4]|(1)[0-9])[0-9]))))\]",
37
+ r")"
38
+ ),
33
39
  "hostname" => {
34
40
  r"[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*"
35
41
  }
@@ -1,4 +1,4 @@
1
- use anyhow::{anyhow, ensure, Result};
1
+ use anyhow::{anyhow, bail, ensure, Result};
2
2
  use toktrie::{SimpleVob, TokEnv, TokenId};
3
3
 
4
4
  use crate::{api::StopReason, earley::ParserStats, panic_utils, TokenParser};
@@ -48,8 +48,9 @@ impl Matcher {
48
48
  match r {
49
49
  Ok(r) => Ok(r),
50
50
  Err(e) => {
51
- self.0 = MatcherState::Error(e.to_string());
52
- Err(e)
51
+ let msg = inner.parser.augment_err(e);
52
+ self.0 = MatcherState::Error(msg.clone());
53
+ bail!(msg);
53
54
  }
54
55
  }
55
56
  }
@@ -85,6 +86,10 @@ impl Matcher {
85
86
  self.consume_tokens(&[token])
86
87
  }
87
88
 
89
+ pub fn test_trigger_lexer_error(&mut self) -> Result<()> {
90
+ self.with_inner(|inner| inner.parser.parser.test_trigger_lexer_error())
91
+ }
92
+
88
93
  pub fn rollback(&mut self, num_tokens: usize) -> Result<()> {
89
94
  self.with_inner(|inner| inner.parser.rollback(num_tokens))
90
95
  }
@@ -1,4 +1,4 @@
1
- use std::{hint::black_box, panic::AssertUnwindSafe, sync::Arc, time::Duration};
1
+ use std::{fmt::Display, hint::black_box, panic::AssertUnwindSafe, sync::Arc, time::Duration};
2
2
 
3
3
  use crate::{
4
4
  api::{GrammarInit, ParserLimits, StopReason},
@@ -22,6 +22,9 @@ pub struct TokenParser {
22
22
  max_step_stats: ParserStats,
23
23
  eos_token: TokenId,
24
24
 
25
+ had_rollback: bool,
26
+ had_backtrack: bool,
27
+
25
28
  is_accepting_cache: Option<bool>,
26
29
  ff_tokens_cache: Option<(Vec<TokenId>, Vec<u8>)>,
27
30
  stop_reason: StopReason,
@@ -110,6 +113,8 @@ impl TokenParser {
110
113
  max_tokens_total: max_tokens,
111
114
  last_bias_time: Duration::from_secs(0),
112
115
  is_fresh: true,
116
+ had_backtrack: false,
117
+ had_rollback: false,
113
118
  })
114
119
  }
115
120
 
@@ -268,6 +273,36 @@ impl TokenParser {
268
273
  res_prompt
269
274
  }
270
275
 
276
+ pub fn augment_err(&self, e: impl Display) -> String {
277
+ format!("{e}\n<state>\n{}\n</state>", self.dump_state())
278
+ }
279
+
280
+ pub fn dump_state(&self) -> String {
281
+ // make sure not take self.parser.shared lock
282
+ // for example, self.parser.lexer_stats() takes it
283
+ // if we take it after panic, it will be poisoned
284
+ format!(
285
+ "Tokens: {}\n{} tokens, {} bytes; grm_prefix: {:?}\nFlags:{}{}\nParser: {}\nStop: {}\nError: {}",
286
+ self.tok_trie().tokens_dbg(&self.llm_tokens),
287
+ self.llm_tokens.len(),
288
+ self.llm_bytes.len(),
289
+ String::from_utf8_lossy(&self.grm_prefix),
290
+ if self.had_backtrack {
291
+ " had_backtrack"
292
+ } else {
293
+ ""
294
+ },
295
+ if self.had_rollback {
296
+ " had_rollback"
297
+ } else {
298
+ ""
299
+ },
300
+ self.parser.stats(),
301
+ self.stop_reason,
302
+ self.error_message.as_deref().unwrap_or("None"),
303
+ )
304
+ }
305
+
271
306
  fn clear_caches(&mut self) {
272
307
  self.is_accepting_cache = None;
273
308
  self.ff_tokens_cache = None;
@@ -332,6 +367,8 @@ impl TokenParser {
332
367
  // this will fail in case we're in error state or not initialized
333
368
  self.check_initialized("rollback")?;
334
369
 
370
+ self.had_rollback = true;
371
+
335
372
  let new_len = self.llm_tokens.len() - n_tokens;
336
373
  let mut bytes_to_drop = 0;
337
374
  for tok in &self.llm_tokens[new_len..] {
@@ -522,6 +559,7 @@ impl TokenParser {
522
559
  self.llm_bytes.extend_from_slice(tok_bytes);
523
560
 
524
561
  if backtrack_bytes0 != 0 {
562
+ self.had_backtrack = true;
525
563
  let mut backtrack_bytes: isize = backtrack_bytes0.try_into().unwrap();
526
564
  let mut backtrack_tokens = 0;
527
565
  while backtrack_bytes > 0 {
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "llguidance"
3
- version = "0.7.20"
3
+ version = "0.7.22"
4
4
  description = "Bindings for the Low-level Guidance (llguidance) Rust library for use within Guidance"
5
5
  requires-python = ">=3.9"
6
6
  license = "MIT"
@@ -23,10 +23,6 @@ class TokenizerWrapper:
23
23
  gtokenizer(b"test")
24
24
  except:
25
25
  self._accepts_bytes = False
26
- # If the tokenizer used bytes, then b"\xff" would be better (since it's invalid UTF-8)
27
- # For now, we'll settle for "\x02" as assume it doesn't start any other token
28
- self._prefix_string = "\x02"
29
- self._prefix_tokens = self._encode_string(self._prefix_string)
30
26
 
31
27
  def _encode_string(self, s: str) -> List[TokenId]:
32
28
  r: List[TokenId]
@@ -37,7 +33,4 @@ class TokenizerWrapper:
37
33
  return r
38
34
 
39
35
  # required by LLTokenizer
40
- def __call__(self, s: str) -> List[TokenId]:
41
- tokens = self._encode_string(self._prefix_string + s)
42
- assert tokens[: len(self._prefix_tokens)] == self._prefix_tokens
43
- return tokens[len(self._prefix_tokens) :]
36
+ __call__ = _encode_string
@@ -1,7 +1,7 @@
1
1
  import argparse
2
2
  import json
3
3
  import huggingface_hub
4
- from transformers import AutoTokenizer # type: ignore[attr-defined]
4
+ from transformers import AutoTokenizer
5
5
  import llguidance
6
6
 
7
7
 
@@ -13,11 +13,11 @@ def from_tokenizer(
13
13
  """
14
14
  Create a new tokenizer from a fast Hugging Face tokenizer.
15
15
  This is an expensive operation (~1s), so the result should be cached.
16
- It also currently creates a non-canonical tokenizer, which means it cannot
17
- produce fast-forward tokens (though it can produce fast-forward bytes).
16
+ It currently only supports fast tokenizers, which are then handled
17
+ by the Rust tokenizers library.
18
18
 
19
19
  Args:
20
- hf_tokenizer: transformers.PreTrainedTokenizerBase - the tokenizer to wrap
20
+ hf_tokenizer: transformers.PreTrainedTokenizerFast - the tokenizer to wrap
21
21
  n_vocab: int - override the size of the vocabulary
22
22
  eos_token: int - override the EOS token
23
23
  slices: List[str] - configuration for slicer optimization; pass [] to disable,
@@ -17,7 +17,7 @@ from llguidance import LLMatcher, LLTokenizer, LLExecutor
17
17
 
18
18
  import llguidance.hf
19
19
 
20
- from transformers import AutoTokenizer # type: ignore[attr-defined]
20
+ from transformers import AutoTokenizer
21
21
 
22
22
 
23
23
  def _build_tokenizer() -> LLTokenizer:
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "llguidance_py"
3
- version = "0.7.20"
3
+ version = "0.7.22"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  description = "Super-fast Structured Outputs"
@@ -241,14 +241,7 @@ impl PyTokenizer {
241
241
  }
242
242
  }
243
243
 
244
- // we want decode_bytes([EOS]) etc to be empty
245
- tokens[tok_eos as usize] = vec![];
246
- // if let Some(t) = tok_bos {
247
- // tokens[t as usize] = vec![];
248
- // }
249
-
250
244
  let info = TokRxInfo::new(tokens.len() as u32, tok_eos);
251
-
252
245
  let tok_trie = TokTrie::from(&info, &tokens);
253
246
  Ok(PyTokenizer {
254
247
  tok_trie: Arc::new(tok_trie),
@@ -1306,3 +1306,37 @@ fn test_json_min_max_properties() {
1306
1306
  ],
1307
1307
  );
1308
1308
  }
1309
+
1310
+ #[test]
1311
+ fn test_json_format_email() {
1312
+ json_test_many(
1313
+ &json!({
1314
+ "type": "string",
1315
+ "format": "email",
1316
+ }),
1317
+ &[
1318
+ json!("test@example.com"),
1319
+ json!("foo.bar@example.com"),
1320
+ json!("foo.bar@example-123.com"),
1321
+ json!("foo+bar@example-123.com"),
1322
+ json!("f$o#o`b-a!r@example-123.com"),
1323
+ json!("fo%o#bar@example-123.com"),
1324
+ json!("test@[192.168.1.1]"),
1325
+ ],
1326
+ &[
1327
+ json!(""),
1328
+ json!(" @example.com"),
1329
+ json!("test@"),
1330
+ json!("@example.com"),
1331
+ json!("test@.com"),
1332
+ json!("test@com"),
1333
+ json!("test@com."),
1334
+ json!("test@example..com"),
1335
+ json!("test@example.c"),
1336
+ json!("test@example.c."),
1337
+ json!("test@.example.com"),
1338
+ json!("test:2@example.com"),
1339
+ json!("test[2]@example.com"),
1340
+ ],
1341
+ );
1342
+ }
@@ -3,7 +3,7 @@ use llguidance::{
3
3
  api::TopLevelGrammar,
4
4
  earley::SlicedBiasComputer,
5
5
  toktrie::{InferenceCapabilities, TokEnv},
6
- ParserFactory, TokenParser,
6
+ Matcher, ParserFactory, TokenParser,
7
7
  };
8
8
  use serde_json::{json, Value};
9
9
 
@@ -207,3 +207,64 @@ fn test_ff_early() {
207
207
  parser.consume_token(*tok).unwrap();
208
208
  }
209
209
  }
210
+
211
+ #[test]
212
+ fn test_err_state() {
213
+ let lark = r#"
214
+ start: /[a-z]*/
215
+ "#;
216
+
217
+ let tokens = get_tok_env().tokenize("fobarbazqu123");
218
+ let mut t2 = vec![];
219
+ for _ in 0..100 {
220
+ t2.push(tokens[0]);
221
+ t2.push(tokens[1]);
222
+ t2.push(tokens[2]);
223
+ }
224
+ t2.extend_from_slice(&tokens);
225
+ let mut matcher = Matcher::new(Ok(make_parser(lark)));
226
+
227
+ for tok in t2.iter() {
228
+ if let Err(e) = matcher.consume_token(*tok) {
229
+ let e = e.to_string();
230
+ println!("Error: {}", e);
231
+ assert!(e.contains("<state>"));
232
+ assert!(e.contains("Tokens:"));
233
+ return;
234
+ }
235
+ }
236
+ unreachable!();
237
+ }
238
+
239
+ #[test]
240
+ fn test_trigger_lexer_error() {
241
+ let lark = r#"
242
+ start: /[a-z]*/
243
+ "#;
244
+
245
+ let tokens = get_tok_env().tokenize("fobarbazqu");
246
+ let mut matcher = Matcher::new(Ok(make_parser(lark)));
247
+
248
+ for tok in tokens.iter() {
249
+ matcher.consume_token(*tok).unwrap();
250
+ }
251
+
252
+ if let Err(e) = matcher.test_trigger_lexer_error() {
253
+ let e = e.to_string();
254
+ println!("Error: {}", e);
255
+ assert!(e.contains("<state>"));
256
+ assert!(e.contains("synthetic error"));
257
+ } else {
258
+ unreachable!();
259
+ }
260
+
261
+ // now all calls should return the same error
262
+ if let Err(e) = matcher.consume_token(123) {
263
+ let e = e.to_string();
264
+ println!("Error: {}", e);
265
+ assert!(e.contains("<state>"));
266
+ assert!(e.contains("synthetic error"));
267
+ } else {
268
+ unreachable!();
269
+ }
270
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  # installing guidance for deps
4
4
  pip install pytest guidance huggingface_hub tokenizers jsonschema maturin[zig] \
5
- torch transformers bitsandbytes ipython psutil mypy
5
+ torch transformers==4.52.1 bitsandbytes ipython psutil mypy
6
6
  pip uninstall -y guidance
7
7
 
8
8
  # print out versions
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "toktrie"
3
- version = "0.7.20"
3
+ version = "0.7.22"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  description = "LLM Token Trie library"
@@ -295,26 +295,25 @@ impl TokTrie {
295
295
  }
296
296
 
297
297
  fn tokens_dbg_ext(&self, toks: &[u32], quote: bool) -> String {
298
+ // if the token list is too long, we are typically interested in the most recent ones
298
299
  let (limited, toks) = if toks.len() > Self::MAX_DBG_TOKENS {
299
- (true, &toks[0..Self::MAX_DBG_TOKENS])
300
+ ("…", &toks[toks.len() - Self::MAX_DBG_TOKENS..])
300
301
  } else {
301
- (false, toks)
302
+ ("", toks)
302
303
  };
303
304
 
304
- let mut joined = toks
305
+ let joined = toks
305
306
  .iter()
306
307
  .map(|t| self.token_dbg_ext(*t, false))
307
308
  .collect::<Vec<_>>()
308
309
  .join("‧");
309
310
 
310
- if limited {
311
- joined.push('…');
312
- }
313
-
314
311
  if quote {
315
- format!("⟦{}⟧", joined)
316
- } else {
312
+ format!("⟦{}{}⟧", limited, joined)
313
+ } else if limited.is_empty() {
317
314
  joined
315
+ } else {
316
+ format!("{}{}", limited, joined)
318
317
  }
319
318
  }
320
319
 
@@ -1037,9 +1036,12 @@ impl TrieHash {
1037
1036
  self.children.sort_by_key(|e| e.byte);
1038
1037
  for entry in &mut self.children {
1039
1038
  num_ch -= 1;
1039
+ assert!(num_parents < 0xff);
1040
1040
  entry.serialize(data, if num_ch == 0 { num_parents + 1 } else { 1 });
1041
1041
  }
1042
- data[idx].bits2 |= ((data.len() - idx) as u32) << 8;
1042
+ let subtree_size = data.len() - idx;
1043
+ assert!(subtree_size < 0x100_0000);
1044
+ data[idx].bits2 |= (subtree_size as u32) << 8;
1043
1045
  }
1044
1046
  }
1045
1047
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "toktrie_hf_downloader"
3
- version = "0.7.20"
3
+ version = "0.7.22"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  description = "HuggingFace Hub download library support for toktrie and llguidance"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "toktrie_hf_tokenizers"
3
- version = "0.7.20"
3
+ version = "0.7.22"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  description = "HuggingFace tokenizers library support for toktrie and llguidance"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes