renderers 0.1.8.dev53__tar.gz → 0.1.8.dev54__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 (69) hide show
  1. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/PKG-INFO +1 -1
  2. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/__init__.py +2 -0
  3. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/_version.py +2 -2
  4. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/base.py +4 -1
  5. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/configs.py +24 -0
  6. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/laguna_xs2.py +26 -17
  7. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/conftest.py +3 -0
  8. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/.github/workflows/publish-dev.yml +0 -0
  9. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/.github/workflows/publish.yml +0 -0
  10. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/.github/workflows/style.yml +0 -0
  11. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/.github/workflows/test.yml +0 -0
  12. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/.gitignore +0 -0
  13. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/.pre-commit-config.yaml +0 -0
  14. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/LICENSE +0 -0
  15. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/README.md +0 -0
  16. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/docs/renderer-config.md +0 -0
  17. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/examples/README.md +0 -0
  18. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/examples/sglang/multiturn_generate_sglang.py +0 -0
  19. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/examples/sglang/online_multiturn_sglang.py +0 -0
  20. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/examples/tinker/multiturn_generate_tinker.py +0 -0
  21. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/examples/transformers/multiturn_generate_transformers.py +0 -0
  22. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/examples/vllm/multiturn_generate_vllm.py +0 -0
  23. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/pyproject.toml +0 -0
  24. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/client.py +0 -0
  25. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/deepseek_r1.py +0 -0
  26. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/deepseek_v3.py +0 -0
  27. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/default.py +0 -0
  28. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/glm45.py +0 -0
  29. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/glm5.py +0 -0
  30. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/gpt_oss.py +0 -0
  31. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/kimi_k2.py +0 -0
  32. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/kimi_k25.py +0 -0
  33. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/llama_3.py +0 -0
  34. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/minimax_m2.py +0 -0
  35. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/nemotron3.py +0 -0
  36. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/parsers.py +0 -0
  37. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/parsing.py +0 -0
  38. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/qwen3.py +0 -0
  39. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/qwen35.py +0 -0
  40. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/qwen36.py +0 -0
  41. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/renderers/qwen3_vl.py +0 -0
  42. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_bridge.py +0 -0
  43. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_build_helpers.py +0 -0
  44. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_client.py +0 -0
  45. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_deepseek_r1.py +0 -0
  46. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_gpt_oss_harmony_parity.py +0 -0
  47. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_incremental.py +0 -0
  48. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_is_content.py +0 -0
  49. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_kimi_k25_tool_schema.py +0 -0
  50. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_llama_3.py +0 -0
  51. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_load_tokenizer.py +0 -0
  52. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_message_indices.py +0 -0
  53. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_message_tool_names.py +0 -0
  54. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_multimodal.py +0 -0
  55. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_nemotron3_parity.py +0 -0
  56. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_nemotron3_ultra.py +0 -0
  57. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_parse_response.py +0 -0
  58. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_parse_response_robustness.py +0 -0
  59. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_parsers.py +0 -0
  60. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_preserve_thinking.py +0 -0
  61. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_qwen35_size_coverage.py +0 -0
  62. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_render_ids.py +0 -0
  63. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_renderer_config.py +0 -0
  64. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_renderer_config_parity.py +0 -0
  65. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_roundtrip.py +0 -0
  66. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_sampled_mask.py +0 -0
  67. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_tokens_per_message.py +0 -0
  68. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/tests/test_tool_arg_type_preservation.py +0 -0
  69. {renderers-0.1.8.dev53 → renderers-0.1.8.dev54}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: renderers
3
- Version: 0.1.8.dev53
3
+ Version: 0.1.8.dev54
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
@@ -54,6 +54,7 @@ from renderers.configs import (
54
54
  KimiK25RendererConfig,
55
55
  KimiK2RendererConfig,
56
56
  LagunaXS2RendererConfig,
57
+ LagunaXS21RendererConfig,
57
58
  Llama3RendererConfig,
58
59
  MiniMaxM2RendererConfig,
59
60
  Nemotron3RendererConfig,
@@ -139,6 +140,7 @@ __all__ = [
139
140
  "KimiK2RendererConfig",
140
141
  "LagunaXS2Renderer",
141
142
  "LagunaXS2RendererConfig",
143
+ "LagunaXS21RendererConfig",
142
144
  "Llama3Renderer",
143
145
  "Llama3RendererConfig",
144
146
  "MULTIMODAL_MODELS",
@@ -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.8.dev53'
22
- __version_tuple__ = version_tuple = (0, 1, 8, 'dev53')
21
+ __version__ = version = '0.1.8.dev54'
22
+ __version_tuple__ = version_tuple = (0, 1, 8, 'dev54')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1060,8 +1060,10 @@ MODEL_RENDERER_MAP: dict[str, str] = {
1060
1060
  # construction to pin a different date.
1061
1061
  "meta-llama/Llama-3.2-1B-Instruct": "llama-3",
1062
1062
  "meta-llama/Llama-3.2-3B-Instruct": "llama-3",
1063
- # Poolside Laguna.
1063
+ # Poolside Laguna. XS-2.1's template is byte-identical to XS.2's minus
1064
+ # the default system message; the config name selects the variant.
1064
1065
  "poolside/Laguna-XS.2": "laguna-xs.2",
1066
+ "poolside/Laguna-XS-2.1": "laguna-xs-2.1",
1065
1067
  # GPT-OSS.
1066
1068
  "openai/gpt-oss-20b": "gpt-oss",
1067
1069
  "openai/gpt-oss-120b": "gpt-oss",
@@ -1327,6 +1329,7 @@ def _populate_registry():
1327
1329
  "kimi-k2": KimiK2Renderer,
1328
1330
  "kimi-k2.5": KimiK25Renderer,
1329
1331
  "laguna-xs.2": LagunaXS2Renderer,
1332
+ "laguna-xs-2.1": LagunaXS2Renderer,
1330
1333
  "llama-3": Llama3Renderer,
1331
1334
  "nemotron-3": Nemotron3Renderer,
1332
1335
  "nemotron-3-ultra": Nemotron3UltraRenderer,
@@ -422,6 +422,27 @@ class LagunaXS2RendererConfig(BaseRendererConfig):
422
422
  chat template's ``render_assistant_messages_raw`` gate."""
423
423
 
424
424
 
425
+ class LagunaXS21RendererConfig(BaseRendererConfig):
426
+ """Laguna XS-2.1 renderer config — distinct discriminator so auto
427
+ resolution gives XS-2.1 checkpoints the no-default-system-message
428
+ template variant.
429
+
430
+ XS-2.1's chat template is byte-identical to XS.2's except it ships
431
+ no default system message: when the caller provides none (and no
432
+ tools), the ``<system>`` block is omitted entirely. Shares
433
+ :class:`renderers.laguna_xs2.LagunaXS2Renderer`, which selects the
434
+ variant from ``config.name``.
435
+ """
436
+
437
+ name: Literal["laguna-xs-2.1"] = "laguna-xs-2.1"
438
+
439
+ enable_thinking: bool = False
440
+ """See :class:`LagunaXS2RendererConfig.enable_thinking`."""
441
+
442
+ render_assistant_messages_raw: bool = False
443
+ """See :class:`LagunaXS2RendererConfig.render_assistant_messages_raw`."""
444
+
445
+
425
446
  class Llama3RendererConfig(BaseRendererConfig):
426
447
  """Llama-3.x Instruct renderer config.
427
448
 
@@ -576,6 +597,7 @@ RendererConfig = Annotated[
576
597
  KimiK2RendererConfig,
577
598
  KimiK25RendererConfig,
578
599
  LagunaXS2RendererConfig,
600
+ LagunaXS21RendererConfig,
579
601
  Llama3RendererConfig,
580
602
  MiniMaxM2RendererConfig,
581
603
  Nemotron3RendererConfig,
@@ -613,6 +635,7 @@ _CONFIG_BY_NAME: dict[str, type[BaseRendererConfig]] = {
613
635
  "kimi-k2": KimiK2RendererConfig,
614
636
  "kimi-k2.5": KimiK25RendererConfig,
615
637
  "laguna-xs.2": LagunaXS2RendererConfig,
638
+ "laguna-xs-2.1": LagunaXS21RendererConfig,
616
639
  "llama-3": Llama3RendererConfig,
617
640
  "minimax-m2": MiniMaxM2RendererConfig,
618
641
  "nemotron-3": Nemotron3RendererConfig,
@@ -659,6 +682,7 @@ __all__ = [
659
682
  "KimiK25RendererConfig",
660
683
  "KimiK2RendererConfig",
661
684
  "LagunaXS2RendererConfig",
685
+ "LagunaXS21RendererConfig",
662
686
  "Llama3RendererConfig",
663
687
  "MiniMaxM2RendererConfig",
664
688
  "Nemotron3RendererConfig",
@@ -1,4 +1,4 @@
1
- """Laguna-XS.2 Renderer.
1
+ """Laguna-XS.2 / XS-2.1 Renderer.
2
2
 
3
3
  Main properties:
4
4
  - Prefix is the single token ``〈|EOS|〉`` (also the EOS / stop token).
@@ -12,10 +12,13 @@ Main properties:
12
12
  - Tool calls: ``<tool_call>`` / ``</tool_call>`` ARE single tokens, but the
13
13
  inner ``<arg_key>`` / ``</arg_key>`` / ``<arg_value>`` / ``</arg_value>``
14
14
  markers are plain text — parsed via regex on the decoded inner block.
15
- - The template bakes in a default system prompt when ``messages[0]`` is not
16
- a system message. The system block also contains the tools section (under
17
- a ``### Tools`` header with an ``<available_tools>`` listing and prose
18
- format instructions that vary on ``enable_thinking``).
15
+ - XS.2's template bakes in a default system prompt when ``messages[0]`` is
16
+ not a system message; XS-2.1's (otherwise byte-identical) template
17
+ removed it, so no system message and no tools means no ``<system>``
18
+ block at all. The config's ``name`` selects the variant. The system
19
+ block also contains the tools section (under a ``### Tools`` header
20
+ with an ``<available_tools>`` listing and prose format instructions
21
+ that vary on ``enable_thinking``).
19
22
  - Reasoning is rendered for every assistant message — no last-user-index
20
23
  gating. ``thinking_retention`` is accepted for protocol uniformity but
21
24
  is effectively a no-op since past reasoning is preserved by default.
@@ -39,7 +42,7 @@ from renderers.base import (
39
42
  resolve_thinking_retention,
40
43
  should_rerender_for_thinking_retention,
41
44
  )
42
- from renderers.configs import LagunaXS2RendererConfig
45
+ from renderers.configs import LagunaXS2RendererConfig, LagunaXS21RendererConfig
43
46
  from renderers.parsing import parse_laguna_xs2
44
47
 
45
48
  _DEFAULT_SYSTEM_MESSAGE = (
@@ -81,7 +84,7 @@ class LagunaXS2Renderer:
81
84
  def __init__(
82
85
  self,
83
86
  tokenizer: PreTrainedTokenizer,
84
- config: LagunaXS2RendererConfig | None = None,
87
+ config: LagunaXS2RendererConfig | LagunaXS21RendererConfig | None = None,
85
88
  ):
86
89
  self._tokenizer = tokenizer
87
90
  self.config = config or LagunaXS2RendererConfig()
@@ -89,6 +92,11 @@ class LagunaXS2Renderer:
89
92
  self.config,
90
93
  "all",
91
94
  )
95
+ # XS.2's template bakes in a default system prompt; XS-2.1's
96
+ # (otherwise byte-identical) template removed it.
97
+ self._default_system_message = (
98
+ _DEFAULT_SYSTEM_MESSAGE if self.config.name == "laguna-xs.2" else ""
99
+ )
92
100
 
93
101
  self._eos = self._token_id("〈|EOS|〉")
94
102
  self._think = self._token_id("<think>")
@@ -184,7 +192,7 @@ class LagunaXS2Renderer:
184
192
  emit_special(self._eos, -1, is_sampled=False, is_content=False)
185
193
 
186
194
  # ── System header (absorbs messages[0] if it's a system message) ──
187
- system_content = _DEFAULT_SYSTEM_MESSAGE
195
+ system_content = self._default_system_message
188
196
  system_msg_idx = -1
189
197
  caller_has_system = bool(messages and messages[0].get("role") == "system")
190
198
  if caller_has_system:
@@ -196,16 +204,12 @@ class LagunaXS2Renderer:
196
204
  # gate: when the caller passes an empty system message and no tools,
197
205
  # the whole ``<system>...</system>`` block is omitted.
198
206
  if has_sys_content or tools:
199
- # The template emits ``<system>\n`` then conditionally a second
200
- # ``\n``. Bundle those into one emit so BPE merges ``\n\n`` into
201
- # its single-token form (rather than two ``\n`` atoms).
202
- emit_text(
203
- "<system>\n\n" if has_sys_content else "<system>\n",
204
- -1,
205
- is_sampled=False,
206
- is_content=False,
207
- )
208
207
  if has_sys_content:
208
+ # The template emits ``<system>\n`` then a second ``\n``
209
+ # before the system body. Bundle those into one emit so BPE
210
+ # merges ``\n\n`` into its single-token form (rather than
211
+ # two ``\n`` atoms).
212
+ emit_text("<system>\n\n", -1, is_sampled=False, is_content=False)
209
213
  # If the caller provided system content, it's body bytes;
210
214
  # otherwise this is the default system prompt (scaffold).
211
215
  sys_is_content = caller_has_system
@@ -224,6 +228,11 @@ class LagunaXS2Renderer:
224
228
  if self.config.enable_thinking
225
229
  else _TOOLS_FOOTER_NO_THINKING
226
230
  )
231
+ if not has_sys_content:
232
+ # No system body: ``<system>\n`` runs straight into the
233
+ # tools header's ``\n\n`` — encode them together so BPE
234
+ # merges the ``\n\n\n`` seam as the template does.
235
+ tool_text = "<system>\n" + tool_text
227
236
  emit_text(tool_text, -1, is_sampled=False, is_content=False)
228
237
  emit_text("\n</system>\n", -1, is_sampled=False, is_content=False)
229
238
 
@@ -37,6 +37,9 @@ RENDERER_MODELS = [
37
37
  # name (auto → MODEL_RENDERER_MAP → nemotron-3-ultra).
38
38
  ("nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", "auto"),
39
39
  ("poolside/Laguna-XS.2", "auto"),
40
+ # XS-2.1 resolves to the `laguna-xs-2.1` config variant (no default
41
+ # system message) via the model name.
42
+ ("poolside/Laguna-XS-2.1", "auto"),
40
43
  # DeepSeek-V3/R1 are intentionally NOT in this shared barrage: their
41
44
  # chat templates can't render the barrage's tool-call fixtures (the
42
45
  # templates require ``tool['type']`` and a string-serialized
File without changes
File without changes