diff --git a/renderers/base.py b/renderers/base.py index 2d6e78c..20e85b0 100644 --- a/renderers/base.py +++ b/renderers/base.py @@ -1033,6 +1033,7 @@ def bridge_to_next_turn(self, *args: Any, **kwargs: Any) -> "RenderedTokens | No "Qwen/Qwen3.6-35B-A3B": "qwen3.6", # Qwen3.8. "Qwen/Qwen3.8-27B": "qwen3.8", + "Qwen/Qwen3.8-Flash-Next": "qwen3.8", # Qwen3-VL. "Qwen/Qwen3-VL-4B-Instruct": "qwen3-vl", "Qwen/Qwen3-VL-8B-Instruct": "qwen3-vl", @@ -1140,6 +1141,7 @@ def bridge_to_next_turn(self, *args: Any, **kwargs: Any) -> "RenderedTokens | No "Qwen/Qwen3.6-35B-A3B": {"image"}, # Qwen3.8 adds reasoning-effort control and preserves thinking by default. "Qwen/Qwen3.8-27B": {"image"}, + "Qwen/Qwen3.8-Flash-Next": {"image"}, # Kimi K2.5 / K2.6 are unified VLMs (HF tag ``image-text-to-text``) # with custom processor (``KimiK25Processor`` + ``KimiK25VisionProcessor``). # Vision wrap is different from Qwen-VL: diff --git a/renderers/qwen35.py b/renderers/qwen35.py index ad6d945..e63c691 100644 --- a/renderers/qwen35.py +++ b/renderers/qwen35.py @@ -104,6 +104,7 @@ "Qwen/Qwen3.6-35B-A3B": True, # Qwen3.8 keeps thinking enabled by default. "Qwen/Qwen3.8-27B": True, + "Qwen/Qwen3.8-Flash-Next": True, } diff --git a/tests/conftest.py b/tests/conftest.py index 23ae8f4..92d36e6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,6 +23,7 @@ ("Qwen/Qwen3.5-9B", "auto"), ("Qwen/Qwen3.6-35B-A3B", "auto"), ("Qwen/Qwen3.8-27B", "auto"), + ("Qwen/Qwen3.8-Flash-Next", "auto"), ("Qwen/Qwen3-VL-4B-Instruct", "auto"), ("google/gemma-4-31B-it", "auto"), ("zai-org/GLM-5", "auto"), diff --git a/tests/test_bridge.py b/tests/test_bridge.py index 20415c2..1f36bbf 100644 --- a/tests/test_bridge.py +++ b/tests/test_bridge.py @@ -27,6 +27,7 @@ ("Qwen/Qwen3.5-9B", "auto"), ("Qwen/Qwen3.6-35B-A3B", "auto"), ("Qwen/Qwen3.8-27B", "auto"), + ("Qwen/Qwen3.8-Flash-Next", "auto"), ("google/gemma-4-31B-it", "auto"), ("thinkingmachines/Inkling", "auto"), ("thinkingmachines/Inkling-Small", "auto"), diff --git a/tests/test_client.py b/tests/test_client.py index dce4ef5..502e7e1 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -385,8 +385,9 @@ def test_generate_threads_prompt_attribution_through_prebuilt_prompt_path(): ("Qwen/Qwen3-VL-4B-Instruct", "renderers.qwen3_vl:Qwen3VLRenderer"), ("Qwen/Qwen3.5-2B", "renderers.qwen35:Qwen35Renderer"), ("Qwen/Qwen3.8-27B", "renderers.qwen38:Qwen38Renderer"), + ("Qwen/Qwen3.8-Flash-Next", "renderers.qwen38:Qwen38Renderer"), ], - ids=["qwen3_vl", "qwen35", "qwen38"], + ids=["qwen3_vl", "qwen35", "qwen38", "qwen38_flash_next"], ) def test_generate_serializes_multimodal_features_for_qwen_vl_family( model_id, renderer_class_path diff --git a/tests/test_disabled_thinking_stability.py b/tests/test_disabled_thinking_stability.py index 3ec2a60..9724d07 100644 --- a/tests/test_disabled_thinking_stability.py +++ b/tests/test_disabled_thinking_stability.py @@ -45,6 +45,10 @@ "Qwen/Qwen3.8-27B", Qwen38RendererConfig(enable_thinking=False), ), + ( + "Qwen/Qwen3.8-Flash-Next", + Qwen38RendererConfig(enable_thinking=False), + ), ( "google/gemma-4-26B-A4B-it", Gemma4RendererConfig(enable_thinking=False), diff --git a/tests/test_qwen38.py b/tests/test_qwen38.py index 4348d6d..1e94610 100644 --- a/tests/test_qwen38.py +++ b/tests/test_qwen38.py @@ -31,10 +31,12 @@ } ] +QWEN38_MODELS = ["Qwen/Qwen3.8-27B", "Qwen/Qwen3.8-Flash-Next"] -@lru_cache(maxsize=1) -def _qwen38(): - tokenizer = load_tokenizer("Qwen/Qwen3.8-27B") + +@lru_cache(maxsize=None) +def _qwen38(model_name): + tokenizer = load_tokenizer(model_name) return tokenizer, create_renderer(tokenizer) @@ -48,10 +50,11 @@ def _expected(tokenizer, messages, **kwargs): return list(result) -def test_qwen38_is_registered_with_native_defaults(): - tokenizer, renderer = _qwen38() +@pytest.mark.parametrize("qwen38_model", QWEN38_MODELS) +def test_qwen38_is_registered_with_native_defaults(qwen38_model): + tokenizer, renderer = _qwen38(qwen38_model) - assert tokenizer.name_or_path == "Qwen/Qwen3.8-27B" + assert tokenizer.name_or_path == qwen38_model assert MODEL_RENDERER_MAP[tokenizer.name_or_path] == "qwen3.8" assert MULTIMODAL_MODELS[tokenizer.name_or_path] == {"image"} assert isinstance(renderer, Qwen38Renderer) @@ -86,8 +89,9 @@ def test_qwen38_config_discriminator(): pytest.param({"preserve_thinking": False}, id="drop-history-thinking"), ], ) -def test_qwen38_text_and_tool_parity(config_kwargs): - tokenizer, _ = _qwen38() +@pytest.mark.parametrize("qwen38_model", QWEN38_MODELS) +def test_qwen38_text_and_tool_parity(config_kwargs, qwen38_model): + tokenizer, _ = _qwen38(qwen38_model) renderer = Qwen38Renderer(tokenizer, Qwen38RendererConfig(**config_kwargs)) cases = [ ( @@ -152,8 +156,9 @@ def test_qwen38_text_and_tool_parity(config_kwargs): assert renderer.render_ids(messages, **render_kwargs) == expected -def test_qwen38_keeps_inline_think_markup_in_visible_content(): - tokenizer, renderer = _qwen38() +@pytest.mark.parametrize("qwen38_model", QWEN38_MODELS) +def test_qwen38_keeps_inline_think_markup_in_visible_content(qwen38_model): + tokenizer, renderer = _qwen38(qwen38_model) messages = [ {"role": "user", "content": "Echo this."}, { @@ -165,8 +170,9 @@ def test_qwen38_keeps_inline_think_markup_in_visible_content(): assert renderer.render_ids(messages) == _expected(tokenizer, messages) -def test_qwen38_requires_a_real_user_query(): - _, renderer = _qwen38() +@pytest.mark.parametrize("qwen38_model", QWEN38_MODELS) +def test_qwen38_requires_a_real_user_query(qwen38_model): + _, renderer = _qwen38(qwen38_model) with pytest.raises(ValueError, match="No user query found"): renderer.render_ids([{"role": "system", "content": "System only."}]) diff --git a/tests/test_renderer_config_parity.py b/tests/test_renderer_config_parity.py index c7717d7..745b2cf 100644 --- a/tests/test_renderer_config_parity.py +++ b/tests/test_renderer_config_parity.py @@ -48,6 +48,7 @@ ("Qwen/Qwen3.5-9B", "auto"), ("Qwen/Qwen3.6-35B-A3B", "auto"), ("Qwen/Qwen3.8-27B", "auto"), + ("Qwen/Qwen3.8-Flash-Next", "auto"), ("google/gemma-4-31B-it", "auto"), ("zai-org/GLM-5", "auto"), ("zai-org/GLM-5.1", "auto"), diff --git a/tests/test_roundtrip.py b/tests/test_roundtrip.py index ade0ca3..ab36bf7 100644 --- a/tests/test_roundtrip.py +++ b/tests/test_roundtrip.py @@ -33,6 +33,7 @@ ("Qwen/Qwen3.5-9B", "auto"), ("Qwen/Qwen3.6-35B-A3B", "auto"), ("Qwen/Qwen3.8-27B", "auto"), + ("Qwen/Qwen3.8-Flash-Next", "auto"), ("Qwen/Qwen3-VL-4B-Instruct", "auto"), ("google/gemma-4-31B-it", "auto"), ("thinkingmachines/Inkling", "auto"),