Commit graph

29 commits

Author SHA1 Message Date
Nicolò Boschi
15ea23d5d6
feat: introduce hindsight-api-slim and hindsight-all-slim packages (#560)
* feat: introduce hindsight-api-slim and hindsight-all-slim packages

Closes #552

- Move all source code from hindsight-api/ to new hindsight-api-slim/
- hindsight-api-slim has heavy ML deps (torch, sentence-transformers,
  transformers, einops, flashrank, mlx, mlx-lm, safetensors) and
  pg0-embedded as optional extras: [local-ml], [embedded-db], [all]
- hindsight-api becomes a zero-code meta-package depending on
  hindsight-api-slim[all] for full backward compatibility
- Add hindsight-all-slim meta-package: hindsight-api-slim + client + embed
- hindsight-all updated to depend on hindsight-api-slim[all]
- pg0.py: lazy-import pg0 with clear ImportError pointing to [embedded-db]
- Dockerfile: replace sed hack with proper uv sync --extra flags
- Update release.yml, test.yml, lint.sh, release.sh, CLAUDE.md and
  all path references throughout the repo

* refactor: rename hindsight/ directory to hindsight-all/

* docs: document hindsight-api-slim and hindsight-all-slim package variants

Add package variants table and extras explanation to installation.md

* docs: remove emojis from installation.md, use professional tone

* docs: link Docker slim variant to pip package variants section

* docs: consolidate Docker image variants into single table

* ci: fix working-directory paths after package restructure

- Replace all hindsight-api → hindsight-api-slim in test.yml
- Replace hindsight → hindsight-all in test.yml
- Add --extra embedded-db to test-embed API install step

* ci: add local-ml and embedded-db extras to API sync steps

These extras were previously implicit in the old hindsight-api package
(which bundled everything). Now that hindsight-api-slim uses optional
extras, we must explicitly request local-ml and embedded-db in CI.

* ci: add API install step with embedded-db to test-embed smoke test

The smoke test starts hindsight-api as a daemon, which requires pg0-embedded.
Add a dedicated install step for hindsight-api-slim with embedded-db extra
so the daemon can start successfully.

* ci: remove --no-install-project when using optional extras

When --no-install-project is combined with --extra, the optional deps
are not installed because extras require the project to be active.
Remove --no-install-project from steps that need local-ml or embedded-db.

* ci: fix ordering of uv sync steps to preserve optional extras

When uv sync runs for a different workspace member, it removes optional
extras installed for other members. Fix by always running extra-requiring
API sync last, after other workspace member syncs.

Also remove --no-install-project from embedded-db sync in test-embed,
as --no-install-project prevents optional extras from being active.

* ci: add local-ml extra to test-embed API install for smoke test

The smoke test starts the full API server which needs sentence-transformers
for local embeddings (default provider). Add local-ml extra to the install.

* ci: simplify extras with --all-extras and add slim pip smoke test

- Replace explicit --extra local-ml --extra embedded-db with --all-extras
  for cleaner, more maintainable sync steps
- Add test-pip-slim job: tests hindsight-api-slim[embedded-db] without
  local ML models, using Cohere for embeddings/reranking (mirrors Docker
  slim smoke test approach)

* ci: simplify slim smoke test to health check only (mirrors Docker test)
2026-03-13 13:50:03 +01:00
Nicolò Boschi
eeb938fc65
fix: truncate documents exceeding LiteLLM reranker context limit (#549)
* fix: register embedded profiles in CLI metadata on daemon start

When HindsightEmbedded(profile="myapp") starts a daemon, the profile
was never written to metadata.json or given a .env file, making it
invisible to `hindsight-embed profile list` and other CLI commands.

Add _register_profile() to DaemonEmbedManager which saves HINDSIGHT_API_*
config to ~/.hindsight/profiles/{name}.env and registers the port in
metadata.json. Called after a successful new daemon start and when the
daemon is already running, so orphaned profiles also get registered on
next use.

* fix: truncate documents exceeding LiteLLM reranker context limit

Add HINDSIGHT_API_RERANKER_LITELLM_MAX_TOKENS_PER_DOC env var for both
litellm and litellm-sdk reranker providers. When set, documents are
truncated to the configured token limit using tiktoken (cl100k_base)
before being sent to the reranker, preventing BadRequestError for
models with small context windows (e.g. 1024-token limit).

* refactor: use shared _tiktoken_encoder for doc truncation in LiteLLM reranker

* refactor: use _get_tiktoken_encoding() consistently, remove eager module-level encoder instance

* doc: add HINDSIGHT_API_RERANKER_LITELLM_MAX_TOKENS_PER_DOC to configuration reference
2026-03-13 10:18:18 +01:00
Nicolò Boschi
1caf5ec9ee
feat: add jina-mlx reranker provider for Apple Silicon (#542)
* feat: add JinaMLXCrossEncoder for native Apple Silicon reranking

Adds a new `jina-mlx` reranker provider backed by jinaai/jina-reranker-v3-mlx,
a 0.6B multilingual listwise reranker running via the MLX framework on Apple Silicon.
The model is downloaded automatically from HuggingFace Hub on first use.

Benchmarked latencies (Apple Silicon): 1 doc→32ms, 5→45ms, 10→60ms, 20→94ms.
Sub-linear scaling because all docs are ranked in a single forward pass.

- Embeds the MLX reranker implementation (_MLXReranker / _MLPProjector) directly
  in cross_encoder.py with no transformers/PyTorch dependency
- Adds `mlx`, `mlx-lm`, `safetensors` to pyproject.toml optional deps (uv add)
- Updates configuration.md with provider docs and benchmark table

* refactor: import MLXReranker from repo rerank.py instead of duplicating code

Use importlib to load MLXReranker directly from the model repo's own rerank.py
(downloaded via snapshot_download). Also pin exact minimum versions for
mlx>=0.31.0, mlx-lm>=0.31.1, safetensors>=0.6.2 (verified against installed versions).

* refactor: move MLX reranker impl to dedicated jina_mlx_reranker.py

Replaces the importlib hack with a proper module. jina_mlx_reranker.py is
adapted from jinaai/jina-reranker-v3-mlx/rerank.py (CC BY-NC 4.0) with the
source clearly documented at the top of the file.

* docs: simplify jina-mlx reranker docs

* fix: disable GIN fastupdate on source_memory_ids index to prevent deadlocks

GIN fastupdate buffers inserts in a pending list and flushes it with
AccessExclusiveLock when full. Under concurrent test load (8 xdist workers
all running retain_async), two workers can trigger a flush simultaneously
and deadlock. Recreating the index with fastupdate=off eliminates the
flush/lock cycle at the cost of slightly slower individual inserts.

* fix: drop per-bank HNSW indexes after transaction to avoid AccessExclusiveLock deadlock

When deleting a bank, the previous code dropped HNSW indexes inside the
same transaction as the DELETE FROM memory_units. Since DROP INDEX needs
AccessExclusiveLock on the parent table and DELETE holds RowExclusiveLock,
two concurrent bank deletions deadlocked on the same table lock.

Fix: capture internal_id inside the transaction, commit, then drop the
indexes outside the transaction so no row-level locks are held.
2026-03-11 15:15:58 +01:00
Nicolò Boschi
f6f1a7d889
fix: zeroentropy rerank URL missing /v1 prefix and MCP retain async_processing param (#460)
* fix: zeroentropy rerank URL missing /v1 prefix and MCP routing tests

- Fix ZeroEntropy reranker URL: /models/rerank -> /v1/models/rerank (#453)
- Fix test_mcp_routing tests: update assertions to use submit_async_retain
  instead of the non-existent async_processing=False/retain_batch_async pattern

* fix(openclaw): pass retainEveryNTurns through getPluginConfig and set it to 1 in tests

getPluginConfig was not forwarding retainEveryNTurns from the raw config,
so pluginConfig.retainEveryNTurns was always undefined (defaulting to 10).
The integration tests use retainEveryNTurns: 1 so retain fires every turn.
2026-03-02 10:32:01 +01:00
Eliah Rusin
172596751f
feat: add ZeroEntropy reranker provider support (#420)
Add ZeroEntropy as a reranker provider using their Rerank API
(https://docs.zeroentropy.dev/models). Supports zerank-2 (flagship)
and zerank-2-small models via direct HTTP API calls with httpx (no
additional SDK dependency required).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 10:12:32 +01:00
Nicolò Boschi
e408b7e072
feat: support litellm-sdk as reranker and embeddings (#357)
* feat: support litellm-sdk for reranker endpoint

* feat: support litellm-sdk for reranker endpoint

* fix: make litellm SDK cohere test fixture async function-scoped

* fix: store litellm module reference during initialization to avoid import issues

* feat: add LiteLLM SDK embeddings support

- Add LiteLLMSDKEmbeddings class for direct API access without proxy
- Support multiple providers: Cohere, OpenAI, Together AI, HuggingFace, Voyage AI
- Automatic dimension detection via test embedding
- Provider-specific API key mapping
- Batch processing support (configurable batch size)
- Comprehensive test coverage (17 unit tests)
- Update documentation with configuration examples

Implements embeddings in same PR as reranker per user request

* fix: correct config mocking in embeddings factory tests

- Mock get_config() from its source module (hindsight_api.config)
- Fixes factory tests that were returning LocalSTEmbeddings instead of LiteLLMSDKEmbeddings
- All 17 unit tests now passing

* fix: skip Cohere integration tests when API key is invalid

- Catch initialization errors and skip tests instead of failing
- Prevents CI failures when COHERE_API_KEY is set but invalid
- Integration tests now properly skip when authentication fails

* fix: skip Cohere reranker integration tests when API key is invalid

- Add same error handling as embeddings tests
- Prevents CI failures when COHERE_API_KEY is set but invalid
- Tests now properly skip when authentication fails

* Revert "fix: skip Cohere reranker integration tests when API key is invalid"

This reverts commit 655dacaffb25851ff48e202b4379fc8332a66df7.

* Revert "fix: skip Cohere integration tests when API key is invalid"

This reverts commit 5d00548e39faa3da6b427ace89589a216816f9e7.

* fix: pass API key directly to litellm SDK functions

- Add api_key parameter to arerank(), rerank(), aembedding(), and embedding() calls
- Prevents authentication issues in multi-process environments (pytest-xdist)
- More reliable than relying solely on environment variables
- Update test assertions to expect api_key parameter

* feat: pass api_base parameter to litellm SDK calls and remove hasattr check

* fix: raise errors instead of silently returning 0.0 scores

* refactor: pass API keys directly in kwargs instead of setting env vars
2026-02-12 23:53:12 +01:00
Nicolò Boschi
60574ee08f
fix: add trust_code env config (#347)
* fix: add trust_code env config

* doc
2026-02-11 17:06:59 +01:00
Nicolò Boschi
7d95a002c7
fix: improve model configuration for litellm gateway (#345)
* fix: improve model configuration for litellm gateway

* fix: add missing config imports for Cohere and LiteLLM providers

Add missing DEFAULT_* and ENV_* constants to cross_encoder.py and embeddings.py imports:
- DEFAULT_RERANKER_COHERE_MODEL
- DEFAULT_LITELLM_API_BASE
- DEFAULT_RERANKER_LITELLM_MODEL
- DEFAULT_EMBEDDINGS_COHERE_MODEL
- DEFAULT_EMBEDDINGS_LITELLM_MODEL
- ENV_RERANKER_COHERE_MODEL

This fixes NameError failures in test-api, test-hindsight-all, and test-upgrade CI jobs.
2026-02-11 11:24:26 +01:00
Nicolò Boschi
34d9188e13
fix: hide hf logging (#295) 2026-02-04 13:12:30 +01:00
Nicolò Boschi
c2ac7d0440
feat: support vertex as llm provider (#233)
* feat: support vertex as llm provider

* fix

* fix: add uv index-strategy to resolve dependency conflicts with pytorch index

When using pytorch index for faster torch downloads in CI,
filelock dependency resolution was failing because pytorch index
only has older versions. Adding unsafe-best-match strategy allows
uv to search all configured indexes.

Also fix type checking warnings from ty.

* fix: add index-strategy to root pyproject.toml for workspace-level uv resolution

* chore: regenerate client SDKs after Vertex AI support
2026-01-29 16:13:57 -05:00
Nicolò Boschi
c16ccc2c22
fix: hindsight-embed on macos crashes (#228)
* fix: hindsight-embed on macos crashes

* fix: hindsight-embed on macos crashes

* fix(doc): improve docs versioning and release

* fix(doc): improve docs versioning and release

* fixes
2026-01-29 16:57:51 +01:00
Nicolò Boschi
67c47881cb
fix: add defensive error handling to PyTorch device detection (#221)
* fix: include correct __version__ in python packages

* fix(embed): force CPU mode for local models in daemon to prevent XPC crashes

Adds HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU and HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU
environment variables to force CPU-only operation for local sentence-transformer models.

This prevents XPC_ERROR_CONNECTION_INVALID crashes on macOS when running in daemon mode.
The issue occurs because PyTorch's MPS (Metal Performance Shaders) backend has unstable
XPC connections in background processes, leading to C++ assertion failures that Python
exception handlers cannot catch.

Changes:
- config.py: Add ENV_*_FORCE_CPU constants and config dataclass fields
- embeddings.py: Add force_cpu parameter to LocalSTEmbeddings constructor
- cross_encoder.py: Add force_cpu parameter to LocalSTCrossEncoder constructor
- main.py: Set force CPU env vars in daemon mode, add fields to config constructor

The daemon mode automatically enables force CPU for both embeddings and reranker,
while normal mode allows hardware acceleration (GPU/MPS) as before.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add defensive error handling to PyTorch device detection

Wraps all PyTorch device detection code (torch.cuda.is_available()
and torch.backends.mps.is_available()) in try-except blocks that
gracefully fall back to CPU if any errors occur.

This complements PR #218's force_cpu configuration by ensuring the
code works reliably in all environments without configuration:
- CI environments with CPU-only PyTorch builds
- Systems without proper GPU/MPS support
- Partial or misconfigured PyTorch installations

The defensive approach prevents startup failures while still taking
advantage of GPU/MPS acceleration when available and force_cpu is
not explicitly set.

Changes:
- embeddings.py: Added try-except in initialize() and _reinitialize_model_sync()
- cross_encoder.py: Added try-except in initialize() and _reinitialize_model_sync()

* refactor: use get_config() for embeddings and reranker force_cpu

Changes create_embeddings_from_env() and create_cross_encoder_from_env()
to read configuration via get_config() instead of directly accessing
os.environ. This ensures consistency across the codebase and properly
respects the force_cpu configuration set by daemon mode.

Changes:
- embeddings.py: Use config.embeddings_local_model and config.embeddings_local_force_cpu
- cross_encoder.py: Use config.reranker_local_model and config.reranker_local_force_cpu
- Both: Use get_config() for provider, tei_url, and other config fields
- Note: Some fields not in config (like max_concurrent for local reranker) still read from os.environ

This fixes the issue where force_cpu was read inconsistently from environment
variables instead of using the centralized config system.

* test: clear config cache in test_create_from_env

Fixes test failure caused by cached config not picking up
environment variable changes in test. The test now calls
clear_config_cache() before and after patching os.environ
to ensure the factory function reads the test's env vars.

* refactor: add reranker_local_max_concurrent to config system

Adds reranker_local_max_concurrent to HindsightConfig dataclass
and removes the workaround in create_cross_encoder_from_env() that
was reading it directly from os.environ.

Changes:
- config.py: Add reranker_local_max_concurrent field to dataclass and from_env()
- main.py: Add reranker_local_max_concurrent to manual config constructor
- cross_encoder.py: Use config.reranker_local_max_concurrent instead of os.environ

This completes the refactoring to use the centralized config system
for all reranker configuration.

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-28 18:14:54 +01:00
Nicolò Boschi
e5fc6eedb6
fix(embed): daemon process XPC connection crash on macos (#215)
* fix(embed): daemon process XPC connection crash on macos

* other fix
2026-01-28 14:52:31 +01:00
Nicolò Boschi
ddaa5f5f1b
fix: simplify pytorch model initialization to prevent meta tensor issues (#185)
Remove device_map from model_kwargs as it conflicts with CrossEncoder's
internal .to(device) call. The low_cpu_mem_usage=False setting alone is
sufficient to prevent lazy loading (meta tensors).
2026-01-22 16:25:28 +01:00
Nicolò Boschi
0bf85a3435
fix: improve pytorch model initialization to prevent meta tensor issues (#180)
* fix: prevent meta tensor issues when accelerate is installed without GPU

When accelerate is installed but no GPU is available, transformers can
incorrectly use lazy loading (meta tensors) which fails when
sentence-transformers tries to move the model to a device.

The fix checks hardware and installed packages to determine the right
loading strategy:
- GPU available: device=None, device_map=None (auto-detect GPU)
- No GPU + accelerate: device='cpu', device_map='cpu' (force CPU loading)
- No GPU + no accelerate: device='cpu', device_map=None (normal CPU)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: add filelock for model initialization in parallel tests

When pytest-xdist runs multiple workers in parallel, they all try to
load models from the HuggingFace cache simultaneously, causing race
conditions and intermittent meta tensor errors.

Added filelock around embeddings and cross_encoder initialization in
conftest.py, similar to how pg0 database setup is serialized. Models
are now pre-initialized in the fixture before being passed to tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* fix: add MPS support for macOS Apple Silicon

Extend GPU detection to include Apple MPS backend in addition to CUDA.
This ensures macOS users with Apple Silicon use MPS acceleration
instead of being incorrectly routed to the CPU fallback path.
2026-01-20 14:15:51 +01:00
Nicolò Boschi
0284595909
fix: pytorch init failures (#175) 2026-01-19 15:02:20 +01:00
Nicolò Boschi
d47c8a28cc
feat: support litellm gateway (#154) 2026-01-13 16:55:28 +01:00
Nicolò Boschi
fa53917c63
feat: support custom url for openai embeddings & cohere (#150)
* feat: support custom url for openai embeddings & cohere

* feat: support custom url for openai embeddings & cohere
2026-01-13 14:01:44 +01:00
Nicolò Boschi
7935b0accd
fix: improve mpfp retrieval (#146)
* fix: improve mpfp retrieval

* fix: improve mpfp retrieval

* fix: improve embeddings service performances

* fix: improve embeddings service performances

* fix: improve embeddings service performances

* fix: improve embeddings service performances
2026-01-12 18:58:05 +01:00
Nicolò Boschi
eb2702bcba
misc: performance improvements (#140)
* misc: performance improvements

* misc: performance improvements

* misc: performance improvements
2026-01-09 14:47:20 +01:00
Nicolò Boschi
a6798f7e2a
fix: improve tei client parameters (#137)
* fix: improve tei client parameters

* fix: improve tei client parameters

* fix: improve tei client parameters
2026-01-09 11:31:22 +01:00
Nicolò Boschi
4de0730c40
feat: support cohere as embeddings and reranker (#122) 2026-01-08 11:41:15 +01:00
Nicolò Boschi
9394cf92f2
fix: doc build and lint files (#34)
* fix doc build

* fix doc build
2025-12-16 13:49:09 +01:00
Derek Bouius
d6b7b9b398
Fix base CI issues and the defaults in .env.example (#24)
* Add the LLM_PROVIDER in example

* fix the assert in testing recall

* trial to fix failing client tests

NotImplementedError: Cannot copy out of meta tensor; no data! Please use torch.nn.Module.to_empty() instead of torch.nn.Module.to() when moving module from meta to a different device.

* lock the sentence transformer packages to align with the breaking changes around lazy tensor loading

* Add the LLM_PROVIDER in example

* fix the assert in testing recall

* trial to fix failing client tests

* pre-cache the model so CI doesn't need workarounds

* remove assert that is a race condition

The test was checking that the bank count increased, but with parallel tests (-n 8), other tests can delete their banks while this test is running, causing a race condition. The important assertion is assert test_bank_id in final_banks - which verifies the bank was actually created.

* add debug to figure out why docker build fails sometimes

* use the CPU only version of pytorch to avoid pulling cuda libraries

* add best match strategy to uv

* change the example openai model
2025-12-11 16:48:12 -05:00
Nicolò Boschi
f42476bf94
fix: make sure openai provider works + docs updates (#23)
* fix: make sure openai provider works

* fix: make sure openai provider works

* fix
2025-12-10 16:10:10 +01:00
Nicolò Boschi
e722a48b14 add tei support 2025-12-10 12:12:21 +01:00
Nicolò Boschi
040eb33ea6
improve ci and tests (#22)
* improve ci and tests

* add more tests

* fixes

* fix tests

* fix more

* fix

* fix

* fix

* fix

* fix for real

* tests and doc

* fix cp

* fix link pg0

* fix pg0

* fix pg0

* fix pg0

* even better

* more

* fix
2025-12-09 19:16:00 +01:00
Nicolò Boschi
09fbcc2020 prepare for release 2025-12-03 11:52:25 +01:00
Nicolò Boschi
b1ff2e8823
rename to hindsight (#2) 2025-11-25 19:28:26 +01:00
Renamed from memora/memora/cross_encoder.py (Browse further)