"""Tests P1.z — résolution centralisée du modèle V4/reasoning (DGX-safe). Garantit que les chemins V4/reasoning (ORALoop, détection dialogue/popup, vram_orchestrator) ne tombent plus sur le default brut `qwen2.5vl:7b` (absent du tunnel DGX → 404) quand `RPA_REASONING_MODEL` n'est pas positionné. """ import importlib import os import pytest from core.detection import vlm_config # Le default historique dangereux : présent dans aucun modèle DGX → 404. DANGEROUS_RAW_DEFAULT = "qwen2.5vl:7b" # Les 3 env vars qui influencent la résolution reasoning. _REASONING_ENVS = ("RPA_REASONING_MODEL", "RPA_VLM_MODEL", "VLM_MODEL") @pytest.fixture def clean_reasoning_env(monkeypatch): """Neutralise toute env reasoning/VLM pour tester le default pur.""" for var in _REASONING_ENVS: monkeypatch.delenv(var, raising=False) return monkeypatch def test_default_is_dgx_safe(clean_reasoning_env): """Sans aucune env, le default ne doit PAS être `qwen2.5vl:7b` brut.""" model = vlm_config.get_reasoning_model() assert model != DANGEROUS_RAW_DEFAULT # Le default doit pointer vers un modèle présent sur DGX (tag -rpa). assert model == vlm_config.DEFAULT_REASONING_MODEL assert "-rpa" in model def test_rpa_reasoning_model_has_priority(clean_reasoning_env): """RPA_REASONING_MODEL prime sur tout le reste.""" clean_reasoning_env.setenv("RPA_REASONING_MODEL", "mon-modele:custom") clean_reasoning_env.setenv("RPA_VLM_MODEL", "autre:vlm") assert vlm_config.get_reasoning_model() == "mon-modele:custom" def test_falls_back_to_vlm_model(clean_reasoning_env): """Sans RPA_REASONING_MODEL, on hérite de la config VLM existante.""" clean_reasoning_env.setenv("RPA_VLM_MODEL", "qwen2.5vl:7b-rpa") assert vlm_config.get_reasoning_model() == "qwen2.5vl:7b-rpa" def test_falls_back_to_legacy_vlm_model_alias(clean_reasoning_env): """L'alias de compat VLM_MODEL est honoré en dernier recours avant default.""" clean_reasoning_env.setenv("VLM_MODEL", "qwen2.5vl:7b-rpa") assert vlm_config.get_reasoning_model() == "qwen2.5vl:7b-rpa" @pytest.mark.parametrize( "module_name", [ "core.execution.input_handler", "core.execution.observe_reason_act", "core.cognition.vram_orchestrator", ], ) def test_v4_modules_have_no_raw_hardcoded_default(module_name): """Non-régression : aucun module V4 ne hardcode plus `os.environ.get("RPA_REASONING_MODEL", "qwen2.5vl:7b")`.""" module = importlib.import_module(module_name) source = open(module.__file__, encoding="utf-8").read() assert 'RPA_REASONING_MODEL", "qwen2.5vl:7b"' not in source, ( f"{module_name} hardcode encore le default dangereux qwen2.5vl:7b" ) def test_vram_orchestrator_reasoning_model_is_dgx_safe(clean_reasoning_env): """Le constant module-level REASONING_MODEL, recalculé sans env, ne doit pas valoir le default brut dangereux.""" from core.cognition import vram_orchestrator importlib.reload(vram_orchestrator) assert vram_orchestrator.REASONING_MODEL != DANGEROUS_RAW_DEFAULT