diff --git a/afd_plugin/model_executor/models/model_utils.py b/afd_plugin/model_executor/models/model_utils.py index 4edc7273..ecfb1568 100644 --- a/afd_plugin/model_executor/models/model_utils.py +++ b/afd_plugin/model_executor/models/model_utils.py @@ -4,7 +4,7 @@ from __future__ import annotations -from copy import copy +from copy import deepcopy from typing import TYPE_CHECKING from afd_plugin import _DEEPSEEK_MODEL_REGISTRATIONS @@ -18,8 +18,11 @@ def get_afd_model_config(model_config: ModelConfig) -> ModelConfig: for model_arch in model_config.hf_config.architectures: if model_arch in _DEEPSEEK_MODEL_REGISTRATIONS: - afd_model_config = copy(model_config) - afd_model_config.hf_config = copy(model_config.hf_config) + # deepcopy preserves aliasing within the copied object graph, so + # the pure-text identity hf_text_config is hf_config is retained + # automatically. vLLM Ascend uses that identity to distinguish + # text models from multimodal models. + afd_model_config = deepcopy(model_config) afd_model_config.hf_config.architectures = [f"AFD{model_arch}"] return afd_model_config return model_config diff --git a/tests/unit/package/test_package.py b/tests/unit/package/test_package.py index 6a379557..6966bc18 100644 --- a/tests/unit/package/test_package.py +++ b/tests/unit/package/test_package.py @@ -50,18 +50,40 @@ def test_afd_model_config_uses_private_architecture_copy(): pytest.importorskip("vllm") from afd_plugin.model_executor.models.model_utils import get_afd_model_config + hf_config = SimpleNamespace(architectures=["DeepseekV2ForCausalLM"]) model_config = SimpleNamespace( - hf_config=SimpleNamespace(architectures=["DeepseekV2ForCausalLM"]), + hf_config=hf_config, + hf_text_config=hf_config, ) afd_model_config = get_afd_model_config(model_config) assert afd_model_config is not model_config assert afd_model_config.hf_config is not model_config.hf_config + assert afd_model_config.hf_text_config is afd_model_config.hf_config assert afd_model_config.hf_config.architectures == ["AFDDeepseekV2ForCausalLM"] assert model_config.hf_config.architectures == ["DeepseekV2ForCausalLM"] +def test_afd_model_config_preserves_nested_text_config(): + pytest.importorskip("vllm") + from afd_plugin.model_executor.models.model_utils import get_afd_model_config + + hf_text_config = SimpleNamespace() + model_config = SimpleNamespace( + hf_config=SimpleNamespace(architectures=["DeepseekV2ForCausalLM"]), + hf_text_config=hf_text_config, + ) + + afd_model_config = get_afd_model_config(model_config) + + # deepcopy privatizes the whole graph; a genuinely distinct nested + # hf_text_config stays distinct from hf_config. + assert afd_model_config.hf_config is not model_config.hf_config + assert afd_model_config.hf_text_config is not hf_text_config + assert afd_model_config.hf_text_config is not afd_model_config.hf_config + + def test_entry_point_is_registered(): entry_points = importlib.metadata.entry_points(group="vllm.general_plugins") matches = [ep for ep in entry_points if ep.name == "afd"]