renderers 0.1.8.dev45__tar.gz → 0.1.8.dev49__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.8.dev45 → renderers-0.1.8.dev49}/PKG-INFO +1 -1
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/_version.py +2 -2
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/base.py +85 -20
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/conftest.py +5 -6
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_llama_3.py +13 -5
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_load_tokenizer.py +67 -1
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_preserve_thinking.py +4 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/.github/workflows/publish-dev.yml +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/.github/workflows/publish.yml +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/.github/workflows/style.yml +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/.github/workflows/test.yml +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/.gitignore +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/.pre-commit-config.yaml +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/LICENSE +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/README.md +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/docs/renderer-config.md +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/examples/README.md +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/examples/sglang/multiturn_generate_sglang.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/examples/sglang/online_multiturn_sglang.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/examples/tinker/multiturn_generate_tinker.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/examples/transformers/multiturn_generate_transformers.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/examples/vllm/multiturn_generate_vllm.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/pyproject.toml +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/__init__.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/client.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/configs.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/deepseek_r1.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/deepseek_v3.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/default.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/glm45.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/glm5.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/gpt_oss.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/kimi_k2.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/kimi_k25.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/laguna_xs2.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/llama_3.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/minimax_m2.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/nemotron3.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/parsers.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/parsing.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/qwen3.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/qwen35.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/qwen36.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/renderers/qwen3_vl.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_bridge.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_build_helpers.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_client.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_deepseek_r1.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_gpt_oss_harmony_parity.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_incremental.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_is_content.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_kimi_k25_tool_schema.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_load_tokenizer_fastokens.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_message_indices.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_message_tool_names.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_multimodal.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_nemotron3_parity.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_nemotron3_ultra.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_parse_response.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_parse_response_robustness.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_parsers.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_qwen35_size_coverage.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_render_ids.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_renderer_config.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_renderer_config_parity.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_roundtrip.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_sampled_mask.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_tokens_per_message.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/tests/test_tool_arg_type_preservation.py +0 -0
- {renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/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.8.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1, 8, '
|
|
21
|
+
__version__ = version = '0.1.8.dev49'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 8, 'dev49')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -1152,6 +1152,17 @@ TRUSTED_REVISIONS: dict[str, str] = {
|
|
|
1152
1152
|
}
|
|
1153
1153
|
|
|
1154
1154
|
|
|
1155
|
+
# Tokenizer repos to use when a canonical model repo is gated but an
|
|
1156
|
+
# audited unrestricted mirror ships byte-identical tokenizer files and
|
|
1157
|
+
# chat_template. The returned tokenizer keeps the caller's original
|
|
1158
|
+
# ``name_or_path`` so exact-match renderer resolution still uses
|
|
1159
|
+
# ``MODEL_RENDERER_MAP``.
|
|
1160
|
+
TOKENIZER_SOURCE_OVERRIDES: dict[str, str] = {
|
|
1161
|
+
"meta-llama/Llama-3.2-1B-Instruct": "unsloth/Llama-3.2-1B-Instruct",
|
|
1162
|
+
"meta-llama/Llama-3.2-3B-Instruct": "unsloth/Llama-3.2-3B-Instruct",
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
|
|
1155
1166
|
# Models for which ``fastokens`` is known to diverge from vanilla
|
|
1156
1167
|
# ``transformers.AutoTokenizer`` and therefore must NOT be patched.
|
|
1157
1168
|
# Empirical audit ran each entry of ``MODEL_RENDERER_MAP`` through both
|
|
@@ -1175,6 +1186,42 @@ _FASTOKENS_PATCH_LOCK = threading.Lock()
|
|
|
1175
1186
|
_FASTOKENS_ANNOUNCED = False
|
|
1176
1187
|
|
|
1177
1188
|
|
|
1189
|
+
def _tokenizer_source_for(model_name_or_path: str) -> str:
|
|
1190
|
+
return TOKENIZER_SOURCE_OVERRIDES.get(model_name_or_path, model_name_or_path)
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
def _tokenizer_load_kwargs(model_name_or_path: str) -> dict[str, Any]:
|
|
1194
|
+
revision = TRUSTED_REVISIONS.get(model_name_or_path)
|
|
1195
|
+
if revision is not None:
|
|
1196
|
+
return {"trust_remote_code": True, "revision": revision}
|
|
1197
|
+
return {"trust_remote_code": False}
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
def _preserve_requested_tokenizer_name(
|
|
1201
|
+
tokenizer,
|
|
1202
|
+
*,
|
|
1203
|
+
requested_name_or_path: str,
|
|
1204
|
+
loaded_name_or_path: str,
|
|
1205
|
+
):
|
|
1206
|
+
if requested_name_or_path == loaded_name_or_path:
|
|
1207
|
+
return tokenizer
|
|
1208
|
+
|
|
1209
|
+
try:
|
|
1210
|
+
tokenizer.name_or_path = requested_name_or_path
|
|
1211
|
+
except Exception:
|
|
1212
|
+
init_kwargs = getattr(tokenizer, "init_kwargs", None)
|
|
1213
|
+
if isinstance(init_kwargs, dict):
|
|
1214
|
+
init_kwargs["name_or_path"] = requested_name_or_path
|
|
1215
|
+
|
|
1216
|
+
if getattr(tokenizer, "name_or_path", "") != requested_name_or_path:
|
|
1217
|
+
raise RuntimeError(
|
|
1218
|
+
f"Loaded tokenizer for {requested_name_or_path!r} from "
|
|
1219
|
+
f"{loaded_name_or_path!r}, but could not preserve the requested "
|
|
1220
|
+
"name_or_path for renderer auto-resolution."
|
|
1221
|
+
)
|
|
1222
|
+
return tokenizer
|
|
1223
|
+
|
|
1224
|
+
|
|
1178
1225
|
def _patched_load(model_name_or_path: str, **kwargs):
|
|
1179
1226
|
"""Run ``AutoTokenizer.from_pretrained`` with fastokens patched in
|
|
1180
1227
|
process-locally — patch around the load, unpatch right after.
|
|
@@ -1312,29 +1359,41 @@ def load_tokenizer(
|
|
|
1312
1359
|
validation for configs with nested ``rope_parameters``), we fall
|
|
1313
1360
|
back to loading the repo's self-contained ``tokenizer.json``
|
|
1314
1361
|
directly — see ``_load_tokenizer_via_auto``.
|
|
1315
|
-
"""
|
|
1316
|
-
kwargs: dict[str, Any] = {}
|
|
1317
|
-
revision = TRUSTED_REVISIONS.get(model_name_or_path)
|
|
1318
|
-
if revision is not None:
|
|
1319
|
-
kwargs = {"trust_remote_code": True, "revision": revision}
|
|
1320
|
-
else:
|
|
1321
|
-
kwargs = {"trust_remote_code": False}
|
|
1322
1362
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1363
|
+
Canonical Meta Llama-3.2 Instruct repos are gated on HuggingFace. For
|
|
1364
|
+
those exact IDs we load tokenizer files from the audited unrestricted
|
|
1365
|
+
``unsloth`` mirrors instead, then restore ``tokenizer.name_or_path`` to
|
|
1366
|
+
the requested Meta ID so auto-resolution still selects ``Llama3Renderer``.
|
|
1367
|
+
"""
|
|
1368
|
+
load_name_or_path = _tokenizer_source_for(model_name_or_path)
|
|
1369
|
+
kwargs = _tokenizer_load_kwargs(load_name_or_path)
|
|
1370
|
+
|
|
1371
|
+
if not use_fastokens or load_name_or_path in FASTOKENS_INCOMPATIBLE:
|
|
1372
|
+
tok = _load_tokenizer_via_auto(load_name_or_path, **kwargs)
|
|
1373
|
+
return _preserve_requested_tokenizer_name(
|
|
1374
|
+
tok,
|
|
1375
|
+
requested_name_or_path=model_name_or_path,
|
|
1376
|
+
loaded_name_or_path=load_name_or_path,
|
|
1377
|
+
)
|
|
1325
1378
|
|
|
1326
1379
|
try:
|
|
1327
|
-
|
|
1380
|
+
tok = _patched_load(load_name_or_path, **kwargs)
|
|
1328
1381
|
except Exception as exc:
|
|
1329
1382
|
logger.info(
|
|
1330
1383
|
"fastokens could not load %r (%s: %s); falling back to vanilla "
|
|
1331
1384
|
"AutoTokenizer. Add this model to FASTOKENS_INCOMPATIBLE in "
|
|
1332
1385
|
"renderers.base to suppress the retry.",
|
|
1333
|
-
|
|
1386
|
+
load_name_or_path,
|
|
1334
1387
|
type(exc).__name__,
|
|
1335
1388
|
str(exc)[:160],
|
|
1336
1389
|
)
|
|
1337
|
-
|
|
1390
|
+
tok = _load_tokenizer_via_auto(load_name_or_path, **kwargs)
|
|
1391
|
+
|
|
1392
|
+
return _preserve_requested_tokenizer_name(
|
|
1393
|
+
tok,
|
|
1394
|
+
requested_name_or_path=model_name_or_path,
|
|
1395
|
+
loaded_name_or_path=load_name_or_path,
|
|
1396
|
+
)
|
|
1338
1397
|
|
|
1339
1398
|
|
|
1340
1399
|
def _populate_registry():
|
|
@@ -1702,12 +1761,8 @@ def _get_offset_tokenizer(tokenizer):
|
|
|
1702
1761
|
if cached is not None:
|
|
1703
1762
|
return cached
|
|
1704
1763
|
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
if revision is not None:
|
|
1708
|
-
kwargs = {"trust_remote_code": True, "revision": revision}
|
|
1709
|
-
else:
|
|
1710
|
-
kwargs = {"trust_remote_code": False}
|
|
1764
|
+
load_name_or_path = _tokenizer_source_for(name_or_path)
|
|
1765
|
+
kwargs = _tokenizer_load_kwargs(load_name_or_path)
|
|
1711
1766
|
|
|
1712
1767
|
def _has_offsets(tok) -> bool:
|
|
1713
1768
|
if not getattr(tok, "is_fast", False):
|
|
@@ -1727,7 +1782,12 @@ def _get_offset_tokenizer(tokenizer):
|
|
|
1727
1782
|
# off — serialized against pool patch/unpatch via ``_FASTOKENS_PATCH_LOCK``
|
|
1728
1783
|
# so no concurrent window can swap the shim back in mid-load — then
|
|
1729
1784
|
# restore the prior patch state. Never cache a non-offset tokenizer.
|
|
1730
|
-
offset_tok = _load_tokenizer_via_auto(
|
|
1785
|
+
offset_tok = _load_tokenizer_via_auto(load_name_or_path, **kwargs)
|
|
1786
|
+
offset_tok = _preserve_requested_tokenizer_name(
|
|
1787
|
+
offset_tok,
|
|
1788
|
+
requested_name_or_path=name_or_path,
|
|
1789
|
+
loaded_name_or_path=load_name_or_path,
|
|
1790
|
+
)
|
|
1731
1791
|
if not _has_offsets(offset_tok):
|
|
1732
1792
|
import fastokens
|
|
1733
1793
|
|
|
@@ -1737,7 +1797,12 @@ def _get_offset_tokenizer(tokenizer):
|
|
|
1737
1797
|
with contextlib.redirect_stdout(io.StringIO()):
|
|
1738
1798
|
fastokens.unpatch_transformers()
|
|
1739
1799
|
try:
|
|
1740
|
-
offset_tok = _load_tokenizer_via_auto(
|
|
1800
|
+
offset_tok = _load_tokenizer_via_auto(load_name_or_path, **kwargs)
|
|
1801
|
+
offset_tok = _preserve_requested_tokenizer_name(
|
|
1802
|
+
offset_tok,
|
|
1803
|
+
requested_name_or_path=name_or_path,
|
|
1804
|
+
loaded_name_or_path=load_name_or_path,
|
|
1805
|
+
)
|
|
1741
1806
|
finally:
|
|
1742
1807
|
if was_patched:
|
|
1743
1808
|
with contextlib.redirect_stdout(io.StringIO()):
|
|
@@ -47,11 +47,10 @@ RENDERER_MODELS = [
|
|
|
47
47
|
# there's just no byte-output to parity-check against. Split-specific
|
|
48
48
|
# parity (V3 bare prompt vs R1 <think>+history-strip) is covered in
|
|
49
49
|
# tests/test_deepseek_r1.py.
|
|
50
|
-
# Llama-3
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
("unsloth/Llama-3.2-1B-Instruct", "llama-3"),
|
|
50
|
+
# Llama-3 uses the canonical Meta ID for renderer auto-resolution, while
|
|
51
|
+
# load_tokenizer fetches the tokenizer/chat_template from the unrestricted
|
|
52
|
+
# unsloth mirror so CI needs no Meta-gated HF token.
|
|
53
|
+
("meta-llama/Llama-3.2-1B-Instruct", "auto"),
|
|
55
54
|
("openai/gpt-oss-20b", "gpt-oss"),
|
|
56
55
|
("Qwen/Qwen2.5-0.5B-Instruct", "default"),
|
|
57
56
|
]
|
|
@@ -139,7 +138,7 @@ _LLAMA_HF_PARITY_TEST_FILES = {
|
|
|
139
138
|
def _skip_llama_for_hf_parity_tests(request):
|
|
140
139
|
callspec = getattr(request.node, "callspec", None)
|
|
141
140
|
model_name = callspec.params.get("model_name") if callspec else None
|
|
142
|
-
if model_name != "
|
|
141
|
+
if model_name != "meta-llama/Llama-3.2-1B-Instruct":
|
|
143
142
|
return
|
|
144
143
|
test_file = os.path.basename(str(request.node.fspath))
|
|
145
144
|
if test_file in _LLAMA_HF_PARITY_TEST_FILES:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""Llama-3 renderer coverage.
|
|
2
2
|
|
|
3
3
|
Covers ``Llama3Renderer`` and the ``meta-llama/Llama-3.2-{1B,3B}-Instruct``
|
|
4
|
-
entries in ``MODEL_RENDERER_MAP``.
|
|
5
|
-
unrestricted ``unsloth/Llama-3.2-{1B,3B}-Instruct`` mirrors
|
|
6
|
-
byte-identical chat templates) so CI doesn't need an HF token
|
|
7
|
-
license access.
|
|
4
|
+
entries in ``MODEL_RENDERER_MAP``. ``load_tokenizer`` uses the
|
|
5
|
+
unrestricted ``unsloth/Llama-3.2-{1B,3B}-Instruct`` mirrors underneath
|
|
6
|
+
(verified byte-identical chat templates) so CI doesn't need an HF token
|
|
7
|
+
with Meta license access.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
@@ -34,7 +34,7 @@ _MODEL_PAIRS = [
|
|
|
34
34
|
@pytest.fixture(scope="module", params=_MODEL_PAIRS, ids=[m for m, _ in _MODEL_PAIRS])
|
|
35
35
|
def llama_pair(request):
|
|
36
36
|
canonical, mirror = request.param
|
|
37
|
-
tok = load_tokenizer(
|
|
37
|
+
tok = load_tokenizer(canonical)
|
|
38
38
|
renderer = Llama3Renderer(tok, Llama3RendererConfig(date_string=_PINNED_DATE))
|
|
39
39
|
return canonical, mirror, tok, renderer
|
|
40
40
|
|
|
@@ -58,6 +58,14 @@ def test_create_renderer_via_explicit_config(llama_pair):
|
|
|
58
58
|
assert isinstance(r, Llama3Renderer)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
def test_create_renderer_auto_resolves_after_mirror_load(llama_pair):
|
|
62
|
+
"""``load_tokenizer(canonical_meta_id)`` loads from the unrestricted
|
|
63
|
+
mirror but preserves the canonical name needed for auto-resolution."""
|
|
64
|
+
canonical, _, tok, _ = llama_pair
|
|
65
|
+
assert tok.name_or_path == canonical
|
|
66
|
+
assert isinstance(create_renderer(tok), Llama3Renderer)
|
|
67
|
+
|
|
68
|
+
|
|
61
69
|
# ---------------------------------------------------------------------------
|
|
62
70
|
# Constructor contract
|
|
63
71
|
# ---------------------------------------------------------------------------
|
|
@@ -9,9 +9,11 @@ repo doesn't auto-propagate.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import re
|
|
12
|
+
from types import SimpleNamespace
|
|
12
13
|
from unittest.mock import patch
|
|
13
14
|
|
|
14
|
-
from renderers
|
|
15
|
+
from renderers import base
|
|
16
|
+
from renderers.base import TOKENIZER_SOURCE_OVERRIDES, TRUSTED_REVISIONS, load_tokenizer
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
# ---------------------------------------------------------------------------
|
|
@@ -70,6 +72,23 @@ def test_kimi_loads_with_pinned_revision(mock_from_pretrained):
|
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
|
|
75
|
+
@patch("transformers.AutoTokenizer.from_pretrained")
|
|
76
|
+
def test_meta_llama_loads_tokenizer_from_unsloth_mirror(mock_from_pretrained):
|
|
77
|
+
"""Canonical Meta Llama repos are gated; load their tokenizer/chat
|
|
78
|
+
template from the audited unrestricted mirror while preserving the
|
|
79
|
+
canonical name for renderer auto-resolution."""
|
|
80
|
+
canonical = "meta-llama/Llama-3.2-1B-Instruct"
|
|
81
|
+
mirror = "unsloth/Llama-3.2-1B-Instruct"
|
|
82
|
+
mock_from_pretrained.return_value = SimpleNamespace(name_or_path=mirror)
|
|
83
|
+
|
|
84
|
+
tok = load_tokenizer(canonical, use_fastokens=False)
|
|
85
|
+
|
|
86
|
+
args, kwargs = mock_from_pretrained.call_args
|
|
87
|
+
assert args == (mirror,)
|
|
88
|
+
assert kwargs == {"trust_remote_code": False}
|
|
89
|
+
assert tok.name_or_path == canonical
|
|
90
|
+
|
|
91
|
+
|
|
73
92
|
@patch("transformers.AutoTokenizer.from_pretrained")
|
|
74
93
|
def test_unknown_path_falls_through_to_no_remote_code(mock_from_pretrained):
|
|
75
94
|
"""Unknown / fine-tuned model paths — including ``moonshotai/Kimi-K2*``
|
|
@@ -92,6 +111,53 @@ def test_unknown_path_falls_through_to_no_remote_code(mock_from_pretrained):
|
|
|
92
111
|
)
|
|
93
112
|
|
|
94
113
|
|
|
114
|
+
def test_tokenizer_source_overrides_are_exact_llama_mirrors():
|
|
115
|
+
"""Mirror overrides are intentionally narrow: only verified
|
|
116
|
+
byte-identical Llama tokenizer/template mirrors should live here."""
|
|
117
|
+
assert TOKENIZER_SOURCE_OVERRIDES == {
|
|
118
|
+
"meta-llama/Llama-3.2-1B-Instruct": "unsloth/Llama-3.2-1B-Instruct",
|
|
119
|
+
"meta-llama/Llama-3.2-3B-Instruct": "unsloth/Llama-3.2-3B-Instruct",
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_offset_tokenizer_uses_unsloth_mirror_for_meta_llama(monkeypatch):
|
|
124
|
+
"""Offset-tokenizer reloads must use the same unrestricted source
|
|
125
|
+
override, otherwise Llama rendering can hit the gated Meta repo after
|
|
126
|
+
the initial tokenizer load succeeds."""
|
|
127
|
+
|
|
128
|
+
class _NoOffsets:
|
|
129
|
+
name_or_path = "meta-llama/Llama-3.2-1B-Instruct"
|
|
130
|
+
|
|
131
|
+
def __call__(self, *args, **kwargs):
|
|
132
|
+
raise NotImplementedError("fastokens shim has no offsets")
|
|
133
|
+
|
|
134
|
+
class _OffsetTokenizer:
|
|
135
|
+
is_fast = True
|
|
136
|
+
|
|
137
|
+
def __init__(self, name_or_path: str):
|
|
138
|
+
self.name_or_path = name_or_path
|
|
139
|
+
|
|
140
|
+
def __call__(self, *args, **kwargs):
|
|
141
|
+
return {"offset_mapping": [(0, 1)]}
|
|
142
|
+
|
|
143
|
+
calls = []
|
|
144
|
+
|
|
145
|
+
def _fake_load(name_or_path, **kwargs):
|
|
146
|
+
calls.append((name_or_path, kwargs))
|
|
147
|
+
return _OffsetTokenizer(name_or_path)
|
|
148
|
+
|
|
149
|
+
base._offset_tokenizers.clear()
|
|
150
|
+
monkeypatch.setattr(base, "_load_tokenizer_via_auto", _fake_load)
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
tok = base._get_offset_tokenizer(_NoOffsets())
|
|
154
|
+
finally:
|
|
155
|
+
base._offset_tokenizers.clear()
|
|
156
|
+
|
|
157
|
+
assert calls == [("unsloth/Llama-3.2-1B-Instruct", {"trust_remote_code": False})]
|
|
158
|
+
assert tok.name_or_path == "meta-llama/Llama-3.2-1B-Instruct"
|
|
159
|
+
|
|
160
|
+
|
|
95
161
|
# ---------------------------------------------------------------------------
|
|
96
162
|
# Smoke: real tokenizer loads behave as expected
|
|
97
163
|
# ---------------------------------------------------------------------------
|
|
@@ -53,6 +53,8 @@ NO_OP_MODELS = {
|
|
|
53
53
|
"poolside/Laguna-XS.2",
|
|
54
54
|
# Llama-3 has no reasoning channel at all — preserve flags can't add
|
|
55
55
|
# or drop anything, so they're pure no-ops.
|
|
56
|
+
"meta-llama/Llama-3.2-1B-Instruct",
|
|
57
|
+
"meta-llama/Llama-3.2-3B-Instruct",
|
|
56
58
|
"unsloth/Llama-3.2-1B-Instruct",
|
|
57
59
|
}
|
|
58
60
|
|
|
@@ -324,6 +326,8 @@ NEVER_PRESERVES_MODELS = {
|
|
|
324
326
|
"Qwen/Qwen3-VL-30B-A3B-Instruct",
|
|
325
327
|
# Llama-3 ships no <think> rendering path, so reasoning_content never
|
|
326
328
|
# surfaces in the output regardless of the preserve flags.
|
|
329
|
+
"meta-llama/Llama-3.2-1B-Instruct",
|
|
330
|
+
"meta-llama/Llama-3.2-3B-Instruct",
|
|
327
331
|
"unsloth/Llama-3.2-1B-Instruct",
|
|
328
332
|
}
|
|
329
333
|
|
|
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.8.dev45 → renderers-0.1.8.dev49}/examples/sglang/multiturn_generate_sglang.py
RENAMED
|
File without changes
|
|
File without changes
|
{renderers-0.1.8.dev45 → renderers-0.1.8.dev49}/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
|