127 lines
4.5 KiB
Python
127 lines
4.5 KiB
Python
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
|