renderers 0.1.12.dev20__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.
Files changed (96) hide show
  1. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/PKG-INFO +1 -1
  2. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/_version.py +2 -2
  3. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/client.py +21 -1
  4. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_client.py +27 -0
  5. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/.github/workflows/publish-dev.yml +0 -0
  6. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/.github/workflows/publish.yml +0 -0
  7. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/.github/workflows/style.yml +0 -0
  8. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/.github/workflows/test.yml +0 -0
  9. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/.gitignore +0 -0
  10. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/.pre-commit-config.yaml +0 -0
  11. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/LICENSE +0 -0
  12. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/README.md +0 -0
  13. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/docs/renderer-config.md +0 -0
  14. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/examples/README.md +0 -0
  15. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/examples/sglang/multiturn_generate_sglang.py +0 -0
  16. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/examples/sglang/online_multiturn_sglang.py +0 -0
  17. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/examples/tinker/multiturn_generate_tinker.py +0 -0
  18. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/examples/transformers/multiturn_generate_transformers.py +0 -0
  19. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/examples/vllm/multiturn_generate_vllm.py +0 -0
  20. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/pyproject.toml +0 -0
  21. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/__init__.py +0 -0
  22. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/base.py +0 -0
  23. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/configs.py +0 -0
  24. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/custom.py +0 -0
  25. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/deepseek_r1.py +0 -0
  26. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/deepseek_v3.py +0 -0
  27. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/deepseek_v4.py +0 -0
  28. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/default.py +0 -0
  29. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/gemma4.py +0 -0
  30. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/glm45.py +0 -0
  31. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/glm5.py +0 -0
  32. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/gpt_oss.py +0 -0
  33. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/hy3.py +0 -0
  34. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/inkling.py +0 -0
  35. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/kimi_k2.py +0 -0
  36. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/kimi_k25.py +0 -0
  37. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/laguna_s21.py +0 -0
  38. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/laguna_xs2.py +0 -0
  39. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/llama_3.py +0 -0
  40. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/minimax_m2.py +0 -0
  41. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/nemotron3.py +0 -0
  42. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/parsers.py +0 -0
  43. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/parsing.py +0 -0
  44. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/prime_qwen3.py +0 -0
  45. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/qwen3.py +0 -0
  46. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/qwen35.py +0 -0
  47. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/qwen36.py +0 -0
  48. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/qwen38.py +0 -0
  49. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/qwen3_vl.py +0 -0
  50. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/reasoning.py +0 -0
  51. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/renderers/tagged.py +0 -0
  52. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/audit_prefix_stability.py +0 -0
  53. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/conftest.py +0 -0
  54. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/fixtures/prefix_stability.json +0 -0
  55. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/parity.py +0 -0
  56. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/reference_continuations.py +0 -0
  57. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/reference_rendering.py +0 -0
  58. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/replay.py +0 -0
  59. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_bridge.py +0 -0
  60. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_build_helpers.py +0 -0
  61. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_custom.py +0 -0
  62. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_deepseek_r1.py +0 -0
  63. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_deepseek_v4.py +0 -0
  64. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_disabled_thinking_stability.py +0 -0
  65. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_gemma4.py +0 -0
  66. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_glm_tool_name_validation.py +0 -0
  67. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_hy3.py +0 -0
  68. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_incremental.py +0 -0
  69. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_inkling.py +0 -0
  70. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_is_content.py +0 -0
  71. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_kimi_k25_tool_schema.py +0 -0
  72. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_laguna_m1.py +0 -0
  73. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_laguna_xs21.py +0 -0
  74. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_llama_3.py +0 -0
  75. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_load_tokenizer.py +0 -0
  76. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_message_indices.py +0 -0
  77. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_message_tool_names.py +0 -0
  78. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_multimodal.py +0 -0
  79. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_nemotron35_vlm.py +0 -0
  80. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_nemotron3_ultra.py +0 -0
  81. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_offsetless_tokenizers.py +0 -0
  82. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_parity.py +0 -0
  83. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_parse_response.py +0 -0
  84. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_parse_response_robustness.py +0 -0
  85. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_parsers.py +0 -0
  86. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_preserve_thinking.py +0 -0
  87. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_qwen35_size_coverage.py +0 -0
  88. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_qwen38.py +0 -0
  89. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_reasoning_boundaries.py +0 -0
  90. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_renderer_config.py +0 -0
  91. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_roundtrip.py +0 -0
  92. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_sampled_mask.py +0 -0
  93. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_tagged_rollout.py +0 -0
  94. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_tokens_per_message.py +0 -0
  95. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/tests/test_tool_arg_type_preservation.py +0 -0
  96. {renderers-0.1.12.dev20 → renderers-0.1.13.dev4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: renderers
3
- Version: 0.1.12.dev20
3
+ Version: 0.1.13.dev4
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
@@ -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.dev20'
22
- __version_tuple__ = version_tuple = (0, 1, 12, 'dev20')
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
@@ -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",...} —
@@ -336,6 +336,33 @@ def test_generate_preserves_zero_completion_logprob():
336
336
  assert result["completion_logprobs"] == [0.0, -0.2]
337
337
 
338
338
 
339
+ def test_generate_reads_packed_completion_logprobs():
340
+ client = _FakeClient()
341
+ client.choice.pop("logprobs")
342
+ values = np.array([-0.1, 0.0], dtype=np.float32)
343
+ client.choice["completion_logprobs"] = {
344
+ "data": base64.b64encode(values.tobytes()).decode(),
345
+ "shape": [2],
346
+ "dtype": "float32",
347
+ }
348
+
349
+ result = _run_generate(client)
350
+
351
+ assert result["completion_logprobs"] == values.tolist()
352
+
353
+ client.choice["completion_logprobs"]["data"] = base64.b64encode(
354
+ np.array([-0.1, -9999.0], dtype=np.float32).tobytes()
355
+ ).decode()
356
+ with pytest.raises(MalformedGenerateResponseError, match="missing"):
357
+ _run_generate(client)
358
+
359
+ client.choice["completion_logprobs"]["data"] = base64.b64encode(
360
+ np.array([-0.1, np.inf], dtype=np.float32).tobytes()
361
+ ).decode()
362
+ with pytest.raises(MalformedGenerateResponseError, match="non-finite"):
363
+ _run_generate(client)
364
+
365
+
339
366
  class _MalformedToolRenderer(_FakeRenderer):
340
367
  """Returns only a malformed tool-call attempt — finish_reason must stay "stop"."""
341
368