Skip to content

fix(embeddings): scope the memory client's default embedder to config credentials - #5515

Merged
senamakel merged 3 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/managed-embeddings-batch-skip-5501
Aug 13, 2026
Merged

fix(embeddings): scope the memory client's default embedder to config credentials#5515
senamakel merged 3 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/managed-embeddings-batch-skip-5501

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Managed/cloud embeddings ran with a credential scope that diverged from "Test connection", so a signed-in user's ingested documents embedded with "No backend session" and persisted vector-less — silently unsearchable, no error surfaced.
  • Add default_embedding_provider_with_config(config) and route the two config-holding callers (the memory-client embedding-host seam and the agent-experience store) through it, so the ingest embedder resolves the same credential scope "Test connection" uses.
  • The keyless default_embedding_provider() is retained for genuinely config-less callers, doc-warned as a best-effort fallback.

Problem

After #5427 fixed the managed sign-in flow, "Test connection" passes and raw ingestion completes — but the embedding pass produces no vectors and memory search returns nothing, with no error shown to the user (#5501).

Root cause: the namespace-document ingest tier builds its inline embedder via the keyless default_embedding_provider(), hardcoded OpenHumanCloudEmbedding::new(openhuman_dir = None, secrets_encrypt = true, …). openhuman_dir = None resolves the managed session from default_state_dir() with encryption forced on — a scope that diverges from where sign-in actually wrote the app-session token whenever the config disables secret encryption or roots the workspace/user elsewhere than the process default. "Test connection" instead builds through create_embedding_provider_with_configmanaged_credential_scope(config), so the two paths disagree on where the token lives. The memory client caches its embedder process-globally, so the wrong scope sticks for the process lifetime. #5427 fixed the config-aware path but left this keyless one.

Solution

  • New default_embedding_provider_with_config(config) builds the managed cloud embedder through managed_credential_scope(config) — the exact (state_dir, encrypt) pair AuthService::from_config writes the app-session token to at sign-in.
  • OpenHumanEmbeddingHost::default_embedding_provider (the process-global-cached memory-client seam, MemoryClient::from_workspace_dir) and agent::experience::ops::open_store_in_subdir now use the config-aware constructor via &self.config / config.
  • This mirrors the already-correct cloud_embedding_provider seam that the memory-tree tier uses, so both tiers now resolve managed credentials identically.
  • The keyless variant stays for config-less callers, with a doc note that it is a best-effort fallback and config-holding callers must prefer the config-aware path.
  • Note: the namespace-document tier has no re-embed backfill, so a missed embed is permanent — fixing the scope is what makes a signed-in user's ingested content searchable at all.

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) — new e2e binding test default_provider_with_config_authenticates_with_config_scoped_token (local axum mock captures the bearer, asserts the config-scoped app-session token is used); its failure mode is exactly the divergent-scope regression this PR fixes. Existing managed_scope_resolves_signin_stored_app_session_token round-trip retained.
  • Diff coverage ≥ 80% — changed lines are exercised by the new e2e binding test plus the existing experience/seam tests; the Rust Core Coverage / coverage-gate jobs confirm the merged-lcov threshold on changed lines.
  • Coverage matrix updated — N/A: behaviour-only credential-scope fix; no feature rows added/removed/renamed.
  • All affected feature IDs from the matrix are listed under ## Related — N/A: no matrix rows change.
  • No new external network dependencies introduced — the new test uses a local axum mock (no real network).
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: no new user-facing surface; the managed-embeddings ingest path already exists.
  • Linked issue closed via Closes #NNN in the ## Related section.

Impact

  • Runtime/platform: desktop + CLI (Rust core). Signed-in users' managed embeddings now actually produce vectors on ingest, so semantic memory search works.
  • Security: no change to what is stored or logged — credentials are read from the correct config-scoped store; only the non-identifying encrypt flag is logged, never the path. No new network dependency. No migration.

Related

CI note — pre-existing failures inherited from main

The red checks on this PR are not produced by this diff, which touches only four src/openhuman/** files (no Cargo.toml/Cargo.lock, no config/**):

  • Rust Quality (fmt, clippy) fails with cannot update the lock file app/src-tauri/Cargo.lock because --locked. This branch's app/src-tauri/Cargo.lock is byte-identical to main (untouched here) and the error reproduces locally on a clean checkout — it is a lock-drift on main.
  • Rust Feature-Gate Smoke (gates off) fails on two config::migration_helpers::ops tests, code this PR does not touch.

Both jobs fail identically on main's own latest CI Lite run (base commit #5492), so they are pre-existing breakage, surfaced here rather than worked around. They should be fixed on main / in dedicated PRs, not papered over in this one.


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

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/managed-embeddings-batch-skip-5501
  • Commit SHA: 934cbefe3

Validation Run

  • N/A — pnpm --filter openhuman-app format:check: no app/ frontend changes.
  • N/A — pnpm typecheck: no TypeScript changed.
  • Focused tests: cargo test --lib inference::embeddings::factory (6/6), agent::experience (29/29), memory::seam_integration (8/8).
  • Rust fmt/check: cargo fmt --check clean; cargo clippy clean on the touched files.
  • N/A — Tauri fmt/check: no app/src-tauri change.

Validation Blocked

  • command: full diff-cover + full cargo test --lib
  • error: not run locally (long); the memory::driver::embedded subtree fails in isolation with "no EmbeddingHost installed" because those tests rely on a process-global seam that only another test installs in the full suite — verified identical pass/fail counts with this change stashed, so it is a pre-existing test-ordering artifact unaffected by this PR.
  • impact: CI runs the full suite + diff-cover gate.

Behavior Changes

  • Intended behavior change: managed embeddings resolve the signed-in session during ingest, not only during "Test connection".
  • User-visible effect: ingested documents become semantically searchable for signed-in users (previously stored vector-less and silently unsearchable).

Parity Contract

  • Legacy behavior preserved: keyless default_embedding_provider() is unchanged for config-less callers; non-managed providers (Ollama/custom/voyage/none) are untouched.
  • Guard/fallback/dispatch parity checks: config-less fallback retained and doc-warned; the config-aware path mirrors the existing cloud_embedding_provider seam already used by the memory-tree tier.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: N/A
  • Resolution (closed/superseded/updated): N/A

Summary by CodeRabbit

  • Bug Fixes
    • Embedding services now consistently use configured authentication and security settings.
    • Profile-specific and host-managed experiences can authenticate using the correct configuration scope.
    • Improved reliability for cloud embedding requests, including configuration-scoped sessions.
  • Tests
    • Added coverage confirming configured authentication works and embeddings are returned with the expected dimensions.
    • Updated routing coverage for explicitly configured local embedding services.

… credentials

The namespace-document ingest tier builds its inline embedder through the keyless `default_embedding_provider()`, which hardcodes `(openhuman_dir=None, secrets_encrypt=true)`. That resolves the managed session from `default_state_dir()` with encryption forced on — a scope that diverges from where sign-in actually wrote the `app-session` token whenever the config disables secret encryption or roots the workspace/user elsewhere than the process default. "Test connection" builds through the config-aware `create_embedding_provider_with_config` (managed_credential_scope) and passes, while every ingest embed then fails with "No backend session" and the document persists vector-less — so a signed-in user's ingested memory is silently unsearchable. tinyhumansai#5427 fixed the config-aware path but left this keyless one.

Add `default_embedding_provider_with_config(config)` — routes managed construction through `managed_credential_scope`, the same (state_dir, encrypt) scope Test connection uses — and call it from the two config-holding callers: the memory-client embedding-host seam (`OpenHumanEmbeddingHost::default_embedding_provider`) and the agent-experience store. The keyless variant stays for genuinely config-less callers, doc-warned as a best-effort fallback.

Adds an e2e binding test (axum mock captures the bearer) proving the config-scoped default embedder authenticates with the app-session token sign-in stored.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ffce281-b14e-450e-b3cb-1e4dba50caaa

📥 Commits

Reviewing files that changed from the base of the PR and between 934cbef and 6f81e82.

📒 Files selected for processing (1)
  • src/openhuman/inference/embeddings/rpc.rs

📝 Walkthrough

Walkthrough

Embedding provider creation now accepts Config to use scoped credentials and encryption settings. The memory host and profile-specific experience stores use this factory. Tests verify bearer authentication, default vector dimensions, and explicit local Ollama routing.

Changes

Config-scoped embedding providers

Layer / File(s) Summary
Configuration-aware provider factory
src/openhuman/inference/embeddings/factory.rs, src/openhuman/inference/embeddings/mod.rs
Adds default_embedding_provider_with_config, documents the keyless factory scope, re-exports the new function, and tests config-scoped token authentication.
Scoped provider caller integration
src/openhuman/agent/experience/ops.rs, src/openhuman/memory/host_impls.rs, src/openhuman/inference/embeddings/rpc.rs
Passes loaded configuration to the embedding provider factory. The effective-provider test configures explicit local Ollama routing.

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

Mergeability Score: ⚪ Minimal · up to 6f81e

The PR routes config-holding embedding callers through the configured credential scope while retaining the keyless fallback; no actionable merge-blocking risk remains at the current head, so it is merge-ready after normal checks.

Sequence Diagram(s)

sequenceDiagram
  participant Config
  participant EmbeddingFactory
  participant CredentialStore
  participant EmbeddingServer
  Config->>EmbeddingFactory: provide credential scope and model settings
  EmbeddingFactory->>CredentialStore: read config-scoped app-session token
  CredentialStore-->>EmbeddingFactory: return session token
  EmbeddingFactory->>EmbeddingServer: send embedding request with bearer token
  EmbeddingServer-->>EmbeddingFactory: return default-sized vectors
Loading

Possibly related PRs

Suggested labels: rust-core

Suggested reviewers: m3ga-mind

Poem

A rabbit checks the token store,
Then bounds through vectors, many more.
Scoped credentials guide the way,
Default-sized hops complete the day.
Squeak! The provider now knows the door.

🚥 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 clearly and concisely describes the main change: scoping the memory client's default embedder to configuration credentials.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@YellowSnnowmann YellowSnnowmann added bug memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. labels Aug 12, 2026
@YellowSnnowmann
YellowSnnowmann marked this pull request as ready for review August 12, 2026 09:48
@YellowSnnowmann
YellowSnnowmann requested a review from a team August 12, 2026 09:48
@coderabbitai coderabbitai Bot added the rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. label Aug 12, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 12, 2026
@tinysweeper

tinysweeper Bot commented Aug 12, 2026

Copy link
Copy Markdown

What this change touches

5 files, +152 -4 across 3 components. The code graph knows nothing about these files yet — normal for newly added files, and a cold index otherwise.

flowchart LR
  n0["src/openhuman/inference/embeddings<br/>3 files +139 -2"]:::changed
  n1["src/openhuman/memory<br/>1 file +9 -1"]:::changed
  n2["src/openhuman/agent/experience<br/>1 file +4 -1"]:::changed
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading

Green: changed. Grey: untouched, reached through an import or a call. Orange: has findings. Red: has a finding that blocks the merge.

Component Files Lines Findings
src/openhuman/inference/embeddings changed 3 +139 -2
src/openhuman/memory changed 1 +9 -1
src/openhuman/agent/experience changed 1 +4 -1
Changed files

src/openhuman/inference/embeddings

  • src/openhuman/inference/embeddings/factory.rs
  • src/openhuman/inference/embeddings/mod.rs
  • src/openhuman/inference/embeddings/rpc.rs

src/openhuman/memory

  • src/openhuman/memory/host_impls.rs

src/openhuman/agent/experience

  • src/openhuman/agent/experience/ops.rs

tinysweeper 0.1.0

@tinysweeper tinysweeper 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.

tinysweeper found nothing blocking. Approving.

             $0.0372 · 32,342 in / 9,807 out · 17,111 cached (53%) · z-ai/glm-5.2
critique:    $0.0183 · 12,286 in / 5,191 out · 5,521 cached (45%)  · z-ai/glm-5.2
security:    $0.0068 · 9,394 in  / 1,685 out · 6,959 cached (74%)  · z-ai/glm-5.2
tests:       $0.0070 · 4,377 in  / 2,420 out · 3,351 cached (77%)  · z-ai/glm-5.2
description: $0.0052 · 6,285 in  / 511 out   · 1,280 cached (20%)  · z-ai/glm-5.2

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Aug 12, 2026
…ory v1.0.1

Same pre-existing broken-main as folded into tinyhumansai#5528: the inference coverage
lane runs the whole openhuman::inference namespace, and tinymemory v1.0.1
changed the effective-embedder ladder (local Ollama now resolves from an
explicit memory_tree.embedding_endpoint override or the unified
workload_local_model setting, not the embeddings_provider string alone). The
submodule bump landed on main without updating this test. Drive the
deterministic explicit-endpoint rung so the test keeps its tinyhumansai#5402 assertion.
Not caused by this PR; fails identically on plain main.
@tinysweeper tinysweeper Bot added priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. and removed priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. labels Aug 13, 2026
@senamakel
senamakel merged commit 178a11a into tinyhumansai:main Aug 13, 2026
31 of 37 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Team Openhuman Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. 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.

Bug: managed embeddings — Test Connection succeeds but embedding batch is not run after ingestion

2 participants