fix(llm): surface Ollama error body; refresh pre-gemma3 summaries

Two small hardening fixes from the mistral-nemo testing round:

1. stream_chat / stream_chat_with_tools now read the Ollama response
   body and log it before raising on non-2xx. Previously all we saw
   was 'HTTP 400 Bad Request' — the gemma3-no-tools failure would
   have been diagnosed in one step if we'd been logging the body,
   which says e.g. 'model does not support tools'.

2. backfill_project_summaries() now also targets summaries stamped
   before 2026-04-12 (the gemma3:4b cutover). The remaining projects
   still carrying the broken qwen2.5:3b output (token repetition,
   hallucinated topics) will regenerate on next startup on the
   better model.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-12 22:13:21 -04:00
parent 9a851de624
commit 782f36ed51
2 changed files with 39 additions and 4 deletions
+20 -2
View File
@@ -159,6 +159,24 @@ async def wait_for_model_loaded(model: str, timeout: float = 90.0) -> bool:
await asyncio.sleep(min(2.0, remaining))
async def _raise_ollama_error(resp: httpx.Response, model: str) -> None:
"""On a non-2xx Ollama response, log its body before raising.
``resp.raise_for_status()`` alone throws away Ollama's error body, which
carries the actual reason (e.g. ``"model does not support tools"``,
``"context length exceeded"``). Reading the body first means failures
surface a usable message instead of a bare HTTPStatusError.
"""
if resp.status_code < 400:
return
body = (await resp.aread()).decode("utf-8", errors="replace").strip()
logger.error(
"Ollama /api/chat %d for model=%s: %s",
resp.status_code, model, body[:500],
)
resp.raise_for_status()
async def stream_chat(
messages: list[dict],
model: str,
@@ -184,7 +202,7 @@ async def stream_chat(
f"{Config.OLLAMA_URL}/api/chat",
json=payload,
) as resp:
resp.raise_for_status()
await _raise_ollama_error(resp, model)
async for line in resp.aiter_lines():
if not line.strip():
continue
@@ -245,7 +263,7 @@ async def stream_chat_with_tools(
f"{Config.OLLAMA_URL}/api/chat",
json=payload,
) as resp:
resp.raise_for_status()
await _raise_ollama_error(resp, model)
accumulated_tool_calls: list[dict] = []
async for line in resp.aiter_lines():
if not line.strip():