Skip to content

fix(providers): increase model probe timeout for local LLM servers#515

Merged
penso merged 2 commits intomainfrom
time-fabrosaurus
Mar 28, 2026
Merged

fix(providers): increase model probe timeout for local LLM servers#515
penso merged 2 commits intomainfrom
time-fabrosaurus

Conversation

@penso
Copy link
Copy Markdown
Collaborator

@penso penso commented Mar 28, 2026

Summary

  • Increase models.test and provider validation probe timeouts from 10s to 30s to accommodate local LLM servers that need time to load models into memory before responding
  • Treat timeout as non-blocking in the single-model save flow — save the model with a console warning instead of showing an error and refusing to save
  • Show a neutral "Slow" badge (instead of the alarming red "Unsupported") for timed-out probes in the multi-model selector, with tooltip "Slow to respond (may still work)"
  • Add isTimeoutError() helper to distinguish timeout from other probe failures

Closes #514

Validation

Completed

  • cargo +nightly-2025-11-30 fmt --all -- --check passes
  • cargo clippy -p moltis-chat -p moltis-provider-setup --all-targets -- -D warnings passes
  • biome check --write on changed JS files
  • model_probe_succeeds_with_slow_start_provider — SlowStartProvider with 2s delay succeeds within 30s timeout
  • model_probe_times_out_for_unresponsive_provider — 120s delay provider correctly times out at ~30s

Remaining

  • ./scripts/local-validate.sh 515 (full validation suite)
  • Manual QA with a local LLM server (llama.cpp or Ollama)

Manual QA

  1. Start a local OpenAI-compatible LLM server with a large model that takes >10s to load
  2. Settings → LLM → Add LLM → select "Local LLM" or custom OpenAI-compatible
  3. Enter endpoint URL, click next
  4. Select a model from the discovered list
  5. Expected: Model saves successfully (previously would show "Connection timed out")
  6. In multi-model selector, select a slow model
  7. Expected: Shows "Slow" badge (not "Unsupported"), model remains selectable

🤖 Generated with Claude Code

Local LLM servers (llama.cpp, Ollama, etc.) often need 10-20+ seconds
to load a model into memory before streaming the first token. The
previous 10-second timeout caused most models to fail selection during
provider setup.

- Increase models.test and validation probe timeouts from 10s to 30s
- Treat timeout as non-blocking in the single-model save flow (save
  the model with a warning instead of rejecting it)
- Show "Slow" badge instead of "Unsupported" for timed-out probes in
  the multi-model selector
- Add regression tests with SlowStartProvider mock

Closes #514

Entire-Checkpoint: 1b5ed6ad8d52
@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq bot commented Mar 28, 2026

Merging this PR will improve performance by 19.39%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 38 untouched benchmarks
⏩ 5 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
env_substitution 12.1 µs 10.1 µs +19.39%

Comparing time-fabrosaurus (636eccd) with main (e77c74d)

Open in CodSpeed

Footnotes

  1. 5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 28, 2026

Greptile Summary

This PR fixes #514 by raising model-probe timeouts from 10 s to 30 s throughout the stack (Rust backend, provider-validation flow, per-probe constant) to support local LLM servers (llama.cpp, Ollama, etc.) that require extra time for a cold-start. On the frontend, timed-out probes are demoted from blocking errors to soft warnings — the model is saved anyway in the single-model flow, and the multi-model selector replaces the alarming red "Unsupported" badge with a neutral "Slow" badge. Two regression tests (one with paused time, so no CI wall-clock cost) guard the 30 s boundary.

Key changes:

  • crates/chat/src/lib.rs: tokio::time::timeout raised 10 s → 30 s; two new unit tests cover the slow-start success path and the genuine-timeout path
  • crates/provider-setup/src/lib.rs: VALIDATION_MAX_TIMEOUTS 3 → 1, VALIDATION_PROBE_TIMEOUT_SECS 10 → 30 — worst-case validation stays at ~30 s
  • provider-validation.js: new isTimeoutError() helper exported from the shared validation module
  • providers.js: timeout bypass + "Slow" hint in the single-model save flow; tier-badge "Slow" instead of provider-item-badge warning "Unsupported" in the multi-model selector

Issue found:

  • onboarding-view.js was not updated alongside providers.js. Its probeModelAsync function (sets probe badge state) and its single-model save flow both lack the isTimeoutError check, so a slow local LLM will still trigger a blocking error in the onboarding wizard and show an "Unsupported" badge — directly contradicting the PR's stated goal for that code path.

Confidence Score: 4/5

Safe to merge for the Settings → Providers flow; however the onboarding wizard retains the blocking-error behavior for slow local LLMs that the PR explicitly aimed to fix.

The Rust backend changes, new tests, and providers.js fixes are all correct. The one remaining P1 is that onboarding-view.js — which shares the same probeModelAsync / testModel pattern — was not updated: timeout still aborts the onboarding save and still renders "Unsupported". This directly contradicts the PR's stated goals for new users setting up a local LLM during onboarding, so a 4 is appropriate until that path is patched.

crates/web/src/assets/js/onboarding-view.js — both probeModelAsync and the single-model save block need the same isTimeoutError treatment applied to providers.js

Important Files Changed

Filename Overview
crates/chat/src/lib.rs Timeout increased from 10 s to 30 s; two regression tests added — slow-start (2 s delay, real time) and stuck (120 s delay, paused clock via start_paused = true so no CI wall-clock cost). No issues found.
crates/provider-setup/src/lib.rs VALIDATION_MAX_TIMEOUTS reduced 3 → 1 and VALIDATION_PROBE_TIMEOUT_SECS raised 10 → 30; worst-case validation time stays at ~30 s (addresses previous reviewer concern). No issues found.
crates/web/src/assets/js/provider-validation.js Adds isTimeoutError() helper that checks for "timeout"/"timed out" substrings; correctly handles null/non-string input. No issues found.
crates/web/src/assets/js/providers.js Single-model save correctly bypasses timeout errors and shows a "Slow" hint; multi-model selector shows neutral tier-badge "Slow" instead of warning "Unsupported". The same treatment is not applied to the parallel code paths in onboarding-view.js, which still blocks saves on timeout and shows "Unsupported".

Sequence Diagram

sequenceDiagram
    participant User
    participant providers.js
    participant onboarding-view.js
    participant provider-validation.js
    participant Rust

    Note over providers.js,Rust: Single-model save (providers.js — UPDATED)
    User->>providers.js: Select model, click Save
    providers.js->>Rust: testModel(modelId)
    Rust-->>providers.js: timeout after 30s
    providers.js->>provider-validation.js: isTimeoutError(error)
    provider-validation.js-->>providers.js: true
    providers.js->>providers.js: Save model + show Slow hint ✅

    Note over onboarding-view.js,Rust: Single-model save (onboarding-view.js — NOT UPDATED)
    User->>onboarding-view.js: Select model, complete onboarding
    onboarding-view.js->>Rust: testModel(modelVal)
    Rust-->>onboarding-view.js: timeout after 30s
    onboarding-view.js->>onboarding-view.js: setError, return — blocks save ❌

    Note over providers.js,Rust: Probe badge (providers.js — UPDATED)
    providers.js->>Rust: testModel(modelId)
    Rust-->>providers.js: timeout
    providers.js->>provider-validation.js: isTimeoutError(error)
    provider-validation.js-->>providers.js: true
    providers.js->>providers.js: badge = tier-badge Slow ✅

    Note over onboarding-view.js,Rust: Probe badge (onboarding-view.js — NOT UPDATED)
    onboarding-view.js->>Rust: testModel(modelId)
    Rust-->>onboarding-view.js: timeout
    onboarding-view.js->>onboarding-view.js: badge = provider-item-badge warning Unsupported ❌
Loading

Reviews (2): Last reviewed commit: "fix(providers): address PR review feedba..." | Re-trigger Greptile

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 28, 2026

Codecov Report

❌ Patch coverage is 88.88889% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/chat/src/lib.rs 88.88% 8 Missing ⚠️

📢 Thoughts on this report? Let us know!

- Use tokio start_paused=true in timeout test to avoid 30s CI wait
- Reduce VALIDATION_MAX_TIMEOUTS from 3 to 1 (worst-case stays ~30s)
- Show user-visible hint when model save succeeds despite timeout
- Extend modal auto-close to 3.5s when slow hint is shown

Entire-Checkpoint: 79aa5c9d511d
@penso penso merged commit 34dbd45 into main Mar 28, 2026
15 of 23 checks passed
@penso penso deleted the time-fabrosaurus branch March 28, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Most models can't be selected

1 participant