Commit graph

380 commits

Author SHA1 Message Date
Volodymyr Prypeshniuk
07de798c3b
feat(google): add support for google embeddings and reranker (#863)
* Add support for google embeddings gemini/vertex and google reranker via vertex search api

* Add reference docs
2026-04-07 09:15:31 +02:00
Ben
cd4b3e96e2
blog: Persistent Memory for AutoGen Agents with Hindsight (#883)
* Add AutoGen persistent memory blog post
2026-04-06 14:59:43 -04:00
Ben
e02e7ad3d4
blog: Hindsight is now a native memory provider in Hermes Agent (#882)
* Add Hermes native memory provider blog post
2026-04-06 10:55:48 -04:00
Ben
98fee1e380
docs(hermes): update integration docs for plugin overhaul (hermes-agent#5094) (#881)
* docs(hermes): update integration docs for hermes-agent plugin overhaul
2026-04-06 10:54:59 -04:00
Nicolò Boschi
906b740dd7 fix(docs): add missing SEO frontmatter to paperclip integration 2026-04-02 17:37:02 +02:00
Nicolò Boschi
7990381f6a
fix(ci): resolve all CI failures (#847)
* fix(ci): resolve all CI failures — unversioned integrations, test retries

- Move integration docs to separate unversioned docs plugin (docs-integrations/)
  so new integrations don't need to be duplicated across versioned_docs
- Remove integration pages from versioned_docs (v0.3, v0.4) — sidebar
  entries now use links instead of doc refs
- Add missing title/description SEO frontmatter to autogen.md
- Add retry logic (2 attempts) to test-doc-examples.sh for transient
  LLM timeouts
- Add pytest-rerunfailures to test-api with --reruns 2 for flaky
  Gemini-dependent integration tests

* ci: retrigger

* fix: graph entity inheritance, SyncTaskBackend error propagation, fact_type test regressions

- Fix observation entity inheritance in get_graph_data: the unit_entities
  query only fetched entities for visible observation IDs, not their source
  memory IDs, so the inheritance loop always found an empty entity_map
- Remove error swallowing in SyncTaskBackend._execute_task so test failures
  surface instead of being silently logged
- Wrap remaining consolidation submission call sites with try/except since
  consolidation is non-critical for those operations
- Fix test_sync_backend test to expect errors to propagate
- Remove fact_type=["world"] filter from test_document_upsert_behavior and
  test_mentioned_at_from_context_string (same PR #848 regression)
- Remove flaky marker from consolidation test (now deterministic)
2026-04-02 17:17:42 +02:00
Ben
045e8910d1
Blog: Hindsight Is #1 on BEAM — the Benchmark That Tests Memory at 10M Tokens (#851)
* Add BEAM SOTA blog post
2026-04-02 11:02:16 -04:00
Ben
81441ee9af
feat(paperclip): add hindsight-paperclip TypeScript integration (#773)
* feat(paperclip): add hindsight-paperclip TypeScript integration

Adds long-term memory for Paperclip AI agents via a lightweight
TypeScript/Node.js npm package with no runtime dependencies.

- recall() / retain() functions for heartbeat lifecycle hooks
- createMemoryMiddleware() for Express HTTP adapter agents
- Bank ID strategy: paperclip::{companyId}::{agentId} (configurable)
- Skill file for agents to call Hindsight REST API directly
- 27 unit tests covering bank derivation, recall, and retain
- Docs page at sdks/integrations/paperclip

* Remove skills file from paperclip integration

* Rename package to @vectorize-io/hindsight-paperclip
2026-04-02 14:26:45 +02:00
Nicolò Boschi
30a319a6ab
feat: bank template import/export with Template Hub (#819)
* feat(api): add bank template import/export endpoints

Add POST /banks/{bank_id}/import and GET /banks/{bank_id}/export
endpoints for declarative bank setup via JSON manifests.

A template manifest (version 1) can include bank config overrides
and mental model definitions. Import creates or updates mental
models matched by id, applies config as per-bank overrides, and
returns async operation IDs for content generation.

Export dumps a bank's explicit overrides and mental models as a
manifest that can be re-imported into another bank.

Includes control plane UI: bank creation dialog now accepts an
optional template JSON to pre-configure the bank on creation.

* docs: add Template Gallery page and bank templates reference

- Template Gallery (/templates) with search, category filter, manifest
  preview modal with copy-to-clipboard
- 5 starter templates: Customer Support, Research Assistant, Personal
  Journal, Code Review Buddy, Meeting Notes
- Bank Templates API reference doc (developer/api/bank-templates)
- Sidebar entry under API section

* docs: add Template Gallery links to navbar and sidebar

- Top navbar: "Templates" link between Integrations and Changelog
- Sidebar: "Template Gallery" in Resources section

* fix(docs): remove emoji icons, autofocus search, fix placeholder in template gallery

* docs: rename to Bank Templates, move to Resources sidebar only

* docs: add Bank Templates to Resources navbar dropdown

* feat(api): add directives to bank template import/export

- Add BankTemplateDirective model with name, content, priority, is_active, tags
- Import creates/updates directives matched by name
- Export includes all directives (active and inactive)
- Validation: duplicate names rejected, empty name/content caught
- Tests: 24 tests covering directives create/update, existing vs new
  bank import, validation, export with directives, full round-trip

* docs: add directives to bank templates docs and sample templates

* feat(api): add JSON Schema endpoint for bank template validation

- GET /v1/default/bank-template-schema returns the JSON Schema
  auto-generated from the Pydantic BankTemplateManifest model
- Static schema file at docs/static/bank-template-schema.json
- Docs updated with schema endpoint, static file link, and
  validation examples (Python jsonschema, Node ajv-cli)

* feat(api): live schema validation on import, fix schema endpoint path

- Move schema endpoint to /v1/bank-template-schema (system-level, not per-bank)
- Import endpoint now accepts raw JSON and validates with Pydantic manually,
  returning clean 400 errors instead of raw 422s for all validation failures
- All validation (schema + semantic) returns consistent 400 with detailed messages

* docs: add interactive JSON Schema viewer to Bank Templates page

Renders the Pydantic-generated schema as a collapsible property tree
with types, required badges, defaults, and descriptions. The schema
is imported from the static bank-template-schema.json file.

* ui: add template toggle switch and browse link to bank creation dialog

- Replace always-visible textarea with a switch toggle ("Import from template")
- Textarea only shows when switch is on, keeping the dialog clean by default
- Add "Browse templates" link pointing to hindsight.vectorize.io/templates
- Reset template state when switch is toggled off or dialog is cancelled

* ui: add empty state with Add Document CTA to data view

When a bank has 0 memories, the data view (all tabs: constellation,
graph, table, timeline) shows a centered empty state with a CTA
button that opens the Add Document dialog.

* docs: replace templates with Conversation and Coding Agent

Remove generic placeholder templates. Add two practical templates
based on actual integration patterns:

- Conversation: for chat agents (LiteLLM, LangGraph, Pydantic AI,
  Vercel AI SDK). Tracks user preferences, open threads.
- Coding Agent: for Claude Code/Codex. Tracks technical decisions,
  project context, developer preferences. High literalism.

* docs: rename gallery to Bank Templates Hub, keep API doc as Bank Templates

* docs: register layout-template and file-json icons in navbar and sidebar

* docs: register layout-template icon in DefaultNavbarItem for dropdown items

* docs: show integration icons on template cards

Templates now have an optional `integrations` field referencing
integration IDs from integrations.json. Icons are resolved at render
time and shown in the card header next to the category badge.

* docs: add Personal Assistant template for OpenClaw, Hermes, NemoClaw

* feat: add Export Template to bank actions + map all integrations to templates

- Add "Export Template" to the bank Actions dropdown — exports config,
  mental models, and directives as JSON, copies to clipboard
- Add export API route and client method
- Map remaining integrations to templates: CrewAI, AG2, Agno, Strands,
  LlamaIndex, local-mcp, skills → Conversation; hindclaw → Personal Assistant

* feat: add --template flag to LoCoMo benchmark + remove schema from Hub

- LoCoMo benchmark accepts --template <path> to apply a bank template
  manifest (config, mental models, directives) before ingestion
- Template is applied per-bank in both single-phase and two-phase modes
- BenchmarkRunner.apply_template() reuses the same engine methods as
  the /import API endpoint
- Remove Manifest Schema section from Bank Templates Hub page
  (schema stays in the API reference doc)

* refactor: remove description field from bank template manifest

* docs: remove tags, fact_types, and directives from starter templates

* docs: remove reflect_mission and disposition fields from starter templates

* build: validate template manifests against JSON Schema during docs build

* cleanup: remove unused JsonSchemaViewer component

* docs: remove retain_extraction_mode from starter templates

* ui: enable word wrap in template manifest preview

* docs: add link to Bank Templates reference doc from Hub page

* docs: convert bank templates doc to mdx with multi-language code snippets

- Convert bank-templates.md to .mdx with Tabs/CodeSnippet components
- Add example files: bank-templates.py, .mjs, .sh, .go with doc markers
- Examples cover import, dry-run, export, round-trip, and schema
- Regenerate OpenAPI spec and all client SDKs (Python, TS, Rust, Go)

* fix: migration revision collision + use typed models in benchmark template

- Rename merge migration d6e7f8a9b0c1 -> d6e7f8a9b0c2 to resolve
  revision ID collision with case_insensitive_entities_trgm_index
- Update a4b5c6d7e8f9 down_revision to point to the renamed migration
- Fix f-string lint in case_insensitive migration
- BenchmarkRunner.apply_template() now validates manifest through
  BankTemplateManifest Pydantic model instead of raw dict access
- Remove redundant inline imports (json, Path already at module top)

* fix(docs): add missing Go tab to dry-run code snippet

* ci: retrigger

* fix: sync skills openapi.json + fix bankId null type error in export

- Copy updated openapi.json to skills/hindsight-docs/references/
- Add null guard for bankId in Export Template onClick handler

* fix: sync generated files (memory_engine formatting, docs skill references)

* cleanup: remove obsolete migration collision workaround
2026-04-02 12:21:53 +02:00
Nicolò Boschi
8d1bfbbd2b
feat: add detail parameter to list/get mental models (#846)
* feat: add detail parameter to list/get mental models (#825)

Add a `detail` query parameter (metadata|content|full) to both list and get
mental model endpoints (HTTP + MCP) to control response size. This reduces
payload for agent boot flows and MCP clients where context budget is limited.

Closes #825

* fix: update Rust CLI for optional mental model fields

The generated Rust client now has content/source_query as Option<String>
after the detail parameter was added. Update CLI code to handle optionals.
2026-04-02 11:52:45 +02:00
Nicolò Boschi
0c97b555ab release(autogen): v0.1.1 2026-04-01 17:51:46 +02:00
DK09876
a757765ab2
feat: add AutoGen integration for Hindsight (#719)
* feat: add AutoGen integration for Hindsight

Adds hindsight-autogen package providing FunctionTool instances that give
AutoGen agents persistent long-term memory via retain/recall/reflect APIs.

- Package: hindsight_autogen with create_hindsight_tools() factory
- 31 unit tests covering tool creation, invocation, config fallback, errors
- Docs page and integrations.json entry
- README with quickstart and configuration reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback for autogen integration

- Fix install instructions to include autogen-agentchat and autogen-ext[openai]
- Add autogen.svg icon to prevent broken image in integrations grid
- Change icon reference from .png to .svg in integrations.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add sleep between retain/recall and close clients in examples

- Add time.sleep(3) between retain and recall to wait for async processing
- Close Hindsight client and model client to avoid unclosed session warnings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use asyncio.sleep instead of time.sleep in async examples

time.sleep blocks the event loop; asyncio.sleep yields control.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback - validation, defaults, release script

- Add autogen to VALID_INTEGRATIONS in release-integration.sh
- Remove unused verbose config field
- Extract DEFAULT_BUDGET/MAX_TOKENS/RECALL_TAGS_MATCH constants in config.py,
  import from tools.py to eliminate default duplication
- Add Literal types for budget and recall_tags_match validation
- Modernize type hints to X | None with from __future__ import annotations
- Add [tool.ruff] line-length = 120 to match monorepo convention
- Add py.typed PEP 561 marker
- Re-raise HindsightError before broad Exception catch
- Expand asyncio.sleep(3) comment explaining when/why it's needed
- Remove verbose from docs configure() reference table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-01 17:48:11 +02:00
Ben
1a1fb35cb0
Add OpenClaw shared memory team setup guide (#788)
* Add blog post: Shared Memory for OpenClaw
2026-04-01 09:33:15 -04:00
Nicolò Boschi
914ba7962c
perf: 3-phase retain pipeline — fix deadlocks, cap temporal links, query-time entity expansion (#722)
* perf: 3-phase retain pipeline — fix deadlocks, cap temporal links, query-time entity expansion

Major retain pipeline overhaul addressing deadlocks, write amplification,
and TimeoutErrors. Restructures retain into three phases:

Phase 1: Entity resolution on separate connection (read-heavy)
Phase 2: Core write transaction (atomic) — facts, unit_entities, links
Phase 3: Best-effort display data (error-isolated) — entity viz links, stats

Key changes:
- Sorted bulk INSERT FROM unnest() prevents deadlocks
- Temporal links capped to top-20 per unit (95% reduction)
- Batched semantic ANN via temp table + LATERAL
- Query-time entity expansion via unit_entities self-join
- Entity viz links moved to Phase 3 (post-transaction)
- HINDSIGHT_API_RETAIN_MAX_CONCURRENT config (default: 32)

* fix: increase semantic link top_k from 5 to 20

The hardcoded top_k=5 was artificially limiting semantic link creation.
Link expansion retrieval can consume up to budget (50-200) semantic
neighbors per seed set, but each fact only had 5 outgoing edges — making
the bidirectional graph very sparse.

Increasing to 20 gives retrieval 4x more edges to work with. The ANN
probe cost is unchanged (same HNSW traversal per fact, just returning
more rows). INSERT cost is negligible (~14k rows via bulk INSERT).

Also: all 18 TimeoutErrors in the latest benchmark (beam-1m-u20) were
from Gemini LLM calls, zero from the database — confirming the entity
resolution split eliminated DB timeouts entirely.

* perf: move semantic ANN search to Phase 1 to avoid transaction timeouts

The batched LATERAL ANN query (700 HNSW probes) was the last remaining
source of DB TimeoutErrors — all 29 in the latest benchmark were from
create_semantic_links_batch inside the Phase 2 write transaction.

Split semantic link creation into three phases:
- Phase 1 (separate conn, autocommit): ANN search via temp table + LATERAL.
  No transaction locks, no contention with concurrent writers.
- Phase 2 (write transaction): within-batch numpy similarities (instant) +
  INSERT of both within-batch and Phase 1 ANN results. No DB reads.
- Phase 3 (flush_pending_stats): future hook point for re-checking ANN
  results after commit to catch links missed by concurrent batches.

Also adds 7 unit tests for compute_semantic_links_within_batch covering
empty input, identical/orthogonal embeddings, threshold filtering, top_k
cap, and tuple structure validation.

* fix: handle placeholder unit_ids in Phase 1 ANN search (not valid UUIDs)

* test: add Phase 1 ANN cross-batch test + configurable test PG port

- New test_semantic_links_phase1_ann_cross_batch verifies that the Phase 1
  ANN search with placeholder unit IDs correctly creates cross-batch
  semantic links after remapping to real IDs.
- Test PG port now configurable via HINDSIGHT_TEST_PG_PORT env var
  (default: 5556) to avoid conflicts with running benchmark daemons.

* perf: remove retry_with_backoff from retain, set semaphore default to 4

Remove retry_with_backoff from _run_db_work and _run_delta_db_work:
- Deadlocks are prevented by sorted bulk INSERT (no need for retry)
- Transient timeouts are handled by the worker poller's task-level retry
  (3 attempts, 60s spacing) which is better than rapid internal retries
  that amplify I/O pressure during contention storms

Set HINDSIGHT_API_RETAIN_MAX_CONCURRENT default from 32 to 4:
- The semaphore gates Phase 1 (ANN + entity resolution) + Phase 2 (writes)
- At 4 concurrent, HNSW index I/O is manageable; at 10+ concurrent the
  probes saturate disk and cause cascading timeouts
- LLM extraction still runs at full parallelism (semaphore acquired after)

* fix: add fact_type filter to Phase 1 ANN query to use per-bank HNSW indexes

The LATERAL ANN query was falling back to sequential scan + sort (90ms/probe)
because the per-bank HNSW indexes are partial indexes filtered on fact_type.
Without fact_type in the WHERE clause, PostgreSQL couldn't use them.

Fix: iterate over ('world', 'experience') and run one HNSW-indexed ANN per
type. EXPLAIN shows 8ms/probe (was 90ms) — 11x faster.

700 probes × 8ms × 2 types = ~11s total (was ~63s via seq scan).

* fix: scope temporal links by fact_type + add integration tests

Temporal links now filter by fact_type in the LATERAL query — world facts
only link to world facts, experience to experience. This matches how
retrieval filters results and avoids wasted cross-type link rows.

New integration tests:
- test_semantic_ann_uses_hnsw_index: verifies Phase 1 ANN creates
  cross-batch semantic links (tests fact_type filter + placeholder remap)
- test_temporal_links_scoped_by_fact_type: verifies world facts get
  temporal links to other world facts but NOT to experience facts

* fix: tolerate individual chunk LLM failures instead of failing entire batch

Changed asyncio.gather(*tasks) to asyncio.gather(*tasks, return_exceptions=True)
in both chunk-level and content-level fact extraction. A single chunk timeout
(e.g., Gemini >90s) no longer discards all other successfully extracted facts.

For a 50MB document with 17k chunks, even a 2% chunk failure rate previously
caused 0 completions (entire batch discarded). Now 16,700 facts are extracted
and only the 300 failed chunks are skipped with a warning log.

* fix: batch temporal LATERAL query for large documents (16k+ chunks)

The LATERAL query for temporal links passed all unit_ids at once into
unnest(), causing PostgreSQL timeouts on documents with 16k+ chunks.
Split into batches of 500 units per query to keep each under the
command_timeout.

Also identified: HNSW index creation on shared pg0 instances with
50k+ existing units exceeds the 60s command_timeout. This is a
test infrastructure issue (shared pg0 accumulates data) but also
affects production when creating new banks on large instances.

* feat: streaming chunk batching for large documents (RETAIN_CHUNK_BATCH_SIZE)

Process chunks in mini-batches of N (default 500), committing each batch
to the DB before starting the next. This prevents OOM kills on large
documents (50MB / 17k+ chunks) by keeping only ~500 facts + embeddings
in memory at a time instead of 50k+.

Each mini-batch goes through the full Phase 1 → 2 → 3 pipeline
independently, sharing the same document_id. On recovery (process dies
mid-way), delta retain detects already-committed chunks via content_hash
and skips them — only remaining chunks get re-extracted.

Config: HINDSIGHT_API_RETAIN_CHUNK_BATCH_SIZE (default: 500, 0 to disable)
Per-bank configurable via the hierarchical config system.

Tests:
- test_streaming_chunk_batching_produces_same_facts
- test_streaming_chunk_batching_recovery (delta retain skips committed chunks)
- test_streaming_disabled_for_small_docs

* perf(retain): producer-consumer pipeline + deferred semantic ANN

Replace the sequential streaming loop with a producer-consumer pipeline:
- LLM producer fires concurrent chunk extractions (semaphore-bounded)
- DB consumer drains queue in batches, runs Phase 1+2+3 per batch
- LLM and DB work overlap instead of running sequentially

Defer semantic links to a single final ANN pass after all batches commit:
- Remove within-batch semantic links from Phase 2 (was 2.6s/batch)
- Run parallel ANN (4 connections) after all facts committed
- top_k reduced from 50 to 20 (recall uses at most 20 neighbors)
- Recovery via operation result_metadata checkpoint

Additional optimizations:
- skip_exists_check on temporal/causal link INSERT (saves ~0.5s/batch)
- WHERE EXISTS guard on semantic link INSERT (handles document upsert)
- timeout=300s on ANN queries and bulk INSERT for large banks
- Demote [ANN] debug logs to logger.debug()
- Fix docstring typos (agent_id → bank_id)
- Fix content_index remapping in producer-consumer batches
- Fix delta retain passing contents vs delta_contents

50MB benchmark (mock LLM): 9.2 min (was 23 min) — 2.5x faster.
BEAM 10m benchmark: zero deadlocks, zero DB errors.

* refactor(retain): remove legacy fallback code paths

- Remove process_entities_batch (legacy single-connection entity processing)
- Remove extract_entities_batch_optimized (only caller was the above)
- Remove fallback entity processing inside Phase 2 transaction
- Remove legacy ANN inline fallback in create_semantic_links_batch
- Remove fallback entity_links direct-insert path in Phase 3
- Make resolved_entity_ids/entity_to_unit/unit_to_entity_ids required params

* refactor(retain): replace tuple returns with dataclasses, remove dead code

- Add EntityResolutionResult and Phase1Result dataclasses in types.py
- Replace 4-tuple return from _pre_resolve_phase1 with Phase1Result
- Remove dead `entity_links = []` variables in retain_batch and _try_delta_retain
- Remove unused `confidence_score` parameter from orchestrator.retain_batch
  and _retain_batch_async_internal (was accepted but never used)

* fix(entity-resolver): remove LIKE full-scan fallbacks, use index-only trigram matching

The entity resolution query had LIKE '%...' substring conditions that bypassed
the GIN trigram index, causing full sequential scans of the entities table.
On banks with 10k+ entities, this caused TimeoutErrors (observed in BEAM 10m).

Changes:
- Remove LIKE fallbacks, use trigram % operator only (GIN index-based)
- Lower similarity threshold from 0.3 to 0.15 to catch substring relationships
- Use LOWER() on both sides for case-insensitive matching
- Migration: recreate GIN trigram index on LOWER(canonical_name)

* fix: remove schema prefix from index names in trigram migration

* fix(delta-retain): use same chunk_size as streaming path (3000 vs 120000)

_chunk_contents_for_delta defaulted to chunk_size=120000 while the streaming
path used 3000. On retry, delta re-chunked the document with different
boundaries, found 0 matching chunks, and fell through to full re-extraction.
This wasted all LLM calls on already-committed chunks.

Fix: use the same default (3000) so chunk hashes match on recovery.

* fix(retain): persist generated document_id in operation metadata for retry recovery

When no document_id is provided, retain generates a UUID. On retry, a new UUID
was generated, making delta retain and streaming chunk-hash recovery unable to
find previously committed chunks. All LLM extraction was wasted on retry.

Fix: resolve document_id early in retain_batch (before delta), persist it to
operation result_metadata, and recover it on retry. Both delta and streaming
paths now see the same document_id across attempts.

* refactor(retain): unify into single streaming pipeline, remove non-streaming path

All retains now go through the producer-consumer streaming pipeline,
regardless of document size. Small documents are processed as a single batch.
This eliminates the maintenance burden of two separate code paths.

Also fix document upsert: compare content hash to distinguish recovery
(same content, partially committed) from update (different content, needs
cascade-delete). Previously, existing chunks always triggered recovery mode.

* refactor(retain): remove dead code, replace raw dicts with Phase3Context dataclass

- Remove dead _handle_zero_facts_documents (no callers after path unification)
- Remove unused imports: defaultdict, EntityLink
- Replace raw dict phase3_context with typed Phase3Context dataclass
- Update _build_and_insert_entity_links_phase3 to use typed parameter
2026-04-01 12:52:49 +02:00
Nicolò Boschi
ea834bc7dc
breaking: remove BFS and MPFP graph retrieval strategies (#767)
Remove the BFS spreading activation and MPFP (Multi-Path Fact Propagation)
graph retrieval strategies, leaving link_expansion as the sole graph
retrieval algorithm. Rename MPFPTimings to GraphRetrievalTimings and
mpfp_timings field to graph_timings since the timing struct is used by
LinkExpansionRetriever.

Deleted:
- hindsight-api-slim/hindsight_api/engine/search/mpfp_retrieval.py
- hindsight-api-slim/tests/test_mpfp_retrieval.py

Removed config: HINDSIGHT_API_MPFP_TOP_K_NEIGHBORS
2026-04-01 12:44:40 +02:00
Derek Bouius
ee4510a762
fix(deps): address critical and high severity security vulnerabilities (#827)
* fix(deps): address critical and high severity security vulnerabilities

Bump vulnerable dependencies to patched versions across the monorepo:

Python (critical/high):
- fastmcp >=2.14.0 → >=3.2.0 (SSRF, path traversal, OAuth confused deputy, command injection)
- langchain-core >=1.2.11 → >=1.2.22 (path traversal in legacy load_prompt)

Python (low):
- cryptography >=46.0.5 → >=46.0.6 (incomplete DNS name constraint enforcement)
- pygments: add >=2.20.0 pin (ReDoS via GUID regex)

Node.js:
- serialize-javascript ^7.0.3 → ^7.0.5 (CPU exhaustion DoS)
- handlebars: add >=4.7.9 override (JS injection via AST type confusion)
- path-to-regexp: add >=0.1.13 override (ReDoS via route params)
- brace-expansion: add version range override (process hang/memory exhaustion)

Also adds type: ignore comments for FastMCP 2.x private attribute access that
ty now flags since FastMCP 3.x removed _tool_manager (guarded by try/except
and hasattr at runtime).

Regenerated all lock files across API, integrations, and tests.

* fix(deps): add ajv v8 scoped overrides for schema-utils and ajv-keywords

The global ajv ^6.14.0 override caused schema-utils and ajv-keywords to
receive ajv v6, but they require ajv v8 (for dist/compile/codegen). Add
scoped overrides to ensure these packages get ajv v8 while the global
override remains for packages that need v6.

* fix(tests): remove stateless_http from FastMCP() constructor calls

FastMCP 3.x no longer accepts stateless_http in the constructor. The
tests call tools directly without HTTP transport, so the parameter is
not needed.

* fix: update MCP tests for FastMCP 3.x _tool_manager removal

FastMCP 3.x removed _tool_manager. Tests now use
_local_provider._components for sync tool dict access and
mcp.list_tools() for async filtered tool listing.

* fix: resolve docusaurus build failures (ajv overrides + missing blog date)

- Remove global ajv ^6.14.0 override and scoped ajv-keywords/schema-utils
  overrides that caused webpack compilation errors manifesting as
  "Cannot read properties of undefined (reading 'date')" during SSR
  and "these parameters are deprecated" warnings. Natural version
  resolution (v6.12.6+ for v6 consumers, v8+ for v8 consumers) already
  satisfies the security fix (>= 6.12.3).
- Add missing date frontmatter to learning-capabilities blog post.

* chore: regenerate openapi spec and docs skill
2026-04-01 09:20:34 +02:00
Nicolò Boschi
6f7437be21
blog: What's New in Hindsight 0.4.22 release notes and changelog (#818) 2026-03-31 18:47:30 +02:00
Nicolò Boschi
d7f6723546 Release v0.4.22
- Update version to 0.4.22 in all components
- Regenerate OpenAPI spec and client SDKs
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-embed
- Python client: hindsight-clients/python
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- Helm chart
- Sync documentation to version-0.4
2026-03-31 18:14:59 +02:00
Nicolò Boschi
2c32ffadc9
fix(mental-models): add tags_match and tag_groups to trigger config (#786) (#804)
When a mental model has tags, refresh_mental_model hardcoded
tags_match="all_strict", causing empty results when most memories
are untagged. Add configurable tags_match and tag_groups fields
to MentalModelTrigger so users can control refresh filtering.

- Add tags_match (any/all/any_strict/all_strict) to override default
- Add tag_groups for compound boolean tag expressions during refresh
- Default behavior unchanged (all_strict when tags present)
- Update both refresh paths (task-based and direct)
- Add UI controls in Create/Update mental model dialogs
- Regenerate OpenAPI spec and client SDKs
2026-03-31 18:09:01 +02:00
Nicolò Boschi
baf5447de2
refactor: replace LLMProvider classmethods with from_env() and document missing config fields (#816)
CI failures are unrelated to this PR:
- test_mental_models_dimension_change_empty_table: database OID error (infrastructure flake)
- test_reflect_searches_mental_models_when_available: LLM-dependent assertion (flaky)
2026-03-31 18:00:41 +02:00
Ben
410c208746
What's New: multi-org support and credit transfers (March 29) (#815)
* Add What's New post: multi-org support and credit transfers
2026-03-31 10:19:08 -04:00
Amin Bolakhrif
f841bcb92d
feat: add optional LiteLLM SDK embedding output dimensions (#809)
* feat: add optional LiteLLM SDK embedding output dimensions

Allow configuring an optional output dimension for litellm-sdk embeddings and pass it through only when set, while preserving default behavior.

Made-with: Cursor

* test: assert wrapped init error for invalid dimensions

Add a LiteLLM SDK embeddings test that verifies invalid OpenAI dimensions fail during initialize() and preserve provider error details in the wrapped RuntimeError.

Made-with: Cursor
2026-03-31 14:58:02 +02:00
Nicolò Boschi
627ec5d524
feat: expose document_metadata in API and control plane (#798)
* feat: expose document_metadata in API and control plane

Add document_metadata (sourced from retain_params.metadata) to both
list and get document endpoints. Display it in the control plane
documents table and detail panel. Drop the unused metadata column
from the documents table (was always stored as empty {}).

* fix: code review fixes for document_metadata feature

- Remove unnecessary `import json as _json` (json already imported at module level)
- Simplify redundant truthiness checks in retain_params parsing
- Regenerate OpenAPI spec and client SDKs (Python, TypeScript, Go)
- Add tests for document_metadata in get_document and list_documents

* feat(ui): improve documents table and detail panel

- Relative timestamps with full date on hover
- Remove context column from table
- Metadata shown as k=v badges (blue, like tags)
- Size in bytes instead of chars
- Document IDs wrap instead of truncating
- Detail panel wider (560px)
- Retain params: context, event_date, metadata badges
2026-03-31 11:42:02 +02:00
Nicolò Boschi
b104bad02c
fix(codex): merge new settings on upgrade instead of skipping (#780)
The installer skipped settings.json entirely if it already existed,
leaving version and new config keys stale. Now merges: updates version,
adds new upstream keys, preserves user customizations.

Also fixes pre-existing typo: RERANK_URL → rerank_url in ZeroEntropy
cross-encoder.
2026-03-31 09:05:49 +02:00
Chris Bartholomew
45ffc7fe90
SEO: add title and description to all integration pages (#787)
* SEO: add title and description to all integration pages

All 17 integration docs pages were missing title and description
frontmatter, causing Docusaurus to generate unhelpful titles like
"OpenClaw | Hindsight" and pull body text as meta descriptions.

- Add keyword-rich title and description frontmatter to all integration
  pages in both docs/ (current) and versioned_docs/version-0.4/
- Add scripts/check-integration-seo.mjs to enforce title + description
  on all future integration pages
- Wire the check into the build script so it runs locally and in CI

* Fix missing frontmatter on docs/sdks/integrations/openclaw.md

* Regenerate docs skill after integration page SEO updates
2026-03-30 17:53:43 -04:00
Chris Bartholomew
99122055f0 Improve OpenClaw post title, tags, and meta description
- Retitle to match search intent: "How to Add Persistent Memory to
  OpenClaw with Hindsight" targets openclaw memory/persistent memory queries
- Add intro paragraph before <!-- truncate --> so Docusaurus generates a
  proper meta description instead of "TL;DR"
- Expand tags from [openclaw] to include memory, agents, persistent-memory,
  knowledge-graph
2026-03-30 15:41:55 -04:00
Nicolò Boschi
75e2679cf1 release(llamaindex): v0.1.3 2026-03-30 18:34:25 +02:00
DK09876
d93dfea8ce
fix(llamaindex): document_id, memory API, and ReAct trace fixes (#777)
* fix(llamaindex): use uuid for document_id and sync version metadata

- Replace timestamp-based document_id with uuid4 hex to prevent
  collisions on rapid retains (timestamp_ms can duplicate in tight loops)
- Sync __version__ in __init__.py to match pyproject.toml (0.1.2)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(docs): pass memory to run() instead of ReActAgent constructor

LlamaIndex 0.14.x ReActAgent does not accept a memory parameter in
its constructor — it's silently dropped via **kwargs. Memory must be
passed to agent.run(memory=...) where AgentWorkflow picks it up.

Also fixes the undefined `tools` variable (now `tools=[]`).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(llamaindex): strip ReAct reasoning traces from retained assistant messages

HindsightMemory.put/aput now extracts only the final Answer: text from
assistant messages containing ReAct reasoning (Thought:/Action:/Observation:
prefixes), preventing internal reasoning traces from polluting long-term memory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(llamaindex): fix docstring example to pass memory to run()

The HindsightMemory class docstring showed the broken pattern of passing
memory= to the ReActAgent constructor, which silently drops it. Updated
to show the correct pattern: pass memory to agent.run().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 18:33:03 +02:00
Nicolò Boschi
e5209b18b3
docs: add RERANKER_ZEROENTROPY_BASE_URL to configuration page (#779)
Document the new configurable base URL for the ZeroEntropy reranker
provider added in #766. Also fix a type error where RERANK_URL was
renamed to rerank_url but one usage was missed.
2026-03-30 17:51:04 +02:00
Nicolò Boschi
a7adfbb0df release(codex): v0.2.0 2026-03-30 17:50:02 +02:00
Nicolò Boschi
2c72af5525 release(openclaw): v0.5.1 2026-03-30 16:58:18 +02:00
DK09876
7af01e35e9
fix(docs): use tools=[] in BaseMemory example (#772)
The automatic memory example referenced an undefined `tools` variable.
Since HindsightMemory handles retain/recall transparently, no tools
are needed — use an empty list.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 16:56:22 +02:00
Ben
f30ca3deda
Fix blog homepage: Hindsight Cloud section always shows top 3 posts (#770)
* Fix blog homepage: show all posts so Cloud section always gets top 3
2026-03-30 10:40:57 -04:00
Ben
d61517d502
Update MCP OAuth blog post date to 2026-03-30 (#769) 2026-03-30 13:53:41 +00:00
Ben
df17570d8a
blog: What's New in Hindsight Cloud — Native OAuth for MCP Clients (#731)
* Add MCP OAuth blog post
2026-03-30 09:33:58 -04:00
Nicolò Boschi
7a9e99998a
docs: 0.4.21 release blog post and changelog (#765)
* docs: 0.4.21 release blog post and changelog

* fix(blog): align 0.4.21 code snippets with docs, add release image

* chore: regenerate docs skill references
2026-03-30 15:28:27 +02:00
Nicolò Boschi
cc3cdc2f83 Release v0.4.21
- Update version to 0.4.21 in all components
- Regenerate OpenAPI spec and client SDKs
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-embed
- Python client: hindsight-clients/python
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- Helm chart
- Sync documentation to version-0.4
2026-03-30 14:52:50 +02:00
Nicolò Boschi
88630f93d7 release(hermes): v0.5.0 2026-03-30 14:50:04 +02:00
Nicolò Boschi
6a28373ecf release(openclaw): v0.5.0 2026-03-30 14:47:01 +02:00
Nicolò Boschi
b8b40e458b release(codex): v0.1.1 2026-03-30 14:40:58 +02:00
Nicolò Boschi
e65bd361cc release(llamaindex): v0.1.2 2026-03-30 14:37:15 +02:00
Nicolò Boschi
56489a58d1
refactor(llamaindex): merge into single hindsight-llamaindex package (#760)
* refactor(llamaindex): merge two packages into single hindsight-llamaindex

Merge `llama-index-tools-hindsight` and `llama-index-memory-hindsight` into
a single `hindsight-llamaindex` package following our naming convention.

- Rename package to `hindsight-llamaindex` (Python module: `hindsight_llamaindex`)
- Move HindsightToolSpec and HindsightMemory into the same package
- Delete `llamaindex-memory/` directory
- Add CI test job for llamaindex integration
- Update docs, blog post, and integrations.json

* fix(blog): update llamaindex blog post for merged package

- Move date to 2026-03-30
- Add HindsightMemory (automatic BaseMemory) pattern
- Fix "bank must exist first" pitfall — mission auto-creates
- Align all code examples with docs page
- Update architecture diagram to show both patterns

* fix(docs): add llamaindex/openai icons, rename Codex

- Add llamaindex.png and openai.png icons
- Rename "OpenAI Codex CLI" to "Codex" in integrations.json and docs
- Use openai.png icon for Codex integration
2026-03-30 14:30:48 +02:00
Nicolò Boschi
a8a63818c7
feat(api): add duration_ms to audit log entries (#758)
* feat(api): add duration_ms to audit log entries

Server-computed duration in milliseconds (started_at → ended_at) on
the list audit logs endpoint. Null when ended_at is not set.

Closes #749

* feat(api): add duration_ms to audit log entries and type audit endpoints

- Add server-computed duration_ms (started_at → ended_at) to audit log
  list response. Null when ended_at is not set.
- Add typed Pydantic response models for both audit log endpoints
  (list and stats) so they appear in the OpenAPI spec.
- Regenerate OpenAPI spec and all client SDKs.

Closes #749

* chore: regenerate docs skill after audit log response models
2026-03-30 12:32:02 +02:00
Nicolò Boschi
d8050387e4
fix(mcp): handle Claude Code GET probe and make stateless_http configurable (#757)
* fix(mcp): handle Claude Code GET probe and make stateless_http configurable (#751)

Claude Code v2.1.84+ sends a GET to /mcp/ before POST initialize,
which fails with 405 (stateless) or 400 (stateful). Intercept
sessionless GET requests in MCPMiddleware and return 200 OK so the
client proceeds to POST initialize.

Also make stateless_http configurable via HINDSIGHT_API_MCP_STATELESS
(default: false/stateful) instead of hardcoding true.

Closes #751

* docs: add HINDSIGHT_API_MCP_STATELESS to configuration reference
2026-03-30 12:15:06 +02:00
Nicolò Boschi
38e03e419d
Convert codex tool_choice test to pytest style (#752)
* Convert codex tool_choice test to pytest style

Follow-up to #734: replace unittest.TestCase + manual sys.path
manipulation with idiomatic pytest + @pytest.mark.asyncio,
matching the rest of the test suite.

* Fix test_hierarchical_fields_categorization for new configurable fields

Update expected count from 20 to 21 and add assertions for fields
added by recent PRs: retain_default_strategy, retain_strategies,
max_observations_per_scope, reflect_source_facts_max_tokens,
llm_gemini_safety_settings, mcp_enabled_tools.

* Add LlamaIndex doc to v0.4 versioned docs and sidebars

The LlamaIndex integration doc was added to docs/ (next version) in
#672 but not to versioned_docs/version-0.4/, causing a broken link
on the /integrations page which resolves to the latest version.

* Regenerate docs skill references

Run generate-docs-skill.sh to pick up new integration pages
(codex, llamaindex) and updated configuration docs.

* Add Codex integration doc to v0.4 versioned docs and sidebar

Same issue as LlamaIndex: doc was added to docs/ (next) but not
versioned_docs/version-0.4/, causing broken link on /integrations.
2026-03-30 11:58:59 +02:00
Nicolò Boschi
ecf16ea1e6
fix(codex): cleanup dead code, add release lifecycle and docs (#753)
* fix(codex): cleanup dead code and add to release lifecycle

- Remove orphaned reflect() method from client.py (leftover from dropped auto-mode)
- Remove dead retainToolCalls config default (never wired through)
- Add codex to release-integration.sh valid integrations
- Add settings.json version fallback to release script
- Add codex CI test job in test.yml
- Add codex to integrations.json registry

* docs(codex): add changelog page and link from integration docs

* feat(codex): add hosted installer script (get-codex)

Add self-contained installer at hindsight.vectorize.io/get-codex that
downloads scripts from GitHub, configures hooks, and supports local/cloud
mode selection — no git clone required.

Update docs and README to use the one-liner install:
  curl -fsSL https://hindsight.vectorize.io/get-codex | bash

* chore(codex): remove install.sh in favor of hosted get-codex

* fix(docs): use /next/ prefix for codex changelog link

* fix(docs): use GitHub link for codex changelog back-link
2026-03-30 11:34:43 +02:00
Ben
0b17a67c70
feat: add Hindsight memory integration for OpenAI Codex CLI (#730)
* feat(codex): add Hindsight memory integration for OpenAI Codex CLI

Hooks-based integration that gives Codex CLI long-term memory via Hindsight.
Three hooks keep memory in sync: SessionStart (daemon pre-warm), UserPromptSubmit
(recall + context injection), Stop (retain conversation to memory).

Key differences from the Claude Code integration:
- Codex transcript format: JSONL with {msg: {type, message}} (user_message/agent_message)
- No CODEX_PLUGIN_ROOT env var — install.sh writes hooks.json with absolute paths
- State stored in ~/.hindsight/codex/state/ (not CLAUDE_PLUGIN_DATA)
- No async: true in hooks (not supported by Codex)
- No SessionEnd event
- hooks.json written to ~/.codex/hooks.json with codex_hooks = true in config.toml

* fix(codex): fix transcript parser for actual Codex disk format

Codex stores sessions as rollout-*.jsonl with response_item entries:
  User:      {type:response_item, payload:{type:message, role:user, content:[{type:input_text, text:...}]}}
  Assistant: {type:response_item, payload:{type:message, role:assistant, phase:final_answer, content:[{type:output_text, text:...}]}}

Previous parser expected an undocumented {msg:{type:user_message}} format from the Rust protocol spec
that does not match the actual on-disk storage format.

* feat(codex): add reflect mode to UserPromptSubmit hook

Add recallMode config option (default: 'recall') that switches the
UserPromptSubmit hook between:
- 'recall': existing behavior, fast raw facts list
- 'reflect': agentic synthesis loop, returns coherent prose answer

Also adds reflect() method to HindsightClient and HINDSIGHT_RECALL_MODE
env var override. Reflect uses a 25s timeout (vs 10s for recall).

* feat(codex): auto mode for recall/reflect selection

Add recallMode: 'auto' (new default) that picks the operation per-query:
- Synthesis patterns (what do you know, what's my, summarize, etc.) → reflect
- All other prompts → recall (fast, raw facts, better for code tasks)

* feat(codex): add automated test suite and finalize recall-only mode

* docs(codex): add docs page and sidebar entry for Codex CLI integration
2026-03-30 10:51:53 +02:00
DK09876
2d787c4ffd
feat: add LlamaIndex integration (#672)
* feat: add LlamaIndex integration for Hindsight

Add hindsight-llamaindex package providing persistent memory tools for
LlamaIndex agents via the native BaseToolSpec pattern. Includes retain,
recall, and reflect tools, a convenience factory, global config, full
test suite, docs page, blog post, and integrations.json entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback for llamaindex integration

- Fix ReActAgent API: from_tools() → constructor, chat() → await run()
- Add create_bank step to all quickstart examples
- Add production patterns section to docs (tags, error handling, bank lifecycle)
- Add memory scoping recommendation to README
- Add when-not-to-use section to blog post
- Add LlamaIndex compatibility tests (agent acceptance, FunctionTool.call)
- Fix self-hosted auth wording in cookbook notebook

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use async client methods and asyncio.run() for runnable examples

- Use await client.acreate_bank() instead of sync create_bank() to
  avoid "event loop already running" errors in notebooks and async contexts
- Wrap plain Python examples in async def main() + asyncio.run(main())
  so they are copy-paste runnable as scripts
- Add Jupyter notebook tip to docs showing top-level await pattern
- Bank lifecycle example in docs now uses async acreate_bank

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add async tool methods to avoid event loop conflicts

HindsightToolSpec now provides both sync and async tool implementations
using LlamaIndex's (sync_fn, async_fn) tuple pattern in spec_functions.
Async agents (ReActAgent, etc.) use aretain/arecall/areflect natively,
avoiding the "Timeout context manager should be used inside a task"
error that occurred when sync _run_async() was called from within an
active event loop.

- Add aretain_memory, arecall_memory, areflect_on_memory async methods
- Extract shared kwargs builders (_retain_kwargs, _recall_kwargs, etc.)
- spec_functions now uses tuples: [("retain_memory", "aretain_memory"), ...]
- Tests verify tools have both sync fn and async fn set
- Notebook verified end-to-end with nbclient against local Hindsight

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove blog post from integration PR

The blog post will be pulled in separately from its own PR.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address PR review: add context label, document_id auto-gen, bank mission, graceful errors

- Add `retain_context` param (default: "llamaindex") as source label on retain ops
- Auto-generate `document_id` as `{session_id}-{timestamp_ms}` when not provided
- Add `retain_async` param (default: True) for non-blocking retain processing
- Add `mission` param for automatic bank creation/management on first use
- Change error handling from raising HindsightError to graceful log + return message
- Add per-operation timeout constants in _client.py
- Add `context` and `mission` fields to config.py and configure()
- Update docs: document as standalone package (not LlamaHub), new params, patterns
- Tests: 51 passing (up from 34), covering all new features

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Restructure to LlamaIndex namespace packages + add BaseMemory implementation

Tools package (llama-index-tools-hindsight):
- Restructured from hindsight_llamaindex/ to llama_index/tools/hindsight/
- Import: from llama_index.tools.hindsight import HindsightToolSpec
- Follows PEP 420 implicit namespace package convention
- Removed retain_async param (client.retain() doesn't support async_processing)

Memory package (llama-index-memory-hindsight):
- New package: llama_index/memory/hindsight/
- HindsightMemory(BaseMemory) for automatic memory
- put() auto-retains user/assistant messages to Hindsight
- get(input) auto-recalls relevant memories, prepends as system message
- Graceful error handling, bank mission management, document_id generation
- 28 unit tests passing

Both packages follow LlamaIndex community conventions for future LlamaHub submission.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 10:43:35 +02:00
Nicolò Boschi
b32767caa8
feat: add max_observations_per_scope bank config (#729)
* feat: add max_observations_per_scope bank config

Adds a configurable limit on the number of observations per tag scope.
When the limit is reached, consolidation only updates/deletes existing
observations — no new ones are created. Enforcement is done via a
constrained Pydantic response model (max_length on creates list) so the
LLM structurally cannot exceed the limit, plus prompt guidance.

- Config: HINDSIGHT_API_MAX_OBSERVATIONS_PER_SCOPE (-1 = unlimited)
- Reorder action execution: deletes → updates → creates
- Dynamic _ConsolidationBatchResponse with max_length constraint
- Prompt CAPACITY CONSTRAINT section when near/at limit
- Observations with no tags skip the limit entirely
- Control plane UI field + docs

* fix: strengthen max_observations tests with mock LLM + defensive truncation

- Rewrite integration tests to use MockLLM with deterministic responses
  (one observation per fact) instead of relying on real LLM behavior
- Add defensive truncation in _consolidate_batch_with_llm as belt-and-
  suspenders — catches LLM providers that ignore JSON schema max_length
- Tests now assert exact counts, not just upper bounds
2026-03-30 10:29:56 +02:00
Ben
a69bdbb55f
How We Built a 4-Way Hybrid Search System That Actually Runs in Parallel (#708)
* Add blog: How We Built a 4-Way Parallel Hybrid Search System

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

* Add cover image for parallel hybrid search post

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

* Update parallel hybrid search post date to 2026-03-27

* Set author to chrislatimer

* Update recall docs link

* review: align blog post to actual retrieval code

- Reframe as evolutionary narrative (V1 asyncio.gather → connection sharing)
- Add missing reranker section (cross-encoder + multiplicative boost scoring)
- Replace MPFP references with LinkExpansion (3-signal CTE)
- Fix SQL to match actual UNION ALL approach, explain CTE planner issue
- Fix acquire_with_retry, index types (ivfflat→HNSW), fusion code
- Remove fabricated perf numbers
- Add alpha calibration rationale and connection contention insight

* add nicoloboschi and benfrank241 as co-authors

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Nicolò Boschi <boschi1997@gmail.com>
2026-03-27 11:21:01 -04:00