from __future__ import annotations import re from collections import Counter from pathlib import Path import yaml REPO_ROOT = Path(__file__).resolve().parents[3] DIRECT_OLLAMA_URL_PATTERN = re.compile( r""" settings\.OLLAMA_URL | get_settings\(\)\.OLLAMA_URL | _get_settings\(\)\.OLLAMA_URL | _gs\(\)\.OLLAMA_URL | self\._settings\.OLLAMA_URL | getattr\([^\n]*["']OLLAMA_URL["'] | OLLAMA_URL\s*=\s*os\.getenv | OLLAMA_URL\s*=\s*_get_settings\(\)\.OLLAMA_URL """, re.VERBOSE, ) # Existing direct settings.OLLAMA_URL usage is legacy debt captured in # docs/awooop/inventory/INV-10-ollama-call-sites.md. New call sites must go # through a resolver, provider registry, or AwoooP EffectivePolicy path. MAX_DIRECT_OLLAMA_URL_REFERENCES = { "apps/api/scripts/reembed_bge_m3.py": 1, "apps/api/src/api/v1/ai.py": 1, "apps/api/src/api/v1/health.py": 1, "apps/api/src/api/v1/rag.py": 1, "apps/api/src/hermes/nl_gateway.py": 1, "apps/api/src/routes/agent.py": 1, "apps/api/src/routes/health.py": 1, "apps/api/src/services/ai_providers/ollama.py": 3, "apps/api/src/services/chat_manager.py": 1, "apps/api/src/services/decision_fusion.py": 1, "apps/api/src/services/decision_fusion_adapter.py": 1, "apps/api/src/services/decision_manager.py": 2, "apps/api/src/services/drift_narrator_service.py": 1, "apps/api/src/services/heartbeat_report_service.py": 1, "apps/api/src/services/image_analysis_service.py": 1, "apps/api/src/services/intent_classifier.py": 1, "apps/api/src/services/knowledge_extractor_service.py": 1, "apps/api/src/services/log_summary_service.py": 1, "apps/api/src/services/model_version_probe.py": 2, "apps/api/src/services/nvidia_provider.py": 3, "apps/api/src/services/ollama_auto_recovery.py": 2, "apps/api/src/services/ollama_failover_manager.py": 3, "apps/api/src/services/openclaw.py": 4, } APPROVED_ROUTING_MODULES = { "apps/api/src/services/ollama_endpoint_resolver.py", } def _iter_python_files() -> list[Path]: roots = [ REPO_ROOT / "apps/api/src", REPO_ROOT / "apps/api/scripts", ] files: list[Path] = [] for root in roots: files.extend(path for path in root.rglob("*.py") if "__pycache__" not in path.parts) return sorted(files) def _direct_ollama_reference_counts() -> Counter[str]: counts: Counter[str] = Counter() for path in _iter_python_files(): rel_path = path.relative_to(REPO_ROOT).as_posix() if rel_path in APPROVED_ROUTING_MODULES: continue for line in path.read_text(encoding="utf-8").splitlines(): if line.lstrip().startswith("#"): continue matches = sum(1 for _ in DIRECT_OLLAMA_URL_PATTERN.finditer(line)) if matches: counts[rel_path] += matches return counts def test_no_new_direct_ollama_url_call_sites() -> None: counts = _direct_ollama_reference_counts() unexpected = sorted(set(counts) - set(MAX_DIRECT_OLLAMA_URL_REFERENCES)) increased = { path: (counts[path], MAX_DIRECT_OLLAMA_URL_REFERENCES[path]) for path in sorted(set(counts) & set(MAX_DIRECT_OLLAMA_URL_REFERENCES)) if counts[path] > MAX_DIRECT_OLLAMA_URL_REFERENCES[path] } assert not unexpected, ( "New direct OLLAMA_URL call sites must be routed through a resolver, " "provider registry, or AwoooP EffectivePolicy first: " f"{unexpected}" ) assert not increased, ( "Direct OLLAMA_URL references increased. Update the code to use an " f"approved routing path instead: {increased}" ) def test_prod_ollama_env_matches_configmap_source_of_truth() -> None: configmap_path = REPO_ROOT / "k8s/awoooi-prod/04-configmap.yaml" deployment_path = REPO_ROOT / "k8s/awoooi-prod/06-deployment-api.yaml" configmap = yaml.safe_load(configmap_path.read_text(encoding="utf-8")) deployment_docs = list(yaml.safe_load_all(deployment_path.read_text(encoding="utf-8"))) deployment = next(doc for doc in deployment_docs if doc.get("kind") == "Deployment") expected = { key: configmap["data"][key] for key in ("OLLAMA_URL", "OLLAMA_SECONDARY_URL", "OLLAMA_FALLBACK_URL") } containers = deployment["spec"]["template"]["spec"]["containers"] api_container = next(container for container in containers if container["name"] == "api") actual = { env["name"]: env["value"] for env in api_container["env"] if env["name"] in expected } assert actual == expected