renderers 0.1.12.dev8__tar.gz → 0.1.12.dev9__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.
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/PKG-INFO +1 -1
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/_version.py +2 -2
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/qwen3.py +18 -7
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_bridge.py +18 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/.github/workflows/publish-dev.yml +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/.github/workflows/publish.yml +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/.github/workflows/style.yml +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/.github/workflows/test.yml +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/.gitignore +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/.pre-commit-config.yaml +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/LICENSE +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/README.md +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/docs/renderer-config.md +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/README.md +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/sglang/multiturn_generate_sglang.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/sglang/online_multiturn_sglang.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/tinker/multiturn_generate_tinker.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/transformers/multiturn_generate_transformers.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/vllm/multiturn_generate_vllm.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/pyproject.toml +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/__init__.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/base.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/client.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/configs.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/deepseek_r1.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/deepseek_v3.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/deepseek_v4.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/default.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/gemma4.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/glm45.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/glm5.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/gpt_oss.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/hy3.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/inkling.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/kimi_k2.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/kimi_k25.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/laguna_s21.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/laguna_xs2.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/llama_3.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/minimax_m2.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/nemotron3.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/parsers.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/parsing.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/prime_qwen3.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/qwen35.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/qwen36.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/qwen38.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/qwen3_vl.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/renderers/reasoning.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/conftest.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/parity.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/reference_rendering.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_build_helpers.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_client.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_deepseek_r1.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_deepseek_v4.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_disabled_thinking_stability.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_gemma4.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_glm_tool_name_validation.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_hy3.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_incremental.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_inkling.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_is_content.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_kimi_k25_tool_schema.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_laguna_m1.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_laguna_xs21.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_llama_3.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_load_tokenizer.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_message_indices.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_message_tool_names.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_multimodal.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_nemotron35_vlm.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_nemotron3_ultra.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_offsetless_tokenizers.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_parity.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_parse_response.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_parse_response_robustness.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_parsers.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_preserve_thinking.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_qwen35_size_coverage.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_qwen38.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_reasoning_boundaries.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_renderer_config.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_roundtrip.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_sampled_mask.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_tokens_per_message.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/tests/test_tool_arg_type_preservation.py +0 -0
- {renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/uv.lock +0 -0
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1, 12, '
|
|
21
|
+
__version__ = version = '0.1.12.dev9'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 12, 'dev9')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -93,9 +93,16 @@ class Qwen3Renderer:
|
|
|
93
93
|
return self._tokenizer.encode(text, add_special_tokens=False)
|
|
94
94
|
|
|
95
95
|
@staticmethod
|
|
96
|
-
def
|
|
96
|
+
def _content_text(content) -> str:
|
|
97
|
+
"""Return the text parts of a message in a renderer-safe form.
|
|
98
|
+
|
|
99
|
+
Qwen3's native template is text-only, but text-only messages can also
|
|
100
|
+
use OpenAI-style content lists: ``[{"type": "text", "text": ...}]``.
|
|
101
|
+
Treat both representations identically instead of silently dropping
|
|
102
|
+
the message body.
|
|
103
|
+
"""
|
|
97
104
|
if isinstance(content, str):
|
|
98
|
-
return content
|
|
105
|
+
return content
|
|
99
106
|
if isinstance(content, list):
|
|
100
107
|
parts: list[str] = []
|
|
101
108
|
for item in content:
|
|
@@ -103,9 +110,13 @@ class Qwen3Renderer:
|
|
|
103
110
|
parts.append(item)
|
|
104
111
|
elif isinstance(item, dict) and isinstance(item.get("text"), str):
|
|
105
112
|
parts.append(item["text"])
|
|
106
|
-
return "".join(parts)
|
|
113
|
+
return "".join(parts)
|
|
107
114
|
return ""
|
|
108
115
|
|
|
116
|
+
@staticmethod
|
|
117
|
+
def _query_boundary_text(content) -> str:
|
|
118
|
+
return Qwen3Renderer._content_text(content).strip()
|
|
119
|
+
|
|
109
120
|
@staticmethod
|
|
110
121
|
def _is_user_query_message(msg: Message) -> bool:
|
|
111
122
|
if msg.get("role") != "user":
|
|
@@ -186,7 +197,7 @@ class Qwen3Renderer:
|
|
|
186
197
|
# JSON as message body.
|
|
187
198
|
segments: list[tuple[str, bool]] = [("system\n", False)]
|
|
188
199
|
if first_is_system:
|
|
189
|
-
sys_content = messages[0].get("content")
|
|
200
|
+
sys_content = self._content_text(messages[0].get("content"))
|
|
190
201
|
if sys_content:
|
|
191
202
|
segments.append((sys_content, True))
|
|
192
203
|
segments.append(("\n\n", False))
|
|
@@ -199,7 +210,7 @@ class Qwen3Renderer:
|
|
|
199
210
|
emit_text("\n", sys_idx, is_sampled=False, is_content=False)
|
|
200
211
|
elif first_is_system:
|
|
201
212
|
emit_special(self._im_start, 0, is_sampled=False, is_content=False)
|
|
202
|
-
sys_content = messages[0].get("content")
|
|
213
|
+
sys_content = self._content_text(messages[0].get("content"))
|
|
203
214
|
sys_segments: list[tuple[str, bool]] = [("system\n", False)]
|
|
204
215
|
if sys_content:
|
|
205
216
|
sys_segments.append((sys_content, True))
|
|
@@ -214,7 +225,7 @@ class Qwen3Renderer:
|
|
|
214
225
|
num_messages = len(messages)
|
|
215
226
|
for i, msg in enumerate(messages):
|
|
216
227
|
role = msg["role"]
|
|
217
|
-
content =
|
|
228
|
+
content = self._content_text(msg.get("content"))
|
|
218
229
|
|
|
219
230
|
if role == "system":
|
|
220
231
|
if i == 0:
|
|
@@ -415,7 +426,7 @@ class Qwen3Renderer:
|
|
|
415
426
|
|
|
416
427
|
for i, msg in enumerate(new_messages):
|
|
417
428
|
role = msg.get("role")
|
|
418
|
-
content =
|
|
429
|
+
content = self._content_text(msg.get("content"))
|
|
419
430
|
if role == "user":
|
|
420
431
|
emit_special(self._im_start, i)
|
|
421
432
|
user_segments: list[tuple[str, bool]] = [("user\n", False)]
|
|
@@ -205,6 +205,24 @@ def test_bridge_extension_includes_new_message_text(
|
|
|
205
205
|
)
|
|
206
206
|
|
|
207
207
|
|
|
208
|
+
def test_qwen3_renders_openai_text_content_parts(br_renderer, br_tokenizer, br_model):
|
|
209
|
+
"""Text content lists must not become an empty user turn."""
|
|
210
|
+
if br_model not in {"Qwen/Qwen3-8B", "Qwen/Qwen3-4B"}:
|
|
211
|
+
pytest.skip(f"{br_model}: not a Qwen3 text renderer")
|
|
212
|
+
|
|
213
|
+
text = "CONTENT_LIST_SENTINEL_XYZ"
|
|
214
|
+
string_ids = br_renderer.render_ids(
|
|
215
|
+
[{"role": "user", "content": text}], add_generation_prompt=True
|
|
216
|
+
)
|
|
217
|
+
list_ids = br_renderer.render_ids(
|
|
218
|
+
[{"role": "user", "content": [{"type": "text", "text": text}]}],
|
|
219
|
+
add_generation_prompt=True,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
assert list_ids == string_ids
|
|
223
|
+
assert text in br_tokenizer.decode(list_ids, skip_special_tokens=False)
|
|
224
|
+
|
|
225
|
+
|
|
208
226
|
def test_bridge_declines_across_user_query_when_template_drops_thinking():
|
|
209
227
|
"""Qwen3's template drops a past block's thinking once a new user turn
|
|
210
228
|
arrives. The resolved ``tool_cycle`` bridge policy therefore treats a
|
|
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
|
{renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/sglang/multiturn_generate_sglang.py
RENAMED
|
File without changes
|
|
File without changes
|
{renderers-0.1.12.dev8 → renderers-0.1.12.dev9}/examples/tinker/multiturn_generate_tinker.py
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|