ADR-037: Live Ollama Model Discovery via the Raw REST API¶
Status: Accepted
Date: 2026-06-21
Related: agentic_v2/models/ollama_discovery.py (new),
agentic_v2/langchain/models.py (enumerate_known_models),
agentic_v2/server/routes/models.py (GET /api/models/probe),
ui/src/pages/ModelFinderPage.tsx, ui/src/api/types.ts (ProbedModel).
Builds on ADR-036 (OllamaBackend on the official client). Complements the
tools/llm discovery scan's separate ollama_cloud provider.
Context¶
The console's model probe (GET /api/models/probe → enumerate_known_models())
returned a static list: only the models hardcoded in _TIER_FALLBACK_CHAINS,
annotated with provider-level credential availability. It never asked the Ollama
server what was actually installed, so locally-pulled models did not appear and
cloud models (Ollama's hosted offering) were invisible — the "probe" probed
credentials, not models.
A first pass (same session) wired a live probe in using the official ollama
client's Client.list(). Researching the API (docs.ollama.com, OpenAPI spec)
surfaced two problems with that transport:
- The pinned client is lossy.
ollama0.6.1's typedListResponse.Modelexposes onlymodel / modified_at / digest / size / details. The wire/api/tagsresponse also carriescapabilitiesand — per the OpenAPI spec —remote_model/remote_host, which the typed model drops. remote_hostis the authoritative cloud marker. A signed-in local server proxies cloud models into its own/api/tags, stamping them withremote_host/remote_model. That is a far more reliable cloud signal than guessing from a:cloud/-cloudname suffix.
Cloud access has two documented forms: ollama signin (local server proxies to
ollama.com transparently) or an API key (OLLAMA_API_KEY, Authorization:
Bearer, against https://ollama.com/api). An Ollama Pro plan raises cloud rate
limits but does not, by itself, expose the catalog to a headless probe.
Decision¶
Add a dedicated best-effort discovery module, agentic_v2/models/ollama_discovery.py,
that reads the raw Ollama REST API over httpx (not the typed client):
GET {OLLAMA_BASE_URL}/api/tags— local models (includes proxied cloud models when signed in).GET {OLLAMA_BASE_URL}/api/ps— locally loaded models, to set arunningflag.GET https://ollama.com/api/tagswith a bearer token — the hosted cloud catalog, only whenOLLAMA_API_KEYis set (no key → no network call).
It returns OllamaModelInfo(id, name, cloud, capabilities, running, size,
remote_host) records, de-duplicated local-first. Cloud is classified by
remote_host / remote_model first, falling back to the :cloud / -cloud
suffix; models from the hosted endpoint are always cloud=True.
enumerate_known_models() merges these records into the probe output: catalog
models that are present are marked available and enriched with
cloud / capabilities / running; discovered models absent from every tier
chain are appended at tier 0. The ProbedModel API/TS type gains optional
cloud / capabilities / running; the model-router page renders capability
chips, a cloud badge, and a running indicator, keeping everything under the one
ollama provider group (cloud distinguished by badge + suffix).
Discovery is best-effort: any probe failure (unreachable server, bad key,
/api/ps down) contributes no entries, so the endpoint degrades to the static
catalog instead of erroring. Timeouts are short (5s) so the on-demand probe
never hangs. The API key is never logged.
Consequences¶
- The console now reflects what is actually runnable: real local models,
their capabilities (
tools/thinking/vision), whether they are loaded, and — with a key or signin — cloud models, all surfaced on "rescan". - Discovery is decoupled from the lossy SDK; protocol additions (new
/api/tagsfields) are picked up by reading raw JSON. Theollamaclient remains the transport for actual inference inOllamaBackend(ADR-036). - The probe endpoint now performs network I/O to the local Ollama (and cloud when keyed). It is an explicit on-demand probe, bounded by timeouts and guarded so failures never surface to the caller.
- Cloud end-to-end requires the operator to set
OLLAMA_API_KEY(or sign in); Ollama Pro alone is insufficient. Documented inMODEL_LAYER.md. - The
tools/llmdiscovery scan keeps its own id-list contract and separateollama_cloudprovider; this ADR governs the runtime/app path only.