Commit graph

559 commits

Author SHA1 Message Date
Nicolò Boschi
3d87ef5cee
doc: update cookbook (#479)
* doc: update cookbook

* fix(cookbook): preserve tag keys during sync, strip local .md links

- Fix extract_tags_from_readme/notebook to return dict[str,str] preserving
  sdk/topic keys instead of bare values, preventing topics like
  "Customer Service" from being misclassified as SDK
- Add strip_local_md_links() to remove relative .md references that
  would cause broken link errors in Docusaurus build

* ci: run test-doc-examples independently without waiting for test-rust-cli

Build the CLI directly in the job instead of downloading the artifact,
so test-doc-examples can start at the beginning in parallel with all other jobs.
2026-03-03 18:46:59 +01:00
Nicolò Boschi
5c3d3274d7
docs: 0.4.15 release blog post and changelog (#477)
* docs: add 0.4.15 release blog post and changelog

* docs: update 0.4.15 blog cover image
2026-03-03 15:52:56 +01:00
Nicolò Boschi
144e4c49d1 Release v0.4.15
- Update version to 0.4.15 in all components
- Regenerate OpenAPI spec and client SDKs
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-litellm, hindsight-crewai, hindsight-pydantic-ai, hindsight-embed
- Python client: hindsight-clients/python
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- OpenClaw integration: hindsight-integrations/openclaw
- AI SDK integration: hindsight-integrations/ai-sdk
- Chat SDK integration: hindsight-integrations/chat
- Helm chart
- Sync documentation to version-0.4
2026-03-03 15:03:42 +01:00
Nicolò Boschi
861295dd7c
refactor: replace set_gemini_safety_settings() with LLMProvider.with_config() (#474)
* refactor: replace set_gemini_safety_settings() with LLMProvider.with_config()

Removes the fragile ContextVar-setter pattern where callers had to remember
to call set_gemini_safety_settings() at every operation entry point.

Instead, LLMProvider.with_config(resolved_config) returns a
ConfiguredLLMProvider wrapper that:
- injects per-bank settings (Gemini safety settings) on every call via
  token-based ContextVar set/reset — properly scoped, no leakage
- proxies all attribute access to the underlying provider via __getattr__
- requires zero changes to LLMInterface or any provider implementations

Call sites (retain, reflect, consolidation) now pass
llm_config.with_config(resolved_config) to sub-components instead of
setting a global context var and hoping nothing else runs in between.
This pattern also composes naturally with a future per-bank provider
factory: callers always receive something with a .call() method.

* fix: pass messages/tools as kwargs in ConfiguredLLMProvider to preserve class-level patch compatibility
2026-03-03 15:00:32 +01:00
Nicolò Boschi
15f4b8769b
fix(ts-sdk): send null instead of undefined when includeEntities is false (#476)
* fix(ts-sdk): send null instead of undefined when includeEntities is false

When `includeEntities: false` was passed, the client serialized `entities`
as `undefined`, which is stripped from JSON. The API then applied its
default (`EntityIncludeOptions()` — enabled), silently ignoring the flag.

Fix: send `null` explicitly when `includeEntities === false` so the API
correctly interprets it as "disable entities".

chunks and source_facts are unaffected since their API defaults are null
(disabled), so omitting them from JSON produces the correct behaviour.

Also adds integration tests covering all three states of includeEntities.

* fix(ts-sdk): use toBeFalsy for null entity check in test
2026-03-03 14:54:48 +01:00
Nicolò Boschi
61bf428ba9
perf: fetch all recall chunks in a single query instead of batched while-loop (#475)
Replace the multi-round-trip while-loop in step 5.5 of recall_async with a
single WHERE chunk_id = ANY($1) query covering all candidate chunk IDs.
Token-budget accounting happens in Python after the single fetch.

Measured on a 97K-unit / 98M-link bank (budget=HIGH, include_chunks,
include_entities):
  p50:  1.209s → 0.611s  (−49%)
  mean: 1.534s → 0.772s  (−50%)
  p95:  3.366s → 2.316s  (−31%)

Also update recall_perf.py benchmark to use Budget.HIGH, include_chunks,
include_entities, and a realistic mixed fact_type distribution.
2026-03-03 14:52:48 +01:00
Nicolò Boschi
73ef99e7b1
feat: add configurable Gemini/Vertex AI safety settings (#473)
Adds per-bank configurable safety settings for Gemini/Vertex AI:
- New `HINDSIGHT_API_LLM_GEMINI_SAFETY_SETTINGS` env var (JSON array)
- Hierarchical config field so banks can override via Config API
- ContextVar pattern for zero-signature-change per-request override
- All 6 thresholds supported: UNSPECIFIED, OFF, BLOCK_NONE, BLOCK_LOW_AND_ABOVE, BLOCK_MEDIUM_AND_ABOVE, BLOCK_ONLY_HIGH
- UI: Models > Gemini/Vertex AI section with per-category threshold selectors and link to Google docs
- Graceful handling when bank_config_api feature is disabled
- 12 new tests covering config parsing, GeminiLLM behaviour, and context var override
2026-03-03 13:48:29 +01:00
Nicolò Boschi
7942f181c2
fix(performance): improve recall and retain performance on large banks (#469) 2026-03-03 13:35:22 +01:00
Anton Evseev
5aff8e0c70
refactor(openclaw): replace console.log with debug() helper gated by plugin config (#456)
Replace ~73 console.log calls with a debug() helper that is silent by default.
Debug output is now controlled via plugin config param (debug: true) instead of
environment variables, making it easier for users to configure.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:05:04 +01:00
DK09876
e407f4bc55
feat: add extension hooks for root routing and error headers (#470)
* feat: add OAuth extension hooks for MCP authentication

Add extension points in core that allow cloud extensions to support
OAuth 2.1 (RFC 9728 / RFC 7591) for MCP server authentication:

- HttpExtension.get_root_router() for well-known endpoint mounting
- AuthenticationError.headers for WWW-Authenticate propagation
- MCP middleware forwards auth error headers to clients

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

* docs: document get_root_router and AuthenticationError.headers

Add documentation for the new extension points introduced in the
OAuth extension hooks commit.

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

* Remove OAuth-specific wording from extension docs

Make the AuthenticationError headers example generic instead of
OAuth-specific, since these are general-purpose extension hooks.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:50:03 +01:00
Ben
8138fa9002
blog: add CrewAI persistent memory post (#471)
* Add CrewAI persistent memory blog post

* Update blog: add image, remove full example and alternatives sections

* Add CrewAI blog hero image
2026-03-02 16:00:27 -05:00
Nicolò Boschi
1d70abfe85
feat: add tags filtering and q description fix for list documents API (#468)
* feat: add Pydantic AI integration to CI, release pipeline, and docs

- Add test-pydantic-ai-integration job to CI (test.yml)
- Add build, publish, and artifact steps to release workflow (release.yml)
- Add hindsight-integrations/pydantic-ai to release.sh version bumping
- Add Pydantic AI documentation page (sdks/integrations/pydantic-ai.md)
- Add Pydantic AI entry to sidebar with icon

* docs: remove Requirements section from pydantic-ai integration page

* feat: add tags filtering and fix offset pagination docs for list documents API

- Add `tags` and `tags_match` query params to GET /banks/{bank_id}/documents
- Supports any, all, any_strict, all_strict matching modes (default: any_strict)
- Fix `q` param description — it's a case-insensitive substring match on document ID only
- Add tests for offset pagination and all tags_match modes
- Regenerate OpenAPI spec and Python/TypeScript/Go clients
- Document the new filtering options in docs/developer/api/documents.mdx

* fix(cli): pass new tags/tags_match args to list_documents
2026-03-02 17:03:16 +01:00
Nicolò Boschi
ecf609c8aa
feat: add Pydantic AI integration to CI, release pipeline, and docs (#467)
* feat: add Pydantic AI integration to CI, release pipeline, and docs

- Add test-pydantic-ai-integration job to CI (test.yml)
- Add build, publish, and artifact steps to release workflow (release.yml)
- Add hindsight-integrations/pydantic-ai to release.sh version bumping
- Add Pydantic AI documentation page (sdks/integrations/pydantic-ai.md)
- Add Pydantic AI entry to sidebar with icon

* docs: remove Requirements section from pydantic-ai integration page
2026-03-02 15:40:37 +01:00
Ben
cab5a40f3a
feat: add Pydantic AI integration for persistent agent memory (#441)
* feat: add Pydantic AI integration for persistent agent memory

Adds hindsight-pydantic-ai package providing Hindsight-backed memory
tools for Pydantic AI agents. Since Pydantic AI is async-native, tools
use the hindsight-client async API directly (no thread-pool compat layer).

- create_hindsight_tools(): factory returning retain/recall/reflect Tool instances
- memory_instructions(): auto-injects relevant memories via Agent instructions
- Global configure()/get_config()/reset_config() following existing integration pattern

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

* doc: add README for Pydantic AI integration

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:14:00 +01:00
Nicolò Boschi
ab70da1ead
docs: entities vs tags vs metadata (#466)
* docs: move entity labels detail to memory-banks, simplify retain overview

* docs: move entity labels blurb under entity-recognition section in retain

* docs: update metadata filtering FAQ to cover entity graph retrieval and entity labels tag option

* docs: enable TOC and fix missing separators in FAQ

* docs: add benchmarks leaderboard screenshot and link to models page

* docs: add 'Which model should I use?' FAQ entry with leaderboard screenshot

* docs: fix leaderboard description to cover retain, reflect, and observations
2026-03-02 14:47:40 +01:00
Nicolò Boschi
9b96becc5c
feat: entity labels — optional, free_values, multi_value, UI polish (#450)
* feat: entity labels

* feat: entity labels — optional, free_values, multi_value, UI polish

Completes the entity labels system:

**Schema & extraction**
- Dynamic Pydantic Labels model per fact: each group becomes a typed
  field (Literal | None, list[Literal], str | None, or list[str])
- `optional: bool` flag per group — non-optional enum fields appear in
  JSON schema required array so structured-output providers enforce them
- `free_values: bool` flag per group — accepts any LLM-generated string
  instead of a predefined enum; example values shown as hints in prompt
- New `is_label_entity()` helper for labels-only mode filtering that
  handles both enum lookup and free_values key-prefix matching
- Sentinel rejection: "None"/"null"/"n/a" strings dropped in post-processing

**BM25 / dense retrieval**
- `text_signals` column on memory_units: entity names + date tokens for
  enriched BM25 indexing without polluting stored fact text
- Dense embedding includes occurred_end when it differs from occurred_start
- Alembic migration z1u2v3w4x5y6 (merge revision fixing two heads)

**UI (bank-config-view)**
- Shadcn Switch replaces custom Toggle for both entity-labels and observations
- Shadcn Checkbox for multi/optional/free_values per group
- Input heights bumped to h-8 throughout the editor
- "Label Groups" → "Entity Labels", "Free-form entities" → "Entities"
- Free-text groups show "Example hints" banner in values section

**Tests (45 unit + 3 LLM integration)**
- build_labels_model: single, multi, mixed, free_values optional/required/multi
- is_label_entity: enum match, free_values prefix match, no false positives
- Post-processing: null/absent/string-None/free_values/sentinels/multi-value
- Schema: labels in required, structured object, no labels when unconfigured
- LLM integration: single-value enum, multi-value enum, free_values retain

**Docs**
- retain.md: new Entity Labels section covering groups, flags, examples
- configuration.md: retain_free_form_entities env var + entity_labels note

* fix(tests): update hierarchical fields count for entity_labels additions

entity_labels and retain_free_form_entities are hierarchical fields,
bumping the expected count from 11 to 13.

* fix(migration): rename text_signals revision to avoid collision with main

Main branch claimed z1u2v3w4x5y6 for observation_scopes. Rename our
text_signals migration to a2b3c4d5e6f7, chaining after z1u2v3w4x5y6.

* refactor(entity-labels): simplify free_values — always str|None, no multi

- free_values groups always produce str | None (multi_value and optional
  flags are ignored for free text groups — always optional, never multi)
- Prompt section for free_values groups shows only key + description,
  no values list (users put examples in the description instead)
- UI: section title "Entities", toggle "Free Form Entities", replace
  per-group checkboxes with a type dropdown (Enum / Free text); only
  show multi checkbox and values list when type is Enum
- Update tests to reflect new behaviour

* refactor(entity-labels): replace free_values/multi_value booleans with type field

- LabelGroup now uses type: "value" | "multi-values" | "text" instead of
  free_values/multi_value boolean pair
- Backward-compat migration converts legacy dicts automatically
- Rename retain_free_form_entities → entities_allow_free_form throughout
- Update UI dropdown to show Single value / Multi-values / Free text
- Remove separate multi checkbox (captured by type selection)
- Update docs examples and configuration.md
- Update all tests to use new field names

* fix(migration): backfill observation_scopes column for DBs with swapped z1u2v3w4x5y6

Local DBs that had z1u2v3w4x5y6 applied when it referred to the old
text_signals migration (before it was renamed to a2b3c4d5e6f7) won't have
observation_scopes in their memory_units table. This migration adds the
column with IF NOT EXISTS so it's a no-op on clean installs.

* feat(entity-labels): add tag field to auto-populate memory unit tags from labels

When a LabelGroup has tag=True, extracted key:value entities for that group
are automatically written to the memory unit's tags array. This lets entity
labels double as tags, enabling immediate filtering via the existing
tags/tags_match API params with no extra infrastructure.

- Add tag: bool = False to LabelGroup
- _inject_label_tags() helper called in both sync and batch extraction paths
- UI: add Tag checkbox per label group row
- Docs: document the new tag field
- Tests: 4 new unit tests covering all tag injection paths

* style: ruff format migration file

* fix(migration): fix multiple alembic heads after rebase — point text_signals after nullable_event_date

* fix(clients): update timestamp field to use Timestamp wrapper type after timestamp=unset feature

* style: ruff format agent.py

* fix(docs): update Go quickstart example to use NullableTimestamp for timestamp field
2026-03-02 13:05:25 +01:00
Nicolò Boschi
f903948a26
feat: support timestamp="unset" to retain content without a date (#465)
* feat: support timestamp="unset" to retain content without a date

When callers retain timeless content (e.g. fictional documents, static
reference material), passing timestamp="unset" now skips the utcnow()
default so mentioned_at is stored as NULL instead of an artificial date.

- HTTP: validate_timestamp recognises "unset" sentinel and threads it
  through api_retain as event_date=None (key present, value None), which
  the orchestrator distinguishes from key-absent (still defaults to now)
- Orchestrator: new branching logic separates "key absent" → utcnow()
  from "key present but None" → no date
- types.py: RetainContent.event_date and ProcessedFact.mentioned_at are
  now datetime | None; removed the unused _now_utc factory
- fact_extraction.py: all event_date params accept datetime | None;
  _build_user_message emits "Event Date: Unknown" when None; removed
  mentioned_at from the Fact LLM response model (LLM never sets it)
- embedding_processing: skip date suffix when fact_date is None
- entity_resolver: COALESCE(event_date, now()) for first_seen/last_seen
  so entities table NOT NULL constraint is preserved
- link_utils: skip temporal linking for units without event_date
- Migration aa2b3c4d5e6f: DROP NOT NULL on memory_units.event_date
- Tests: test_retain_no_timestamp and test_retain_omit_timestamp_defaults_to_now
- Docs + OpenAPI + TypeScript client updated

* refactor: replace _TIMESTAMP_UNKNOWN sentinel with plain string comparison

The sentinel object() was only needed to distinguish "unset" from None
at the boundary — but since the field type is datetime | str | None,
"unset" can pass through the validator unchanged and be compared directly.

* chore: regenerate OpenAPI spec and clients after timestamp type change

timestamp field is now datetime | str | None to accept the "unset" sentinel value.
2026-03-02 12:03:23 +01:00
Nicolò Boschi
77defd96e9
fix(reflect): prevent context_length_exceeded on large memory banks (#462)
* fix(reflect): prevent context_length_exceeded on large memory banks (#457)

The reflect agent's agentic loop accumulated tool-call messages across
iterations with no upper bound on token count, causing
context_length_exceeded errors on banks with 19K+ nodes.

Changes:
- Add proactive token-budget guard: before each call_with_tools, count
  accumulated message tokens via tiktoken; if >= max_context_tokens and
  evidence has been gathered, immediately synthesize from what was found
- Detect context-overflow errors specifically (_is_context_overflow_error)
  and skip the retry path — retrying after overflow only makes it worse
- Truncate context_history in build_final_prompt to a 60K-token budget
  so the fallback synthesis prompt itself cannot overflow
- Add HINDSIGHT_API_REFLECT_MAX_CONTEXT_TOKENS config (default 100000)
  wired through config.py → main.py → memory_engine → run_reflect_agent
- Tests: unit tests for helpers + mock-LLM behavior tests + an
  end-to-end integration test using a real LLM with max_context_tokens=1

* fix(reflect): derive final prompt context budget from max_context_tokens

Replace the hardcoded _FINAL_PROMPT_CONTEXT_BUDGET (60K tokens) with
a fraction of max_context_tokens (80%), so the fallback synthesis prompt
automatically scales with whatever context window is configured.
2026-03-02 12:03:12 +01:00
Nicolò Boschi
c2876490df
fix: resolve consolidation deadlock caused by zombie processing tasks on retry (#463)
* fix: resolve consolidation deadlock caused by zombie 'processing' tasks on retry

When a task failed and was rescheduled for retry, submit_task() only updated
task_payload without resetting status/worker_id/claimed_at. The task stayed
permanently in 'processing', blocking all future consolidation for that bank
via the NOT EXISTS guard in claim_batch().

Fix: remove the duplicate payload-based retry mechanism from execute_task().
Retryable failures now re-raise so the poller handles them via _retry_or_fail(),
which already correctly resets status='pending', worker_id=NULL, claimed_at=NULL
and uses the DB retry_count column as single source of truth.

Non-retryable tasks (file_convert_retain) continue to mark themselves failed
and return normally — no exception reaches the poller.

Tests: add regression tests for the retry path (status reset to pending) and
the max-retries exhaustion path (status set to failed).

* ci: re-trigger CI
2026-03-02 11:45:41 +01:00
Nicolò Boschi
eaeaa1f24d
fix(control-plane): observations count always showing 0 due to wrong field name (#464)
The BankStats interface used total_mental_models but the API returns
total_observations, causing the Observations card to always display 0.
2026-03-02 11:20:19 +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
Nicolò Boschi
ecb833f40d
fix: resolve JSON serialization and logging exception propagation in claude_code_llm (#458, #459) (#461)
- Replace json.dumps(result) with result.model_dump_json() for Pydantic models to fix TypeError during consolidation
- Wrap record_llm_call tracing block in try/except so logging failures never propagate to retry handler
- Fix test_llm_provider.py to use _get_raw_config() for bank-configurable enable_observations field
2026-03-02 10:14:16 +01:00
Chris Bartholomew
5270aa5a6e
Add bank-scoped validation to engine and HTTP handlers (#454)
* feat: add bank-scoped validation to engine methods and HTTP handlers

Add validate_bank_read/validate_bank_write hooks to all bank-scoped
engine methods so the operation validator can enforce per-bank API key
restrictions. Add OperationValidationError handling to HTTP handlers
and MCP tools to return proper 403 responses. Add allowed_bank_ids
field to RequestContext.

* Add OperationValidationError handling to mental model GET and DELETE endpoints
2026-03-02 09:55:21 +01:00
Fabio Scarsi
ad1660b313
feat(openclaw): retain last n+2 turns every n turns (default n=10) (#452) 2026-03-02 09:44:52 +01:00
Nicolò Boschi
55af468187
feat: observation_scopes field to drive observations granularity (#447)
* feat: observation_scopes field to drive observations granularity

* fix(migration): make a2b3c4d5e6f7 a no-op to fix CI on fresh DB

The z1u2v3w4x5y6 migration already creates observation_scopes directly,
so the rename migration fails on fresh installs where observation_tags
never existed.

* chore: remove no-op migration a2b3c4d5e6f7

* feat: regenerate clients with observation_scopes field

- Add observation_scopes to OpenAPI spec and all generated clients
- Fix Rust build.rs to handle anyOf with >2 variants containing null
  (previously only handled 2-item anyOf, causing progenitor to panic
  on the observation_scopes union type)

* fix(rust): add observation_scopes: None to MemoryItem struct literals

* fix(api): add title to observation_scopes Field for deterministic client generation

Adding title="ObservationScopes" makes the inline anyOf schema use
the explicit name instead of deriving it from the field name, which
was non-deterministic between arm64 (macOS) and amd64 (CI) Docker.

Also fixes description: "each entity" -> "each tag".

* fix(scripts): use linux/amd64 Docker for client generation to ensure reproducibility

Both Python and Go client generation now use --platform linux/amd64
Docker, ensuring identical output on macOS arm64 (local) and Linux
amd64 (CI). Also switches Go from JAR+Java to Docker to eliminate
Java version variability.

* chore: update generated clients to API v0.4.14

* fix(test): add retry logic to test_retain_chinese_content to handle non-deterministic LLM output

* fix(test): mark test_retain_chinese_content as xfail due to non-deterministic LLM translation
2026-02-28 10:46:21 +01:00
Nicolò Boschi
2b5fb10dab
doc: 0.4.14 (#449) 2026-02-27 15:41:08 +01:00
Nicolò Boschi
5443c18bfc
doc: improvements (#448) 2026-02-27 14:59:11 +01:00
Nicolò Boschi
1c21c0c1a6
doc: changelog and blog post (#445)
* doc: changelog and blog post

* doc: changelog and blog post

* sync
2026-02-26 20:24:53 +01:00
Nicolò Boschi
145454533c Release v0.4.14
- Update version to 0.4.14 in all components
- Regenerate OpenAPI spec and client SDKs
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-litellm, hindsight-crewai, hindsight-embed
- Python client: hindsight-clients/python
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- OpenClaw integration: hindsight-integrations/openclaw
- AI SDK integration: hindsight-integrations/ai-sdk
- Chat SDK integration: hindsight-integrations/chat
- Helm chart
- Sync documentation to version-0.4
2026-02-26 18:03:14 +01:00
Nicolò Boschi
9aaa78b9a6 fix: doc build 2026-02-26 18:01:56 +01:00
Nicolò Boschi
bfa09d1685
fix: doc build and add chat doc (#444)
* fix doc build and add chat doc

* fix doc build and add chat doc
2026-02-26 17:55:36 +01:00
Nicolò Boschi
6f5245ae58
chore: integrate chat with release (#443)
* integrate chat with release

* integrate chat with release
2026-02-26 17:38:51 +01:00
Ben
fed987f931
feat: add Chat SDK integration for persistent chat bot memory (#442)
Adds @vectorize-io/hindsight-chat, a wrapper for the Vercel Chat SDK
that gives any chat bot (Slack, Discord, Teams, etc.) long-term memory
via Hindsight. Includes withHindsightChat() handler wrapper with
auto-recall, auto-retain, and memoriesAsSystemPrompt() formatting.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 17:07:47 +01:00
Anton Evseev
8cd65b9896
fix: raise error when embedding dimensions exceed pgvector HNSW limit (#361)
Instead of silently skipping HNSW index creation for embeddings > 2000
dimensions, raise a RuntimeError with an actionable message suggesting
pgvectorscale/DiskANN as an alternative.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:24:17 +01:00
Nicolò Boschi
b813bd2728 doc: fix build 2026-02-25 16:58:06 +01:00
And#ocean
86d8ac08b1
fix(storage): use dynamic schema_getter in PostgreSQLFileStorage for multi-tenant (#440)
PostgreSQLFileStorage was initialized once at startup with a static
schema value. Since get_current_schema() returns the default schema at
init time, multi-tenant requests always queried the wrong schema,
causing "relation file_storage does not exist" errors.

Replace static schema with schema_getter callable (same pattern used
by BrokerTaskBackend since #208) so the schema is resolved dynamically
per-request via contextvars.
2026-02-25 15:19:08 +01:00
Nicolò Boschi
4b328a9cb3
feat: configure exposed mcp tools per bank (#439)
* feat: configure exposed mcp tools per bank

* fix: update configurable fields count to 11 after adding mcp_enabled_tools
2026-02-25 11:57:46 +01:00
Sense_wang
f5b94d4b28
fix: catch ValueError instead of bare except in date parsing (#438)
The datetime.strptime() call can only raise ValueError on format
mismatch. Bare except catches KeyboardInterrupt and SystemExit,
which masks real errors.

Co-authored-by: haosenwang1018 <haosenwang1018@users.noreply.github.com>
2026-02-25 10:33:56 +01:00
Eliah Rusin
58f2de70fb
fix: pass encoding_format="float" in LiteLLM embedding calls (#434)
DeepInfra rejects requests when encoding_format is null. LiteLLM sets
it to None by default, so we explicitly pass "float" — the only format
compatible with our list[list[float]] return type.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:32:05 +01:00
Nicolò Boschi
0bb5ca4caf
feat: filter graph memories with tags (#431)
* feat: filter graph memories with tags

* fix(cli): pass new q/tags/tags_match args to get_graph

* docs: use CodeSnippet for tags_match examples in recall.mdx
2026-02-25 10:31:40 +01:00
DK09876
3ffec65090
feat: expand MCP tool surface area with 18 new tools and enhanced parameters (#435)
Add directives, memory browsing, documents, operations, tags, and bank
management tools to the MCP server. Expose previously hardcoded parameters
(budget, types, tags, response_schema, trigger) on retain, recall, reflect,
and mental model tools. Update docs for all new tools and parameters.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:26:46 +01:00
Nicolò Boschi
0aa7c2b3a1
feat: batch observations consolidation (#430)
* feat: batch observations consolidation

* feat: batch observations consolidation

* docs: add CONSOLIDATION_LLM_BATCH_SIZE config flag documentation
2026-02-24 15:19:39 +01:00
Nicolò Boschi
ac9a94ade3
fix: handle observations regeneration when memories get deleted (#429)
* fix: handle observations regeneration when memories get deleted

* feat: add clear_memory_observations endpoint and regenerate clients

- Add DELETE /banks/{id}/memories/{memory_id}/observations endpoint
- Add observations lifecycle/invalidation section to docs
- Regenerate OpenAPI spec and all clients (Python, TypeScript, Go, Rust)

* refactor: use dedicated response model for clear_memory_observations, remove code example from docs
2026-02-24 13:26:33 +01:00
Anton Evseev
40b02645f4
fix(openclaw): pass auth token to health check endpoint (#427)
The checkExternalApiHealth function didn't include the Bearer token
in its requests. When the Hindsight API requires authentication
(HINDSIGHT_API_TENANT_API_KEY), health checks would fail with 401/403,
preventing plugin initialization.

Pass apiToken to all checkExternalApiHealth call sites and include
the Authorization header when a token is configured.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 13:17:00 +01:00
Nicolò Boschi
5fddd9a79c
feat: add reflect mode to LoComo benchmark and improve reflect agent (#428)
* feat: add reflect mode to LoComo benchmark and improve reflect agent

- Replace think mode with reflect mode in LoComo benchmark using reflect_async with Budget.HIGH
- Add --question-index CLI flag to run a single question by its index
- Track and display original question index in logs and visualizer
- Update visualizer to show reflect mode results

Reflect agent improvements:
- tool_recall: always fetch chunks (max_chunk_tokens=1000 min, non-optional)
- tool_search_observations: use include_source_facts=True instead of separate DB query
- Use model_dump() throughout to avoid manual error-prone dict conversion
- Enforce minimum 1000 tokens for max_tokens and max_chunk_tokens in _execute_tool
- Fix NoneType error when LLM passes null for mental_model_ids/observation_ids arrays
- Add non-conversational constraint to system prompt to prevent follow-up questions
- Fix recall_fn Callable type hint to include max_chunk_tokens parameter
- Fix main.py missing reranker_zeroentropy fields in HindsightConfig constructor

* fix: update tests for reflect tool API changes

- source_memory_ids -> source_fact_ids in test_search_observations (MemoryFact.model_dump() field name)
- Remove proof_count check (not in MemoryFact, was ObservationResult-specific)
- Remove max_results param from tool_recall call (no longer supported)
- Fix recall_result["count"] -> len(recall_result["memories"])
2026-02-24 09:48:23 +01:00
Nicolò Boschi
4d030707ad
feat: enable bank config API by default (#426)
Change DEFAULT_ENABLE_BANK_CONFIG_API from false to true, update all docs,
error messages, and client docstrings to reflect the new default. Remove
explicit env var overrides in CI and tests that are no longer needed.
2026-02-24 08:52:42 +01:00
Chris Bartholomew
5fef54d501 Fix typos in README 2026-02-23 15:32:49 -05:00
Nicolò Boschi
2a32273226
feat: increase customization for reflect, retain and consolidation (#419) 2026-02-23 20:35:32 +01:00
Nicolò Boschi
87219b731d
feat: include doc metadata in fact extraction (#424) 2026-02-23 11:31:02 +01:00
Nicolò Boschi
9f0c031df7
fix: improve memory footprint of recall (#423) 2026-02-23 11:30:16 +01:00