Skip to content

fix(inference): local model reliability — /api/tags fallback + real Ollama model ids - #5219

Merged
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/local-model-reliability
Jul 27, 2026
Merged

fix(inference): local model reliability — /api/tags fallback + real Ollama model ids#5219
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/local-model-reliability

Conversation

@M3gA-Mind

@M3gA-Mind M3gA-Mind commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Problem

#5055 lists five failure modes. Three of them were already fixed before this PR, so re-implementing them would have been duplicated work and churn on tested code. What I found on main:

#5053 (wrong discovery endpoint) — already fixed. inference/local/provider.rs has model_discovery_api() and endpoint_is_openai_v1(), which gate discovery on endpoint type (does the path end in /v1?) rather than "is it localhost" — the exact conflation that caused the bug. It is wired into ollama_admin/diagnostics.rs and pinned by a regression test whose mock serves only /v1/models.

#5017 (embedding verification) — already fixed. embeddings/rpc.rs sends a real POST /v1/embeddings carrying the user's model name and API key, and classify_embed_probe splits the outcome into seven distinct causes: EMBEDDINGS_AUTH_FAILED (401/403), _ENDPOINT_UNREACHABLE (network/DNS), _MODEL_INCOMPATIBLE (a chat model in the embeddings field — the reporter's exact case), _DIMENSION_MISMATCH, _ENDPOINT_NO_API (404/405), _NO_MODEL_LOADED, and a generic fallback. EmbeddingsPanel.tsx surfaces the backend message for every code, and conformant_custom_endpoint_verifies_and_sends_expected_request captures the auth header and request body against a mock endpoint to prove the request shape.

That maps onto the issue's requested NetworkUnreachable / AuthFailed / ModelNotFound / DimensionMismatch / UnexpectedResponse set, so scope items 2 and 4 needed no code.

What was actually still broken:

  1. No 404 fallback. The issue asks for /v1/models → 404 → try /api/tags once with a warning. That did not exist in any form.
  2. No resolved-discovery-URL log.
  3. A model id that cannot be pulled. MVP_ALLOWED_CHAT_MODELS contained gemma4:e4b-it-q8_0 and the 16 GB+ preset used gemma4:e4b for both chat_model_id and vision_model_id. There is no gemma4 namespace on the Ollama library — this is precisely the issue's failure mode 3 ("defaults may be stale or unavailable, causing silent fallback or no-model errors"), and it had a second-order effect described below.

Solution

1. One-shot /api/tags fallback (local/service/lm_studio.rs)

On a /v1/models 404 only, list_ollama_tags_fallback retries the host-rooted /api/tags once and WARNs on entry (taking this path means the base URL and provider type disagree, so the user should still fix their config even though discovery recovered).

Three cases deliberately do not recover, because a permissive fallback would recreate the bug this is meant to fix:

Case Behaviour Why
Non-404 status Fallback never runs A 500 is a server fault, not a wrong-endpoint signal; probing a second path would mask it. Asserted with a request hit-counter on the mock.
Empty /api/tags catalog Not a recovery LM Studio answers unknown paths with 200 {"error": …} and zero models (#5053). Accepting that would look like "discovered 0 models" instead of a real error.
Fallback itself fails Original /v1/models error is surfaced The user should see the real problem, not a second confusing one from a speculative retry.

New ollama_tags_fallback_url() (local/lm_studio.rs) strips a trailing /v1 via a shared host_root_of() helper, so the probe can never become the malformed /v1/api/tags that LM Studio logs as Unexpected endpoint or method.

Discovery is still chosen by provider type first. This is a recovery path, not a probe order.

2. DEBUG log of the resolved discovery URL

discovery_url + api = "openai_v1_models" on the outbound GET, and the equivalent on the fallback.

3. gemma4gemma3n (model_ids.rs, presets.rs)

Verified every local default against the public Ollama library before changing anything:

Model id Where Exists?
gemma3:1b-it-qat default + allowlist + 2–4 GB tier Yes, 1.0 GB
gemma3:4b-it-qat 8–16 GB tier Yes, 4.0 GB
moondream:1.8b-v2-q4_K_S low-vision default Yes
bge-m3 DEFAULT_OLLAMA_EMBED_MODEL Yes, 1.2 GB
gemma3n:e4b-it-q8_0 new 16 GB+ tier + allowlist Yes, 9.5 GB
gemma4:e4b, gemma4:e4b-it-q8_0 was 16 GB+ tier + allowlist No such namespace

"e4b" is Gemma 3n's Effective 4B designation, and 9.5 GB + nomic-embed-text matches the tier's existing approx_download_gb: 9.9 — so gemma3n:e4b-it-q8_0 is what the tier was sized against.

Latent second bug closed: the preset (gemma4:e4b) and the allowlist (gemma4:e4b-it-q8_0) named different ids, so selecting that tier would have been silently redirected to gemma3:1b-it-qat by enforce_mvp_chat_allowlist. They now agree. (The tier is not MVP-gated today, so this bit only on a lifted ceiling — but it was still wrong.)

quantization on that tier moves "qat""q8_0" to match what is actually pulled. I checked first: it is a display string consumed by effective_quantization and takes no part in resolving the model tag, and no test asserts on it.

Not addressed (deliberate)

  • spaCy click (issue item 4) is outside this PR's dispatched scope and untouched — it needs its own change.
  • vision_model_id on the 16 GB+ tier: Ollama lists gemma3n variants as text-input, so vision_mode: Bundled may be non-functional there. It was already non-functional with a model that did not exist, so I corrected the namespace and did not re-architect the vision choice on a guess. Flagged under Related as a follow-up for someone who can test it.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy — 4 fallback tests (recovers / original error preserved / empty catalog rejected / non-404 never probes twice), 1 URL-derivation test, 3 guards against the gemma4 namespace returning.
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/ci-lite.yml. Run pnpm test:coverage and pnpm test:rust locally; PRs below 80% on changed lines will not merge. — every changed Rust path has a new or updated test. Not run locally (see Validation Blocked); CI is the authority on the number.
  • Coverage matrix updated — added/removed/renamed feature rows in docs/TEST-COVERAGE-MATRIX.md reflect this change (or N/A: behaviour-only change) — N/A: behaviour-only change — no feature leaf added, removed or renamed; this fixes existing local-inference behaviour.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related
  • No new external network dependencies introduced (mock backend used per Testing Strategy) — every new test runs against a local axum mock on 127.0.0.1. The Ollama library lookups used to verify model ids were research during authoring, not test-time calls.
  • Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md) — N/A: no release-cut smoke step changes — local-model setup is not in the release-cut checklist, and the default (managed/cloud) path is untouched.
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

  • Platform: desktop + CLI (Rust core only). No frontend, Tauri, or backend changes in this PR.
  • Managed / cloud path: entirely unaffected. Nothing here touches cloud inference or managed embeddings.
  • Ollama path: unaffected. The fallback lives only inside list_lm_studio_models, which a genuine Ollama config never reaches — diagnostics() routes it to the /api/tags branch first. Confirmed by tracing every caller.
  • Behaviour change for local users: an OpenAI-compatible endpoint that 404s on /v1/models but serves /api/tags now discovers models instead of failing. Users on the 16 GB+ preset get a model that can actually be pulled; anyone who had literally selected gemma4:* will be redirected to the default by the existing allowlist, which is the pre-existing behaviour for an unknown id.
  • Performance: one extra HTTP request, only on a 404, only once, only on the OpenAI-compatible discovery path.
  • Migration: none. No config schema change; gemma4:* in a stored config was already non-functional.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

Commit & Branch

  • Branch: fix/local-model-reliability
  • Commit SHA: e499ce440 (branched from 9a484aa50)

Validation Run

  • pnpm --filter openhuman-app format:checkN/A — no frontend files changed in this PR.
  • pnpm typecheckN/A — no TypeScript changed in this PR.
  • Focused tests: not executed — see Validation Blocked. GGML_NATIVE=OFF cargo check -p openhuman --tests completed clean twice (exit 0, only three pre-existing warnings: address_book, Memory, alice_phoenix_thread), so everything compiles including the new tests; the test run was stopped before it produced results.
  • Rust fmt/check (if changed): cargo check -p openhuman --tests clean, as above. cargo fmt not re-run after the final edit — see Validation Blocked.
  • Tauri fmt/check (if changed): N/A — no files under app/src-tauri/ changed.

Validation Blocked

  • command: cargo test -p openhuman --lib, cargo fmt, and any further cargo check
  • error: not run — the build machine was overloaded and further cargo compiles were stopped mid-run by an operator instruction; no compile has been run since.
  • impact: The six new tests compile but have never been executed — CI is the first thing to actually run them. Two late edits (the quantization: "q8_0" label and its comment) landed after the last successful cargo check, so they are not type-checked either; both are string literals in an existing struct field with no test asserting on them. If CI shows a formatting failure, cargo fmt on presets.rs is the likely fix.

Behavior Changes

  • Intended behavior change: a /v1/models 404 falls back once to /api/tags; the 16 GB+ local preset and the chat allowlist name a real, pullable Gemma 3n build.
  • User-visible effect: local model discovery succeeds against runtimes that only serve the Ollama listing; the 16 GB+ preset can actually be downloaded. No change for managed/cloud users or for working Ollama setups.

Parity Contract

  • Legacy behavior preserved: discovery is still selected by provider type (model_discovery_api) before any fallback; the Ollama /api/tags branch is unchanged; the embeddings verification path is untouched; enforce_mvp_chat_allowlist semantics are unchanged.
  • Guard/fallback/dispatch parity checks: non_404_status_does_not_trigger_the_fallback asserts with a hit counter that a 500 never probes /api/tags; empty_api_tags_fallback_is_not_treated_as_recovery and v1_models_404_reports_the_original_error_when_fallback_also_fails pin the two non-recovery cases; presets_reference_no_unpullable_gemma4_namespace and mvp_chat_allowlist_has_no_unpullable_namespaces prevent the bad namespace returning.

Duplicate / Superseded PR Handling

Summary by CodeRabbit

  • New Features

    • LM Studio model discovery now falls back to Ollama’s native model endpoint when the compatible endpoint returns a not-found response.
    • Discovery URLs are normalized to avoid invalid paths and improve diagnostics.
  • Bug Fixes

    • Preserved original errors when fallback discovery fails or returns no models.
    • Updated built-in local presets to use the available Gemma 3n model.
  • Tests

    • Added coverage for fallback behavior, error handling, URL construction, and updated model presets.

…llama model ids

Scope is narrower than issue tinyhumansai#5055 reads, because its two root-cause
sub-issues already shipped and are on main:

- tinyhumansai#5053 (discovery endpoint): `model_discovery_api` / `endpoint_is_openai_v1`
  in inference/local/provider.rs already gate discovery by endpoint *type*
  rather than "is it localhost", wired into diagnostics.rs with a regression
  test. Left as-is.
- tinyhumansai#5017 (embedding verification): the setup probe already sends a real
  POST /v1/embeddings with the user's model and key and classifies seven
  outcomes (auth / unreachable / model-incompatible / dimension-mismatch /
  no-embeddings-API / no-model-loaded / generic), surfaced by
  EmbeddingsPanel.tsx and pinned by a mock-endpoint test that captures the
  auth header and request body. Left as-is.

What was actually missing:

1. No 404 fallback. A `/v1/models` 404 now retries the host-rooted
   `/api/tags` exactly once, logging a warning, so a runtime that only
   speaks the Ollama listing still discovers its models. Three cases
   deliberately do NOT recover, because a permissive fallback would
   reintroduce tinyhumansai#5053: a non-404 status never triggers it (a 500 is a server
   fault, not a wrong-endpoint signal); an empty fallback catalog is not a
   recovery (LM Studio answers unknown paths with `200 {"error": …}` and
   zero models); and when the fallback fails the caller sees the original
   /v1/models error rather than a second, more confusing one. The new
   `ollama_tags_fallback_url` strips a trailing `/v1` so the probe can never
   become the malformed `/v1/api/tags`.

2. The resolved discovery URL is now logged at DEBUG, so a wrong base URL is
   diagnosable from app logs without reproducing against the runtime's own
   request log.

3. `gemma4` is not a real Ollama namespace. `MVP_ALLOWED_CHAT_MODELS` carried
   `gemma4:e4b-it-q8_0` and the 16 GB+ preset shipped `gemma4:e4b` for chat
   and vision, so that tier offered a model no `ollama pull` could fetch —
   the "stale or unavailable default" failure mode in the issue. The intended
   model is Gemma 3n, published as `gemma3n:e4b-it-q8_0` (9.5 GB, which is
   what the tier's approx_download_gb was sized against). Verified against
   the public library: gemma3:1b-it-qat, gemma3:4b-it-qat,
   moondream:1.8b-v2-q4_K_S, bge-m3 and gemma3n:e4b-it-q8_0 all resolve;
   gemma4:* does not.

   This also closes a latent second bug: the preset (`gemma4:e4b`) and the
   allowlist (`gemma4:e4b-it-q8_0`) disagreed, so selecting the tier would
   have been silently redirected to gemma3:1b-it-qat by
   enforce_mvp_chat_allowlist. They now agree.

   The tier's `quantization` label moves "qat" -> "q8_0" to match what is
   actually pulled. It is a display string (effective_quantization) and takes
   no part in resolving the model tag.

Tests added: four for the fallback (recovers, original error preserved when
the fallback also fails, empty catalog is not a recovery, non-404 never
probes twice — asserted with a hit counter), one for the fallback URL
derivation, and three guards that no allowlist entry or preset can name the
unpullable gemma4 namespace again.

The Ollama path is untouched: the fallback lives only in
list_lm_studio_models, which a genuine Ollama config never reaches because
diagnostics() takes the /api/tags branch first.

Fixes tinyhumansai#5055
@M3gA-Mind
M3gA-Mind requested a review from a team July 27, 2026 14:48
@M3gA-Mind

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 20 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0c14137b-8fc0-4246-8d0c-82c55d3dbf8b

📥 Commits

Reviewing files that changed from the base of the PR and between e499ce4 and 53f3cdd.

📒 Files selected for processing (3)
  • src/openhuman/inference/local/ollama.rs
  • src/openhuman/inference/local/service/lm_studio.rs
  • src/openhuman/inference/local/service/ollama_admin_tests.rs
📝 Walkthrough

Walkthrough

LM Studio model discovery now falls back from /v1/models 404 responses to host-rooted /api/tags. Local model allowlists, presets, and coverage tests replace retired Gemma 4 identifiers with gemma3n:e4b-it-q8_0.

Changes

LM Studio discovery fallback

Layer / File(s) Summary
Host-rooted endpoint helpers
src/openhuman/inference/local/lm_studio.rs
Native LM Studio and Ollama URLs now derive from a normalized host root, with unit coverage for /v1 and host-rooted bases.
404 discovery recovery
src/openhuman/inference/local/service/lm_studio.rs, src/openhuman/inference/local/service/ollama_admin_tests.rs
A /v1/models 404 triggers one /api/tags attempt; non-empty results recover discovery, while failures, empty catalogs, and non-404 errors preserve the original path.

Gemma model refresh

Layer / File(s) Summary
Allowlist and preset updates
src/openhuman/inference/model_ids.rs, src/openhuman/inference/presets.rs
The MVP allowlist and 16 GB+ preset use gemma3n:e4b-it-q8_0, with tests rejecting retired or incomplete Gemma names.
Raw coverage alignment
tests/raw_coverage/*
Raw coverage configurations, assertions, and Ollama mock defaults now reference Gemma 3n.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LocalAiService
  participant LMStudioModels
  participant OllamaTagsFallback
  participant OllamaTags
  LocalAiService->>LMStudioModels: GET /v1/models
  LMStudioModels-->>LocalAiService: 404 Not Found
  LocalAiService->>OllamaTagsFallback: request fallback catalog
  OllamaTagsFallback->>OllamaTags: GET /api/tags
  OllamaTags-->>OllamaTagsFallback: model catalog
  OllamaTagsFallback-->>LocalAiService: non-empty models or None
Loading

Possibly related issues

  • Issue 5055: The PR implements the LM Studio discovery fallback and Gemma model correction described by the issue.

Possibly related PRs

  • tinyhumansai/openhuman#5067: Both PRs modify LM Studio/OpenAI-compatible endpoint probing and /v1 versus host-rooted endpoint handling.

Suggested labels: rust-core, bug

Suggested reviewers: codeghost21, sanil-23

Poem

A rabbit hops where endpoints grew,
From /v1 paths to tags anew.
Gemma 3n models bloom in line,
Tests guard every model sign.
Thump, thump—discovery’s fine!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main changes: local inference reliability, /api/tags fallback, and updated Ollama model IDs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 27, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e499ce4407

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/openhuman/inference/local/service/lm_studio.rs
Comment thread src/openhuman/inference/local/service/lm_studio.rs Outdated
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes two concrete defects in local model discovery: adds a one-shot /api/tags fallback when /v1/models returns 404, and corrects the 16 GB+ preset and chat allowlist from the non-existent gemma4 Ollama namespace to the real gemma3n:e4b-it-q8_0 build.

  • /api/tags fallback (service/lm_studio.rs, lm_studio.rs, ollama.rs): on a 404-only trigger, probes the host-rooted Ollama endpoint once; guards against LM Studio's error-envelope {"error":…} (distinguishing it from a legitimately empty fresh-Ollama catalog), non-404 status codes, and fallback-also-fails scenarios — all three non-recovery cases are pinned by new integration tests with hit counters.
  • gemma4gemma3n namespace fix (model_ids.rs, presets.rs): replaces every occurrence of the unpullable gemma4:* id with gemma3n:e4b-it-q8_0; regression guards presets_reference_no_unpullable_gemma4_namespace and mvp_chat_allowlist_has_no_unpullable_namespaces prevent the bad namespace from returning. The 16 GB+ preset's vision_mode: Bundled pointing at a text-only model is a known follow-up item acknowledged by the PR author.

Confidence Score: 5/5

Safe to merge; the fallback is gated to 404-only on the OpenAI-compatible LM Studio path and does not touch Ollama or cloud inference.

All three deliberate non-recovery cases (non-404 status, error-envelope response, fallback-itself-fails) are independently verified by integration tests with mock servers. The gemma4→gemma3n rename is a one-for-one string substitution guarded by two new regression tests. The only finding is a duplicate INFO log entry on the empty-catalog recovery branch, which has no runtime impact.

Files Needing Attention: No files require special attention; the core fallback logic in service/lm_studio.rs and URL derivation in lm_studio.rs are well-covered by new tests.

Important Files Changed

Filename Overview
src/openhuman/inference/local/service/lm_studio.rs Adds list_ollama_tags_fallback: a one-shot /api/tags probe triggered only on HTTP 404 from /v1/models. Error-envelope detection (LM Studio {"error":…}) correctly distinguishes fake-empty from real-empty catalogs; non-404 statuses are correctly blocked by the hit-counter test. Minor: empty-catalog recovery emits two consecutive INFO logs.
src/openhuman/inference/local/lm_studio.rs Extracts shared host_root_of helper (strips trailing /v1) and adds ollama_tags_fallback_url; new unit tests cover the host-rooted URL derivation and the malformed /v1/api/tags guard.
src/openhuman/inference/local/ollama.rs Adds error: Option<String> to OllamaTagsResponse with #[serde(default)]; backward-compatible and required to distinguish LM Studio's error-envelope {"error":…} from a genuinely empty Ollama catalog.
src/openhuman/inference/model_ids.rs Replaces non-existent gemma4:e4b-it-q8_0 with gemma3n:e4b-it-q8_0 in MVP_ALLOWED_CHAT_MODELS; adds regression guard mvp_chat_allowlist_has_no_unpullable_namespaces.
src/openhuman/inference/presets.rs Corrects the 16 GB+ tier: gemma4:e4bgemma3n:e4b-it-q8_0 for both chat and vision IDs, and quantization label qatq8_0; adds two regression tests. vision_mode: Bundled with a text-only model remains a known follow-up item (acknowledged by PR author).
src/openhuman/inference/local/service/ollama_admin_tests.rs Adds five new integration tests for the fallback path: happy-path recovery, original-error preservation, error-envelope rejection, empty-catalog recovery, and non-404 no-probe guard (with atomic hit counter).
tests/raw_coverage/inference_local_admin_raw_coverage_e2e.rs Mechanical gemma4:e4b-it-q8_0gemma3n:e4b-it-q8_0 rename throughout the e2e coverage harness to match the corrected model ID.
tests/raw_coverage/inference_provider_admin_round22_raw_coverage_e2e.rs Same mechanical gemma4gemma3n rename in the round-22 coverage harness.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[list_lm_studio_models] --> B[GET /v1/models]
    B --> C{HTTP status?}
    C -->|2xx| D[Parse LmStudioModelsResponse]
    D --> E[Return Ok models]
    C -->|non-404 error| F[Return Err original status]
    C -->|404| G[list_ollama_tags_fallback]
    G --> H[GET /api/tags\nhost_root_of base + /api/tags]
    H --> I{Fallback result?}
    I -->|request error| J[Return None]
    I -->|non-2xx| J
    I -->|parse error| J
    I -->|error envelope present| J
    I -->|models list empty or non-empty| K[Return Some models]
    K --> E
    J --> F
Loading

Reviews (2): Last reviewed commit: "fix(inference): accept a valid empty Oll..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/inference/local/service/ollama_admin_tests.rs`:
- Around line 1322-1345: The test
v1_models_404_reports_the_original_error_when_fallback_also_fails does not
distinguish the primary /v1/models error from the fallback failure. Update the
mock router to make the fallback /api/tags response return a distinct error,
then strengthen the assertion to verify the surfaced error contains the original
/v1/models 404 details rather than the fallback error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bc653390-d3fa-453e-a317-544c4d3d2c0a

📥 Commits

Reviewing files that changed from the base of the PR and between 35f3b1c and e499ce4.

📒 Files selected for processing (7)
  • src/openhuman/inference/local/lm_studio.rs
  • src/openhuman/inference/local/service/lm_studio.rs
  • src/openhuman/inference/local/service/ollama_admin_tests.rs
  • src/openhuman/inference/model_ids.rs
  • src/openhuman/inference/presets.rs
  • tests/raw_coverage/inference_local_admin_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_provider_admin_round22_raw_coverage_e2e.rs

Comment thread src/openhuman/inference/local/service/ollama_admin_tests.rs
… tests (tinyhumansai#5055)

P2 (Codex) — the /api/tags fallback rejected an EMPTY catalog, but
`{"models":[]}` is exactly what a fresh Ollama with nothing pulled returns.
Treating it as a failure hid a reachable runtime behind the original 404, so
availability/bootstrap reported a degraded error and the UI could not offer
the model-download action.

The real LM Studio signal is an error envelope, not emptiness: it answers
unknown paths with `200 {"error": …}` and no models (tinyhumansai#5053). `OllamaTagsResponse`
now carries an optional `error` field and the fallback branches on that,
accepting an empty `models` array as a successful zero-model catalog. The
field is `#[serde(default)]` and the type is only ever deserialized, so no
construction sites change.

Minor (CodeRabbit) — `v1_models_404_reports_the_original_error_when_fallback_also_fails`
was not actually distinguishing the two errors: Axum's implicit fallback route
also answers 404, so the assertion passed even if the implementation surfaced
the /api/tags failure. The mock now returns a distinct 503 for /api/tags and
the test asserts the 404 survives AND the 503 does not leak.

Splits the old empty-catalog test into the two cases it was conflating:
an error envelope is still not a recovery, an empty catalog now is.
@M3gA-Mind

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Fix local model reliability: validate local model behavior in Tiny Agents and correct provider configuration

1 participant