Files
rpa_vision_v3/tests/unit/test_autonomous_planner_owl_flag.py

122 lines
4.1 KiB
Python

"""Tests pour le feature flag AGENT_CHAT_ENABLE_OWL (C1b).
Contexte : depuis 2026-05-25, OWL-v2 ne se charge plus au boot du service
rpa-agent-chat par défaut (économie ~600 MiB VRAM constatée par Codex après
restart C1). Activation via AGENT_CHAT_ENABLE_OWL=1.
Référence : inbox_claude/2026-05-25_1327_codex-to-claude_C1-post-restart-ok-c1b-vram.md
Fix : agent_chat/autonomous_planner.py _init_visual_detection() l. 139-...
"""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
@pytest.mark.unit
def test_owl_skipped_by_default(monkeypatch):
"""Sans AGENT_CHAT_ENABLE_OWL, OWL ne doit PAS se charger au boot."""
monkeypatch.delenv("AGENT_CHAT_ENABLE_OWL", raising=False)
from agent_chat.autonomous_planner import AutonomousPlanner
planner = AutonomousPlanner(llm_model="qwen2.5:7b")
assert planner._owl_detector is None, (
f"OWL chargé alors que flag OFF (économie VRAM perdue) : "
f"{planner._owl_detector}"
)
@pytest.mark.unit
def test_owl_skipped_when_flag_zero(monkeypatch):
"""AGENT_CHAT_ENABLE_OWL=0 → OWL skip."""
monkeypatch.setenv("AGENT_CHAT_ENABLE_OWL", "0")
from agent_chat.autonomous_planner import AutonomousPlanner
planner = AutonomousPlanner(llm_model="qwen2.5:7b")
assert planner._owl_detector is None
@pytest.mark.unit
def test_owl_skipped_when_flag_false(monkeypatch):
"""AGENT_CHAT_ENABLE_OWL=false → OWL skip (alias accepté)."""
monkeypatch.setenv("AGENT_CHAT_ENABLE_OWL", "false")
from agent_chat.autonomous_planner import AutonomousPlanner
planner = AutonomousPlanner(llm_model="qwen2.5:7b")
assert planner._owl_detector is None
@pytest.mark.unit
def test_owl_init_attempted_when_flag_one(monkeypatch):
"""AGENT_CHAT_ENABLE_OWL=1 → tentative d'init (succès ou échec rattrapé).
Le test ne valide PAS que OWL charge effectivement (dépend GPU + modèle
HF disponible), juste que le code passe la garde du flag et tente l'init.
On mocke OwlDetector pour vérifier qu'il est instancié.
"""
monkeypatch.setenv("AGENT_CHAT_ENABLE_OWL", "1")
from agent_chat import autonomous_planner as ap_module
calls = []
class FakeOwl:
def __init__(self, **kwargs):
calls.append(kwargs)
monkeypatch.setattr(ap_module, "OwlDetector", FakeOwl)
monkeypatch.setattr(ap_module, "VISUAL_DETECTION_AVAILABLE", True)
planner = ap_module.AutonomousPlanner(llm_model="qwen2.5:7b")
assert planner._owl_detector is not None, (
"OWL doit être instancié quand AGENT_CHAT_ENABLE_OWL=1"
)
assert len(calls) == 1
assert calls[0].get("confidence_threshold") == 0.1
@pytest.mark.unit
def test_owl_device_override(monkeypatch):
"""AGENT_CHAT_OWL_DEVICE=cpu force le device CPU même si CUDA dispo."""
monkeypatch.setenv("AGENT_CHAT_ENABLE_OWL", "1")
monkeypatch.setenv("AGENT_CHAT_OWL_DEVICE", "cpu")
from agent_chat import autonomous_planner as ap_module
calls = []
class FakeOwl:
def __init__(self, **kwargs):
calls.append(kwargs)
monkeypatch.setattr(ap_module, "OwlDetector", FakeOwl)
monkeypatch.setattr(ap_module, "VISUAL_DETECTION_AVAILABLE", True)
ap_module.AutonomousPlanner(llm_model="qwen2.5:7b")
assert calls[0].get("device") == "cpu"
@pytest.mark.unit
def test_owl_init_exception_caught(monkeypatch):
"""Si OWL crash à l'init (OOM CUDA, modèle absent, etc.), AutonomousPlanner
doit continuer à booter avec _owl_detector=None."""
monkeypatch.setenv("AGENT_CHAT_ENABLE_OWL", "1")
from agent_chat import autonomous_planner as ap_module
class CrashOwl:
def __init__(self, **kwargs):
raise RuntimeError("CUDA out of memory (simulation)")
monkeypatch.setattr(ap_module, "OwlDetector", CrashOwl)
monkeypatch.setattr(ap_module, "VISUAL_DETECTION_AVAILABLE", True)
planner = ap_module.AutonomousPlanner(llm_model="qwen2.5:7b")
assert planner._owl_detector is None, (
"L'exception doit être catchée — AutonomousPlanner ne doit pas crash"
)