Skip to content

fix(hindsight): declare full local_embedded pip deps + actionable upstream packaging-gap error - #57243

Draft
agy590 wants to merge 1 commit into
NousResearch:mainfrom
agy590:fix/hindsight-local-package-deps
Draft

fix(hindsight): declare full local_embedded pip deps + actionable upstream packaging-gap error#57243
agy590 wants to merge 1 commit into
NousResearch:mainfrom
agy590:fix/hindsight-local-package-deps

Conversation

@agy590

@agy590 agy590 commented Jul 2, 2026

Copy link
Copy Markdown

What changed

Three files in plugins/memory/hindsight/:

  1. plugin.yaml — added hindsight-embed>=0.8.4 and hindsight-api-slim[embedded-db]>=0.8.4 to pip_dependencies. The setup wizard (post_setup) was already installing these by hand; making them declarative fixes the silent "fresh install + edit-config mode=local_embedded + retry → ModuleNotFoundError" footgun.

  2. __init__.py — wrapped the from hindsight import HindsightEmbedded import in a try/except that raises a clear, actionable error message pointing at the three known workarounds for the upstream hindsight-all packaging gap (the bare hindsight/ package is shipped inside the wheel but its metadata does not declare it as a dependency, so neither pip install hindsight-all nor a transitive resolution makes the import succeed).

  3. README.md — added a "Local Embedded — Ollama / OpenAI-Compatible Notes" section covering:

    • Required env vars for pointing embeddings at Ollama (the embedding provider is separate from the LLM provider and not read from ~/.hermes/hindsight/config.json — only from env)
    • Ollama 0.24.x + structured output + concurrency hang and the *_MAX_CONCURRENT=1 + LLM_TIMEOUT=300 mitigations that have been stable on CPU-only Linux
    • retain_async=True recommendation (the default False blocks the client for minutes waiting on fact-extraction + embedding + consolidation)
    • The upstream hindsight-all packaging note with the three workarounds, in preference order

Why a PR and not a fresh issue

The packaging bug lives upstream in vectorize-io/hindsight. This PR does the parts that can be fixed inside hermes-agent: declaring the dependencies the wizard was already installing, and giving the next person who hits this a useful error message plus a documentation page they can land on.

Reproduction (before this PR)

$ uv pip install --python ~/.hermes/hermes-agent/venv/bin/python3 hindsight-client hindsight-embed
$ # then edit config.json mode: local_embedded
$ hermes memory status
Plugin: installed ✓
Status: not available ✗
Missing:
  ✗ HINDSIGHT_API_KEY  → ...

$ python3 -c "from hindsight import HindsightEmbedded"
ModuleNotFoundError: No module named 'hindsight'

After: hindsight-embed and hindsight-api-slim[embedded-db] are auto-installed by the plugin load, and the import either succeeds (when the upstream fix lands) or raises an actionable error pointing at workarounds.

Scope notes

  • Does not add hindsight-all as a dependency — that package has the packaging bug and would pull 1.5 GB of torch/CUDA dependencies for every plugin user.
  • Does not change retain_async default behavior — defaults stay the same, the README documents the recommendation.
  • Does not delete any existing behavior; the only logic change is the import wrapper in _get_client.

Test plan

  • Pre-PR: install with the patched pip_dependencies, verify hindsight-embed and hindsight-api-slim[embedded-db] get installed automatically
  • Trigger the upstream packaging gap by removing site-packages/hindsight/, verify the new error message is what a user sees (actionable + lists 3 workarounds)
  • Confirm cloud mode (from hindsight_client import Hindsight) path is untouched

…tream packaging-gap error

When users switch to mode: local_embedded after a fresh plugin install, they
hit 'ModuleNotFoundError: No module named hindsight' at the
'from hindsight import HindsightEmbedded' line in _get_client. The plugin's
pip_dependencies only declared 'hindsight-client' (the cloud-mode HTTP
client), but the local_embedded code path imports from 'hindsight' (a
top-level package shipped inside the 'hindsight-all' wheel whose own
setuptools metadata does not declare that bare package as installed), so
neither a fresh install nor 'pip install hindsight-all' makes the import
succeed.

This commit:

1. Adds 'hindsight-embed>=0.8.4' and 'hindsight-api-slim[embedded-db]>=0.8.4'
   to the plugin's pip_dependencies, matching what the setup wizard
   (post_setup) installs by hand. A fresh plugin install now brings the
   daemon manager and the embedded PostgreSQL backend automatically.

2. Wraps the 'from hindsight import HindsightEmbedded' import in a clear
   error message that names the upstream packaging gap (vectorize-io/hindsight
   0.8.4) and lists the three known workarounds in preference order, so the
   next person who hits this gets actionable guidance instead of a bare
   ModuleNotFoundError.

3. Adds a 'Local Embedded - Ollama / OpenAI-Compatible Notes' section to
   README.md covering:
   - required env vars for pointing embeddings at Ollama
     (HINDSIGHT_API_EMBEDDINGS_PROVIDER=openai and friends - not read from
     config.json, only from env)
   - the Ollama 0.24.x + structured-output + concurrency hang and the
     *_MAX_CONCURRENT=1 + LLM_TIMEOUT=300 mitigations
   - the retain_async=True recommendation (default False blocks the client
     for minutes waiting on fact-extraction + embedding + consolidation)
   - the upstream hindsight-all packaging note with the three workarounds
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins tool/memory Memory tool and memory providers area/nix Nix flake, NixOS module, container packaging labels Jul 2, 2026
@agy590

agy590 commented Jul 3, 2026

Copy link
Copy Markdown
Author

Tested end-to-end (2026-07-03, WSL2 + Ollama 0.24, host RAM 8GB / WSL 6GB)

Verified the full local_embedded pipeline after this PR:

Environment

  • qwen2.5:3b + nomic-embed-text:latest via Ollama 0.24
  • hindsight-api daemon auto-spawned on port 9177
  • hindsight-embed==0.8.4, hindsight-api-slim[embedded-db]==0.8.4 (declared in patched plugin.yaml)
  • WSL 2, host physical 8GB, .wslconfig set to 6GB to fit qwen2.5:3b (1.9 GB)

Results

Path Status Evidence
Plugin pip install both declared deps install automatically (was the bug pre-PR)
hindsight-api --daemon start daemon ready, /health returns {"status":"healthy","database":"connected"}
retain(bank_id='hermes', retain_async=True) 0.05s fire-and-forget, operation_id accepted
Background fact-extract (llm.openai.retain_extract_facts+structured) ⚠️ LLM-bound stalls on qwen2.5:3b (3B model insufficient for the daemon's structured fact-extract prompt at the prompt complexity Hindsight uses for entity resolution + consolidation). Larger model (≥7B) or cloud LLM unblocks this path.
recall(query=...) end-to-end 3.2s, returns semantically retrieved facts (embed → retrieval → rerank pipeline all alive)

What this PR fixes: the packaging-gap failure mode that prevents the daemon from starting at all. Pre-PR: fresh pip install hermes-agent + edit config → ModuleNotFoundError: No module named 'hindsight'. Post-PR: daemon starts, /health reports healthy, recall returns hits within 3s.

What this PR does NOT fix: fact-extract quality / LLM capacity. That is bounded by (1) the LLM model the user wires up via the HINDSIGHT_API_LLM_* env vars, and (2) the Hindsight upstream structured-fact-extract prompt complexity (the daemon's retain_extract_facts+structured stage calls the LLM with a schema that includes entity extraction + consolidation directives — empirically needs ≥7B model on CPU Linux).

Reproduction (verified):

$ uv pip install --python ~/.hermes/hermes-agent/venv/bin/python3 hermes-agent
$ ollama pull qwen2.5:3b && ollama pull nomic-embed-text
$ ~/.hermes/hermes-agent/venv/bin/hindsight-api --daemon --port 9177 &
$ curl -s http://127.0.0.1:9177/health
{"status":"healthy","database":"connected"}
$ python3 -c "from hindsight.client_wrapper import Hindsight; \
    c=Hindsight(base_url='http://127.0.0.1:9177'); \
    print(c.recall(bank_id='hermes', query='test', budget='low'))"
# returns semantically retrieved facts within ~3s

Side-note for review: the recall-side path (embed → pgvector → cross-encoder rerank) works end-to-end with qwen2.5:3b and nomic-embed-text. The retain-side fact-extract stall is a property of the Hindsight daemon's LLM-call prompt, not anything in this PR's diff.

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

Thanks for documenting a real local-embedded setup gap. The current implementation needs rework before it can safely land.

Problems

  • hermes_cli/memory_setup.py:219 and :277 install every plugin.yaml dependency before post_setup selects a Hindsight mode. Adding hindsight-embed and hindsight-api-slim at plugins/memory/hindsight/plugin.yaml:16-17 would therefore install local-only packages for cloud and local-external users.
  • The new import wrapper is after the existing runtime probe. _check_local_runtime() imports hindsight at plugins/memory/hindsight/__init__.py:135-140, and _get_client() raises at :1016-1021 when that probe fails; the proposed actionable ImportError would not be reached for the reported missing-module path.
  • The added bare >=0.8.4 constraints conflict with the bounded-dependency policy in AGENTS.md:561-576.
  • No regression test accompanies the new failure path; the existing embedded-client test mocks the runtime probe as successful at tests/plugins/memory/test_hindsight_provider.py:420-441.

Suggested changes

  • Resolve local dependencies only after local_embedded is selected, surface the diagnostic from the pre-import failure path, and add a hermetic missing-import test.

Automated hermes-sweeper review.

# (which separately pulls a fuller set including torch for sentence-transformers).
- "hindsight-client>=0.6.1"
- "hindsight-embed>=0.8.4"
- "hindsight-api-slim[embedded-db]>=0.8.4"

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.

hermes_cli/memory_setup.py:219 and :277 install all manifest dependencies before post_setup selects cloud, local_external, or local_embedded. This makes this local-only package install for cloud and external users too; keep dependency selection mode-specific inside the local-embedded setup path.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users area/memory Memory subsystem: store, providers, sync, background reviews labels Jul 15, 2026
@benfrank241

Copy link
Copy Markdown
Contributor

Thanks for tackling this @agy590 — one heads-up before this lands. I checked the published wheels (0.8.5): hindsight-embed ships only the hindsight_embed/ package (deps httpx + rich) and contains no top-level hindsight module and no HindsightEmbedded class. The local_embedded import is from hindsight import HindsightEmbedded, which is provided only by hindsight-all (its wheel ships the top-level hindsight/ package). So adding hindsight-embed to plugin.yaml wouldn't actually resolve the import — it'd still ModuleNotFoundError: No module named 'hindsight'.

The tricky part is that the correct package (hindsight-all) pulls the full server stack (hindsight-api-slim[all], torch), so declaring it unconditionally bloats cloud-only installs. I went a different route in #70295: keep plugin.yaml thin and make the runtime disable-warning actionable (point users at hindsight-all / hermes memory setup). Flagging so the two don't get merged in conflict — happy to reconcile.

zipzob added a commit to zipzob/hermes-agent that referenced this pull request Aug 6, 2026
Guard local_embedded memory tools from repeating the daemon startup wait when the embedded runtime is broken or still booting. Probe sentence_transformers before daemon startup, track startup failure state, and fail fast during the cooldown with log/status remediation hints.

Refs upstream Hindsight lifecycle/dependency work:
- NousResearch#57243
- NousResearch#51066
- NousResearch#60358

(cherry picked from commit dc92daf653f7cf583e72037d53bb1eda720f9cba)
(cherry picked from commit 4b6d16ff8aaf7f14cdac8e2ea84867837ffcc27a)
zipzob added a commit to zipzob/hermes-agent that referenced this pull request Aug 13, 2026
Guard local_embedded memory tools from repeating the daemon startup wait when the embedded runtime is broken or still booting. Probe sentence_transformers before daemon startup, track startup failure state, and fail fast during the cooldown with log/status remediation hints.

Refs upstream Hindsight lifecycle/dependency work:
- NousResearch#57243
- NousResearch#51066
- NousResearch#60358

(cherry picked from commit dc92daf653f7cf583e72037d53bb1eda720f9cba)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/memory Memory subsystem: store, providers, sync, background reviews area/nix Nix flake, NixOS module, container packaging comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades tool/memory Memory tool and memory providers type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants