Skip to content

Add LM Studio as a local model provider - #1750

Merged
senamakel merged 9 commits into
tinyhumansai:mainfrom
EvanWangZ:codex/OH-1673-lm-studio-local-provider
May 15, 2026
Merged

senamakel merged 9 commits into
tinyhumansai:mainfrom
EvanWangZ:codex/OH-1673-lm-studio-local-provider

Conversation

@EvanWangZ

@EvanWangZ EvanWangZ commented May 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds LM Studio as a first-class local AI provider alongside Ollama.
  • Wires LM Studio provider config through Rust config schemas, persistence, Tauri config mapping, routing, diagnostics, and local inference.
  • Implements LM Studio model discovery and chat completion calls against its OpenAI-compatible local server API.
  • Updates local AI docs, capability catalog entries, and the test coverage matrix.
  • Fixes Codex PR preflight path validation so /workspace/openhuman symlinked checkouts pass strict path checks.

Problem

  • Closes Add LM Studio as a local model provider alongside Ollama #1673: users who already run LM Studio could not configure OpenHuman to use it as a local model provider.
  • The existing local model path was effectively Ollama-only, creating setup friction and duplicated local model downloads for LM Studio users.
  • The provider integration needed to preserve existing core routing boundaries instead of adding transport-specific shortcuts.

Solution

  • Adds typed provider normalization for ollama and lm_studio, including lm-studio input compatibility.
  • Adds LM Studio API helpers for /v1/models and /v1/chat/completions, then uses them from local AI admin, diagnostics, prompt, and chat flows.
  • Extends config apply/schema/RPC paths so LM Studio settings round-trip through the core and app config bridge.
  • Keeps Ollama behavior as the default and preserves existing hosted OpenHuman backend URL handling.
  • Adds Rust unit coverage, JSON-RPC E2E coverage, and focused app config tests for the new provider surface.

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
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/coverage.yml. Run pnpm test:coverage and pnpm test:rust locally; PRs below 80% on changed lines will not merge.
  • Coverage matrix updated — added/removed/renamed feature rows in docs/TEST-COVERAGE-MATRIX.md reflect this change (or N/A: behaviour-only change)
  • 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)
  • N/A: Manual smoke checklist update not needed because no release-cut-only surface was added; LM Studio behavior is covered by Rust, JSON-RPC, and focused app config tests.
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

  • Desktop local AI users can configure LM Studio and use locally served models through the OpenAI-compatible LM Studio server.
  • Ollama remains the default local provider and existing Ollama model flows are preserved.
  • No migration is required; new LM Studio config fields default to localhost-compatible values.
  • No new external network dependency is introduced. Tests use local mock servers.

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: codex/OH-1673-lm-studio-local-provider
  • Commit SHA: 8cbd2f63476a3a246439081e25893fa064edd453

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: bash scripts/test-rust-with-mock.sh api::config::tests -- --nocapture; pnpm --dir app exec vitest run src/utils/tauriCommands/config.test.ts --config test/vitest.config.ts
  • Rust fmt/check (if changed): cargo fmt --manifest-path Cargo.toml --all --check; cargo check --manifest-path Cargo.toml; pnpm test:rust
  • Tauri fmt/check (if changed): cargo fmt --manifest-path app/src-tauri/Cargo.toml --all --check; cargo check --manifest-path app/src-tauri/Cargo.toml

Additional validation:

  • node scripts/test-codex-pr-preflight.mjs
  • cd /workspace/openhuman && node scripts/codex-pr-preflight.mjs --strict-path --lightweight
  • pnpm lint
  • pnpm test:coverage
  • git diff --check
  • Duplicate PR search: no open PRs found for LM Studio, local model provider, or lmstudio.

Validation Blocked

  • command: N/A — no validation command is blocked.
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: LM Studio is now a supported local AI provider alongside Ollama.
  • User-visible effect: users can configure LM Studio local server settings, list usable LM Studio models, and route local inference through LM Studio.

Parity Contract

  • Legacy behavior preserved: Ollama remains the default provider; existing Ollama diagnostics, pull/status, and inference paths remain available.
  • Guard/fallback/dispatch parity checks: provider dispatch remains in the core local AI/routing layers; hosted OpenHuman backend endpoints are not misclassified as local AI endpoints.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): None found.
  • Canonical PR: This PR from codex/OH-1673-lm-studio-local-provider.
  • Resolution (closed/superseded/updated): N/A

Summary by CodeRabbit

  • New Features

    • Optional LM Studio local-AI provider and related provider-selection, opt-in, and model ID controls.
  • Behavior

    • Local runtime can route to LM Studio for model discovery, chat completions, diagnostics, and provider-aware status; improved base-URL normalization and fallback handling.
  • Documentation

    • Expanded LM Studio setup, troubleshooting, and opt-in guidance.
  • Config

    • New optional example env/config entry to override LM Studio base URL.
  • Tests

    • Added unit, integration, and end-to-end coverage for LM Studio flows.

Review Change Stack

@EvanWangZ
EvanWangZ requested a review from a team May 14, 2026 15:56
@coderabbitai

coderabbitai Bot commented May 14, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds LM Studio as a selectable local AI provider: new config fields and RPC mappings, LM Studio base-URL normalization and OpenAI-compatible DTOs, provider-selection helpers, service wiring (availability, models, chat completions, diagnostics, assets/bootstrap), routing factory changes, docs updates, and comprehensive tests including an e2e JSON-RPC scenario.

Changes

LM Studio Local AI Integration

Layer / File(s) Summary
Docs, env example, and preflight
.env.example, docs/*, gitbooks/*, scripts/codex-pr-preflight.mjs, scripts/test-codex-pr-preflight.mjs
Document OPENHUMAN_LM_STUDIO_BASE_URL, update docs/readme and preflight script/fixtures.
App tests & e2e script
app/src/*, app/scripts/e2e-run-session.sh, app/.prettierignore
Front-end tests use env-driven backend URL and reset user id between tests; e2e cleanup hardened and test artifacts ignored.
API backend URL logic
src/api/config.rs
Add hosted-backend detection, normalize effective backend override behavior, add URL redaction for logs, and refactor tests for deterministic fallback base.
Config RPC & apply logic
src/openhuman/config/schemas.rs, src/openhuman/config/ops.rs, tests
Expose new optional local-AI inputs (opt_in_confirmed, provider, base_url, model_id, chat_model_id) and persist/normalize them; add unit tests for LM Studio fields.
Local AI docs & schema comments
src/openhuman/config/schema/local_ai.rs, src/openhuman/local_ai/README.md, gitbooks/features/model-routing/local-ai.md
Update docs and Rust doc comments to describe LM Studio provider, defaults, and troubleshooting.
LM Studio API module
src/openhuman/local_ai/lm_studio_api.rs
Add base-URL normalization, DEFAULT_LM_STUDIO_BASE_URL, auth application helper, and OpenAI-compatible DTOs with unit tests.
Provider helpers & model-id logic
src/openhuman/local_ai/provider.rs, src/openhuman/local_ai/model_ids.rs
Add LocalAiProvider enum, normalization, provider_from_config, and LM Studio-specific chat-model passthrough behavior with tests.
Service: LM Studio core methods
src/openhuman/local_ai/service/lm_studio.rs
Implement ensure_lm_studio_available, list_lm_studio_models, has_lm_studio_model, and lm_studio_chat_completion (timeouts, auth, parsing, token usage).
Service wiring: assets/bootstrap/public infer/diagnostics
src/openhuman/local_ai/service/*, src/openhuman/local_ai/service/ollama_admin.rs
Make assets/bootstrap/public_infer provider-aware, add LM Studio diagnostics branch and tests, update model-path mapping and download logic.
Routing factory & provider docs
src/openhuman/routing/factory.rs, src/openhuman/routing/provider.rs
Normalize provider config in routing, add LM Studio local branch probing /v1/models, and update documentation.
Integration tests & e2e
tests/json_rpc_e2e.rs, various *_tests.rs
Add JSON-RPC e2e that mocks LM Studio endpoints, plus unit/integration tests covering diagnostics, public_infer, assets, and schema deserialize cases.
Test infra and event recording
src/openhuman/agent/triage/events.rs, src/openhuman/accessibility/*, other tests
Add test event recording helpers, centralize test locks, and refactor tests to polling-based collection and shared locks.

Sequence Diagram

sequenceDiagram
  participant Client
  participant LocalAiService
  participant ConfigStore
  participant LMStudioServer
  Client->>LocalAiService: request chat (provider=lm_studio, messages)
  LocalAiService->>ConfigStore: read local_ai config (base_url, model_id, api_key)
  LocalAiService->>LMStudioServer: GET {base}/models (health)
  LMStudioServer-->>LocalAiService: models list
  LocalAiService->>LMStudioServer: POST {base}/chat/completions (payload)
  LMStudioServer-->>LocalAiService: chat completion response
  LocalAiService-->>Client: assistant reply (tokens/metadata)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • senamakel

Poem

🐇 A curious rabbit found a new tune,

LM Studio hums beneath the moon.
Two runtimes now, both snug and neat,
Local models ready, prompt and sweet.
Hooray — small hops, large leaps, and a treat!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add LM Studio as a local model provider' directly and clearly describes the main change—adding LM Studio support alongside Ollama, which is the primary objective of the PR.
Linked Issues check ✅ Passed The PR comprehensively implements all acceptance criteria from issue #1673: users can configure LM Studio as a provider [app config routes], detect/connect to LM Studio servers with error handling [lm_studio.rs diagnostics], list/select models with parity to Ollama [model discovery via /v1/models], core routing avoids one-off logic [provider.rs abstractions, routing/factory.rs], documentation is updated [local-ai.md], and tests cover core/app flows [lm_studio_api.rs tests, e2e JSON-RPC test].
Out of Scope Changes check ✅ Passed All changes directly support LM Studio provider integration. The codex-pr-preflight and e2e-run-session.sh updates fix preflight/test infrastructure for symlinked checkouts and teardown resilience, both necessary for CI/test workflows. The accessibility/automation_state and config/load refactors extract test-lock helpers for shared synchronization—supporting test isolation required by the new LM Studio test suite. No extraneous changes present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

@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: 2

🧹 Nitpick comments (2)
src/openhuman/config/ops.rs (1)

586-595: ⚡ Quick win

Allow explicit clearing for local model IDs.

Line 586 and Line 591 currently ignore empty/whitespace values, so clients cannot clear previously persisted model_id/chat_model_id via RPC.

💡 Proposed fix
     if let Some(model_id) = update.model_id {
-        if !model_id.trim().is_empty() {
-            config.local_ai.model_id = model_id.trim().to_string();
-        }
+        config.local_ai.model_id = model_id.trim().to_string();
     }
     if let Some(chat_model_id) = update.chat_model_id {
-        if !chat_model_id.trim().is_empty() {
-            config.local_ai.chat_model_id = chat_model_id.trim().to_string();
-        }
+        config.local_ai.chat_model_id = chat_model_id.trim().to_string();
     }
🤖 Prompt for 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.

In `@src/openhuman/config/ops.rs` around lines 586 - 595, The current code ignores
Some("")/whitespace for update.model_id and update.chat_model_id so clients
can't clear persisted values; remove the !trim().is_empty() guard and always
assign the trimmed string when the Option is Some. Specifically, change the
blocks handling update.model_id and update.chat_model_id so that if let
Some(model_id) = update.model_id { config.local_ai.model_id =
model_id.trim().to_string(); } and similarly for config.local_ai.chat_model_id,
allowing explicit clearing by sending an empty/whitespace value.
src/openhuman/local_ai/service/bootstrap.rs (1)

306-309: ⚡ Quick win

Prefer the new model_path_for_config helper for consistency.

The new model_path_for_config helper (lines 395–401) exists to compute provider-specific URIs, but this code still hardcodes the ollama:// format. While functionally correct (this path only runs for Ollama after the LM Studio early return), using the helper ensures a single source of truth for model path formatting.

♻️ Proposed refactor to use the helper
-        status.model_path = Some(format!(
-            "ollama://{}",
-            model_ids::effective_chat_model_id(&effective_config)
-        ));
+        status.model_path = Some(model_path_for_config(&effective_config));
🤖 Prompt for 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.

In `@src/openhuman/local_ai/service/bootstrap.rs` around lines 306 - 309, Replace
the hardcoded Ollama URI assignment to status.model_path with a call to the new
model_path_for_config helper so formatting is consistent: instead of
constructing "ollama://{}" with
model_ids::effective_chat_model_id(&effective_config), call
model_path_for_config(&effective_config, /* pass effective chat model id or the
config that function expects */) and assign its Some(...) result to
status.model_path; update references to
model_ids::effective_chat_model_id(&effective_config) only if
model_path_for_config already uses the effective_config internally.
🤖 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/api/config.rs`:
- Around line 148-159: The URL-classification function
looks_like_openhuman_backend_endpoint currently returns boolean without emitting
diagnostics; add grep-friendly debug/trace logging inside the function showing
the incoming URL, parse success/failure, extracted host (if any), and final
match decision (e.g., "classified as openhuman backend" vs "not classified"),
using the project's logging macros (debug! or trace!); also add similar
debug/trace messages at the calling routing branch (the fallback/warn path
referenced around the other routing logic) so branch selection and misroutes are
easily traceable.

In `@src/openhuman/local_ai/lm_studio_api.rs`:
- Around line 12-66: Add verbose diagnostics to LM Studio URL/auth resolution:
instrument lm_studio_base_url_from_local_ai to trace each candidate source
inspected (env vars and local_ai.base_url), which candidate passed to
normalize_lm_studio_base_url, and log the final chosen base URL or that
DEFAULT_LM_STUDIO_BASE_URL was used, using a stable grep-friendly prefix like
"[lm-studio]". In normalize_lm_studio_base_url add trace logs for the raw input,
the trimmed/with_scheme result, the without_known_endpoint result, and whether
"/v1" was appended. In apply_lm_studio_auth log whether an API key was present
and applied (e.g. "[lm-studio] auth applied: yes/no") but never log the full key
(only indicate presence/length or masked form). Use the project's standard
logging/tracing macros (trace!/debug!) consistent with other core code.

---

Nitpick comments:
In `@src/openhuman/config/ops.rs`:
- Around line 586-595: The current code ignores Some("")/whitespace for
update.model_id and update.chat_model_id so clients can't clear persisted
values; remove the !trim().is_empty() guard and always assign the trimmed string
when the Option is Some. Specifically, change the blocks handling
update.model_id and update.chat_model_id so that if let Some(model_id) =
update.model_id { config.local_ai.model_id = model_id.trim().to_string(); } and
similarly for config.local_ai.chat_model_id, allowing explicit clearing by
sending an empty/whitespace value.

In `@src/openhuman/local_ai/service/bootstrap.rs`:
- Around line 306-309: Replace the hardcoded Ollama URI assignment to
status.model_path with a call to the new model_path_for_config helper so
formatting is consistent: instead of constructing "ollama://{}" with
model_ids::effective_chat_model_id(&effective_config), call
model_path_for_config(&effective_config, /* pass effective chat model id or the
config that function expects */) and assign its Some(...) result to
status.model_path; update references to
model_ids::effective_chat_model_id(&effective_config) only if
model_path_for_config already uses the effective_config internally.
🪄 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: f228fb69-59c4-4110-9b73-f3f8c0f6e14b

📥 Commits

Reviewing files that changed from the base of the PR and between 4d5e0d5 and 8cbd2f6.

📒 Files selected for processing (34)
  • .env.example
  • app/src/utils/tauriCommands/config.test.ts
  • app/src/utils/tauriCommands/config.ts
  • docs/TEST-COVERAGE-MATRIX.md
  • docs/agent-workflows/codex-pr-checklist.md
  • gitbooks/README.md
  • gitbooks/features/model-routing/local-ai.md
  • scripts/codex-pr-preflight.mjs
  • scripts/test-codex-pr-preflight.mjs
  • src/api/config.rs
  • src/openhuman/about_app/catalog.rs
  • src/openhuman/about_app/catalog_tests.rs
  • src/openhuman/config/ops.rs
  • src/openhuman/config/ops_tests.rs
  • src/openhuman/config/schema/local_ai.rs
  • src/openhuman/config/schemas.rs
  • src/openhuman/config/schemas_tests.rs
  • src/openhuman/local_ai/README.md
  • src/openhuman/local_ai/lm_studio_api.rs
  • src/openhuman/local_ai/mod.rs
  • src/openhuman/local_ai/model_ids.rs
  • src/openhuman/local_ai/provider.rs
  • src/openhuman/local_ai/service/assets.rs
  • src/openhuman/local_ai/service/bootstrap.rs
  • src/openhuman/local_ai/service/lm_studio.rs
  • src/openhuman/local_ai/service/mod.rs
  • src/openhuman/local_ai/service/ollama_admin.rs
  • src/openhuman/local_ai/service/ollama_admin_tests.rs
  • src/openhuman/local_ai/service/public_infer.rs
  • src/openhuman/local_ai/service/public_infer_tests.rs
  • src/openhuman/local_ai/types.rs
  • src/openhuman/routing/factory.rs
  • src/openhuman/routing/provider.rs
  • tests/json_rpc_e2e.rs

Comment thread src/api/config.rs Resolved
Comment thread src/openhuman/local_ai/lm_studio_api.rs Resolved
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 14, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 14, 2026

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/openhuman/local_ai/model_ids.rs (1)

3-6: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale module docs to reflect LM Studio allowlist bypass.

The rustdoc says all effective_* functions enforce MVP allowlists, but effective_chat_model_id now bypasses that logic for LM Studio. Please align the comment with current behavior.

🤖 Prompt for 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.

In `@src/openhuman/local_ai/model_ids.rs` around lines 3 - 6, Update the module
doc to reflect that not all effective_* helpers enforce the MVP allowlist:
specifically note that effective_chat_model_id bypasses the MVP allowlist for LM
Studio model IDs (while other effective_* functions still fall back to the
default MVP model and log a warning when an ID is not allowed). Mention the
rationale succinctly and reference effective_chat_model_id and the generic
effective_* helpers so reviewers can find and reconcile the documentation with
the implemented behavior.
🤖 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/local_ai/model_ids.rs`:
- Around line 77-79: Add grep-friendly debug/trace diagnostics around the new LM
Studio branch and the empty-model return in model_ids.rs: when evaluating
provider_from_config(config) and matching LocalAiProvider::LmStudio, emit a
trace/debug log with a stable prefix like "[local_ai]" indicating the chosen
branch and config details; likewise, in raw_chat_model_id (and the empty-model
return path referenced around lines 100-111) emit a trace/debug log with
"[local_ai]" explaining that an empty model ID is being returned and any
relevant inputs. Use the crate’s tracing/log macros (trace! or debug!) for both
spots and keep messages concise and grep-friendly.

---

Outside diff comments:
In `@src/openhuman/local_ai/model_ids.rs`:
- Around line 3-6: Update the module doc to reflect that not all effective_*
helpers enforce the MVP allowlist: specifically note that
effective_chat_model_id bypasses the MVP allowlist for LM Studio model IDs
(while other effective_* functions still fall back to the default MVP model and
log a warning when an ID is not allowed). Mention the rationale succinctly and
reference effective_chat_model_id and the generic effective_* helpers so
reviewers can find and reconcile the documentation with the implemented
behavior.
🪄 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: 90607537-5ad1-4abe-a898-05998f4381b7

📥 Commits

Reviewing files that changed from the base of the PR and between c73af4e and 942c099.

📒 Files selected for processing (8)
  • app/scripts/e2e-run-session.sh
  • src/openhuman/about_app/catalog.rs
  • src/openhuman/config/schema/local_ai.rs
  • src/openhuman/local_ai/mod.rs
  • src/openhuman/local_ai/model_ids.rs
  • src/openhuman/local_ai/service/lm_studio.rs
  • src/openhuman/routing/factory.rs
  • src/openhuman/routing/provider.rs
✅ Files skipped from review due to trivial changes (2)
  • src/openhuman/routing/provider.rs
  • src/openhuman/config/schema/local_ai.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/openhuman/local_ai/mod.rs
  • src/openhuman/about_app/catalog.rs
  • app/scripts/e2e-run-session.sh
  • src/openhuman/routing/factory.rs
  • src/openhuman/local_ai/service/lm_studio.rs

Comment thread src/openhuman/local_ai/model_ids.rs Resolved
@senamakel

Copy link
Copy Markdown
Member

fuck yeah.. LM studio FTW

@senamakel senamakel self-assigned this May 15, 2026

@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: 2

🤖 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/local_ai/service/lm_studio.rs`:
- Around line 44-51: The LM Studio HTTP call paths return Err(String) but lack
structured tracing—add tracing::debug/trace/span logs on each failure branch in
lm_studio.rs (around the HTTP send and subsequent status/body/parse handling).
Specifically, instrument the request/send that uses apply_lm_studio_auth(...)
and the response handling (the branches that map_err like "lm studio models
request failed" and the status/body/parse error branches referenced at ranges
53-74, 133-136, 138-157) to emit contextual fields (url, status, error = %e,
maybe body snippet) so callers can triage; keep existing Err(String) returns but
also call tracing::debug! or tracing::trace! with structured key-value fields
immediately before returning the error.

In `@src/openhuman/local_ai/service/ollama_admin.rs`:
- Around line 1048-1052: The code sets healthy = models_result.is_ok(), which
makes the models_error branch unreachable when healthy is true and collapses
parse/auth/status errors into a generic "server not running" case; modify the
health computation so it reflects the actual upstream status separate from
models_result success (e.g., compute healthy from a distinct status check or
include status_result), and preserve the original models_result error into
models_error when Err(err) so detailed errors are surfaced even if healthy is
true; update the matching logic around models_result (and the analogous block at
1093-1097) to set healthy and models_error independently while keeping the
existing variable names models_result, models_error, and healthy so callers
(e.g., response construction) can report specific parse/auth/status diagnostics.
🪄 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: a6306e20-fcfa-4afc-bc74-3e827ba58e0f

📥 Commits

Reviewing files that changed from the base of the PR and between 942c099 and e6e3291.

📒 Files selected for processing (3)
  • src/api/config.rs
  • src/openhuman/local_ai/service/lm_studio.rs
  • src/openhuman/local_ai/service/ollama_admin.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/api/config.rs

EvanWangZ and others added 7 commits May 16, 2026 00:30
…routing)

- Resolved merge conflict in app/scripts/e2e-run-session.sh (kept PR retry-loop cleanup)
- Resolved merge conflict in src/openhuman/local_ai/mod.rs (include install_piper, install_whisper, lm_studio_api, provider, voice_install_common)
- src/openhuman/local_ai/service/lm_studio.rs: add #[allow(dead_code)] + doc comment to lm_studio_healthy
- src/openhuman/routing/factory.rs: replace inline provider alias match with normalize_provider call
- src/openhuman/local_ai/model_ids.rs: raw_chat_model_id no longer falls back to DEFAULT_OLLAMA_MODEL for LM Studio; returns empty string + new test lm_studio_chat_model_returns_empty_when_no_model_configured
…nostics

- Add 120 s timeout to LM Studio chat completion requests so long
  inference runs don't block indefinitely (lm_studio.rs)
- Relax ensure_lm_studio_available to probe connectivity only; remove
  the dead lm_studio_healthy fn that carried an #[allow(dead_code)]
  attr — the "no models loaded" check was a hard error that prevented
  bootstrap; the UI surfaces an actionable CTA instead (lm_studio.rs)
- Make redact_url_for_log handle bare-host URLs (e.g. "localhost:1234")
  by retrying with an "http://" prefix so they are redacted consistently
  rather than returned verbatim (src/api/config.rs)
- Guard the duplicate models_error issue push behind `if healthy` in
  ollama_admin so the low-level error is only surfaced when the server
  appeared healthy but model-listing failed; the existing "not running"
  issue is already the canonical message for unreachable servers
  (ollama_admin.rs)
@EvanWangZ
EvanWangZ force-pushed the codex/OH-1673-lm-studio-local-provider branch from 5cf65fc to c67fc55 Compare May 15, 2026 16:45
@EvanWangZ

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

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 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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/openhuman/local_ai/service/assets.rs (1)

28-56: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add provider-branch diagnostics for the new LM Studio/Ollama routing paths.

The new provider decision branches should emit debug/trace logs (entry/branch/exit) with stable prefixes and correlation fields so runtime routing is observable.

As per coding guidelines: "src/**/*.rs: In Rust, use log / tracing at debug or trace level for development-oriented diagnostics on new/changed flows, including logs at entry/exit points, branch decisions, external calls, retries/timeouts, state transitions, and error handling paths."

Also applies to: 308-318, 401-411

🤖 Prompt for 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.

In `@src/openhuman/local_ai/service/assets.rs` around lines 28 - 56, Add
trace/debug diagnostics around the provider routing flow: at entry of the
function that calls provider_from_config, emit a trace with a stable prefix
(e.g., "assets:provider_routing") and a correlation_id/context; log the selected
provider (provider_from_config result) and the branch taken
(LocalAiProvider::LmStudio vs LocalAiProvider::Ollama vs default) before calling
ollama_binary_present, has_lm_studio_model, or has_model; on each external check
(ollama_binary_present, has_lm_studio_model, has_model) log a debug with the
target model name and result/Err (unwrap_or paths too), and add an exit trace
summarizing chat_ready/vision_ready/embedding_ready so routing decisions are
observable (reference functions: provider_from_config, ollama_binary_present,
has_lm_studio_model, has_model and enum LocalAiProvider).
🤖 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/agent/triage/events.rs`:
- Around line 14-48: TEST_EVENTS is a global test mutex that accumulates events
across tests causing cross-test leakage; add a test-only reset function (e.g.,
pub(crate) fn clear_test_events() or reset_test_events()) that locks TEST_EVENTS
(using the same lock/unwrap_or_else pattern as record_test_event) and calls
clear() on the inner Vec, and export it so tests can call it in their
setup/teardown; reference TEST_EVENTS, record_test_event, and
test_events_for_external_id when adding this new reset function.

In `@src/openhuman/local_ai/service/assets.rs`:
- Around line 155-164: The LM Studio branch currently sets provider to "ollama"
but leaves path as None and sets a warning, which contradicts later logic that
bypasses Ollama model bootstrap and blocks embedding downloads; update the
LocalAiProvider::LmStudio handling so that when provider ==
LocalAiProvider::LmStudio you also set path to the same Ollama embedding path
used for Ollama models (instead of None), and adjust the bootstrap/download
logic (the condition that currently bypasses Ollama model bootstrap and the
block that prevents `embedding` downloads) to treat LmStudio the same as Ollama
so embeddings can be downloaded and initialized; keep or update the warning text
to reflect that embeddings use the Ollama path.

In `@src/openhuman/local_ai/service/ollama_admin.rs`:
- Around line 1083-1101: The current logic can push "load_lm_studio_model"
repairs even when models listing failed (models_error is Some), which is
misleading; update the conditional guards around the blocks that inspect models
and chat presence so they only run when models_error.is_none(): change the first
branch that checks healthy && models.is_empty() to require healthy &&
models_error.is_none() && models.is_empty(), and similarly require
models_error.is_none() for the branch that checks chat_found/expected_chat
before pushing a load action; keep the existing separate block that, when
healthy and models_error.is_some(), pushes the "Failed to list LM Studio models:
{err}" issue without suggesting load actions.

---

Outside diff comments:
In `@src/openhuman/local_ai/service/assets.rs`:
- Around line 28-56: Add trace/debug diagnostics around the provider routing
flow: at entry of the function that calls provider_from_config, emit a trace
with a stable prefix (e.g., "assets:provider_routing") and a
correlation_id/context; log the selected provider (provider_from_config result)
and the branch taken (LocalAiProvider::LmStudio vs LocalAiProvider::Ollama vs
default) before calling ollama_binary_present, has_lm_studio_model, or
has_model; on each external check (ollama_binary_present, has_lm_studio_model,
has_model) log a debug with the target model name and result/Err (unwrap_or
paths too), and add an exit trace summarizing
chat_ready/vision_ready/embedding_ready so routing decisions are observable
(reference functions: provider_from_config, ollama_binary_present,
has_lm_studio_model, has_model and enum LocalAiProvider).
🪄 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: ea4f97ea-685f-473c-a613-deabeb9eb611

📥 Commits

Reviewing files that changed from the base of the PR and between 942c099 and c67fc55.

📒 Files selected for processing (45)
  • .env.example
  • app/.prettierignore
  • app/scripts/e2e-run-session.sh
  • app/src/providers/__tests__/CoreStateProvider.test.tsx
  • app/src/services/api/__tests__/authApi.test.ts
  • app/src/utils/tauriCommands/config.test.ts
  • app/src/utils/tauriCommands/config.ts
  • docs/TEST-COVERAGE-MATRIX.md
  • docs/agent-workflows/codex-pr-checklist.md
  • gitbooks/README.md
  • gitbooks/features/model-routing/local-ai.md
  • scripts/codex-pr-preflight.mjs
  • scripts/test-codex-pr-preflight.mjs
  • src/api/config.rs
  • src/openhuman/about_app/catalog.rs
  • src/openhuman/about_app/catalog_tests.rs
  • src/openhuman/accessibility/automation_state.rs
  • src/openhuman/accessibility/permissions_tests.rs
  • src/openhuman/agent/triage/escalation.rs
  • src/openhuman/agent/triage/events.rs
  • src/openhuman/config/ops.rs
  • src/openhuman/config/ops_tests.rs
  • src/openhuman/config/schema/load.rs
  • src/openhuman/config/schema/load_tests.rs
  • src/openhuman/config/schema/local_ai.rs
  • src/openhuman/config/schemas.rs
  • src/openhuman/config/schemas_tests.rs
  • src/openhuman/local_ai/README.md
  • src/openhuman/local_ai/lm_studio_api.rs
  • src/openhuman/local_ai/mod.rs
  • src/openhuman/local_ai/model_ids.rs
  • src/openhuman/local_ai/provider.rs
  • src/openhuman/local_ai/service/assets.rs
  • src/openhuman/local_ai/service/bootstrap.rs
  • src/openhuman/local_ai/service/lm_studio.rs
  • src/openhuman/local_ai/service/mod.rs
  • src/openhuman/local_ai/service/ollama_admin.rs
  • src/openhuman/local_ai/service/ollama_admin_tests.rs
  • src/openhuman/local_ai/service/public_infer.rs
  • src/openhuman/local_ai/service/public_infer_tests.rs
  • src/openhuman/local_ai/types.rs
  • src/openhuman/routing/factory.rs
  • src/openhuman/routing/provider.rs
  • src/openhuman/screen_intelligence/tests.rs
  • tests/json_rpc_e2e.rs
✅ Files skipped from review due to trivial changes (9)
  • app/src/services/api/tests/authApi.test.ts
  • app/.prettierignore
  • src/openhuman/about_app/catalog_tests.rs
  • gitbooks/README.md
  • src/openhuman/routing/provider.rs
  • src/openhuman/local_ai/provider.rs
  • src/openhuman/local_ai/README.md
  • src/openhuman/accessibility/automation_state.rs
  • src/openhuman/config/schema/local_ai.rs
🚧 Files skipped from review as they are similar to previous changes (24)
  • src/openhuman/local_ai/service/mod.rs
  • docs/agent-workflows/codex-pr-checklist.md
  • app/src/utils/tauriCommands/config.ts
  • scripts/test-codex-pr-preflight.mjs
  • src/openhuman/local_ai/model_ids.rs
  • app/src/utils/tauriCommands/config.test.ts
  • src/openhuman/local_ai/service/ollama_admin_tests.rs
  • docs/TEST-COVERAGE-MATRIX.md
  • src/openhuman/local_ai/service/public_infer_tests.rs
  • src/openhuman/local_ai/service/public_infer.rs
  • src/openhuman/local_ai/mod.rs
  • src/openhuman/config/ops_tests.rs
  • tests/json_rpc_e2e.rs
  • src/openhuman/routing/factory.rs
  • src/openhuman/config/schemas.rs
  • src/openhuman/local_ai/types.rs
  • src/openhuman/local_ai/lm_studio_api.rs
  • gitbooks/features/model-routing/local-ai.md
  • src/openhuman/config/schemas_tests.rs
  • scripts/codex-pr-preflight.mjs
  • src/openhuman/local_ai/service/lm_studio.rs
  • src/openhuman/local_ai/service/bootstrap.rs
  • src/openhuman/config/ops.rs
  • src/api/config.rs

Comment thread src/openhuman/agent/triage/events.rs Resolved
@EvanWangZ

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

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 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: 2

🤖 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/local_ai/service/assets.rs`:
- Around line 485-516: The early-return branch in download_all_models sets
status.state/embedding_state/warning before calling ensure_ollama_server,
ensure_ollama_model_available, ensure_stt_asset_available and
ensure_tts_asset_available, but any of those functions can return an error and
leave status stuck in "downloading"; update download_all_models to
normalize/restore status on both success and error paths: wrap the preload
sequence (when config.local_ai.preload_embedding_model / preload_stt_model /
preload_tts_voice) in a scoped guard or try/finally-like pattern that ensures
self.status.lock() is reset (state="ready" or previous state,
embedding_state="ready"/"idle" as appropriate, vision_state="disabled", clear
warning and download telemetry) before every return or propagated error from
ensure_ollama_server, ensure_ollama_model_available, ensure_stt_asset_available,
ensure_tts_asset_available; alternatively extract a helper (e.g.,
finalize_lm_studio_status) and call it in both the success path and in the error
handling branch so no error leaves embedding_state="downloading" or stale
warnings.

In `@src/openhuman/local_ai/service/bootstrap.rs`:
- Around line 170-239: The LM Studio bootstrap branch in bootstrap.rs lacks
debug/trace diagnostics; add log::debug or log::trace statements at entry into
the provider_from_config(...) == LocalAiProvider::LmStudio branch, before/after
calling ensure_lm_studio_available(&effective_config), before each preload
decision (checking effective_config.local_ai.preload_embedding_model /
preload_stt_model / preload_tts_voice), around external calls
ensure_ollama_server, ensure_ollama_model_available(&embedding_model,
"embedding"), ensure_stt_asset_available, and ensure_tts_asset_available
(including success/failure outcomes and any returned errors), and log the final
status state transitions when setting status.state to "degraded" or "ready" and
when updating embedding_state/stt_state/tts_state; use consistent “[local_ai]”
prefixes and debug/trace level so these flows are diagnosable.
🪄 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: 34182ee1-c3dc-458a-99e0-e14fbbe77a00

📥 Commits

Reviewing files that changed from the base of the PR and between c67fc55 and 88d210b.

📒 Files selected for processing (6)
  • src/openhuman/agent/triage/escalation.rs
  • src/openhuman/agent/triage/events.rs
  • src/openhuman/local_ai/service/assets.rs
  • src/openhuman/local_ai/service/bootstrap.rs
  • src/openhuman/local_ai/service/ollama_admin.rs
  • src/openhuman/local_ai/service/ollama_admin_tests.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/openhuman/agent/triage/events.rs
  • src/openhuman/local_ai/service/ollama_admin.rs
  • src/openhuman/local_ai/service/ollama_admin_tests.rs

@EvanWangZ

Copy link
Copy Markdown
Contributor Author

@coderabbitai resolve

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Comments resolved and changes approved.

@senamakel
senamakel merged commit 5411f19 into tinyhumansai:main May 15, 2026
21 checks passed
@senamakel

Copy link
Copy Markdown
Member

LFG

AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
senamakel pushed a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
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.

Add LM Studio as a local model provider alongside Ollama

2 participants