Skip to content

feat: native embeddings module with Ollama and vector store - #521

Merged
senamakel merged 11 commits into
tinyhumansai:mainfrom
senamakel:feat/embeddings
Apr 13, 2026
Merged

senamakel merged 11 commits into
tinyhumansai:mainfrom
senamakel:feat/embeddings

Conversation

@senamakel

@senamakel senamakel commented Apr 13, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Replace fastembed + ONNX Runtime with a clean, native embeddings module at src/openhuman/embeddings/
  • Default provider is Ollama (nomic-embed-text:latest, 768 dims) — delegates to the local Ollama server for model management, quantization, and GPU acceleration
  • Add SQLite-backed VectorStore for local insert, search (cosine similarity), delete, and namespace management
  • Remove fastembed and ort crates — eliminates all C++ dynamic library dependencies, ONNX Runtime dylib path resolution, mutex poisoning workarounds, and catch_unwind state machines

Module structure

src/openhuman/embeddings/
├── mod.rs       — EmbeddingProvider trait, factory, re-exports
├── ollama.rs    — OllamaEmbedding (default, calls /api/embed)
├── openai.rs    — OpenAI / compatible endpoints
├── noop.rs      — Keyword-only fallback
└── store.rs     — VectorStore (SQLite, cosine similarity search)

Breaking changes

  • embedding_provider default changed from "fastembed" to "ollama"
  • embedding_model default changed from "BGESmallENV15" to "nomic-embed-text:latest"
  • embedding_dimensions default changed from 384 to 768
  • Old "fastembed" config value now falls through to noop

Coverage

95 unit tests, 97-100% line coverage per file (measured with cargo llvm-cov).

Test plan

  • cargo check passes (core + Tauri shell)
  • cargo test --lib -- embeddings — 95 tests pass
  • cargo test --lib -- memory:: — 113 memory tests pass (re-export shim works)
  • cargo llvm-cov — all files at 97%+ line coverage
  • Manual: verify Ollama embedding works with ollama pull nomic-embed-text + app launch

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Ollama-based local embeddings as default provider
    • Added support for OpenAI-compatible embedding APIs
    • Introduced vector store with semantic search capability
    • Added no-op embedding mode for keyword-only search
  • Chores

    • Removed external embedding dependencies to reduce package footprint
    • Reorganized embeddings module for better maintainability

- Introduced a new `CandleEmbedding` provider using the `candle` ML framework, eliminating C++ dependencies and enhancing performance.
- Updated configuration to default to `candle` for embedding provider settings, replacing the previous `fastembed` references.
- Added new modules for embedding providers, including `candle_embed`, `noop`, and `openai`, to support various embedding strategies.
- Enhanced the `EmbeddingProvider` interface to accommodate the new `CandleEmbedding` implementation.
- Refactored related tests to ensure comprehensive coverage of the new embedding functionalities and maintain backward compatibility with existing configurations.
- Replaced the default embedding provider from Candle to Ollama, enhancing local embedding capabilities with improved model management and GPU acceleration.
- Updated configuration defaults for embedding model and dimensions to align with Ollama specifications.
- Introduced a new Ollama embedding module, including necessary constants and functionality for embedding requests.
- Refactored related code and tests to ensure compatibility with the new provider, maintaining backward compatibility with existing configurations.
- Deleted the `CandleEmbedding` module and its associated files, streamlining the embedding provider architecture.
- Updated `Cargo.toml` and `Cargo.lock` to remove references to Candle-related packages, ensuring a cleaner dependency tree.
- Refactored the `EmbeddingProvider` interface to eliminate support for the Candle provider, maintaining compatibility with existing providers.
- Adjusted tests and documentation to reflect the removal of the Candle embedding functionality, ensuring clarity and consistency across the codebase.
- Introduced a new `store` module to implement a local vector store backed by SQLite, enabling efficient storage and retrieval of text embeddings.
- Added functionality for inserting, updating, and searching embeddings using cosine similarity, enhancing the embedding management capabilities.
- Updated the `mod.rs` file to include the new `store` module and expose relevant functions for cosine similarity and vector operations.
- Enhanced documentation to provide usage examples and clarify the integration of the vector store with existing embedding providers.
Add tests for batch insert mismatch error path, invalid metadata
JSON handling, disk store parent directory creation, and fake
embedding dimensions accessor. 95 tests total across the module,
all files at 97-100% line coverage.
@coderabbitai

coderabbitai Bot commented Apr 13, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@senamakel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 42 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 3 minutes and 42 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fa97beb5-272d-4db3-a6a2-6900fc3c0b20

📥 Commits

Reviewing files that changed from the base of the PR and between f75f0e6 and 24371f7.

📒 Files selected for processing (5)
  • src/openhuman/embeddings/mod.rs
  • src/openhuman/embeddings/ollama.rs
  • src/openhuman/embeddings/openai.rs
  • src/openhuman/embeddings/store.rs
  • src/openhuman/memory/store/factories.rs
📝 Walkthrough

Walkthrough

This PR removes fastembed and ort dependencies, reorganizes embedding functionality into a new top-level openhuman::embeddings module with pluggable providers (Ollama, OpenAI, Noop), implements a SQLite-backed vector store with search capabilities, and refactors the old memory::embeddings module into a compatibility shim.

Changes

Cohort / File(s) Summary
Dependency & Configuration Updates
Cargo.toml, src/openhuman/config/schema/storage_memory.rs
Removed fastembed and ort dependencies. Updated default embedding provider from "fastembed" to "ollama", model from "BGESmallENV15" to "nomic-embed-text:latest", and dimensions from 384 to 768.
Core Embeddings Module (new)
src/openhuman/embeddings/mod.rs
New central module introducing EmbeddingProvider trait with async embed and embed_one methods. Factory function create_embedding_provider supports "ollama", "openai", "custom:" selectors. Re-exports all provider types and vector utilities.
Embedding Providers (new)
src/openhuman/embeddings/noop.rs, src/openhuman/embeddings/ollama.rs, src/openhuman/embeddings/openai.rs
Three provider implementations: NoopEmbedding (returns empty vectors), OllamaEmbedding (local Ollama server via HTTP), and OpenAiEmbedding (OpenAI-compatible API). Each includes comprehensive request/response handling, error paths, and unit tests.
Vector Store (new)
src/openhuman/embeddings/store.rs
SQLite-backed VectorStore supporting insert/upsert, batch operations, vector search with cosine similarity ranking, namespace isolation, and crud operations. Includes vector utilities (vec_to_bytes, bytes_to_vec, cosine_similarity) and extensive test coverage.
Module Reorganization
src/openhuman/mod.rs, src/openhuman/memory/embeddings.rs, src/openhuman/memory/store/client.rs
Exposed new embeddings module in openhuman. Converted old memory/embeddings.rs to re-export shim. Updated comment referencing embedding provider default.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant VectorStore
    participant EmbeddingProvider
    participant HTTPServer as Ollama/OpenAI Server
    participant Database as SQLite DB

    Client->>VectorStore: insert(id, namespace, text, metadata)
    VectorStore->>EmbeddingProvider: embed([text])
    EmbeddingProvider->>HTTPServer: POST /api/embed or /v1/embeddings
    HTTPServer-->>EmbeddingProvider: Vec<Vec<f32>>
    EmbeddingProvider-->>VectorStore: Ok(Vec<Vec<f32>>)
    VectorStore->>Database: INSERT INTO vectors (id, namespace, embedding, text, metadata)
    Database-->>VectorStore: success
    VectorStore-->>Client: Ok(())
Loading
sequenceDiagram
    participant Client
    participant VectorStore
    participant EmbeddingProvider
    participant HTTPServer as Ollama/OpenAI Server
    participant Database as SQLite DB

    Client->>VectorStore: search(namespace, query, limit)
    VectorStore->>EmbeddingProvider: embed_one(query)
    EmbeddingProvider->>HTTPServer: POST with query text
    HTTPServer-->>EmbeddingProvider: Vec<f32>
    EmbeddingProvider-->>VectorStore: Ok(Vec<f32>)
    VectorStore->>Database: SELECT * FROM vectors WHERE namespace = ?
    Database-->>VectorStore: rows with embedding BLOBs
    VectorStore->>VectorStore: compute cosine_similarity(query_vec, row_embedding)
    VectorStore->>VectorStore: sort by score DESC, limit results
    VectorStore-->>Client: Vec<SearchResult>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • No strong code-level connections identified among retrieved PRs.

Poem

🐰 Embeddings hop from fast to local ground,
With Ollama and OpenAI paths found,
A vector store seeds SQLite's deep root,
Providers plug in—no complex pursuit,
Search blooms with cosine, a fuzzy delight! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: introducing a native embeddings module featuring Ollama integration and a vector store, replacing the previous fastembed dependency.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@senamakel

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 13, 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: 7

🧹 Nitpick comments (3)
src/openhuman/embeddings/mod.rs (1)

24-83: Keep this domain mod.rs export-focused.

This file now holds the trait, factory logic, default-provider wiring, and tests. Please move the operational pieces into sibling modules such as types.rs / factory.rs and re-export them here so the domain follows the repo’s mod.rs layout rule.

As per coding guidelines, "Keep domain mod.rs files light and export-focused; place operational code in sibling files (e.g. ops.rs, store.rs, schedule.rs, types.rs), then re-export the public API from mod.rs."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/openhuman/embeddings/mod.rs` around lines 24 - 83, Move operational code
out of mod.rs: extract the EmbeddingProvider trait and any related types into a
new types.rs, move create_embedding_provider and
default_local_embedding_provider (and any provider structs/impls like
OllamaEmbedding, OpenAiEmbedding, NoopEmbedding) into a new factory.rs (or
provider-specific files) and move tests into a tests/ or factory_tests module;
then reduce mod.rs to only pub mod declarations and pub use re-exports (e.g.,
pub use types::EmbeddingProvider; pub use factory::{create_embedding_provider,
default_local_embedding_provider};) so mod.rs stays export-focused while
implementations and tests live in sibling files.
src/openhuman/embeddings/openai.rs (1)

88-135: Add tracing around the new provider call path.

This new external flow has no debug/trace logs at entry, URL selection, success, or error branches. When an endpoint misbehaves, there is nothing grep-friendly tying the request, status, and model together.

As per coding guidelines, "Add substantial, development-oriented logs on new/changed flows; include logs at entry/exit points, branch decisions, external calls, retries/timeouts, state transitions, and error handling paths" and "In Rust, use log/tracing at debug or trace level; prefer stable prefixes."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/openhuman/embeddings/openai.rs` around lines 88 - 135, Add tracing to the
embed flow: mark the async fn embed with #[tracing::instrument] (capture &self
and texts.len()), emit a trace/debug at entry with model and texts.len(), log
the chosen URL from self.embeddings_url() and headers (omit secrets like
self.api_key) before sending the request, log the response status and body on
non-success (include status and text) and on success log a debug with model and
produced embeddings.len(); use tracing::debug! or tracing::trace! for these
messages and prefer stable prefixes like "openai::embed".
src/openhuman/embeddings/store.rs (1)

92-100: Add the missing trace/debug logs around the new search and mutation flows.

The store currently logs open/insert/clear, but the embedder calls, limit == 0 branch, delete path, and query/count/list operations are still opaque when debugging failures. Please add stable [vector-store] debug/trace logs at entry/exit and error branches for these new flows.

As per coding guidelines "Add substantial, development-oriented logs on new/changed flows; include logs at entry/exit points, branch decisions, external calls, retries/timeouts, state transitions, and error handling paths".

Also applies to: 112-121, 153-195, 204-319

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/openhuman/embeddings/store.rs` around lines 92 - 100, Add structured
[vector-store] debug/trace logs at entry, exit, and error branches for the new
search and mutation flows: instrument the methods that call the embedder (e.g.,
the embedder invocation sites), the limit == 0 early-return branch, the delete
path, and operations that perform query/count/list so each starts with a trace
log (including input params), logs key branch decisions (like limit==0), logs
external calls/retries/timeouts around embedder and DB operations, and logs
exit/results or errors with context; place these logs alongside existing
open/insert/clear logs in the same module (functions/methods such as search,
insert, delete, query, count, list and the embedder call sites) using the stable
“[vector-store]” prefix and include enough state (ids/counts/limit/SQL) to aid
debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/openhuman/embeddings/mod.rs`:
- Around line 60-77: The provider match in src/openhuman/embeddings/mod.rs
currently falls back to NoopEmbedding for unknown names; change it to treat
unknown providers as a configuration error instead: map the explicit "none"
provider to NoopEmbedding (or keep current explicit providers like "ollama",
"openai", and "custom:..."), and for any other name return an error (e.g.,
Err(ConfigError) or Result::Err) rather than Box::new(NoopEmbedding). Update the
factory function that uses this match to return a Result so callers of
OllamaEmbedding::new, OpenAiEmbedding::new, and the NoopEmbedding branch handle
the error, and ensure the error includes the unknown provider name for
diagnostics.

In `@src/openhuman/embeddings/ollama.rs`:
- Around line 132-140: embed() currently drops blank entries by filtering the
trimmed texts into input, breaking positional alignment; change the logic to
preserve original indices: iterate texts with .enumerate(), build a vector of
(idx, trimmed_nonempty) for non-blank items, send only those strings to the
embedding call, collect embeddings, then reconstruct a result Vec<Vec<f32>> of
the same length as texts by inserting the computed embedding at its original idx
and a placeholder (e.g., empty Vec::new() or a Vec of zeros) for any
blank/whitespace entries; update references to the temporary input variable and
ensure the returned Vec length matches texts.len() so callers can map by index.
- Around line 177-193: After parsing resp into payload: OllamaEmbedResponse,
validate that payload.embeddings.len() equals the input batch count (the
caller's expected count) and that every vector in payload.embeddings has length
self.dims; if the counts differ or any vector.len() != self.dims, return an
error (anyhow::bail! or map_err) with a clear message referencing the mismatched
batch size or dimension and include the offending sizes so malformed data never
reaches insert_batch(); perform these checks before the existing empty check and
before returning Ok(payload.embeddings).

In `@src/openhuman/embeddings/openai.rs`:
- Around line 113-135: The embedding-response handling code must fail on
malformed or size-mismatched vectors and add debug logs: replace the
filter_map-based conversion with a strict iterator that returns an error if any
element in item.get("embedding") is non-numeric, validate that data.len() equals
the original texts count (texts.len()) and that each produced Vec<f32> has
length self.dims, and return an error if not; also add tracing::debug! logs at
method entry (including model, request count), on successful parse (count and
dims), and on error paths (include the offending item and context). Locate the
block that reads resp.json().await, iterates over data, constructs embeddings
Vec, and uses self.dims/texts to insert these checks and logging.
- Around line 98-103: The embed() flow currently always adds an Authorization
header with self.api_key (possibly empty) and lacks logging; update embed() to
only set the "Authorization: Bearer <token>" header when self.api_key is
non-empty (i.e., skip adding the header for the no-auth custom: case) and add
development logs at key points: log method entry/parameters, log the outbound
request URL and headers (sans sensitive API key), log the HTTP response
status/body on success, and log error details on failures; in your changes
reference the existing methods/fields http_client(), embeddings_url(), api_key,
and embed() so you conditionally build the req and instrument the external call
and error paths with the project’s logger/tracing utilities.

In `@src/openhuman/embeddings/store.rs`:
- Around line 27-42: The DB schema needs to persist and validate embedding
provider/model/dimensions so an open() can detect incompatibility: extend
INIT_SQL to create a metadata table (e.g., "store_meta" with keys like
"embed_provider", "embed_model", "embed_dim" and timestamps) and update the
store creation path (where INIT_SQL is executed) to insert the current
provider/model/dim into that table; then modify open() in store.rs to read these
keys from "store_meta" and compare against the runtime embedding config
(provider/model/dim) and either return an explicit error indicating
incompatibility or trigger a clear rebuild path (drop-and-recreate) when
mismatched. Ensure checks reference the constants/values used to configure the
embedder (the same symbols that set the active provider/model/dim) and fail fast
before any similarity comparisons occur.
- Around line 230-252: The current search pipeline silently drops row/decoding
errors because of filter_map(|r| r.ok()), so replace that with collecting the
iterator as Result<Vec<_>, _> and propagate errors instead of omitting rows:
change the query_map + filter_map chain in the block that builds scored (the
closure passed to stmt.query_map) to return Result<SearchResult, Box<dyn Error>>
(or the concrete error type), collect with
.collect::<rusqlite::Result<Vec<_>>>() (or Result<Vec<_>, _>), and propagate the
Err up; additionally validate the embedding blob after bytes_to_vec (in the same
mapping closure) and return an error if the blob is malformed/has unexpected
length, and convert serde_json::from_str failures into errors rather than
unwrapping, so SearchResult (id, namespace, text, score, metadata) is only
produced for fully valid rows and any decode/parse/validation failure is
returned to the caller.

---

Nitpick comments:
In `@src/openhuman/embeddings/mod.rs`:
- Around line 24-83: Move operational code out of mod.rs: extract the
EmbeddingProvider trait and any related types into a new types.rs, move
create_embedding_provider and default_local_embedding_provider (and any provider
structs/impls like OllamaEmbedding, OpenAiEmbedding, NoopEmbedding) into a new
factory.rs (or provider-specific files) and move tests into a tests/ or
factory_tests module; then reduce mod.rs to only pub mod declarations and pub
use re-exports (e.g., pub use types::EmbeddingProvider; pub use
factory::{create_embedding_provider, default_local_embedding_provider};) so
mod.rs stays export-focused while implementations and tests live in sibling
files.

In `@src/openhuman/embeddings/openai.rs`:
- Around line 88-135: Add tracing to the embed flow: mark the async fn embed
with #[tracing::instrument] (capture &self and texts.len()), emit a trace/debug
at entry with model and texts.len(), log the chosen URL from
self.embeddings_url() and headers (omit secrets like self.api_key) before
sending the request, log the response status and body on non-success (include
status and text) and on success log a debug with model and produced
embeddings.len(); use tracing::debug! or tracing::trace! for these messages and
prefer stable prefixes like "openai::embed".

In `@src/openhuman/embeddings/store.rs`:
- Around line 92-100: Add structured [vector-store] debug/trace logs at entry,
exit, and error branches for the new search and mutation flows: instrument the
methods that call the embedder (e.g., the embedder invocation sites), the limit
== 0 early-return branch, the delete path, and operations that perform
query/count/list so each starts with a trace log (including input params), logs
key branch decisions (like limit==0), logs external calls/retries/timeouts
around embedder and DB operations, and logs exit/results or errors with context;
place these logs alongside existing open/insert/clear logs in the same module
(functions/methods such as search, insert, delete, query, count, list and the
embedder call sites) using the stable “[vector-store]” prefix and include enough
state (ids/counts/limit/SQL) to aid debugging.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8c8c5fb3-dfc5-4049-8d2c-1a09f86c14a9

📥 Commits

Reviewing files that changed from the base of the PR and between 01a948c and f75f0e6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • Cargo.toml
  • src/openhuman/config/schema/storage_memory.rs
  • src/openhuman/embeddings/mod.rs
  • src/openhuman/embeddings/noop.rs
  • src/openhuman/embeddings/ollama.rs
  • src/openhuman/embeddings/openai.rs
  • src/openhuman/embeddings/store.rs
  • src/openhuman/memory/embeddings.rs
  • src/openhuman/memory/store/client.rs
  • src/openhuman/mod.rs
💤 Files with no reviewable changes (1)
  • Cargo.toml

Comment thread src/openhuman/embeddings/mod.rs
Comment thread src/openhuman/embeddings/ollama.rs Outdated
Comment thread src/openhuman/embeddings/ollama.rs Outdated
Comment thread src/openhuman/embeddings/openai.rs Outdated
Comment thread src/openhuman/embeddings/openai.rs
Comment thread src/openhuman/embeddings/store.rs
Comment thread src/openhuman/embeddings/store.rs Outdated
- Updated the `create_embedding_provider` function to return an `anyhow::Result`, allowing for immediate error reporting on unrecognized provider names.
- Added support for a "none" provider that returns a no-op embedding.
- Enhanced tests to cover new error handling paths and validate behavior for known and unknown providers, improving overall test coverage.
…dling for blank inputs and response validation

- Updated the `embed` method in both `OllamaEmbedding` and `OpenAiEmbedding` to skip blank inputs while preserving their positions in the output as zero-vectors.
- Added validation to ensure the response count matches the input count, with appropriate error handling for dimension mismatches.
- Enhanced tests to cover new behavior for blank inputs and response validation, ensuring robustness in embedding functionality.
- Factory returns Result for unknown providers instead of silent noop
- Ollama: preserve positional alignment when blank texts are filtered
- Ollama: validate response count and dimensions before returning
- OpenAI: strict parsing errors on non-numeric embedding values
- OpenAI: skip Authorization header when api_key is empty
- OpenAI: validate response count and dimensions
- OpenAI/Ollama: add tracing at entry, success, and error paths
- Store: add store_meta table to persist and validate embedding
  provider/dimensions on open — errors on dimension mismatch
- Store: propagate row decode errors instead of filter_map(ok)
- Store: add tracing to search, insert, delete, and count paths
- Update factories.rs caller for Result-returning factory

101 tests pass, all files at 97%+ coverage.
@senamakel
senamakel merged commit 4cf608c into tinyhumansai:main Apr 13, 2026
8 of 9 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
…nsai#521)

* feat: replace fastembed with candle for local embeddings

- Introduced a new `CandleEmbedding` provider using the `candle` ML framework, eliminating C++ dependencies and enhancing performance.
- Updated configuration to default to `candle` for embedding provider settings, replacing the previous `fastembed` references.
- Added new modules for embedding providers, including `candle_embed`, `noop`, and `openai`, to support various embedding strategies.
- Enhanced the `EmbeddingProvider` interface to accommodate the new `CandleEmbedding` implementation.
- Refactored related tests to ensure comprehensive coverage of the new embedding functionalities and maintain backward compatibility with existing configurations.

* feat: update embedding provider to Ollama

- Replaced the default embedding provider from Candle to Ollama, enhancing local embedding capabilities with improved model management and GPU acceleration.
- Updated configuration defaults for embedding model and dimensions to align with Ollama specifications.
- Introduced a new Ollama embedding module, including necessary constants and functionality for embedding requests.
- Refactored related code and tests to ensure compatibility with the new provider, maintaining backward compatibility with existing configurations.

* refactor: remove Candle embedding provider and related dependencies

- Deleted the `CandleEmbedding` module and its associated files, streamlining the embedding provider architecture.
- Updated `Cargo.toml` and `Cargo.lock` to remove references to Candle-related packages, ensuring a cleaner dependency tree.
- Refactored the `EmbeddingProvider` interface to eliminate support for the Candle provider, maintaining compatibility with existing providers.
- Adjusted tests and documentation to reflect the removal of the Candle embedding functionality, ensuring clarity and consistency across the codebase.

* feat: add SQLite-backed vector store for embeddings

- Introduced a new `store` module to implement a local vector store backed by SQLite, enabling efficient storage and retrieval of text embeddings.
- Added functionality for inserting, updating, and searching embeddings using cosine similarity, enhancing the embedding management capabilities.
- Updated the `mod.rs` file to include the new `store` module and expose relevant functions for cosine similarity and vector operations.
- Enhanced documentation to provide usage examples and clarify the integration of the vector store with existing embedding providers.

* Add fs2 dependency for improved file locking in ComposeIO trigger history

* test: boost embeddings module coverage to 97%+

Add tests for batch insert mismatch error path, invalid metadata
JSON handling, disk store parent directory creation, and fake
embedding dimensions accessor. 95 tests total across the module,
all files at 97-100% line coverage.

* style: apply cargo fmt to embeddings module

* feat: enhance embedding provider creation with error handling

- Updated the `create_embedding_provider` function to return an `anyhow::Result`, allowing for immediate error reporting on unrecognized provider names.
- Added support for a "none" provider that returns a no-op embedding.
- Enhanced tests to cover new error handling paths and validate behavior for known and unknown providers, improving overall test coverage.

* feat: enhance Ollama and OpenAI embedding providers with improved handling for blank inputs and response validation

- Updated the `embed` method in both `OllamaEmbedding` and `OpenAiEmbedding` to skip blank inputs while preserving their positions in the output as zero-vectors.
- Added validation to ensure the response count matches the input count, with appropriate error handling for dimension mismatches.
- Enhanced tests to cover new behavior for blank inputs and response validation, ensuring robustness in embedding functionality.

* fix: address PR review findings for embeddings module

- Factory returns Result for unknown providers instead of silent noop
- Ollama: preserve positional alignment when blank texts are filtered
- Ollama: validate response count and dimensions before returning
- OpenAI: strict parsing errors on non-numeric embedding values
- OpenAI: skip Authorization header when api_key is empty
- OpenAI: validate response count and dimensions
- OpenAI/Ollama: add tracing at entry, success, and error paths
- Store: add store_meta table to persist and validate embedding
  provider/dimensions on open — errors on dimension mismatch
- Store: propagate row decode errors instead of filter_map(ok)
- Store: add tracing to search, insert, delete, and count paths
- Update factories.rs caller for Result-returning factory

101 tests pass, all files at 97%+ coverage.
senamakel added a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
…nsai#521)\n\n* feat: replace fastembed with candle for local embeddings\n\n- Introduced a new `CandleEmbedding` provider using the `candle` ML framework, eliminating C++ dependencies and enhancing performance.\n- Updated configuration to default to `candle` for embedding provider settings, replacing the previous `fastembed` references.\n- Added new modules for embedding providers, including `candle_embed`, `noop`, and `openai`, to support various embedding strategies.\n- Enhanced the `EmbeddingProvider` interface to accommodate the new `CandleEmbedding` implementation.\n- Refactored related tests to ensure comprehensive coverage of the new embedding functionalities and maintain backward compatibility with existing configurations.\n\n* feat: update embedding provider to Ollama\n\n- Replaced the default embedding provider from Candle to Ollama, enhancing local embedding capabilities with improved model management and GPU acceleration.\n- Updated configuration defaults for embedding model and dimensions to align with Ollama specifications.\n- Introduced a new Ollama embedding module, including necessary constants and functionality for embedding requests.\n- Refactored related code and tests to ensure compatibility with the new provider, maintaining backward compatibility with existing configurations.\n\n* refactor: remove Candle embedding provider and related dependencies\n\n- Deleted the `CandleEmbedding` module and its associated files, streamlining the embedding provider architecture.\n- Updated `Cargo.toml` and `Cargo.lock` to remove references to Candle-related packages, ensuring a cleaner dependency tree.\n- Refactored the `EmbeddingProvider` interface to eliminate support for the Candle provider, maintaining compatibility with existing providers.\n- Adjusted tests and documentation to reflect the removal of the Candle embedding functionality, ensuring clarity and consistency across the codebase.\n\n* feat: add SQLite-backed vector store for embeddings\n\n- Introduced a new `store` module to implement a local vector store backed by SQLite, enabling efficient storage and retrieval of text embeddings.\n- Added functionality for inserting, updating, and searching embeddings using cosine similarity, enhancing the embedding management capabilities.\n- Updated the `mod.rs` file to include the new `store` module and expose relevant functions for cosine similarity and vector operations.\n- Enhanced documentation to provide usage examples and clarify the integration of the vector store with existing embedding providers.\n\n* Add fs2 dependency for improved file locking in ComposeIO trigger history\n\n* test: boost embeddings module coverage to 97%+\n\nAdd tests for batch insert mismatch error path, invalid metadata\nJSON handling, disk store parent directory creation, and fake\nembedding dimensions accessor. 95 tests total across the module,\nall files at 97-100% line coverage.\n\n* style: apply cargo fmt to embeddings module\n\n* feat: enhance embedding provider creation with error handling\n\n- Updated the `create_embedding_provider` function to return an `anyhow::Result`, allowing for immediate error reporting on unrecognized provider names.\n- Added support for a "none" provider that returns a no-op embedding.\n- Enhanced tests to cover new error handling paths and validate behavior for known and unknown providers, improving overall test coverage.\n\n* feat: enhance Ollama and OpenAI embedding providers with improved handling for blank inputs and response validation\n\n- Updated the `embed` method in both `OllamaEmbedding` and `OpenAiEmbedding` to skip blank inputs while preserving their positions in the output as zero-vectors.\n- Added validation to ensure the response count matches the input count, with appropriate error handling for dimension mismatches.\n- Enhanced tests to cover new behavior for blank inputs and response validation, ensuring robustness in embedding functionality.\n\n* fix: address PR review findings for embeddings module\n\n- Factory returns Result for unknown providers instead of silent noop\n- Ollama: preserve positional alignment when blank texts are filtered\n- Ollama: validate response count and dimensions before returning\n- OpenAI: strict parsing errors on non-numeric embedding values\n- OpenAI: skip Authorization header when api_key is empty\n- OpenAI: validate response count and dimensions\n- OpenAI/Ollama: add tracing at entry, success, and error paths\n- Store: add store_meta table to persist and validate embedding\n  provider/dimensions on open — errors on dimension mismatch\n- Store: propagate row decode errors instead of filter_map(ok)\n- Store: add tracing to search, insert, delete, and count paths\n- Update factories.rs caller for Result-returning factory\n\n101 tests pass, all files at 97%+ coverage.\n
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.

1 participant