Compare commits
3
Commits
main
...
fix/ci-failures
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
056083f810 | ||
|
|
e8a46f4474 | ||
|
|
66d0d3c83a |
+2
-5
@@ -1,7 +1,7 @@
|
||||
"""Fix per-bank vector indexes to match configured extension
|
||||
|
||||
Revision ID: a4b5c6d7e8f9
|
||||
Revises: c2d3e4f5g6h7, c5d6e7f8a9b0
|
||||
Revises: d6e7f8a9b0c1
|
||||
Create Date: 2026-04-01
|
||||
|
||||
Migration d5e6f7a8b9c0 hardcoded HNSW when creating per-bank partial vector
|
||||
@@ -21,10 +21,7 @@ from alembic import context, op
|
||||
from sqlalchemy import text
|
||||
|
||||
revision: str = "a4b5c6d7e8f9"
|
||||
# Updated: the merge migration d6e7f8a9b0c1 was renamed to d6e7f8a9b0c2
|
||||
# to avoid colliding with the case_insensitive_entities_trgm_index migration
|
||||
# that shares the same revision ID.
|
||||
down_revision: str | Sequence[str] | None = "d6e7f8a9b0c2"
|
||||
down_revision: str | Sequence[str] | None = "d6e7f8a9b0c1"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
@@ -3625,7 +3625,10 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
}
|
||||
|
||||
if invalidated_obs > 0:
|
||||
await self.submit_async_consolidation(bank_id=bank_id, request_context=request_context)
|
||||
try:
|
||||
await self.submit_async_consolidation(bank_id=bank_id, request_context=request_context)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to submit consolidation after document deletion for bank {bank_id}: {e}")
|
||||
|
||||
return result
|
||||
|
||||
@@ -3759,7 +3762,10 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
)
|
||||
|
||||
if invalidated_obs > 0:
|
||||
await self.submit_async_consolidation(bank_id=bank_id, request_context=request_context)
|
||||
try:
|
||||
await self.submit_async_consolidation(bank_id=bank_id, request_context=request_context)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to submit consolidation after document update for bank {bank_id}: {e}")
|
||||
|
||||
return True
|
||||
|
||||
@@ -3821,7 +3827,14 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
}
|
||||
|
||||
if bank_id_for_consolidation:
|
||||
await self.submit_async_consolidation(bank_id=bank_id_for_consolidation, request_context=request_context)
|
||||
try:
|
||||
await self.submit_async_consolidation(
|
||||
bank_id=bank_id_for_consolidation, request_context=request_context
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"Failed to submit consolidation after memory deletion for bank {bank_id_for_consolidation}: {e}"
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@@ -3830,6 +3843,7 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
bank_id: str,
|
||||
fact_type: str | None = None,
|
||||
*,
|
||||
delete_bank_profile: bool = True,
|
||||
request_context: "RequestContext",
|
||||
) -> dict[str, int]:
|
||||
"""
|
||||
@@ -3916,20 +3930,21 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
# Delete entities (cascades to unit_entities, entity_cooccurrences, memory_links with entity_id)
|
||||
await conn.execute(f"DELETE FROM {fq_table('entities')} WHERE bank_id = $1", bank_id)
|
||||
|
||||
# Delete the bank profile and retrieve internal_id for HNSW index cleanup
|
||||
internal_id = await conn.fetchval(
|
||||
f"DELETE FROM {fq_table('banks')} WHERE bank_id = $1 RETURNING internal_id", bank_id
|
||||
)
|
||||
if internal_id:
|
||||
bank_internal_id = str(internal_id)
|
||||
|
||||
result = {
|
||||
"memory_units_deleted": units_count,
|
||||
"entities_deleted": entities_count,
|
||||
"documents_deleted": documents_count,
|
||||
"bank_deleted": True,
|
||||
}
|
||||
|
||||
if delete_bank_profile:
|
||||
# Delete the bank profile and retrieve internal_id for HNSW index cleanup
|
||||
internal_id = await conn.fetchval(
|
||||
f"DELETE FROM {fq_table('banks')} WHERE bank_id = $1 RETURNING internal_id", bank_id
|
||||
)
|
||||
if internal_id:
|
||||
bank_internal_id = str(internal_id)
|
||||
result["bank_deleted"] = True
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Failed to delete agent data: {str(e)}")
|
||||
|
||||
@@ -3940,7 +3955,10 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
await bank_utils.drop_bank_vector_indexes(conn, bank_internal_id)
|
||||
|
||||
if invalidated_obs > 0:
|
||||
await self.submit_async_consolidation(bank_id=bank_id, request_context=request_context)
|
||||
try:
|
||||
await self.submit_async_consolidation(bank_id=bank_id, request_context=request_context)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to submit consolidation after bank deletion for bank {bank_id}: {e}")
|
||||
|
||||
return result
|
||||
|
||||
@@ -4331,7 +4349,10 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
]
|
||||
|
||||
# Get entity information — only for visible units
|
||||
if unit_ids:
|
||||
# Fetch entities for visible units AND their source memories
|
||||
# (so observations can inherit entities from source memories)
|
||||
entity_lookup_ids = unit_ids + source_memory_ids
|
||||
if entity_lookup_ids:
|
||||
unit_entities = await conn.fetch(
|
||||
f"""
|
||||
SELECT ue.unit_id, e.canonical_name
|
||||
@@ -4340,7 +4361,7 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
WHERE ue.unit_id = ANY($1::uuid[])
|
||||
ORDER BY ue.unit_id
|
||||
""",
|
||||
unit_ids,
|
||||
entity_lookup_ids,
|
||||
)
|
||||
else:
|
||||
unit_entities = []
|
||||
@@ -6340,6 +6361,7 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
*,
|
||||
tags: list[str] | None = None,
|
||||
tags_match: str = "any",
|
||||
detail: str = "full",
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
request_context: "RequestContext",
|
||||
@@ -6350,6 +6372,7 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
bank_id: Bank identifier
|
||||
tags: Optional tags to filter by
|
||||
tags_match: How to match tags - 'any', 'all', or 'exact'
|
||||
detail: Detail level - 'metadata', 'content', or 'full'
|
||||
limit: Maximum number of results
|
||||
offset: Offset for pagination
|
||||
request_context: Request context for authentication
|
||||
@@ -6391,13 +6414,14 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
*params,
|
||||
)
|
||||
|
||||
return [self._row_to_mental_model(row) for row in rows]
|
||||
return [self._row_to_mental_model(row, detail=detail) for row in rows]
|
||||
|
||||
async def get_mental_model(
|
||||
self,
|
||||
bank_id: str,
|
||||
mental_model_id: str,
|
||||
*,
|
||||
detail: str = "full",
|
||||
request_context: "RequestContext",
|
||||
) -> dict[str, Any] | None:
|
||||
"""Get a single pinned mental model by ID.
|
||||
@@ -6405,6 +6429,7 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
Args:
|
||||
bank_id: Bank identifier
|
||||
mental_model_id: Pinned mental model UUID
|
||||
detail: Detail level - 'metadata', 'content', or 'full'
|
||||
request_context: Request context for authentication
|
||||
|
||||
Returns:
|
||||
@@ -6438,7 +6463,7 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
mental_model_id,
|
||||
)
|
||||
|
||||
result = self._row_to_mental_model(row) if row else None
|
||||
result = self._row_to_mental_model(row, detail=detail) if row else None
|
||||
|
||||
# Post-operation hook (usage recording)
|
||||
if result and self._operation_validator:
|
||||
@@ -6836,34 +6861,45 @@ class MemoryEngine(MemoryEngineInterface):
|
||||
|
||||
return result == "DELETE 1"
|
||||
|
||||
def _row_to_mental_model(self, row) -> dict[str, Any]:
|
||||
"""Convert a database row to a mental model dict."""
|
||||
reflect_response = row.get("reflect_response")
|
||||
# Parse JSON string to dict if needed (asyncpg may return JSONB as string)
|
||||
if isinstance(reflect_response, str):
|
||||
try:
|
||||
reflect_response = json.loads(reflect_response)
|
||||
except json.JSONDecodeError:
|
||||
reflect_response = None
|
||||
def _row_to_mental_model(self, row, *, detail: str = "full") -> dict[str, Any]:
|
||||
"""Convert a database row to a mental model dict.
|
||||
|
||||
Args:
|
||||
row: Database row
|
||||
detail: Detail level - 'metadata', 'content', or 'full'
|
||||
"""
|
||||
result: dict[str, Any] = {
|
||||
"id": str(row["id"]),
|
||||
"bank_id": row["bank_id"],
|
||||
"name": row["name"],
|
||||
"tags": row["tags"] or [],
|
||||
"last_refreshed_at": row["last_refreshed_at"].isoformat() if row["last_refreshed_at"] else None,
|
||||
"created_at": row["created_at"].isoformat() if row["created_at"] else None,
|
||||
}
|
||||
if detail == "metadata":
|
||||
return result
|
||||
|
||||
trigger = row.get("trigger")
|
||||
if isinstance(trigger, str):
|
||||
try:
|
||||
trigger = json.loads(trigger)
|
||||
except json.JSONDecodeError:
|
||||
trigger = None
|
||||
return {
|
||||
"id": str(row["id"]),
|
||||
"bank_id": row["bank_id"],
|
||||
"name": row["name"],
|
||||
"source_query": row["source_query"],
|
||||
"content": row["content"],
|
||||
"tags": row["tags"] or [],
|
||||
"max_tokens": row.get("max_tokens"),
|
||||
"trigger": trigger,
|
||||
"last_refreshed_at": row["last_refreshed_at"].isoformat() if row["last_refreshed_at"] else None,
|
||||
"created_at": row["created_at"].isoformat() if row["created_at"] else None,
|
||||
"reflect_response": reflect_response,
|
||||
}
|
||||
result["source_query"] = row["source_query"]
|
||||
result["content"] = row["content"]
|
||||
result["max_tokens"] = row.get("max_tokens")
|
||||
result["trigger"] = trigger
|
||||
|
||||
if detail == "full":
|
||||
reflect_response = row.get("reflect_response")
|
||||
if isinstance(reflect_response, str):
|
||||
try:
|
||||
reflect_response = json.loads(reflect_response)
|
||||
except json.JSONDecodeError:
|
||||
reflect_response = None
|
||||
result["reflect_response"] = reflect_response
|
||||
|
||||
return result
|
||||
|
||||
# =========================================================================
|
||||
# Directives - Hard rules injected into prompts
|
||||
|
||||
@@ -82,20 +82,16 @@ class TaskBackend(ABC):
|
||||
|
||||
Args:
|
||||
task_dict: Task dictionary to execute
|
||||
|
||||
Raises:
|
||||
Exception: Re-raised from executor on failure.
|
||||
"""
|
||||
if self._executor is None:
|
||||
task_type = task_dict.get("type", "unknown")
|
||||
logger.warning(f"No executor registered, skipping task {task_type}")
|
||||
return
|
||||
|
||||
try:
|
||||
await self._executor(task_dict)
|
||||
except Exception as e:
|
||||
task_type = task_dict.get("type", "unknown")
|
||||
logger.error(f"Error executing task {task_type}: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
await self._executor(task_dict)
|
||||
|
||||
|
||||
class SyncTaskBackend(TaskBackend):
|
||||
|
||||
@@ -136,6 +136,7 @@ dev = [
|
||||
"pytest-asyncio>=1.3.0",
|
||||
"pytest-timeout>=2.4.0",
|
||||
"pytest-xdist>=3.8.0",
|
||||
"pytest-rerunfailures>=15.0",
|
||||
"python-dotenv>=1.2.1",
|
||||
"filelock>=3.20.1", # TOCTOU race condition fix
|
||||
"ruff>=0.8.0",
|
||||
|
||||
@@ -161,6 +161,7 @@ def _parse_history(hist: Any) -> list[str]:
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.flaky(reruns=2, reruns_delay=5)
|
||||
async def test_horse_farm_observation_history(memory: MemoryEngine, request_context: Any) -> None:
|
||||
"""Retain a sequence of horse facts and inspect how observations evolve."""
|
||||
bank_id = f"test-horses-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
@@ -245,13 +245,12 @@ async def test_event_date_storage(memory, request_context):
|
||||
|
||||
assert len(unit_ids) > 0, "Should have created at least one memory unit"
|
||||
|
||||
# Recall the fact
|
||||
# Recall the fact (no fact_type filter — LLM may classify as world or experience)
|
||||
result = await memory.recall_async(
|
||||
bank_id=bank_id,
|
||||
query="When did Alice complete the product launch?",
|
||||
budget=Budget.LOW,
|
||||
max_tokens=500,
|
||||
fact_type=["world"],
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
@@ -547,13 +546,12 @@ async def test_mentioned_at_from_context_string(memory, request_context):
|
||||
|
||||
assert len(unit_ids) > 0, "Should create memory unit"
|
||||
|
||||
# Recall and verify mentioned_at is set
|
||||
# Recall and verify mentioned_at is set (no fact_type filter — LLM may classify as world or experience)
|
||||
result = await memory.recall_async(
|
||||
bank_id=bank_id,
|
||||
query="What does Alice like?",
|
||||
budget=Budget.LOW,
|
||||
max_tokens=500,
|
||||
fact_type=["world"],
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
@@ -738,13 +736,12 @@ async def test_context_preservation(memory, request_context):
|
||||
|
||||
assert len(unit_ids) > 0, "Should create at least one memory unit"
|
||||
|
||||
# Recall and verify context is returned
|
||||
# Recall and verify context is returned (no fact_type filter — LLM may classify as world or experience)
|
||||
result = await memory.recall_async(
|
||||
bank_id=bank_id,
|
||||
query="What did the team decide?",
|
||||
budget=Budget.LOW,
|
||||
max_tokens=500,
|
||||
fact_type=["world"],
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
@@ -1106,13 +1103,12 @@ async def test_document_upsert_behavior(memory, request_context):
|
||||
|
||||
assert len(v2_units) > 0, "Should create units for v2"
|
||||
|
||||
# Recall should return the updated information
|
||||
# Recall should return the updated information (no fact_type filter — LLM may classify as world or experience)
|
||||
result = await memory.recall_async(
|
||||
bank_id=bank_id,
|
||||
query="What is the project status?",
|
||||
budget=Budget.MID,
|
||||
max_tokens=1000,
|
||||
fact_type=["world"],
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
@@ -2060,20 +2056,23 @@ async def test_semantic_links_phase1_ann_cross_batch(memory, request_context):
|
||||
bank_id = f"test_semantic_phase1_{datetime.now(timezone.utc).timestamp()}"
|
||||
|
||||
try:
|
||||
# First batch: store some facts about Python
|
||||
# First batch: store some world facts about a topic
|
||||
# Use clearly "world" content (general knowledge, not personal experience)
|
||||
# to ensure consistent fact_type classification across batches,
|
||||
# since ANN search filters by fact_type.
|
||||
await memory.retain_async(
|
||||
bank_id=bank_id,
|
||||
content="Alice is an expert Python developer who builds web applications using FastAPI.",
|
||||
context="team skills",
|
||||
content="Python is a high-level programming language widely used for web development with frameworks like FastAPI.",
|
||||
context="programming languages",
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
# Second batch: store similar facts — Phase 1 ANN should find the first batch's
|
||||
# Second batch: store similar world facts — Phase 1 ANN should find the first batch's
|
||||
# facts via HNSW index and create cross-batch semantic links
|
||||
unit_ids_2 = await memory.retain_async(
|
||||
bank_id=bank_id,
|
||||
content="Bob specializes in Python programming and creates REST APIs with FastAPI.",
|
||||
context="team skills",
|
||||
content="FastAPI is a modern Python web framework known for its high performance and automatic API documentation.",
|
||||
context="programming languages",
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
|
||||
@@ -952,8 +952,8 @@ class TestSyncTaskBackend:
|
||||
assert executed[0] == task_dict
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_backend_handles_errors(self):
|
||||
"""Test that SyncTaskBackend handles executor errors gracefully."""
|
||||
async def test_sync_backend_propagates_errors(self):
|
||||
"""Test that SyncTaskBackend propagates executor errors instead of swallowing them."""
|
||||
|
||||
async def failing_executor(task_dict):
|
||||
raise ValueError("Test error")
|
||||
@@ -962,8 +962,9 @@ class TestSyncTaskBackend:
|
||||
backend.set_executor(failing_executor)
|
||||
await backend.initialize()
|
||||
|
||||
# Should not raise, error is logged
|
||||
await backend.submit_task({"type": "test"})
|
||||
# Should raise so callers can handle or surface the failure
|
||||
with pytest.raises(ValueError, match="Test error"):
|
||||
await backend.submit_task({"type": "test"})
|
||||
|
||||
|
||||
class TestDynamicTenantDiscovery:
|
||||
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
---
|
||||
sidebar_position: 12
|
||||
title: "AutoGen Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add long-term memory to AutoGen agents with Hindsight. Provides FunctionTool instances for retain, recall, and reflect that plug directly into AutoGen's AssistantAgent."
|
||||
---
|
||||
|
||||
# AutoGen
|
||||
@@ -165,6 +165,18 @@ const config: Config = {
|
||||
],
|
||||
],
|
||||
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-docs',
|
||||
{
|
||||
id: 'integrations',
|
||||
path: './docs-integrations',
|
||||
routeBasePath: 'sdks/integrations',
|
||||
sidebarPath: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
themes: [
|
||||
'@docusaurus/theme-mermaid',
|
||||
[
|
||||
|
||||
@@ -41,7 +41,7 @@ curl -X POST "$HINDSIGHT_URL/v1/default/banks/my-bank/import" \
|
||||
# [docs:import-dry-run]
|
||||
curl -X POST "$HINDSIGHT_URL/v1/default/banks/my-bank/import?dry_run=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @template.json
|
||||
-d '{"version": "1", "bank": {"retain_mission": "Dry run test."}}'
|
||||
# [/docs:import-dry-run]
|
||||
|
||||
# [docs:export-template]
|
||||
|
||||
@@ -15,7 +15,7 @@ import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const integrationsDir = join(__dirname, '..', 'docs', 'sdks', 'integrations');
|
||||
const integrationsDir = join(__dirname, '..', 'docs-integrations');
|
||||
|
||||
const IGNORED_FILES = ['_template.md', '_category_.json'];
|
||||
|
||||
@@ -55,7 +55,7 @@ for (const filename of files) {
|
||||
if (violations.length > 0) {
|
||||
console.error('[integration-seo] ❌ The following integration pages are missing required frontmatter:\n');
|
||||
for (const { filename, missing } of violations) {
|
||||
console.error(` docs/sdks/integrations/${filename} — missing: ${missing.join(', ')}`);
|
||||
console.error(` docs-integrations/${filename} — missing: ${missing.join(', ')}`);
|
||||
}
|
||||
console.error('\nAll integration pages must have both `title` and `description` in their frontmatter.');
|
||||
console.error('Example:\n');
|
||||
|
||||
+42
-36
@@ -179,110 +179,116 @@ const sidebars: SidebarsConfig = {
|
||||
collapsible: false,
|
||||
items: [
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/local-mcp',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/local-mcp',
|
||||
label: 'Local MCP Server',
|
||||
customProps: { icon: '/img/icons/mcp.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/litellm',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/litellm',
|
||||
label: 'LiteLLM',
|
||||
customProps: { icon: '/img/icons/litellm.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/claude-code',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/claude-code',
|
||||
label: 'Claude Code',
|
||||
customProps: { icon: '/img/icons/claudecode.svg' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/codex',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/codex',
|
||||
label: 'OpenAI Codex CLI',
|
||||
customProps: { icon: '/img/icons/terminal.svg' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/openclaw',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/openclaw',
|
||||
label: 'OpenClaw',
|
||||
customProps: { icon: '/img/icons/openclaw.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/ai-sdk',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/ai-sdk',
|
||||
label: 'Vercel AI SDK',
|
||||
customProps: { icon: '/img/icons/vercel.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/chat',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/chat',
|
||||
label: 'Vercel Chat SDK',
|
||||
customProps: { icon: '/img/icons/vercel.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/crewai',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/crewai',
|
||||
label: 'CrewAI',
|
||||
customProps: { icon: '/img/icons/crewai.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/pydantic-ai',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/pydantic-ai',
|
||||
label: 'Pydantic AI',
|
||||
customProps: { icon: '/img/icons/pydanticai.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/agno',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/agno',
|
||||
label: 'Agno',
|
||||
customProps: { icon: '/img/icons/agno.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/hermes',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/hermes',
|
||||
label: 'Hermes Agent',
|
||||
customProps: { icon: '/img/icons/hermes.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/langgraph',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/langgraph',
|
||||
label: 'LangGraph / LangChain',
|
||||
customProps: { icon: '/img/icons/langgraph.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/nemoclaw',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/nemoclaw',
|
||||
label: 'NemoClaw',
|
||||
customProps: { icon: '/img/icons/nemoclaw.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/paperclip',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/paperclip',
|
||||
label: 'Paperclip',
|
||||
customProps: { icon: '/img/icons/nodejs.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/strands',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/strands',
|
||||
label: 'Strands Agents',
|
||||
customProps: { icon: '/img/icons/strands.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/ag2',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/ag2',
|
||||
label: 'AG2',
|
||||
customProps: { icon: '/img/icons/ag2.svg' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/llamaindex',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/autogen',
|
||||
label: 'AutoGen',
|
||||
customProps: { icon: '/img/icons/autogen.svg' },
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/llamaindex',
|
||||
label: 'LlamaIndex',
|
||||
customProps: { icon: '/img/icons/llamaindex.png' },
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/skills',
|
||||
type: 'link',
|
||||
href: '/sdks/integrations/skills',
|
||||
label: 'Skills',
|
||||
customProps: { icon: '/img/icons/skills.png' },
|
||||
},
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# LiteLLM
|
||||
|
||||
Universal LLM memory integration via [LiteLLM](https://github.com/BerriAI/litellm). Add persistent memory to any LLM application with just a few lines of code.
|
||||
|
||||
## Features
|
||||
|
||||
- **Universal LLM Support** - Works with 100+ LLM providers via LiteLLM (OpenAI, Anthropic, Groq, Azure, AWS Bedrock, Google Vertex AI, and more)
|
||||
- **Simple Integration** - Just configure, enable, and use `hindsight_litellm.completion()`
|
||||
- **Automatic Memory Injection** - Relevant memories are injected into prompts before LLM calls
|
||||
- **Automatic Conversation Storage** - Conversations are stored to Hindsight for future recall
|
||||
- **Two Memory Modes** - Choose between `reflect` (synthesized context) or `recall` (raw memory retrieval)
|
||||
- **Direct Memory APIs** - Query, synthesize, and store memories manually
|
||||
- **Native Client Wrappers** - Alternative wrappers for OpenAI and Anthropic SDKs
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-litellm
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
import hindsight_litellm
|
||||
|
||||
# Configure and enable memory integration
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="my-agent",
|
||||
)
|
||||
hindsight_litellm.enable()
|
||||
|
||||
# Use the convenience wrapper - memory is automatically injected and stored
|
||||
response = hindsight_litellm.completion(
|
||||
model="gpt-4o-mini",
|
||||
messages=[{"role": "user", "content": "What did we discuss about AI?"}]
|
||||
)
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
When you call `completion()`, the following happens automatically:
|
||||
|
||||
1. **Memory Retrieval** - Hindsight is queried for relevant memories based on the conversation
|
||||
2. **Prompt Injection** - Memories are injected into the system message
|
||||
3. **LLM Call** - The enriched prompt is sent to the LLM
|
||||
4. **Conversation Storage** - The conversation is stored to Hindsight for future recall
|
||||
5. **Response Returned** - You receive the response as normal
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```python
|
||||
hindsight_litellm.configure(
|
||||
# Required
|
||||
hindsight_api_url="http://localhost:8888", # Hindsight API server URL
|
||||
bank_id="my-agent", # Memory bank ID
|
||||
|
||||
api_key="your-api-key", # Optional API key for authentication
|
||||
|
||||
# Optional - Memory behavior
|
||||
store_conversations=True, # Store conversations after LLM calls
|
||||
inject_memories=True, # Inject relevant memories into prompts
|
||||
use_reflect=False, # Use reflect API (synthesized) vs recall (raw memories)
|
||||
reflect_include_facts=False, # Include source facts with reflect responses
|
||||
max_memories=None, # Maximum memories to inject (None = unlimited)
|
||||
max_memory_tokens=4096, # Maximum tokens for memory context
|
||||
recall_budget="mid", # Recall budget: "low", "mid", "high"
|
||||
fact_types=["world", "agent"], # Filter fact types to inject
|
||||
|
||||
# Optional - Bank Configuration
|
||||
bank_name="My Agent", # Human-readable display name for the memory bank
|
||||
background="This agent...", # Instructions guiding what Hindsight should remember
|
||||
|
||||
# Optional - Advanced
|
||||
injection_mode="system_message", # or "prepend_user"
|
||||
excluded_models=["gpt-3.5*"], # Exclude certain models
|
||||
verbose=True, # Enable verbose logging and debug info
|
||||
)
|
||||
```
|
||||
|
||||
### Bank Configuration
|
||||
|
||||
The `background` and `bank_name` parameters configure the memory bank itself. When provided, `configure()` will automatically create or update the bank with these settings.
|
||||
|
||||
```python
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="support-router",
|
||||
bank_name="Customer Support Router",
|
||||
background="""This agent routes customer support requests to the appropriate team.
|
||||
Remember which types of issues should go to which teams (billing, technical, sales).
|
||||
Track customer preferences for communication channels and past issue resolutions.""",
|
||||
)
|
||||
```
|
||||
|
||||
### Memory Modes: Reflect vs Recall
|
||||
|
||||
- **Recall mode** (`use_reflect=False`, default): Retrieves raw memory facts and injects them as a numbered list. Best when you need precise, individual memories.
|
||||
- **Reflect mode** (`use_reflect=True`): Synthesizes memories into a coherent context paragraph. Best for natural, conversational memory context.
|
||||
|
||||
```python
|
||||
# Recall mode - raw memories
|
||||
hindsight_litellm.configure(
|
||||
bank_id="my-agent",
|
||||
use_reflect=False, # Default
|
||||
)
|
||||
# Injects: "1. [WORLD] User prefers Python\n2. [OPINION] User dislikes Java..."
|
||||
|
||||
# Reflect mode - synthesized context
|
||||
hindsight_litellm.configure(
|
||||
bank_id="my-agent",
|
||||
use_reflect=True,
|
||||
)
|
||||
# Injects: "Based on previous conversations, the user is a Python developer who..."
|
||||
```
|
||||
|
||||
## Multi-Provider Support
|
||||
|
||||
Works with any LiteLLM-supported provider:
|
||||
|
||||
```python
|
||||
import hindsight_litellm
|
||||
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="my-agent",
|
||||
)
|
||||
hindsight_litellm.enable()
|
||||
|
||||
# OpenAI
|
||||
hindsight_litellm.completion(model="gpt-4o", messages=[...])
|
||||
|
||||
# Anthropic
|
||||
hindsight_litellm.completion(model="claude-3-5-sonnet-20241022", messages=[...])
|
||||
|
||||
# Groq
|
||||
hindsight_litellm.completion(model="groq/llama-3.1-70b-versatile", messages=[...])
|
||||
|
||||
# Azure OpenAI
|
||||
hindsight_litellm.completion(model="azure/gpt-4", messages=[...])
|
||||
|
||||
# AWS Bedrock
|
||||
hindsight_litellm.completion(model="bedrock/anthropic.claude-3", messages=[...])
|
||||
|
||||
# Google Vertex AI
|
||||
hindsight_litellm.completion(model="vertex_ai/gemini-pro", messages=[...])
|
||||
```
|
||||
|
||||
## Direct Memory APIs
|
||||
|
||||
### Recall - Query raw memories
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, recall
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
memories = recall("what projects am I working on?", budget="mid")
|
||||
for m in memories:
|
||||
print(f"- [{m.fact_type}] {m.text}")
|
||||
```
|
||||
|
||||
### Reflect - Get synthesized context
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, reflect
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
result = reflect("what do you know about the user's preferences?")
|
||||
print(result.text)
|
||||
```
|
||||
|
||||
### Retain - Store memories
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, retain
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
result = retain(
|
||||
content="User mentioned they're working on a machine learning project",
|
||||
context="Discussion about current projects",
|
||||
)
|
||||
```
|
||||
|
||||
### Async APIs
|
||||
|
||||
```python
|
||||
from hindsight_litellm import arecall, areflect, aretain
|
||||
|
||||
# Async versions of all memory APIs
|
||||
memories = await arecall("what do you know about me?")
|
||||
context = await areflect("summarize user preferences")
|
||||
result = await aretain(content="New information to remember")
|
||||
```
|
||||
|
||||
## Native Client Wrappers
|
||||
|
||||
Alternative to LiteLLM callbacks for direct SDK integration.
|
||||
|
||||
### OpenAI Wrapper
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
from hindsight_litellm import wrap_openai
|
||||
|
||||
client = OpenAI()
|
||||
wrapped = wrap_openai(
|
||||
client,
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
response = wrapped.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[{"role": "user", "content": "What do you know about me?"}]
|
||||
)
|
||||
```
|
||||
|
||||
### Anthropic Wrapper
|
||||
|
||||
```python
|
||||
from anthropic import Anthropic
|
||||
from hindsight_litellm import wrap_anthropic
|
||||
|
||||
client = Anthropic()
|
||||
wrapped = wrap_anthropic(
|
||||
client,
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
response = wrapped.messages.create(
|
||||
model="claude-3-5-sonnet-20241022",
|
||||
max_tokens=1024,
|
||||
messages=[{"role": "user", "content": "Hello!"}]
|
||||
)
|
||||
```
|
||||
|
||||
## Debug Mode
|
||||
|
||||
When `verbose=True`, you can inspect exactly what memories are being injected:
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, enable, completion, get_last_injection_debug
|
||||
|
||||
configure(
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
verbose=True,
|
||||
)
|
||||
enable()
|
||||
|
||||
response = completion(
|
||||
model="gpt-4o-mini",
|
||||
messages=[{"role": "user", "content": "What's my favorite color?"}]
|
||||
)
|
||||
|
||||
# Inspect what was injected
|
||||
debug = get_last_injection_debug()
|
||||
if debug:
|
||||
print(f"Mode: {debug.mode}") # "reflect" or "recall"
|
||||
print(f"Injected: {debug.injected}") # True/False
|
||||
print(f"Results: {debug.results_count}")
|
||||
print(f"Memory context:\n{debug.memory_context}")
|
||||
```
|
||||
|
||||
## Context Manager
|
||||
|
||||
```python
|
||||
from hindsight_litellm import hindsight_memory
|
||||
import litellm
|
||||
|
||||
with hindsight_memory(bank_id="user-123"):
|
||||
response = litellm.completion(model="gpt-4", messages=[...])
|
||||
# Memory integration automatically disabled after context
|
||||
```
|
||||
|
||||
## Disabling and Cleanup
|
||||
|
||||
```python
|
||||
from hindsight_litellm import disable, cleanup
|
||||
|
||||
# Temporarily disable memory integration
|
||||
disable()
|
||||
|
||||
# Clean up all resources (call when shutting down)
|
||||
cleanup()
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Main Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `configure(...)` | Configure global Hindsight settings |
|
||||
| `enable()` | Enable memory integration with LiteLLM |
|
||||
| `disable()` | Disable memory integration |
|
||||
| `is_enabled()` | Check if memory integration is enabled |
|
||||
| `cleanup()` | Clean up all resources |
|
||||
|
||||
### Configuration Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get_config()` | Get current configuration |
|
||||
| `is_configured()` | Check if Hindsight is configured |
|
||||
| `reset_config()` | Reset configuration to defaults |
|
||||
|
||||
### Memory Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `recall(query, ...)` | Synchronously query raw memories |
|
||||
| `arecall(query, ...)` | Asynchronously query raw memories |
|
||||
| `reflect(query, ...)` | Synchronously get synthesized memory context |
|
||||
| `areflect(query, ...)` | Asynchronously get synthesized memory context |
|
||||
| `retain(content, ...)` | Synchronously store a memory |
|
||||
| `aretain(content, ...)` | Asynchronously store a memory |
|
||||
|
||||
### Debug Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get_last_injection_debug()` | Get debug info from last memory injection |
|
||||
| `clear_injection_debug()` | Clear stored debug info |
|
||||
|
||||
### Client Wrappers
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `wrap_openai(client, ...)` | Wrap OpenAI client with memory |
|
||||
| `wrap_anthropic(client, ...)` | Wrap Anthropic client with memory |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- litellm >= 1.40.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,193 +0,0 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Local MCP Server
|
||||
|
||||
Hindsight provides a fully local MCP server that runs entirely on your machine with an embedded PostgreSQL database. No external server or database setup required.
|
||||
|
||||
This is ideal for:
|
||||
- **Personal use with Claude Desktop** — Give Claude long-term memory across conversations
|
||||
- **Development and testing** — Quick setup without infrastructure
|
||||
- **Privacy-focused setups** — All data stays on your machine
|
||||
|
||||
## Quick Install
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- \
|
||||
--app claude-desktop \
|
||||
--set HINDSIGHT_API_LLM_API_KEY=sk-...
|
||||
```
|
||||
|
||||
This script will:
|
||||
1. Install [uv](https://docs.astral.sh/uv/) if not already installed
|
||||
2. Configure Claude Desktop to use the Hindsight MCP server
|
||||
3. Set the provided environment variables in the MCP configuration
|
||||
|
||||
:::info Other MCP Applications
|
||||
The quick install script currently supports Claude Desktop only. For other MCP-compatible applications (Cursor, Cline, etc.), follow the [Manual Configuration](#manual-configuration) steps below.
|
||||
:::
|
||||
|
||||
## Manual Configuration
|
||||
|
||||
Add the following to your MCP client's configuration. For Claude Desktop:
|
||||
|
||||
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
||||
|
||||
For other MCP clients, refer to their documentation for the configuration file location.
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"hindsight": {
|
||||
"command": "uvx",
|
||||
"args": ["--from", "hindsight-api", "hindsight-local-mcp"],
|
||||
"env": {
|
||||
"HINDSIGHT_API_LLM_API_KEY": "sk-..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### With Custom Bank ID
|
||||
|
||||
By default, memories are stored in a bank called `mcp`. To use a different bank:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"hindsight": {
|
||||
"command": "uvx",
|
||||
"args": ["--from", "hindsight-api", "hindsight-local-mcp"],
|
||||
"env": {
|
||||
"HINDSIGHT_API_LLM_API_KEY": "sk-...",
|
||||
"HINDSIGHT_API_MCP_LOCAL_BANK_ID": "my-personal-memory"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All standard [Hindsight configuration variables](/developer/configuration) are supported.
|
||||
|
||||
### Local MCP Specific
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `HINDSIGHT_API_MCP_LOCAL_BANK_ID` | No | `mcp` | Memory bank ID to use |
|
||||
| `HINDSIGHT_API_MCP_INSTRUCTIONS` | No | - | Additional instructions appended to both `retain` and `recall` tools |
|
||||
|
||||
### Customizing Tool Behavior
|
||||
|
||||
You can customize what gets stored by adding instructions to the tools. Re-run the install script with the additional `--set` flag:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- \
|
||||
--app claude-desktop \
|
||||
--set HINDSIGHT_API_LLM_API_KEY=sk-... \
|
||||
--set HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take, code you write, and files you modify."
|
||||
```
|
||||
|
||||
These instructions are appended to the default tool descriptions, guiding Claude on when and how to use the memory tools.
|
||||
|
||||
## Available Tools
|
||||
|
||||
### retain
|
||||
|
||||
Store information to long-term memory. This is a **fire-and-forget** operation — it returns immediately while processing happens in the background.
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `content` | string | Yes | The fact or memory to store |
|
||||
| `context` | string | No | Category for the memory (default: `general`) |
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"name": "retain",
|
||||
"arguments": {
|
||||
"content": "User's favorite color is blue",
|
||||
"context": "preferences"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "accepted",
|
||||
"message": "Memory storage initiated"
|
||||
}
|
||||
```
|
||||
|
||||
### recall
|
||||
|
||||
Search memories to provide personalized responses.
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `query` | string | Yes | Natural language search query |
|
||||
| `max_tokens` | integer | No | Maximum tokens to return (default: 4096) |
|
||||
| `budget` | string | No | Search depth: `low`, `mid`, or `high` (default: `low`) |
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"name": "recall",
|
||||
"arguments": {
|
||||
"query": "What are the user's color preferences?",
|
||||
"max_tokens": 2048,
|
||||
"budget": "mid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
The local MCP server:
|
||||
|
||||
1. **Starts an embedded PostgreSQL** (pg0) on an automatically assigned port
|
||||
2. **Initializes the Hindsight memory engine** with local embeddings
|
||||
3. **Connects via stdio** to Claude Code using the MCP protocol
|
||||
|
||||
Data is persisted in the pg0 data directory (`~/.pg0/hindsight-mcp/`), so your memories survive restarts.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "HINDSIGHT_API_LLM_API_KEY required"
|
||||
|
||||
Make sure you've set the API key in your MCP configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"HINDSIGHT_API_LLM_API_KEY": "sk-..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Slow startup
|
||||
|
||||
The first startup may take longer as it:
|
||||
- Downloads the embedding model (~100MB)
|
||||
- Initializes the PostgreSQL database
|
||||
|
||||
Subsequent starts are faster.
|
||||
|
||||
### Checking logs
|
||||
|
||||
Set `HINDSIGHT_API_LOG_LEVEL=debug` for verbose output:
|
||||
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"HINDSIGHT_API_LOG_LEVEL": "debug"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Logs are written to stderr and visible in Claude Code's MCP server output.
|
||||
@@ -1,323 +0,0 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Skills
|
||||
|
||||
Hindsight provides an Agent Skill that gives AI coding assistants persistent memory across sessions. Skills are reusable prompt templates that agents can load when needed to gain specialized capabilities.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Skills Directory |
|
||||
|----------|-----------------|
|
||||
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `~/.claude/skills/` |
|
||||
| [OpenCode](https://github.com/opencode-ai/opencode) | `~/.opencode/skills/` |
|
||||
| [Codex CLI](https://github.com/openai/codex) | `~/.codex/skills/` |
|
||||
|
||||
## Deployment Modes
|
||||
|
||||
The skill supports two deployment modes:
|
||||
|
||||
| Mode | Best For | Data Location |
|
||||
|------|----------|---------------|
|
||||
| **Local** | Individual developers | Your machine (`~/.pg0/`) |
|
||||
| **Cloud** | Teams sharing knowledge | Hindsight Cloud |
|
||||
|
||||
## Quick Install
|
||||
|
||||
### Option 1: Interactive Installer (Recommended)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash
|
||||
```
|
||||
|
||||
The installer will:
|
||||
1. Prompt you to select your AI coding assistant
|
||||
2. Select deployment mode (local or cloud)
|
||||
3. Configure the appropriate settings
|
||||
4. Install the skill to the appropriate directory
|
||||
|
||||
### Install for a Specific Platform
|
||||
|
||||
```bash
|
||||
# Claude Code (interactive mode selection)
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude
|
||||
|
||||
# OpenCode
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app opencode
|
||||
|
||||
# Codex CLI
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app codex
|
||||
```
|
||||
|
||||
### Install with Cloud Mode
|
||||
|
||||
```bash
|
||||
# Direct cloud setup (skips interactive prompts for mode)
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude --mode cloud
|
||||
```
|
||||
|
||||
### Option 2: Using add-skill
|
||||
|
||||
If you use [add-skill](https://add-skill.org/) to manage your agent skills:
|
||||
|
||||
```bash
|
||||
# For local mode (individual developers)
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-local
|
||||
|
||||
# For Hindsight Cloud (teams)
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-cloud
|
||||
|
||||
# For self-hosted Hindsight servers
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-self-hosted
|
||||
```
|
||||
|
||||
On first use, the AI will guide you through the remaining setup:
|
||||
- **Local**: Run `uvx hindsight-embed configure` to set up your LLM provider
|
||||
- **Cloud**: Provide your API key and bank ID
|
||||
- **Self-hosted**: Provide your server URL, API key, and bank ID
|
||||
|
||||
## What the Skill Provides
|
||||
|
||||
Once installed, your AI assistant gains the ability to:
|
||||
|
||||
- **Retain** - Store user preferences, learnings, and procedure outcomes
|
||||
- **Recall** - Search for relevant context before starting tasks
|
||||
- **Reflect** - Synthesize memories into contextual answers
|
||||
|
||||
The skill uses the `hindsight-embed` CLI which runs a lightweight local daemon with an embedded database.
|
||||
|
||||
## How Skills Work
|
||||
|
||||
Skills are **model-invoked**, meaning the AI assistant automatically decides when to use them based on the context of your conversation. You don't need to explicitly trigger the skill.
|
||||
|
||||
The assistant will:
|
||||
- **Store** when you share preferences, when tasks succeed/fail, or when learnings emerge
|
||||
- **Recall** before starting non-trivial tasks to get relevant context
|
||||
|
||||
### What Gets Stored
|
||||
|
||||
The skill is optimized to store:
|
||||
|
||||
| Category | Examples |
|
||||
|----------|----------|
|
||||
| **User Preferences** | Coding style, tool preferences, language choices |
|
||||
| **Procedure Outcomes** | Commands that worked, configurations that resolved issues |
|
||||
| **Learnings** | Bug solutions, workarounds, architecture decisions |
|
||||
|
||||
## Architecture
|
||||
|
||||
### Local Mode
|
||||
|
||||
```
|
||||
AI Coding Assistant
|
||||
│
|
||||
▼
|
||||
Hindsight Skill (SKILL.md)
|
||||
│
|
||||
▼
|
||||
hindsight-embed CLI
|
||||
│
|
||||
▼
|
||||
Local Daemon (auto-started)
|
||||
│
|
||||
▼
|
||||
Embedded PostgreSQL (~/.pg0/hindsight-embed/)
|
||||
```
|
||||
|
||||
All data stays on your machine. The daemon auto-starts when needed and shuts down after inactivity.
|
||||
|
||||
### Cloud Mode
|
||||
|
||||
```
|
||||
AI Coding Assistant
|
||||
│
|
||||
▼
|
||||
Hindsight Skill (SKILL.md)
|
||||
│
|
||||
▼
|
||||
hindsight-cli
|
||||
│
|
||||
▼
|
||||
Hindsight Cloud API (https://api.hindsight.vectorize.io)
|
||||
│
|
||||
▼
|
||||
Shared Memory Bank (team-accessible)
|
||||
```
|
||||
|
||||
Data is stored in Hindsight Cloud and shared across your team. All team members with the same bank ID can access shared memories.
|
||||
|
||||
---
|
||||
|
||||
## Local Mode Setup
|
||||
|
||||
The skill uses configuration stored in `~/.hindsight/config.env`. Reconfigure anytime:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cloud Mode Setup
|
||||
|
||||
Cloud mode connects to [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup), allowing teams to share memories about a codebase. When one team member learns something, everyone benefits.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. A Hindsight Cloud account ([sign up](https://ui.hindsight.vectorize.io/signup))
|
||||
2. An API key from your team admin
|
||||
3. A bank ID for your project (e.g., `team-acme-frontend`)
|
||||
|
||||
### Installation
|
||||
|
||||
Run the installer with cloud mode:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
|
||||
```
|
||||
|
||||
You'll be prompted for:
|
||||
|
||||
| Setting | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| **Cloud API URL** | Hindsight Cloud endpoint | `https://api.hindsight.vectorize.io` |
|
||||
| **API Key** | Your authentication key | `hs_xxx...` |
|
||||
| **Bank ID** | Shared memory bank for your team | `team-acme-frontend` |
|
||||
|
||||
### Configuration Files
|
||||
|
||||
Cloud mode creates two files:
|
||||
|
||||
**`~/.hindsight/config`** — API connection settings (TOML format):
|
||||
```toml
|
||||
api_url = "https://api.hindsight.vectorize.io"
|
||||
api_key = "hs_xxx..."
|
||||
```
|
||||
|
||||
**`~/.claude/skills/hindsight/SKILL.md`** — Skill definition with your bank ID baked in.
|
||||
|
||||
### Team Setup
|
||||
|
||||
To set up cloud mode for your team:
|
||||
|
||||
1. **Team admin** creates a bank in Hindsight Cloud (e.g., `team-acme-frontend`)
|
||||
2. **Team admin** generates API keys for each team member
|
||||
3. **Each developer** runs the installer with their API key and the shared bank ID
|
||||
4. All team members now share the same memory bank
|
||||
|
||||
### What to Store in Team Banks
|
||||
|
||||
Cloud mode uses a **shared team bank**. Be thoughtful about what goes in:
|
||||
|
||||
| Type | Examples | How to Store |
|
||||
|------|----------|--------------|
|
||||
| **Project conventions** | Linting rules, testing requirements, Node version | `"Project uses ESLint with Airbnb config"` |
|
||||
| **Team knowledge** | Architecture decisions, common pitfalls, domain logic | `"Auth module requires Redis 7+"` |
|
||||
| **Individual preferences** | Personal coding style, communication preferences | `"Alice prefers verbose commit messages"` |
|
||||
|
||||
**Key distinction**: Project conventions apply to everyone. Individual preferences should include the person's name so the AI knows when to apply them.
|
||||
|
||||
### Example Workflow
|
||||
|
||||
```
|
||||
Day 1: Alice discovers a requirement
|
||||
─────────────────────────────────────
|
||||
Alice's AI assistant stores:
|
||||
"The auth module requires Redis 7+ due to HEXPIRE command usage"
|
||||
"Alice prefers explicit error handling over silent failures"
|
||||
|
||||
Day 2: Bob starts working on auth
|
||||
─────────────────────────────────
|
||||
Bob's AI assistant recalls:
|
||||
"The auth module requires Redis 7+ due to HEXPIRE command usage"
|
||||
|
||||
Bob avoids the same issue Alice hit!
|
||||
(Alice's personal preference is stored but won't be applied to Bob)
|
||||
```
|
||||
|
||||
### Testing Cloud Connection
|
||||
|
||||
After installation, verify the connection:
|
||||
|
||||
```bash
|
||||
# Store a test memory
|
||||
hindsight memory retain team-acme-frontend "Alice works at Google as a software engineer"
|
||||
|
||||
# Recall it
|
||||
hindsight memory recall team-acme-frontend "Alice"
|
||||
```
|
||||
|
||||
### Switching Between Banks
|
||||
|
||||
If you work on multiple projects, you can have different skills installed for each AI assistant, or manually switch banks:
|
||||
|
||||
```bash
|
||||
# Environment variable override (temporary)
|
||||
HINDSIGHT_API_URL=https://api.hindsight.vectorize.io \
|
||||
HINDSIGHT_API_KEY=hs_xxx \
|
||||
hindsight memory recall different-bank "query"
|
||||
```
|
||||
|
||||
For permanent multi-bank setups, reinstall the skill with a different bank ID.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not activating
|
||||
|
||||
The skill activates based on its description matching your request. Try being explicit:
|
||||
- "Remember that..." triggers storage
|
||||
- "What do you know about..." triggers recall
|
||||
|
||||
### Local Mode Issues
|
||||
|
||||
**Daemon not starting:**
|
||||
```bash
|
||||
uvx hindsight-embed daemon status
|
||||
uvx hindsight-embed daemon logs
|
||||
```
|
||||
|
||||
**Reconfigure LLM provider:**
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
### Cloud Mode Issues
|
||||
|
||||
**Authentication errors:**
|
||||
```bash
|
||||
# Verify your config
|
||||
cat ~/.hindsight/config
|
||||
|
||||
# Test connection manually
|
||||
hindsight bank list
|
||||
```
|
||||
|
||||
**Wrong bank ID:**
|
||||
|
||||
Check your SKILL.md file to see which bank ID is configured:
|
||||
```bash
|
||||
cat ~/.claude/skills/hindsight/SKILL.md | grep "memory retain"
|
||||
```
|
||||
|
||||
To change the bank ID, reinstall the skill:
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
|
||||
```
|
||||
|
||||
**Network/firewall issues:**
|
||||
```bash
|
||||
# Test connectivity to cloud API
|
||||
curl -I https://api.hindsight.vectorize.io/health
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
### Local Mode
|
||||
- Python 3.10+ (for `uvx`)
|
||||
- An LLM API key (OpenAI, Anthropic, Groq, etc.)
|
||||
|
||||
### Cloud Mode
|
||||
- Python 3.10+ (for `uvx`)
|
||||
- Hindsight Cloud API key
|
||||
- Network access to `https://api.hindsight.vectorize.io`
|
||||
@@ -1,184 +0,0 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
title: "AG2 (AutoGen) Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add long-term persistent memory to your AG2 (AutoGen) agents with Hindsight. Automatic fact extraction, entity tracking, and recall tools that persist across conversations."
|
||||
---
|
||||
|
||||
# AG2
|
||||
|
||||
Persistent long-term memory for [AG2](https://ag2.ai) agents (community AutoGen fork). Give your agents retain/recall/reflect tools that persist across conversations.
|
||||
|
||||
[View Changelog →](/changelog/integrations/ag2)
|
||||
|
||||
## Features
|
||||
|
||||
- **Drop-in Tools** — `register_hindsight_tools()` registers retain, recall, and reflect in one line
|
||||
- **AG2-native** — Uses `Annotated` type hints compatible with AG2's `@register_for_llm` / `@register_for_execution` pattern
|
||||
- **GroupChat Support** — Multiple agents can share a single memory bank
|
||||
- **Selective Tools** — Include only the tools you need (`include_retain`, `include_recall`, `include_reflect`)
|
||||
- **Simple Configuration** — Configure once globally or override per tool set
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-ag2
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from autogen import AssistantAgent, UserProxyAgent, LLMConfig
|
||||
from hindsight_ag2 import register_hindsight_tools
|
||||
|
||||
llm_config = LLMConfig(api_type="openai", model="gpt-4o-mini")
|
||||
|
||||
with llm_config:
|
||||
assistant = AssistantAgent(
|
||||
name="assistant",
|
||||
system_message="You are a helpful assistant with long-term memory.",
|
||||
)
|
||||
user_proxy = UserProxyAgent(
|
||||
name="user",
|
||||
human_input_mode="NEVER",
|
||||
)
|
||||
|
||||
# Register Hindsight memory tools on both agents
|
||||
register_hindsight_tools(
|
||||
assistant, user_proxy,
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
# The assistant can now use hindsight_retain, hindsight_recall, hindsight_reflect
|
||||
result = user_proxy.initiate_chat(
|
||||
assistant,
|
||||
message="Remember that I prefer Python over JavaScript.",
|
||||
)
|
||||
```
|
||||
|
||||
That's it. The assistant can now store and retrieve memories across conversations.
|
||||
|
||||
## How It Works
|
||||
|
||||
The integration provides three AG2-compatible tool functions backed by Hindsight's API:
|
||||
|
||||
| Tool | Hindsight | What happens |
|
||||
|------|-----------|--------------|
|
||||
| `hindsight_retain(content)` | `retain(bank_id, content, ...)` | Content is stored. Hindsight extracts facts, entities, and relationships from the raw text. |
|
||||
| `hindsight_recall(query)` | `recall(bank_id, query, ...)` | Hindsight runs semantic search, BM25, graph traversal, and reranking. Returns a numbered list of matching memories. |
|
||||
| `hindsight_reflect(query)` | `reflect(bank_id, query, ...)` | Hindsight synthesizes a reasoned answer from all relevant memories, using the bank's disposition traits. |
|
||||
|
||||
Tools are plain Python functions with `Annotated` type hints. AG2 uses these hints to generate the tool schema that the LLM sees.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Global Configuration
|
||||
|
||||
```python
|
||||
from hindsight_ag2 import configure
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-key", # or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # low / mid / high
|
||||
max_tokens=4096,
|
||||
tags=["source:ag2"], # default tags for retain
|
||||
)
|
||||
```
|
||||
|
||||
### Per-Tool Overrides
|
||||
|
||||
Constructor arguments override global configuration:
|
||||
|
||||
```python
|
||||
from hindsight_ag2 import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
budget="high",
|
||||
max_tokens=8192,
|
||||
tags=["team:alpha"],
|
||||
)
|
||||
```
|
||||
|
||||
## GroupChat with Shared Memory
|
||||
|
||||
Multiple agents can share a single memory bank in a GroupChat:
|
||||
|
||||
```python
|
||||
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager, LLMConfig
|
||||
from hindsight_ag2 import register_hindsight_tools
|
||||
|
||||
llm_config = LLMConfig(api_type="openai", model="gpt-4o-mini")
|
||||
|
||||
with llm_config:
|
||||
researcher = AssistantAgent(name="researcher", system_message="You research topics.")
|
||||
writer = AssistantAgent(name="writer", system_message="You write content.")
|
||||
executor = UserProxyAgent(name="executor", human_input_mode="NEVER")
|
||||
|
||||
# All agents share the same memory bank
|
||||
for agent in [researcher, writer]:
|
||||
register_hindsight_tools(agent, executor, bank_id="team-memory")
|
||||
|
||||
group_chat = GroupChat(agents=[researcher, writer, executor], messages=[])
|
||||
manager = GroupChatManager(groupchat=group_chat)
|
||||
```
|
||||
|
||||
## Manual Registration
|
||||
|
||||
For full control over how tools are registered:
|
||||
|
||||
```python
|
||||
from hindsight_ag2 import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
for tool_fn in tools:
|
||||
assistant.register_for_llm(description=tool_fn.__doc__)(tool_fn)
|
||||
user_proxy.register_for_execution()(tool_fn)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Configuration
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `configure(...)` | Set global connection and default settings |
|
||||
| `get_config()` | Get current configuration |
|
||||
| `reset_config()` | Reset configuration to None |
|
||||
|
||||
### create_hindsight_tools
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `bank_id` | required | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured `Hindsight` client |
|
||||
| `hindsight_api_url` | from config | Hindsight API URL |
|
||||
| `api_key` | from config | API key |
|
||||
| `budget` | `"mid"` | Recall/reflect budget (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Max tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode (any/all/any_strict/all_strict) |
|
||||
| `retain_metadata` | `None` | Metadata dict for retain operations |
|
||||
| `retain_document_id` | `None` | Document ID for retain (groups/upserts memories) |
|
||||
| `recall_types` | `None` | Fact types to filter (world, experience, opinion, observation) |
|
||||
| `recall_include_entities` | `False` | Include entity information in recall results |
|
||||
| `reflect_context` | `None` | Additional context for reflect operations |
|
||||
| `reflect_max_tokens` | `max_tokens` | Max tokens for reflect results |
|
||||
| `reflect_response_schema` | `None` | JSON schema to constrain reflect output format |
|
||||
| `reflect_tags` | `recall_tags` | Tags to filter memories used in reflect |
|
||||
| `reflect_tags_match` | `recall_tags_match` | Tag matching for reflect |
|
||||
| `include_retain` | `True` | Include the retain tool |
|
||||
| `include_recall` | `True` | Include the recall tool |
|
||||
| `include_reflect` | `True` | Include the reflect tool |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- ag2 >= 0.9.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
title: "Agno Agent Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to Agno agents using Hindsight's retain, recall, and reflect tools. Plug into Agno's native Toolkit pattern for long-term memory across sessions."
|
||||
---
|
||||
|
||||
# Agno
|
||||
|
||||
Persistent memory tools for [Agno](https://github.com/agno-agi/agno) agents via Hindsight. Give your agents long-term memory with retain, recall, and reflect — using Agno's native Toolkit pattern.
|
||||
|
||||
## Features
|
||||
|
||||
- **Native Toolkit** - Extends Agno's `Toolkit` base class, just like `Mem0Tools`
|
||||
- **Memory Instructions** - Pre-recall memories for injection into `Agent(instructions=[...])`
|
||||
- **Three Memory Tools** - Retain (store), Recall (search), Reflect (synthesize) — include any combination
|
||||
- **Flexible Bank Resolution** - Static bank ID, `RunContext.user_id`, or custom resolver
|
||||
- **Simple Configuration** - Configure once globally, or pass a client directly
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-agno
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from agno.agent import Agent
|
||||
from agno.models.openai import OpenAIChat
|
||||
from hindsight_agno import HindsightTools
|
||||
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
)
|
||||
|
||||
agent.print_response("Remember that I prefer dark mode")
|
||||
agent.print_response("What are my preferences?")
|
||||
```
|
||||
|
||||
The agent now has three tools it can call:
|
||||
|
||||
- **`retain_memory`** — Store information to long-term memory
|
||||
- **`recall_memory`** — Search long-term memory for relevant facts
|
||||
- **`reflect_on_memory`** — Synthesize a reasoned answer from memories
|
||||
|
||||
## With Memory Instructions
|
||||
|
||||
Pre-recall relevant memories and inject them into the system prompt:
|
||||
|
||||
```python
|
||||
from hindsight_agno import HindsightTools, memory_instructions
|
||||
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
instructions=[memory_instructions(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = [HindsightTools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
enable_retain=True,
|
||||
enable_recall=True,
|
||||
enable_reflect=False, # Omit reflect
|
||||
)]
|
||||
```
|
||||
|
||||
## Bank Resolution
|
||||
|
||||
The bank ID is resolved in order:
|
||||
|
||||
1. **`bank_resolver`** — Custom callable `(RunContext) -> str`
|
||||
2. **`bank_id`** — Static bank ID passed to constructor
|
||||
3. **`run_context.user_id`** — Automatic per-user banks
|
||||
|
||||
```python
|
||||
# Per-user banks from RunContext
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(hindsight_api_url="http://localhost:8888")],
|
||||
user_id="user-123", # Used as bank_id
|
||||
)
|
||||
|
||||
# Custom resolver
|
||||
def resolve_bank(ctx):
|
||||
return f"team-{ctx.user_id}"
|
||||
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(
|
||||
bank_resolver=resolve_bank,
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing connection details to every toolkit, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_agno import configure, HindsightTools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create toolkit without passing connection details
|
||||
tools = [HindsightTools(bank_id="user-123")]
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
### `HindsightTools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | `None` | Static Hindsight memory bank ID |
|
||||
| `bank_resolver` | `None` | Callable `(RunContext) -> str` for dynamic bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `enable_retain` | `True` | Include the retain (store) tool |
|
||||
| `enable_recall` | `True` | Include the recall (search) tool |
|
||||
| `enable_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `memory_instructions()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `query` | `"relevant context about the user"` | Recall query for memory injection |
|
||||
| `budget` | `"low"` | Recall budget level |
|
||||
| `max_results` | `5` | Maximum memories to inject |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `prefix` | `"Relevant memories:\n"` | Text prepended before memory list |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- agno
|
||||
- hindsight-client >= 0.4.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,101 +0,0 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
title: "Vercel AI SDK Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to any Vercel AI SDK application with five ready-to-use Hindsight tools. Retain conversations, recall context, and reflect on past interactions — works with any model."
|
||||
---
|
||||
|
||||
# Vercel AI SDK
|
||||
|
||||
The `@vectorize-io/hindsight-ai-sdk` package integrates [Hindsight](https://hindsight.vectorize.io) memory with the [Vercel AI SDK](https://ai-sdk.dev). It provides five ready-to-use tools for retaining, recalling, and reflecting on long-term memories.
|
||||
|
||||
[View Changelog →](/changelog/integrations/ai-sdk)
|
||||
|
||||
import CodeSnippet from '@site/src/components/CodeSnippet';
|
||||
|
||||
import aiSdkTs from '!!raw-loader!@site/examples/integrations/ai-sdk.ts';
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @vectorize-io/hindsight-ai-sdk @vectorize-io/hindsight-client ai
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
Create a Hindsight client and pass it to `createHindsightTools` along with a `bankId`. The `bankId` identifies the memory store for this session—typically a user ID.
|
||||
|
||||
<CodeSnippet code={aiSdkTs} section="setup" language="typescript" />
|
||||
|
||||
:::tip Per-request bank IDs
|
||||
In multi-user applications, create `tools` inside your request handler so each request closes over the correct `bankId`. See the [Next.js example](#in-a-nextjs-route-handler) below.
|
||||
:::
|
||||
|
||||
## Usage
|
||||
|
||||
### With `generateText`
|
||||
|
||||
<CodeSnippet code={aiSdkTs} section="generate-text" language="typescript" />
|
||||
|
||||
### With `streamText`
|
||||
|
||||
<CodeSnippet code={aiSdkTs} section="stream-text" language="typescript" />
|
||||
|
||||
### With `ToolLoopAgent`
|
||||
|
||||
<CodeSnippet code={aiSdkTs} section="tool-loop-agent" language="typescript" />
|
||||
|
||||
### In a Next.js Route Handler
|
||||
|
||||
<CodeSnippet code={aiSdkTs} section="next-api-route" language="typescript" />
|
||||
|
||||
---
|
||||
|
||||
## Tools Reference
|
||||
|
||||
Five tools are registered. The `bankId` is fixed at creation time—the agent cannot change it.
|
||||
|
||||
| Tool | What the agent provides | What the constructor controls |
|
||||
|------|------------------------|-------------------------------|
|
||||
| `retain` | `content`, `documentId`, `timestamp`, `context` | `async`, `tags`, `metadata` |
|
||||
| `recall` | `query`, `queryTimestamp` | `budget`, `types`, `maxTokens`, `includeEntities`, `includeChunks` |
|
||||
| `reflect` | `query`, `context` | `budget` |
|
||||
| `getMentalModel` | `mentalModelId` | — |
|
||||
| `getDocument` | `documentId` | — |
|
||||
|
||||
**Why this split?** Semantic inputs (what to remember, what to search for) belong to the agent. Infrastructure concerns (cost budget, tagging strategy, async mode) belong to the application.
|
||||
|
||||
---
|
||||
|
||||
## Constructor Options
|
||||
|
||||
All options except `client` and `bankId` are optional. Each tool's options are grouped under the tool name.
|
||||
|
||||
<CodeSnippet code={aiSdkTs} section="constructor-options" language="typescript" />
|
||||
|
||||
### `retain`
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `async` | `boolean` | `false` | Fire-and-forget — do not wait for ingestion to complete |
|
||||
| `tags` | `string[]` | — | Tags attached to every retained memory |
|
||||
| `metadata` | `Record<string, string>` | — | Metadata attached to every retained memory |
|
||||
| `description` | `string` | built-in | Override the tool description shown to the model |
|
||||
|
||||
### `recall`
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `budget` | `'low' \| 'mid' \| 'high'` | `'mid'` | Controls retrieval depth and latency |
|
||||
| `types` | `('world' \| 'experience' \| 'observation')[]` | all | Restrict results to these fact types |
|
||||
| `maxTokens` | `number` | API default | Cap the total tokens returned |
|
||||
| `includeEntities` | `boolean` | `false` | Include entity observations in results |
|
||||
| `includeChunks` | `boolean` | `false` | Include raw source chunks in results |
|
||||
| `description` | `string` | built-in | Override the tool description shown to the model |
|
||||
|
||||
### `reflect`
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `budget` | `'low' \| 'mid' \| 'high'` | `'mid'` | Controls synthesis depth and latency |
|
||||
| `maxTokens` | `number` | API default | Maximum tokens for the response |
|
||||
| `description` | `string` | built-in | Override the tool description shown to the model |
|
||||
@@ -1,167 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "Vercel Chat SDK Persistent Memory with Hindsight | Integration"
|
||||
description: "Give your Vercel Chat SDK bot persistent, per-user memory across Slack, Discord, Teams, and more. Single handler wrapper, no custom plumbing required."
|
||||
---
|
||||
|
||||
# Vercel Chat SDK
|
||||
|
||||
We built `@vectorize-io/hindsight-chat` to give [Vercel Chat SDK](https://github.com/vercel/chat) bots persistent, per-user memory with a single handler wrapper. The integration works across Slack, Discord, Teams, Google Chat, GitHub, and Linear — no custom plumbing required.
|
||||
|
||||
[View Changelog →](/changelog/integrations/chat)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @vectorize-io/hindsight-chat
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { Chat } from 'chat';
|
||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
||||
import { withHindsightChat } from '@vectorize-io/hindsight-chat';
|
||||
import { streamText } from 'ai';
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
|
||||
const chat = new Chat({ connectors: [/* your connectors */] });
|
||||
const hindsight = new HindsightClient({ apiKey: process.env.HINDSIGHT_API_KEY });
|
||||
|
||||
chat.onNewMention(
|
||||
withHindsightChat(
|
||||
{
|
||||
client: hindsight,
|
||||
bankId: (msg) => msg.author.userId, // per-user memory
|
||||
},
|
||||
async (thread, message, ctx) => {
|
||||
await thread.subscribe();
|
||||
|
||||
const result = await streamText({
|
||||
model: openai('gpt-4o'),
|
||||
system: ctx.memoriesAsSystemPrompt(),
|
||||
messages: [{ role: 'user', content: message.text }],
|
||||
});
|
||||
|
||||
// Stream the response
|
||||
const chunks: string[] = [];
|
||||
for await (const chunk of result.textStream) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
const fullResponse = chunks.join('');
|
||||
await thread.post(fullResponse);
|
||||
|
||||
// Store the conversation in memory
|
||||
await ctx.retain(
|
||||
`User: ${message.text}\nAssistant: ${fullResponse}`
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### `withHindsightChat(options, handler)`
|
||||
|
||||
`withHindsightChat` wraps your existing Chat SDK handler and injects memory context automatically. It returns a standard handler `(thread, message) => Promise<void>` so it drops in without changing your handler signature.
|
||||
|
||||
#### Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `client` | `HindsightClient` | *required* | Hindsight client instance |
|
||||
| `bankId` | `string \| (msg) => string` | *required* | Memory bank ID or resolver function |
|
||||
| `recall.enabled` | `boolean` | `true` | Auto-recall memories before handler |
|
||||
| `recall.budget` | `'low' \| 'mid' \| 'high'` | `'mid'` | Processing budget for recall |
|
||||
| `recall.maxTokens` | `number` | API default | Max tokens for recall results |
|
||||
| `recall.types` | `FactType[]` | all | Filter to specific fact types |
|
||||
| `recall.includeEntities` | `boolean` | `true` | Include entity observations |
|
||||
| `retain.enabled` | `boolean` | `false` | Auto-retain inbound messages |
|
||||
| `retain.async` | `boolean` | `true` | Fire-and-forget retain |
|
||||
| `retain.tags` | `string[]` | – | Tags for retained memories |
|
||||
| `retain.metadata` | `Record<string, string>` | – | Metadata for retained memories |
|
||||
|
||||
### Context (`ctx`)
|
||||
|
||||
We inject a third `ctx` argument into your handler that exposes the full Hindsight memory API scoped to the current user's bank:
|
||||
|
||||
| Property/Method | Description |
|
||||
|----------------|-------------|
|
||||
| `ctx.bankId` | Resolved bank ID |
|
||||
| `ctx.memories` | Array of recalled memories |
|
||||
| `ctx.entities` | Entity observations (or null) |
|
||||
| `ctx.memoriesAsSystemPrompt(options?)` | Format memories for LLM system prompt |
|
||||
| `ctx.retain(content, options?)` | Store content in memory |
|
||||
| `ctx.recall(query, options?)` | Search memories |
|
||||
| `ctx.reflect(query, options?)` | Reason over memories |
|
||||
|
||||
## Examples
|
||||
|
||||
### Subscribed Message Handler
|
||||
|
||||
```typescript
|
||||
chat.onSubscribedMessage(
|
||||
withHindsightChat(
|
||||
{
|
||||
client: hindsight,
|
||||
bankId: (msg) => msg.author.userId,
|
||||
recall: { budget: 'high', maxTokens: 1000 },
|
||||
},
|
||||
async (thread, message, ctx) => {
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4o'),
|
||||
system: ctx.memoriesAsSystemPrompt(),
|
||||
messages: [{ role: 'user', content: message.text }],
|
||||
});
|
||||
await thread.post(result.text);
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### Auto-Retain Inbound Messages
|
||||
|
||||
```typescript
|
||||
chat.onNewMention(
|
||||
withHindsightChat(
|
||||
{
|
||||
client: hindsight,
|
||||
bankId: (msg) => msg.author.userId,
|
||||
retain: { enabled: true, tags: ['slack', 'inbound'] },
|
||||
},
|
||||
async (thread, message, ctx) => {
|
||||
// Inbound message is already being retained automatically
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4o'),
|
||||
system: ctx.memoriesAsSystemPrompt(),
|
||||
messages: [{ role: 'user', content: message.text }],
|
||||
});
|
||||
await thread.post(result.text);
|
||||
|
||||
// Retain the assistant response separately
|
||||
await ctx.retain(`Assistant: ${result.text}`, {
|
||||
tags: ['slack', 'outbound'],
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### Static Bank ID (Shared Memory)
|
||||
|
||||
```typescript
|
||||
// All users share the same memory bank
|
||||
chat.onNewMention(
|
||||
withHindsightChat(
|
||||
{ client: hindsight, bankId: 'shared-team-memory' },
|
||||
async (thread, message, ctx) => {
|
||||
// ...
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
We designed the integration so that memory failures never break your bot. Auto-recall and auto-retain errors are caught internally, logged as warnings, and the handler continues with empty memories. Manual `ctx.retain()`, `ctx.recall()`, and `ctx.reflect()` calls propagate errors normally so you can handle them as needed.
|
||||
@@ -1,216 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "Claude Code Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Claude Code with Hindsight. Automatically captures conversations and recalls relevant context across sessions using Claude Code's hook-based architecture."
|
||||
---
|
||||
|
||||
# Claude Code
|
||||
|
||||
Biomimetic long-term memory for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) using [Hindsight](https://vectorize.io/hindsight). Automatically captures conversations and intelligently recalls relevant context — a complete port of [`hindsight-openclaw`](./openclaw) adapted to Claude Code's hook-based plugin architecture.
|
||||
|
||||
[View Changelog →](/changelog/integrations/claude-code)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Add the Hindsight marketplace and install the plugin
|
||||
claude plugin marketplace add vectorize-io/hindsight
|
||||
claude plugin install hindsight-memory
|
||||
|
||||
# 2. Configure your LLM provider for memory extraction
|
||||
# Option A: OpenAI (auto-detected)
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option B: Anthropic (auto-detected)
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
|
||||
# Option C: No API key needed (uses Claude Code's own model — personal/local use only)
|
||||
export HINDSIGHT_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option D: Connect to an external Hindsight server instead of running locally
|
||||
mkdir -p ~/.hindsight
|
||||
echo '{"hindsightApiUrl": "https://your-hindsight-server.com"}' > ~/.hindsight/claude-code.json
|
||||
|
||||
# 3. Start Claude Code — the plugin activates automatically
|
||||
claude
|
||||
```
|
||||
|
||||
That's it! The plugin will automatically start capturing and recalling memories.
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-recall** — on every user prompt, queries Hindsight for relevant memories and injects them as context (invisible to the chat transcript, visible to Claude)
|
||||
- **Auto-retain** — after every response (or every N turns), extracts and retains conversation content to Hindsight for long-term storage
|
||||
- **Daemon management** — can auto-start/stop `hindsight-embed` locally or connect to an external Hindsight server
|
||||
- **Dynamic bank IDs** — supports per-agent, per-project, or per-session memory isolation
|
||||
- **Channel-agnostic** — works with Claude Code Channels (Telegram, Discord, Slack) or interactive sessions
|
||||
- **Zero dependencies** — pure Python stdlib, no pip install required
|
||||
|
||||
## Architecture
|
||||
|
||||
The plugin uses all four Claude Code hook events:
|
||||
|
||||
| Hook | Event | Purpose |
|
||||
|------|-------|---------|
|
||||
| `session_start.py` | `SessionStart` | Health check — verify Hindsight is reachable |
|
||||
| `recall.py` | `UserPromptSubmit` | **Auto-recall** — query memories, inject as `additionalContext` |
|
||||
| `retain.py` | `Stop` | **Auto-retain** — extract transcript, POST to Hindsight (async) |
|
||||
| `session_end.py` | `SessionEnd` | Cleanup — stop auto-managed daemon if started |
|
||||
|
||||
## Connection Modes
|
||||
|
||||
### 1. External API (recommended for production)
|
||||
|
||||
Connect to a running Hindsight server (cloud or self-hosted). No local LLM needed — the server handles fact extraction.
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "https://your-hindsight-server.com",
|
||||
"hindsightApiToken": "your-token"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Local Daemon (auto-managed)
|
||||
|
||||
The plugin automatically starts and stops `hindsight-embed` via `uvx`. Requires an LLM provider API key for local fact extraction.
|
||||
|
||||
Set an LLM provider:
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
# or
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
# or
|
||||
export HINDSIGHT_LLM_PROVIDER=claude-code # No API key needed
|
||||
```
|
||||
|
||||
The model is selected automatically by the Hindsight API. To override, set `HINDSIGHT_LLM_MODEL`.
|
||||
|
||||
### 3. Existing Local Server
|
||||
|
||||
If you already have `hindsight-embed` running, leave `hindsightApiUrl` empty and set `apiPort` to match your server's port. The plugin will detect it automatically.
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings live in `~/.hindsight/claude-code.json`. Every setting can also be overridden via environment variables. The plugin ships with sensible defaults — you only need to configure what you want to change.
|
||||
|
||||
**Loading order** (later entries win):
|
||||
1. Built-in defaults (hardcoded in the plugin)
|
||||
2. Plugin `settings.json` (ships with the plugin, at `CLAUDE_PLUGIN_ROOT/settings.json`)
|
||||
3. User config (`~/.hindsight/claude-code.json` — recommended for your overrides)
|
||||
4. Environment variables
|
||||
|
||||
---
|
||||
|
||||
### Connection & Daemon
|
||||
|
||||
These settings control how the plugin connects to the Hindsight API.
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `hindsightApiUrl` | `HINDSIGHT_API_URL` | `""` (empty) | URL of an external Hindsight API server. When empty, the plugin uses a local daemon instead. |
|
||||
| `hindsightApiToken` | `HINDSIGHT_API_TOKEN` | `null` | Authentication token for the external API. Only needed when `hindsightApiUrl` is set. |
|
||||
| `apiPort` | `HINDSIGHT_API_PORT` | `9077` | Port used by the local `hindsight-embed` daemon. Change this if you run multiple instances or have a port conflict. |
|
||||
| `daemonIdleTimeout` | `HINDSIGHT_DAEMON_IDLE_TIMEOUT` | `0` | Seconds of inactivity before the local daemon shuts itself down. `0` means the daemon stays running until the session ends. |
|
||||
| `embedVersion` | `HINDSIGHT_EMBED_VERSION` | `"latest"` | Which version of `hindsight-embed` to install via `uvx`. Pin to a specific version (e.g. `"0.5.2"`) for reproducibility. |
|
||||
| `embedPackagePath` | `HINDSIGHT_EMBED_PACKAGE_PATH` | `null` | Local filesystem path to a `hindsight-embed` checkout. When set, the plugin runs from this path instead of installing via `uvx`. Useful for development. |
|
||||
|
||||
---
|
||||
|
||||
### LLM Provider (local daemon only)
|
||||
|
||||
These settings configure which LLM the local daemon uses for fact extraction. They are **ignored** when connecting to an external API (the server uses its own LLM configuration).
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `llmProvider` | `HINDSIGHT_LLM_PROVIDER` | auto-detect | Which LLM provider to use. Supported values: `openai`, `anthropic`, `gemini`, `groq`, `ollama`, `openai-codex`, `claude-code`. When omitted, the plugin auto-detects by checking for API key env vars in order: `OPENAI_API_KEY` → `ANTHROPIC_API_KEY` → `GEMINI_API_KEY` → `GROQ_API_KEY`. |
|
||||
| `llmModel` | `HINDSIGHT_LLM_MODEL` | provider default | Override the default model for the chosen provider (e.g. `"gpt-4o"`, `"claude-sonnet-4-20250514"`). When omitted, the Hindsight API picks a sensible default for each provider. |
|
||||
| `llmApiKeyEnv` | — | provider standard | Name of the environment variable that holds the API key. Normally auto-detected (e.g. `OPENAI_API_KEY` for the `openai` provider). Set this only if your key is in a non-standard env var. |
|
||||
|
||||
---
|
||||
|
||||
### Memory Bank
|
||||
|
||||
A **bank** is an isolated memory store — like a separate "brain." These settings control which bank the plugin reads from and writes to.
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `bankId` | `HINDSIGHT_BANK_ID` | `"claude_code"` | The bank ID to use when `dynamicBankId` is `false`. All sessions share this single bank. |
|
||||
| `bankMission` | `HINDSIGHT_BANK_MISSION` | generic assistant prompt | A short description of the agent's identity and purpose. Sent to Hindsight when creating or updating the bank, and used during recall to contextualize results. |
|
||||
| `retainMission` | — | extraction prompt | Instructions for the fact extraction LLM — tells it *what* to extract from conversations (e.g. "Extract technical decisions and user preferences"). |
|
||||
| `dynamicBankId` | `HINDSIGHT_DYNAMIC_BANK_ID` | `false` | When `true`, the plugin derives a unique bank ID from context fields (see `dynamicBankGranularity`), giving each combination its own isolated memory. |
|
||||
| `dynamicBankGranularity` | — | `["agent", "project"]` | Which context fields to combine when building a dynamic bank ID. Available fields: `agent` (agent name), `project` (working directory), `session` (session ID), `channel` (channel ID), `user` (user ID). |
|
||||
| `bankIdPrefix` | — | `""` | A string prepended to all bank IDs — both static and dynamic. Useful for namespacing (e.g. `"prod"` or `"staging"`). |
|
||||
| `agentName` | `HINDSIGHT_AGENT_NAME` | `"claude-code"` | Name used for the `agent` field in dynamic bank ID derivation. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Recall
|
||||
|
||||
Auto-recall runs on every user prompt. It queries Hindsight for relevant memories and injects them into Claude's context as invisible `additionalContext` (the user doesn't see them in the chat transcript).
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRecall` | `HINDSIGHT_AUTO_RECALL` | `true` | Master switch for auto-recall. Set to `false` to disable memory retrieval entirely. |
|
||||
| `recallBudget` | `HINDSIGHT_RECALL_BUDGET` | `"mid"` | Controls how hard Hindsight searches for memories. `"low"` = fast, fewer strategies; `"mid"` = balanced; `"high"` = thorough, slower. Affects latency directly. |
|
||||
| `recallMaxTokens` | `HINDSIGHT_RECALL_MAX_TOKENS` | `1024` | Maximum number of tokens in the recalled memory block. Lower values reduce context usage but may truncate relevant memories. |
|
||||
| `recallTypes` | — | `["world", "experience"]` | Which memory types to retrieve. `"world"` = general facts; `"experience"` = personal experiences; `"observation"` = raw observations. |
|
||||
| `recallContextTurns` | `HINDSIGHT_RECALL_CONTEXT_TURNS` | `1` | How many prior conversation turns to include when composing the recall query. `1` = only the latest user message; higher values give more context but may dilute the query. |
|
||||
| `recallMaxQueryChars` | `HINDSIGHT_RECALL_MAX_QUERY_CHARS` | `800` | Maximum character length of the query sent to Hindsight. Longer queries are truncated. |
|
||||
| `recallRoles` | — | `["user", "assistant"]` | Which message roles to include when building the recall query from prior turns. |
|
||||
| `recallPromptPreamble` | — | built-in string | Text placed above the recalled memories in the injected context block. Customize this to change how Claude interprets the memories. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Retain
|
||||
|
||||
Auto-retain runs after Claude responds. It extracts the conversation transcript and sends it to Hindsight for long-term storage and fact extraction.
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRetain` | `HINDSIGHT_AUTO_RETAIN` | `true` | Master switch for auto-retain. Set to `false` to disable memory storage entirely. |
|
||||
| `retainMode` | `HINDSIGHT_RETAIN_MODE` | `"full-session"` | Retention strategy. `"full-session"` sends the full conversation transcript (with chunking). |
|
||||
| `retainEveryNTurns` | — | `10` | How often to retain. `1` = every turn; `10` = every 10th turn. Higher values reduce API calls but delay memory capture. Values > 1 enable **chunked retention** with a sliding window. |
|
||||
| `retainOverlapTurns` | — | `2` | When chunked retention fires, this many extra turns from the previous chunk are included for continuity. Total window size = `retainEveryNTurns + retainOverlapTurns`. |
|
||||
| `retainRoles` | — | `["user", "assistant"]` | Which message roles to include in the retained transcript. |
|
||||
| `retainToolCalls` | — | `true` | Whether to include tool calls (function invocations and results) in the retained transcript. Captures structured actions like file reads, searches, and code edits. |
|
||||
| `retainTags` | — | `["{session_id}"]` | Tags attached to the retained document. Supports `{session_id}` placeholder which is replaced with the current session ID at runtime. |
|
||||
| `retainMetadata` | — | `{}` | Arbitrary key-value metadata attached to the retained document. |
|
||||
| `retainContext` | — | `"claude-code"` | A label attached to retained memories identifying their source. Useful when multiple integrations write to the same bank. |
|
||||
|
||||
---
|
||||
|
||||
### Debug
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `debug` | `HINDSIGHT_DEBUG` | `false` | Enable verbose logging to stderr. All log lines are prefixed with `[Hindsight]`. Useful for diagnosing connection issues, recall/retain behavior, and bank ID derivation. |
|
||||
|
||||
## Claude Code Channels
|
||||
|
||||
With [Claude Code Channels](https://docs.anthropic.com/en/docs/claude-code), Claude Code can operate as a persistent background agent connected to Telegram, Discord, Slack, and other messaging platforms. This plugin gives Channel-based agents the same long-term memory that `hindsight-openclaw` provides for Openclaw agents.
|
||||
|
||||
For Channel agents, enable dynamic bank IDs for per-channel/per-user memory isolation:
|
||||
|
||||
```json
|
||||
{
|
||||
"dynamicBankId": true,
|
||||
"dynamicBankGranularity": ["agent", "channel", "user"]
|
||||
}
|
||||
```
|
||||
|
||||
And set channel context via environment variables:
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_CHANNEL_ID="telegram-group-12345"
|
||||
export HINDSIGHT_USER_ID="user-67890"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Plugin not activating**: Check Claude Code logs for `[Hindsight]` messages. Enable `"debug": true` in `~/.hindsight/claude-code.json`.
|
||||
|
||||
**Recall returning no memories**: Verify the Hindsight server is reachable (`curl http://localhost:9077/health`). Memories need at least one retain cycle before they're available.
|
||||
|
||||
**Daemon not starting**: Ensure an LLM API key is set (or use `HINDSIGHT_LLM_PROVIDER=claude-code`). Review daemon logs at `~/.hindsight/profiles/claude-code.log`.
|
||||
|
||||
**High latency on recall**: The recall hook has a 12-second timeout. Use `recallBudget: "low"` or reduce `recallMaxTokens` for faster responses.
|
||||
@@ -1,184 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
title: "Codex CLI Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to OpenAI Codex CLI with Hindsight. Three Python hook scripts automatically recall context before each prompt and retain conversations — no workflow changes required."
|
||||
---
|
||||
|
||||
# Codex
|
||||
|
||||
[View Changelog →](/changelog/integrations/codex)
|
||||
|
||||
Persistent memory for [Codex CLI](https://github.com/openai/codex) using [Hindsight](https://vectorize.io/hindsight). Three Python hook scripts automatically recall relevant context before each prompt and retain conversations after each turn — no changes to your Codex workflow required.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-codex | bash
|
||||
```
|
||||
|
||||
The installer will guide you through choosing local or cloud mode and configuring your connection. Once installed, start a new Codex session — memory is live.
|
||||
|
||||
To uninstall:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-codex | bash -s -- --uninstall
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-recall** — on every user prompt, queries Hindsight for relevant memories and injects them as `additionalContext` (invisible to the transcript, visible to Codex)
|
||||
- **Auto-retain** — after each Codex response, stores the conversation transcript to Hindsight for future recall
|
||||
- **Dynamic bank IDs** — supports per-project memory isolation based on the working directory
|
||||
- **Session-level upsert** — uses the session ID as the document ID so re-running the same session updates rather than duplicates stored content
|
||||
- **Zero dependencies** — pure Python stdlib, no pip install required
|
||||
|
||||
## Architecture
|
||||
|
||||
The plugin uses three Codex hook events:
|
||||
|
||||
| Hook | Event | Purpose |
|
||||
|------|-------|---------|
|
||||
| `session_start.py` | `SessionStart` | Warm up — verify Hindsight is reachable |
|
||||
| `recall.py` | `UserPromptSubmit` | **Auto-recall** — query memories, inject as `additionalContext` |
|
||||
| `retain.py` | `Stop` | **Auto-retain** — extract transcript, POST to Hindsight (async) |
|
||||
|
||||
On `UserPromptSubmit`, the hook reads the prompt, queries Hindsight for the most relevant memories, and outputs a `hookSpecificOutput.additionalContext` block. Codex prepends this to the conversation before sending it to the model:
|
||||
|
||||
```
|
||||
<hindsight_memories>
|
||||
Relevant memories from past conversations...
|
||||
Current time - 2026-03-27 09:14
|
||||
|
||||
- Project uses FastAPI with asyncpg — not SQLAlchemy [world] (2026-03-26)
|
||||
- Preferred testing framework: pytest with pytest-asyncio [experience] (2026-03-26)
|
||||
</hindsight_memories>
|
||||
```
|
||||
|
||||
On `Stop`, the hook reads the session transcript, strips previously injected memory tags (to prevent feedback loops), and POSTs the conversation to Hindsight asynchronously.
|
||||
|
||||
## Connection Modes
|
||||
|
||||
### 1. External API (recommended)
|
||||
|
||||
Connect to a running Hindsight server (cloud or self-hosted):
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "https://api.hindsight.vectorize.io",
|
||||
"hindsightApiToken": "hsk_your_token"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Local Daemon
|
||||
|
||||
Run `hindsight-embed` locally. The `session_start.py` hook will detect it on `apiPort` (default `9077`). The daemon is not auto-started by the Codex plugin — start it separately:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed
|
||||
```
|
||||
|
||||
Then leave `hindsightApiUrl` empty in your config and the plugin will connect to `http://localhost:9077`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Settings are loaded from `~/.hindsight/codex.json`. Every setting can also be overridden via environment variable.
|
||||
|
||||
**Loading order** (later entries win):
|
||||
|
||||
1. Built-in defaults
|
||||
2. Plugin `settings.json` (at `~/.hindsight/codex/settings.json`)
|
||||
3. User config (`~/.hindsight/codex.json`)
|
||||
4. Environment variables
|
||||
|
||||
---
|
||||
|
||||
### Connection
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `hindsightApiUrl` | `HINDSIGHT_API_URL` | `""` | URL of the Hindsight API server. Required. |
|
||||
| `hindsightApiToken` | `HINDSIGHT_API_TOKEN` | `null` | API token for authentication. Required for Hindsight Cloud. |
|
||||
| `apiPort` | `HINDSIGHT_API_PORT` | `9077` | Port for the local `hindsight-embed` daemon. |
|
||||
|
||||
---
|
||||
|
||||
### Memory Bank
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `bankId` | `HINDSIGHT_BANK_ID` | `"codex"` | The bank to read from and write to. All sessions share this bank unless `dynamicBankId` is enabled. |
|
||||
| `bankMission` | `HINDSIGHT_BANK_MISSION` | coding assistant prompt | Describes the agent's purpose. Sent when creating or updating the bank. |
|
||||
| `retainMission` | — | extraction prompt | Instructions for Hindsight's fact extraction — what to extract from coding conversations. |
|
||||
| `dynamicBankId` | `HINDSIGHT_DYNAMIC_BANK_ID` | `false` | When `true`, derives a unique bank ID from `dynamicBankGranularity` fields — useful for per-project isolation. |
|
||||
| `dynamicBankGranularity` | — | `["agent", "project"]` | Which fields to combine for dynamic bank IDs. `"project"` = working directory, `"agent"` = agent name. |
|
||||
| `bankIdPrefix` | — | `""` | Prefix prepended to all bank IDs. |
|
||||
| `agentName` | `HINDSIGHT_AGENT_NAME` | `"codex"` | Agent name used in dynamic bank ID derivation. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Recall
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRecall` | `HINDSIGHT_AUTO_RECALL` | `true` | Master switch for auto-recall. |
|
||||
| `recallBudget` | `HINDSIGHT_RECALL_BUDGET` | `"mid"` | Search depth: `"low"` (fast), `"mid"` (balanced), `"high"` (thorough). |
|
||||
| `recallMaxTokens` | `HINDSIGHT_RECALL_MAX_TOKENS` | `1024` | Max tokens in the recalled memory block. |
|
||||
| `recallTypes` | — | `["world", "experience"]` | Memory types to retrieve. |
|
||||
| `recallContextTurns` | `HINDSIGHT_RECALL_CONTEXT_TURNS` | `1` | Prior turns to include when building the recall query. `1` = latest prompt only. |
|
||||
| `recallMaxQueryChars` | `HINDSIGHT_RECALL_MAX_QUERY_CHARS` | `800` | Max characters in the query sent to Hindsight. |
|
||||
| `recallRoles` | — | `["user", "assistant"]` | Which roles to include when building a multi-turn query. |
|
||||
| `recallPromptPreamble` | — | built-in | Text placed above the recalled memories in the injected context block. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Retain
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRetain` | `HINDSIGHT_AUTO_RETAIN` | `true` | Master switch for auto-retain. |
|
||||
| `retainMode` | `HINDSIGHT_RETAIN_MODE` | `"full-session"` | `"full-session"` sends the full transcript per session (upserted by session ID). `"chunked"` sends sliding windows every N turns. |
|
||||
| `retainEveryNTurns` | — | `10` | Retain fires every N turns. `1` = every turn. Higher values reduce API calls. |
|
||||
| `retainOverlapTurns` | — | `2` | Extra turns included from the previous chunk (chunked mode only). |
|
||||
| `retainRoles` | — | `["user", "assistant"]` | Which roles to include in the retained transcript. |
|
||||
| `retainTags` | — | `["{session_id}"]` | Tags attached to the stored document. `{session_id}` is replaced at runtime. |
|
||||
| `retainMetadata` | — | `{}` | Arbitrary key-value metadata attached to the stored document. |
|
||||
| `retainContext` | — | `"codex"` | Label identifying the source integration. Useful when multiple integrations write to the same bank. |
|
||||
|
||||
---
|
||||
|
||||
### Debug
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `debug` | `HINDSIGHT_DEBUG` | `false` | Enable verbose logging to stderr. All log lines are prefixed with `[Hindsight]`. |
|
||||
|
||||
## Per-Project Memory
|
||||
|
||||
To give each project its own isolated memory bank, enable dynamic bank IDs:
|
||||
|
||||
```json
|
||||
{
|
||||
"dynamicBankId": true,
|
||||
"dynamicBankGranularity": ["agent", "project"]
|
||||
}
|
||||
```
|
||||
|
||||
With this config, running Codex in `~/projects/api` and `~/projects/frontend` stores and recalls memories separately. Bank IDs are derived from the working directory path.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Hooks not firing**: Check that `~/.codex/config.toml` contains `codex_hooks = true` under `[features]`. Re-run the installer to fix this automatically.
|
||||
|
||||
**No memories recalled**: Recall returns results only after something has been retained. Either complete one Codex session first, or seed your bank manually using the [cookbook example](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/codex-memory).
|
||||
|
||||
**Memory not being stored**: `retainEveryNTurns` defaults to `10` — retain only fires every 10 turns. While testing, add `"retainEveryNTurns": 1` to `~/.hindsight/codex.json`.
|
||||
|
||||
**Debug mode**: Add `"debug": true` to `~/.hindsight/codex.json` to see what Hindsight is doing on each turn:
|
||||
|
||||
```
|
||||
[Hindsight] Recalling from bank 'codex', query length: 42
|
||||
[Hindsight] Injecting 3 memories
|
||||
[Hindsight] Retaining to bank 'codex', doc 'sess-abc123', 2 messages, 847 chars
|
||||
```
|
||||
|
||||
**High latency on recall**: Use `"recallBudget": "low"` or reduce `recallMaxTokens` to speed up recall queries.
|
||||
@@ -1,245 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "CrewAI Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add long-term memory to your CrewAI agent crews. Hindsight provides fact extraction, entity tracking, and temporal awareness — persisted automatically across all crew runs."
|
||||
---
|
||||
|
||||
# CrewAI
|
||||
|
||||
Persistent memory for AI agent crews via [CrewAI](https://github.com/crewAIInc/crewAI). Give your crews long-term memory with fact extraction, entity tracking, and temporal awareness.
|
||||
|
||||
[View Changelog →](/changelog/integrations/crewai)
|
||||
|
||||
## Features
|
||||
|
||||
- **Drop-in Storage Backend** - Implements CrewAI's `Storage` interface for `ExternalMemory`
|
||||
- **Automatic Memory Flow** - CrewAI automatically stores task outputs and retrieves relevant memories
|
||||
- **Per-Agent Banks** - Optionally give each agent its own isolated memory bank
|
||||
- **Reflect Tool** - Agents can explicitly reason over memories with disposition-aware synthesis
|
||||
- **Simple Configuration** - Configure once, use everywhere
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-crewai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from hindsight_crewai import configure, HindsightStorage
|
||||
from crewai.memory.external.external_memory import ExternalMemory
|
||||
from crewai import Agent, Crew, Task
|
||||
|
||||
configure(hindsight_api_url="http://localhost:8888")
|
||||
|
||||
crew = Crew(
|
||||
agents=[Agent(role="Researcher", goal="Find information", backstory="...")],
|
||||
tasks=[Task(description="Research AI trends", expected_output="Report")],
|
||||
external_memory=ExternalMemory(
|
||||
storage=HindsightStorage(bank_id="my-crew")
|
||||
),
|
||||
)
|
||||
|
||||
crew.kickoff()
|
||||
```
|
||||
|
||||
That's it. CrewAI will automatically:
|
||||
- **Query memories** at the start of each task
|
||||
- **Store task outputs** to Hindsight after each task completes
|
||||
|
||||
Memories persist across crew runs, so your crew learns over time.
|
||||
|
||||
## How It Works
|
||||
|
||||
The integration maps CrewAI's 3-method `Storage` interface to Hindsight's API:
|
||||
|
||||
| CrewAI | Hindsight | What happens |
|
||||
|--------|-----------|--------------|
|
||||
| `save(value, metadata, agent)` | `retain(bank_id, content, ...)` | Task output is stored. Hindsight extracts facts, entities, and relationships from the raw text. |
|
||||
| `search(query, limit)` | `recall(bank_id, query, ...)` | CrewAI constructs a query from the task description. Hindsight runs semantic search, BM25, graph traversal, and reranking. |
|
||||
| `reset()` | `delete_bank(bank_id)` | Wipes the bank and optionally recreates it with its original mission. |
|
||||
|
||||
CrewAI calls `search()` automatically at the start of each task and `save()` after each task completes.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```python
|
||||
from hindsight_crewai import configure
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888", # Hindsight API URL
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: "low", "mid", "high"
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match: any/all/any_strict/all_strict
|
||||
verbose=True, # Enable logging
|
||||
)
|
||||
```
|
||||
|
||||
### Per-Storage Overrides
|
||||
|
||||
Constructor arguments override global configuration:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
budget="high",
|
||||
max_tokens=8192,
|
||||
tags=["team:alpha"],
|
||||
)
|
||||
```
|
||||
|
||||
## Bank Missions
|
||||
|
||||
Set a mission to guide how Hindsight processes and organizes memories:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
mission="Track software architecture decisions, technical debt, and team preferences.",
|
||||
)
|
||||
```
|
||||
|
||||
## Per-Agent Memory Banks
|
||||
|
||||
Give each agent its own isolated memory bank:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
per_agent_banks=True,
|
||||
# Researcher -> "my-crew-researcher"
|
||||
# Writer -> "my-crew-writer"
|
||||
)
|
||||
```
|
||||
|
||||
Or use a custom bank resolver for full control:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
bank_resolver=lambda base, agent: f"{base}-{agent.lower()}" if agent else base,
|
||||
)
|
||||
```
|
||||
|
||||
:::info
|
||||
When `per_agent_banks=True`, the automatic `search()` at task start queries the base bank (shared context), since CrewAI's `search()` method does not receive the agent parameter. For per-agent search isolation, create separate `HindsightStorage` instances per agent.
|
||||
:::
|
||||
|
||||
## Reflect Tool
|
||||
|
||||
CrewAI's storage interface only supports save/search/reset. To give agents access to Hindsight's `reflect` (disposition-aware memory synthesis), add it as a tool:
|
||||
|
||||
```python
|
||||
from hindsight_crewai import HindsightReflectTool
|
||||
|
||||
reflect_tool = HindsightReflectTool(
|
||||
bank_id="my-crew",
|
||||
budget="mid",
|
||||
reflect_context="You are helping a software team track decisions.",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
role="Analyst",
|
||||
goal="Analyze project history",
|
||||
backstory="...",
|
||||
tools=[reflect_tool],
|
||||
)
|
||||
```
|
||||
|
||||
When the agent calls this tool, it gets a synthesized, contextual answer based on all relevant memories rather than raw fact snippets.
|
||||
|
||||
## Full Example
|
||||
|
||||
A research crew that remembers findings across runs:
|
||||
|
||||
```python
|
||||
from hindsight_crewai import configure, HindsightStorage, HindsightReflectTool
|
||||
from crewai.memory.external.external_memory import ExternalMemory
|
||||
from crewai import Agent, Crew, Task
|
||||
|
||||
configure(hindsight_api_url="http://localhost:8888")
|
||||
|
||||
storage = HindsightStorage(
|
||||
bank_id="research-crew",
|
||||
mission="Track technology research findings and comparisons.",
|
||||
)
|
||||
|
||||
reflect_tool = HindsightReflectTool(bank_id="research-crew", budget="mid")
|
||||
|
||||
researcher = Agent(
|
||||
role="Researcher",
|
||||
goal="Research topics, building on prior knowledge.",
|
||||
backstory="Before starting, use hindsight_reflect to check what you already know.",
|
||||
tools=[reflect_tool],
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
role="Writer",
|
||||
goal="Write summaries incorporating prior findings.",
|
||||
backstory="Use hindsight_reflect to recall prior research.",
|
||||
tools=[reflect_tool],
|
||||
)
|
||||
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
tasks=[
|
||||
Task(description="Research the benefits of Rust", expected_output="Analysis", agent=researcher),
|
||||
Task(description="Write an executive summary", expected_output="Summary", agent=writer),
|
||||
],
|
||||
external_memory=ExternalMemory(storage=storage),
|
||||
)
|
||||
|
||||
# Run 1: researches Rust, stores findings
|
||||
crew.kickoff()
|
||||
|
||||
# Run 2: recalls Rust research when comparing with Go
|
||||
crew.tasks[0].description = "Compare Rust with Go"
|
||||
crew.kickoff()
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Configuration
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `configure(...)` | Set global connection and default settings |
|
||||
| `get_config()` | Get current configuration |
|
||||
| `reset_config()` | Reset configuration to None |
|
||||
|
||||
### Storage
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `bank_id` | required | Hindsight memory bank ID |
|
||||
| `hindsight_api_url` | from config | Override API URL |
|
||||
| `api_key` | from config | Override API key |
|
||||
| `budget` | `"mid"` | Recall budget (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Max tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `per_agent_banks` | `False` | Give each agent its own bank |
|
||||
| `bank_resolver` | `None` | Custom `(bank_id, agent) -> bank_id` |
|
||||
| `mission` | `None` | Bank mission for memory organization |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
### Reflect Tool
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `bank_id` | required | Hindsight memory bank ID |
|
||||
| `budget` | `"mid"` | Reflect budget (low/mid/high) |
|
||||
| `reflect_context` | `None` | Additional context for reasoning |
|
||||
| `hindsight_api_url` | from config | Override API URL |
|
||||
| `api_key` | from config | Override API key |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- crewai >= 0.86.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,177 +0,0 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
title: "Hermes Agent Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Hermes Agent with Hindsight. Automatically recalls context before every LLM call and retains conversations for future sessions."
|
||||
---
|
||||
|
||||
# Hermes Agent
|
||||
|
||||
Persistent long-term memory for [Hermes Agent](https://github.com/NousResearch/hermes-agent) using [Hindsight](https://vectorize.io/hindsight). Automatically recalls relevant context before every LLM call and retains conversations for future sessions — plus explicit retain/recall/reflect tools.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Install the plugin into Hermes's Python environment
|
||||
uv pip install hindsight-hermes --python $HOME/.hermes/hermes-agent/venv/bin/python
|
||||
|
||||
# 2. Configure (choose one)
|
||||
# Option A: Config file (recommended)
|
||||
mkdir -p ~/.hindsight
|
||||
cat > ~/.hindsight/hermes.json << 'EOF'
|
||||
{
|
||||
"hindsightApiUrl": "http://localhost:9077",
|
||||
"bankId": "hermes"
|
||||
}
|
||||
EOF
|
||||
|
||||
# Option B: Environment variables
|
||||
export HINDSIGHT_API_URL=http://localhost:9077
|
||||
export HINDSIGHT_BANK_ID=hermes
|
||||
|
||||
# 3. Start Hermes — the plugin activates automatically
|
||||
hermes
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-recall** — on every turn, queries Hindsight for relevant memories and injects them into the system prompt (via `pre_llm_call` hook)
|
||||
- **Auto-retain** — after every response, retains the user/assistant exchange to Hindsight (via `post_llm_call` hook)
|
||||
- **Explicit tools** — `hindsight_retain`, `hindsight_recall`, `hindsight_reflect` for direct model control
|
||||
- **Config file** — `~/.hindsight/hermes.json` with the same field names as openclaw and claude-code integrations
|
||||
- **Zero config overhead** — env vars still work as overrides for CI/automation
|
||||
|
||||
:::note
|
||||
The lifecycle hooks (`pre_llm_call`/`post_llm_call`) require hermes-agent with [PR #2823](https://github.com/NousResearch/hermes-agent/pull/2823) or later. On older versions, only the three tools are registered — hooks are silently skipped.
|
||||
:::
|
||||
|
||||
## Architecture
|
||||
|
||||
The plugin registers via Hermes's `hermes_agent.plugins` entry point system:
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| `pre_llm_call` hook | **Auto-recall** — query memories, inject as ephemeral system prompt context |
|
||||
| `post_llm_call` hook | **Auto-retain** — store user/assistant exchange to Hindsight |
|
||||
| `hindsight_retain` tool | Explicit memory storage (model-initiated) |
|
||||
| `hindsight_recall` tool | Explicit memory search (model-initiated) |
|
||||
| `hindsight_reflect` tool | LLM-synthesized answer from stored memories |
|
||||
|
||||
## Connection Modes
|
||||
|
||||
### 1. External API (recommended for production)
|
||||
|
||||
Connect to a running Hindsight server (cloud or self-hosted). No local LLM needed — the server handles fact extraction.
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "https://your-hindsight-server.com",
|
||||
"hindsightApiToken": "your-token",
|
||||
"bankId": "hermes"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Local Daemon
|
||||
|
||||
If you're running `hindsight-embed` locally, point to it:
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "http://localhost:9077",
|
||||
"bankId": "hermes"
|
||||
}
|
||||
```
|
||||
|
||||
Follow the [Quick Start](/developer/api/quickstart) guide to get the Hindsight API running.
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings are in `~/.hindsight/hermes.json`. Every setting can also be overridden via environment variables (env vars take priority).
|
||||
|
||||
### Connection & Daemon
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `hindsightApiUrl` | — | `HINDSIGHT_API_URL` | Hindsight API URL |
|
||||
| `hindsightApiToken` | `null` | `HINDSIGHT_API_TOKEN` / `HINDSIGHT_API_KEY` | Auth token for API |
|
||||
| `apiPort` | `9077` | `HINDSIGHT_API_PORT` | Port for local Hindsight daemon |
|
||||
| `daemonIdleTimeout` | `0` | `HINDSIGHT_DAEMON_IDLE_TIMEOUT` | Seconds before idle daemon shuts down (0 = never) |
|
||||
| `embedVersion` | `"latest"` | `HINDSIGHT_EMBED_VERSION` | `hindsight-embed` version for `uvx` |
|
||||
|
||||
### LLM Provider (daemon mode only)
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `llmProvider` | auto-detect | `HINDSIGHT_LLM_PROVIDER` | LLM provider: `openai`, `anthropic`, `gemini`, `groq`, `ollama` |
|
||||
| `llmModel` | provider default | `HINDSIGHT_LLM_MODEL` | Model override |
|
||||
|
||||
### Memory Bank
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `bankId` | — | `HINDSIGHT_BANK_ID` | Memory bank ID |
|
||||
| `bankMission` | `""` | `HINDSIGHT_BANK_MISSION` | Agent identity/purpose for the memory bank |
|
||||
| `retainMission` | `null` | — | Custom retain mission (what to extract from conversations) |
|
||||
| `bankIdPrefix` | `""` | — | Prefix for all bank IDs |
|
||||
|
||||
### Auto-Recall
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRecall` | `true` | `HINDSIGHT_AUTO_RECALL` | Enable automatic memory recall via `pre_llm_call` hook |
|
||||
| `recallBudget` | `"mid"` | `HINDSIGHT_RECALL_BUDGET` | Recall effort: `low`, `mid`, `high` |
|
||||
| `recallMaxTokens` | `4096` | `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens in recall response |
|
||||
| `recallMaxQueryChars` | `800` | `HINDSIGHT_RECALL_MAX_QUERY_CHARS` | Max chars of user message used as query |
|
||||
| `recallPromptPreamble` | see below | — | Header text injected before recalled memories |
|
||||
|
||||
Default preamble:
|
||||
> Relevant memories from past conversations (prioritize recent when conflicting). Only use memories that are directly useful to continue this conversation; ignore the rest:
|
||||
|
||||
### Auto-Retain
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRetain` | `true` | `HINDSIGHT_AUTO_RETAIN` | Enable automatic retention via `post_llm_call` hook |
|
||||
| `retainEveryNTurns` | `1` | — | Retain every Nth turn |
|
||||
| `retainOverlapTurns` | `2` | — | Extra overlap turns for continuity |
|
||||
| `retainRoles` | `["user", "assistant"]` | — | Which message roles to retain |
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `debug` | `false` | `HINDSIGHT_DEBUG` | Enable debug logging to stderr |
|
||||
|
||||
## Hermes Gateway (Telegram, Discord, Slack)
|
||||
|
||||
When using Hermes in gateway mode (multi-platform messaging), the plugin works across all platforms. Hermes creates a fresh `AIAgent` per message, and the plugin's `pre_llm_call` hook ensures relevant memories are recalled for each turn regardless of platform.
|
||||
|
||||
## Disabling Hermes's Built-in Memory
|
||||
|
||||
Hermes has a built-in `memory` tool that saves to local markdown files. If both are active, the LLM may prefer the built-in one. Disable it:
|
||||
|
||||
```bash
|
||||
hermes tools disable memory
|
||||
```
|
||||
|
||||
Re-enable later with `hermes tools enable memory`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Plugin not loading**: Verify the entry point is registered:
|
||||
```bash
|
||||
python -c "
|
||||
import importlib.metadata
|
||||
eps = importlib.metadata.entry_points(group='hermes_agent.plugins')
|
||||
print(list(eps))
|
||||
"
|
||||
```
|
||||
You should see `EntryPoint(name='hindsight', value='hindsight_hermes', ...)`.
|
||||
|
||||
**Tools don't appear in `/tools`**: Check that `hindsightApiUrl` (or `HINDSIGHT_API_URL`) is set. The plugin silently skips registration when unconfigured.
|
||||
|
||||
**Connection refused**: Verify the Hindsight API is running:
|
||||
```bash
|
||||
curl http://localhost:9077/health
|
||||
```
|
||||
|
||||
**Recall returning no memories**: Memories need at least one retain cycle. Try storing a fact first, then asking about it in a new session.
|
||||
@@ -1,319 +0,0 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
title: "LangGraph & LangChain Persistent Memory with Hindsight"
|
||||
description: "Add long-term memory to LangGraph and LangChain agents with Hindsight. Three integration patterns — tools, nodes, and BaseStore adapter — for persistent memory across agent runs."
|
||||
---
|
||||
|
||||
# LangGraph / LangChain
|
||||
|
||||
Persistent long-term memory for [LangGraph](https://langchain-ai.github.io/langgraph/) and [LangChain](https://python.langchain.com/) agents via Hindsight. Three integration patterns at different abstraction levels — the tools pattern works with both LangChain and LangGraph, while nodes and the BaseStore adapter are LangGraph-specific.
|
||||
|
||||
[View Changelog →](/changelog/integrations/langgraph)
|
||||
|
||||
## Features
|
||||
|
||||
- **Memory Tools** — retain, recall, and reflect as LangChain `@tool` functions compatible with `bind_tools()` and `ToolNode`. Works with **both LangChain and LangGraph** — no LangGraph dependency required for this pattern.
|
||||
- **Graph Nodes** *(LangGraph)* — Pre-built nodes that auto-inject memories before LLM calls and auto-store after responses
|
||||
- **BaseStore Adapter** *(LangGraph)* — Drop-in `BaseStore` implementation backed by Hindsight, for LangGraph's native memory patterns
|
||||
- **Dynamic Banks** — Resolve bank IDs per-request from `RunnableConfig` for per-user memory
|
||||
- **Async-Native** — Uses `aretain`, `arecall`, `areflect` directly — no thread-pool workarounds
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-langgraph
|
||||
```
|
||||
|
||||
## Quick Start: Tools (LangChain & LangGraph)
|
||||
|
||||
The tools pattern creates standard LangChain `@tool` functions that work with any LangChain-compatible model via `bind_tools()`. You can use them with a LangGraph agent or with plain LangChain — no LangGraph required.
|
||||
|
||||
**With LangGraph (recommended):**
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import create_hindsight_tools
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
tools = create_hindsight_tools(client=client, bank_id="user-123")
|
||||
|
||||
agent = create_react_agent(ChatOpenAI(model="gpt-4o"), tools=tools)
|
||||
|
||||
result = await agent.ainvoke(
|
||||
{"messages": [{"role": "user", "content": "Remember that I prefer dark mode"}]}
|
||||
)
|
||||
```
|
||||
|
||||
**With plain LangChain:**
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import create_hindsight_tools
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
tools = create_hindsight_tools(client=client, bank_id="user-123")
|
||||
|
||||
model = ChatOpenAI(model="gpt-4o").bind_tools(tools)
|
||||
response = await model.ainvoke("Remember that I prefer dark mode")
|
||||
```
|
||||
|
||||
When using plain LangChain, you handle the tool execution loop yourself — call the model, check for `tool_calls`, execute them, and feed results back. LangGraph automates this loop for you.
|
||||
|
||||
The agent gets three tools it can call:
|
||||
|
||||
- **`hindsight_retain`** — Store information to long-term memory
|
||||
- **`hindsight_recall`** — Search long-term memory for relevant facts
|
||||
- **`hindsight_reflect`** — Synthesize a reasoned answer from memories
|
||||
|
||||
## Quick Start: Memory Nodes (LangGraph)
|
||||
|
||||
Add recall and retain nodes to your graph for automatic memory injection and storage.
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import create_recall_node, create_retain_node
|
||||
from langgraph.graph import StateGraph, MessagesState, START, END
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
recall = create_recall_node(client=client, bank_id="user-123")
|
||||
retain = create_retain_node(client=client, bank_id="user-123")
|
||||
|
||||
builder = StateGraph(MessagesState)
|
||||
builder.add_node("recall", recall)
|
||||
builder.add_node("agent", agent_node) # your LLM node
|
||||
builder.add_node("retain", retain)
|
||||
|
||||
builder.add_edge(START, "recall")
|
||||
builder.add_edge("recall", "agent")
|
||||
builder.add_edge("agent", "retain")
|
||||
builder.add_edge("retain", END)
|
||||
|
||||
graph = builder.compile()
|
||||
```
|
||||
|
||||
The recall node extracts the latest user message, searches Hindsight, and injects matching memories as a `SystemMessage`. The retain node stores human messages (optionally AI messages too) after the response.
|
||||
|
||||
## Quick Start: BaseStore (LangGraph)
|
||||
|
||||
Use Hindsight as a LangGraph `BaseStore` for cross-thread persistent memory with semantic search.
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import HindsightStore
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
store = HindsightStore(client=client)
|
||||
|
||||
graph = builder.compile(checkpointer=checkpointer, store=store)
|
||||
|
||||
# Store and search via the store API
|
||||
await store.aput(("user", "123", "prefs"), "theme", {"value": "dark mode"})
|
||||
results = await store.asearch(("user", "123", "prefs"), query="theme preference")
|
||||
```
|
||||
|
||||
Namespace tuples are mapped to Hindsight bank IDs with `.` as separator (e.g., `("user", "123")` becomes bank `user.123`). Banks are auto-created on first access.
|
||||
|
||||
## Dynamic Bank IDs
|
||||
|
||||
Both nodes and the store support per-user bank resolution from `RunnableConfig`:
|
||||
|
||||
```python
|
||||
recall = create_recall_node(client=client, bank_id_from_config="user_id")
|
||||
retain = create_retain_node(client=client, bank_id_from_config="user_id")
|
||||
|
||||
# Bank ID resolved at runtime from config
|
||||
result = await graph.ainvoke(
|
||||
{"messages": [{"role": "user", "content": "hello"}]},
|
||||
config={"configurable": {"user_id": "user-456"}},
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=True,
|
||||
include_recall=True,
|
||||
include_reflect=False, # Omit reflect
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing a client to every call, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_langgraph import configure, create_hindsight_tools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create tools without passing client — uses global config
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
## Retain Node Options
|
||||
|
||||
```python
|
||||
retain = create_retain_node(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
retain_human=True, # Store human messages (default: True)
|
||||
retain_ai=False, # Store AI responses (default: False)
|
||||
tags=["source:chat"], # Tags applied to stored memories
|
||||
)
|
||||
```
|
||||
|
||||
## Recall Node Options
|
||||
|
||||
```python
|
||||
recall = create_recall_node(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
budget="low", # Recall budget: low/mid/high
|
||||
max_results=10, # Max memories injected
|
||||
max_tokens=4096, # Max tokens for recall
|
||||
tags=["scope:user"], # Filter by tags
|
||||
tags_match="all", # Tag match mode
|
||||
)
|
||||
```
|
||||
|
||||
### Using `output_key` for Prompt Control
|
||||
|
||||
By default, the recall node appends a `SystemMessage` to `messages`. Use `output_key` to write memory text to a custom state field instead, giving you full control over prompt ordering:
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
from langgraph.graph import MessagesState
|
||||
|
||||
class AgentState(MessagesState):
|
||||
memory_context: Optional[str] = None
|
||||
|
||||
recall = create_recall_node(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
output_key="memory_context",
|
||||
)
|
||||
|
||||
# In your agent node, read state["memory_context"] and prepend it
|
||||
# to the system prompt before calling the model.
|
||||
```
|
||||
|
||||
## Limitations and Notes
|
||||
|
||||
### HindsightStore
|
||||
|
||||
- **Async-only.** All sync methods (`batch`, `get`, `put`, `delete`, `search`, `list_namespaces`) raise `NotImplementedError`. Use the async variants (`abatch`, `aget`, `aput`, `adelete`, `asearch`, `alist_namespaces`) instead.
|
||||
- **`get()` relies on recall.** There is no direct key lookup — the key is used as a recall query and only exact `document_id` matches are returned. Items that do not rank in the top recall results may appear missing.
|
||||
- **`list_namespaces` is session-scoped.** It only tracks namespaces that have been written to via `aput()` during the current process. After a restart, `list_namespaces` returns empty even though data still exists in Hindsight.
|
||||
- **`delete` is a no-op.** Calling `adelete()` logs a debug message but does not remove data from Hindsight. Hindsight's memory model is append-oriented; fact superseding is handled automatically during retain.
|
||||
|
||||
### Memory Nodes
|
||||
|
||||
- **SystemMessage ordering.** The recall node adds a `SystemMessage` with recalled memories. Because `MessagesState` uses `add_messages` (which appends), this message appears after existing messages rather than at position 0. The message has a stable ID (`hindsight_memory_context`) so it is updated rather than duplicated across invocations. If your LLM provider requires system messages first, sort or filter messages in your agent node before passing them to the model.
|
||||
|
||||
### Error Handling
|
||||
|
||||
- **Tools** raise `HindsightError` on failure, which surfaces to the agent as a tool error.
|
||||
- **Nodes** silently log errors and return empty messages, so a Hindsight outage does not crash your graph.
|
||||
|
||||
## API Reference
|
||||
|
||||
### `create_hindsight_tools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode (any/all/any\_strict/all\_strict) |
|
||||
| `retain_metadata` | `None` | Default metadata dict for retain operations |
|
||||
| `retain_document_id` | `None` | Default document\_id for retain (groups/upserts memories) |
|
||||
| `recall_types` | `None` | Fact types to filter (world, experience, opinion, observation) |
|
||||
| `recall_include_entities` | `False` | Include entity information in recall results |
|
||||
| `reflect_context` | `None` | Additional context for reflect operations |
|
||||
| `reflect_max_tokens` | `None` | Max tokens for reflect results (defaults to `max_tokens`) |
|
||||
| `reflect_response_schema` | `None` | JSON schema to constrain reflect output format |
|
||||
| `reflect_tags` | `None` | Tags to filter memories used in reflect (defaults to `recall_tags`) |
|
||||
| `reflect_tags_match` | `None` | Tag matching for reflect (defaults to `recall_tags_match`) |
|
||||
| `include_retain` | `True` | Include the retain (store) tool |
|
||||
| `include_recall` | `True` | Include the recall (search) tool |
|
||||
| `include_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `create_recall_node()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | `None` | Static bank ID (or use `bank_id_from_config`) |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall budget level |
|
||||
| `max_tokens` | `4096` | Max tokens for recall results |
|
||||
| `max_results` | `10` | Max memories to inject |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
| `bank_id_from_config` | `"user_id"` | Config key to resolve bank ID at runtime |
|
||||
| `output_key` | `None` | If set, write memory text to this state key instead of appending a SystemMessage to `messages` |
|
||||
|
||||
### `create_retain_node()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | `None` | Static bank ID (or use `bank_id_from_config`) |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `tags` | `None` | Tags applied to stored memories |
|
||||
| `bank_id_from_config` | `"user_id"` | Config key to resolve bank ID at runtime |
|
||||
| `retain_human` | `True` | Store human messages |
|
||||
| `retain_ai` | `False` | Store AI responses |
|
||||
|
||||
### `HindsightStore()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `tags` | `None` | Tags applied to all retain operations |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- langchain-core >= 0.3.0
|
||||
- hindsight-client >= 0.4.0
|
||||
- langgraph >= 0.3.0 *(only for nodes and store patterns — install with `pip install hindsight-langgraph[langgraph]`)*
|
||||
@@ -1,349 +0,0 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
title: "LiteLLM Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to any LLM application via LiteLLM and Hindsight. Universal integration — works with any model or provider with just a few lines of code."
|
||||
---
|
||||
|
||||
# LiteLLM
|
||||
|
||||
Universal LLM memory integration via [LiteLLM](https://github.com/BerriAI/litellm). Add persistent memory to any LLM application with just a few lines of code.
|
||||
|
||||
[View Changelog →](/changelog/integrations/litellm)
|
||||
|
||||
## Features
|
||||
|
||||
- **Universal LLM Support** - Works with 100+ LLM providers via LiteLLM (OpenAI, Anthropic, Groq, Azure, AWS Bedrock, Google Vertex AI, and more)
|
||||
- **Simple Integration** - Just configure, enable, and use `hindsight_litellm.completion()`
|
||||
- **Automatic Memory Injection** - Relevant memories are injected into prompts before LLM calls
|
||||
- **Automatic Conversation Storage** - Conversations are stored to Hindsight for future recall
|
||||
- **Two Memory Modes** - Choose between `reflect` (synthesized context) or `recall` (raw memory retrieval)
|
||||
- **Direct Memory APIs** - Query, synthesize, and store memories manually
|
||||
- **Native Client Wrappers** - Alternative wrappers for OpenAI and Anthropic SDKs
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-litellm
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
import hindsight_litellm
|
||||
|
||||
# Configure and enable memory integration
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="my-agent",
|
||||
)
|
||||
hindsight_litellm.enable()
|
||||
|
||||
# Use the convenience wrapper - memory is automatically injected and stored
|
||||
response = hindsight_litellm.completion(
|
||||
model="gpt-4o-mini",
|
||||
messages=[{"role": "user", "content": "What did we discuss about AI?"}]
|
||||
)
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
When you call `completion()`, the following happens automatically:
|
||||
|
||||
1. **Memory Retrieval** - Hindsight is queried for relevant memories based on the conversation
|
||||
2. **Prompt Injection** - Memories are injected into the system message
|
||||
3. **LLM Call** - The enriched prompt is sent to the LLM
|
||||
4. **Conversation Storage** - The conversation is stored to Hindsight for future recall
|
||||
5. **Response Returned** - You receive the response as normal
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```python
|
||||
hindsight_litellm.configure(
|
||||
# Required
|
||||
hindsight_api_url="http://localhost:8888", # Hindsight API server URL
|
||||
bank_id="my-agent", # Memory bank ID
|
||||
|
||||
api_key="your-api-key", # Optional API key for authentication
|
||||
|
||||
# Optional - Memory behavior
|
||||
store_conversations=True, # Store conversations after LLM calls
|
||||
inject_memories=True, # Inject relevant memories into prompts
|
||||
use_reflect=False, # Use reflect API (synthesized) vs recall (raw memories)
|
||||
reflect_include_facts=False, # Include source facts with reflect responses
|
||||
max_memories=None, # Maximum memories to inject (None = unlimited)
|
||||
max_memory_tokens=4096, # Maximum tokens for memory context
|
||||
recall_budget="mid", # Recall budget: "low", "mid", "high"
|
||||
fact_types=["world", "agent"], # Filter fact types to inject
|
||||
|
||||
# Optional - Bank Configuration
|
||||
bank_name="My Agent", # Human-readable display name for the memory bank
|
||||
mission="This agent...", # Instructions guiding what Hindsight should remember
|
||||
|
||||
# Optional - Advanced
|
||||
injection_mode="system_message", # or "prepend_user"
|
||||
excluded_models=["gpt-3.5*"], # Exclude certain models
|
||||
verbose=True, # Enable verbose logging and debug info
|
||||
)
|
||||
```
|
||||
|
||||
### Bank Configuration
|
||||
|
||||
The `mission` and `bank_name` parameters configure the memory bank itself. When provided, `configure()` will automatically create or update the bank with these settings.
|
||||
|
||||
```python
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="support-router",
|
||||
bank_name="Customer Support Router",
|
||||
mission="""You're a customer support router - keep track of which types of issues
|
||||
should go to which teams (billing, technical, sales), customer preferences for
|
||||
communication channels, and past issue resolutions.""",
|
||||
)
|
||||
```
|
||||
|
||||
### Memory Modes: Reflect vs Recall
|
||||
|
||||
- **Recall mode** (`use_reflect=False`, default): Retrieves raw memory facts and injects them as a numbered list. Best when you need precise, individual memories.
|
||||
- **Reflect mode** (`use_reflect=True`): Synthesizes memories into a coherent context paragraph. Best for natural, conversational memory context.
|
||||
|
||||
```python
|
||||
# Recall mode - raw memories
|
||||
hindsight_litellm.configure(
|
||||
bank_id="my-agent",
|
||||
use_reflect=False, # Default
|
||||
)
|
||||
# Injects: "1. [WORLD] User prefers Python\n2. [MENTAL MODEL] User prefers simple code..."
|
||||
|
||||
# Reflect mode - synthesized context
|
||||
hindsight_litellm.configure(
|
||||
bank_id="my-agent",
|
||||
use_reflect=True,
|
||||
)
|
||||
# Injects: "Based on previous conversations, the user is a Python developer who..."
|
||||
```
|
||||
|
||||
## Multi-Provider Support
|
||||
|
||||
Works with any LiteLLM-supported provider:
|
||||
|
||||
```python
|
||||
import hindsight_litellm
|
||||
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="my-agent",
|
||||
)
|
||||
hindsight_litellm.enable()
|
||||
|
||||
# OpenAI
|
||||
hindsight_litellm.completion(model="gpt-4o", messages=[...])
|
||||
|
||||
# Anthropic
|
||||
hindsight_litellm.completion(model="claude-3-5-sonnet-20241022", messages=[...])
|
||||
|
||||
# Groq
|
||||
hindsight_litellm.completion(model="groq/llama-3.1-70b-versatile", messages=[...])
|
||||
|
||||
# Azure OpenAI
|
||||
hindsight_litellm.completion(model="azure/gpt-4", messages=[...])
|
||||
|
||||
# AWS Bedrock
|
||||
hindsight_litellm.completion(model="bedrock/anthropic.claude-3", messages=[...])
|
||||
|
||||
# Google Vertex AI
|
||||
hindsight_litellm.completion(model="vertex_ai/gemini-pro", messages=[...])
|
||||
```
|
||||
|
||||
## Direct Memory APIs
|
||||
|
||||
### Recall - Query raw memories
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, recall
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
memories = recall("what projects am I working on?", budget="mid")
|
||||
for m in memories:
|
||||
print(f"- [{m.fact_type}] {m.text}")
|
||||
```
|
||||
|
||||
### Reflect - Get synthesized context
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, reflect
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
result = reflect("what do you know about the user's preferences?")
|
||||
print(result.text)
|
||||
```
|
||||
|
||||
### Retain - Store memories
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, retain
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
result = retain(
|
||||
content="User mentioned they're working on a machine learning project",
|
||||
context="Discussion about current projects",
|
||||
)
|
||||
```
|
||||
|
||||
### Async APIs
|
||||
|
||||
```python
|
||||
from hindsight_litellm import arecall, areflect, aretain
|
||||
|
||||
# Async versions of all memory APIs
|
||||
memories = await arecall("what do you know about me?")
|
||||
context = await areflect("summarize user preferences")
|
||||
result = await aretain(content="New information to remember")
|
||||
```
|
||||
|
||||
## Native Client Wrappers
|
||||
|
||||
Alternative to LiteLLM callbacks for direct SDK integration.
|
||||
|
||||
### OpenAI Wrapper
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
from hindsight_litellm import wrap_openai
|
||||
|
||||
client = OpenAI()
|
||||
wrapped = wrap_openai(
|
||||
client,
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
response = wrapped.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[{"role": "user", "content": "What do you know about me?"}]
|
||||
)
|
||||
```
|
||||
|
||||
### Anthropic Wrapper
|
||||
|
||||
```python
|
||||
from anthropic import Anthropic
|
||||
from hindsight_litellm import wrap_anthropic
|
||||
|
||||
client = Anthropic()
|
||||
wrapped = wrap_anthropic(
|
||||
client,
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
response = wrapped.messages.create(
|
||||
model="claude-3-5-sonnet-20241022",
|
||||
max_tokens=1024,
|
||||
messages=[{"role": "user", "content": "Hello!"}]
|
||||
)
|
||||
```
|
||||
|
||||
## Debug Mode
|
||||
|
||||
When `verbose=True`, you can inspect exactly what memories are being injected:
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, enable, completion, get_last_injection_debug
|
||||
|
||||
configure(
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
verbose=True,
|
||||
)
|
||||
enable()
|
||||
|
||||
response = completion(
|
||||
model="gpt-4o-mini",
|
||||
messages=[{"role": "user", "content": "What's my favorite color?"}]
|
||||
)
|
||||
|
||||
# Inspect what was injected
|
||||
debug = get_last_injection_debug()
|
||||
if debug:
|
||||
print(f"Mode: {debug.mode}") # "reflect" or "recall"
|
||||
print(f"Injected: {debug.injected}") # True/False
|
||||
print(f"Results: {debug.results_count}")
|
||||
print(f"Memory context:\n{debug.memory_context}")
|
||||
```
|
||||
|
||||
## Context Manager
|
||||
|
||||
```python
|
||||
from hindsight_litellm import hindsight_memory
|
||||
import litellm
|
||||
|
||||
with hindsight_memory(bank_id="user-123"):
|
||||
response = litellm.completion(model="gpt-4", messages=[...])
|
||||
# Memory integration automatically disabled after context
|
||||
```
|
||||
|
||||
## Disabling and Cleanup
|
||||
|
||||
```python
|
||||
from hindsight_litellm import disable, cleanup
|
||||
|
||||
# Temporarily disable memory integration
|
||||
disable()
|
||||
|
||||
# Clean up all resources (call when shutting down)
|
||||
cleanup()
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Main Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `configure(...)` | Configure global Hindsight settings |
|
||||
| `enable()` | Enable memory integration with LiteLLM |
|
||||
| `disable()` | Disable memory integration |
|
||||
| `is_enabled()` | Check if memory integration is enabled |
|
||||
| `cleanup()` | Clean up all resources |
|
||||
|
||||
### Configuration Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get_config()` | Get current configuration |
|
||||
| `is_configured()` | Check if Hindsight is configured |
|
||||
| `reset_config()` | Reset configuration to defaults |
|
||||
|
||||
### Memory Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `recall(query, ...)` | Synchronously query raw memories |
|
||||
| `arecall(query, ...)` | Asynchronously query raw memories |
|
||||
| `reflect(query, ...)` | Synchronously get synthesized memory context |
|
||||
| `areflect(query, ...)` | Asynchronously get synthesized memory context |
|
||||
| `retain(content, ...)` | Synchronously store a memory |
|
||||
| `aretain(content, ...)` | Asynchronously store a memory |
|
||||
|
||||
### Debug Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get_last_injection_debug()` | Get debug info from last memory injection |
|
||||
| `clear_injection_debug()` | Clear stored debug info |
|
||||
|
||||
### Client Wrappers
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `wrap_openai(client, ...)` | Wrap OpenAI client with memory |
|
||||
| `wrap_anthropic(client, ...)` | Wrap Anthropic client with memory |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- litellm >= 1.40.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,251 +0,0 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
title: "LlamaIndex Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to LlamaIndex agents with Hindsight. Supports agent-driven tools (HindsightToolSpec) and automatic memory via the BaseMemory interface."
|
||||
---
|
||||
|
||||
# LlamaIndex
|
||||
|
||||
Persistent long-term memory for [LlamaIndex](https://docs.llamaindex.ai/) agents via Hindsight. The `hindsight-llamaindex` package provides two complementary patterns:
|
||||
|
||||
- **`HindsightToolSpec`** — Agent-driven memory tools (retain/recall/reflect)
|
||||
- **`HindsightMemory`** — Automatic memory via LlamaIndex's `BaseMemory` interface
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-llamaindex
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Automatic Memory (BaseMemory)
|
||||
|
||||
The simplest way to add Hindsight memory to a LlamaIndex agent. Messages are automatically stored on each turn, and relevant memories are recalled and injected as context.
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_llamaindex import HindsightMemory
|
||||
from llama_index.core.agent import ReActAgent
|
||||
from llama_index.llms.openai import OpenAI
|
||||
|
||||
async def main():
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
memory = HindsightMemory.from_client(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user preferences and project context",
|
||||
)
|
||||
|
||||
agent = ReActAgent(tools=[], llm=OpenAI(model="gpt-4o"))
|
||||
response = await agent.run("Remember that I prefer dark mode", memory=memory)
|
||||
print(response)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
| Event | What Happens |
|
||||
|-------|-------------|
|
||||
| Agent receives input | `aget(input)` recalls relevant memories from Hindsight, prepends as system message |
|
||||
| Agent produces output | `aput(message)` retains the message to Hindsight for future recall |
|
||||
| New session starts | Previous memories are available via recall; local chat buffer starts empty |
|
||||
|
||||
### `HindsightMemory.from_client()`
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `client` | `Hindsight` | *required* | Hindsight client instance |
|
||||
| `bank_id` | `str` | *required* | Memory bank ID |
|
||||
| `mission` | `str` | `None` | Bank mission — auto-creates bank on first use |
|
||||
| `context` | `str` | `"llamaindex"` | Source label for retain operations |
|
||||
| `budget` | `str` | `"mid"` | Recall budget level |
|
||||
| `max_tokens` | `int` | `4096` | Max recall tokens |
|
||||
| `tags` | `list[str]` | `None` | Tags for retain operations |
|
||||
| `recall_tags` | `list[str]` | `None` | Tags to filter recall |
|
||||
| `recall_tags_match` | `str` | `"any"` | Tag matching mode |
|
||||
| `system_prompt` | `str` | *(built-in)* | Template for memory system message. Must contain `{memories}` |
|
||||
| `chat_history_limit` | `int` | `100` | Max messages in local buffer |
|
||||
|
||||
Also available: `HindsightMemory.from_url(hindsight_api_url, bank_id, ...)` for creating without a pre-built client.
|
||||
|
||||
---
|
||||
|
||||
## Agent-Driven Tools (BaseToolSpec)
|
||||
|
||||
For explicit control, expose retain/recall/reflect as tools the agent can choose to call.
|
||||
|
||||
### Quick Start: Tool Spec
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_llamaindex import HindsightToolSpec
|
||||
from llama_index.llms.openai import OpenAI
|
||||
from llama_index.core.agent import ReActAgent
|
||||
|
||||
async def main():
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
spec = HindsightToolSpec(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user preferences",
|
||||
)
|
||||
tools = spec.to_tool_list()
|
||||
|
||||
agent = ReActAgent(tools=tools, llm=OpenAI(model="gpt-4o"))
|
||||
response = await agent.run("Remember that I prefer dark mode")
|
||||
print(response)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### Quick Start: Factory Function
|
||||
|
||||
```python
|
||||
from hindsight_llamaindex import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user preferences",
|
||||
)
|
||||
```
|
||||
|
||||
### Selecting Tools
|
||||
|
||||
```python
|
||||
# Via to_tool_list()
|
||||
tools = spec.to_tool_list(spec_functions=["recall_memory", "reflect_on_memory"])
|
||||
|
||||
# Via factory flags
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=True,
|
||||
include_recall=True,
|
||||
include_reflect=False,
|
||||
)
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Set defaults via `configure()`, override per-call:
|
||||
|
||||
```python
|
||||
from hindsight_llamaindex import configure
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # or set HINDSIGHT_API_KEY env var
|
||||
budget="mid",
|
||||
tags=["source:llamaindex"],
|
||||
context="my-app",
|
||||
mission="Track user preferences",
|
||||
)
|
||||
|
||||
# Now create tools without passing client/url
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
### `HindsightToolSpec()`
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `bank_id` | `str` | *required* | Hindsight memory bank to operate on |
|
||||
| `client` | `Hindsight` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `str` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `str` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `str` | `None` → `"mid"` | Recall/reflect budget: `low`, `mid`, `high` |
|
||||
| `max_tokens` | `int` | `None` → `4096` | Max tokens for recall results |
|
||||
| `tags` | `list[str]` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `list[str]` | `None` | Tags to filter recall results |
|
||||
| `recall_tags_match` | `str` | `None` → `"any"` | Tag matching: `any`, `all`, `any_strict`, `all_strict` |
|
||||
| `retain_metadata` | `dict[str, str]` | `None` | Default metadata for retain operations |
|
||||
| `retain_document_id` | `str` | `None` | Document ID for retain. Auto-generates `{session}-{timestamp}` if not set |
|
||||
| `retain_context` | `str` | `"llamaindex"` | Source label for retain operations |
|
||||
| `recall_types` | `list[str]` | `None` | Fact types: `world`, `experience`, `opinion`, `observation` |
|
||||
| `recall_include_entities` | `bool` | `False` | Include entity info in recall results |
|
||||
| `reflect_context` | `str` | `None` | Additional context for reflect |
|
||||
| `reflect_max_tokens` | `int` | `None` | Max tokens for reflect (defaults to `max_tokens`) |
|
||||
| `reflect_response_schema` | `dict` | `None` | JSON schema to constrain reflect output |
|
||||
| `reflect_tags` | `list[str]` | `None` | Tags for reflect (defaults to `recall_tags`) |
|
||||
| `reflect_tags_match` | `str` | `None` | Tag matching for reflect (defaults to `recall_tags_match`) |
|
||||
| `mission` | `str` | `None` | Bank mission — auto-creates bank on first use |
|
||||
|
||||
---
|
||||
|
||||
## Production Patterns
|
||||
|
||||
### Bank Mission
|
||||
|
||||
Set a mission to give the memory engine context for fact extraction:
|
||||
|
||||
```python
|
||||
# Tools
|
||||
spec = HindsightToolSpec(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user coding preferences, project context, and technical decisions",
|
||||
)
|
||||
|
||||
# Memory
|
||||
memory = HindsightMemory.from_client(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user coding preferences, project context, and technical decisions",
|
||||
)
|
||||
```
|
||||
|
||||
The bank is created automatically on first use. If it already exists, creation is silently skipped.
|
||||
|
||||
### Memory Scoping with Tags
|
||||
|
||||
```python
|
||||
spec = HindsightToolSpec(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
tags=["source:chat", "session:abc"], # applied to all retains
|
||||
recall_tags=["source:chat"], # filter recalls to chat memories
|
||||
recall_tags_match="any",
|
||||
)
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
Both patterns handle errors gracefully — operations are logged and return friendly messages instead of raising exceptions. Agents continue functioning even if memory is unavailable.
|
||||
|
||||
### Combining Tools + Memory
|
||||
|
||||
Use both patterns together for maximum flexibility:
|
||||
|
||||
```python
|
||||
from hindsight_llamaindex import create_hindsight_tools, HindsightMemory
|
||||
|
||||
# Automatic memory for context enrichment
|
||||
memory = HindsightMemory.from_client(client=client, bank_id="user-123")
|
||||
|
||||
# Explicit tools for agent-driven reflect
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=False, # memory handles retain automatically
|
||||
include_recall=False, # memory handles recall automatically
|
||||
include_reflect=True, # agent can still explicitly reflect
|
||||
)
|
||||
|
||||
agent = ReActAgent(tools=tools, llm=llm)
|
||||
|
||||
# Pass memory to run()
|
||||
response = await agent.run("What should I prioritize?", memory=memory)
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.10+
|
||||
- `llama-index-core >= 0.11.0`
|
||||
- `hindsight-client >= 0.4.0`
|
||||
@@ -1,176 +0,0 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
title: "Hindsight Local MCP Server | Persistent Memory for Claude"
|
||||
description: "Run Hindsight as a local MCP server with embedded PostgreSQL — no external setup required. Ideal for Claude Code and Claude Desktop for long-term memory across conversations."
|
||||
---
|
||||
|
||||
# Local MCP Server
|
||||
|
||||
Hindsight provides a local MCP server that runs entirely on your machine with an embedded PostgreSQL database. No external server or database setup required.
|
||||
|
||||
This is ideal for:
|
||||
- **Personal use with Claude Code / Claude Desktop** — Give Claude long-term memory across conversations
|
||||
- **Development and testing** — Quick setup without infrastructure
|
||||
- **Privacy-focused setups** — All data stays on your machine
|
||||
|
||||
## How It Works
|
||||
|
||||
Running `hindsight-local-mcp` starts the full Hindsight API on `localhost:8888` with an embedded PostgreSQL database (pg0). You then connect your MCP client to it over HTTP.
|
||||
|
||||
- Starts an embedded PostgreSQL (pg0) automatically
|
||||
- Runs database migrations on startup
|
||||
- Exposes the full MCP endpoint at `http://localhost:8888/mcp/`
|
||||
- Data persists in `~/.pg0/hindsight-mcp/` across restarts
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Start the server
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_API_KEY=sk-... uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
|
||||
Or with Ollama (no API key needed):
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_PROVIDER=ollama HINDSIGHT_API_LLM_MODEL=llama3.2 uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
|
||||
### 2. Configure your MCP client
|
||||
|
||||
**Claude Code:**
|
||||
|
||||
```bash
|
||||
claude mcp add --transport http hindsight http://localhost:8888/mcp/
|
||||
```
|
||||
|
||||
**Other MCP clients** — add an HTTP transport entry pointing to `http://localhost:8888/mcp/`.
|
||||
|
||||
## Bank Modes
|
||||
|
||||
The local server supports the same two modes as the hosted API:
|
||||
|
||||
### Multi-bank mode (default)
|
||||
|
||||
Use `http://localhost:8888/mcp/` — exposes all tools including bank management. Bank is selected per-request via the `bank_id` tool parameter or the `X-Bank-Id` header.
|
||||
|
||||
```bash
|
||||
claude mcp add --transport http hindsight http://localhost:8888/mcp/
|
||||
```
|
||||
|
||||
### Single-bank mode
|
||||
|
||||
Use `http://localhost:8888/mcp/<bank-id>/` — pins all tools to one bank, no `bank_id` parameter needed. This replaces the old `HINDSIGHT_API_MCP_LOCAL_BANK_ID` env var.
|
||||
|
||||
```bash
|
||||
claude mcp add --transport http hindsight http://localhost:8888/mcp/my-bank/
|
||||
```
|
||||
|
||||
## Available Tools
|
||||
|
||||
The local server exposes the full tool set (29 tools in multi-bank mode, 26 in single-bank mode):
|
||||
|
||||
**Core Memory**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `retain` | Store information to long-term memory with optional tags, metadata, and document association |
|
||||
| `recall` | Search memories with natural language, configurable budget, type filters, and tag filters |
|
||||
| `reflect` | Synthesize memories into a reasoned answer with optional structured output |
|
||||
|
||||
**Mental Models**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_mental_models` | List pinned reflections for a bank |
|
||||
| `get_mental_model` | Get a specific mental model |
|
||||
| `create_mental_model` | Create a new mental model with optional auto-refresh trigger |
|
||||
| `update_mental_model` | Update a mental model's metadata |
|
||||
| `delete_mental_model` | Delete a mental model |
|
||||
| `refresh_mental_model` | Regenerate a mental model's content |
|
||||
|
||||
**Directives**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_directives` | List directives that guide memory processing |
|
||||
| `create_directive` | Create a new directive |
|
||||
| `delete_directive` | Delete a directive |
|
||||
|
||||
**Memory Browsing**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_memories` | Browse memories with filtering and pagination |
|
||||
| `get_memory` | Get a specific memory by ID |
|
||||
| `delete_memory` | Delete a specific memory |
|
||||
|
||||
**Documents**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_documents` | List ingested documents |
|
||||
| `get_document` | Get a specific document |
|
||||
| `delete_document` | Delete a document and its linked memories |
|
||||
|
||||
**Operations**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_operations` | List async operations with status filtering |
|
||||
| `get_operation` | Check operation status and progress |
|
||||
| `cancel_operation` | Cancel a pending or running operation |
|
||||
|
||||
**Tags & Bank Management**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_tags` | List unique tags used in a bank |
|
||||
| `get_bank` | Get bank profile (name, mission, disposition) |
|
||||
| `get_bank_stats` | Get bank statistics (multi-bank only) |
|
||||
| `update_bank` | Update bank name or mission |
|
||||
| `delete_bank` | Delete an entire bank and all its data |
|
||||
| `clear_memories` | Clear memories without deleting the bank |
|
||||
| `list_banks` | List all memory banks (multi-bank only) |
|
||||
| `create_bank` | Create or configure a memory bank (multi-bank only) |
|
||||
|
||||
For detailed parameter documentation, see the [MCP Server reference](/developer/mcp-server#available-tools).
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All standard [Hindsight configuration variables](/developer/configuration) are supported. Key ones for local use:
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `HINDSIGHT_API_LLM_API_KEY` | Yes* | — | API key for your LLM provider |
|
||||
| `HINDSIGHT_API_LLM_PROVIDER` | No | `openai` | LLM provider (`openai`, `anthropic`, `ollama`, etc.) |
|
||||
| `HINDSIGHT_API_LLM_MODEL` | No | `gpt-4o-mini` | Model name |
|
||||
| `HINDSIGHT_API_DATABASE_URL` | No | `pg0://hindsight-mcp` | Override the database URL |
|
||||
| `HINDSIGHT_API_PORT` | No | `8888` | Port to listen on |
|
||||
| `HINDSIGHT_API_LOG_LEVEL` | No | `info` | Log level |
|
||||
|
||||
*Not required when using a local provider like Ollama.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Slow first startup
|
||||
|
||||
The first startup downloads the local embedding model (~100MB) and initializes the database. Subsequent starts are faster.
|
||||
|
||||
### Port already in use
|
||||
|
||||
Set a different port:
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_API_KEY=sk-... HINDSIGHT_API_PORT=9000 uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
|
||||
Then update your MCP client URL to `http://localhost:9000/mcp/`.
|
||||
|
||||
### Checking logs
|
||||
|
||||
Set `HINDSIGHT_API_LOG_LEVEL=debug` for verbose output:
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_API_KEY=sk-... HINDSIGHT_API_LOG_LEVEL=debug uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
@@ -1,250 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "NemoClaw Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to NemoClaw sandboxed agents with Hindsight. One command adds automated memory extraction and auto-recall to any NemoClaw sandbox — no code changes required."
|
||||
---
|
||||
|
||||
# NemoClaw
|
||||
|
||||
Persistent memory for [NemoClaw](https://nemoclaw.ai) sandboxed agents using [Hindsight](https://hindsight.vectorize.io).
|
||||
|
||||
NemoClaw runs [OpenClaw](https://openclaw.ai) inside an OpenShell sandbox with controlled filesystem, process, and network egress policies. The `hindsight-nemoclaw` package automates adding Hindsight memory to a sandbox in one command — no code changes required.
|
||||
|
||||
[View Changelog →](/changelog/integrations/nemoclaw)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
npx @vectorize-io/hindsight-nemoclaw setup \
|
||||
--sandbox my-assistant \
|
||||
--api-url https://api.hindsight.vectorize.io \
|
||||
--api-token <your-api-key> \
|
||||
--bank-prefix my-sandbox
|
||||
```
|
||||
|
||||
Get an API key at [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup).
|
||||
|
||||
You'll see output like:
|
||||
|
||||
```
|
||||
[0] Preflight checks...
|
||||
✓ openshell found
|
||||
✓ openclaw found
|
||||
|
||||
[1] Installing @vectorize-io/hindsight-openclaw plugin...
|
||||
✓ Plugin installed
|
||||
|
||||
[2] Configuring plugin in ~/.openclaw/openclaw.json...
|
||||
✓ Plugin config written (bank: my-sandbox-openclaw)
|
||||
|
||||
[3] Applying Hindsight network policy to sandbox "my-assistant"...
|
||||
✓ Policy version 2 submitted
|
||||
✓ Policy version 2 loaded (active version: 2)
|
||||
|
||||
[4] Restarting OpenClaw gateway...
|
||||
✓ Gateway restarted
|
||||
|
||||
✓ Setup complete!
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### The sandbox problem
|
||||
|
||||
OpenShell enforces strict network egress — every outbound endpoint must be explicitly permitted in the sandbox policy. By default, the Hindsight API (`api.hindsight.vectorize.io`) is not in that list.
|
||||
|
||||
The `hindsight-openclaw` plugin supports **external API mode**, where it skips the local daemon entirely and makes direct HTTPS calls to Hindsight Cloud. This is the natural fit for sandboxed environments: the plugin becomes a thin HTTP client, and the only sandbox change needed is one egress rule.
|
||||
|
||||
### What the setup command does
|
||||
|
||||
1. **Preflight** — verifies `openshell` and `openclaw` are installed
|
||||
2. **Install plugin** — runs `openclaw plugins install @vectorize-io/hindsight-openclaw`
|
||||
3. **Configure plugin** — writes external API mode config to `~/.openclaw/openclaw.json`
|
||||
4. **Apply policy** — reads the current sandbox policy, merges the Hindsight egress block, and re-applies via `openshell policy set`
|
||||
5. **Restart gateway** — runs `openclaw gateway restart`
|
||||
|
||||
### Memory flow
|
||||
|
||||
Once set up, the `hindsight-openclaw` plugin hooks into the OpenClaw gateway lifecycle:
|
||||
|
||||
- **`before_agent_start`** — recalls relevant memories from past sessions and injects them into context
|
||||
- **`agent_end`** — retains the conversation to the Hindsight memory bank
|
||||
|
||||
The sandbox doesn't interfere with either step — it sees the Hindsight calls as normal HTTPS egress to a permitted endpoint.
|
||||
|
||||
## CLI Reference
|
||||
|
||||
```
|
||||
hindsight-nemoclaw setup [options]
|
||||
|
||||
Options:
|
||||
--sandbox <name> NemoClaw sandbox name (required)
|
||||
--api-url <url> Hindsight API URL (required)
|
||||
--api-token <token> Hindsight API token (required)
|
||||
--bank-prefix <prefix> Memory bank prefix (default: "nemoclaw")
|
||||
--skip-policy Skip sandbox network policy update
|
||||
--skip-plugin-install Skip openclaw plugin installation
|
||||
--dry-run Preview changes without applying
|
||||
--help Show help
|
||||
```
|
||||
|
||||
Use `--dry-run` to preview all changes before applying anything. Use `--skip-policy` if you manage sandbox policies manually.
|
||||
|
||||
## Manual Setup
|
||||
|
||||
If you prefer to apply the steps yourself instead of using the CLI:
|
||||
|
||||
### 1. Install the plugin
|
||||
|
||||
```bash
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
### 2. Configure `~/.openclaw/openclaw.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"hindsightApiUrl": "https://api.hindsight.vectorize.io",
|
||||
"hindsightApiToken": "<your-api-key>",
|
||||
"llmProvider": "claude-code",
|
||||
"dynamicBankId": false,
|
||||
"bankIdPrefix": "my-sandbox"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`llmProvider: "claude-code"` uses the Claude Code process already present in the sandbox — no additional API key needed.
|
||||
|
||||
### 3. Add the Hindsight network policy
|
||||
|
||||
`openshell policy set` replaces the entire policy document. Export your current policy first, add the Hindsight block, then re-apply:
|
||||
|
||||
```yaml
|
||||
network_policies:
|
||||
hindsight:
|
||||
name: hindsight
|
||||
endpoints:
|
||||
- host: api.hindsight.vectorize.io
|
||||
port: 443
|
||||
protocol: rest
|
||||
tls: terminate
|
||||
enforcement: enforce
|
||||
rules:
|
||||
- allow:
|
||||
method: GET
|
||||
path: /**
|
||||
- allow:
|
||||
method: POST
|
||||
path: /**
|
||||
- allow:
|
||||
method: PUT
|
||||
path: /**
|
||||
binaries:
|
||||
- path: /usr/local/bin/openclaw
|
||||
```
|
||||
|
||||
```bash
|
||||
openshell policy set my-sandbox --policy /path/to/full-policy.yaml --wait
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `hindsightApiUrl` | string | — | Hindsight API base URL |
|
||||
| `hindsightApiToken` | string | — | API token for authentication |
|
||||
| `llmProvider` | string | auto-detect | LLM provider for memory extraction |
|
||||
| `dynamicBankId` | boolean | `false` | Isolate memory per user (`true`) or share across sessions (`false`) |
|
||||
| `bankIdPrefix` | string | `"nemoclaw"` | Prefix for the memory bank name |
|
||||
|
||||
### Bank naming
|
||||
|
||||
When `dynamicBankId: false`, all sessions write to a single bank named `{bankIdPrefix}-openclaw`. When `dynamicBankId: true`, each user gets an isolated bank — useful for multi-tenant deployments.
|
||||
|
||||
## Verifying It Works
|
||||
|
||||
After setup, check the gateway logs:
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
```
|
||||
|
||||
On startup you should see:
|
||||
|
||||
```
|
||||
[Hindsight] Plugin loaded successfully
|
||||
[Hindsight] ✓ Using external API: https://api.hindsight.vectorize.io
|
||||
[Hindsight] External API health: {"status":"healthy","database":"connected"}
|
||||
[Hindsight] Default bank: my-sandbox-openclaw
|
||||
[Hindsight] ✓ Ready (external API mode)
|
||||
```
|
||||
|
||||
After a conversation:
|
||||
|
||||
```
|
||||
[Hindsight] before_agent_start - bank: my-sandbox-openclaw, channel: undefined/webchat
|
||||
[Hindsight Hook] agent_end triggered - bank: my-sandbox-openclaw
|
||||
[Hindsight] Retained 6 messages to bank my-sandbox-openclaw for session agent:main:...
|
||||
```
|
||||
|
||||
## Pitfalls
|
||||
|
||||
### Policy replacement is full-document
|
||||
|
||||
`openshell policy set` replaces the entire policy document. The `hindsight-nemoclaw setup` command handles this automatically. If you're applying manually, export the current policy first so existing rules aren't lost.
|
||||
|
||||
### LaunchAgent can't follow symlinks on macOS
|
||||
|
||||
On macOS, the OpenClaw gateway runs as a LaunchAgent under a restricted security context. `openclaw plugins install --link` creates a symlink the LaunchAgent can't follow — the setup command installs as a copy instead. If you see `EPERM: operation not permitted, scandir` in gateway logs, this is the cause.
|
||||
|
||||
### Memory retention is asynchronous
|
||||
|
||||
Fact extraction and entity resolution happen in the background after `retain`. If you open a new session immediately after closing one, the most recent memories may not be indexed yet — typically a few seconds.
|
||||
|
||||
### Binary-scoped egress
|
||||
|
||||
The `binaries` field in the network policy restricts the egress rule to a specific executable path. If OpenClaw updates and the binary path changes, the rule silently stops working. Check your binary path after upgrades.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
```bash
|
||||
openclaw plugins list | grep hindsight
|
||||
# Should show: ✓ enabled │ Hindsight Memory │ ...
|
||||
|
||||
# Reinstall
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
### Egress blocked
|
||||
|
||||
If calls to `api.hindsight.vectorize.io` are being blocked, check the active sandbox policy:
|
||||
|
||||
```bash
|
||||
openshell sandbox get my-assistant
|
||||
```
|
||||
|
||||
Verify the `hindsight` block is present and the `binaries` path matches your OpenClaw binary:
|
||||
|
||||
```bash
|
||||
which openclaw
|
||||
```
|
||||
|
||||
### External API not connecting
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
|
||||
# If you see daemon startup messages instead of "Using external API",
|
||||
# the plugin config isn't being read — check ~/.openclaw/openclaw.json
|
||||
```
|
||||
@@ -1,374 +0,0 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
title: "OpenClaw Persistent Memory with Hindsight | Plugin Integration"
|
||||
description: "Add persistent, automated memory to your OpenClaw agent with Hindsight. Local-first, open source — one plugin install replaces built-in memory with structured knowledge extraction and auto-recall."
|
||||
---
|
||||
|
||||
# OpenClaw
|
||||
|
||||
Local, long term memory for [OpenClaw](https://openclaw.ai) agents using [Hindsight](https://vectorize.io/hindsight).
|
||||
|
||||
This plugin integrates [hindsight-embed](https://vectorize.io/hindsight/cli), a standalone daemon that bundles Hindsight's memory engine (API + PostgreSQL) into a single command. Everything runs locally on your machine, reuses the LLM you're already paying for, and costs nothing extra.
|
||||
|
||||
[View Changelog →](/changelog/integrations/openclaw)
|
||||
|
||||
## Quick Start
|
||||
|
||||
**Step 1: Set up LLM for memory extraction**
|
||||
|
||||
Choose one provider and set its API key:
|
||||
|
||||
```bash
|
||||
# Option A: OpenAI
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option B: Anthropic
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
|
||||
# Option C: Gemini
|
||||
export GEMINI_API_KEY="your-key"
|
||||
|
||||
# Option D: Groq
|
||||
export GROQ_API_KEY="your-key"
|
||||
|
||||
# Option E: Claude Code (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option F: OpenAI Codex (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||
```
|
||||
|
||||
**Step 2: Install the plugin**
|
||||
|
||||
```bash
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
**Step 3: Start OpenClaw**
|
||||
|
||||
```bash
|
||||
openclaw gateway
|
||||
```
|
||||
|
||||
The plugin will automatically:
|
||||
- Start a local Hindsight daemon (port 9077)
|
||||
- Capture conversations after each turn
|
||||
- Inject relevant memories before agent responses
|
||||
|
||||
**Important:** The LLM you configure above is **only for memory extraction** (background processing). Your main OpenClaw agent can use any model you configure separately.
|
||||
|
||||
## How It Works
|
||||
|
||||
**Auto-Capture:** Every conversation is automatically stored after each turn. Facts, entities, and relationships are extracted in the background.
|
||||
|
||||
**Auto-Recall:** Before each agent response, relevant memories are automatically injected into the context (up to 1024 tokens). The agent uses past context without needing to call tools.
|
||||
|
||||
**Feedback Loop Prevention:** The plugin automatically strips injected memory tags (`<hindsight_memories>`) before storing conversations. This prevents recalled memories from being re-extracted as new facts, which would cause exponential memory growth and duplicate entries.
|
||||
|
||||
Traditional memory systems give agents a `search_memory` tool - but models don't use it consistently. Auto-recall solves this by injecting memories automatically before every turn.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Plugin Settings
|
||||
|
||||
Optional settings in `~/.openclaw/openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"apiPort": 9077,
|
||||
"daemonIdleTimeout": 0,
|
||||
"embedVersion": "latest"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `apiPort` - Port for the openclaw profile daemon (default: `9077`)
|
||||
- `daemonIdleTimeout` - Seconds before daemon shuts down from inactivity (default: `0` = never)
|
||||
- `embedVersion` - hindsight-embed version (default: `"latest"`)
|
||||
- `bankMission` - Agent identity/purpose stored on the memory bank. Helps the memory engine understand context for better fact extraction during retain. Set once per bank on first use — not a recall prompt.
|
||||
- `dynamicBankId` - Enable per-context memory banks (default: `true`)
|
||||
- `bankIdPrefix` - Optional prefix for bank IDs (e.g. `"prod"` → `"prod-slack-C123"`)
|
||||
- `dynamicBankGranularity` - Fields used to derive bank ID: `agent`, `channel`, `user`, `provider` (default: `["agent", "channel", "user"]`)
|
||||
- `excludeProviders` - Message providers to skip for recall/retain (e.g. `["slack"]`, `["telegram"]`, `["discord"]`)
|
||||
- `autoRecall` - Auto-inject memories before each turn (default: `true`). Set to `false` when the agent has its own recall tool.
|
||||
- `autoRetain` - Auto-retain conversations after each turn (default: `true`)
|
||||
- `retainRoles` - Which message roles to retain (default: `["user", "assistant"]`). Options: `user`, `assistant`, `system`, `tool`
|
||||
- `recallBudget` - Recall effort: `"low"`, `"mid"`, or `"high"` (default: `"mid"`). Higher budgets use more retrieval strategies for better results.
|
||||
- `recallMaxTokens` - Max tokens for recall response (default: `1024`). Controls how much memory context is injected per turn.
|
||||
- `recallTopK` - Max number of memories to inject per turn (default: unlimited).
|
||||
- `recallTypes` - Memory types to recall (default: `["world", "experience"]`). Options: `world`, `experience`, `observation`.
|
||||
- `recallContextTurns` - Number of prior user turns to include in the recall query (default: `1`).
|
||||
- `recallMaxQueryChars` - Max characters for the composed recall query (default: `800`).
|
||||
- `recallPromptPreamble` - Custom preamble text placed above recalled memories. Overrides the built-in guidance text.
|
||||
- `recallInjectionPosition` - Where to inject recalled memories: `"prepend"` (default), `"append"`, or `"user"`. Use `"append"` to preserve prompt caching with large static system prompts. Use `"user"` to inject before the user message instead of in the system prompt.
|
||||
- `recallRoles` - Which message roles to include when composing the contextual recall query (default: `["user", "assistant"]`).
|
||||
- `retainEveryNTurns` - Retain every Nth turn (default: `1` = every turn). Values > 1 enable chunked retention.
|
||||
- `retainOverlapTurns` - Extra prior turns included when chunked retention fires (default: `0`).
|
||||
- `debug` - Enable debug logging (default: `false`).
|
||||
|
||||
### Memory Isolation
|
||||
|
||||
The plugin creates separate memory banks based on conversation context. By default, banks are derived from the `agent`, `channel`, and `user` fields — so each unique combination gets its own isolated memory store.
|
||||
|
||||
You can customize which fields are used for bank segmentation with `dynamicBankGranularity`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"dynamicBankGranularity": ["provider", "user"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, memories are isolated per provider + user, meaning the same user shares memories across all channels within a provider.
|
||||
|
||||
Available isolation fields:
|
||||
- `agent` - The agent/bot identity
|
||||
- `channel` - The channel or conversation ID
|
||||
- `user` - The user interacting with the agent
|
||||
- `provider` - The message provider (e.g. Slack, Discord)
|
||||
|
||||
Use `bankIdPrefix` to namespace bank IDs across environments (e.g. `"prod"`, `"staging"`). Set `dynamicBankId` to `false` to use a single shared bank for all conversations.
|
||||
|
||||
### Retention Controls
|
||||
|
||||
By default, the plugin retains `user` and `assistant` messages after each turn. You can customize this behavior:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"autoRetain": true,
|
||||
"retainRoles": ["user", "assistant", "system"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `autoRetain` - Set to `false` to disable automatic retention entirely (useful if you handle retention yourself)
|
||||
- `retainRoles` - Controls which message roles are included in the retained transcript. Only messages from the last user message onward are retained each turn, preventing duplicate storage.
|
||||
|
||||
### LLM Configuration
|
||||
|
||||
The plugin auto-detects your LLM provider from these environment variables:
|
||||
|
||||
| Provider | Env Var | Notes |
|
||||
|----------|---------|-------|
|
||||
| OpenAI | `OPENAI_API_KEY` | |
|
||||
| Anthropic | `ANTHROPIC_API_KEY` | |
|
||||
| Gemini | `GEMINI_API_KEY` | |
|
||||
| Groq | `GROQ_API_KEY` | |
|
||||
| Claude Code | `HINDSIGHT_API_LLM_PROVIDER=claude-code` | No API key needed |
|
||||
| OpenAI Codex | `HINDSIGHT_API_LLM_PROVIDER=openai-codex` | No API key needed |
|
||||
|
||||
The model is selected automatically by the Hindsight API. To override, set `HINDSIGHT_API_LLM_MODEL`.
|
||||
|
||||
**Override with explicit config:**
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai
|
||||
export HINDSIGHT_API_LLM_API_KEY=sk-your-key
|
||||
|
||||
# Optional: custom base URL (OpenRouter, Azure, vLLM, etc.)
|
||||
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
```
|
||||
|
||||
**Example: Free OpenRouter model**
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai
|
||||
export HINDSIGHT_API_LLM_MODEL=xiaomi/mimo-v2-flash # FREE!
|
||||
export HINDSIGHT_API_LLM_API_KEY=sk-or-v1-your-openrouter-key
|
||||
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
```
|
||||
|
||||
### External API (Advanced)
|
||||
|
||||
Connect to a remote Hindsight API server instead of running a local daemon. This is useful for:
|
||||
|
||||
- **Shared memory** across multiple OpenClaw instances
|
||||
- **Production deployments** with centralized memory storage
|
||||
- **Team environments** where agents share knowledge
|
||||
|
||||
#### Plugin Configuration
|
||||
|
||||
Configure in `~/.openclaw/openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"hindsightApiUrl": "https://your-hindsight-server.com",
|
||||
"hindsightApiToken": "your-api-token"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `hindsightApiUrl` - Full URL to external Hindsight API (e.g., `https://mcp.hindsight.example.com`)
|
||||
- `hindsightApiToken` - API token for authentication (optional, only if API requires auth)
|
||||
|
||||
#### Environment Variables (Alternative)
|
||||
|
||||
You can also configure via environment variables:
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_EMBED_API_URL=https://your-hindsight-server.com
|
||||
export HINDSIGHT_EMBED_API_TOKEN=your-api-token # Optional
|
||||
|
||||
openclaw gateway
|
||||
```
|
||||
|
||||
**Note:** Plugin config takes precedence over environment variables.
|
||||
|
||||
#### Behavior
|
||||
|
||||
When external API mode is enabled:
|
||||
- **No local daemon** is started (no hindsight-embed process)
|
||||
- **Health check** runs on startup to verify API connectivity
|
||||
- **All memory operations** (retain, recall, reflect) go to the external API
|
||||
- **Faster startup** since no local PostgreSQL or embedding models are needed
|
||||
|
||||
#### Verification
|
||||
|
||||
Check OpenClaw logs for external API mode:
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
|
||||
# Should see on startup:
|
||||
# [Hindsight] External API mode enabled: https://your-hindsight-server.com
|
||||
# [Hindsight] External API health check passed
|
||||
```
|
||||
|
||||
If you see daemon startup messages instead, verify your configuration is correct.
|
||||
|
||||
## Inspecting Memories
|
||||
|
||||
### Check Configuration
|
||||
|
||||
View the daemon config that was written by the plugin:
|
||||
|
||||
```bash
|
||||
cat ~/.hindsight/profiles/openclaw.env
|
||||
```
|
||||
|
||||
This shows the LLM provider, model, port, and other settings the daemon is using.
|
||||
|
||||
### Check Daemon Status
|
||||
|
||||
```bash
|
||||
# Check if daemon is running
|
||||
uvx hindsight-embed@latest -p openclaw daemon status
|
||||
|
||||
# View daemon logs
|
||||
tail -f ~/.hindsight/profiles/openclaw.log
|
||||
```
|
||||
|
||||
### Query Memories
|
||||
|
||||
```bash
|
||||
# Search memories
|
||||
uvx hindsight-embed@latest -p openclaw memory recall openclaw "user preferences"
|
||||
|
||||
# View recent memories
|
||||
uvx hindsight-embed@latest -p openclaw memory list openclaw --limit 10
|
||||
|
||||
# Open web UI (uses openclaw profile's daemon)
|
||||
uvx hindsight-embed@latest -p openclaw ui
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
```bash
|
||||
openclaw plugins list | grep hindsight
|
||||
# Should show: ✓ enabled │ Hindsight Memory │ ...
|
||||
|
||||
# Reinstall if needed
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
### Daemon not starting
|
||||
|
||||
```bash
|
||||
# Check daemon status (note: -p openclaw uses the openclaw profile)
|
||||
uvx hindsight-embed@latest -p openclaw daemon status
|
||||
|
||||
# View logs for errors
|
||||
tail -f ~/.hindsight/profiles/openclaw.log
|
||||
|
||||
# Check configuration
|
||||
cat ~/.hindsight/profiles/openclaw.env
|
||||
|
||||
# List all profiles
|
||||
uvx hindsight-embed@latest profile list
|
||||
```
|
||||
|
||||
### No API key error
|
||||
|
||||
Make sure you've set one of the provider API keys (or use a provider that doesn't require one):
|
||||
|
||||
```bash
|
||||
# Option 1: OpenAI
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option 2: Anthropic
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
|
||||
# Option 3: Claude Code (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option 4: OpenAI Codex (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||
|
||||
# Verify it's set
|
||||
echo $OPENAI_API_KEY
|
||||
# or
|
||||
echo $HINDSIGHT_API_LLM_PROVIDER
|
||||
```
|
||||
|
||||
### Verify it's working
|
||||
|
||||
Check gateway logs for memory operations:
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
|
||||
# Should see on startup:
|
||||
# [Hindsight] ✓ Using provider: openai, model: gpt-4o-mini
|
||||
# or
|
||||
# [Hindsight] ✓ Using provider: claude-code, model: claude-sonnet-4-20250514
|
||||
|
||||
# Should see after conversations:
|
||||
# [Hindsight] Retained X messages for session ...
|
||||
# [Hindsight] Auto-recall: Injecting X memories
|
||||
```
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
title: "Pydantic AI Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Pydantic AI agents with Hindsight. Async-native retain, recall, and reflect tools — persistent memory across all agent runs with no thread-pool hacks."
|
||||
---
|
||||
|
||||
# Pydantic AI
|
||||
|
||||
Persistent memory tools for [Pydantic AI](https://ai.pydantic.dev/) agents via Hindsight. Give your agents long-term memory with retain, recall, and reflect — all async-native with no thread-pool hacks.
|
||||
|
||||
[View Changelog →](/changelog/integrations/pydantic-ai)
|
||||
|
||||
## Features
|
||||
|
||||
- **Async-Native Tools** — Uses Pydantic AI's async tool interface directly (`aretain`, `arecall`, `areflect`)
|
||||
- **Memory Instructions** — Auto-inject relevant memories into every agent run via `instructions=[...]`
|
||||
- **Three Memory Tools** — Retain (store), Recall (search), Reflect (synthesize) — include any combination
|
||||
- **Simple Configuration** — Configure once globally, or pass a client directly
|
||||
- **Lightweight** — Depends on `pydantic-ai-slim` to avoid pulling in all model providers
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-pydantic-ai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_pydantic_ai import create_hindsight_tools, memory_instructions
|
||||
from pydantic_ai import Agent
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
agent = Agent(
|
||||
"openai:gpt-4o",
|
||||
tools=create_hindsight_tools(client=client, bank_id="user-123"),
|
||||
instructions=[memory_instructions(client=client, bank_id="user-123")],
|
||||
)
|
||||
|
||||
result = await agent.run("What do you remember about my preferences?")
|
||||
print(result.output)
|
||||
```
|
||||
|
||||
The agent now has three tools it can call:
|
||||
|
||||
- **`hindsight_retain`** — Store information to long-term memory
|
||||
- **`hindsight_recall`** — Search long-term memory for relevant facts
|
||||
- **`hindsight_reflect`** — Synthesize a reasoned answer from memories
|
||||
|
||||
The `memory_instructions` callable automatically recalls relevant memories and injects them into the system prompt on every run.
|
||||
|
||||
## Tools Only (No Auto-Injection)
|
||||
|
||||
If you want the agent to decide when to use memory rather than always injecting context:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
"openai:gpt-4o",
|
||||
tools=create_hindsight_tools(client=client, bank_id="user-123"),
|
||||
)
|
||||
```
|
||||
|
||||
## Instructions Only (No Tools)
|
||||
|
||||
If you just want memories auto-injected without giving the agent explicit memory tools:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
"openai:gpt-4o",
|
||||
instructions=[memory_instructions(client=client, bank_id="user-123")],
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=True,
|
||||
include_recall=True,
|
||||
include_reflect=False, # Omit reflect
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing a client to every call, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_pydantic_ai import configure, create_hindsight_tools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create tools without passing client — uses global config
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
## Per-Tool Overrides
|
||||
|
||||
Constructor arguments override global configuration:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
budget="high", # Override global budget
|
||||
max_tokens=8192, # Override global max_tokens
|
||||
tags=["session:abc"], # Override global tags
|
||||
)
|
||||
```
|
||||
|
||||
## Memory Instructions Options
|
||||
|
||||
Customize what memories get injected and how:
|
||||
|
||||
```python
|
||||
instructions_fn = memory_instructions(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
query="relevant context about the user", # What to search for
|
||||
budget="low", # Keep it fast
|
||||
max_results=5, # Limit injected memories
|
||||
max_tokens=4096, # Max recall tokens
|
||||
prefix="Relevant memories:\n", # Text before the memory list
|
||||
tags=["scope:global"], # Filter by tags
|
||||
tags_match="any", # Tag match mode
|
||||
)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `create_hindsight_tools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `include_retain` | `True` | Include the retain (store) tool |
|
||||
| `include_recall` | `True` | Include the recall (search) tool |
|
||||
| `include_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `memory_instructions()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `query` | `"relevant context about the user"` | Recall query for memory injection |
|
||||
| `budget` | `"low"` | Recall budget level |
|
||||
| `max_results` | `5` | Maximum memories to inject |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `prefix` | `"Relevant memories:\n"` | Text prepended before memory list |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
@@ -1,325 +0,0 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
title: "Hindsight Agent Memory Skill | AI Coding Assistant Integration"
|
||||
description: "Give AI coding assistants like Claude Code and Codex persistent memory across sessions with Hindsight's Agent Skill — a reusable prompt template for long-term context retention."
|
||||
---
|
||||
|
||||
# Skills
|
||||
|
||||
Hindsight provides an Agent Skill that gives AI coding assistants persistent memory across sessions. Skills are reusable prompt templates that agents can load when needed to gain specialized capabilities.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Skills Directory |
|
||||
|----------|-----------------|
|
||||
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `~/.claude/skills/` |
|
||||
| [OpenCode](https://github.com/opencode-ai/opencode) | `~/.opencode/skills/` |
|
||||
| [Codex CLI](https://github.com/openai/codex) | `~/.codex/skills/` |
|
||||
|
||||
## Deployment Modes
|
||||
|
||||
The skill supports two deployment modes:
|
||||
|
||||
| Mode | Best For | Data Location |
|
||||
|------|----------|---------------|
|
||||
| **Local** | Individual developers | Your machine (`~/.pg0/`) |
|
||||
| **Cloud** | Teams sharing knowledge | Hindsight Cloud |
|
||||
|
||||
## Quick Install
|
||||
|
||||
### Option 1: Interactive Installer (Recommended)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash
|
||||
```
|
||||
|
||||
The installer will:
|
||||
1. Prompt you to select your AI coding assistant
|
||||
2. Select deployment mode (local or cloud)
|
||||
3. Configure the appropriate settings
|
||||
4. Install the skill to the appropriate directory
|
||||
|
||||
### Install for a Specific Platform
|
||||
|
||||
```bash
|
||||
# Claude Code (interactive mode selection)
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude
|
||||
|
||||
# OpenCode
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app opencode
|
||||
|
||||
# Codex CLI
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app codex
|
||||
```
|
||||
|
||||
### Install with Cloud Mode
|
||||
|
||||
```bash
|
||||
# Direct cloud setup (skips interactive prompts for mode)
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude --mode cloud
|
||||
```
|
||||
|
||||
### Option 2: Using add-skill
|
||||
|
||||
If you use [add-skill](https://add-skill.org/) to manage your agent skills:
|
||||
|
||||
```bash
|
||||
# For local mode (individual developers)
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-local
|
||||
|
||||
# For Hindsight Cloud (teams)
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-cloud
|
||||
|
||||
# For self-hosted Hindsight servers
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-self-hosted
|
||||
```
|
||||
|
||||
On first use, the AI will guide you through the remaining setup:
|
||||
- **Local**: Run `uvx hindsight-embed configure` to set up your LLM provider
|
||||
- **Cloud**: Provide your API key and bank ID
|
||||
- **Self-hosted**: Provide your server URL, API key, and bank ID
|
||||
|
||||
## What the Skill Provides
|
||||
|
||||
Once installed, your AI assistant gains the ability to:
|
||||
|
||||
- **Retain** - Store user preferences, learnings, and procedure outcomes
|
||||
- **Recall** - Search for relevant context before starting tasks
|
||||
- **Reflect** - Synthesize memories into contextual answers
|
||||
|
||||
The skill uses the `hindsight-embed` CLI which runs a lightweight local daemon with an embedded database.
|
||||
|
||||
## How Skills Work
|
||||
|
||||
Skills are **model-invoked**, meaning the AI assistant automatically decides when to use them based on the context of your conversation. You don't need to explicitly trigger the skill.
|
||||
|
||||
The assistant will:
|
||||
- **Store** when you share preferences, when tasks succeed/fail, or when learnings emerge
|
||||
- **Recall** before starting non-trivial tasks to get relevant context
|
||||
|
||||
### What Gets Stored
|
||||
|
||||
The skill is optimized to store:
|
||||
|
||||
| Category | Examples |
|
||||
|----------|----------|
|
||||
| **User Preferences** | Coding style, tool preferences, language choices |
|
||||
| **Procedure Outcomes** | Commands that worked, configurations that resolved issues |
|
||||
| **Learnings** | Bug solutions, workarounds, architecture decisions |
|
||||
|
||||
## Architecture
|
||||
|
||||
### Local Mode
|
||||
|
||||
```
|
||||
AI Coding Assistant
|
||||
│
|
||||
▼
|
||||
Hindsight Skill (SKILL.md)
|
||||
│
|
||||
▼
|
||||
hindsight-embed CLI
|
||||
│
|
||||
▼
|
||||
Local Daemon (auto-started)
|
||||
│
|
||||
▼
|
||||
Embedded PostgreSQL (~/.pg0/hindsight-embed/)
|
||||
```
|
||||
|
||||
All data stays on your machine. The daemon auto-starts when needed and shuts down after inactivity.
|
||||
|
||||
### Cloud Mode
|
||||
|
||||
```
|
||||
AI Coding Assistant
|
||||
│
|
||||
▼
|
||||
Hindsight Skill (SKILL.md)
|
||||
│
|
||||
▼
|
||||
hindsight-cli
|
||||
│
|
||||
▼
|
||||
Hindsight Cloud API (https://api.hindsight.vectorize.io)
|
||||
│
|
||||
▼
|
||||
Shared Memory Bank (team-accessible)
|
||||
```
|
||||
|
||||
Data is stored in Hindsight Cloud and shared across your team. All team members with the same bank ID can access shared memories.
|
||||
|
||||
---
|
||||
|
||||
## Local Mode Setup
|
||||
|
||||
The skill uses configuration stored in `~/.hindsight/config.env`. Reconfigure anytime:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cloud Mode Setup
|
||||
|
||||
Cloud mode connects to [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup), allowing teams to share memories about a codebase. When one team member learns something, everyone benefits.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. A Hindsight Cloud account ([sign up](https://ui.hindsight.vectorize.io/signup))
|
||||
2. An API key from your team admin
|
||||
3. A bank ID for your project (e.g., `team-acme-frontend`)
|
||||
|
||||
### Installation
|
||||
|
||||
Run the installer with cloud mode:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
|
||||
```
|
||||
|
||||
You'll be prompted for:
|
||||
|
||||
| Setting | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| **Cloud API URL** | Hindsight Cloud endpoint | `https://api.hindsight.vectorize.io` |
|
||||
| **API Key** | Your authentication key | `hs_xxx...` |
|
||||
| **Bank ID** | Shared memory bank for your team | `team-acme-frontend` |
|
||||
|
||||
### Configuration Files
|
||||
|
||||
Cloud mode creates two files:
|
||||
|
||||
**`~/.hindsight/config`** — API connection settings (TOML format):
|
||||
```toml
|
||||
api_url = "https://api.hindsight.vectorize.io"
|
||||
api_key = "hs_xxx..."
|
||||
```
|
||||
|
||||
**`~/.claude/skills/hindsight/SKILL.md`** — Skill definition with your bank ID baked in.
|
||||
|
||||
### Team Setup
|
||||
|
||||
To set up cloud mode for your team:
|
||||
|
||||
1. **Team admin** creates a bank in Hindsight Cloud (e.g., `team-acme-frontend`)
|
||||
2. **Team admin** generates API keys for each team member
|
||||
3. **Each developer** runs the installer with their API key and the shared bank ID
|
||||
4. All team members now share the same memory bank
|
||||
|
||||
### What to Store in Team Banks
|
||||
|
||||
Cloud mode uses a **shared team bank**. Be thoughtful about what goes in:
|
||||
|
||||
| Type | Examples | How to Store |
|
||||
|------|----------|--------------|
|
||||
| **Project conventions** | Linting rules, testing requirements, Node version | `"Project uses ESLint with Airbnb config"` |
|
||||
| **Team knowledge** | Architecture decisions, common pitfalls, domain logic | `"Auth module requires Redis 7+"` |
|
||||
| **Individual preferences** | Personal coding style, communication preferences | `"Alice prefers verbose commit messages"` |
|
||||
|
||||
**Key distinction**: Project conventions apply to everyone. Individual preferences should include the person's name so the AI knows when to apply them.
|
||||
|
||||
### Example Workflow
|
||||
|
||||
```
|
||||
Day 1: Alice discovers a requirement
|
||||
─────────────────────────────────────
|
||||
Alice's AI assistant stores:
|
||||
"The auth module requires Redis 7+ due to HEXPIRE command usage"
|
||||
"Alice prefers explicit error handling over silent failures"
|
||||
|
||||
Day 2: Bob starts working on auth
|
||||
─────────────────────────────────
|
||||
Bob's AI assistant recalls:
|
||||
"The auth module requires Redis 7+ due to HEXPIRE command usage"
|
||||
|
||||
Bob avoids the same issue Alice hit!
|
||||
(Alice's personal preference is stored but won't be applied to Bob)
|
||||
```
|
||||
|
||||
### Testing Cloud Connection
|
||||
|
||||
After installation, verify the connection:
|
||||
|
||||
```bash
|
||||
# Store a test memory
|
||||
hindsight memory retain team-acme-frontend "Alice works at Google as a software engineer"
|
||||
|
||||
# Recall it
|
||||
hindsight memory recall team-acme-frontend "Alice"
|
||||
```
|
||||
|
||||
### Switching Between Banks
|
||||
|
||||
If you work on multiple projects, you can have different skills installed for each AI assistant, or manually switch banks:
|
||||
|
||||
```bash
|
||||
# Environment variable override (temporary)
|
||||
HINDSIGHT_API_URL=https://api.hindsight.vectorize.io \
|
||||
HINDSIGHT_API_KEY=hs_xxx \
|
||||
hindsight memory recall different-bank "query"
|
||||
```
|
||||
|
||||
For permanent multi-bank setups, reinstall the skill with a different bank ID.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not activating
|
||||
|
||||
The skill activates based on its description matching your request. Try being explicit:
|
||||
- "Remember that..." triggers storage
|
||||
- "What do you know about..." triggers recall
|
||||
|
||||
### Local Mode Issues
|
||||
|
||||
**Daemon not starting:**
|
||||
```bash
|
||||
uvx hindsight-embed daemon status
|
||||
uvx hindsight-embed daemon logs
|
||||
```
|
||||
|
||||
**Reconfigure LLM provider:**
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
### Cloud Mode Issues
|
||||
|
||||
**Authentication errors:**
|
||||
```bash
|
||||
# Verify your config
|
||||
cat ~/.hindsight/config
|
||||
|
||||
# Test connection manually
|
||||
hindsight bank list
|
||||
```
|
||||
|
||||
**Wrong bank ID:**
|
||||
|
||||
Check your SKILL.md file to see which bank ID is configured:
|
||||
```bash
|
||||
cat ~/.claude/skills/hindsight/SKILL.md | grep "memory retain"
|
||||
```
|
||||
|
||||
To change the bank ID, reinstall the skill:
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
|
||||
```
|
||||
|
||||
**Network/firewall issues:**
|
||||
```bash
|
||||
# Test connectivity to cloud API
|
||||
curl -I https://api.hindsight.vectorize.io/health
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
### Local Mode
|
||||
- Python 3.10+ (for `uvx`)
|
||||
- An LLM API key (OpenAI, Anthropic, Groq, etc.)
|
||||
|
||||
### Cloud Mode
|
||||
- Python 3.10+ (for `uvx`)
|
||||
- Hindsight Cloud API key
|
||||
- Network access to `https://api.hindsight.vectorize.io`
|
||||
@@ -1,157 +0,0 @@
|
||||
---
|
||||
sidebar_position: 13
|
||||
title: "Strands Agents Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Strands Agents SDK agents with Hindsight. Retain, recall, and reflect tools using Strands' native @tool pattern for persistent memory across sessions."
|
||||
---
|
||||
|
||||
# Strands Agents
|
||||
|
||||
Persistent memory tools for [Strands Agents SDK](https://github.com/strands-agents/sdk-python) agents via Hindsight. Give your agents long-term memory with retain, recall, and reflect — using Strands' native `@tool` pattern.
|
||||
|
||||
## Features
|
||||
|
||||
- **Native `@tool` Functions** - Tools are plain Python functions, compatible with `Agent(tools=[...])`
|
||||
- **Memory Instructions** - Pre-recall memories for injection into agent system prompt
|
||||
- **Three Memory Tools** - Retain (store), Recall (search), Reflect (synthesize) — include any combination
|
||||
- **Simple Configuration** - Configure once globally, or pass a client directly
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-strands
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from strands import Agent
|
||||
from hindsight_strands import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
agent = Agent(tools=tools)
|
||||
agent("Remember that I prefer dark mode")
|
||||
agent("What are my preferences?")
|
||||
```
|
||||
|
||||
The agent now has three tools it can call:
|
||||
|
||||
- **`hindsight_retain`** — Store information to long-term memory
|
||||
- **`hindsight_recall`** — Search long-term memory for relevant facts
|
||||
- **`hindsight_reflect`** — Synthesize a reasoned answer from memories
|
||||
|
||||
## With Memory Instructions
|
||||
|
||||
Pre-recall relevant memories and inject them into the system prompt:
|
||||
|
||||
```python
|
||||
from hindsight_strands import create_hindsight_tools, memory_instructions
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
memories = memory_instructions(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
tools=tools,
|
||||
system_prompt=f"You are a helpful assistant.\n\n{memories}",
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
enable_retain=True,
|
||||
enable_recall=True,
|
||||
enable_reflect=False, # Omit reflect
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing connection details to every call, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_strands import configure, create_hindsight_tools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create tools without passing connection details
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
### `create_hindsight_tools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `enable_retain` | `True` | Include the retain (store) tool |
|
||||
| `enable_recall` | `True` | Include the recall (search) tool |
|
||||
| `enable_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `memory_instructions()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `query` | `"relevant context about the user"` | Recall query for memory injection |
|
||||
| `budget` | `"low"` | Recall budget level |
|
||||
| `max_results` | `5` | Maximum memories to inject |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `prefix` | `"Relevant memories:\n"` | Text prepended before memory list |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- strands-agents
|
||||
- hindsight-client >= 0.4.0
|
||||
- A running Hindsight API server
|
||||
@@ -5,14 +5,70 @@
|
||||
"label": "Architecture",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{ "type": "doc", "id": "developer/index", "label": "Overview", "customProps": { "icon": "lu-book" } },
|
||||
{ "type": "doc", "id": "developer/retain", "label": "Retain", "customProps": { "icon": "lu-brain" } },
|
||||
{ "type": "doc", "id": "developer/retrieval", "label": "Recall", "customProps": { "icon": "lu-search" } },
|
||||
{ "type": "doc", "id": "developer/reflect", "label": "Reflect", "customProps": { "icon": "lu-message" } },
|
||||
{ "type": "doc", "id": "developer/multilingual", "label": "Multilingual", "customProps": { "icon": "lu-languages" } },
|
||||
{ "type": "doc", "id": "developer/performance", "label": "Performance", "customProps": { "icon": "lu-zap" } },
|
||||
{ "type": "doc", "id": "developer/storage", "label": "Storage", "customProps": { "icon": "lu-database" } },
|
||||
{ "type": "doc", "id": "developer/rag-vs-hindsight", "label": "RAG vs Memory", "customProps": { "icon": "lu-compare" } }
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/index",
|
||||
"label": "Overview",
|
||||
"customProps": {
|
||||
"icon": "lu-book"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/retain",
|
||||
"label": "Retain",
|
||||
"customProps": {
|
||||
"icon": "lu-brain"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/retrieval",
|
||||
"label": "Recall",
|
||||
"customProps": {
|
||||
"icon": "lu-search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/reflect",
|
||||
"label": "Reflect",
|
||||
"customProps": {
|
||||
"icon": "lu-message"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/multilingual",
|
||||
"label": "Multilingual",
|
||||
"customProps": {
|
||||
"icon": "lu-languages"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/performance",
|
||||
"label": "Performance",
|
||||
"customProps": {
|
||||
"icon": "lu-zap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/storage",
|
||||
"label": "Storage",
|
||||
"customProps": {
|
||||
"icon": "lu-database"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/rag-vs-hindsight",
|
||||
"label": "RAG vs Memory",
|
||||
"customProps": {
|
||||
"icon": "lu-compare"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -20,14 +76,70 @@
|
||||
"label": "API",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{ "type": "doc", "id": "developer/api/quickstart", "label": "Quick Start", "customProps": { "icon": "lu-rocket" } },
|
||||
{ "type": "doc", "id": "developer/api/retain", "label": "Retain", "customProps": { "icon": "lu-brain" } },
|
||||
{ "type": "doc", "id": "developer/api/recall", "label": "Recall", "customProps": { "icon": "lu-search" } },
|
||||
{ "type": "doc", "id": "developer/api/reflect", "label": "Reflect", "customProps": { "icon": "lu-message" } },
|
||||
{ "type": "doc", "id": "developer/api/memory-banks", "label": "Memory Banks", "customProps": { "icon": "lu-memory" } },
|
||||
{ "type": "doc", "id": "developer/api/entities", "label": "Entities", "customProps": { "icon": "lu-network" } },
|
||||
{ "type": "doc", "id": "developer/api/documents", "label": "Documents", "customProps": { "icon": "lu-file" } },
|
||||
{ "type": "doc", "id": "developer/api/operations", "label": "Operations", "customProps": { "icon": "lu-cpu" } }
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/quickstart",
|
||||
"label": "Quick Start",
|
||||
"customProps": {
|
||||
"icon": "lu-rocket"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/retain",
|
||||
"label": "Retain",
|
||||
"customProps": {
|
||||
"icon": "lu-brain"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/recall",
|
||||
"label": "Recall",
|
||||
"customProps": {
|
||||
"icon": "lu-search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/reflect",
|
||||
"label": "Reflect",
|
||||
"customProps": {
|
||||
"icon": "lu-message"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/memory-banks",
|
||||
"label": "Memory Banks",
|
||||
"customProps": {
|
||||
"icon": "lu-memory"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/entities",
|
||||
"label": "Entities",
|
||||
"customProps": {
|
||||
"icon": "lu-network"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/documents",
|
||||
"label": "Documents",
|
||||
"customProps": {
|
||||
"icon": "lu-file"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/operations",
|
||||
"label": "Operations",
|
||||
"customProps": {
|
||||
"icon": "lu-cpu"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -35,9 +147,30 @@
|
||||
"label": "Clients",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{ "type": "doc", "id": "sdks/python", "label": "Python", "customProps": { "icon": "si-python" } },
|
||||
{ "type": "doc", "id": "sdks/nodejs", "label": "TypeScript", "customProps": { "icon": "/img/icons/typescript.png" } },
|
||||
{ "type": "doc", "id": "sdks/cli", "label": "CLI", "customProps": { "icon": "lu-terminal" } }
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/python",
|
||||
"label": "Python",
|
||||
"customProps": {
|
||||
"icon": "si-python"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/nodejs",
|
||||
"label": "TypeScript",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/typescript.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/cli",
|
||||
"label": "CLI",
|
||||
"customProps": {
|
||||
"icon": "lu-terminal"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -45,9 +178,30 @@
|
||||
"label": "Integrations",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{ "type": "doc", "id": "sdks/integrations/local-mcp", "label": "Local MCP Server", "customProps": { "icon": "/img/icons/mcp.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/litellm", "label": "LiteLLM", "customProps": { "icon": "/img/icons/litellm.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/skills", "label": "Skills", "customProps": { "icon": "/img/icons/skills.png" } }
|
||||
{
|
||||
"type": "link",
|
||||
"label": "Local MCP Server",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/mcp.png"
|
||||
},
|
||||
"href": "/sdks/integrations/local-mcp"
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"label": "LiteLLM",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/litellm.png"
|
||||
},
|
||||
"href": "/sdks/integrations/litellm"
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"label": "Skills",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/skills.png"
|
||||
},
|
||||
"href": "/sdks/integrations/skills"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -55,14 +209,70 @@
|
||||
"label": "Hosting",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{ "type": "doc", "id": "developer/installation", "label": "Installation", "customProps": { "icon": "lu-package" } },
|
||||
{ "type": "doc", "id": "developer/services", "label": "Services", "customProps": { "icon": "lu-server" } },
|
||||
{ "type": "doc", "id": "developer/configuration", "label": "Configuration", "customProps": { "icon": "lu-settings" } },
|
||||
{ "type": "doc", "id": "developer/admin-cli", "label": "Admin CLI", "customProps": { "icon": "lu-terminal" } },
|
||||
{ "type": "doc", "id": "developer/extensions", "label": "Extensions", "customProps": { "icon": "lu-plug" } },
|
||||
{ "type": "doc", "id": "developer/models", "label": "Models", "customProps": { "icon": "lu-cpu" } },
|
||||
{ "type": "doc", "id": "developer/monitoring", "label": "Monitoring", "customProps": { "icon": "lu-activity" } },
|
||||
{ "type": "doc", "id": "developer/mcp-server", "label": "MCP Server", "customProps": { "icon": "lu-network" } }
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/installation",
|
||||
"label": "Installation",
|
||||
"customProps": {
|
||||
"icon": "lu-package"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/services",
|
||||
"label": "Services",
|
||||
"customProps": {
|
||||
"icon": "lu-server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/configuration",
|
||||
"label": "Configuration",
|
||||
"customProps": {
|
||||
"icon": "lu-settings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/admin-cli",
|
||||
"label": "Admin CLI",
|
||||
"customProps": {
|
||||
"icon": "lu-terminal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/extensions",
|
||||
"label": "Extensions",
|
||||
"customProps": {
|
||||
"icon": "lu-plug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/models",
|
||||
"label": "Models",
|
||||
"customProps": {
|
||||
"icon": "lu-cpu"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/monitoring",
|
||||
"label": "Monitoring",
|
||||
"customProps": {
|
||||
"icon": "lu-activity"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/mcp-server",
|
||||
"label": "MCP Server",
|
||||
"customProps": {
|
||||
"icon": "lu-network"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -220,140 +220,140 @@
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/local-mcp",
|
||||
"type": "link",
|
||||
"label": "Local MCP Server",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/mcp.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/local-mcp"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/litellm",
|
||||
"type": "link",
|
||||
"label": "LiteLLM",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/litellm.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/litellm"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/claude-code",
|
||||
"type": "link",
|
||||
"label": "Claude Code",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/claudecode.svg"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/claude-code"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/codex",
|
||||
"type": "link",
|
||||
"label": "OpenAI Codex CLI",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/terminal.svg"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/codex"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/openclaw",
|
||||
"type": "link",
|
||||
"label": "OpenClaw",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/openclaw.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/openclaw"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/ai-sdk",
|
||||
"type": "link",
|
||||
"label": "Vercel AI SDK",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/vercel.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/ai-sdk"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/chat",
|
||||
"type": "link",
|
||||
"label": "Vercel Chat SDK",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/vercel.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/chat"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/crewai",
|
||||
"type": "link",
|
||||
"label": "CrewAI",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/crewai.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/crewai"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/pydantic-ai",
|
||||
"type": "link",
|
||||
"label": "Pydantic AI",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/pydanticai.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/pydantic-ai"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/agno",
|
||||
"type": "link",
|
||||
"label": "Agno",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/agno.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/agno"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/hermes",
|
||||
"type": "link",
|
||||
"label": "Hermes Agent",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/hermes.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/hermes"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/langgraph",
|
||||
"type": "link",
|
||||
"label": "LangGraph / LangChain",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/langgraph.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/langgraph"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/nemoclaw",
|
||||
"type": "link",
|
||||
"label": "NemoClaw",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/nemoclaw.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/nemoclaw"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/strands",
|
||||
"type": "link",
|
||||
"label": "Strands Agents",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/strands.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/strands"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/ag2",
|
||||
"type": "link",
|
||||
"label": "AG2",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/ag2.svg"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/ag2"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/llamaindex",
|
||||
"type": "link",
|
||||
"label": "LlamaIndex",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/llamaindex.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/llamaindex"
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/skills",
|
||||
"type": "link",
|
||||
"label": "Skills",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/skills.png"
|
||||
}
|
||||
},
|
||||
"href": "/sdks/integrations/skills"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -42,6 +42,9 @@ fi
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# Number of retry attempts for each example (handles transient LLM timeouts)
|
||||
MAX_RETRIES=2
|
||||
|
||||
# Function to run a single example
|
||||
run_example() {
|
||||
local file="$1"
|
||||
@@ -54,19 +57,30 @@ run_example() {
|
||||
echo -n "Running $basename... "
|
||||
|
||||
pushd "$workdir" > /dev/null 2>&1
|
||||
if $runner "$file" > "$logfile" 2>&1; then
|
||||
echo -e "${GREEN}✓ PASS${NC}"
|
||||
TOTAL_PASSED=$((TOTAL_PASSED + 1))
|
||||
rm -f "$logfile" # Clean up successful test logs
|
||||
popd > /dev/null 2>&1
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}✗ FAIL${NC}"
|
||||
TOTAL_FAILED=$((TOTAL_FAILED + 1))
|
||||
FAILED_EXAMPLES+=("$basename:$logfile")
|
||||
popd > /dev/null 2>&1
|
||||
return 1
|
||||
fi
|
||||
local attempt=1
|
||||
while [ $attempt -le $MAX_RETRIES ]; do
|
||||
if $runner "$file" > "$logfile" 2>&1; then
|
||||
if [ $attempt -gt 1 ]; then
|
||||
echo -e "${GREEN}✓ PASS${NC} (passed on retry $attempt)"
|
||||
else
|
||||
echo -e "${GREEN}✓ PASS${NC}"
|
||||
fi
|
||||
TOTAL_PASSED=$((TOTAL_PASSED + 1))
|
||||
rm -f "$logfile" # Clean up successful test logs
|
||||
popd > /dev/null 2>&1
|
||||
return 0
|
||||
fi
|
||||
if [ $attempt -lt $MAX_RETRIES ]; then
|
||||
echo -e -n "${YELLOW}(attempt $attempt failed, retrying)${NC} "
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
echo -e "${RED}✗ FAIL${NC} (after $MAX_RETRIES attempts)"
|
||||
TOTAL_FAILED=$((TOTAL_FAILED + 1))
|
||||
FAILED_EXAMPLES+=("$basename:$logfile")
|
||||
popd > /dev/null 2>&1
|
||||
return 1
|
||||
}
|
||||
|
||||
# Run Python examples
|
||||
|
||||
@@ -6,4 +6,4 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="Vercel AI SDK Changelog" subtitle="@vectorize-io/hindsight-ai-sdk — memory integration for Vercel AI SDK." />
|
||||
|
||||
[← Vercel AI SDK integration](../../sdks/integrations/ai-sdk.md)
|
||||
← Vercel AI SDK integration
|
||||
|
||||
@@ -6,4 +6,4 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="Vercel Chat SDK Changelog" subtitle="@vectorize-io/hindsight-chat — memory integration for Vercel Chat SDK." />
|
||||
|
||||
[← Vercel Chat SDK integration](../../sdks/integrations/chat.md)
|
||||
← Vercel Chat SDK integration
|
||||
|
||||
@@ -6,7 +6,7 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="Claude Code Changelog" subtitle="hindsight-memory — Hindsight memory plugin for Claude Code." />
|
||||
|
||||
[← Claude Code integration](../../sdks/integrations/claude-code.md)
|
||||
← Claude Code integration
|
||||
|
||||
## [0.3.0](https://github.com/vectorize-io/hindsight/tree/integrations/claude-code/v0.3.0)
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="CrewAI Changelog" subtitle="hindsight-crewai — persistent memory for CrewAI agents." />
|
||||
|
||||
[← CrewAI integration](../../sdks/integrations/crewai.md)
|
||||
← CrewAI integration
|
||||
|
||||
@@ -6,7 +6,7 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="LangGraph Changelog" subtitle="hindsight-langgraph — LangGraph and LangChain memory integration." />
|
||||
|
||||
[← LangGraph integration](../../sdks/integrations/langgraph.md)
|
||||
← LangGraph integration
|
||||
|
||||
## [0.1.1](https://github.com/vectorize-io/hindsight/tree/integrations/langgraph/v0.1.1)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="LiteLLM Changelog" subtitle="hindsight-litellm — universal LLM memory integration via LiteLLM." />
|
||||
|
||||
[← LiteLLM integration](../../sdks/integrations/litellm.md)
|
||||
← LiteLLM integration
|
||||
|
||||
## [0.5.0](https://github.com/vectorize-io/hindsight/tree/integrations/litellm/v0.5.0)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="NemoClaw Changelog" subtitle="@vectorize-io/hindsight-nemoclaw — persistent memory for NemoClaw sandboxed agents." />
|
||||
|
||||
[← NemoClaw integration](../../sdks/integrations/nemoclaw.md)
|
||||
← NemoClaw integration
|
||||
|
||||
## [0.1.1](https://github.com/vectorize-io/hindsight/tree/integrations/nemoclaw/v0.1.1)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="OpenClaw Changelog" subtitle="@vectorize-io/hindsight-openclaw — Hindsight memory plugin for OpenClaw." />
|
||||
|
||||
[← OpenClaw integration](../../sdks/integrations/openclaw.md)
|
||||
← OpenClaw integration
|
||||
|
||||
## [0.5.1](https://github.com/vectorize-io/hindsight/tree/integrations/openclaw/v0.5.1)
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="Pydantic AI Changelog" subtitle="hindsight-pydantic-ai — persistent memory tools for Pydantic AI agents." />
|
||||
|
||||
[← Pydantic AI integration](../../sdks/integrations/pydantic-ai.md)
|
||||
← Pydantic AI integration
|
||||
|
||||
@@ -277,7 +277,7 @@ console.log('Would apply config:', dryRunResult.config_applied);
|
||||
```bash
|
||||
curl -X POST "$HINDSIGHT_URL/v1/default/banks/my-bank/import?dry_run=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @template.json
|
||||
-d '{"version": "1", "bank": {"retain_mission": "Dry run test."}}'
|
||||
```
|
||||
|
||||
### Go
|
||||
|
||||
@@ -293,19 +293,50 @@ console.log(`Last refreshed: ${mentalModel.last_refreshed_at}`);
|
||||
# Section 'get-mental-model' not found in api/mental-models.go
|
||||
```
|
||||
|
||||
### Detail Levels
|
||||
|
||||
Both **List** and **Get** endpoints accept an optional `detail` query parameter that controls how much data is returned. This is useful for reducing response size, especially in agent boot flows or MCP clients where context budget is limited.
|
||||
|
||||
| Level | Fields Returned | Use Case |
|
||||
|-------|----------------|----------|
|
||||
| `metadata` | `id`, `bank_id`, `name`, `tags`, `last_refreshed_at`, `created_at` | Inventory — "what models exist?" |
|
||||
| `content` | All metadata fields + `source_query`, `content`, `max_tokens`, `trigger` | Agent boot — "what do the models say?" |
|
||||
| `full` (default) | All fields including `reflect_response` | Deep inspection — "what evidence backs this model?" |
|
||||
|
||||
```bash
|
||||
# List only names and tags (smallest response)
|
||||
curl "$BASE_URL/v1/default/banks/$BANK_ID/mental-models?detail=metadata"
|
||||
|
||||
# List with content but without provenance chains
|
||||
curl "$BASE_URL/v1/default/banks/$BANK_ID/mental-models?detail=content"
|
||||
|
||||
# Get full detail (default behavior)
|
||||
curl "$BASE_URL/v1/default/banks/$BANK_ID/mental-models/$MODEL_ID?detail=full"
|
||||
```
|
||||
|
||||
The `detail` parameter is also available in the MCP tools:
|
||||
|
||||
```json
|
||||
{"bank_id": "my-bank", "detail": "metadata"}
|
||||
```
|
||||
|
||||
:::tip
|
||||
Use `detail=content` for agent orientation flows. It includes everything the agent needs to understand the models without the heavyweight `reflect_response` provenance chains, which can exceed 200KB for banks with many models.
|
||||
### Response Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `id` | string | Unique mental model ID |
|
||||
| `bank_id` | string | Memory bank ID |
|
||||
| `name` | string | Human-readable name |
|
||||
| `source_query` | string | The query used to generate content |
|
||||
| `content` | string | The generated mental model text |
|
||||
| `tags` | list | Tags for filtering |
|
||||
| `last_refreshed_at` | string | When the mental model was last updated |
|
||||
| `created_at` | string | When the mental model was created |
|
||||
| `reflect_response` | object | Full reflect response including `based_on` facts |
|
||||
| Field | Type | Detail Level | Description |
|
||||
|-------|------|-------------|-------------|
|
||||
| `id` | string | metadata | Unique mental model ID |
|
||||
| `bank_id` | string | metadata | Memory bank ID |
|
||||
| `name` | string | metadata | Human-readable name |
|
||||
| `tags` | list | metadata | Tags for filtering |
|
||||
| `last_refreshed_at` | string | metadata | When the mental model was last updated |
|
||||
| `created_at` | string | metadata | When the mental model was created |
|
||||
| `source_query` | string | content | The query used to generate content |
|
||||
| `content` | string | content | The generated mental model text |
|
||||
| `max_tokens` | int | content | Maximum tokens for the mental model content |
|
||||
| `trigger` | object | content | Trigger settings (see [Automatic Refresh](#automatic-refresh)) |
|
||||
| `reflect_response` | object | full | Full reflect response including `based_on` provenance facts |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -971,6 +971,23 @@
|
||||
},
|
||||
"description": "How to match tags"
|
||||
},
|
||||
{
|
||||
"name": "detail",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"metadata",
|
||||
"content",
|
||||
"full"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Detail level: 'metadata' (names/tags only), 'content' (adds content/config), 'full' (includes reflect_response)",
|
||||
"default": "full",
|
||||
"title": "Detail"
|
||||
},
|
||||
"description": "Detail level: 'metadata' (names/tags only), 'content' (adds content/config), 'full' (includes reflect_response)"
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
@@ -1129,6 +1146,23 @@
|
||||
"title": "Mental Model Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "detail",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"metadata",
|
||||
"content",
|
||||
"full"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Detail level: 'metadata' (names/tags only), 'content' (adds content/config), 'full' (includes reflect_response)",
|
||||
"default": "full",
|
||||
"title": "Detail"
|
||||
},
|
||||
"description": "Detail level: 'metadata' (names/tags only), 'content' (adds content/config), 'full' (includes reflect_response)"
|
||||
},
|
||||
{
|
||||
"name": "authorization",
|
||||
"in": "header",
|
||||
@@ -7261,11 +7295,25 @@
|
||||
"title": "Name"
|
||||
},
|
||||
"source_query": {
|
||||
"type": "string",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Source Query"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Content",
|
||||
"description": "The mental model content as well-formatted markdown (auto-generated from reflect endpoint)"
|
||||
},
|
||||
@@ -7278,13 +7326,25 @@
|
||||
"default": []
|
||||
},
|
||||
"max_tokens": {
|
||||
"type": "integer",
|
||||
"title": "Max Tokens",
|
||||
"default": 2048
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Max Tokens"
|
||||
},
|
||||
"trigger": {
|
||||
"$ref": "#/components/schemas/MentalModelTrigger-Output",
|
||||
"default": {}
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MentalModelTrigger-Output"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"last_refreshed_at": {
|
||||
"anyOf": [
|
||||
@@ -7326,9 +7386,7 @@
|
||||
"required": [
|
||||
"id",
|
||||
"bank_id",
|
||||
"name",
|
||||
"source_query",
|
||||
"content"
|
||||
"name"
|
||||
],
|
||||
"title": "MentalModelResponse",
|
||||
"description": "Response model for a mental model (stored reflect response)."
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
title: "AG2 (AutoGen) Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add long-term persistent memory to your AG2 (AutoGen) agents with Hindsight. Automatic fact extraction, entity tracking, and recall tools that persist across conversations."
|
||||
---
|
||||
|
||||
# AG2
|
||||
|
||||
Persistent long-term memory for [AG2](https://ag2.ai) agents (community AutoGen fork). Give your agents retain/recall/reflect tools that persist across conversations.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/ag2.md)
|
||||
|
||||
## Features
|
||||
|
||||
- **Drop-in Tools** — `register_hindsight_tools()` registers retain, recall, and reflect in one line
|
||||
- **AG2-native** — Uses `Annotated` type hints compatible with AG2's `@register_for_llm` / `@register_for_execution` pattern
|
||||
- **GroupChat Support** — Multiple agents can share a single memory bank
|
||||
- **Selective Tools** — Include only the tools you need (`include_retain`, `include_recall`, `include_reflect`)
|
||||
- **Simple Configuration** — Configure once globally or override per tool set
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-ag2
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from autogen import AssistantAgent, UserProxyAgent, LLMConfig
|
||||
from hindsight_ag2 import register_hindsight_tools
|
||||
|
||||
llm_config = LLMConfig(api_type="openai", model="gpt-4o-mini")
|
||||
|
||||
with llm_config:
|
||||
assistant = AssistantAgent(
|
||||
name="assistant",
|
||||
system_message="You are a helpful assistant with long-term memory.",
|
||||
)
|
||||
user_proxy = UserProxyAgent(
|
||||
name="user",
|
||||
human_input_mode="NEVER",
|
||||
)
|
||||
|
||||
# Register Hindsight memory tools on both agents
|
||||
register_hindsight_tools(
|
||||
assistant, user_proxy,
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
# The assistant can now use hindsight_retain, hindsight_recall, hindsight_reflect
|
||||
result = user_proxy.initiate_chat(
|
||||
assistant,
|
||||
message="Remember that I prefer Python over JavaScript.",
|
||||
)
|
||||
```
|
||||
|
||||
That's it. The assistant can now store and retrieve memories across conversations.
|
||||
|
||||
## How It Works
|
||||
|
||||
The integration provides three AG2-compatible tool functions backed by Hindsight's API:
|
||||
|
||||
| Tool | Hindsight | What happens |
|
||||
|------|-----------|--------------|
|
||||
| `hindsight_retain(content)` | `retain(bank_id, content, ...)` | Content is stored. Hindsight extracts facts, entities, and relationships from the raw text. |
|
||||
| `hindsight_recall(query)` | `recall(bank_id, query, ...)` | Hindsight runs semantic search, BM25, graph traversal, and reranking. Returns a numbered list of matching memories. |
|
||||
| `hindsight_reflect(query)` | `reflect(bank_id, query, ...)` | Hindsight synthesizes a reasoned answer from all relevant memories, using the bank's disposition traits. |
|
||||
|
||||
Tools are plain Python functions with `Annotated` type hints. AG2 uses these hints to generate the tool schema that the LLM sees.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Global Configuration
|
||||
|
||||
```python
|
||||
from hindsight_ag2 import configure
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-key", # or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # low / mid / high
|
||||
max_tokens=4096,
|
||||
tags=["source:ag2"], # default tags for retain
|
||||
)
|
||||
```
|
||||
|
||||
### Per-Tool Overrides
|
||||
|
||||
Constructor arguments override global configuration:
|
||||
|
||||
```python
|
||||
from hindsight_ag2 import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
budget="high",
|
||||
max_tokens=8192,
|
||||
tags=["team:alpha"],
|
||||
)
|
||||
```
|
||||
|
||||
## GroupChat with Shared Memory
|
||||
|
||||
Multiple agents can share a single memory bank in a GroupChat:
|
||||
|
||||
```python
|
||||
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager, LLMConfig
|
||||
from hindsight_ag2 import register_hindsight_tools
|
||||
|
||||
llm_config = LLMConfig(api_type="openai", model="gpt-4o-mini")
|
||||
|
||||
with llm_config:
|
||||
researcher = AssistantAgent(name="researcher", system_message="You research topics.")
|
||||
writer = AssistantAgent(name="writer", system_message="You write content.")
|
||||
executor = UserProxyAgent(name="executor", human_input_mode="NEVER")
|
||||
|
||||
# All agents share the same memory bank
|
||||
for agent in [researcher, writer]:
|
||||
register_hindsight_tools(agent, executor, bank_id="team-memory")
|
||||
|
||||
group_chat = GroupChat(agents=[researcher, writer, executor], messages=[])
|
||||
manager = GroupChatManager(groupchat=group_chat)
|
||||
```
|
||||
|
||||
## Manual Registration
|
||||
|
||||
For full control over how tools are registered:
|
||||
|
||||
```python
|
||||
from hindsight_ag2 import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
for tool_fn in tools:
|
||||
assistant.register_for_llm(description=tool_fn.__doc__)(tool_fn)
|
||||
user_proxy.register_for_execution()(tool_fn)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Configuration
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `configure(...)` | Set global connection and default settings |
|
||||
| `get_config()` | Get current configuration |
|
||||
| `reset_config()` | Reset configuration to None |
|
||||
|
||||
### create_hindsight_tools
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `bank_id` | required | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured `Hindsight` client |
|
||||
| `hindsight_api_url` | from config | Hindsight API URL |
|
||||
| `api_key` | from config | API key |
|
||||
| `budget` | `"mid"` | Recall/reflect budget (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Max tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode (any/all/any_strict/all_strict) |
|
||||
| `retain_metadata` | `None` | Metadata dict for retain operations |
|
||||
| `retain_document_id` | `None` | Document ID for retain (groups/upserts memories) |
|
||||
| `recall_types` | `None` | Fact types to filter (world, experience, opinion, observation) |
|
||||
| `recall_include_entities` | `False` | Include entity information in recall results |
|
||||
| `reflect_context` | `None` | Additional context for reflect operations |
|
||||
| `reflect_max_tokens` | `max_tokens` | Max tokens for reflect results |
|
||||
| `reflect_response_schema` | `None` | JSON schema to constrain reflect output format |
|
||||
| `reflect_tags` | `recall_tags` | Tags to filter memories used in reflect |
|
||||
| `reflect_tags_match` | `recall_tags_match` | Tag matching for reflect |
|
||||
| `include_retain` | `True` | Include the retain tool |
|
||||
| `include_recall` | `True` | Include the recall tool |
|
||||
| `include_reflect` | `True` | Include the reflect tool |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- ag2 >= 0.9.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
title: "Agno Agent Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to Agno agents using Hindsight's retain, recall, and reflect tools. Plug into Agno's native Toolkit pattern for long-term memory across sessions."
|
||||
---
|
||||
|
||||
# Agno
|
||||
|
||||
Persistent memory tools for [Agno](https://github.com/agno-agi/agno) agents via Hindsight. Give your agents long-term memory with retain, recall, and reflect — using Agno's native Toolkit pattern.
|
||||
|
||||
## Features
|
||||
|
||||
- **Native Toolkit** - Extends Agno's `Toolkit` base class, just like `Mem0Tools`
|
||||
- **Memory Instructions** - Pre-recall memories for injection into `Agent(instructions=[...])`
|
||||
- **Three Memory Tools** - Retain (store), Recall (search), Reflect (synthesize) — include any combination
|
||||
- **Flexible Bank Resolution** - Static bank ID, `RunContext.user_id`, or custom resolver
|
||||
- **Simple Configuration** - Configure once globally, or pass a client directly
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-agno
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from agno.agent import Agent
|
||||
from agno.models.openai import OpenAIChat
|
||||
from hindsight_agno import HindsightTools
|
||||
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
)
|
||||
|
||||
agent.print_response("Remember that I prefer dark mode")
|
||||
agent.print_response("What are my preferences?")
|
||||
```
|
||||
|
||||
The agent now has three tools it can call:
|
||||
|
||||
- **`retain_memory`** — Store information to long-term memory
|
||||
- **`recall_memory`** — Search long-term memory for relevant facts
|
||||
- **`reflect_on_memory`** — Synthesize a reasoned answer from memories
|
||||
|
||||
## With Memory Instructions
|
||||
|
||||
Pre-recall relevant memories and inject them into the system prompt:
|
||||
|
||||
```python
|
||||
from hindsight_agno import HindsightTools, memory_instructions
|
||||
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
instructions=[memory_instructions(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = [HindsightTools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
enable_retain=True,
|
||||
enable_recall=True,
|
||||
enable_reflect=False, # Omit reflect
|
||||
)]
|
||||
```
|
||||
|
||||
## Bank Resolution
|
||||
|
||||
The bank ID is resolved in order:
|
||||
|
||||
1. **`bank_resolver`** — Custom callable `(RunContext) -> str`
|
||||
2. **`bank_id`** — Static bank ID passed to constructor
|
||||
3. **`run_context.user_id`** — Automatic per-user banks
|
||||
|
||||
```python
|
||||
# Per-user banks from RunContext
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(hindsight_api_url="http://localhost:8888")],
|
||||
user_id="user-123", # Used as bank_id
|
||||
)
|
||||
|
||||
# Custom resolver
|
||||
def resolve_bank(ctx):
|
||||
return f"team-{ctx.user_id}"
|
||||
|
||||
agent = Agent(
|
||||
model=OpenAIChat(id="gpt-4o-mini"),
|
||||
tools=[HindsightTools(
|
||||
bank_resolver=resolve_bank,
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)],
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing connection details to every toolkit, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_agno import configure, HindsightTools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create toolkit without passing connection details
|
||||
tools = [HindsightTools(bank_id="user-123")]
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
### `HindsightTools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | `None` | Static Hindsight memory bank ID |
|
||||
| `bank_resolver` | `None` | Callable `(RunContext) -> str` for dynamic bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `enable_retain` | `True` | Include the retain (store) tool |
|
||||
| `enable_recall` | `True` | Include the recall (search) tool |
|
||||
| `enable_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `memory_instructions()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `query` | `"relevant context about the user"` | Recall query for memory injection |
|
||||
| `budget` | `"low"` | Recall budget level |
|
||||
| `max_results` | `5` | Maximum memories to inject |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `prefix` | `"Relevant memories:\n"` | Text prepended before memory list |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- agno
|
||||
- hindsight-client >= 0.4.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,196 +0,0 @@
|
||||
|
||||
# Vercel AI SDK
|
||||
|
||||
The `@vectorize-io/hindsight-ai-sdk` package integrates [Hindsight](https://hindsight.vectorize.io) memory with the [Vercel AI SDK](https://ai-sdk.dev). It provides five ready-to-use tools for retaining, recalling, and reflecting on long-term memories.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/ai-sdk.md)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @vectorize-io/hindsight-ai-sdk @vectorize-io/hindsight-client ai
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
Create a Hindsight client and pass it to `createHindsightTools` along with a `bankId`. The `bankId` identifies the memory store for this session—typically a user ID.
|
||||
|
||||
```typescript
|
||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
||||
import { createHindsightTools } from '@vectorize-io/hindsight-ai-sdk';
|
||||
|
||||
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
|
||||
|
||||
const tools = createHindsightTools({
|
||||
client,
|
||||
bankId: 'user-123',
|
||||
});
|
||||
```
|
||||
|
||||
> **💡 Per-request bank IDs**
|
||||
>
|
||||
In multi-user applications, create `tools` inside your request handler so each request closes over the correct `bankId`. See the [Next.js example](#in-a-nextjs-route-handler) below.
|
||||
## Usage
|
||||
|
||||
### With `generateText`
|
||||
|
||||
```typescript
|
||||
import { generateText } from 'ai';
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
|
||||
const { text } = await generateText({
|
||||
model: openai('gpt-4o'),
|
||||
tools,
|
||||
maxSteps: 5,
|
||||
system: 'You are a helpful assistant with long-term memory.',
|
||||
prompt: 'Remember that I prefer dark mode and large fonts.',
|
||||
});
|
||||
```
|
||||
|
||||
### With `streamText`
|
||||
|
||||
```typescript
|
||||
import { streamText } from 'ai';
|
||||
|
||||
const result = streamText({
|
||||
model: openai('gpt-4o'),
|
||||
tools,
|
||||
maxSteps: 5,
|
||||
system: 'You are a helpful assistant with long-term memory.',
|
||||
prompt: 'What are my display preferences?',
|
||||
});
|
||||
|
||||
for await (const chunk of result.textStream) {
|
||||
process.stdout.write(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
### With `ToolLoopAgent`
|
||||
|
||||
```typescript
|
||||
import { generateText, ToolLoopAgent, stepCountIs } from 'ai';
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
||||
import { createHindsightTools } from '@vectorize-io/hindsight-ai-sdk';
|
||||
|
||||
const client = new HindsightClient({ baseUrl: process.env.HINDSIGHT_API_URL! });
|
||||
|
||||
const agent = new ToolLoopAgent({
|
||||
model: openai('gpt-4o'),
|
||||
tools: createHindsightTools({ client, bankId: 'user-123' }),
|
||||
stopWhen: stepCountIs(10),
|
||||
system: 'You are a helpful assistant with long-term memory.',
|
||||
});
|
||||
|
||||
const result = await agent.generate({
|
||||
prompt: 'Remember that my favorite editor is Neovim',
|
||||
});
|
||||
```
|
||||
|
||||
### In a Next.js Route Handler
|
||||
|
||||
```typescript
|
||||
// app/api/chat/route.ts
|
||||
import { streamText } from 'ai';
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
||||
import { createHindsightTools } from '@vectorize-io/hindsight-ai-sdk';
|
||||
|
||||
const hindsightClient = new HindsightClient({
|
||||
baseUrl: process.env.HINDSIGHT_API_URL!,
|
||||
});
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { messages, userId } = await req.json();
|
||||
|
||||
// Tools are created per-request, closing over the current user's bankId
|
||||
const tools = createHindsightTools({
|
||||
client: hindsightClient,
|
||||
bankId: userId,
|
||||
});
|
||||
|
||||
return streamText({
|
||||
model: openai('gpt-4o'),
|
||||
tools,
|
||||
maxSteps: 5,
|
||||
system: 'You are a helpful assistant with long-term memory.',
|
||||
messages,
|
||||
}).toDataStreamResponse();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tools Reference
|
||||
|
||||
Five tools are registered. The `bankId` is fixed at creation time—the agent cannot change it.
|
||||
|
||||
| Tool | What the agent provides | What the constructor controls |
|
||||
|------|------------------------|-------------------------------|
|
||||
| `retain` | `content`, `documentId`, `timestamp`, `context` | `async`, `tags`, `metadata` |
|
||||
| `recall` | `query`, `queryTimestamp` | `budget`, `types`, `maxTokens`, `includeEntities`, `includeChunks` |
|
||||
| `reflect` | `query`, `context` | `budget` |
|
||||
| `getMentalModel` | `mentalModelId` | — |
|
||||
| `getDocument` | `documentId` | — |
|
||||
|
||||
**Why this split?** Semantic inputs (what to remember, what to search for) belong to the agent. Infrastructure concerns (cost budget, tagging strategy, async mode) belong to the application.
|
||||
|
||||
---
|
||||
|
||||
## Constructor Options
|
||||
|
||||
All options except `client` and `bankId` are optional. Each tool's options are grouped under the tool name.
|
||||
|
||||
```typescript
|
||||
const tools = createHindsightTools({
|
||||
client,
|
||||
bankId: userId,
|
||||
|
||||
retain: {
|
||||
async: true, // fire-and-forget (default: false)
|
||||
tags: ['env:prod', 'app:support'], // always attached to every retained memory
|
||||
metadata: { version: '2.0' }, // always attached to every retained memory
|
||||
},
|
||||
|
||||
recall: {
|
||||
budget: 'high', // processing depth: low | mid | high (default: 'mid')
|
||||
types: ['experience', 'world'], // restrict to these fact types (default: all)
|
||||
maxTokens: 2048, // cap token budget (default: API default)
|
||||
includeEntities: true, // include entity observations (default: false)
|
||||
includeChunks: true, // include raw source chunks (default: false)
|
||||
},
|
||||
|
||||
reflect: {
|
||||
budget: 'mid', // processing depth (default: 'mid')
|
||||
},
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
### `retain`
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `async` | `boolean` | `false` | Fire-and-forget — do not wait for ingestion to complete |
|
||||
| `tags` | `string[]` | — | Tags attached to every retained memory |
|
||||
| `metadata` | `Record<string, string>` | — | Metadata attached to every retained memory |
|
||||
| `description` | `string` | built-in | Override the tool description shown to the model |
|
||||
|
||||
### `recall`
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `budget` | `'low' \| 'mid' \| 'high'` | `'mid'` | Controls retrieval depth and latency |
|
||||
| `types` | `('world' \| 'experience' \| 'observation')[]` | all | Restrict results to these fact types |
|
||||
| `maxTokens` | `number` | API default | Cap the total tokens returned |
|
||||
| `includeEntities` | `boolean` | `false` | Include entity observations in results |
|
||||
| `includeChunks` | `boolean` | `false` | Include raw source chunks in results |
|
||||
| `description` | `string` | built-in | Override the tool description shown to the model |
|
||||
|
||||
### `reflect`
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `budget` | `'low' \| 'mid' \| 'high'` | `'mid'` | Controls synthesis depth and latency |
|
||||
| `maxTokens` | `number` | API default | Maximum tokens for the response |
|
||||
| `description` | `string` | built-in | Override the tool description shown to the model |
|
||||
@@ -1,222 +0,0 @@
|
||||
---
|
||||
sidebar_position: 12
|
||||
---
|
||||
|
||||
# AutoGen
|
||||
|
||||
Persistent long-term memory for [AutoGen](https://microsoft.github.io/autogen/) agents via Hindsight. Provides `FunctionTool` instances that plug directly into AutoGen's `AssistantAgent`.
|
||||
|
||||
## Features
|
||||
|
||||
- **Memory Tools** — retain, recall, and reflect as AutoGen `FunctionTool` instances compatible with `AssistantAgent(tools=[...])`
|
||||
- **Async-Native** — Uses `aretain`, `arecall`, `areflect` directly — works seamlessly in AutoGen's async runtime
|
||||
- **Selective Tools** — Include only the tools you need with `include_retain/recall/reflect` flags
|
||||
- **Tag-Based Scoping** — Partition memories by topic, session, or user with tags
|
||||
- **Global Configuration** — Configure once with `configure()`, create tools anywhere
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-autogen autogen-agentchat "autogen-ext[openai]"
|
||||
```
|
||||
|
||||
`hindsight-autogen` pulls in `autogen-core` and `hindsight-client`. You also need `autogen-agentchat` for `AssistantAgent` and `autogen-ext[openai]` for the OpenAI model client.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_autogen import create_hindsight_tools
|
||||
|
||||
async def main():
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
await client.acreate_bank(bank_id="user-123")
|
||||
|
||||
model_client = OpenAIChatCompletionClient(model="gpt-4o")
|
||||
tools = create_hindsight_tools(client=client, bank_id="user-123")
|
||||
|
||||
agent = AssistantAgent(
|
||||
name="assistant",
|
||||
model_client=model_client,
|
||||
tools=tools,
|
||||
)
|
||||
|
||||
# Store a memory
|
||||
result = await agent.run(task="Remember that I prefer dark mode")
|
||||
print(result.messages[-1].content)
|
||||
|
||||
# Hindsight processes retained content asynchronously (fact extraction,
|
||||
# entity resolution, embeddings). A brief pause ensures memories are
|
||||
# searchable before the next recall. In production, this delay is only
|
||||
# needed when retain and recall happen back-to-back in the same script.
|
||||
await asyncio.sleep(3)
|
||||
|
||||
# Recall it later
|
||||
result = await agent.run(task="What are my UI preferences?")
|
||||
print(result.messages[-1].content)
|
||||
|
||||
# Clean up
|
||||
await client.aclose()
|
||||
await model_client.close()
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
:::tip Jupyter Notebooks
|
||||
If you're running in a Jupyter notebook, you don't need `asyncio.run()` — just use `await` directly in cells since the notebook already has an active event loop.
|
||||
:::
|
||||
|
||||
The agent gets three tools it can call:
|
||||
|
||||
- **`hindsight_retain`** — Store information to long-term memory
|
||||
- **`hindsight_recall`** — Search long-term memory for relevant facts
|
||||
- **`hindsight_reflect`** — Synthesize a reasoned answer from memories
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=True,
|
||||
include_recall=True,
|
||||
include_reflect=False, # Omit reflect
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing a client to every call, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_autogen import configure, create_hindsight_tools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode
|
||||
)
|
||||
|
||||
# Now create tools without passing client — uses global config
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
## Memory Scoping with Tags
|
||||
|
||||
Use tags to partition memories by topic, session, or user:
|
||||
|
||||
```python
|
||||
# Store memories tagged by source
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
tags=["source:chat", "session:abc"],
|
||||
recall_tags=["source:chat"],
|
||||
recall_tags_match="any",
|
||||
)
|
||||
```
|
||||
|
||||
## Production Patterns
|
||||
|
||||
### Error Handling
|
||||
|
||||
Tools raise `HindsightError` on failure, which AutoGen surfaces to the agent as a tool error. Wrap agent calls for graceful degradation:
|
||||
|
||||
```python
|
||||
from hindsight_autogen.errors import HindsightError
|
||||
|
||||
try:
|
||||
result = await agent.run(task="What do you remember about me?")
|
||||
except HindsightError as e:
|
||||
print(f"Memory operation failed: {e}")
|
||||
```
|
||||
|
||||
### Bank Lifecycle
|
||||
|
||||
Create banks before first use and clean up when done:
|
||||
|
||||
```python
|
||||
async def main():
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
# Create bank (idempotent)
|
||||
await client.acreate_bank(bank_id="user-123")
|
||||
|
||||
tools = create_hindsight_tools(client=client, bank_id="user-123")
|
||||
# ... use tools ...
|
||||
|
||||
# Optional: delete bank when no longer needed
|
||||
await client.adelete_bank(bank_id="user-123")
|
||||
```
|
||||
|
||||
### Multi-Agent Teams
|
||||
|
||||
Give each agent its own memory bank, or share a bank across a team:
|
||||
|
||||
```python
|
||||
# Per-agent memory
|
||||
researcher_tools = create_hindsight_tools(client=client, bank_id="researcher-memory")
|
||||
writer_tools = create_hindsight_tools(client=client, bank_id="writer-memory")
|
||||
|
||||
# Shared team memory
|
||||
shared_tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="team-shared",
|
||||
tags=["team:content"],
|
||||
)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `create_hindsight_tools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode (any/all/any\_strict/all\_strict) |
|
||||
| `retain_metadata` | `None` | Default metadata dict for retain operations |
|
||||
| `retain_document_id` | `None` | Default document\_id for retain (groups/upserts memories) |
|
||||
| `recall_types` | `None` | Fact types to filter (world, experience, opinion, observation) |
|
||||
| `recall_include_entities` | `False` | Include entity information in recall results |
|
||||
| `reflect_context` | `None` | Additional context for reflect operations |
|
||||
| `reflect_max_tokens` | `None` | Max tokens for reflect results (defaults to `max_tokens`) |
|
||||
| `reflect_response_schema` | `None` | JSON schema to constrain reflect output format |
|
||||
| `reflect_tags` | `None` | Tags to filter memories used in reflect (defaults to `recall_tags`) |
|
||||
| `reflect_tags_match` | `None` | Tag matching for reflect (defaults to `recall_tags_match`) |
|
||||
| `include_retain` | `True` | Include the retain (store) tool |
|
||||
| `include_recall` | `True` | Include the recall (search) tool |
|
||||
| `include_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- autogen-core >= 0.4.0
|
||||
- hindsight-client >= 0.4.0
|
||||
@@ -1,167 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "Vercel Chat SDK Persistent Memory with Hindsight | Integration"
|
||||
description: "Give your Vercel Chat SDK bot persistent, per-user memory across Slack, Discord, Teams, and more. Single handler wrapper, no custom plumbing required."
|
||||
---
|
||||
|
||||
# Vercel Chat SDK
|
||||
|
||||
We built `@vectorize-io/hindsight-chat` to give [Vercel Chat SDK](https://github.com/vercel/chat) bots persistent, per-user memory with a single handler wrapper. The integration works across Slack, Discord, Teams, Google Chat, GitHub, and Linear — no custom plumbing required.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/chat.md)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @vectorize-io/hindsight-chat
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { Chat } from 'chat';
|
||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
||||
import { withHindsightChat } from '@vectorize-io/hindsight-chat';
|
||||
import { streamText } from 'ai';
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
|
||||
const chat = new Chat({ connectors: [/* your connectors */] });
|
||||
const hindsight = new HindsightClient({ apiKey: process.env.HINDSIGHT_API_KEY });
|
||||
|
||||
chat.onNewMention(
|
||||
withHindsightChat(
|
||||
{
|
||||
client: hindsight,
|
||||
bankId: (msg) => msg.author.userId, // per-user memory
|
||||
},
|
||||
async (thread, message, ctx) => {
|
||||
await thread.subscribe();
|
||||
|
||||
const result = await streamText({
|
||||
model: openai('gpt-4o'),
|
||||
system: ctx.memoriesAsSystemPrompt(),
|
||||
messages: [{ role: 'user', content: message.text }],
|
||||
});
|
||||
|
||||
// Stream the response
|
||||
const chunks: string[] = [];
|
||||
for await (const chunk of result.textStream) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
const fullResponse = chunks.join('');
|
||||
await thread.post(fullResponse);
|
||||
|
||||
// Store the conversation in memory
|
||||
await ctx.retain(
|
||||
`User: ${message.text}\nAssistant: ${fullResponse}`
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### `withHindsightChat(options, handler)`
|
||||
|
||||
`withHindsightChat` wraps your existing Chat SDK handler and injects memory context automatically. It returns a standard handler `(thread, message) => Promise<void>` so it drops in without changing your handler signature.
|
||||
|
||||
#### Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `client` | `HindsightClient` | *required* | Hindsight client instance |
|
||||
| `bankId` | `string \| (msg) => string` | *required* | Memory bank ID or resolver function |
|
||||
| `recall.enabled` | `boolean` | `true` | Auto-recall memories before handler |
|
||||
| `recall.budget` | `'low' \| 'mid' \| 'high'` | `'mid'` | Processing budget for recall |
|
||||
| `recall.maxTokens` | `number` | API default | Max tokens for recall results |
|
||||
| `recall.types` | `FactType[]` | all | Filter to specific fact types |
|
||||
| `recall.includeEntities` | `boolean` | `true` | Include entity observations |
|
||||
| `retain.enabled` | `boolean` | `false` | Auto-retain inbound messages |
|
||||
| `retain.async` | `boolean` | `true` | Fire-and-forget retain |
|
||||
| `retain.tags` | `string[]` | – | Tags for retained memories |
|
||||
| `retain.metadata` | `Record<string, string>` | – | Metadata for retained memories |
|
||||
|
||||
### Context (`ctx`)
|
||||
|
||||
We inject a third `ctx` argument into your handler that exposes the full Hindsight memory API scoped to the current user's bank:
|
||||
|
||||
| Property/Method | Description |
|
||||
|----------------|-------------|
|
||||
| `ctx.bankId` | Resolved bank ID |
|
||||
| `ctx.memories` | Array of recalled memories |
|
||||
| `ctx.entities` | Entity observations (or null) |
|
||||
| `ctx.memoriesAsSystemPrompt(options?)` | Format memories for LLM system prompt |
|
||||
| `ctx.retain(content, options?)` | Store content in memory |
|
||||
| `ctx.recall(query, options?)` | Search memories |
|
||||
| `ctx.reflect(query, options?)` | Reason over memories |
|
||||
|
||||
## Examples
|
||||
|
||||
### Subscribed Message Handler
|
||||
|
||||
```typescript
|
||||
chat.onSubscribedMessage(
|
||||
withHindsightChat(
|
||||
{
|
||||
client: hindsight,
|
||||
bankId: (msg) => msg.author.userId,
|
||||
recall: { budget: 'high', maxTokens: 1000 },
|
||||
},
|
||||
async (thread, message, ctx) => {
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4o'),
|
||||
system: ctx.memoriesAsSystemPrompt(),
|
||||
messages: [{ role: 'user', content: message.text }],
|
||||
});
|
||||
await thread.post(result.text);
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### Auto-Retain Inbound Messages
|
||||
|
||||
```typescript
|
||||
chat.onNewMention(
|
||||
withHindsightChat(
|
||||
{
|
||||
client: hindsight,
|
||||
bankId: (msg) => msg.author.userId,
|
||||
retain: { enabled: true, tags: ['slack', 'inbound'] },
|
||||
},
|
||||
async (thread, message, ctx) => {
|
||||
// Inbound message is already being retained automatically
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4o'),
|
||||
system: ctx.memoriesAsSystemPrompt(),
|
||||
messages: [{ role: 'user', content: message.text }],
|
||||
});
|
||||
await thread.post(result.text);
|
||||
|
||||
// Retain the assistant response separately
|
||||
await ctx.retain(`Assistant: ${result.text}`, {
|
||||
tags: ['slack', 'outbound'],
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### Static Bank ID (Shared Memory)
|
||||
|
||||
```typescript
|
||||
// All users share the same memory bank
|
||||
chat.onNewMention(
|
||||
withHindsightChat(
|
||||
{ client: hindsight, bankId: 'shared-team-memory' },
|
||||
async (thread, message, ctx) => {
|
||||
// ...
|
||||
}
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
We designed the integration so that memory failures never break your bot. Auto-recall and auto-retain errors are caught internally, logged as warnings, and the handler continues with empty memories. Manual `ctx.retain()`, `ctx.recall()`, and `ctx.reflect()` calls propagate errors normally so you can handle them as needed.
|
||||
@@ -1,216 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "Claude Code Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Claude Code with Hindsight. Automatically captures conversations and recalls relevant context across sessions using Claude Code's hook-based architecture."
|
||||
---
|
||||
|
||||
# Claude Code
|
||||
|
||||
Biomimetic long-term memory for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) using [Hindsight](https://vectorize.io/hindsight). Automatically captures conversations and intelligently recalls relevant context — a complete port of [`hindsight-openclaw`](./openclaw) adapted to Claude Code's hook-based plugin architecture.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/claude-code.md)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Add the Hindsight marketplace and install the plugin
|
||||
claude plugin marketplace add vectorize-io/hindsight
|
||||
claude plugin install hindsight-memory
|
||||
|
||||
# 2. Configure your LLM provider for memory extraction
|
||||
# Option A: OpenAI (auto-detected)
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option B: Anthropic (auto-detected)
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
|
||||
# Option C: No API key needed (uses Claude Code's own model — personal/local use only)
|
||||
export HINDSIGHT_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option D: Connect to an external Hindsight server instead of running locally
|
||||
mkdir -p ~/.hindsight
|
||||
echo '{"hindsightApiUrl": "https://your-hindsight-server.com"}' > ~/.hindsight/claude-code.json
|
||||
|
||||
# 3. Start Claude Code — the plugin activates automatically
|
||||
claude
|
||||
```
|
||||
|
||||
That's it! The plugin will automatically start capturing and recalling memories.
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-recall** — on every user prompt, queries Hindsight for relevant memories and injects them as context (invisible to the chat transcript, visible to Claude)
|
||||
- **Auto-retain** — after every response (or every N turns), extracts and retains conversation content to Hindsight for long-term storage
|
||||
- **Daemon management** — can auto-start/stop `hindsight-embed` locally or connect to an external Hindsight server
|
||||
- **Dynamic bank IDs** — supports per-agent, per-project, or per-session memory isolation
|
||||
- **Channel-agnostic** — works with Claude Code Channels (Telegram, Discord, Slack) or interactive sessions
|
||||
- **Zero dependencies** — pure Python stdlib, no pip install required
|
||||
|
||||
## Architecture
|
||||
|
||||
The plugin uses all four Claude Code hook events:
|
||||
|
||||
| Hook | Event | Purpose |
|
||||
|------|-------|---------|
|
||||
| `session_start.py` | `SessionStart` | Health check — verify Hindsight is reachable |
|
||||
| `recall.py` | `UserPromptSubmit` | **Auto-recall** — query memories, inject as `additionalContext` |
|
||||
| `retain.py` | `Stop` | **Auto-retain** — extract transcript, POST to Hindsight (async) |
|
||||
| `session_end.py` | `SessionEnd` | Cleanup — stop auto-managed daemon if started |
|
||||
|
||||
## Connection Modes
|
||||
|
||||
### 1. External API (recommended for production)
|
||||
|
||||
Connect to a running Hindsight server (cloud or self-hosted). No local LLM needed — the server handles fact extraction.
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "https://your-hindsight-server.com",
|
||||
"hindsightApiToken": "your-token"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Local Daemon (auto-managed)
|
||||
|
||||
The plugin automatically starts and stops `hindsight-embed` via `uvx`. Requires an LLM provider API key for local fact extraction.
|
||||
|
||||
Set an LLM provider:
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
# or
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
# or
|
||||
export HINDSIGHT_LLM_PROVIDER=claude-code # No API key needed
|
||||
```
|
||||
|
||||
The model is selected automatically by the Hindsight API. To override, set `HINDSIGHT_LLM_MODEL`.
|
||||
|
||||
### 3. Existing Local Server
|
||||
|
||||
If you already have `hindsight-embed` running, leave `hindsightApiUrl` empty and set `apiPort` to match your server's port. The plugin will detect it automatically.
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings live in `~/.hindsight/claude-code.json`. Every setting can also be overridden via environment variables. The plugin ships with sensible defaults — you only need to configure what you want to change.
|
||||
|
||||
**Loading order** (later entries win):
|
||||
1. Built-in defaults (hardcoded in the plugin)
|
||||
2. Plugin `settings.json` (ships with the plugin, at `CLAUDE_PLUGIN_ROOT/settings.json`)
|
||||
3. User config (`~/.hindsight/claude-code.json` — recommended for your overrides)
|
||||
4. Environment variables
|
||||
|
||||
---
|
||||
|
||||
### Connection & Daemon
|
||||
|
||||
These settings control how the plugin connects to the Hindsight API.
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `hindsightApiUrl` | `HINDSIGHT_API_URL` | `""` (empty) | URL of an external Hindsight API server. When empty, the plugin uses a local daemon instead. |
|
||||
| `hindsightApiToken` | `HINDSIGHT_API_TOKEN` | `null` | Authentication token for the external API. Only needed when `hindsightApiUrl` is set. |
|
||||
| `apiPort` | `HINDSIGHT_API_PORT` | `9077` | Port used by the local `hindsight-embed` daemon. Change this if you run multiple instances or have a port conflict. |
|
||||
| `daemonIdleTimeout` | `HINDSIGHT_DAEMON_IDLE_TIMEOUT` | `0` | Seconds of inactivity before the local daemon shuts itself down. `0` means the daemon stays running until the session ends. |
|
||||
| `embedVersion` | `HINDSIGHT_EMBED_VERSION` | `"latest"` | Which version of `hindsight-embed` to install via `uvx`. Pin to a specific version (e.g. `"0.5.2"`) for reproducibility. |
|
||||
| `embedPackagePath` | `HINDSIGHT_EMBED_PACKAGE_PATH` | `null` | Local filesystem path to a `hindsight-embed` checkout. When set, the plugin runs from this path instead of installing via `uvx`. Useful for development. |
|
||||
|
||||
---
|
||||
|
||||
### LLM Provider (local daemon only)
|
||||
|
||||
These settings configure which LLM the local daemon uses for fact extraction. They are **ignored** when connecting to an external API (the server uses its own LLM configuration).
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `llmProvider` | `HINDSIGHT_LLM_PROVIDER` | auto-detect | Which LLM provider to use. Supported values: `openai`, `anthropic`, `gemini`, `groq`, `ollama`, `openai-codex`, `claude-code`. When omitted, the plugin auto-detects by checking for API key env vars in order: `OPENAI_API_KEY` → `ANTHROPIC_API_KEY` → `GEMINI_API_KEY` → `GROQ_API_KEY`. |
|
||||
| `llmModel` | `HINDSIGHT_LLM_MODEL` | provider default | Override the default model for the chosen provider (e.g. `"gpt-4o"`, `"claude-sonnet-4-20250514"`). When omitted, the Hindsight API picks a sensible default for each provider. |
|
||||
| `llmApiKeyEnv` | — | provider standard | Name of the environment variable that holds the API key. Normally auto-detected (e.g. `OPENAI_API_KEY` for the `openai` provider). Set this only if your key is in a non-standard env var. |
|
||||
|
||||
---
|
||||
|
||||
### Memory Bank
|
||||
|
||||
A **bank** is an isolated memory store — like a separate "brain." These settings control which bank the plugin reads from and writes to.
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `bankId` | `HINDSIGHT_BANK_ID` | `"claude_code"` | The bank ID to use when `dynamicBankId` is `false`. All sessions share this single bank. |
|
||||
| `bankMission` | `HINDSIGHT_BANK_MISSION` | generic assistant prompt | A short description of the agent's identity and purpose. Sent to Hindsight when creating or updating the bank, and used during recall to contextualize results. |
|
||||
| `retainMission` | — | extraction prompt | Instructions for the fact extraction LLM — tells it *what* to extract from conversations (e.g. "Extract technical decisions and user preferences"). |
|
||||
| `dynamicBankId` | `HINDSIGHT_DYNAMIC_BANK_ID` | `false` | When `true`, the plugin derives a unique bank ID from context fields (see `dynamicBankGranularity`), giving each combination its own isolated memory. |
|
||||
| `dynamicBankGranularity` | — | `["agent", "project"]` | Which context fields to combine when building a dynamic bank ID. Available fields: `agent` (agent name), `project` (working directory), `session` (session ID), `channel` (channel ID), `user` (user ID). |
|
||||
| `bankIdPrefix` | — | `""` | A string prepended to all bank IDs — both static and dynamic. Useful for namespacing (e.g. `"prod"` or `"staging"`). |
|
||||
| `agentName` | `HINDSIGHT_AGENT_NAME` | `"claude-code"` | Name used for the `agent` field in dynamic bank ID derivation. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Recall
|
||||
|
||||
Auto-recall runs on every user prompt. It queries Hindsight for relevant memories and injects them into Claude's context as invisible `additionalContext` (the user doesn't see them in the chat transcript).
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRecall` | `HINDSIGHT_AUTO_RECALL` | `true` | Master switch for auto-recall. Set to `false` to disable memory retrieval entirely. |
|
||||
| `recallBudget` | `HINDSIGHT_RECALL_BUDGET` | `"mid"` | Controls how hard Hindsight searches for memories. `"low"` = fast, fewer strategies; `"mid"` = balanced; `"high"` = thorough, slower. Affects latency directly. |
|
||||
| `recallMaxTokens` | `HINDSIGHT_RECALL_MAX_TOKENS` | `1024` | Maximum number of tokens in the recalled memory block. Lower values reduce context usage but may truncate relevant memories. |
|
||||
| `recallTypes` | — | `["world", "experience"]` | Which memory types to retrieve. `"world"` = general facts; `"experience"` = personal experiences; `"observation"` = raw observations. |
|
||||
| `recallContextTurns` | `HINDSIGHT_RECALL_CONTEXT_TURNS` | `1` | How many prior conversation turns to include when composing the recall query. `1` = only the latest user message; higher values give more context but may dilute the query. |
|
||||
| `recallMaxQueryChars` | `HINDSIGHT_RECALL_MAX_QUERY_CHARS` | `800` | Maximum character length of the query sent to Hindsight. Longer queries are truncated. |
|
||||
| `recallRoles` | — | `["user", "assistant"]` | Which message roles to include when building the recall query from prior turns. |
|
||||
| `recallPromptPreamble` | — | built-in string | Text placed above the recalled memories in the injected context block. Customize this to change how Claude interprets the memories. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Retain
|
||||
|
||||
Auto-retain runs after Claude responds. It extracts the conversation transcript and sends it to Hindsight for long-term storage and fact extraction.
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRetain` | `HINDSIGHT_AUTO_RETAIN` | `true` | Master switch for auto-retain. Set to `false` to disable memory storage entirely. |
|
||||
| `retainMode` | `HINDSIGHT_RETAIN_MODE` | `"full-session"` | Retention strategy. `"full-session"` sends the full conversation transcript (with chunking). |
|
||||
| `retainEveryNTurns` | — | `10` | How often to retain. `1` = every turn; `10` = every 10th turn. Higher values reduce API calls but delay memory capture. Values > 1 enable **chunked retention** with a sliding window. |
|
||||
| `retainOverlapTurns` | — | `2` | When chunked retention fires, this many extra turns from the previous chunk are included for continuity. Total window size = `retainEveryNTurns + retainOverlapTurns`. |
|
||||
| `retainRoles` | — | `["user", "assistant"]` | Which message roles to include in the retained transcript. |
|
||||
| `retainToolCalls` | — | `true` | Whether to include tool calls (function invocations and results) in the retained transcript. Captures structured actions like file reads, searches, and code edits. |
|
||||
| `retainTags` | — | `["{session_id}"]` | Tags attached to the retained document. Supports `{session_id}` placeholder which is replaced with the current session ID at runtime. |
|
||||
| `retainMetadata` | — | `{}` | Arbitrary key-value metadata attached to the retained document. |
|
||||
| `retainContext` | — | `"claude-code"` | A label attached to retained memories identifying their source. Useful when multiple integrations write to the same bank. |
|
||||
|
||||
---
|
||||
|
||||
### Debug
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `debug` | `HINDSIGHT_DEBUG` | `false` | Enable verbose logging to stderr. All log lines are prefixed with `[Hindsight]`. Useful for diagnosing connection issues, recall/retain behavior, and bank ID derivation. |
|
||||
|
||||
## Claude Code Channels
|
||||
|
||||
With [Claude Code Channels](https://docs.anthropic.com/en/docs/claude-code), Claude Code can operate as a persistent background agent connected to Telegram, Discord, Slack, and other messaging platforms. This plugin gives Channel-based agents the same long-term memory that `hindsight-openclaw` provides for Openclaw agents.
|
||||
|
||||
For Channel agents, enable dynamic bank IDs for per-channel/per-user memory isolation:
|
||||
|
||||
```json
|
||||
{
|
||||
"dynamicBankId": true,
|
||||
"dynamicBankGranularity": ["agent", "channel", "user"]
|
||||
}
|
||||
```
|
||||
|
||||
And set channel context via environment variables:
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_CHANNEL_ID="telegram-group-12345"
|
||||
export HINDSIGHT_USER_ID="user-67890"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Plugin not activating**: Check Claude Code logs for `[Hindsight]` messages. Enable `"debug": true` in `~/.hindsight/claude-code.json`.
|
||||
|
||||
**Recall returning no memories**: Verify the Hindsight server is reachable (`curl http://localhost:9077/health`). Memories need at least one retain cycle before they're available.
|
||||
|
||||
**Daemon not starting**: Ensure an LLM API key is set (or use `HINDSIGHT_LLM_PROVIDER=claude-code`). Review daemon logs at `~/.hindsight/profiles/claude-code.log`.
|
||||
|
||||
**High latency on recall**: The recall hook has a 12-second timeout. Use `recallBudget: "low"` or reduce `recallMaxTokens` for faster responses.
|
||||
@@ -1,184 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
title: "Codex CLI Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to OpenAI Codex CLI with Hindsight. Three Python hook scripts automatically recall context before each prompt and retain conversations — no workflow changes required."
|
||||
---
|
||||
|
||||
# Codex
|
||||
|
||||
[View Changelog →](../../changelog/integrations/codex.md)
|
||||
|
||||
Persistent memory for [Codex CLI](https://github.com/openai/codex) using [Hindsight](https://vectorize.io/hindsight). Three Python hook scripts automatically recall relevant context before each prompt and retain conversations after each turn — no changes to your Codex workflow required.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-codex | bash
|
||||
```
|
||||
|
||||
The installer will guide you through choosing local or cloud mode and configuring your connection. Once installed, start a new Codex session — memory is live.
|
||||
|
||||
To uninstall:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-codex | bash -s -- --uninstall
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-recall** — on every user prompt, queries Hindsight for relevant memories and injects them as `additionalContext` (invisible to the transcript, visible to Codex)
|
||||
- **Auto-retain** — after each Codex response, stores the conversation transcript to Hindsight for future recall
|
||||
- **Dynamic bank IDs** — supports per-project memory isolation based on the working directory
|
||||
- **Session-level upsert** — uses the session ID as the document ID so re-running the same session updates rather than duplicates stored content
|
||||
- **Zero dependencies** — pure Python stdlib, no pip install required
|
||||
|
||||
## Architecture
|
||||
|
||||
The plugin uses three Codex hook events:
|
||||
|
||||
| Hook | Event | Purpose |
|
||||
|------|-------|---------|
|
||||
| `session_start.py` | `SessionStart` | Warm up — verify Hindsight is reachable |
|
||||
| `recall.py` | `UserPromptSubmit` | **Auto-recall** — query memories, inject as `additionalContext` |
|
||||
| `retain.py` | `Stop` | **Auto-retain** — extract transcript, POST to Hindsight (async) |
|
||||
|
||||
On `UserPromptSubmit`, the hook reads the prompt, queries Hindsight for the most relevant memories, and outputs a `hookSpecificOutput.additionalContext` block. Codex prepends this to the conversation before sending it to the model:
|
||||
|
||||
```
|
||||
<hindsight_memories>
|
||||
Relevant memories from past conversations...
|
||||
Current time - 2026-03-27 09:14
|
||||
|
||||
- Project uses FastAPI with asyncpg — not SQLAlchemy [world] (2026-03-26)
|
||||
- Preferred testing framework: pytest with pytest-asyncio [experience] (2026-03-26)
|
||||
</hindsight_memories>
|
||||
```
|
||||
|
||||
On `Stop`, the hook reads the session transcript, strips previously injected memory tags (to prevent feedback loops), and POSTs the conversation to Hindsight asynchronously.
|
||||
|
||||
## Connection Modes
|
||||
|
||||
### 1. External API (recommended)
|
||||
|
||||
Connect to a running Hindsight server (cloud or self-hosted):
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "https://api.hindsight.vectorize.io",
|
||||
"hindsightApiToken": "hsk_your_token"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Local Daemon
|
||||
|
||||
Run `hindsight-embed` locally. The `session_start.py` hook will detect it on `apiPort` (default `9077`). The daemon is not auto-started by the Codex plugin — start it separately:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed
|
||||
```
|
||||
|
||||
Then leave `hindsightApiUrl` empty in your config and the plugin will connect to `http://localhost:9077`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Settings are loaded from `~/.hindsight/codex.json`. Every setting can also be overridden via environment variable.
|
||||
|
||||
**Loading order** (later entries win):
|
||||
|
||||
1. Built-in defaults
|
||||
2. Plugin `settings.json` (at `~/.hindsight/codex/settings.json`)
|
||||
3. User config (`~/.hindsight/codex.json`)
|
||||
4. Environment variables
|
||||
|
||||
---
|
||||
|
||||
### Connection
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `hindsightApiUrl` | `HINDSIGHT_API_URL` | `""` | URL of the Hindsight API server. Required. |
|
||||
| `hindsightApiToken` | `HINDSIGHT_API_TOKEN` | `null` | API token for authentication. Required for Hindsight Cloud. |
|
||||
| `apiPort` | `HINDSIGHT_API_PORT` | `9077` | Port for the local `hindsight-embed` daemon. |
|
||||
|
||||
---
|
||||
|
||||
### Memory Bank
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `bankId` | `HINDSIGHT_BANK_ID` | `"codex"` | The bank to read from and write to. All sessions share this bank unless `dynamicBankId` is enabled. |
|
||||
| `bankMission` | `HINDSIGHT_BANK_MISSION` | coding assistant prompt | Describes the agent's purpose. Sent when creating or updating the bank. |
|
||||
| `retainMission` | — | extraction prompt | Instructions for Hindsight's fact extraction — what to extract from coding conversations. |
|
||||
| `dynamicBankId` | `HINDSIGHT_DYNAMIC_BANK_ID` | `false` | When `true`, derives a unique bank ID from `dynamicBankGranularity` fields — useful for per-project isolation. |
|
||||
| `dynamicBankGranularity` | — | `["agent", "project"]` | Which fields to combine for dynamic bank IDs. `"project"` = working directory, `"agent"` = agent name. |
|
||||
| `bankIdPrefix` | — | `""` | Prefix prepended to all bank IDs. |
|
||||
| `agentName` | `HINDSIGHT_AGENT_NAME` | `"codex"` | Agent name used in dynamic bank ID derivation. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Recall
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRecall` | `HINDSIGHT_AUTO_RECALL` | `true` | Master switch for auto-recall. |
|
||||
| `recallBudget` | `HINDSIGHT_RECALL_BUDGET` | `"mid"` | Search depth: `"low"` (fast), `"mid"` (balanced), `"high"` (thorough). |
|
||||
| `recallMaxTokens` | `HINDSIGHT_RECALL_MAX_TOKENS` | `1024` | Max tokens in the recalled memory block. |
|
||||
| `recallTypes` | — | `["world", "experience"]` | Memory types to retrieve. |
|
||||
| `recallContextTurns` | `HINDSIGHT_RECALL_CONTEXT_TURNS` | `1` | Prior turns to include when building the recall query. `1` = latest prompt only. |
|
||||
| `recallMaxQueryChars` | `HINDSIGHT_RECALL_MAX_QUERY_CHARS` | `800` | Max characters in the query sent to Hindsight. |
|
||||
| `recallRoles` | — | `["user", "assistant"]` | Which roles to include when building a multi-turn query. |
|
||||
| `recallPromptPreamble` | — | built-in | Text placed above the recalled memories in the injected context block. |
|
||||
|
||||
---
|
||||
|
||||
### Auto-Retain
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRetain` | `HINDSIGHT_AUTO_RETAIN` | `true` | Master switch for auto-retain. |
|
||||
| `retainMode` | `HINDSIGHT_RETAIN_MODE` | `"full-session"` | `"full-session"` sends the full transcript per session (upserted by session ID). `"chunked"` sends sliding windows every N turns. |
|
||||
| `retainEveryNTurns` | — | `10` | Retain fires every N turns. `1` = every turn. Higher values reduce API calls. |
|
||||
| `retainOverlapTurns` | — | `2` | Extra turns included from the previous chunk (chunked mode only). |
|
||||
| `retainRoles` | — | `["user", "assistant"]` | Which roles to include in the retained transcript. |
|
||||
| `retainTags` | — | `["{session_id}"]` | Tags attached to the stored document. `{session_id}` is replaced at runtime. |
|
||||
| `retainMetadata` | — | `{}` | Arbitrary key-value metadata attached to the stored document. |
|
||||
| `retainContext` | — | `"codex"` | Label identifying the source integration. Useful when multiple integrations write to the same bank. |
|
||||
|
||||
---
|
||||
|
||||
### Debug
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `debug` | `HINDSIGHT_DEBUG` | `false` | Enable verbose logging to stderr. All log lines are prefixed with `[Hindsight]`. |
|
||||
|
||||
## Per-Project Memory
|
||||
|
||||
To give each project its own isolated memory bank, enable dynamic bank IDs:
|
||||
|
||||
```json
|
||||
{
|
||||
"dynamicBankId": true,
|
||||
"dynamicBankGranularity": ["agent", "project"]
|
||||
}
|
||||
```
|
||||
|
||||
With this config, running Codex in `~/projects/api` and `~/projects/frontend` stores and recalls memories separately. Bank IDs are derived from the working directory path.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Hooks not firing**: Check that `~/.codex/config.toml` contains `codex_hooks = true` under `[features]`. Re-run the installer to fix this automatically.
|
||||
|
||||
**No memories recalled**: Recall returns results only after something has been retained. Either complete one Codex session first, or seed your bank manually using the [cookbook example](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/codex-memory).
|
||||
|
||||
**Memory not being stored**: `retainEveryNTurns` defaults to `10` — retain only fires every 10 turns. While testing, add `"retainEveryNTurns": 1` to `~/.hindsight/codex.json`.
|
||||
|
||||
**Debug mode**: Add `"debug": true` to `~/.hindsight/codex.json` to see what Hindsight is doing on each turn:
|
||||
|
||||
```
|
||||
[Hindsight] Recalling from bank 'codex', query length: 42
|
||||
[Hindsight] Injecting 3 memories
|
||||
[Hindsight] Retaining to bank 'codex', doc 'sess-abc123', 2 messages, 847 chars
|
||||
```
|
||||
|
||||
**High latency on recall**: Use `"recallBudget": "low"` or reduce `recallMaxTokens` to speed up recall queries.
|
||||
@@ -1,245 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "CrewAI Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add long-term memory to your CrewAI agent crews. Hindsight provides fact extraction, entity tracking, and temporal awareness — persisted automatically across all crew runs."
|
||||
---
|
||||
|
||||
# CrewAI
|
||||
|
||||
Persistent memory for AI agent crews via [CrewAI](https://github.com/crewAIInc/crewAI). Give your crews long-term memory with fact extraction, entity tracking, and temporal awareness.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/crewai.md)
|
||||
|
||||
## Features
|
||||
|
||||
- **Drop-in Storage Backend** - Implements CrewAI's `Storage` interface for `ExternalMemory`
|
||||
- **Automatic Memory Flow** - CrewAI automatically stores task outputs and retrieves relevant memories
|
||||
- **Per-Agent Banks** - Optionally give each agent its own isolated memory bank
|
||||
- **Reflect Tool** - Agents can explicitly reason over memories with disposition-aware synthesis
|
||||
- **Simple Configuration** - Configure once, use everywhere
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-crewai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from hindsight_crewai import configure, HindsightStorage
|
||||
from crewai.memory.external.external_memory import ExternalMemory
|
||||
from crewai import Agent, Crew, Task
|
||||
|
||||
configure(hindsight_api_url="http://localhost:8888")
|
||||
|
||||
crew = Crew(
|
||||
agents=[Agent(role="Researcher", goal="Find information", backstory="...")],
|
||||
tasks=[Task(description="Research AI trends", expected_output="Report")],
|
||||
external_memory=ExternalMemory(
|
||||
storage=HindsightStorage(bank_id="my-crew")
|
||||
),
|
||||
)
|
||||
|
||||
crew.kickoff()
|
||||
```
|
||||
|
||||
That's it. CrewAI will automatically:
|
||||
- **Query memories** at the start of each task
|
||||
- **Store task outputs** to Hindsight after each task completes
|
||||
|
||||
Memories persist across crew runs, so your crew learns over time.
|
||||
|
||||
## How It Works
|
||||
|
||||
The integration maps CrewAI's 3-method `Storage` interface to Hindsight's API:
|
||||
|
||||
| CrewAI | Hindsight | What happens |
|
||||
|--------|-----------|--------------|
|
||||
| `save(value, metadata, agent)` | `retain(bank_id, content, ...)` | Task output is stored. Hindsight extracts facts, entities, and relationships from the raw text. |
|
||||
| `search(query, limit)` | `recall(bank_id, query, ...)` | CrewAI constructs a query from the task description. Hindsight runs semantic search, BM25, graph traversal, and reranking. |
|
||||
| `reset()` | `delete_bank(bank_id)` | Wipes the bank and optionally recreates it with its original mission. |
|
||||
|
||||
CrewAI calls `search()` automatically at the start of each task and `save()` after each task completes.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```python
|
||||
from hindsight_crewai import configure
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888", # Hindsight API URL
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: "low", "mid", "high"
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match: any/all/any_strict/all_strict
|
||||
verbose=True, # Enable logging
|
||||
)
|
||||
```
|
||||
|
||||
### Per-Storage Overrides
|
||||
|
||||
Constructor arguments override global configuration:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
budget="high",
|
||||
max_tokens=8192,
|
||||
tags=["team:alpha"],
|
||||
)
|
||||
```
|
||||
|
||||
## Bank Missions
|
||||
|
||||
Set a mission to guide how Hindsight processes and organizes memories:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
mission="Track software architecture decisions, technical debt, and team preferences.",
|
||||
)
|
||||
```
|
||||
|
||||
## Per-Agent Memory Banks
|
||||
|
||||
Give each agent its own isolated memory bank:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
per_agent_banks=True,
|
||||
# Researcher -> "my-crew-researcher"
|
||||
# Writer -> "my-crew-writer"
|
||||
)
|
||||
```
|
||||
|
||||
Or use a custom bank resolver for full control:
|
||||
|
||||
```python
|
||||
storage = HindsightStorage(
|
||||
bank_id="my-crew",
|
||||
bank_resolver=lambda base, agent: f"{base}-{agent.lower()}" if agent else base,
|
||||
)
|
||||
```
|
||||
|
||||
:::info
|
||||
When `per_agent_banks=True`, the automatic `search()` at task start queries the base bank (shared context), since CrewAI's `search()` method does not receive the agent parameter. For per-agent search isolation, create separate `HindsightStorage` instances per agent.
|
||||
:::
|
||||
|
||||
## Reflect Tool
|
||||
|
||||
CrewAI's storage interface only supports save/search/reset. To give agents access to Hindsight's `reflect` (disposition-aware memory synthesis), add it as a tool:
|
||||
|
||||
```python
|
||||
from hindsight_crewai import HindsightReflectTool
|
||||
|
||||
reflect_tool = HindsightReflectTool(
|
||||
bank_id="my-crew",
|
||||
budget="mid",
|
||||
reflect_context="You are helping a software team track decisions.",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
role="Analyst",
|
||||
goal="Analyze project history",
|
||||
backstory="...",
|
||||
tools=[reflect_tool],
|
||||
)
|
||||
```
|
||||
|
||||
When the agent calls this tool, it gets a synthesized, contextual answer based on all relevant memories rather than raw fact snippets.
|
||||
|
||||
## Full Example
|
||||
|
||||
A research crew that remembers findings across runs:
|
||||
|
||||
```python
|
||||
from hindsight_crewai import configure, HindsightStorage, HindsightReflectTool
|
||||
from crewai.memory.external.external_memory import ExternalMemory
|
||||
from crewai import Agent, Crew, Task
|
||||
|
||||
configure(hindsight_api_url="http://localhost:8888")
|
||||
|
||||
storage = HindsightStorage(
|
||||
bank_id="research-crew",
|
||||
mission="Track technology research findings and comparisons.",
|
||||
)
|
||||
|
||||
reflect_tool = HindsightReflectTool(bank_id="research-crew", budget="mid")
|
||||
|
||||
researcher = Agent(
|
||||
role="Researcher",
|
||||
goal="Research topics, building on prior knowledge.",
|
||||
backstory="Before starting, use hindsight_reflect to check what you already know.",
|
||||
tools=[reflect_tool],
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
role="Writer",
|
||||
goal="Write summaries incorporating prior findings.",
|
||||
backstory="Use hindsight_reflect to recall prior research.",
|
||||
tools=[reflect_tool],
|
||||
)
|
||||
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
tasks=[
|
||||
Task(description="Research the benefits of Rust", expected_output="Analysis", agent=researcher),
|
||||
Task(description="Write an executive summary", expected_output="Summary", agent=writer),
|
||||
],
|
||||
external_memory=ExternalMemory(storage=storage),
|
||||
)
|
||||
|
||||
# Run 1: researches Rust, stores findings
|
||||
crew.kickoff()
|
||||
|
||||
# Run 2: recalls Rust research when comparing with Go
|
||||
crew.tasks[0].description = "Compare Rust with Go"
|
||||
crew.kickoff()
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Configuration
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `configure(...)` | Set global connection and default settings |
|
||||
| `get_config()` | Get current configuration |
|
||||
| `reset_config()` | Reset configuration to None |
|
||||
|
||||
### Storage
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `bank_id` | required | Hindsight memory bank ID |
|
||||
| `hindsight_api_url` | from config | Override API URL |
|
||||
| `api_key` | from config | Override API key |
|
||||
| `budget` | `"mid"` | Recall budget (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Max tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `per_agent_banks` | `False` | Give each agent its own bank |
|
||||
| `bank_resolver` | `None` | Custom `(bank_id, agent) -> bank_id` |
|
||||
| `mission` | `None` | Bank mission for memory organization |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
### Reflect Tool
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `bank_id` | required | Hindsight memory bank ID |
|
||||
| `budget` | `"mid"` | Reflect budget (low/mid/high) |
|
||||
| `reflect_context` | `None` | Additional context for reasoning |
|
||||
| `hindsight_api_url` | from config | Override API URL |
|
||||
| `api_key` | from config | Override API key |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- crewai >= 0.86.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,177 +0,0 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
title: "Hermes Agent Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Hermes Agent with Hindsight. Automatically recalls context before every LLM call and retains conversations for future sessions."
|
||||
---
|
||||
|
||||
# Hermes Agent
|
||||
|
||||
Persistent long-term memory for [Hermes Agent](https://github.com/NousResearch/hermes-agent) using [Hindsight](https://vectorize.io/hindsight). Automatically recalls relevant context before every LLM call and retains conversations for future sessions — plus explicit retain/recall/reflect tools.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Install the plugin into Hermes's Python environment
|
||||
uv pip install hindsight-hermes --python $HOME/.hermes/hermes-agent/venv/bin/python
|
||||
|
||||
# 2. Configure (choose one)
|
||||
# Option A: Config file (recommended)
|
||||
mkdir -p ~/.hindsight
|
||||
cat > ~/.hindsight/hermes.json << 'EOF'
|
||||
{
|
||||
"hindsightApiUrl": "http://localhost:9077",
|
||||
"bankId": "hermes"
|
||||
}
|
||||
EOF
|
||||
|
||||
# Option B: Environment variables
|
||||
export HINDSIGHT_API_URL=http://localhost:9077
|
||||
export HINDSIGHT_BANK_ID=hermes
|
||||
|
||||
# 3. Start Hermes — the plugin activates automatically
|
||||
hermes
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-recall** — on every turn, queries Hindsight for relevant memories and injects them into the system prompt (via `pre_llm_call` hook)
|
||||
- **Auto-retain** — after every response, retains the user/assistant exchange to Hindsight (via `post_llm_call` hook)
|
||||
- **Explicit tools** — `hindsight_retain`, `hindsight_recall`, `hindsight_reflect` for direct model control
|
||||
- **Config file** — `~/.hindsight/hermes.json` with the same field names as openclaw and claude-code integrations
|
||||
- **Zero config overhead** — env vars still work as overrides for CI/automation
|
||||
|
||||
:::note
|
||||
The lifecycle hooks (`pre_llm_call`/`post_llm_call`) require hermes-agent with [PR #2823](https://github.com/NousResearch/hermes-agent/pull/2823) or later. On older versions, only the three tools are registered — hooks are silently skipped.
|
||||
:::
|
||||
|
||||
## Architecture
|
||||
|
||||
The plugin registers via Hermes's `hermes_agent.plugins` entry point system:
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| `pre_llm_call` hook | **Auto-recall** — query memories, inject as ephemeral system prompt context |
|
||||
| `post_llm_call` hook | **Auto-retain** — store user/assistant exchange to Hindsight |
|
||||
| `hindsight_retain` tool | Explicit memory storage (model-initiated) |
|
||||
| `hindsight_recall` tool | Explicit memory search (model-initiated) |
|
||||
| `hindsight_reflect` tool | LLM-synthesized answer from stored memories |
|
||||
|
||||
## Connection Modes
|
||||
|
||||
### 1. External API (recommended for production)
|
||||
|
||||
Connect to a running Hindsight server (cloud or self-hosted). No local LLM needed — the server handles fact extraction.
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "https://your-hindsight-server.com",
|
||||
"hindsightApiToken": "your-token",
|
||||
"bankId": "hermes"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Local Daemon
|
||||
|
||||
If you're running `hindsight-embed` locally, point to it:
|
||||
|
||||
```json
|
||||
{
|
||||
"hindsightApiUrl": "http://localhost:9077",
|
||||
"bankId": "hermes"
|
||||
}
|
||||
```
|
||||
|
||||
Follow the [Quick Start](../../developer/api/quickstart.md) guide to get the Hindsight API running.
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings are in `~/.hindsight/hermes.json`. Every setting can also be overridden via environment variables (env vars take priority).
|
||||
|
||||
### Connection & Daemon
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `hindsightApiUrl` | — | `HINDSIGHT_API_URL` | Hindsight API URL |
|
||||
| `hindsightApiToken` | `null` | `HINDSIGHT_API_TOKEN` / `HINDSIGHT_API_KEY` | Auth token for API |
|
||||
| `apiPort` | `9077` | `HINDSIGHT_API_PORT` | Port for local Hindsight daemon |
|
||||
| `daemonIdleTimeout` | `0` | `HINDSIGHT_DAEMON_IDLE_TIMEOUT` | Seconds before idle daemon shuts down (0 = never) |
|
||||
| `embedVersion` | `"latest"` | `HINDSIGHT_EMBED_VERSION` | `hindsight-embed` version for `uvx` |
|
||||
|
||||
### LLM Provider (daemon mode only)
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `llmProvider` | auto-detect | `HINDSIGHT_LLM_PROVIDER` | LLM provider: `openai`, `anthropic`, `gemini`, `groq`, `ollama` |
|
||||
| `llmModel` | provider default | `HINDSIGHT_LLM_MODEL` | Model override |
|
||||
|
||||
### Memory Bank
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `bankId` | — | `HINDSIGHT_BANK_ID` | Memory bank ID |
|
||||
| `bankMission` | `""` | `HINDSIGHT_BANK_MISSION` | Agent identity/purpose for the memory bank |
|
||||
| `retainMission` | `null` | — | Custom retain mission (what to extract from conversations) |
|
||||
| `bankIdPrefix` | `""` | — | Prefix for all bank IDs |
|
||||
|
||||
### Auto-Recall
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRecall` | `true` | `HINDSIGHT_AUTO_RECALL` | Enable automatic memory recall via `pre_llm_call` hook |
|
||||
| `recallBudget` | `"mid"` | `HINDSIGHT_RECALL_BUDGET` | Recall effort: `low`, `mid`, `high` |
|
||||
| `recallMaxTokens` | `4096` | `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens in recall response |
|
||||
| `recallMaxQueryChars` | `800` | `HINDSIGHT_RECALL_MAX_QUERY_CHARS` | Max chars of user message used as query |
|
||||
| `recallPromptPreamble` | see below | — | Header text injected before recalled memories |
|
||||
|
||||
Default preamble:
|
||||
> Relevant memories from past conversations (prioritize recent when conflicting). Only use memories that are directly useful to continue this conversation; ignore the rest:
|
||||
|
||||
### Auto-Retain
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `autoRetain` | `true` | `HINDSIGHT_AUTO_RETAIN` | Enable automatic retention via `post_llm_call` hook |
|
||||
| `retainEveryNTurns` | `1` | — | Retain every Nth turn |
|
||||
| `retainOverlapTurns` | `2` | — | Extra overlap turns for continuity |
|
||||
| `retainRoles` | `["user", "assistant"]` | — | Which message roles to retain |
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
| Setting | Default | Env Var | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| `debug` | `false` | `HINDSIGHT_DEBUG` | Enable debug logging to stderr |
|
||||
|
||||
## Hermes Gateway (Telegram, Discord, Slack)
|
||||
|
||||
When using Hermes in gateway mode (multi-platform messaging), the plugin works across all platforms. Hermes creates a fresh `AIAgent` per message, and the plugin's `pre_llm_call` hook ensures relevant memories are recalled for each turn regardless of platform.
|
||||
|
||||
## Disabling Hermes's Built-in Memory
|
||||
|
||||
Hermes has a built-in `memory` tool that saves to local markdown files. If both are active, the LLM may prefer the built-in one. Disable it:
|
||||
|
||||
```bash
|
||||
hermes tools disable memory
|
||||
```
|
||||
|
||||
Re-enable later with `hermes tools enable memory`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Plugin not loading**: Verify the entry point is registered:
|
||||
```bash
|
||||
python -c "
|
||||
import importlib.metadata
|
||||
eps = importlib.metadata.entry_points(group='hermes_agent.plugins')
|
||||
print(list(eps))
|
||||
"
|
||||
```
|
||||
You should see `EntryPoint(name='hindsight', value='hindsight_hermes', ...)`.
|
||||
|
||||
**Tools don't appear in `/tools`**: Check that `hindsightApiUrl` (or `HINDSIGHT_API_URL`) is set. The plugin silently skips registration when unconfigured.
|
||||
|
||||
**Connection refused**: Verify the Hindsight API is running:
|
||||
```bash
|
||||
curl http://localhost:9077/health
|
||||
```
|
||||
|
||||
**Recall returning no memories**: Memories need at least one retain cycle. Try storing a fact first, then asking about it in a new session.
|
||||
@@ -1,319 +0,0 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
title: "LangGraph & LangChain Persistent Memory with Hindsight"
|
||||
description: "Add long-term memory to LangGraph and LangChain agents with Hindsight. Three integration patterns — tools, nodes, and BaseStore adapter — for persistent memory across agent runs."
|
||||
---
|
||||
|
||||
# LangGraph / LangChain
|
||||
|
||||
Persistent long-term memory for [LangGraph](https://langchain-ai.github.io/langgraph/) and [LangChain](https://python.langchain.com/) agents via Hindsight. Three integration patterns at different abstraction levels — the tools pattern works with both LangChain and LangGraph, while nodes and the BaseStore adapter are LangGraph-specific.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/langgraph.md)
|
||||
|
||||
## Features
|
||||
|
||||
- **Memory Tools** — retain, recall, and reflect as LangChain `@tool` functions compatible with `bind_tools()` and `ToolNode`. Works with **both LangChain and LangGraph** — no LangGraph dependency required for this pattern.
|
||||
- **Graph Nodes** *(LangGraph)* — Pre-built nodes that auto-inject memories before LLM calls and auto-store after responses
|
||||
- **BaseStore Adapter** *(LangGraph)* — Drop-in `BaseStore` implementation backed by Hindsight, for LangGraph's native memory patterns
|
||||
- **Dynamic Banks** — Resolve bank IDs per-request from `RunnableConfig` for per-user memory
|
||||
- **Async-Native** — Uses `aretain`, `arecall`, `areflect` directly — no thread-pool workarounds
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-langgraph
|
||||
```
|
||||
|
||||
## Quick Start: Tools (LangChain & LangGraph)
|
||||
|
||||
The tools pattern creates standard LangChain `@tool` functions that work with any LangChain-compatible model via `bind_tools()`. You can use them with a LangGraph agent or with plain LangChain — no LangGraph required.
|
||||
|
||||
**With LangGraph (recommended):**
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import create_hindsight_tools
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
tools = create_hindsight_tools(client=client, bank_id="user-123")
|
||||
|
||||
agent = create_react_agent(ChatOpenAI(model="gpt-4o"), tools=tools)
|
||||
|
||||
result = await agent.ainvoke(
|
||||
{"messages": [{"role": "user", "content": "Remember that I prefer dark mode"}]}
|
||||
)
|
||||
```
|
||||
|
||||
**With plain LangChain:**
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import create_hindsight_tools
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
tools = create_hindsight_tools(client=client, bank_id="user-123")
|
||||
|
||||
model = ChatOpenAI(model="gpt-4o").bind_tools(tools)
|
||||
response = await model.ainvoke("Remember that I prefer dark mode")
|
||||
```
|
||||
|
||||
When using plain LangChain, you handle the tool execution loop yourself — call the model, check for `tool_calls`, execute them, and feed results back. LangGraph automates this loop for you.
|
||||
|
||||
The agent gets three tools it can call:
|
||||
|
||||
- **`hindsight_retain`** — Store information to long-term memory
|
||||
- **`hindsight_recall`** — Search long-term memory for relevant facts
|
||||
- **`hindsight_reflect`** — Synthesize a reasoned answer from memories
|
||||
|
||||
## Quick Start: Memory Nodes (LangGraph)
|
||||
|
||||
Add recall and retain nodes to your graph for automatic memory injection and storage.
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import create_recall_node, create_retain_node
|
||||
from langgraph.graph import StateGraph, MessagesState, START, END
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
recall = create_recall_node(client=client, bank_id="user-123")
|
||||
retain = create_retain_node(client=client, bank_id="user-123")
|
||||
|
||||
builder = StateGraph(MessagesState)
|
||||
builder.add_node("recall", recall)
|
||||
builder.add_node("agent", agent_node) # your LLM node
|
||||
builder.add_node("retain", retain)
|
||||
|
||||
builder.add_edge(START, "recall")
|
||||
builder.add_edge("recall", "agent")
|
||||
builder.add_edge("agent", "retain")
|
||||
builder.add_edge("retain", END)
|
||||
|
||||
graph = builder.compile()
|
||||
```
|
||||
|
||||
The recall node extracts the latest user message, searches Hindsight, and injects matching memories as a `SystemMessage`. The retain node stores human messages (optionally AI messages too) after the response.
|
||||
|
||||
## Quick Start: BaseStore (LangGraph)
|
||||
|
||||
Use Hindsight as a LangGraph `BaseStore` for cross-thread persistent memory with semantic search.
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_langgraph import HindsightStore
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
store = HindsightStore(client=client)
|
||||
|
||||
graph = builder.compile(checkpointer=checkpointer, store=store)
|
||||
|
||||
# Store and search via the store API
|
||||
await store.aput(("user", "123", "prefs"), "theme", {"value": "dark mode"})
|
||||
results = await store.asearch(("user", "123", "prefs"), query="theme preference")
|
||||
```
|
||||
|
||||
Namespace tuples are mapped to Hindsight bank IDs with `.` as separator (e.g., `("user", "123")` becomes bank `user.123`). Banks are auto-created on first access.
|
||||
|
||||
## Dynamic Bank IDs
|
||||
|
||||
Both nodes and the store support per-user bank resolution from `RunnableConfig`:
|
||||
|
||||
```python
|
||||
recall = create_recall_node(client=client, bank_id_from_config="user_id")
|
||||
retain = create_retain_node(client=client, bank_id_from_config="user_id")
|
||||
|
||||
# Bank ID resolved at runtime from config
|
||||
result = await graph.ainvoke(
|
||||
{"messages": [{"role": "user", "content": "hello"}]},
|
||||
config={"configurable": {"user_id": "user-456"}},
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=True,
|
||||
include_recall=True,
|
||||
include_reflect=False, # Omit reflect
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing a client to every call, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_langgraph import configure, create_hindsight_tools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create tools without passing client — uses global config
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
## Retain Node Options
|
||||
|
||||
```python
|
||||
retain = create_retain_node(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
retain_human=True, # Store human messages (default: True)
|
||||
retain_ai=False, # Store AI responses (default: False)
|
||||
tags=["source:chat"], # Tags applied to stored memories
|
||||
)
|
||||
```
|
||||
|
||||
## Recall Node Options
|
||||
|
||||
```python
|
||||
recall = create_recall_node(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
budget="low", # Recall budget: low/mid/high
|
||||
max_results=10, # Max memories injected
|
||||
max_tokens=4096, # Max tokens for recall
|
||||
tags=["scope:user"], # Filter by tags
|
||||
tags_match="all", # Tag match mode
|
||||
)
|
||||
```
|
||||
|
||||
### Using `output_key` for Prompt Control
|
||||
|
||||
By default, the recall node appends a `SystemMessage` to `messages`. Use `output_key` to write memory text to a custom state field instead, giving you full control over prompt ordering:
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
from langgraph.graph import MessagesState
|
||||
|
||||
class AgentState(MessagesState):
|
||||
memory_context: Optional[str] = None
|
||||
|
||||
recall = create_recall_node(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
output_key="memory_context",
|
||||
)
|
||||
|
||||
# In your agent node, read state["memory_context"] and prepend it
|
||||
# to the system prompt before calling the model.
|
||||
```
|
||||
|
||||
## Limitations and Notes
|
||||
|
||||
### HindsightStore
|
||||
|
||||
- **Async-only.** All sync methods (`batch`, `get`, `put`, `delete`, `search`, `list_namespaces`) raise `NotImplementedError`. Use the async variants (`abatch`, `aget`, `aput`, `adelete`, `asearch`, `alist_namespaces`) instead.
|
||||
- **`get()` relies on recall.** There is no direct key lookup — the key is used as a recall query and only exact `document_id` matches are returned. Items that do not rank in the top recall results may appear missing.
|
||||
- **`list_namespaces` is session-scoped.** It only tracks namespaces that have been written to via `aput()` during the current process. After a restart, `list_namespaces` returns empty even though data still exists in Hindsight.
|
||||
- **`delete` is a no-op.** Calling `adelete()` logs a debug message but does not remove data from Hindsight. Hindsight's memory model is append-oriented; fact superseding is handled automatically during retain.
|
||||
|
||||
### Memory Nodes
|
||||
|
||||
- **SystemMessage ordering.** The recall node adds a `SystemMessage` with recalled memories. Because `MessagesState` uses `add_messages` (which appends), this message appears after existing messages rather than at position 0. The message has a stable ID (`hindsight_memory_context`) so it is updated rather than duplicated across invocations. If your LLM provider requires system messages first, sort or filter messages in your agent node before passing them to the model.
|
||||
|
||||
### Error Handling
|
||||
|
||||
- **Tools** raise `HindsightError` on failure, which surfaces to the agent as a tool error.
|
||||
- **Nodes** silently log errors and return empty messages, so a Hindsight outage does not crash your graph.
|
||||
|
||||
## API Reference
|
||||
|
||||
### `create_hindsight_tools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode (any/all/any\_strict/all\_strict) |
|
||||
| `retain_metadata` | `None` | Default metadata dict for retain operations |
|
||||
| `retain_document_id` | `None` | Default document\_id for retain (groups/upserts memories) |
|
||||
| `recall_types` | `None` | Fact types to filter (world, experience, opinion, observation) |
|
||||
| `recall_include_entities` | `False` | Include entity information in recall results |
|
||||
| `reflect_context` | `None` | Additional context for reflect operations |
|
||||
| `reflect_max_tokens` | `None` | Max tokens for reflect results (defaults to `max_tokens`) |
|
||||
| `reflect_response_schema` | `None` | JSON schema to constrain reflect output format |
|
||||
| `reflect_tags` | `None` | Tags to filter memories used in reflect (defaults to `recall_tags`) |
|
||||
| `reflect_tags_match` | `None` | Tag matching for reflect (defaults to `recall_tags_match`) |
|
||||
| `include_retain` | `True` | Include the retain (store) tool |
|
||||
| `include_recall` | `True` | Include the recall (search) tool |
|
||||
| `include_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `create_recall_node()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | `None` | Static bank ID (or use `bank_id_from_config`) |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall budget level |
|
||||
| `max_tokens` | `4096` | Max tokens for recall results |
|
||||
| `max_results` | `10` | Max memories to inject |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
| `bank_id_from_config` | `"user_id"` | Config key to resolve bank ID at runtime |
|
||||
| `output_key` | `None` | If set, write memory text to this state key instead of appending a SystemMessage to `messages` |
|
||||
|
||||
### `create_retain_node()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | `None` | Static bank ID (or use `bank_id_from_config`) |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `tags` | `None` | Tags applied to stored memories |
|
||||
| `bank_id_from_config` | `"user_id"` | Config key to resolve bank ID at runtime |
|
||||
| `retain_human` | `True` | Store human messages |
|
||||
| `retain_ai` | `False` | Store AI responses |
|
||||
|
||||
### `HindsightStore()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `tags` | `None` | Tags applied to all retain operations |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- langchain-core >= 0.3.0
|
||||
- hindsight-client >= 0.4.0
|
||||
- langgraph >= 0.3.0 *(only for nodes and store patterns — install with `pip install hindsight-langgraph[langgraph]`)*
|
||||
@@ -1,349 +0,0 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
title: "LiteLLM Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to any LLM application via LiteLLM and Hindsight. Universal integration — works with any model or provider with just a few lines of code."
|
||||
---
|
||||
|
||||
# LiteLLM
|
||||
|
||||
Universal LLM memory integration via [LiteLLM](https://github.com/BerriAI/litellm). Add persistent memory to any LLM application with just a few lines of code.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/litellm.md)
|
||||
|
||||
## Features
|
||||
|
||||
- **Universal LLM Support** - Works with 100+ LLM providers via LiteLLM (OpenAI, Anthropic, Groq, Azure, AWS Bedrock, Google Vertex AI, and more)
|
||||
- **Simple Integration** - Just configure, enable, and use `hindsight_litellm.completion()`
|
||||
- **Automatic Memory Injection** - Relevant memories are injected into prompts before LLM calls
|
||||
- **Automatic Conversation Storage** - Conversations are stored to Hindsight for future recall
|
||||
- **Two Memory Modes** - Choose between `reflect` (synthesized context) or `recall` (raw memory retrieval)
|
||||
- **Direct Memory APIs** - Query, synthesize, and store memories manually
|
||||
- **Native Client Wrappers** - Alternative wrappers for OpenAI and Anthropic SDKs
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-litellm
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
import hindsight_litellm
|
||||
|
||||
# Configure and enable memory integration
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="my-agent",
|
||||
)
|
||||
hindsight_litellm.enable()
|
||||
|
||||
# Use the convenience wrapper - memory is automatically injected and stored
|
||||
response = hindsight_litellm.completion(
|
||||
model="gpt-4o-mini",
|
||||
messages=[{"role": "user", "content": "What did we discuss about AI?"}]
|
||||
)
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
When you call `completion()`, the following happens automatically:
|
||||
|
||||
1. **Memory Retrieval** - Hindsight is queried for relevant memories based on the conversation
|
||||
2. **Prompt Injection** - Memories are injected into the system message
|
||||
3. **LLM Call** - The enriched prompt is sent to the LLM
|
||||
4. **Conversation Storage** - The conversation is stored to Hindsight for future recall
|
||||
5. **Response Returned** - You receive the response as normal
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```python
|
||||
hindsight_litellm.configure(
|
||||
# Required
|
||||
hindsight_api_url="http://localhost:8888", # Hindsight API server URL
|
||||
bank_id="my-agent", # Memory bank ID
|
||||
|
||||
api_key="your-api-key", # Optional API key for authentication
|
||||
|
||||
# Optional - Memory behavior
|
||||
store_conversations=True, # Store conversations after LLM calls
|
||||
inject_memories=True, # Inject relevant memories into prompts
|
||||
use_reflect=False, # Use reflect API (synthesized) vs recall (raw memories)
|
||||
reflect_include_facts=False, # Include source facts with reflect responses
|
||||
max_memories=None, # Maximum memories to inject (None = unlimited)
|
||||
max_memory_tokens=4096, # Maximum tokens for memory context
|
||||
recall_budget="mid", # Recall budget: "low", "mid", "high"
|
||||
fact_types=["world", "agent"], # Filter fact types to inject
|
||||
|
||||
# Optional - Bank Configuration
|
||||
bank_name="My Agent", # Human-readable display name for the memory bank
|
||||
mission="This agent...", # Instructions guiding what Hindsight should remember
|
||||
|
||||
# Optional - Advanced
|
||||
injection_mode="system_message", # or "prepend_user"
|
||||
excluded_models=["gpt-3.5*"], # Exclude certain models
|
||||
verbose=True, # Enable verbose logging and debug info
|
||||
)
|
||||
```
|
||||
|
||||
### Bank Configuration
|
||||
|
||||
The `mission` and `bank_name` parameters configure the memory bank itself. When provided, `configure()` will automatically create or update the bank with these settings.
|
||||
|
||||
```python
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="support-router",
|
||||
bank_name="Customer Support Router",
|
||||
mission="""You're a customer support router - keep track of which types of issues
|
||||
should go to which teams (billing, technical, sales), customer preferences for
|
||||
communication channels, and past issue resolutions.""",
|
||||
)
|
||||
```
|
||||
|
||||
### Memory Modes: Reflect vs Recall
|
||||
|
||||
- **Recall mode** (`use_reflect=False`, default): Retrieves raw memory facts and injects them as a numbered list. Best when you need precise, individual memories.
|
||||
- **Reflect mode** (`use_reflect=True`): Synthesizes memories into a coherent context paragraph. Best for natural, conversational memory context.
|
||||
|
||||
```python
|
||||
# Recall mode - raw memories
|
||||
hindsight_litellm.configure(
|
||||
bank_id="my-agent",
|
||||
use_reflect=False, # Default
|
||||
)
|
||||
# Injects: "1. [WORLD] User prefers Python\n2. [MENTAL MODEL] User prefers simple code..."
|
||||
|
||||
# Reflect mode - synthesized context
|
||||
hindsight_litellm.configure(
|
||||
bank_id="my-agent",
|
||||
use_reflect=True,
|
||||
)
|
||||
# Injects: "Based on previous conversations, the user is a Python developer who..."
|
||||
```
|
||||
|
||||
## Multi-Provider Support
|
||||
|
||||
Works with any LiteLLM-supported provider:
|
||||
|
||||
```python
|
||||
import hindsight_litellm
|
||||
|
||||
hindsight_litellm.configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
bank_id="my-agent",
|
||||
)
|
||||
hindsight_litellm.enable()
|
||||
|
||||
# OpenAI
|
||||
hindsight_litellm.completion(model="gpt-4o", messages=[...])
|
||||
|
||||
# Anthropic
|
||||
hindsight_litellm.completion(model="claude-3-5-sonnet-20241022", messages=[...])
|
||||
|
||||
# Groq
|
||||
hindsight_litellm.completion(model="groq/llama-3.1-70b-versatile", messages=[...])
|
||||
|
||||
# Azure OpenAI
|
||||
hindsight_litellm.completion(model="azure/gpt-4", messages=[...])
|
||||
|
||||
# AWS Bedrock
|
||||
hindsight_litellm.completion(model="bedrock/anthropic.claude-3", messages=[...])
|
||||
|
||||
# Google Vertex AI
|
||||
hindsight_litellm.completion(model="vertex_ai/gemini-pro", messages=[...])
|
||||
```
|
||||
|
||||
## Direct Memory APIs
|
||||
|
||||
### Recall - Query raw memories
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, recall
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
memories = recall("what projects am I working on?", budget="mid")
|
||||
for m in memories:
|
||||
print(f"- [{m.fact_type}] {m.text}")
|
||||
```
|
||||
|
||||
### Reflect - Get synthesized context
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, reflect
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
result = reflect("what do you know about the user's preferences?")
|
||||
print(result.text)
|
||||
```
|
||||
|
||||
### Retain - Store memories
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, retain
|
||||
|
||||
configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
|
||||
|
||||
result = retain(
|
||||
content="User mentioned they're working on a machine learning project",
|
||||
context="Discussion about current projects",
|
||||
)
|
||||
```
|
||||
|
||||
### Async APIs
|
||||
|
||||
```python
|
||||
from hindsight_litellm import arecall, areflect, aretain
|
||||
|
||||
# Async versions of all memory APIs
|
||||
memories = await arecall("what do you know about me?")
|
||||
context = await areflect("summarize user preferences")
|
||||
result = await aretain(content="New information to remember")
|
||||
```
|
||||
|
||||
## Native Client Wrappers
|
||||
|
||||
Alternative to LiteLLM callbacks for direct SDK integration.
|
||||
|
||||
### OpenAI Wrapper
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
from hindsight_litellm import wrap_openai
|
||||
|
||||
client = OpenAI()
|
||||
wrapped = wrap_openai(
|
||||
client,
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
response = wrapped.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[{"role": "user", "content": "What do you know about me?"}]
|
||||
)
|
||||
```
|
||||
|
||||
### Anthropic Wrapper
|
||||
|
||||
```python
|
||||
from anthropic import Anthropic
|
||||
from hindsight_litellm import wrap_anthropic
|
||||
|
||||
client = Anthropic()
|
||||
wrapped = wrap_anthropic(
|
||||
client,
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
response = wrapped.messages.create(
|
||||
model="claude-3-5-sonnet-20241022",
|
||||
max_tokens=1024,
|
||||
messages=[{"role": "user", "content": "Hello!"}]
|
||||
)
|
||||
```
|
||||
|
||||
## Debug Mode
|
||||
|
||||
When `verbose=True`, you can inspect exactly what memories are being injected:
|
||||
|
||||
```python
|
||||
from hindsight_litellm import configure, enable, completion, get_last_injection_debug
|
||||
|
||||
configure(
|
||||
bank_id="my-agent",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
verbose=True,
|
||||
)
|
||||
enable()
|
||||
|
||||
response = completion(
|
||||
model="gpt-4o-mini",
|
||||
messages=[{"role": "user", "content": "What's my favorite color?"}]
|
||||
)
|
||||
|
||||
# Inspect what was injected
|
||||
debug = get_last_injection_debug()
|
||||
if debug:
|
||||
print(f"Mode: {debug.mode}") # "reflect" or "recall"
|
||||
print(f"Injected: {debug.injected}") # True/False
|
||||
print(f"Results: {debug.results_count}")
|
||||
print(f"Memory context:\n{debug.memory_context}")
|
||||
```
|
||||
|
||||
## Context Manager
|
||||
|
||||
```python
|
||||
from hindsight_litellm import hindsight_memory
|
||||
import litellm
|
||||
|
||||
with hindsight_memory(bank_id="user-123"):
|
||||
response = litellm.completion(model="gpt-4", messages=[...])
|
||||
# Memory integration automatically disabled after context
|
||||
```
|
||||
|
||||
## Disabling and Cleanup
|
||||
|
||||
```python
|
||||
from hindsight_litellm import disable, cleanup
|
||||
|
||||
# Temporarily disable memory integration
|
||||
disable()
|
||||
|
||||
# Clean up all resources (call when shutting down)
|
||||
cleanup()
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Main Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `configure(...)` | Configure global Hindsight settings |
|
||||
| `enable()` | Enable memory integration with LiteLLM |
|
||||
| `disable()` | Disable memory integration |
|
||||
| `is_enabled()` | Check if memory integration is enabled |
|
||||
| `cleanup()` | Clean up all resources |
|
||||
|
||||
### Configuration Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get_config()` | Get current configuration |
|
||||
| `is_configured()` | Check if Hindsight is configured |
|
||||
| `reset_config()` | Reset configuration to defaults |
|
||||
|
||||
### Memory Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `recall(query, ...)` | Synchronously query raw memories |
|
||||
| `arecall(query, ...)` | Asynchronously query raw memories |
|
||||
| `reflect(query, ...)` | Synchronously get synthesized memory context |
|
||||
| `areflect(query, ...)` | Asynchronously get synthesized memory context |
|
||||
| `retain(content, ...)` | Synchronously store a memory |
|
||||
| `aretain(content, ...)` | Asynchronously store a memory |
|
||||
|
||||
### Debug Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get_last_injection_debug()` | Get debug info from last memory injection |
|
||||
| `clear_injection_debug()` | Clear stored debug info |
|
||||
|
||||
### Client Wrappers
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `wrap_openai(client, ...)` | Wrap OpenAI client with memory |
|
||||
| `wrap_anthropic(client, ...)` | Wrap Anthropic client with memory |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- litellm >= 1.40.0
|
||||
- A running Hindsight API server
|
||||
@@ -1,251 +0,0 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
title: "LlamaIndex Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to LlamaIndex agents with Hindsight. Supports agent-driven tools (HindsightToolSpec) and automatic memory via the BaseMemory interface."
|
||||
---
|
||||
|
||||
# LlamaIndex
|
||||
|
||||
Persistent long-term memory for [LlamaIndex](https://docs.llamaindex.ai/) agents via Hindsight. The `hindsight-llamaindex` package provides two complementary patterns:
|
||||
|
||||
- **`HindsightToolSpec`** — Agent-driven memory tools (retain/recall/reflect)
|
||||
- **`HindsightMemory`** — Automatic memory via LlamaIndex's `BaseMemory` interface
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-llamaindex
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Automatic Memory (BaseMemory)
|
||||
|
||||
The simplest way to add Hindsight memory to a LlamaIndex agent. Messages are automatically stored on each turn, and relevant memories are recalled and injected as context.
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_llamaindex import HindsightMemory
|
||||
from llama_index.core.agent import ReActAgent
|
||||
from llama_index.llms.openai import OpenAI
|
||||
|
||||
async def main():
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
memory = HindsightMemory.from_client(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user preferences and project context",
|
||||
)
|
||||
|
||||
agent = ReActAgent(tools=[], llm=OpenAI(model="gpt-4o"))
|
||||
response = await agent.run("Remember that I prefer dark mode", memory=memory)
|
||||
print(response)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
| Event | What Happens |
|
||||
|-------|-------------|
|
||||
| Agent receives input | `aget(input)` recalls relevant memories from Hindsight, prepends as system message |
|
||||
| Agent produces output | `aput(message)` retains the message to Hindsight for future recall |
|
||||
| New session starts | Previous memories are available via recall; local chat buffer starts empty |
|
||||
|
||||
### `HindsightMemory.from_client()`
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `client` | `Hindsight` | *required* | Hindsight client instance |
|
||||
| `bank_id` | `str` | *required* | Memory bank ID |
|
||||
| `mission` | `str` | `None` | Bank mission — auto-creates bank on first use |
|
||||
| `context` | `str` | `"llamaindex"` | Source label for retain operations |
|
||||
| `budget` | `str` | `"mid"` | Recall budget level |
|
||||
| `max_tokens` | `int` | `4096` | Max recall tokens |
|
||||
| `tags` | `list[str]` | `None` | Tags for retain operations |
|
||||
| `recall_tags` | `list[str]` | `None` | Tags to filter recall |
|
||||
| `recall_tags_match` | `str` | `"any"` | Tag matching mode |
|
||||
| `system_prompt` | `str` | *(built-in)* | Template for memory system message. Must contain `{memories}` |
|
||||
| `chat_history_limit` | `int` | `100` | Max messages in local buffer |
|
||||
|
||||
Also available: `HindsightMemory.from_url(hindsight_api_url, bank_id, ...)` for creating without a pre-built client.
|
||||
|
||||
---
|
||||
|
||||
## Agent-Driven Tools (BaseToolSpec)
|
||||
|
||||
For explicit control, expose retain/recall/reflect as tools the agent can choose to call.
|
||||
|
||||
### Quick Start: Tool Spec
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_llamaindex import HindsightToolSpec
|
||||
from llama_index.llms.openai import OpenAI
|
||||
from llama_index.core.agent import ReActAgent
|
||||
|
||||
async def main():
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
spec = HindsightToolSpec(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user preferences",
|
||||
)
|
||||
tools = spec.to_tool_list()
|
||||
|
||||
agent = ReActAgent(tools=tools, llm=OpenAI(model="gpt-4o"))
|
||||
response = await agent.run("Remember that I prefer dark mode")
|
||||
print(response)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### Quick Start: Factory Function
|
||||
|
||||
```python
|
||||
from hindsight_llamaindex import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user preferences",
|
||||
)
|
||||
```
|
||||
|
||||
### Selecting Tools
|
||||
|
||||
```python
|
||||
# Via to_tool_list()
|
||||
tools = spec.to_tool_list(spec_functions=["recall_memory", "reflect_on_memory"])
|
||||
|
||||
# Via factory flags
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=True,
|
||||
include_recall=True,
|
||||
include_reflect=False,
|
||||
)
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Set defaults via `configure()`, override per-call:
|
||||
|
||||
```python
|
||||
from hindsight_llamaindex import configure
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # or set HINDSIGHT_API_KEY env var
|
||||
budget="mid",
|
||||
tags=["source:llamaindex"],
|
||||
context="my-app",
|
||||
mission="Track user preferences",
|
||||
)
|
||||
|
||||
# Now create tools without passing client/url
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
### `HindsightToolSpec()`
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `bank_id` | `str` | *required* | Hindsight memory bank to operate on |
|
||||
| `client` | `Hindsight` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `str` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `str` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `str` | `None` → `"mid"` | Recall/reflect budget: `low`, `mid`, `high` |
|
||||
| `max_tokens` | `int` | `None` → `4096` | Max tokens for recall results |
|
||||
| `tags` | `list[str]` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `list[str]` | `None` | Tags to filter recall results |
|
||||
| `recall_tags_match` | `str` | `None` → `"any"` | Tag matching: `any`, `all`, `any_strict`, `all_strict` |
|
||||
| `retain_metadata` | `dict[str, str]` | `None` | Default metadata for retain operations |
|
||||
| `retain_document_id` | `str` | `None` | Document ID for retain. Auto-generates `{session}-{timestamp}` if not set |
|
||||
| `retain_context` | `str` | `"llamaindex"` | Source label for retain operations |
|
||||
| `recall_types` | `list[str]` | `None` | Fact types: `world`, `experience`, `opinion`, `observation` |
|
||||
| `recall_include_entities` | `bool` | `False` | Include entity info in recall results |
|
||||
| `reflect_context` | `str` | `None` | Additional context for reflect |
|
||||
| `reflect_max_tokens` | `int` | `None` | Max tokens for reflect (defaults to `max_tokens`) |
|
||||
| `reflect_response_schema` | `dict` | `None` | JSON schema to constrain reflect output |
|
||||
| `reflect_tags` | `list[str]` | `None` | Tags for reflect (defaults to `recall_tags`) |
|
||||
| `reflect_tags_match` | `str` | `None` | Tag matching for reflect (defaults to `recall_tags_match`) |
|
||||
| `mission` | `str` | `None` | Bank mission — auto-creates bank on first use |
|
||||
|
||||
---
|
||||
|
||||
## Production Patterns
|
||||
|
||||
### Bank Mission
|
||||
|
||||
Set a mission to give the memory engine context for fact extraction:
|
||||
|
||||
```python
|
||||
# Tools
|
||||
spec = HindsightToolSpec(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user coding preferences, project context, and technical decisions",
|
||||
)
|
||||
|
||||
# Memory
|
||||
memory = HindsightMemory.from_client(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
mission="Track user coding preferences, project context, and technical decisions",
|
||||
)
|
||||
```
|
||||
|
||||
The bank is created automatically on first use. If it already exists, creation is silently skipped.
|
||||
|
||||
### Memory Scoping with Tags
|
||||
|
||||
```python
|
||||
spec = HindsightToolSpec(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
tags=["source:chat", "session:abc"], # applied to all retains
|
||||
recall_tags=["source:chat"], # filter recalls to chat memories
|
||||
recall_tags_match="any",
|
||||
)
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
Both patterns handle errors gracefully — operations are logged and return friendly messages instead of raising exceptions. Agents continue functioning even if memory is unavailable.
|
||||
|
||||
### Combining Tools + Memory
|
||||
|
||||
Use both patterns together for maximum flexibility:
|
||||
|
||||
```python
|
||||
from hindsight_llamaindex import create_hindsight_tools, HindsightMemory
|
||||
|
||||
# Automatic memory for context enrichment
|
||||
memory = HindsightMemory.from_client(client=client, bank_id="user-123")
|
||||
|
||||
# Explicit tools for agent-driven reflect
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=False, # memory handles retain automatically
|
||||
include_recall=False, # memory handles recall automatically
|
||||
include_reflect=True, # agent can still explicitly reflect
|
||||
)
|
||||
|
||||
agent = ReActAgent(tools=tools, llm=llm)
|
||||
|
||||
# Pass memory to run()
|
||||
response = await agent.run("What should I prioritize?", memory=memory)
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.10+
|
||||
- `llama-index-core >= 0.11.0`
|
||||
- `hindsight-client >= 0.4.0`
|
||||
@@ -1,176 +0,0 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
title: "Hindsight Local MCP Server | Persistent Memory for Claude"
|
||||
description: "Run Hindsight as a local MCP server with embedded PostgreSQL — no external setup required. Ideal for Claude Code and Claude Desktop for long-term memory across conversations."
|
||||
---
|
||||
|
||||
# Local MCP Server
|
||||
|
||||
Hindsight provides a local MCP server that runs entirely on your machine with an embedded PostgreSQL database. No external server or database setup required.
|
||||
|
||||
This is ideal for:
|
||||
- **Personal use with Claude Code / Claude Desktop** — Give Claude long-term memory across conversations
|
||||
- **Development and testing** — Quick setup without infrastructure
|
||||
- **Privacy-focused setups** — All data stays on your machine
|
||||
|
||||
## How It Works
|
||||
|
||||
Running `hindsight-local-mcp` starts the full Hindsight API on `localhost:8888` with an embedded PostgreSQL database (pg0). You then connect your MCP client to it over HTTP.
|
||||
|
||||
- Starts an embedded PostgreSQL (pg0) automatically
|
||||
- Runs database migrations on startup
|
||||
- Exposes the full MCP endpoint at `http://localhost:8888/mcp/`
|
||||
- Data persists in `~/.pg0/hindsight-mcp/` across restarts
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Start the server
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_API_KEY=sk-... uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
|
||||
Or with Ollama (no API key needed):
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_PROVIDER=ollama HINDSIGHT_API_LLM_MODEL=llama3.2 uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
|
||||
### 2. Configure your MCP client
|
||||
|
||||
**Claude Code:**
|
||||
|
||||
```bash
|
||||
claude mcp add --transport http hindsight http://localhost:8888/mcp/
|
||||
```
|
||||
|
||||
**Other MCP clients** — add an HTTP transport entry pointing to `http://localhost:8888/mcp/`.
|
||||
|
||||
## Bank Modes
|
||||
|
||||
The local server supports the same two modes as the hosted API:
|
||||
|
||||
### Multi-bank mode (default)
|
||||
|
||||
Use `http://localhost:8888/mcp/` — exposes all tools including bank management. Bank is selected per-request via the `bank_id` tool parameter or the `X-Bank-Id` header.
|
||||
|
||||
```bash
|
||||
claude mcp add --transport http hindsight http://localhost:8888/mcp/
|
||||
```
|
||||
|
||||
### Single-bank mode
|
||||
|
||||
Use `http://localhost:8888/mcp/<bank-id>/` — pins all tools to one bank, no `bank_id` parameter needed. This replaces the old `HINDSIGHT_API_MCP_LOCAL_BANK_ID` env var.
|
||||
|
||||
```bash
|
||||
claude mcp add --transport http hindsight http://localhost:8888/mcp/my-bank/
|
||||
```
|
||||
|
||||
## Available Tools
|
||||
|
||||
The local server exposes the full tool set (29 tools in multi-bank mode, 26 in single-bank mode):
|
||||
|
||||
**Core Memory**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `retain` | Store information to long-term memory with optional tags, metadata, and document association |
|
||||
| `recall` | Search memories with natural language, configurable budget, type filters, and tag filters |
|
||||
| `reflect` | Synthesize memories into a reasoned answer with optional structured output |
|
||||
|
||||
**Mental Models**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_mental_models` | List pinned reflections for a bank |
|
||||
| `get_mental_model` | Get a specific mental model |
|
||||
| `create_mental_model` | Create a new mental model with optional auto-refresh trigger |
|
||||
| `update_mental_model` | Update a mental model's metadata |
|
||||
| `delete_mental_model` | Delete a mental model |
|
||||
| `refresh_mental_model` | Regenerate a mental model's content |
|
||||
|
||||
**Directives**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_directives` | List directives that guide memory processing |
|
||||
| `create_directive` | Create a new directive |
|
||||
| `delete_directive` | Delete a directive |
|
||||
|
||||
**Memory Browsing**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_memories` | Browse memories with filtering and pagination |
|
||||
| `get_memory` | Get a specific memory by ID |
|
||||
| `delete_memory` | Delete a specific memory |
|
||||
|
||||
**Documents**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_documents` | List ingested documents |
|
||||
| `get_document` | Get a specific document |
|
||||
| `delete_document` | Delete a document and its linked memories |
|
||||
|
||||
**Operations**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_operations` | List async operations with status filtering |
|
||||
| `get_operation` | Check operation status and progress |
|
||||
| `cancel_operation` | Cancel a pending or running operation |
|
||||
|
||||
**Tags & Bank Management**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_tags` | List unique tags used in a bank |
|
||||
| `get_bank` | Get bank profile (name, mission, disposition) |
|
||||
| `get_bank_stats` | Get bank statistics (multi-bank only) |
|
||||
| `update_bank` | Update bank name or mission |
|
||||
| `delete_bank` | Delete an entire bank and all its data |
|
||||
| `clear_memories` | Clear memories without deleting the bank |
|
||||
| `list_banks` | List all memory banks (multi-bank only) |
|
||||
| `create_bank` | Create or configure a memory bank (multi-bank only) |
|
||||
|
||||
For detailed parameter documentation, see the [MCP Server reference](../../developer/mcp-server.md#available-tools).
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All standard [Hindsight configuration variables](../../developer/configuration.md) are supported. Key ones for local use:
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `HINDSIGHT_API_LLM_API_KEY` | Yes* | — | API key for your LLM provider |
|
||||
| `HINDSIGHT_API_LLM_PROVIDER` | No | `openai` | LLM provider (`openai`, `anthropic`, `ollama`, etc.) |
|
||||
| `HINDSIGHT_API_LLM_MODEL` | No | `gpt-4o-mini` | Model name |
|
||||
| `HINDSIGHT_API_DATABASE_URL` | No | `pg0://hindsight-mcp` | Override the database URL |
|
||||
| `HINDSIGHT_API_PORT` | No | `8888` | Port to listen on |
|
||||
| `HINDSIGHT_API_LOG_LEVEL` | No | `info` | Log level |
|
||||
|
||||
*Not required when using a local provider like Ollama.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Slow first startup
|
||||
|
||||
The first startup downloads the local embedding model (~100MB) and initializes the database. Subsequent starts are faster.
|
||||
|
||||
### Port already in use
|
||||
|
||||
Set a different port:
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_API_KEY=sk-... HINDSIGHT_API_PORT=9000 uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
|
||||
Then update your MCP client URL to `http://localhost:9000/mcp/`.
|
||||
|
||||
### Checking logs
|
||||
|
||||
Set `HINDSIGHT_API_LOG_LEVEL=debug` for verbose output:
|
||||
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_API_KEY=sk-... HINDSIGHT_API_LOG_LEVEL=debug uvx --from hindsight-api hindsight-local-mcp
|
||||
```
|
||||
@@ -1,250 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "NemoClaw Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Add persistent memory to NemoClaw sandboxed agents with Hindsight. One command adds automated memory extraction and auto-recall to any NemoClaw sandbox — no code changes required."
|
||||
---
|
||||
|
||||
# NemoClaw
|
||||
|
||||
Persistent memory for [NemoClaw](https://nemoclaw.ai) sandboxed agents using [Hindsight](https://hindsight.vectorize.io).
|
||||
|
||||
NemoClaw runs [OpenClaw](https://openclaw.ai) inside an OpenShell sandbox with controlled filesystem, process, and network egress policies. The `hindsight-nemoclaw` package automates adding Hindsight memory to a sandbox in one command — no code changes required.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/nemoclaw.md)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
npx @vectorize-io/hindsight-nemoclaw setup \
|
||||
--sandbox my-assistant \
|
||||
--api-url https://api.hindsight.vectorize.io \
|
||||
--api-token <your-api-key> \
|
||||
--bank-prefix my-sandbox
|
||||
```
|
||||
|
||||
Get an API key at [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup).
|
||||
|
||||
You'll see output like:
|
||||
|
||||
```
|
||||
[0] Preflight checks...
|
||||
✓ openshell found
|
||||
✓ openclaw found
|
||||
|
||||
[1] Installing @vectorize-io/hindsight-openclaw plugin...
|
||||
✓ Plugin installed
|
||||
|
||||
[2] Configuring plugin in ~/.openclaw/openclaw.json...
|
||||
✓ Plugin config written (bank: my-sandbox-openclaw)
|
||||
|
||||
[3] Applying Hindsight network policy to sandbox "my-assistant"...
|
||||
✓ Policy version 2 submitted
|
||||
✓ Policy version 2 loaded (active version: 2)
|
||||
|
||||
[4] Restarting OpenClaw gateway...
|
||||
✓ Gateway restarted
|
||||
|
||||
✓ Setup complete!
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### The sandbox problem
|
||||
|
||||
OpenShell enforces strict network egress — every outbound endpoint must be explicitly permitted in the sandbox policy. By default, the Hindsight API (`api.hindsight.vectorize.io`) is not in that list.
|
||||
|
||||
The `hindsight-openclaw` plugin supports **external API mode**, where it skips the local daemon entirely and makes direct HTTPS calls to Hindsight Cloud. This is the natural fit for sandboxed environments: the plugin becomes a thin HTTP client, and the only sandbox change needed is one egress rule.
|
||||
|
||||
### What the setup command does
|
||||
|
||||
1. **Preflight** — verifies `openshell` and `openclaw` are installed
|
||||
2. **Install plugin** — runs `openclaw plugins install @vectorize-io/hindsight-openclaw`
|
||||
3. **Configure plugin** — writes external API mode config to `~/.openclaw/openclaw.json`
|
||||
4. **Apply policy** — reads the current sandbox policy, merges the Hindsight egress block, and re-applies via `openshell policy set`
|
||||
5. **Restart gateway** — runs `openclaw gateway restart`
|
||||
|
||||
### Memory flow
|
||||
|
||||
Once set up, the `hindsight-openclaw` plugin hooks into the OpenClaw gateway lifecycle:
|
||||
|
||||
- **`before_agent_start`** — recalls relevant memories from past sessions and injects them into context
|
||||
- **`agent_end`** — retains the conversation to the Hindsight memory bank
|
||||
|
||||
The sandbox doesn't interfere with either step — it sees the Hindsight calls as normal HTTPS egress to a permitted endpoint.
|
||||
|
||||
## CLI Reference
|
||||
|
||||
```
|
||||
hindsight-nemoclaw setup [options]
|
||||
|
||||
Options:
|
||||
--sandbox <name> NemoClaw sandbox name (required)
|
||||
--api-url <url> Hindsight API URL (required)
|
||||
--api-token <token> Hindsight API token (required)
|
||||
--bank-prefix <prefix> Memory bank prefix (default: "nemoclaw")
|
||||
--skip-policy Skip sandbox network policy update
|
||||
--skip-plugin-install Skip openclaw plugin installation
|
||||
--dry-run Preview changes without applying
|
||||
--help Show help
|
||||
```
|
||||
|
||||
Use `--dry-run` to preview all changes before applying anything. Use `--skip-policy` if you manage sandbox policies manually.
|
||||
|
||||
## Manual Setup
|
||||
|
||||
If you prefer to apply the steps yourself instead of using the CLI:
|
||||
|
||||
### 1. Install the plugin
|
||||
|
||||
```bash
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
### 2. Configure `~/.openclaw/openclaw.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"hindsightApiUrl": "https://api.hindsight.vectorize.io",
|
||||
"hindsightApiToken": "<your-api-key>",
|
||||
"llmProvider": "claude-code",
|
||||
"dynamicBankId": false,
|
||||
"bankIdPrefix": "my-sandbox"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`llmProvider: "claude-code"` uses the Claude Code process already present in the sandbox — no additional API key needed.
|
||||
|
||||
### 3. Add the Hindsight network policy
|
||||
|
||||
`openshell policy set` replaces the entire policy document. Export your current policy first, add the Hindsight block, then re-apply:
|
||||
|
||||
```yaml
|
||||
network_policies:
|
||||
hindsight:
|
||||
name: hindsight
|
||||
endpoints:
|
||||
- host: api.hindsight.vectorize.io
|
||||
port: 443
|
||||
protocol: rest
|
||||
tls: terminate
|
||||
enforcement: enforce
|
||||
rules:
|
||||
- allow:
|
||||
method: GET
|
||||
path: /**
|
||||
- allow:
|
||||
method: POST
|
||||
path: /**
|
||||
- allow:
|
||||
method: PUT
|
||||
path: /**
|
||||
binaries:
|
||||
- path: /usr/local/bin/openclaw
|
||||
```
|
||||
|
||||
```bash
|
||||
openshell policy set my-sandbox --policy /path/to/full-policy.yaml --wait
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `hindsightApiUrl` | string | — | Hindsight API base URL |
|
||||
| `hindsightApiToken` | string | — | API token for authentication |
|
||||
| `llmProvider` | string | auto-detect | LLM provider for memory extraction |
|
||||
| `dynamicBankId` | boolean | `false` | Isolate memory per user (`true`) or share across sessions (`false`) |
|
||||
| `bankIdPrefix` | string | `"nemoclaw"` | Prefix for the memory bank name |
|
||||
|
||||
### Bank naming
|
||||
|
||||
When `dynamicBankId: false`, all sessions write to a single bank named `{bankIdPrefix}-openclaw`. When `dynamicBankId: true`, each user gets an isolated bank — useful for multi-tenant deployments.
|
||||
|
||||
## Verifying It Works
|
||||
|
||||
After setup, check the gateway logs:
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
```
|
||||
|
||||
On startup you should see:
|
||||
|
||||
```
|
||||
[Hindsight] Plugin loaded successfully
|
||||
[Hindsight] ✓ Using external API: https://api.hindsight.vectorize.io
|
||||
[Hindsight] External API health: {"status":"healthy","database":"connected"}
|
||||
[Hindsight] Default bank: my-sandbox-openclaw
|
||||
[Hindsight] ✓ Ready (external API mode)
|
||||
```
|
||||
|
||||
After a conversation:
|
||||
|
||||
```
|
||||
[Hindsight] before_agent_start - bank: my-sandbox-openclaw, channel: undefined/webchat
|
||||
[Hindsight Hook] agent_end triggered - bank: my-sandbox-openclaw
|
||||
[Hindsight] Retained 6 messages to bank my-sandbox-openclaw for session agent:main:...
|
||||
```
|
||||
|
||||
## Pitfalls
|
||||
|
||||
### Policy replacement is full-document
|
||||
|
||||
`openshell policy set` replaces the entire policy document. The `hindsight-nemoclaw setup` command handles this automatically. If you're applying manually, export the current policy first so existing rules aren't lost.
|
||||
|
||||
### LaunchAgent can't follow symlinks on macOS
|
||||
|
||||
On macOS, the OpenClaw gateway runs as a LaunchAgent under a restricted security context. `openclaw plugins install --link` creates a symlink the LaunchAgent can't follow — the setup command installs as a copy instead. If you see `EPERM: operation not permitted, scandir` in gateway logs, this is the cause.
|
||||
|
||||
### Memory retention is asynchronous
|
||||
|
||||
Fact extraction and entity resolution happen in the background after `retain`. If you open a new session immediately after closing one, the most recent memories may not be indexed yet — typically a few seconds.
|
||||
|
||||
### Binary-scoped egress
|
||||
|
||||
The `binaries` field in the network policy restricts the egress rule to a specific executable path. If OpenClaw updates and the binary path changes, the rule silently stops working. Check your binary path after upgrades.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
```bash
|
||||
openclaw plugins list | grep hindsight
|
||||
# Should show: ✓ enabled │ Hindsight Memory │ ...
|
||||
|
||||
# Reinstall
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
### Egress blocked
|
||||
|
||||
If calls to `api.hindsight.vectorize.io` are being blocked, check the active sandbox policy:
|
||||
|
||||
```bash
|
||||
openshell sandbox get my-assistant
|
||||
```
|
||||
|
||||
Verify the `hindsight` block is present and the `binaries` path matches your OpenClaw binary:
|
||||
|
||||
```bash
|
||||
which openclaw
|
||||
```
|
||||
|
||||
### External API not connecting
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
|
||||
# If you see daemon startup messages instead of "Using external API",
|
||||
# the plugin config isn't being read — check ~/.openclaw/openclaw.json
|
||||
```
|
||||
@@ -1,374 +0,0 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
title: "OpenClaw Persistent Memory with Hindsight | Plugin Integration"
|
||||
description: "Add persistent, automated memory to your OpenClaw agent with Hindsight. Local-first, open source — one plugin install replaces built-in memory with structured knowledge extraction and auto-recall."
|
||||
---
|
||||
|
||||
# OpenClaw
|
||||
|
||||
Local, long term memory for [OpenClaw](https://openclaw.ai) agents using [Hindsight](https://vectorize.io/hindsight).
|
||||
|
||||
This plugin integrates [hindsight-embed](https://vectorize.io/hindsight/cli), a standalone daemon that bundles Hindsight's memory engine (API + PostgreSQL) into a single command. Everything runs locally on your machine, reuses the LLM you're already paying for, and costs nothing extra.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/openclaw.md)
|
||||
|
||||
## Quick Start
|
||||
|
||||
**Step 1: Set up LLM for memory extraction**
|
||||
|
||||
Choose one provider and set its API key:
|
||||
|
||||
```bash
|
||||
# Option A: OpenAI
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option B: Anthropic
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
|
||||
# Option C: Gemini
|
||||
export GEMINI_API_KEY="your-key"
|
||||
|
||||
# Option D: Groq
|
||||
export GROQ_API_KEY="your-key"
|
||||
|
||||
# Option E: Claude Code (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option F: OpenAI Codex (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||
```
|
||||
|
||||
**Step 2: Install the plugin**
|
||||
|
||||
```bash
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
**Step 3: Start OpenClaw**
|
||||
|
||||
```bash
|
||||
openclaw gateway
|
||||
```
|
||||
|
||||
The plugin will automatically:
|
||||
- Start a local Hindsight daemon (port 9077)
|
||||
- Capture conversations after each turn
|
||||
- Inject relevant memories before agent responses
|
||||
|
||||
**Important:** The LLM you configure above is **only for memory extraction** (background processing). Your main OpenClaw agent can use any model you configure separately.
|
||||
|
||||
## How It Works
|
||||
|
||||
**Auto-Capture:** Every conversation is automatically stored after each turn. Facts, entities, and relationships are extracted in the background.
|
||||
|
||||
**Auto-Recall:** Before each agent response, relevant memories are automatically injected into the context (up to 1024 tokens). The agent uses past context without needing to call tools.
|
||||
|
||||
**Feedback Loop Prevention:** The plugin automatically strips injected memory tags (`<hindsight_memories>`) before storing conversations. This prevents recalled memories from being re-extracted as new facts, which would cause exponential memory growth and duplicate entries.
|
||||
|
||||
Traditional memory systems give agents a `search_memory` tool - but models don't use it consistently. Auto-recall solves this by injecting memories automatically before every turn.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Plugin Settings
|
||||
|
||||
Optional settings in `~/.openclaw/openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"apiPort": 9077,
|
||||
"daemonIdleTimeout": 0,
|
||||
"embedVersion": "latest"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `apiPort` - Port for the openclaw profile daemon (default: `9077`)
|
||||
- `daemonIdleTimeout` - Seconds before daemon shuts down from inactivity (default: `0` = never)
|
||||
- `embedVersion` - hindsight-embed version (default: `"latest"`)
|
||||
- `bankMission` - Agent identity/purpose stored on the memory bank. Helps the memory engine understand context for better fact extraction during retain. Set once per bank on first use — not a recall prompt.
|
||||
- `dynamicBankId` - Enable per-context memory banks (default: `true`)
|
||||
- `bankIdPrefix` - Optional prefix for bank IDs (e.g. `"prod"` → `"prod-slack-C123"`)
|
||||
- `dynamicBankGranularity` - Fields used to derive bank ID: `agent`, `channel`, `user`, `provider` (default: `["agent", "channel", "user"]`)
|
||||
- `excludeProviders` - Message providers to skip for recall/retain (e.g. `["slack"]`, `["telegram"]`, `["discord"]`)
|
||||
- `autoRecall` - Auto-inject memories before each turn (default: `true`). Set to `false` when the agent has its own recall tool.
|
||||
- `autoRetain` - Auto-retain conversations after each turn (default: `true`)
|
||||
- `retainRoles` - Which message roles to retain (default: `["user", "assistant"]`). Options: `user`, `assistant`, `system`, `tool`
|
||||
- `recallBudget` - Recall effort: `"low"`, `"mid"`, or `"high"` (default: `"mid"`). Higher budgets use more retrieval strategies for better results.
|
||||
- `recallMaxTokens` - Max tokens for recall response (default: `1024`). Controls how much memory context is injected per turn.
|
||||
- `recallTopK` - Max number of memories to inject per turn (default: unlimited).
|
||||
- `recallTypes` - Memory types to recall (default: `["world", "experience"]`). Options: `world`, `experience`, `observation`.
|
||||
- `recallContextTurns` - Number of prior user turns to include in the recall query (default: `1`).
|
||||
- `recallMaxQueryChars` - Max characters for the composed recall query (default: `800`).
|
||||
- `recallPromptPreamble` - Custom preamble text placed above recalled memories. Overrides the built-in guidance text.
|
||||
- `recallInjectionPosition` - Where to inject recalled memories: `"prepend"` (default), `"append"`, or `"user"`. Use `"append"` to preserve prompt caching with large static system prompts. Use `"user"` to inject before the user message instead of in the system prompt.
|
||||
- `recallRoles` - Which message roles to include when composing the contextual recall query (default: `["user", "assistant"]`).
|
||||
- `retainEveryNTurns` - Retain every Nth turn (default: `1` = every turn). Values > 1 enable chunked retention.
|
||||
- `retainOverlapTurns` - Extra prior turns included when chunked retention fires (default: `0`).
|
||||
- `debug` - Enable debug logging (default: `false`).
|
||||
|
||||
### Memory Isolation
|
||||
|
||||
The plugin creates separate memory banks based on conversation context. By default, banks are derived from the `agent`, `channel`, and `user` fields — so each unique combination gets its own isolated memory store.
|
||||
|
||||
You can customize which fields are used for bank segmentation with `dynamicBankGranularity`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"dynamicBankGranularity": ["provider", "user"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, memories are isolated per provider + user, meaning the same user shares memories across all channels within a provider.
|
||||
|
||||
Available isolation fields:
|
||||
- `agent` - The agent/bot identity
|
||||
- `channel` - The channel or conversation ID
|
||||
- `user` - The user interacting with the agent
|
||||
- `provider` - The message provider (e.g. Slack, Discord)
|
||||
|
||||
Use `bankIdPrefix` to namespace bank IDs across environments (e.g. `"prod"`, `"staging"`). Set `dynamicBankId` to `false` to use a single shared bank for all conversations.
|
||||
|
||||
### Retention Controls
|
||||
|
||||
By default, the plugin retains `user` and `assistant` messages after each turn. You can customize this behavior:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"autoRetain": true,
|
||||
"retainRoles": ["user", "assistant", "system"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `autoRetain` - Set to `false` to disable automatic retention entirely (useful if you handle retention yourself)
|
||||
- `retainRoles` - Controls which message roles are included in the retained transcript. Only messages from the last user message onward are retained each turn, preventing duplicate storage.
|
||||
|
||||
### LLM Configuration
|
||||
|
||||
The plugin auto-detects your LLM provider from these environment variables:
|
||||
|
||||
| Provider | Env Var | Notes |
|
||||
|----------|---------|-------|
|
||||
| OpenAI | `OPENAI_API_KEY` | |
|
||||
| Anthropic | `ANTHROPIC_API_KEY` | |
|
||||
| Gemini | `GEMINI_API_KEY` | |
|
||||
| Groq | `GROQ_API_KEY` | |
|
||||
| Claude Code | `HINDSIGHT_API_LLM_PROVIDER=claude-code` | No API key needed |
|
||||
| OpenAI Codex | `HINDSIGHT_API_LLM_PROVIDER=openai-codex` | No API key needed |
|
||||
|
||||
The model is selected automatically by the Hindsight API. To override, set `HINDSIGHT_API_LLM_MODEL`.
|
||||
|
||||
**Override with explicit config:**
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai
|
||||
export HINDSIGHT_API_LLM_API_KEY=sk-your-key
|
||||
|
||||
# Optional: custom base URL (OpenRouter, Azure, vLLM, etc.)
|
||||
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
```
|
||||
|
||||
**Example: Free OpenRouter model**
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai
|
||||
export HINDSIGHT_API_LLM_MODEL=xiaomi/mimo-v2-flash # FREE!
|
||||
export HINDSIGHT_API_LLM_API_KEY=sk-or-v1-your-openrouter-key
|
||||
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
```
|
||||
|
||||
### External API (Advanced)
|
||||
|
||||
Connect to a remote Hindsight API server instead of running a local daemon. This is useful for:
|
||||
|
||||
- **Shared memory** across multiple OpenClaw instances
|
||||
- **Production deployments** with centralized memory storage
|
||||
- **Team environments** where agents share knowledge
|
||||
|
||||
#### Plugin Configuration
|
||||
|
||||
Configure in `~/.openclaw/openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"hindsight-openclaw": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"hindsightApiUrl": "https://your-hindsight-server.com",
|
||||
"hindsightApiToken": "your-api-token"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `hindsightApiUrl` - Full URL to external Hindsight API (e.g., `https://mcp.hindsight.example.com`)
|
||||
- `hindsightApiToken` - API token for authentication (optional, only if API requires auth)
|
||||
|
||||
#### Environment Variables (Alternative)
|
||||
|
||||
You can also configure via environment variables:
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_EMBED_API_URL=https://your-hindsight-server.com
|
||||
export HINDSIGHT_EMBED_API_TOKEN=your-api-token # Optional
|
||||
|
||||
openclaw gateway
|
||||
```
|
||||
|
||||
**Note:** Plugin config takes precedence over environment variables.
|
||||
|
||||
#### Behavior
|
||||
|
||||
When external API mode is enabled:
|
||||
- **No local daemon** is started (no hindsight-embed process)
|
||||
- **Health check** runs on startup to verify API connectivity
|
||||
- **All memory operations** (retain, recall, reflect) go to the external API
|
||||
- **Faster startup** since no local PostgreSQL or embedding models are needed
|
||||
|
||||
#### Verification
|
||||
|
||||
Check OpenClaw logs for external API mode:
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
|
||||
# Should see on startup:
|
||||
# [Hindsight] External API mode enabled: https://your-hindsight-server.com
|
||||
# [Hindsight] External API health check passed
|
||||
```
|
||||
|
||||
If you see daemon startup messages instead, verify your configuration is correct.
|
||||
|
||||
## Inspecting Memories
|
||||
|
||||
### Check Configuration
|
||||
|
||||
View the daemon config that was written by the plugin:
|
||||
|
||||
```bash
|
||||
cat ~/.hindsight/profiles/openclaw.env
|
||||
```
|
||||
|
||||
This shows the LLM provider, model, port, and other settings the daemon is using.
|
||||
|
||||
### Check Daemon Status
|
||||
|
||||
```bash
|
||||
# Check if daemon is running
|
||||
uvx hindsight-embed@latest -p openclaw daemon status
|
||||
|
||||
# View daemon logs
|
||||
tail -f ~/.hindsight/profiles/openclaw.log
|
||||
```
|
||||
|
||||
### Query Memories
|
||||
|
||||
```bash
|
||||
# Search memories
|
||||
uvx hindsight-embed@latest -p openclaw memory recall openclaw "user preferences"
|
||||
|
||||
# View recent memories
|
||||
uvx hindsight-embed@latest -p openclaw memory list openclaw --limit 10
|
||||
|
||||
# Open web UI (uses openclaw profile's daemon)
|
||||
uvx hindsight-embed@latest -p openclaw ui
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
```bash
|
||||
openclaw plugins list | grep hindsight
|
||||
# Should show: ✓ enabled │ Hindsight Memory │ ...
|
||||
|
||||
# Reinstall if needed
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
### Daemon not starting
|
||||
|
||||
```bash
|
||||
# Check daemon status (note: -p openclaw uses the openclaw profile)
|
||||
uvx hindsight-embed@latest -p openclaw daemon status
|
||||
|
||||
# View logs for errors
|
||||
tail -f ~/.hindsight/profiles/openclaw.log
|
||||
|
||||
# Check configuration
|
||||
cat ~/.hindsight/profiles/openclaw.env
|
||||
|
||||
# List all profiles
|
||||
uvx hindsight-embed@latest profile list
|
||||
```
|
||||
|
||||
### No API key error
|
||||
|
||||
Make sure you've set one of the provider API keys (or use a provider that doesn't require one):
|
||||
|
||||
```bash
|
||||
# Option 1: OpenAI
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option 2: Anthropic
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
|
||||
# Option 3: Claude Code (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option 4: OpenAI Codex (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||
|
||||
# Verify it's set
|
||||
echo $OPENAI_API_KEY
|
||||
# or
|
||||
echo $HINDSIGHT_API_LLM_PROVIDER
|
||||
```
|
||||
|
||||
### Verify it's working
|
||||
|
||||
Check gateway logs for memory operations:
|
||||
|
||||
```bash
|
||||
tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
||||
|
||||
# Should see on startup:
|
||||
# [Hindsight] ✓ Using provider: openai, model: gpt-4o-mini
|
||||
# or
|
||||
# [Hindsight] ✓ Using provider: claude-code, model: claude-sonnet-4-20250514
|
||||
|
||||
# Should see after conversations:
|
||||
# [Hindsight] Retained X messages for session ...
|
||||
# [Hindsight] Auto-recall: Injecting X memories
|
||||
```
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
title: "Pydantic AI Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Pydantic AI agents with Hindsight. Async-native retain, recall, and reflect tools — persistent memory across all agent runs with no thread-pool hacks."
|
||||
---
|
||||
|
||||
# Pydantic AI
|
||||
|
||||
Persistent memory tools for [Pydantic AI](https://ai.pydantic.dev/) agents via Hindsight. Give your agents long-term memory with retain, recall, and reflect — all async-native with no thread-pool hacks.
|
||||
|
||||
[View Changelog →](../../changelog/integrations/pydantic-ai.md)
|
||||
|
||||
## Features
|
||||
|
||||
- **Async-Native Tools** — Uses Pydantic AI's async tool interface directly (`aretain`, `arecall`, `areflect`)
|
||||
- **Memory Instructions** — Auto-inject relevant memories into every agent run via `instructions=[...]`
|
||||
- **Three Memory Tools** — Retain (store), Recall (search), Reflect (synthesize) — include any combination
|
||||
- **Simple Configuration** — Configure once globally, or pass a client directly
|
||||
- **Lightweight** — Depends on `pydantic-ai-slim` to avoid pulling in all model providers
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-pydantic-ai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from hindsight_client import Hindsight
|
||||
from hindsight_pydantic_ai import create_hindsight_tools, memory_instructions
|
||||
from pydantic_ai import Agent
|
||||
|
||||
client = Hindsight(base_url="http://localhost:8888")
|
||||
|
||||
agent = Agent(
|
||||
"openai:gpt-4o",
|
||||
tools=create_hindsight_tools(client=client, bank_id="user-123"),
|
||||
instructions=[memory_instructions(client=client, bank_id="user-123")],
|
||||
)
|
||||
|
||||
result = await agent.run("What do you remember about my preferences?")
|
||||
print(result.output)
|
||||
```
|
||||
|
||||
The agent now has three tools it can call:
|
||||
|
||||
- **`hindsight_retain`** — Store information to long-term memory
|
||||
- **`hindsight_recall`** — Search long-term memory for relevant facts
|
||||
- **`hindsight_reflect`** — Synthesize a reasoned answer from memories
|
||||
|
||||
The `memory_instructions` callable automatically recalls relevant memories and injects them into the system prompt on every run.
|
||||
|
||||
## Tools Only (No Auto-Injection)
|
||||
|
||||
If you want the agent to decide when to use memory rather than always injecting context:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
"openai:gpt-4o",
|
||||
tools=create_hindsight_tools(client=client, bank_id="user-123"),
|
||||
)
|
||||
```
|
||||
|
||||
## Instructions Only (No Tools)
|
||||
|
||||
If you just want memories auto-injected without giving the agent explicit memory tools:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
"openai:gpt-4o",
|
||||
instructions=[memory_instructions(client=client, bank_id="user-123")],
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
include_retain=True,
|
||||
include_recall=True,
|
||||
include_reflect=False, # Omit reflect
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing a client to every call, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_pydantic_ai import configure, create_hindsight_tools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create tools without passing client — uses global config
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
## Per-Tool Overrides
|
||||
|
||||
Constructor arguments override global configuration:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
budget="high", # Override global budget
|
||||
max_tokens=8192, # Override global max_tokens
|
||||
tags=["session:abc"], # Override global tags
|
||||
)
|
||||
```
|
||||
|
||||
## Memory Instructions Options
|
||||
|
||||
Customize what memories get injected and how:
|
||||
|
||||
```python
|
||||
instructions_fn = memory_instructions(
|
||||
client=client,
|
||||
bank_id="user-123",
|
||||
query="relevant context about the user", # What to search for
|
||||
budget="low", # Keep it fast
|
||||
max_results=5, # Limit injected memories
|
||||
max_tokens=4096, # Max recall tokens
|
||||
prefix="Relevant memories:\n", # Text before the memory list
|
||||
tags=["scope:global"], # Filter by tags
|
||||
tags_match="any", # Tag match mode
|
||||
)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `create_hindsight_tools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `include_retain` | `True` | Include the retain (store) tool |
|
||||
| `include_recall` | `True` | Include the recall (search) tool |
|
||||
| `include_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `memory_instructions()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `query` | `"relevant context about the user"` | Recall query for memory injection |
|
||||
| `budget` | `"low"` | Recall budget level |
|
||||
| `max_results` | `5` | Maximum memories to inject |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `prefix` | `"Relevant memories:\n"` | Text prepended before memory list |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
@@ -1,325 +0,0 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
title: "Hindsight Agent Memory Skill | AI Coding Assistant Integration"
|
||||
description: "Give AI coding assistants like Claude Code and Codex persistent memory across sessions with Hindsight's Agent Skill — a reusable prompt template for long-term context retention."
|
||||
---
|
||||
|
||||
# Skills
|
||||
|
||||
Hindsight provides an Agent Skill that gives AI coding assistants persistent memory across sessions. Skills are reusable prompt templates that agents can load when needed to gain specialized capabilities.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Skills Directory |
|
||||
|----------|-----------------|
|
||||
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `~/.claude/skills/` |
|
||||
| [OpenCode](https://github.com/opencode-ai/opencode) | `~/.opencode/skills/` |
|
||||
| [Codex CLI](https://github.com/openai/codex) | `~/.codex/skills/` |
|
||||
|
||||
## Deployment Modes
|
||||
|
||||
The skill supports two deployment modes:
|
||||
|
||||
| Mode | Best For | Data Location |
|
||||
|------|----------|---------------|
|
||||
| **Local** | Individual developers | Your machine (`~/.pg0/`) |
|
||||
| **Cloud** | Teams sharing knowledge | Hindsight Cloud |
|
||||
|
||||
## Quick Install
|
||||
|
||||
### Option 1: Interactive Installer (Recommended)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash
|
||||
```
|
||||
|
||||
The installer will:
|
||||
1. Prompt you to select your AI coding assistant
|
||||
2. Select deployment mode (local or cloud)
|
||||
3. Configure the appropriate settings
|
||||
4. Install the skill to the appropriate directory
|
||||
|
||||
### Install for a Specific Platform
|
||||
|
||||
```bash
|
||||
# Claude Code (interactive mode selection)
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude
|
||||
|
||||
# OpenCode
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app opencode
|
||||
|
||||
# Codex CLI
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app codex
|
||||
```
|
||||
|
||||
### Install with Cloud Mode
|
||||
|
||||
```bash
|
||||
# Direct cloud setup (skips interactive prompts for mode)
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude --mode cloud
|
||||
```
|
||||
|
||||
### Option 2: Using add-skill
|
||||
|
||||
If you use [add-skill](https://add-skill.org/) to manage your agent skills:
|
||||
|
||||
```bash
|
||||
# For local mode (individual developers)
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-local
|
||||
|
||||
# For Hindsight Cloud (teams)
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-cloud
|
||||
|
||||
# For self-hosted Hindsight servers
|
||||
npx add-skill vectorize-io/hindsight --skill hindsight-self-hosted
|
||||
```
|
||||
|
||||
On first use, the AI will guide you through the remaining setup:
|
||||
- **Local**: Run `uvx hindsight-embed configure` to set up your LLM provider
|
||||
- **Cloud**: Provide your API key and bank ID
|
||||
- **Self-hosted**: Provide your server URL, API key, and bank ID
|
||||
|
||||
## What the Skill Provides
|
||||
|
||||
Once installed, your AI assistant gains the ability to:
|
||||
|
||||
- **Retain** - Store user preferences, learnings, and procedure outcomes
|
||||
- **Recall** - Search for relevant context before starting tasks
|
||||
- **Reflect** - Synthesize memories into contextual answers
|
||||
|
||||
The skill uses the `hindsight-embed` CLI which runs a lightweight local daemon with an embedded database.
|
||||
|
||||
## How Skills Work
|
||||
|
||||
Skills are **model-invoked**, meaning the AI assistant automatically decides when to use them based on the context of your conversation. You don't need to explicitly trigger the skill.
|
||||
|
||||
The assistant will:
|
||||
- **Store** when you share preferences, when tasks succeed/fail, or when learnings emerge
|
||||
- **Recall** before starting non-trivial tasks to get relevant context
|
||||
|
||||
### What Gets Stored
|
||||
|
||||
The skill is optimized to store:
|
||||
|
||||
| Category | Examples |
|
||||
|----------|----------|
|
||||
| **User Preferences** | Coding style, tool preferences, language choices |
|
||||
| **Procedure Outcomes** | Commands that worked, configurations that resolved issues |
|
||||
| **Learnings** | Bug solutions, workarounds, architecture decisions |
|
||||
|
||||
## Architecture
|
||||
|
||||
### Local Mode
|
||||
|
||||
```
|
||||
AI Coding Assistant
|
||||
│
|
||||
▼
|
||||
Hindsight Skill (SKILL.md)
|
||||
│
|
||||
▼
|
||||
hindsight-embed CLI
|
||||
│
|
||||
▼
|
||||
Local Daemon (auto-started)
|
||||
│
|
||||
▼
|
||||
Embedded PostgreSQL (~/.pg0/hindsight-embed/)
|
||||
```
|
||||
|
||||
All data stays on your machine. The daemon auto-starts when needed and shuts down after inactivity.
|
||||
|
||||
### Cloud Mode
|
||||
|
||||
```
|
||||
AI Coding Assistant
|
||||
│
|
||||
▼
|
||||
Hindsight Skill (SKILL.md)
|
||||
│
|
||||
▼
|
||||
hindsight-cli
|
||||
│
|
||||
▼
|
||||
Hindsight Cloud API (https://api.hindsight.vectorize.io)
|
||||
│
|
||||
▼
|
||||
Shared Memory Bank (team-accessible)
|
||||
```
|
||||
|
||||
Data is stored in Hindsight Cloud and shared across your team. All team members with the same bank ID can access shared memories.
|
||||
|
||||
---
|
||||
|
||||
## Local Mode Setup
|
||||
|
||||
The skill uses configuration stored in `~/.hindsight/config.env`. Reconfigure anytime:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cloud Mode Setup
|
||||
|
||||
Cloud mode connects to [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup), allowing teams to share memories about a codebase. When one team member learns something, everyone benefits.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. A Hindsight Cloud account ([sign up](https://ui.hindsight.vectorize.io/signup))
|
||||
2. An API key from your team admin
|
||||
3. A bank ID for your project (e.g., `team-acme-frontend`)
|
||||
|
||||
### Installation
|
||||
|
||||
Run the installer with cloud mode:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
|
||||
```
|
||||
|
||||
You'll be prompted for:
|
||||
|
||||
| Setting | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| **Cloud API URL** | Hindsight Cloud endpoint | `https://api.hindsight.vectorize.io` |
|
||||
| **API Key** | Your authentication key | `hs_xxx...` |
|
||||
| **Bank ID** | Shared memory bank for your team | `team-acme-frontend` |
|
||||
|
||||
### Configuration Files
|
||||
|
||||
Cloud mode creates two files:
|
||||
|
||||
**`~/.hindsight/config`** — API connection settings (TOML format):
|
||||
```toml
|
||||
api_url = "https://api.hindsight.vectorize.io"
|
||||
api_key = "hs_xxx..."
|
||||
```
|
||||
|
||||
**`~/.claude/skills/hindsight/SKILL.md`** — Skill definition with your bank ID baked in.
|
||||
|
||||
### Team Setup
|
||||
|
||||
To set up cloud mode for your team:
|
||||
|
||||
1. **Team admin** creates a bank in Hindsight Cloud (e.g., `team-acme-frontend`)
|
||||
2. **Team admin** generates API keys for each team member
|
||||
3. **Each developer** runs the installer with their API key and the shared bank ID
|
||||
4. All team members now share the same memory bank
|
||||
|
||||
### What to Store in Team Banks
|
||||
|
||||
Cloud mode uses a **shared team bank**. Be thoughtful about what goes in:
|
||||
|
||||
| Type | Examples | How to Store |
|
||||
|------|----------|--------------|
|
||||
| **Project conventions** | Linting rules, testing requirements, Node version | `"Project uses ESLint with Airbnb config"` |
|
||||
| **Team knowledge** | Architecture decisions, common pitfalls, domain logic | `"Auth module requires Redis 7+"` |
|
||||
| **Individual preferences** | Personal coding style, communication preferences | `"Alice prefers verbose commit messages"` |
|
||||
|
||||
**Key distinction**: Project conventions apply to everyone. Individual preferences should include the person's name so the AI knows when to apply them.
|
||||
|
||||
### Example Workflow
|
||||
|
||||
```
|
||||
Day 1: Alice discovers a requirement
|
||||
─────────────────────────────────────
|
||||
Alice's AI assistant stores:
|
||||
"The auth module requires Redis 7+ due to HEXPIRE command usage"
|
||||
"Alice prefers explicit error handling over silent failures"
|
||||
|
||||
Day 2: Bob starts working on auth
|
||||
─────────────────────────────────
|
||||
Bob's AI assistant recalls:
|
||||
"The auth module requires Redis 7+ due to HEXPIRE command usage"
|
||||
|
||||
Bob avoids the same issue Alice hit!
|
||||
(Alice's personal preference is stored but won't be applied to Bob)
|
||||
```
|
||||
|
||||
### Testing Cloud Connection
|
||||
|
||||
After installation, verify the connection:
|
||||
|
||||
```bash
|
||||
# Store a test memory
|
||||
hindsight memory retain team-acme-frontend "Alice works at Google as a software engineer"
|
||||
|
||||
# Recall it
|
||||
hindsight memory recall team-acme-frontend "Alice"
|
||||
```
|
||||
|
||||
### Switching Between Banks
|
||||
|
||||
If you work on multiple projects, you can have different skills installed for each AI assistant, or manually switch banks:
|
||||
|
||||
```bash
|
||||
# Environment variable override (temporary)
|
||||
HINDSIGHT_API_URL=https://api.hindsight.vectorize.io \
|
||||
HINDSIGHT_API_KEY=hs_xxx \
|
||||
hindsight memory recall different-bank "query"
|
||||
```
|
||||
|
||||
For permanent multi-bank setups, reinstall the skill with a different bank ID.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not activating
|
||||
|
||||
The skill activates based on its description matching your request. Try being explicit:
|
||||
- "Remember that..." triggers storage
|
||||
- "What do you know about..." triggers recall
|
||||
|
||||
### Local Mode Issues
|
||||
|
||||
**Daemon not starting:**
|
||||
```bash
|
||||
uvx hindsight-embed daemon status
|
||||
uvx hindsight-embed daemon logs
|
||||
```
|
||||
|
||||
**Reconfigure LLM provider:**
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
### Cloud Mode Issues
|
||||
|
||||
**Authentication errors:**
|
||||
```bash
|
||||
# Verify your config
|
||||
cat ~/.hindsight/config
|
||||
|
||||
# Test connection manually
|
||||
hindsight bank list
|
||||
```
|
||||
|
||||
**Wrong bank ID:**
|
||||
|
||||
Check your SKILL.md file to see which bank ID is configured:
|
||||
```bash
|
||||
cat ~/.claude/skills/hindsight/SKILL.md | grep "memory retain"
|
||||
```
|
||||
|
||||
To change the bank ID, reinstall the skill:
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
|
||||
```
|
||||
|
||||
**Network/firewall issues:**
|
||||
```bash
|
||||
# Test connectivity to cloud API
|
||||
curl -I https://api.hindsight.vectorize.io/health
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
### Local Mode
|
||||
- Python 3.10+ (for `uvx`)
|
||||
- An LLM API key (OpenAI, Anthropic, Groq, etc.)
|
||||
|
||||
### Cloud Mode
|
||||
- Python 3.10+ (for `uvx`)
|
||||
- Hindsight Cloud API key
|
||||
- Network access to `https://api.hindsight.vectorize.io`
|
||||
@@ -1,157 +0,0 @@
|
||||
---
|
||||
sidebar_position: 13
|
||||
title: "Strands Agents Persistent Memory with Hindsight | Integration"
|
||||
description: "Add long-term memory to Strands Agents SDK agents with Hindsight. Retain, recall, and reflect tools using Strands' native @tool pattern for persistent memory across sessions."
|
||||
---
|
||||
|
||||
# Strands Agents
|
||||
|
||||
Persistent memory tools for [Strands Agents SDK](https://github.com/strands-agents/sdk-python) agents via Hindsight. Give your agents long-term memory with retain, recall, and reflect — using Strands' native `@tool` pattern.
|
||||
|
||||
## Features
|
||||
|
||||
- **Native `@tool` Functions** - Tools are plain Python functions, compatible with `Agent(tools=[...])`
|
||||
- **Memory Instructions** - Pre-recall memories for injection into agent system prompt
|
||||
- **Three Memory Tools** - Retain (store), Recall (search), Reflect (synthesize) — include any combination
|
||||
- **Simple Configuration** - Configure once globally, or pass a client directly
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hindsight-strands
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from strands import Agent
|
||||
from hindsight_strands import create_hindsight_tools
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
agent = Agent(tools=tools)
|
||||
agent("Remember that I prefer dark mode")
|
||||
agent("What are my preferences?")
|
||||
```
|
||||
|
||||
The agent now has three tools it can call:
|
||||
|
||||
- **`hindsight_retain`** — Store information to long-term memory
|
||||
- **`hindsight_recall`** — Search long-term memory for relevant facts
|
||||
- **`hindsight_reflect`** — Synthesize a reasoned answer from memories
|
||||
|
||||
## With Memory Instructions
|
||||
|
||||
Pre-recall relevant memories and inject them into the system prompt:
|
||||
|
||||
```python
|
||||
from hindsight_strands import create_hindsight_tools, memory_instructions
|
||||
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
memories = memory_instructions(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
tools=tools,
|
||||
system_prompt=f"You are a helpful assistant.\n\n{memories}",
|
||||
)
|
||||
```
|
||||
|
||||
## Selecting Tools
|
||||
|
||||
Include only the tools you need:
|
||||
|
||||
```python
|
||||
tools = create_hindsight_tools(
|
||||
bank_id="user-123",
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
enable_retain=True,
|
||||
enable_recall=True,
|
||||
enable_reflect=False, # Omit reflect
|
||||
)
|
||||
```
|
||||
|
||||
## Global Configuration
|
||||
|
||||
Instead of passing connection details to every call, configure once:
|
||||
|
||||
```python
|
||||
from hindsight_strands import configure, create_hindsight_tools
|
||||
|
||||
configure(
|
||||
hindsight_api_url="http://localhost:8888",
|
||||
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
|
||||
budget="mid", # Recall budget: low/mid/high
|
||||
max_tokens=4096, # Max tokens for recall results
|
||||
tags=["env:prod"], # Tags for stored memories
|
||||
recall_tags=["scope:global"], # Tags to filter recall
|
||||
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
|
||||
)
|
||||
|
||||
# Now create tools without passing connection details
|
||||
tools = create_hindsight_tools(bank_id="user-123")
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
### `create_hindsight_tools()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `tags` | `None` | Tags applied when storing memories |
|
||||
| `recall_tags` | `None` | Tags to filter when searching |
|
||||
| `recall_tags_match` | `"any"` | Tag matching mode |
|
||||
| `enable_retain` | `True` | Include the retain (store) tool |
|
||||
| `enable_recall` | `True` | Include the recall (search) tool |
|
||||
| `enable_reflect` | `True` | Include the reflect (synthesize) tool |
|
||||
|
||||
### `memory_instructions()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `bank_id` | *required* | Hindsight memory bank ID |
|
||||
| `client` | `None` | Pre-configured Hindsight client |
|
||||
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
|
||||
| `api_key` | `None` | API key (used if no client provided) |
|
||||
| `query` | `"relevant context about the user"` | Recall query for memory injection |
|
||||
| `budget` | `"low"` | Recall budget level |
|
||||
| `max_results` | `5` | Maximum memories to inject |
|
||||
| `max_tokens` | `4096` | Maximum tokens for recall results |
|
||||
| `prefix` | `"Relevant memories:\n"` | Text prepended before memory list |
|
||||
| `tags` | `None` | Tags to filter recall results |
|
||||
| `tags_match` | `"any"` | Tag matching mode |
|
||||
|
||||
### `configure()`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `hindsight_api_url` | Production API | Hindsight API URL |
|
||||
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
|
||||
| `budget` | `"mid"` | Default recall budget level |
|
||||
| `max_tokens` | `4096` | Default max tokens for recall |
|
||||
| `tags` | `None` | Default tags for retain operations |
|
||||
| `recall_tags` | `None` | Default tags to filter recall |
|
||||
| `recall_tags_match` | `"any"` | Default tag matching mode |
|
||||
| `verbose` | `False` | Enable verbose logging |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- strands-agents
|
||||
- hindsight-client >= 0.4.0
|
||||
- A running Hindsight API server
|
||||
Reference in New Issue
Block a user