"""Tests dé-hardcodage VLM de l'Observer (_pre_analyze_screen_sync). Le modèle doit venir de vlm_config et l'endpoint viser 11434 (Ollama/tunnel DGX), pas le port mort 11435 ni le modèle gemma4:e4b absent du DGX. """ import sys from pathlib import Path from unittest.mock import MagicMock, patch import pytest _ROOT = str(Path(__file__).resolve().parents[2]) if _ROOT not in sys.path: sys.path.insert(0, _ROOT) from agent_v0.server_v1.resolve_engine import _pre_analyze_screen_sync def _fake_resp(): resp = MagicMock() resp.ok = True resp.json.return_value = {"message": {"content": "ÉTAT: OK\nBOUTON: aucun\nDÉTAIL: rien"}} return resp def test_observer_modele_via_vlm_config(): """Le payload Observer utilise le modèle résolu par vlm_config.""" captured = {} def capture_post(url, json=None, **kwargs): captured["url"] = url captured["model"] = (json or {}).get("model") return _fake_resp() with patch( "agent_v0.server_v1.resolve_engine.vlm_config.get_vlm_model", return_value="modele-resolu:test", ), patch("requests.post", side_effect=capture_post): _pre_analyze_screen_sync("ZmFrZQ==", "écran prêt", "Fenêtre", 1920, 1080) assert captured["model"] == "modele-resolu:test" def test_observer_endpoint_par_defaut_11434(monkeypatch): """Sans GEMMA4_PORT, l'Observer vise 11434, pas le port mort 11435.""" monkeypatch.delenv("GEMMA4_PORT", raising=False) captured = {} def capture_post(url, json=None, **kwargs): captured["url"] = url return _fake_resp() with patch("requests.post", side_effect=capture_post): _pre_analyze_screen_sync("ZmFrZQ==", "écran prêt", "Fenêtre", 1920, 1080) assert ":11434" in captured["url"] assert ":11435" not in captured["url"]