refactor(backend): speak only OpenAI-compat /v1 to the local backend

Three native-API touchpoints converted — steward /api/generate to
/v1/chat/completions, embeddings /api/embeddings to /v1/embeddings,
health /api/tags to /v1/models — so the backend behind OLLAMA_HOST is
swappable by env alone. This makes the serving plan's "tatlock needs
zero changes" claim true for the llama-server cutover and for forge
after it. EMBEDDING_HOST (default: OLLAMA_HOST) lets gen and embed
point at different servers, which the boilerroom stack needs.

The dead OllamaClient goes with it: a native-API client nothing
imported, whose presence would make the post-cutover "no native
endpoints" grep lie.

Contract tests rewritten to mirror the new requests and extended with
the embeddings shape (dim must match the configured Qdrant dimension).
All pass against live Ollama's /v1 — deployable before any cutover.
Both new assertions mutation-checked via env overrides (bogus model,
wrong dim: each fails). The Anthropic contract now skips on 401: the
configured key is deliberately revoked per workspace D-11, which is
"fallback disabled", not a boundary break. Embedding continuity across
backends was measured separately: same nomic bytes, cosine 1.0000.

663 unit tests pass; ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 21:35:48 +02:00
co-authored by Claude Fable 5
parent f578ebded8
commit 16b7edbc26
8 changed files with 110 additions and 278 deletions
+6 -4
View File
@@ -47,9 +47,11 @@ async def check_ollama_health() -> bool:
try:
async with httpx.AsyncClient(timeout=5.0) as client:
response = await client.get(f"{host}/api/tags")
# OpenAI-compat surface, so the check holds for any backend
# behind OLLAMA_HOST (Ollama, llama-server).
response = await client.get(f"{host}/v1/models")
response.raise_for_status()
names = [m.get("name", "") for m in response.json().get("models", [])]
names = [m.get("id", "") for m in response.json().get("data", [])]
if model in names or f"{model}:latest" in names:
_ollama_available = True
@@ -63,10 +65,10 @@ async def check_ollama_health() -> bool:
_ollama_available = False
logger.warning(
"ollama_health_check_failed",
reason="model_not_pulled",
reason="model_not_served",
host=host,
model=model,
hint=f"run `ollama pull {model}`",
hint=f"backend does not list '{model}' — pull it (ollama) or serve it under that alias (llama-server)",
)
return False