renderers 0.1.12.dev19__tar.gz → 0.1.13.dev4__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.dev19 → renderers-0.1.13.dev4}/PKG-INFO +1 -1
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/_version.py +2 -2
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/base.py +3 -2
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/client.py +21 -1
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/deepseek_v4.py +13 -18
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/glm45.py +5 -18
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/glm5.py +4 -17
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/parsing.py +183 -298
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/reasoning.py +18 -7
- renderers-0.1.13.dev4/renderers/tagged.py +192 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/conftest.py +12 -0
- renderers-0.1.13.dev4/tests/reference_continuations.py +164 -0
- renderers-0.1.13.dev4/tests/replay.py +48 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_bridge.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_client.py +27 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_deepseek_r1.py +6 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_deepseek_v4.py +12 -7
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_disabled_thinking_stability.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_gemma4.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_glm_tool_name_validation.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_hy3.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_inkling.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_laguna_m1.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_laguna_xs21.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_multimodal.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_parity.py +10 -2
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_parse_response.py +11 -3
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_parse_response_robustness.py +4 -5
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_qwen38.py +5 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_reasoning_boundaries.py +26 -8
- renderers-0.1.13.dev4/tests/test_roundtrip.py +211 -0
- renderers-0.1.13.dev4/tests/test_tagged_rollout.py +258 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_tool_arg_type_preservation.py +5 -0
- renderers-0.1.12.dev19/tests/test_roundtrip.py +0 -323
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/.github/workflows/publish-dev.yml +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/.github/workflows/publish.yml +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/.github/workflows/style.yml +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/.github/workflows/test.yml +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/.gitignore +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/.pre-commit-config.yaml +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/LICENSE +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/README.md +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/docs/renderer-config.md +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/examples/README.md +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/examples/sglang/multiturn_generate_sglang.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/examples/sglang/online_multiturn_sglang.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/examples/tinker/multiturn_generate_tinker.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/examples/transformers/multiturn_generate_transformers.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/examples/vllm/multiturn_generate_vllm.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/pyproject.toml +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/__init__.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/configs.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/custom.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/deepseek_r1.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/deepseek_v3.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/default.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/gemma4.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/gpt_oss.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/hy3.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/inkling.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/kimi_k2.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/kimi_k25.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/laguna_s21.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/laguna_xs2.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/llama_3.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/minimax_m2.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/nemotron3.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/parsers.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/prime_qwen3.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/qwen3.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/qwen35.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/qwen36.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/qwen38.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/renderers/qwen3_vl.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/audit_prefix_stability.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/fixtures/prefix_stability.json +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/parity.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/reference_rendering.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_build_helpers.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_custom.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_incremental.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_is_content.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_kimi_k25_tool_schema.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_llama_3.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_load_tokenizer.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_message_indices.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_message_tool_names.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_nemotron35_vlm.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_nemotron3_ultra.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_offsetless_tokenizers.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_parsers.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_preserve_thinking.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_qwen35_size_coverage.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_renderer_config.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_sampled_mask.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/tests/test_tokens_per_message.py +0 -0
- {renderers-0.1.12.dev19 → renderers-0.1.13.dev4}/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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
21
|
+
__version__ = version = '0.1.13.dev4'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 13, 'dev4')
|
|
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 []
|
|
786
|
-
|
|
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
|
|
@@ -7,6 +7,7 @@ messages → Renderer.render_ids() → token IDs → POST /inference/v1/generate
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import asyncio
|
|
10
|
+
import base64
|
|
10
11
|
import json
|
|
11
12
|
import logging
|
|
12
13
|
import math
|
|
@@ -14,6 +15,7 @@ from collections.abc import Mapping
|
|
|
14
15
|
from typing import Any, cast
|
|
15
16
|
|
|
16
17
|
import httpx
|
|
18
|
+
import numpy as np
|
|
17
19
|
from openai import AsyncOpenAI
|
|
18
20
|
|
|
19
21
|
from renderers.base import (
|
|
@@ -134,9 +136,26 @@ def parse_generate_response(raw: bytes) -> dict[str, Any]:
|
|
|
134
136
|
return payload
|
|
135
137
|
|
|
136
138
|
|
|
139
|
+
def _parse_packed_completion_logprobs(
|
|
140
|
+
packed: Mapping[str, Any], completion_ids: list[int]
|
|
141
|
+
) -> list[float]:
|
|
142
|
+
"""prime-rl's packed form: base64 float32 ``{data, shape, dtype}``, one per token."""
|
|
143
|
+
values = np.frombuffer(base64.b64decode(packed["data"]), dtype=packed["dtype"])
|
|
144
|
+
valid = np.isfinite(values) & (values > VLLM_LOGPROB_SENTINEL)
|
|
145
|
+
if len(values) != len(completion_ids) or not valid.all():
|
|
146
|
+
raise MalformedGenerateResponseError(
|
|
147
|
+
f"Engine response choice.completion_logprobs: {len(values)} values for "
|
|
148
|
+
f"{len(completion_ids)} completion tokens, or a non-finite or missing (-9999) logprob."
|
|
149
|
+
)
|
|
150
|
+
return values.astype(np.float64).tolist()
|
|
151
|
+
|
|
152
|
+
|
|
137
153
|
def _parse_completion_logprobs(
|
|
138
154
|
choice: Mapping[str, Any], completion_ids: list[int]
|
|
139
155
|
) -> list[float]:
|
|
156
|
+
packed = choice.get("completion_logprobs")
|
|
157
|
+
if packed is not None:
|
|
158
|
+
return _parse_packed_completion_logprobs(packed, completion_ids)
|
|
140
159
|
raw_logprobs = choice.get("logprobs")
|
|
141
160
|
if not isinstance(raw_logprobs, Mapping):
|
|
142
161
|
raise MalformedGenerateResponseError(
|
|
@@ -376,7 +395,8 @@ async def generate(
|
|
|
376
395
|
|
|
377
396
|
routed_experts = choice.get("routed_experts")
|
|
378
397
|
# vLLM's native kept-set sampling masks (``--return-sampling-mask``):
|
|
379
|
-
# one list of surviving vocab ids per completion token
|
|
398
|
+
# one list of surviving vocab ids per completion token, or (prime-rl's
|
|
399
|
+
# server) packed CSR ``{"ids", "counts"}`` base64 int32 arrays.
|
|
380
400
|
sampling_mask = choice.get("sampling_mask")
|
|
381
401
|
|
|
382
402
|
# /inference/v1/generate returns finish_reason in {"stop","length",...} —
|
|
@@ -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=
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
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 =
|
|
831
|
-
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
326
|
-
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
381
|
-
|
|
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.
|
|
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]
|