renderers 0.1.12.dev17__tar.gz → 0.1.12.dev18__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.dev17 → renderers-0.1.12.dev18}/.github/workflows/test.yml +1 -1
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/PKG-INFO +2 -2
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/examples/sglang/multiturn_generate_sglang.py +1 -1
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/examples/sglang/online_multiturn_sglang.py +1 -1
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/examples/transformers/multiturn_generate_transformers.py +1 -1
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/examples/vllm/multiturn_generate_vllm.py +1 -1
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/pyproject.toml +1 -1
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/_version.py +2 -2
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/base.py +53 -42
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/configs.py +16 -16
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_parsers.py +10 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_renderer_config.py +6 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/uv.lock +5 -288
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/.github/workflows/publish-dev.yml +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/.github/workflows/publish.yml +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/.github/workflows/style.yml +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/.gitignore +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/.pre-commit-config.yaml +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/LICENSE +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/README.md +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/docs/renderer-config.md +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/examples/README.md +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/examples/tinker/multiturn_generate_tinker.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/__init__.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/client.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/custom.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/deepseek_r1.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/deepseek_v3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/deepseek_v4.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/default.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/gemma4.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/glm45.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/glm5.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/gpt_oss.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/hy3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/inkling.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/kimi_k2.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/kimi_k25.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/laguna_s21.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/laguna_xs2.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/llama_3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/minimax_m2.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/nemotron3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/parsers.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/parsing.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/prime_qwen3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/qwen3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/qwen35.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/qwen36.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/qwen38.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/qwen3_vl.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/renderers/reasoning.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/conftest.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/parity.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/reference_rendering.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_bridge.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_build_helpers.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_client.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_custom.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_deepseek_r1.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_deepseek_v4.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_disabled_thinking_stability.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_gemma4.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_glm_tool_name_validation.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_hy3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_incremental.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_inkling.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_is_content.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_kimi_k25_tool_schema.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_laguna_m1.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_laguna_xs21.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_llama_3.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_load_tokenizer.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_message_indices.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_message_tool_names.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_multimodal.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_nemotron35_vlm.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_nemotron3_ultra.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_offsetless_tokenizers.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_parity.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_parse_response.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_parse_response_robustness.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_preserve_thinking.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_qwen35_size_coverage.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_qwen38.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_reasoning_boundaries.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_roundtrip.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_sampled_mask.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_tokens_per_message.py +0 -0
- {renderers-0.1.12.dev17 → renderers-0.1.12.dev18}/tests/test_tool_arg_type_preservation.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: renderers
|
|
3
|
-
Version: 0.1.12.
|
|
3
|
+
Version: 0.1.12.dev18
|
|
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
|
|
7
|
-
Requires-Python: <3.15,>=3.
|
|
7
|
+
Requires-Python: <3.15,>=3.11
|
|
8
8
|
Requires-Dist: jinja2
|
|
9
9
|
Requires-Dist: numpy
|
|
10
10
|
Requires-Dist: openai-harmony>=0.0.4
|
|
@@ -13,7 +13,7 @@ description = "Chat template renderers — deterministic message-to-token conver
|
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
license = "Apache-2.0"
|
|
15
15
|
license-files = ["LICENSE"]
|
|
16
|
-
requires-python = ">=3.
|
|
16
|
+
requires-python = ">=3.11,<3.15"
|
|
17
17
|
dependencies = [
|
|
18
18
|
"numpy",
|
|
19
19
|
"openai>=1.108.1",
|
|
@@ -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.dev18'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 12, 'dev18')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import enum
|
|
4
1
|
import logging
|
|
5
2
|
from collections.abc import Mapping
|
|
6
3
|
from dataclasses import dataclass, field
|
|
4
|
+
from enum import StrEnum
|
|
7
5
|
from typing import (
|
|
8
6
|
TYPE_CHECKING,
|
|
9
7
|
Any,
|
|
10
8
|
Callable,
|
|
11
9
|
Literal,
|
|
12
10
|
Protocol,
|
|
11
|
+
Required,
|
|
13
12
|
TypedDict,
|
|
14
13
|
cast,
|
|
15
14
|
runtime_checkable,
|
|
@@ -110,8 +109,8 @@ class Message(TypedDict, total=False):
|
|
|
110
109
|
Optional keys mirror the OpenAI chat format for tool calling.
|
|
111
110
|
"""
|
|
112
111
|
|
|
113
|
-
role: str
|
|
114
|
-
content: Content
|
|
112
|
+
role: Required[str]
|
|
113
|
+
content: Required[Content]
|
|
115
114
|
tool_calls: list[ToolCall]
|
|
116
115
|
tool_call_id: str
|
|
117
116
|
name: str
|
|
@@ -562,7 +561,7 @@ class RenderedTokens:
|
|
|
562
561
|
return mask
|
|
563
562
|
|
|
564
563
|
|
|
565
|
-
class ToolCallParseStatus(
|
|
564
|
+
class ToolCallParseStatus(StrEnum):
|
|
566
565
|
"""Per-attempt outcome of parsing a single ``<tool_call>`` block.
|
|
567
566
|
|
|
568
567
|
The renderer parser's job is JSON-syntax → ``dict`` (the parser-level
|
|
@@ -1310,15 +1309,19 @@ def load_tokenizer(model_name_or_path: str):
|
|
|
1310
1309
|
the requested Meta ID so auto-resolution still selects ``Llama3Renderer``.
|
|
1311
1310
|
Requires the ``renderers[transformers]`` extra.
|
|
1312
1311
|
"""
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1312
|
+
try:
|
|
1313
|
+
_require_transformers("Loading a tokenizer")
|
|
1314
|
+
load_name_or_path = _tokenizer_source_for(model_name_or_path)
|
|
1315
|
+
kwargs = _tokenizer_load_kwargs(load_name_or_path)
|
|
1316
|
+
tok = _load_tokenizer_via_auto(load_name_or_path, **kwargs)
|
|
1317
|
+
return _preserve_requested_tokenizer_name(
|
|
1318
|
+
tok,
|
|
1319
|
+
requested_name_or_path=model_name_or_path,
|
|
1320
|
+
loaded_name_or_path=load_name_or_path,
|
|
1321
|
+
)
|
|
1322
|
+
except Exception as exc:
|
|
1323
|
+
exc.add_note(f"While loading tokenizer {model_name_or_path!r}.")
|
|
1324
|
+
raise
|
|
1322
1325
|
|
|
1323
1326
|
|
|
1324
1327
|
def _populate_registry():
|
|
@@ -1393,7 +1396,7 @@ def _populate_registry():
|
|
|
1393
1396
|
|
|
1394
1397
|
def create_renderer(
|
|
1395
1398
|
tokenizer,
|
|
1396
|
-
config: RendererConfig | None = None,
|
|
1399
|
+
config: "RendererConfig | None" = None,
|
|
1397
1400
|
*,
|
|
1398
1401
|
chat_template_kwargs: Mapping[str, Any] | None = None,
|
|
1399
1402
|
) -> Renderer:
|
|
@@ -1425,26 +1428,34 @@ def create_renderer(
|
|
|
1425
1428
|
"""
|
|
1426
1429
|
_populate_registry()
|
|
1427
1430
|
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1431
|
+
try:
|
|
1432
|
+
config = _resolve_renderer_config(
|
|
1433
|
+
tokenizer,
|
|
1434
|
+
config,
|
|
1435
|
+
chat_template_kwargs=chat_template_kwargs,
|
|
1436
|
+
)
|
|
1437
|
+
from renderers.configs import CustomRendererConfig
|
|
1438
|
+
from renderers.custom import custom_renderer_config, load_custom_renderer
|
|
1439
|
+
|
|
1440
|
+
if isinstance(config, CustomRendererConfig):
|
|
1441
|
+
renderer_cls = load_custom_renderer(config.import_path)
|
|
1442
|
+
return renderer_cls(tokenizer, custom_renderer_config(config))
|
|
1443
|
+
cls = RENDERER_REGISTRY.get(config.name)
|
|
1444
|
+
if cls is None:
|
|
1445
|
+
raise ValueError(
|
|
1446
|
+
f"Unknown renderer {config.name!r}. Available: {', '.join(sorted(RENDERER_REGISTRY))}"
|
|
1447
|
+
)
|
|
1448
|
+
return cls(tokenizer, config)
|
|
1449
|
+
except Exception as exc:
|
|
1450
|
+
model_name = getattr(tokenizer, "name_or_path", "<unnamed tokenizer>")
|
|
1451
|
+
renderer_name = config.name if config is not None else "auto"
|
|
1452
|
+
exc.add_note(
|
|
1453
|
+
f"While creating renderer {renderer_name!r} for tokenizer {model_name!r}."
|
|
1443
1454
|
)
|
|
1444
|
-
|
|
1455
|
+
raise
|
|
1445
1456
|
|
|
1446
1457
|
|
|
1447
|
-
def template_field_names(config: RendererConfig) -> frozenset[str]:
|
|
1458
|
+
def template_field_names(config: "RendererConfig") -> frozenset[str]:
|
|
1448
1459
|
"""Chat-template kwargs that ``config``'s renderer accepts, custom renderers included."""
|
|
1449
1460
|
from renderers.configs import CustomRendererConfig
|
|
1450
1461
|
from renderers.custom import load_custom_renderer
|
|
@@ -1457,9 +1468,9 @@ def template_field_names(config: RendererConfig) -> frozenset[str]:
|
|
|
1457
1468
|
|
|
1458
1469
|
|
|
1459
1470
|
def merge_chat_template_kwargs(
|
|
1460
|
-
config: RendererConfig,
|
|
1471
|
+
config: "RendererConfig",
|
|
1461
1472
|
chat_template_kwargs: Mapping[str, Any] | None,
|
|
1462
|
-
) -> RendererConfig:
|
|
1473
|
+
) -> "RendererConfig":
|
|
1463
1474
|
"""Return ``config`` with the template kwargs applied, validated against its allowlist."""
|
|
1464
1475
|
if not chat_template_kwargs:
|
|
1465
1476
|
return config
|
|
@@ -1504,10 +1515,10 @@ def merge_chat_template_kwargs(
|
|
|
1504
1515
|
|
|
1505
1516
|
def _resolve_renderer_config(
|
|
1506
1517
|
tokenizer,
|
|
1507
|
-
config: RendererConfig | None,
|
|
1518
|
+
config: "RendererConfig | None",
|
|
1508
1519
|
*,
|
|
1509
1520
|
chat_template_kwargs: Mapping[str, Any] | None = None,
|
|
1510
|
-
) -> RendererConfig:
|
|
1521
|
+
) -> "RendererConfig":
|
|
1511
1522
|
"""Resolve auto/default config and merge chat-template kwargs."""
|
|
1512
1523
|
from renderers.configs import AutoRendererConfig
|
|
1513
1524
|
|
|
@@ -1526,10 +1537,10 @@ def _resolve_renderer_config(
|
|
|
1526
1537
|
|
|
1527
1538
|
def _resolve_auto_config(
|
|
1528
1539
|
tokenizer,
|
|
1529
|
-
auto: AutoRendererConfig,
|
|
1540
|
+
auto: "AutoRendererConfig",
|
|
1530
1541
|
*,
|
|
1531
1542
|
chat_template_kwargs: Mapping[str, Any] | None = None,
|
|
1532
|
-
) -> RendererConfig:
|
|
1543
|
+
) -> "RendererConfig":
|
|
1533
1544
|
"""Map ``AutoRendererConfig`` → concrete typed config via the
|
|
1534
1545
|
tokenizer's ``name_or_path``.
|
|
1535
1546
|
|
|
@@ -2117,8 +2128,8 @@ def introduces_user_query(
|
|
|
2117
2128
|
|
|
2118
2129
|
def resolve_thinking_retention(
|
|
2119
2130
|
config: Any,
|
|
2120
|
-
implied: ResolvedThinkingRetention,
|
|
2121
|
-
) -> ResolvedThinkingRetention:
|
|
2131
|
+
implied: "ResolvedThinkingRetention",
|
|
2132
|
+
) -> "ResolvedThinkingRetention":
|
|
2122
2133
|
"""Resolve the effective bridge policy for a renderer instance.
|
|
2123
2134
|
|
|
2124
2135
|
``config.thinking_retention is None`` means "derive from template knobs";
|
|
@@ -2132,7 +2143,7 @@ def resolve_thinking_retention(
|
|
|
2132
2143
|
|
|
2133
2144
|
|
|
2134
2145
|
def should_rerender_for_thinking_retention(
|
|
2135
|
-
thinking_retention: ResolvedThinkingRetention,
|
|
2146
|
+
thinking_retention: "ResolvedThinkingRetention",
|
|
2136
2147
|
new_messages: list[Message],
|
|
2137
2148
|
*,
|
|
2138
2149
|
is_user_query: Callable[[Message], bool] = _is_user_message,
|
|
@@ -21,7 +21,7 @@ keys its tokenizer's template will honour, so it can't enumerate them.
|
|
|
21
21
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
|
-
from typing import Annotated, ClassVar, Literal, Union
|
|
24
|
+
from typing import Annotated, ClassVar, Literal, Self, Union
|
|
25
25
|
|
|
26
26
|
from pydantic import ConfigDict, Field, model_validator
|
|
27
27
|
from pydantic_config import BaseConfig
|
|
@@ -159,7 +159,7 @@ class DefaultRendererConfig(BaseRendererConfig):
|
|
|
159
159
|
_allow_opaque_template_kwargs = True
|
|
160
160
|
|
|
161
161
|
@model_validator(mode="after")
|
|
162
|
-
def _reject_legacy_preserve_flags(self):
|
|
162
|
+
def _reject_legacy_preserve_flags(self) -> Self:
|
|
163
163
|
# ``extra="allow"`` would otherwise swallow the removed ``preserve_*``
|
|
164
164
|
# bools into ``model_extra`` and forward them to apply_chat_template,
|
|
165
165
|
# silently dropping the user's intent (DefaultRenderer can't
|
|
@@ -261,7 +261,7 @@ class Qwen36RendererConfig(BaseRendererConfig):
|
|
|
261
261
|
_internal_fields = frozenset({"image_cache_max"})
|
|
262
262
|
|
|
263
263
|
@model_validator(mode="after")
|
|
264
|
-
def _check_thinking_retention(self):
|
|
264
|
+
def _check_thinking_retention(self) -> Self:
|
|
265
265
|
_reject_thinking_retention_conflict(
|
|
266
266
|
self,
|
|
267
267
|
"preserve_thinking",
|
|
@@ -307,7 +307,7 @@ class Qwen38RendererConfig(BaseRendererConfig):
|
|
|
307
307
|
_internal_fields = frozenset({"image_cache_max"})
|
|
308
308
|
|
|
309
309
|
@model_validator(mode="after")
|
|
310
|
-
def _check_thinking_retention(self):
|
|
310
|
+
def _check_thinking_retention(self) -> Self:
|
|
311
311
|
_reject_thinking_retention_conflict(
|
|
312
312
|
self,
|
|
313
313
|
"preserve_thinking",
|
|
@@ -350,7 +350,7 @@ class Gemma4RendererConfig(BaseRendererConfig):
|
|
|
350
350
|
_internal_fields = frozenset({"image_cache_max"})
|
|
351
351
|
|
|
352
352
|
@model_validator(mode="after")
|
|
353
|
-
def _check_thinking_retention(self):
|
|
353
|
+
def _check_thinking_retention(self) -> Self:
|
|
354
354
|
_reject_thinking_retention_conflict(
|
|
355
355
|
self,
|
|
356
356
|
"preserve_thinking",
|
|
@@ -377,7 +377,7 @@ class GLM5RendererConfig(BaseRendererConfig):
|
|
|
377
377
|
to ``"all"``."""
|
|
378
378
|
|
|
379
379
|
@model_validator(mode="after")
|
|
380
|
-
def _check_thinking_retention(self):
|
|
380
|
+
def _check_thinking_retention(self) -> Self:
|
|
381
381
|
_reject_thinking_retention_conflict(
|
|
382
382
|
self,
|
|
383
383
|
"clear_thinking",
|
|
@@ -401,7 +401,7 @@ class GLM51RendererConfig(BaseRendererConfig):
|
|
|
401
401
|
"""See :class:`GLM5RendererConfig.clear_thinking`."""
|
|
402
402
|
|
|
403
403
|
@model_validator(mode="after")
|
|
404
|
-
def _check_thinking_retention(self):
|
|
404
|
+
def _check_thinking_retention(self) -> Self:
|
|
405
405
|
_reject_thinking_retention_conflict(
|
|
406
406
|
self,
|
|
407
407
|
"clear_thinking",
|
|
@@ -424,7 +424,7 @@ class GLM53RendererConfig(BaseRendererConfig):
|
|
|
424
424
|
"""Reasoning-effort system preamble emitted by the canonical template."""
|
|
425
425
|
|
|
426
426
|
@model_validator(mode="after")
|
|
427
|
-
def _check_thinking_retention(self):
|
|
427
|
+
def _check_thinking_retention(self) -> Self:
|
|
428
428
|
_reject_thinking_retention_conflict(
|
|
429
429
|
self,
|
|
430
430
|
"clear_thinking",
|
|
@@ -506,7 +506,7 @@ class Hy3RendererConfig(BaseRendererConfig):
|
|
|
506
506
|
and suppresses the generation prompt (``add_generation_prompt=False``)."""
|
|
507
507
|
|
|
508
508
|
@model_validator(mode="after")
|
|
509
|
-
def _check_thinking_retention(self):
|
|
509
|
+
def _check_thinking_retention(self) -> Self:
|
|
510
510
|
if self.preserved_thinking is not None and self.thinking_retention is not None:
|
|
511
511
|
implied = "all" if self.preserved_thinking else "tool_cycle"
|
|
512
512
|
if self.thinking_retention != implied:
|
|
@@ -566,7 +566,7 @@ class InklingRendererConfig(BaseRendererConfig):
|
|
|
566
566
|
_internal_fields = frozenset({"image_cache_max", "audio_cache_max"})
|
|
567
567
|
|
|
568
568
|
@model_validator(mode="after")
|
|
569
|
-
def _check_reasoning_effort(self):
|
|
569
|
+
def _check_reasoning_effort(self) -> Self:
|
|
570
570
|
eff = self.reasoning_effort
|
|
571
571
|
if isinstance(eff, str):
|
|
572
572
|
if eff.strip() not in INKLING_EFFORT_MAP:
|
|
@@ -631,7 +631,7 @@ class GptOssRendererConfig(BaseRendererConfig):
|
|
|
631
631
|
)
|
|
632
632
|
|
|
633
633
|
@model_validator(mode="after")
|
|
634
|
-
def _check_thinking_retention(self):
|
|
634
|
+
def _check_thinking_retention(self) -> Self:
|
|
635
635
|
_reject_thinking_retention_conflict(
|
|
636
636
|
self,
|
|
637
637
|
"auto_drop_analysis",
|
|
@@ -836,7 +836,7 @@ class Nemotron3RendererConfig(BaseRendererConfig):
|
|
|
836
836
|
policy to ``"all"``."""
|
|
837
837
|
|
|
838
838
|
@model_validator(mode="after")
|
|
839
|
-
def _check_thinking_retention(self):
|
|
839
|
+
def _check_thinking_retention(self) -> Self:
|
|
840
840
|
_reject_thinking_retention_conflict(
|
|
841
841
|
self,
|
|
842
842
|
"truncate_history_thinking",
|
|
@@ -877,7 +877,7 @@ class Nemotron3UltraRendererConfig(BaseRendererConfig):
|
|
|
877
877
|
"""See :class:`Nemotron3RendererConfig.truncate_history_thinking`."""
|
|
878
878
|
|
|
879
879
|
@model_validator(mode="after")
|
|
880
|
-
def _check_thinking_retention(self):
|
|
880
|
+
def _check_thinking_retention(self) -> Self:
|
|
881
881
|
_reject_thinking_retention_conflict(
|
|
882
882
|
self,
|
|
883
883
|
"truncate_history_thinking",
|
|
@@ -913,7 +913,7 @@ class Nemotron35RendererConfig(BaseRendererConfig):
|
|
|
913
913
|
"""See :class:`Nemotron3RendererConfig.truncate_history_thinking`."""
|
|
914
914
|
|
|
915
915
|
@model_validator(mode="after")
|
|
916
|
-
def _check_thinking_retention(self):
|
|
916
|
+
def _check_thinking_retention(self) -> Self:
|
|
917
917
|
_reject_thinking_retention_conflict(
|
|
918
918
|
self,
|
|
919
919
|
"truncate_history_thinking",
|
|
@@ -984,7 +984,7 @@ class DeepSeekV4RendererConfig(BaseRendererConfig):
|
|
|
984
984
|
"""
|
|
985
985
|
|
|
986
986
|
@model_validator(mode="after")
|
|
987
|
-
def _check_thinking_retention(self):
|
|
987
|
+
def _check_thinking_retention(self) -> Self:
|
|
988
988
|
_reject_thinking_retention_conflict(
|
|
989
989
|
self,
|
|
990
990
|
"drop_thinking",
|
|
@@ -1019,7 +1019,7 @@ class CustomRendererConfig(BaseRendererConfig):
|
|
|
1019
1019
|
_internal_fields = frozenset({"import_path"})
|
|
1020
1020
|
|
|
1021
1021
|
@model_validator(mode="after")
|
|
1022
|
-
def _validate_renderer_fields(self):
|
|
1022
|
+
def _validate_renderer_fields(self) -> Self:
|
|
1023
1023
|
# Fail at config load, not at the first render: the import path must
|
|
1024
1024
|
# resolve and the renderer's config must accept the other fields.
|
|
1025
1025
|
from renderers.custom import custom_renderer_config
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
6
|
+
|
|
5
7
|
import pytest
|
|
6
8
|
|
|
7
9
|
from renderers.base import ToolCallParseStatus, load_tokenizer
|
|
@@ -160,3 +162,11 @@ def test_default_renderer_without_parsers_is_backward_compatible():
|
|
|
160
162
|
def test_think_parser_requires_initial_opener(text):
|
|
161
163
|
parser = get_reasoning_parser("think", None)
|
|
162
164
|
assert parser.extract(text) == (None, text)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_parse_status_uses_wire_value_as_string():
|
|
168
|
+
for status in ToolCallParseStatus:
|
|
169
|
+
assert str(status) == status.value
|
|
170
|
+
assert f"{status}" == status.value
|
|
171
|
+
assert json.loads(json.dumps({"status": status})) == {"status": status.value}
|
|
172
|
+
assert ToolCallParseStatus(status.value) is status
|
|
@@ -349,3 +349,9 @@ def test_default_renderer_config_rejects_legacy_preserve_flags():
|
|
|
349
349
|
|
|
350
350
|
cfg = DefaultRendererConfig(some_jinja_kwarg=True)
|
|
351
351
|
assert cfg.model_extra["some_jinja_kwarg"] is True
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def test_message_required_keys():
|
|
355
|
+
assert base.Message.__required_keys__ == {"role", "content"}
|
|
356
|
+
assert "tool_calls" in base.Message.__optional_keys__
|
|
357
|
+
assert "reasoning_content" in base.Message.__optional_keys__
|