renderers 0.1.10.dev15__tar.gz → 0.1.11.dev2__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 (85) hide show
  1. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/PKG-INFO +29 -17
  2. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/README.md +23 -15
  3. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/docs/renderer-config.md +2 -7
  4. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/pyproject.toml +21 -5
  5. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/__init__.py +11 -15
  6. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/_version.py +2 -2
  7. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/base.py +85 -181
  8. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/client.py +10 -36
  9. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/deepseek_v3.py +2 -3
  10. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/default.py +2 -3
  11. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/gemma4.py +5 -6
  12. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/glm45.py +2 -3
  13. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/glm5.py +2 -3
  14. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/gpt_oss.py +2 -3
  15. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/hy3.py +2 -3
  16. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/inkling.py +5 -6
  17. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/kimi_k2.py +2 -3
  18. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/kimi_k25.py +9 -9
  19. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/laguna_s21.py +2 -3
  20. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/laguna_xs2.py +4 -5
  21. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/llama_3.py +2 -3
  22. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/minimax_m2.py +2 -3
  23. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/nemotron3.py +2 -3
  24. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/prime_qwen3.py +3 -4
  25. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/qwen3.py +2 -3
  26. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/qwen35.py +6 -6
  27. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/qwen3_vl.py +5 -6
  28. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/conftest.py +1 -0
  29. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_bridge.py +1 -0
  30. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_client.py +2 -1
  31. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_disabled_thinking_stability.py +4 -0
  32. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_qwen38.py +18 -12
  33. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_renderer_config.py +0 -26
  34. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_renderer_config_parity.py +1 -0
  35. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_roundtrip.py +1 -0
  36. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/uv.lock +14 -1
  37. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/.github/workflows/publish-dev.yml +0 -0
  38. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/.github/workflows/publish.yml +0 -0
  39. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/.github/workflows/style.yml +0 -0
  40. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/.github/workflows/test.yml +0 -0
  41. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/.gitignore +0 -0
  42. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/.pre-commit-config.yaml +0 -0
  43. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/LICENSE +0 -0
  44. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/examples/README.md +0 -0
  45. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/examples/sglang/multiturn_generate_sglang.py +0 -0
  46. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/examples/sglang/online_multiturn_sglang.py +0 -0
  47. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/examples/tinker/multiturn_generate_tinker.py +0 -0
  48. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/examples/transformers/multiturn_generate_transformers.py +0 -0
  49. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/examples/vllm/multiturn_generate_vllm.py +0 -0
  50. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/configs.py +0 -0
  51. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/deepseek_r1.py +0 -0
  52. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/parsers.py +0 -0
  53. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/parsing.py +0 -0
  54. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/qwen36.py +0 -0
  55. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/renderers/qwen38.py +0 -0
  56. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_build_helpers.py +0 -0
  57. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_deepseek_r1.py +0 -0
  58. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_gemma4.py +0 -0
  59. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_glm_tool_name_validation.py +0 -0
  60. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_gpt_oss_harmony_parity.py +0 -0
  61. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_hy3.py +0 -0
  62. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_incremental.py +0 -0
  63. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_inkling.py +0 -0
  64. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_is_content.py +0 -0
  65. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_kimi_k25_tool_schema.py +0 -0
  66. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_laguna_m1.py +0 -0
  67. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_laguna_s21.py +0 -0
  68. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_laguna_xs21.py +0 -0
  69. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_llama_3.py +0 -0
  70. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_load_tokenizer.py +0 -0
  71. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_message_indices.py +0 -0
  72. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_message_tool_names.py +0 -0
  73. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_multimodal.py +0 -0
  74. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_nemotron3_parity.py +0 -0
  75. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_nemotron3_ultra.py +0 -0
  76. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_parse_response.py +0 -0
  77. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_parse_response_robustness.py +0 -0
  78. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_parsers.py +0 -0
  79. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_preserve_thinking.py +0 -0
  80. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_prime_qwen3_parity.py +0 -0
  81. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_qwen35_size_coverage.py +0 -0
  82. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_render_ids.py +0 -0
  83. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_sampled_mask.py +0 -0
  84. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_tokens_per_message.py +0 -0
  85. {renderers-0.1.10.dev15 → renderers-0.1.11.dev2}/tests/test_tool_arg_type_preservation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: renderers
3
- Version: 0.1.10.dev15
3
+ Version: 0.1.11.dev2
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
@@ -11,7 +11,11 @@ Requires-Dist: openai-harmony>=0.0.4
11
11
  Requires-Dist: openai>=1.108.1
12
12
  Requires-Dist: prime-pydantic-config>=0.3.0.dev83
13
13
  Requires-Dist: tiktoken
14
- Requires-Dist: transformers>=4.50.0
14
+ Provides-Extra: multimodal
15
+ Requires-Dist: pillow>=12.2.0; extra == 'multimodal'
16
+ Requires-Dist: transformers>=4.50.0; extra == 'multimodal'
17
+ Provides-Extra: transformers
18
+ Requires-Dist: transformers>=4.50.0; extra == 'transformers'
15
19
  Description-Content-Type: text/markdown
16
20
 
17
21
  # renderers
@@ -26,13 +30,28 @@ Standalone on PyPI, and portable across training and inference stacks (transform
26
30
  uv add renderers
27
31
  ```
28
32
 
33
+ The base install supports text renderers with a bring-your-own tokenizer. Add
34
+ the Hugging Face integration for the tokenizer-loading helpers, or the complete
35
+ media stack for image/audio rendering:
36
+
37
+ ```bash
38
+ uv add 'renderers[transformers]'
39
+ uv add 'renderers[multimodal]'
40
+ ```
41
+
42
+ A BYO tokenizer must expose `encode`, `decode`, `convert_tokens_to_ids`, token
43
+ IDs such as `eos_token_id`, and `return_offsets_mapping=True` through its call
44
+ interface. `DefaultRenderer` additionally requires `apply_chat_template`.
45
+ This includes text-only Inkling training: `InklingRenderer` loads its
46
+ Transformers processor only when image or audio content is actually rendered.
47
+
29
48
  ## At a glance
30
49
 
31
50
  ```python
32
- from transformers import AutoTokenizer
33
51
  from renderers import create_renderer
52
+ from renderers.base import load_tokenizer
34
53
 
35
- tok = AutoTokenizer.from_pretrained("Qwen/Qwen3-8B")
54
+ tok = load_tokenizer("Qwen/Qwen3-8B") # renderers[transformers]
36
55
  r = create_renderer(tok) # → Qwen3Renderer (auto-resolved)
37
56
 
38
57
  prompt_ids = r.render_ids(
@@ -92,17 +111,10 @@ r = create_renderer(tok) # AutoRendererConfig is the implicit def
92
111
 
93
112
  Auto-detect matches `tokenizer.name_or_path` against `MODEL_RENDERER_MAP` by **exact match**. Prefix matching is intentionally off — same architecture can ship different chat templates (base vs instruct, fine-tune renames). Fine-tunes must pass an explicit typed config (e.g. `Qwen3RendererConfig()`). Unknown text-only names fall back to `DefaultRenderer`, unless `AutoRendererConfig(thinking_retention=...)` was set; the default renderer cannot implement that bridge policy.
94
113
 
95
- ### Pools
96
-
97
- ```python
98
- from renderers import create_renderer_pool
99
-
100
- pool = create_renderer_pool("Qwen/Qwen3-8B", size=16)
101
- with pool.checkout() as r:
102
- ids = r.render_ids(messages)
103
- ```
104
-
105
- Each slot owns its own tokenizer copy. Construction fans out across a thread pool so a 32-slot pool doesn't serially eat ~10–15s of `from_pretrained` calls at startup.
114
+ Without the `transformers` extra, exact-match registered models still
115
+ auto-resolve. For an unknown name, renderers cannot safely probe `AutoConfig`
116
+ to distinguish a text model from an unknown VLM; pass an explicit typed config
117
+ such as `DefaultRendererConfig()` for a known text-only model.
106
118
 
107
119
  ## Why use a renderer
108
120
 
@@ -125,7 +137,7 @@ Each break fragments a rollout into multiple training samples — every fragment
125
137
 
126
138
  ## Typed renderer configs
127
139
 
128
- Each renderer accepts a typed pydantic config at construction. Some fields mirror chat-template kwargs; others configure renderer-only behavior such as image caching, parsers, or Harmony preamble construction. `create_renderer` and `create_renderer_pool` take one positional `config` argument and an optional keyword-only `chat_template_kwargs` mapping:
140
+ Each renderer accepts a typed pydantic config at construction. Some fields mirror chat-template kwargs; others configure renderer-only behavior such as image caching, parsers, or Harmony preamble construction. `create_renderer` takes one positional `config` argument and an optional keyword-only `chat_template_kwargs` mapping:
129
141
 
130
142
  ```python
131
143
  from renderers import (
@@ -175,7 +187,7 @@ Fallback for unsupported text-only models. Wraps `apply_chat_template` and accep
175
187
 
176
188
  ## Roadmap
177
189
 
178
- - **VLM expansion.** `ImagePart` support exists for Qwen3-VL, Qwen3.5-family, Gemma 4, and Kimi K2.5 / K2.6 multimodal templates. Remaining work: audio/video support, broader VLM coverage, and more RL validation. Gemma 4 image preprocessing requires a Transformers release that provides `Gemma4Processor`.
190
+ - **VLM expansion.** `ImagePart` support exists for Qwen3-VL, Qwen3.5-family, Gemma 4, and Kimi K2.5 / K2.6 multimodal templates. Install `renderers[multimodal]` for Pillow and the Hugging Face processors. Remaining work: audio/video support, broader VLM coverage, and more RL validation. Gemma 4 image preprocessing requires a Transformers release that provides `Gemma4Processor`.
179
191
  - **Patched chat templates.** Some shipped templates re-tokenize history or normalize JSON in ways that break token identity. Plan: a `use_patched` opt-in per renderer that renders the same surface form while avoiding known-bad patterns. (Auto-stripping thinking from past turns is *not* one of these — that's intended template behaviour the renderer reproduces; use `thinking_retention` to override it.)
180
192
 
181
193
  ## Testing
@@ -10,13 +10,28 @@ Standalone on PyPI, and portable across training and inference stacks (transform
10
10
  uv add renderers
11
11
  ```
12
12
 
13
+ The base install supports text renderers with a bring-your-own tokenizer. Add
14
+ the Hugging Face integration for the tokenizer-loading helpers, or the complete
15
+ media stack for image/audio rendering:
16
+
17
+ ```bash
18
+ uv add 'renderers[transformers]'
19
+ uv add 'renderers[multimodal]'
20
+ ```
21
+
22
+ A BYO tokenizer must expose `encode`, `decode`, `convert_tokens_to_ids`, token
23
+ IDs such as `eos_token_id`, and `return_offsets_mapping=True` through its call
24
+ interface. `DefaultRenderer` additionally requires `apply_chat_template`.
25
+ This includes text-only Inkling training: `InklingRenderer` loads its
26
+ Transformers processor only when image or audio content is actually rendered.
27
+
13
28
  ## At a glance
14
29
 
15
30
  ```python
16
- from transformers import AutoTokenizer
17
31
  from renderers import create_renderer
32
+ from renderers.base import load_tokenizer
18
33
 
19
- tok = AutoTokenizer.from_pretrained("Qwen/Qwen3-8B")
34
+ tok = load_tokenizer("Qwen/Qwen3-8B") # renderers[transformers]
20
35
  r = create_renderer(tok) # → Qwen3Renderer (auto-resolved)
21
36
 
22
37
  prompt_ids = r.render_ids(
@@ -76,17 +91,10 @@ r = create_renderer(tok) # AutoRendererConfig is the implicit def
76
91
 
77
92
  Auto-detect matches `tokenizer.name_or_path` against `MODEL_RENDERER_MAP` by **exact match**. Prefix matching is intentionally off — same architecture can ship different chat templates (base vs instruct, fine-tune renames). Fine-tunes must pass an explicit typed config (e.g. `Qwen3RendererConfig()`). Unknown text-only names fall back to `DefaultRenderer`, unless `AutoRendererConfig(thinking_retention=...)` was set; the default renderer cannot implement that bridge policy.
78
93
 
79
- ### Pools
80
-
81
- ```python
82
- from renderers import create_renderer_pool
83
-
84
- pool = create_renderer_pool("Qwen/Qwen3-8B", size=16)
85
- with pool.checkout() as r:
86
- ids = r.render_ids(messages)
87
- ```
88
-
89
- Each slot owns its own tokenizer copy. Construction fans out across a thread pool so a 32-slot pool doesn't serially eat ~10–15s of `from_pretrained` calls at startup.
94
+ Without the `transformers` extra, exact-match registered models still
95
+ auto-resolve. For an unknown name, renderers cannot safely probe `AutoConfig`
96
+ to distinguish a text model from an unknown VLM; pass an explicit typed config
97
+ such as `DefaultRendererConfig()` for a known text-only model.
90
98
 
91
99
  ## Why use a renderer
92
100
 
@@ -109,7 +117,7 @@ Each break fragments a rollout into multiple training samples — every fragment
109
117
 
110
118
  ## Typed renderer configs
111
119
 
112
- Each renderer accepts a typed pydantic config at construction. Some fields mirror chat-template kwargs; others configure renderer-only behavior such as image caching, parsers, or Harmony preamble construction. `create_renderer` and `create_renderer_pool` take one positional `config` argument and an optional keyword-only `chat_template_kwargs` mapping:
120
+ Each renderer accepts a typed pydantic config at construction. Some fields mirror chat-template kwargs; others configure renderer-only behavior such as image caching, parsers, or Harmony preamble construction. `create_renderer` takes one positional `config` argument and an optional keyword-only `chat_template_kwargs` mapping:
113
121
 
114
122
  ```python
115
123
  from renderers import (
@@ -159,7 +167,7 @@ Fallback for unsupported text-only models. Wraps `apply_chat_template` and accep
159
167
 
160
168
  ## Roadmap
161
169
 
162
- - **VLM expansion.** `ImagePart` support exists for Qwen3-VL, Qwen3.5-family, Gemma 4, and Kimi K2.5 / K2.6 multimodal templates. Remaining work: audio/video support, broader VLM coverage, and more RL validation. Gemma 4 image preprocessing requires a Transformers release that provides `Gemma4Processor`.
170
+ - **VLM expansion.** `ImagePart` support exists for Qwen3-VL, Qwen3.5-family, Gemma 4, and Kimi K2.5 / K2.6 multimodal templates. Install `renderers[multimodal]` for Pillow and the Hugging Face processors. Remaining work: audio/video support, broader VLM coverage, and more RL validation. Gemma 4 image preprocessing requires a Transformers release that provides `Gemma4Processor`.
163
171
  - **Patched chat templates.** Some shipped templates re-tokenize history or normalize JSON in ways that break token identity. Plan: a `use_patched` opt-in per renderer that renders the same surface form while avoiding known-bad patterns. (Auto-stripping thinking from past turns is *not* one of these — that's intended template behaviour the renderer reproduces; use `thinking_retention` to override it.)
164
172
 
165
173
  ## Testing
@@ -1,8 +1,7 @@
1
1
  # Renderer config
2
2
 
3
- `renderers.RendererConfig` is the typed input to `create_renderer` and
4
- `create_renderer_pool`. It pins the renderer choice and its config at
5
- construction time.
3
+ `renderers.RendererConfig` is the typed input to `create_renderer`. It pins the
4
+ renderer choice and its config at construction time.
6
5
 
7
6
  ```python
8
7
  from renderers import create_renderer, Qwen35RendererConfig
@@ -77,10 +76,6 @@ r = create_renderer(
77
76
  tokenizer,
78
77
  chat_template_kwargs={"enable_thinking": False},
79
78
  )
80
- pool = create_renderer_pool(
81
- "Qwen/Qwen3-8B",
82
- chat_template_kwargs={"enable_thinking": False},
83
- )
84
79
  ```
85
80
 
86
81
  Renderers resolves auto configs before applying `chat_template_kwargs`, so the
@@ -19,11 +19,6 @@ dependencies = [
19
19
  "openai>=1.108.1",
20
20
  "tiktoken",
21
21
  "jinja2",
22
- # Keep this floor compatible with prime-rl's transformers pin. Inkling's
23
- # tokenizer and text-only renderer work on older releases; image/audio
24
- # processing fails lazily with an upgrade message when InklingProcessor is
25
- # unavailable (native support starts in transformers 5.14).
26
- "transformers>=4.50.0",
27
22
  # Used by GptOssRenderer to render and parse harmony tokens. Vendoring
28
23
  # OpenAI's reference implementation keeps us byte-identical with vLLM
29
24
  # (which also uses it) and saves us mirroring a 330-line Jinja template.
@@ -42,6 +37,25 @@ dependencies = [
42
37
  "prime-pydantic-config>=0.3.0.dev83",
43
38
  ]
44
39
 
40
+ [project.optional-dependencies]
41
+ # Tokenizer loading uses Hugging Face. Text-only renderers can instead be
42
+ # constructed with an offset-capable BYO tokenizer and do not import this
43
+ # dependency.
44
+ transformers = [
45
+ # Keep this floor compatible with prime-rl's transformers pin. Inkling's
46
+ # tokenizer and text-only renderer work on older releases; image/audio
47
+ # processing fails lazily with an upgrade message when InklingProcessor is
48
+ # unavailable (native support starts in transformers 5.14).
49
+ "transformers>=4.50.0",
50
+ ]
51
+
52
+ # Image/audio renderers also need Pillow to resolve media inputs. Keep this as
53
+ # a separate convenience extra so tokenizer-only users do not pull it in.
54
+ multimodal = [
55
+ "pillow>=12.2.0",
56
+ "transformers>=4.50.0",
57
+ ]
58
+
45
59
  [tool.hatch.version]
46
60
  source = "vcs"
47
61
  # Tags look like ``renderers-v0.1.8`` (prefix matches the publish.yml
@@ -90,6 +104,8 @@ dev = [
90
104
  "torch>=2.11.0",
91
105
  "torchvision>=0.26.0",
92
106
  "ty>=0.0.1a29,<0.0.22",
107
+ # Optional for consumers, but required by tokenizer/parity/VLM tests.
108
+ "transformers>=4.50.0",
93
109
  ]
94
110
 
95
111
  [tool.uv]
@@ -7,6 +7,7 @@ except ImportError:
7
7
  __version__ = "0+unknown"
8
8
 
9
9
  from renderers.base import (
10
+ ChatTemplateTokenizer,
10
11
  Content,
11
12
  ContentPart,
12
13
  ImagePart,
@@ -21,9 +22,9 @@ from renderers.base import (
21
22
  RenderedTokens,
22
23
  RenderedTrainingSample,
23
24
  Renderer,
24
- RendererPool,
25
25
  TextPart,
26
26
  ThinkingPart,
27
+ Tokenizer,
27
28
  ToolCall,
28
29
  ToolCallFunction,
29
30
  ToolCallParseStatus,
@@ -33,7 +34,6 @@ from renderers.base import (
33
34
  build_training_sample,
34
35
  build_trajectory_step,
35
36
  create_renderer,
36
- create_renderer_pool,
37
37
  extract_message_tool_names,
38
38
  is_multimodal,
39
39
  reject_assistant_in_extension,
@@ -74,17 +74,13 @@ from renderers.configs import (
74
74
  RendererConfig,
75
75
  )
76
76
 
77
- # Concrete renderer classes are lazy-loaded so that consumers needing
78
- # only the config layer (``RendererConfig`` discriminated union) don't
79
- # pay the ``transformers`` import cost. Each renderer module does
80
- # ``from transformers.tokenization_utils import PreTrainedTokenizer``
81
- # at module level, so eager imports here would drag ``transformers``
82
- # into every downstream ``import renderers``. ``__getattr__`` (PEP 562)
83
- # resolves the names on first attribute access, so ``from renderers
84
- # import DefaultRenderer`` and ``renderers.DefaultRenderer`` both work
85
- # transparently. ``create_renderer`` doesn't depend on these eager
86
- # imports — ``renderers.base._populate_registry`` lazy-imports the
87
- # concrete classes itself when a renderer is instantiated.
77
+ # Concrete renderer classes are lazy-loaded so that consumers needing only the
78
+ # config layer (``RendererConfig`` discriminated union) don't import every
79
+ # renderer module. Renderer tokenizer annotations use the local ``Tokenizer``
80
+ # protocols, so resolving a text renderer remains safe when the optional
81
+ # ``transformers`` dependency is absent. ``__getattr__`` (PEP 562) resolves the
82
+ # names on first attribute access, while ``renderers.base._populate_registry``
83
+ # handles lazy registration for ``create_renderer``.
88
84
  _LAZY_RENDERERS: dict[str, str] = {
89
85
  "DeepSeekR1Renderer": "renderers.deepseek_r1",
90
86
  "DeepSeekV3Renderer": "renderers.deepseek_v3",
@@ -134,6 +130,7 @@ def __dir__() -> list[str]:
134
130
  __all__ = [
135
131
  "AutoRendererConfig",
136
132
  "BaseRendererConfig",
133
+ "ChatTemplateTokenizer",
137
134
  "Content",
138
135
  "ContentPart",
139
136
  "DeepSeekR1Renderer",
@@ -205,9 +202,9 @@ __all__ = [
205
202
  "RenderedTrainingSample",
206
203
  "Renderer",
207
204
  "RendererConfig",
208
- "RendererPool",
209
205
  "TextPart",
210
206
  "ThinkingPart",
207
+ "Tokenizer",
211
208
  "ToolCall",
212
209
  "ToolCallFunction",
213
210
  "ToolCallParseStatus",
@@ -219,7 +216,6 @@ __all__ = [
219
216
  "build_trajectory_step",
220
217
  "config_from_name",
221
218
  "create_renderer",
222
- "create_renderer_pool",
223
219
  "extract_message_tool_names",
224
220
  "is_multimodal",
225
221
  "reject_assistant_in_extension",
@@ -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.10.dev15'
22
- __version_tuple__ = version_tuple = (0, 1, 10, 'dev15')
21
+ __version__ = version = '0.1.11.dev2'
22
+ __version_tuple__ = version_tuple = (0, 1, 11, 'dev2')
23
23
 
24
24
  __commit_id__ = commit_id = None