renderers 0.1.8.dev43__tar.gz → 0.1.8.dev44__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 (71) hide show
  1. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/PKG-INFO +2 -2
  2. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/README.md +1 -1
  3. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/__init__.py +4 -0
  4. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/_version.py +2 -2
  5. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/base.py +8 -6
  6. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/configs.py +42 -29
  7. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/nemotron3.py +201 -196
  8. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/conftest.py +2 -1
  9. renderers-0.1.8.dev44/tests/test_nemotron3_parity.py +676 -0
  10. renderers-0.1.8.dev44/tests/test_nemotron3_ultra.py +104 -0
  11. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_renderer_config_parity.py +12 -2
  12. renderers-0.1.8.dev43/tests/test_nemotron3_ultra.py +0 -59
  13. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/.github/workflows/publish-dev.yml +0 -0
  14. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/.github/workflows/publish.yml +0 -0
  15. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/.github/workflows/style.yml +0 -0
  16. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/.github/workflows/test.yml +0 -0
  17. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/.gitignore +0 -0
  18. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/.pre-commit-config.yaml +0 -0
  19. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/LICENSE +0 -0
  20. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/docs/renderer-config.md +0 -0
  21. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/examples/README.md +0 -0
  22. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/examples/sglang/multiturn_generate_sglang.py +0 -0
  23. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/examples/sglang/online_multiturn_sglang.py +0 -0
  24. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/examples/tinker/multiturn_generate_tinker.py +0 -0
  25. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/examples/transformers/multiturn_generate_transformers.py +0 -0
  26. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/examples/vllm/multiturn_generate_vllm.py +0 -0
  27. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/pyproject.toml +0 -0
  28. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/client.py +0 -0
  29. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/deepseek_r1.py +0 -0
  30. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/deepseek_v3.py +0 -0
  31. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/default.py +0 -0
  32. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/glm45.py +0 -0
  33. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/glm5.py +0 -0
  34. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/gpt_oss.py +0 -0
  35. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/kimi_k2.py +0 -0
  36. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/kimi_k25.py +0 -0
  37. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/laguna_xs2.py +0 -0
  38. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/llama_3.py +0 -0
  39. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/minimax_m2.py +0 -0
  40. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/parsers.py +0 -0
  41. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/parsing.py +0 -0
  42. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/qwen3.py +0 -0
  43. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/qwen35.py +0 -0
  44. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/qwen36.py +0 -0
  45. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/renderers/qwen3_vl.py +0 -0
  46. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_bridge.py +0 -0
  47. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_build_helpers.py +0 -0
  48. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_client.py +0 -0
  49. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_deepseek_r1.py +0 -0
  50. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_gpt_oss_harmony_parity.py +0 -0
  51. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_incremental.py +0 -0
  52. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_is_content.py +0 -0
  53. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_kimi_k25_tool_schema.py +0 -0
  54. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_llama_3.py +0 -0
  55. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_load_tokenizer.py +0 -0
  56. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_load_tokenizer_fastokens.py +0 -0
  57. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_message_indices.py +0 -0
  58. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_message_tool_names.py +0 -0
  59. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_multimodal.py +0 -0
  60. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_parse_response.py +0 -0
  61. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_parse_response_robustness.py +0 -0
  62. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_parsers.py +0 -0
  63. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_preserve_thinking.py +0 -0
  64. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_qwen35_size_coverage.py +0 -0
  65. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_render_ids.py +0 -0
  66. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_renderer_config.py +0 -0
  67. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_roundtrip.py +0 -0
  68. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_sampled_mask.py +0 -0
  69. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_tokens_per_message.py +0 -0
  70. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/tests/test_tool_arg_type_preservation.py +0 -0
  71. {renderers-0.1.8.dev43 → renderers-0.1.8.dev44}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: renderers
3
- Version: 0.1.8.dev43
3
+ Version: 0.1.8.dev44
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
@@ -57,7 +57,7 @@ next_prompt_ids = r.bridge_to_next_turn(
57
57
  )
58
58
  ```
59
59
 
60
- Hand-coded renderers ship for `qwen3`, `qwen3-vl`, `qwen3.5`, `qwen3.6`, `glm-5`, `glm-5.1`, `glm-4.5`, `minimax-m2`, `deepseek-v3`, `kimi-k2`, `kimi-k2.5`, `nemotron-3`, `gpt-oss`. Anything else falls back to `DefaultRenderer`, a generic `apply_chat_template` wrapper.
60
+ Hand-coded renderers ship for `qwen3`, `qwen3-vl`, `qwen3.5`, `qwen3.6`, `glm-5`, `glm-5.1`, `glm-4.5`, `minimax-m2`, `deepseek-v3`, `kimi-k2`, `kimi-k2.5`, `nemotron-3`, `nemotron-3-ultra`, `gpt-oss`. Anything else falls back to `DefaultRenderer`, a generic `apply_chat_template` wrapper.
61
61
 
62
62
  ## API
63
63
 
@@ -40,7 +40,7 @@ next_prompt_ids = r.bridge_to_next_turn(
40
40
  )
41
41
  ```
42
42
 
43
- Hand-coded renderers ship for `qwen3`, `qwen3-vl`, `qwen3.5`, `qwen3.6`, `glm-5`, `glm-5.1`, `glm-4.5`, `minimax-m2`, `deepseek-v3`, `kimi-k2`, `kimi-k2.5`, `nemotron-3`, `gpt-oss`. Anything else falls back to `DefaultRenderer`, a generic `apply_chat_template` wrapper.
43
+ Hand-coded renderers ship for `qwen3`, `qwen3-vl`, `qwen3.5`, `qwen3.6`, `glm-5`, `glm-5.1`, `glm-4.5`, `minimax-m2`, `deepseek-v3`, `kimi-k2`, `kimi-k2.5`, `nemotron-3`, `nemotron-3-ultra`, `gpt-oss`. Anything else falls back to `DefaultRenderer`, a generic `apply_chat_template` wrapper.
44
44
 
45
45
  ## API
46
46
 
@@ -56,6 +56,7 @@ from renderers.configs import (
56
56
  Llama3RendererConfig,
57
57
  MiniMaxM2RendererConfig,
58
58
  Nemotron3RendererConfig,
59
+ Nemotron3UltraRendererConfig,
59
60
  Qwen35RendererConfig,
60
61
  Qwen36RendererConfig,
61
62
  Qwen3RendererConfig,
@@ -88,6 +89,7 @@ _LAZY_RENDERERS: dict[str, str] = {
88
89
  "Llama3Renderer": "renderers.llama_3",
89
90
  "MiniMaxM2Renderer": "renderers.minimax_m2",
90
91
  "Nemotron3Renderer": "renderers.nemotron3",
92
+ "Nemotron3UltraRenderer": "renderers.nemotron3",
91
93
  "Qwen35Renderer": "renderers.qwen35",
92
94
  "Qwen36Renderer": "renderers.qwen36",
93
95
  "Qwen3Renderer": "renderers.qwen3",
@@ -146,6 +148,8 @@ __all__ = [
146
148
  "MultimodalRenderer",
147
149
  "Nemotron3Renderer",
148
150
  "Nemotron3RendererConfig",
151
+ "Nemotron3UltraRenderer",
152
+ "Nemotron3UltraRendererConfig",
149
153
  "OverlongPromptError",
150
154
  "ParsedResponse",
151
155
  "ParsedToolCall",
@@ -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.dev43'
22
- __version_tuple__ = version_tuple = (0, 1, 8, 'dev43')
21
+ __version__ = version = '0.1.8.dev44'
22
+ __version_tuple__ = version_tuple = (0, 1, 8, 'dev44')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1040,14 +1040,15 @@ MODEL_RENDERER_MAP: dict[str, str] = {
1040
1040
  "moonshotai/Kimi-K2-Instruct": "kimi-k2",
1041
1041
  "moonshotai/Kimi-K2.5": "kimi-k2.5",
1042
1042
  "moonshotai/Kimi-K2.6": "kimi-k2.5",
1043
- # Nemotron 3. Nano / Super share one chat-template variant; the Ultra
1044
- # checkpoints use the Ultra variant — the renderer auto-selects it from
1045
- # the model name (see ``nemotron3._ULTRA_DEFAULTS``). BF16 and FP8 share the
1043
+ # Nemotron 3. Nano / Super share one chat-template variant (``nemotron-3``);
1044
+ # the Ultra checkpoints use the Ultra variant (``nemotron-3-ultra``, distinct
1045
+ # ``</think>`` glue). Both route to the same Nemotron3Renderer, which selects
1046
+ # the variant from the resolved config's ``name``. BF16 and FP8 share the
1046
1047
  # same tokenizer and template.
1047
1048
  "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16": "nemotron-3",
1048
1049
  "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-BF16": "nemotron-3",
1049
- "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16": "nemotron-3",
1050
- "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-FP8": "nemotron-3",
1050
+ "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16": "nemotron-3-ultra",
1051
+ "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-FP8": "nemotron-3-ultra",
1051
1052
  # Llama 3.2 (Instruct). Tested against the gated meta-llama repos and
1052
1053
  # the unrestricted unsloth/... mirror, which ships a byte-identical
1053
1054
  # chat template. ``Llama3Renderer`` defaults ``date_string`` to
@@ -1350,7 +1351,7 @@ def _populate_registry():
1350
1351
  from renderers.laguna_xs2 import LagunaXS2Renderer
1351
1352
  from renderers.llama_3 import Llama3Renderer
1352
1353
  from renderers.minimax_m2 import MiniMaxM2Renderer
1353
- from renderers.nemotron3 import Nemotron3Renderer
1354
+ from renderers.nemotron3 import Nemotron3Renderer, Nemotron3UltraRenderer
1354
1355
  from renderers.qwen3 import Qwen3Renderer
1355
1356
  from renderers.qwen3_vl import Qwen3VLRenderer
1356
1357
  from renderers.qwen35 import Qwen35Renderer
@@ -1374,6 +1375,7 @@ def _populate_registry():
1374
1375
  "laguna-xs.2": LagunaXS2Renderer,
1375
1376
  "llama-3": Llama3Renderer,
1376
1377
  "nemotron-3": Nemotron3Renderer,
1378
+ "nemotron-3-ultra": Nemotron3UltraRenderer,
1377
1379
  "gpt-oss": GptOssRenderer,
1378
1380
  }
1379
1381
  )
@@ -354,7 +354,14 @@ class MiniMaxM2RendererConfig(BaseRendererConfig):
354
354
 
355
355
 
356
356
  class Nemotron3RendererConfig(BaseRendererConfig):
357
- """Nemotron 3 renderer config."""
357
+ """Nemotron-3 **Nano / Super** renderer config.
358
+
359
+ Nano and Super share one chat-template variant; the renderer routes both
360
+ through :class:`renderers.nemotron3.Nemotron3Renderer`. The Ultra variant
361
+ has its own template (different reasoning-block glue) and config —
362
+ :class:`Nemotron3UltraRendererConfig` — and is reached via the
363
+ ``nemotron-3-ultra`` discriminator.
364
+ """
358
365
 
359
366
  name: Literal["nemotron-3"] = "nemotron-3"
360
367
 
@@ -362,26 +369,6 @@ class Nemotron3RendererConfig(BaseRendererConfig):
362
369
  """When ``True``, the generation prompt includes ``<think>``. Mirrors
363
370
  the chat template's ``enable_thinking`` kwarg."""
364
371
 
365
- ultra: bool | None = None
366
- """Select the Nemotron-3 **Ultra** chat-template variant.
367
-
368
- ``None`` (default) auto-detects from the model name (see
369
- ``renderers.nemotron3._ULTRA_DEFAULTS``): the Ultra checkpoints resolve
370
- to ``True``; Nano / Super and unknown checkpoints to ``False``. Set
371
- explicitly to force a variant — e.g. an Ultra fine-tune or a
372
- locally-pathed checkpoint whose ``name_or_path`` isn't in the table.
373
-
374
- Ultra's template differs from Nano/Super: the reasoning block is glued
375
- as ``<think>\\n{reasoning}</think>{content}`` (no ``\\n`` around
376
- ``</think>``), truncated historical turns collapse to
377
- ``<think></think>{content}`` (no ``\\n``), and the thinking-truncation
378
- boundary follows the template's ``loop.index0 < last_user_idx`` rule
379
- (drop thinking on every assistant turn before the last user message).
380
-
381
- Not a chat-template kwarg — it picks which template the renderer
382
- mirrors, not a variable passed into one — so it's listed in
383
- ``_internal_fields`` and excluded from ``template_field_names()``."""
384
-
385
372
  truncate_history_thinking: bool = True
386
373
  """When ``False``, keep ``<think>{reasoning}</think>`` on past-cycle
387
374
  assistant turns instead of dropping them. Mirrors the chat
@@ -389,14 +376,37 @@ class Nemotron3RendererConfig(BaseRendererConfig):
389
376
  ``preserve_all_thinking`` / ``preserve_thinking_between_tool_calls``
390
377
  — see :class:`BaseRendererConfig` for the contract."""
391
378
 
392
- # ``ultra`` is a template-variant SELECTOR — it picks which template the
393
- # renderer mirrors (Ultra vs Nano/Super), not a variable passed into one;
394
- # there is no ``ultra`` Jinja variable. Marked internal so the parity
395
- # matrix doesn't cross it as a template field. Same ``_internal_fields``
396
- # mechanism DeepSeek-V3 uses for its no-op ``enable_thinking``, for a
397
- # different underlying reason (theirs is an ignored kwarg, this is a
398
- # variant switch).
399
- _internal_fields = frozenset({"ultra"})
379
+ low_effort: bool = False
380
+ """When ``True``, append ``\\n\\n{reasoning effort: low}`` to the last user
381
+ message, nudging the model toward shorter reasoning. Mirrors the **Super**
382
+ chat template's ``low_effort`` kwarg. A no-op on **Nano** (its template
383
+ doesn't define it) exactly as ``apply_chat_template`` ignores an undefined
384
+ template variable; the renderer distinguishes the two by model name (see
385
+ ``renderers.nemotron3._is_super``)."""
386
+
387
+
388
+ class Nemotron3UltraRendererConfig(BaseRendererConfig):
389
+ """Nemotron-3 **Ultra** renderer config — distinct discriminator so the
390
+ registry routes Ultra checkpoints to the Ultra template variant.
391
+
392
+ Ultra's template differs from Nano/Super: the reasoning block is glued as
393
+ ``<think>\\n{reasoning}</think>{content}`` (no ``\\n`` around ``</think>``)
394
+ and truncated historical turns collapse to ``<think></think>{content}``
395
+ (no ``\\n``). It shares the :class:`renderers.nemotron3.Nemotron3Renderer`
396
+ implementation, which selects the variant from ``config.name``.
397
+ """
398
+
399
+ name: Literal["nemotron-3-ultra"] = "nemotron-3-ultra"
400
+
401
+ enable_thinking: bool = True
402
+ """See :class:`Nemotron3RendererConfig.enable_thinking`."""
403
+
404
+ truncate_history_thinking: bool = True
405
+ """See :class:`Nemotron3RendererConfig.truncate_history_thinking`."""
406
+
407
+ medium_effort: bool = False
408
+ """When ``True``, append ``\\n\\n{reasoning effort: efficient}`` to the last
409
+ user message. Mirrors the Ultra chat template's ``medium_effort`` kwarg."""
400
410
 
401
411
 
402
412
  class DeepSeekV3RendererConfig(BaseRendererConfig):
@@ -444,6 +454,7 @@ RendererConfig = Annotated[
444
454
  Llama3RendererConfig,
445
455
  MiniMaxM2RendererConfig,
446
456
  Nemotron3RendererConfig,
457
+ Nemotron3UltraRendererConfig,
447
458
  DeepSeekV3RendererConfig,
448
459
  DeepSeekR1RendererConfig,
449
460
  ],
@@ -480,6 +491,7 @@ _CONFIG_BY_NAME: dict[str, type[BaseRendererConfig]] = {
480
491
  "llama-3": Llama3RendererConfig,
481
492
  "minimax-m2": MiniMaxM2RendererConfig,
482
493
  "nemotron-3": Nemotron3RendererConfig,
494
+ "nemotron-3-ultra": Nemotron3UltraRendererConfig,
483
495
  "deepseek-v3": DeepSeekV3RendererConfig,
484
496
  "deepseek-r1": DeepSeekR1RendererConfig,
485
497
  }
@@ -525,6 +537,7 @@ __all__ = [
525
537
  "Llama3RendererConfig",
526
538
  "MiniMaxM2RendererConfig",
527
539
  "Nemotron3RendererConfig",
540
+ "Nemotron3UltraRendererConfig",
528
541
  "Qwen35RendererConfig",
529
542
  "Qwen36RendererConfig",
530
543
  "Qwen3RendererConfig",