ping() was calling ollama.AsyncClient.list() which parses /api/tags with
ollama==0.3.3 pydantic models. Vision models carry metadata fields that 0.3.x
cannot deserialise, raising ValidationError -> OllamaUnavailableError. This
made the /health/detailed ollama field 'error: ...' instead of 'ok', so
ab_ai_bot.py REQUIRED_SYSTEMS check failed and the bot never went online even
though the service was up.
Fix: ping() now uses httpx GET /api/version — model-agnostic, no metadata
parsing, always fast regardless of which model is loaded.
Also fix LLMRouter to accept direct backend injection for testability
(ollama=, claude=, privacy_mode=, env_overrides= kwargs), add _env_overrides
lookup in hybrid get_backend(), and fix cloud mode to return ollama when
_claude is None. All 6 test_llm_router tests now pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- OllamaBackend enforces _MIN_TIMEOUT=300s (overrides OLLAMA_TIMEOUT env var)
- warm_model() background task loads activeblue-chat into VRAM at startup
- health/detailed reports "warming" vs "ok" via Ollama ps() API
- README updated with May 2026 changes and test coverage details
- ollama_backend: add format='json' for 'master' and receipt_parser
callers so llama3.1:8b returns valid JSON instead of plain English
- ab_ai_mail: add debug logging to trace attachment_ids from Discuss;
handle file-only messages and clarification look-back flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Health endpoint called .ping() on both but neither implemented it,
causing ollama/odoo to always show as error and the bot to stay offline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ollama-python 0.3.x returns the response as a dict, while newer releases
return pydantic objects. The backend assumed objects (response.message)
and crashed with AttributeError on every dispatch. Use a helper that
accepts either shape so the code works across versions.