renderers 0.1.12.dev19__tar.gz → 0.1.12.dev20__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 (97) hide show
  1. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/PKG-INFO +1 -1
  2. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/_version.py +2 -2
  3. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/base.py +3 -2
  4. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/deepseek_v4.py +13 -18
  5. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/glm45.py +5 -18
  6. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/glm5.py +4 -17
  7. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/parsing.py +183 -298
  8. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/reasoning.py +18 -7
  9. renderers-0.1.12.dev20/renderers/tagged.py +192 -0
  10. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/conftest.py +12 -0
  11. renderers-0.1.12.dev20/tests/reference_continuations.py +164 -0
  12. renderers-0.1.12.dev20/tests/replay.py +48 -0
  13. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_bridge.py +5 -0
  14. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_deepseek_r1.py +6 -0
  15. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_deepseek_v4.py +12 -7
  16. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_disabled_thinking_stability.py +5 -0
  17. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_gemma4.py +5 -0
  18. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_glm_tool_name_validation.py +5 -0
  19. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_hy3.py +5 -0
  20. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_inkling.py +5 -0
  21. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_laguna_m1.py +5 -0
  22. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_laguna_xs21.py +5 -0
  23. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_multimodal.py +5 -0
  24. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_parity.py +10 -2
  25. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_parse_response.py +11 -3
  26. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_parse_response_robustness.py +4 -5
  27. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_qwen38.py +5 -0
  28. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_reasoning_boundaries.py +26 -8
  29. renderers-0.1.12.dev20/tests/test_roundtrip.py +211 -0
  30. renderers-0.1.12.dev20/tests/test_tagged_rollout.py +258 -0
  31. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_tool_arg_type_preservation.py +5 -0
  32. renderers-0.1.12.dev19/tests/test_roundtrip.py +0 -323
  33. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/.github/workflows/publish-dev.yml +0 -0
  34. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/.github/workflows/publish.yml +0 -0
  35. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/.github/workflows/style.yml +0 -0
  36. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/.github/workflows/test.yml +0 -0
  37. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/.gitignore +0 -0
  38. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/.pre-commit-config.yaml +0 -0
  39. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/LICENSE +0 -0
  40. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/README.md +0 -0
  41. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/docs/renderer-config.md +0 -0
  42. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/examples/README.md +0 -0
  43. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/examples/sglang/multiturn_generate_sglang.py +0 -0
  44. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/examples/sglang/online_multiturn_sglang.py +0 -0
  45. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/examples/tinker/multiturn_generate_tinker.py +0 -0
  46. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/examples/transformers/multiturn_generate_transformers.py +0 -0
  47. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/examples/vllm/multiturn_generate_vllm.py +0 -0
  48. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/pyproject.toml +0 -0
  49. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/__init__.py +0 -0
  50. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/client.py +0 -0
  51. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/configs.py +0 -0
  52. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/custom.py +0 -0
  53. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/deepseek_r1.py +0 -0
  54. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/deepseek_v3.py +0 -0
  55. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/default.py +0 -0
  56. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/gemma4.py +0 -0
  57. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/gpt_oss.py +0 -0
  58. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/hy3.py +0 -0
  59. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/inkling.py +0 -0
  60. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/kimi_k2.py +0 -0
  61. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/kimi_k25.py +0 -0
  62. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/laguna_s21.py +0 -0
  63. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/laguna_xs2.py +0 -0
  64. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/llama_3.py +0 -0
  65. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/minimax_m2.py +0 -0
  66. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/nemotron3.py +0 -0
  67. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/parsers.py +0 -0
  68. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/prime_qwen3.py +0 -0
  69. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/qwen3.py +0 -0
  70. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/qwen35.py +0 -0
  71. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/qwen36.py +0 -0
  72. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/qwen38.py +0 -0
  73. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/renderers/qwen3_vl.py +0 -0
  74. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/audit_prefix_stability.py +0 -0
  75. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/fixtures/prefix_stability.json +0 -0
  76. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/parity.py +0 -0
  77. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/reference_rendering.py +0 -0
  78. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_build_helpers.py +0 -0
  79. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_client.py +0 -0
  80. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_custom.py +0 -0
  81. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_incremental.py +0 -0
  82. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_is_content.py +0 -0
  83. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_kimi_k25_tool_schema.py +0 -0
  84. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_llama_3.py +0 -0
  85. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_load_tokenizer.py +0 -0
  86. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_message_indices.py +0 -0
  87. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_message_tool_names.py +0 -0
  88. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_nemotron35_vlm.py +0 -0
  89. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_nemotron3_ultra.py +0 -0
  90. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_offsetless_tokenizers.py +0 -0
  91. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_parsers.py +0 -0
  92. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_preserve_thinking.py +0 -0
  93. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_qwen35_size_coverage.py +0 -0
  94. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_renderer_config.py +0 -0
  95. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_sampled_mask.py +0 -0
  96. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/tests/test_tokens_per_message.py +0 -0
  97. {renderers-0.1.12.dev19 → renderers-0.1.12.dev20}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: renderers
3
- Version: 0.1.12.dev19
3
+ Version: 0.1.12.dev20
4
4
  Summary: Chat template renderers — deterministic message-to-token conversion for LLM training
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.1.12.dev19'
22
- __version_tuple__ = version_tuple = (0, 1, 12, 'dev19')
21
+ __version__ = version = '0.1.12.dev20'
22
+ __version_tuple__ = version_tuple = (0, 1, 12, 'dev20')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -782,8 +782,9 @@ class Renderer(Protocol):
782
782
  Pass the exact ``prompt_ids`` used for sampling whenever available.
783
783
  This identifies reasoning prefilled by the prompt, including Gemma's
784
784
  post-tool thought channel and partial assistant prefixes. Omitting it,
785
- passing None, and passing [] all parse a self-contained completion;
786
- generation settings do not imply an initial reasoning channel.
785
+ passing None, and passing [] are equivalent: the format's completion
786
+ grammar applies without prompt context. GLM and DeepSeek V4 also use
787
+ the configured generation mode to determine the initial channel.
787
788
 
788
789
  ``tools`` is the same list passed to ``render`` for this turn.
789
790
  XML-style formats (Qwen3.5, GLM, MiniMax, Laguna) render argument
@@ -22,8 +22,6 @@ import json
22
22
  from dataclasses import dataclass, field
23
23
  from typing import Any, Mapping
24
24
 
25
- from renderers.reasoning import scan_reasoning, prompt_ends_in_reasoning
26
-
27
25
  from renderers.base import (
28
26
  Message,
29
27
  ParsedResponse,
@@ -41,7 +39,7 @@ from renderers.base import (
41
39
  )
42
40
  from renderers.configs import DeepSeekV4RendererConfig
43
41
  from renderers.parsing import parse_deepseek_v4
44
-
42
+ from renderers.reasoning import prompt_ends_in_reasoning
45
43
 
46
44
  _BOS = "<|begin▁of▁sentence|>"
47
45
  _EOS = "<|end▁of▁sentence|>"
@@ -798,15 +796,18 @@ class DeepSeekV4Renderer:
798
796
  self._tokenizer,
799
797
  token_ids,
800
798
  stop_ids={self._eos},
801
- thinking_enabled=prompt_ends_in_reasoning(
802
- self._tokenizer,
803
- prompt_ids,
804
- stop_ids=set(self.get_stop_token_ids()),
805
- assistant_prefix="<|Assistant|>",
799
+ thinking_enabled=(
800
+ prompt_ends_in_reasoning(
801
+ self._tokenizer,
802
+ prompt_ids,
803
+ stop_ids=set(self.get_stop_token_ids()),
804
+ assistant_prefix="<|Assistant|>",
805
+ )
806
+ if prompt_ids
807
+ else self.config.enable_thinking
806
808
  ),
807
809
  think_end_id=self._think_end,
808
810
  think_start_id=self._think_start,
809
- dsml_id=self._dsml,
810
811
  )
811
812
 
812
813
  def get_stop_token_ids(self) -> list[int]:
@@ -827,16 +828,10 @@ class DeepSeekV4Renderer:
827
828
  ):
828
829
  return None
829
830
 
830
- boundary = scan_reasoning(
831
- self._tokenizer,
832
- previous_completion_ids,
833
- prompt_ids=previous_prompt_ids,
834
- stop_ids=set(self.get_stop_token_ids()),
835
- tool_start_id=self._dsml,
836
- tool_start_closes_reasoning=True,
837
- assistant_prefix="<|Assistant|>",
831
+ boundary = self.parse_response(
832
+ previous_completion_ids, prompt_ids=previous_prompt_ids, tools=tools
838
833
  )
839
- if boundary.is_open:
834
+ if boundary.reasoning_complete is False:
840
835
  if any(t in self.get_stop_token_ids() for t in previous_completion_ids):
841
836
  return None
842
837
  previous_completion_ids = [*previous_completion_ids, self._think_end]
@@ -13,14 +13,12 @@ from __future__ import annotations
13
13
  import json
14
14
  from typing import Any
15
15
 
16
- from renderers.reasoning import scan_reasoning, prompt_ends_in_reasoning
17
-
18
16
  from renderers.base import (
19
17
  Message,
20
18
  ParsedResponse,
21
19
  RenderedTokens,
22
- ToolSpec,
23
20
  Tokenizer,
21
+ ToolSpec,
24
22
  _content_mask_or_empty,
25
23
  attribute_text_segments,
26
24
  extract_message_tool_names,
@@ -296,12 +294,7 @@ class GLM45Renderer:
296
294
  arg_value_id=self._arg_value,
297
295
  arg_value_end_id=self._arg_value_end,
298
296
  tools=tools,
299
- prefilled_thinking=prompt_ends_in_reasoning(
300
- self._tokenizer,
301
- prompt_ids,
302
- stop_ids=set(self.get_stop_token_ids()),
303
- assistant_prefix="<|assistant|>",
304
- ),
297
+ thinking_enabled=self.config.enable_thinking,
305
298
  )
306
299
 
307
300
  def get_stop_token_ids(self) -> list[int]:
@@ -322,16 +315,10 @@ class GLM45Renderer:
322
315
  ):
323
316
  return None
324
317
 
325
- boundary = scan_reasoning(
326
- self._tokenizer,
327
- previous_completion_ids,
328
- prompt_ids=previous_prompt_ids,
329
- stop_ids=set(self.get_stop_token_ids()),
330
- tool_start_id=self._tool_call_tok,
331
- tool_start_closes_reasoning=True,
332
- assistant_prefix="<|assistant|>",
318
+ boundary = self.parse_response(
319
+ previous_completion_ids, prompt_ids=previous_prompt_ids, tools=tools
333
320
  )
334
- if boundary.is_open:
321
+ if boundary.reasoning_complete is False:
335
322
  if any(t in self.get_stop_token_ids() for t in previous_completion_ids):
336
323
  return None
337
324
  previous_completion_ids = [*previous_completion_ids, self._think_end]
@@ -14,8 +14,6 @@ from __future__ import annotations
14
14
  import json
15
15
  from typing import Any
16
16
 
17
- from renderers.reasoning import scan_reasoning, prompt_ends_in_reasoning
18
-
19
17
  from renderers.base import (
20
18
  Message,
21
19
  ParsedResponse,
@@ -351,12 +349,7 @@ class GLM5Renderer:
351
349
  arg_value_id=self._arg_value,
352
350
  arg_value_end_id=self._arg_value_end,
353
351
  tools=tools,
354
- prefilled_thinking=prompt_ends_in_reasoning(
355
- self._tokenizer,
356
- prompt_ids,
357
- stop_ids=set(self.get_stop_token_ids()),
358
- assistant_prefix="<|assistant|>",
359
- ),
352
+ thinking_enabled=getattr(self.config, "enable_thinking", True),
360
353
  )
361
354
 
362
355
  def get_stop_token_ids(self) -> list[int]:
@@ -377,16 +370,10 @@ class GLM5Renderer:
377
370
  ):
378
371
  return None
379
372
 
380
- boundary = scan_reasoning(
381
- self._tokenizer,
382
- previous_completion_ids,
383
- prompt_ids=previous_prompt_ids,
384
- stop_ids=set(self.get_stop_token_ids()),
385
- tool_start_id=self._tool_call_tok,
386
- tool_start_closes_reasoning=True,
387
- assistant_prefix="<|assistant|>",
373
+ boundary = self.parse_response(
374
+ previous_completion_ids, prompt_ids=previous_prompt_ids, tools=tools
388
375
  )
389
- if boundary.is_open:
376
+ if boundary.reasoning_complete is False:
390
377
  if any(t in self.get_stop_token_ids() for t in previous_completion_ids):
391
378
  return None
392
379
  previous_completion_ids = [*previous_completion_ids, self._think_end]