fleet-memory/hindsight-docs/static/llms-full.txt
Nicolò Boschi 4191597098 add llms.txt
2025-12-10 13:51:21 +01:00

7792 lines
224 KiB
Text

# Hindsight Documentation
> Agent Memory that Works Like Human Memory
This file contains the complete Hindsight documentation for LLM consumption.
Generated: 2025-12-10T12:49:48.043Z
---
## File: developer/index.md
# Overview
## Why Hindsight?
AI agents forget everything between sessions. Every conversation starts from zero—no context about who you are, what you've discussed, or what the assistant has learned. This isn't just an implementation detail; it fundamentally limits what AI Agents can do.
**The problem is harder than it looks:**
- **Simple vector search isn't enough** — "What did Alice do last spring?" requires temporal reasoning, not just semantic similarity
- **Facts get disconnected** — Knowing "Alice works at Google" and "Google is in Mountain View" should let you answer "Where does Alice work?" even if you never stored that directly
- **AI Agents needs to form opinions** — A coding assistant that remembers "the user prefers functional programming" should weigh that when making recommendations
- **Context matters** — The same information means different things to different memory banks with different personalities
Hindsight solves these problems with a memory system designed specifically for AI agents.
## What Hindsight Does
```mermaid
graph TB
subgraph app["<b>Your Application</b>"]
Agent[AI Agent]
end
subgraph hindsight["<b>Hindsight</b>"]
API[API Server]
subgraph bank["<b>Memory Bank</b>"]
Documents[Documents]
Memories[Memories]
Entities[Entities]
end
end
Agent -->|retain| API
Agent -->|recall| API
Agent -->|reflect| API
API --> Documents
API --> Memories
API --> Entities
```
**Your AI agent** stores information via `retain()`, searches with `recall()`, and reasons with `reflect()` — all interactions with its dedicated **memory bank**
## Key Components
### Three Memory Types
Hindsight separates memories by type for epistemic clarity:
| Type | What it stores | Example |
|------|----------------|---------|
| **World** | Objective facts received | "Alice works at Google" |
| **Bank** | Bank's own actions | "I recommended Python to Bob" |
| **Opinion** | Formed beliefs + confidence | "Python is best for ML" (0.85) |
### Multi-Strategy Retrieval (TEMPR)
Four search strategies run in parallel:
```mermaid
graph LR
Q[Query] --> S[Semantic]
Q --> K[Keyword]
Q --> G[Graph]
Q --> T[Temporal]
S --> RRF[RRF Fusion]
K --> RRF
G --> RRF
T --> RRF
RRF --> CE[Cross-Encoder]
CE --> R[Results]
```
| Strategy | Best for |
|----------|----------|
| **Semantic** | Conceptual similarity, paraphrasing |
| **Keyword (BM25)** | Names, technical terms, exact matches |
| **Graph** | Related entities, indirect connections |
| **Temporal** | "last spring", "in June", time ranges |
### Personality Framework (CARA)
Memory banks have Big Five personality traits that influence opinion formation:
| Trait | Low | High |
|-------|-----|------|
| **Openness** | Prefers proven methods | Embraces new ideas |
| **Conscientiousness** | Flexible, spontaneous | Systematic, organized |
| **Extraversion** | Independent | Collaborative |
| **Agreeableness** | Direct, analytical | Diplomatic, harmonious |
| **Neuroticism** | Calm, optimistic | Risk-aware, cautious |
The `bias_strength` parameter (0-1) controls how much personality influences opinions.
## Next Steps
### Getting Started
- [**Quick Start**](/developer/api/quickstart) — Install and get up and running in 60 seconds
- [**RAG vs Hindsight**](/developer/rag-vs-hindsight) — See how Hindsight differs from traditional RAG with real examples
### Core Concepts
- [**Retain**](/developer/retain) — How memories are stored with multi-dimensional facts
- [**Recall**](/developer/retrieval) — How TEMPR's 4-way search retrieves memories
- [**Reflect**](/developer/reflect) — How personality influences reasoning and opinion formation
### API Methods
- [**Retain**](/developer/api/retain) — Store information in memory banks
- [**Recall**](/developer/api/recall) — Search and retrieve memories
- [**Reflect**](/developer/api/reflect) — Reason with personality
- [**Memory Banks**](/developer/api/memory-banks) — Configure personality and background
- [**Entities**](/developer/api/entities) — Track people, places, and concepts
- [**Documents**](/developer/api/documents) — Manage document sources
- [**Operations**](/developer/api/operations) — Monitor async tasks
### Deployment
- [**Server Setup**](/developer/installation) — Deploy with Docker Compose, Helm, or pip
---
## File: developer/api/quickstart.md
# Quick Start
Get up and running with Hindsight in 60 seconds.
## Start the Server
<Tabs>
<TabItem value="pip" label="pip (API only)">
```bash
pip install hindsight-all
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
hindsight-api
```
API available at http://localhost:8888
</TabItem>
<TabItem value="docker" label="Docker (Full Experience)">
```bash
docker run -p 8888:8888 -p 9999:9999 \
-e HINDSIGHT_API_LLM_PROVIDER=groq \
-e HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx \
ghcr.io/vectorize-io/hindsight
```
- **API**: http://localhost:8888
- **Control Plane** (Web UI): http://localhost:9999
</TabItem>
</Tabs>
:::tip LLM Provider
Hindsight requires an LLM with structured output support. Recommended: **Groq** with `gpt-oss-20b` for fast, cost-effective inference. Also supports OpenAI and Ollama.
:::
---
## Use the Client
<Tabs>
<TabItem value="python" label="Python">
```bash
pip install hindsight-client
```
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
# Retain: Store information
client.retain(bank_id="my-bank", content="Alice works at Google as a software engineer")
# Recall: Search memories
client.recall(bank_id="my-bank", query="What does Alice do?")
# Reflect: Generate personality-aware response
client.reflect(bank_id="my-bank", query="Tell me about Alice")
```
</TabItem>
<TabItem value="node" label="Node.js">
```bash
npm install @vectorize-io/hindsight-client
```
```javascript
const { HindsightClient } = require('@vectorize-io/hindsight-client');
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
// Retain: Store information
await client.retain('my-bank', 'Alice works at Google as a software engineer');
// Recall: Search memories
await client.recall('my-bank', 'What does Alice do?');
// Reflect: Generate response
await client.reflect('my-bank', 'Tell me about Alice');
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
curl -fsSL https://raw.githubusercontent.com/vectorize-io/hindsight/refs/heads/main/hindsight-cli/install.sh | bash
```
```bash
# Retain: Store information
hindsight memory retain my-bank "Alice works at Google as a software engineer"
# Recall: Search memories
hindsight memory recall my-bank "What does Alice do?"
# Reflect: Generate response
hindsight memory reflect my-bank "Tell me about Alice"
```
</TabItem>
</Tabs>
---
## What's Happening
| Operation | What it does |
|-----------|--------------|
| **Retain** | Content is processed, facts are extracted, entities are identified and linked in a knowledge graph |
| **Recall** | Four search strategies (semantic, keyword, graph, temporal) run in parallel to find relevant memories |
| **Reflect** | Retrieved memories are used to generate a personality-aware response |
---
## Next Steps
- [**Retain**](./retain) — Advanced options for storing memories
- [**Recall**](./recall) — Search and retrieval strategies
- [**Reflect**](./reflect) — Personality-aware reasoning
- [**Memory Banks**](./memory-banks) — Configure personality and background
- [**Server Deployment**](/developer/installation) — Docker Compose, Helm, and production setup
---
## File: developer/api/main-methods.md
# Main Methods
Hindsight provides three core operations: **retain**, **recall**, and **reflect**.
:::tip Prerequisites
Make sure you've [installed Hindsight](../installation) and completed the [Quick Start](./quickstart).
:::
## Retain: Store Information
Store conversations, documents, and facts into a memory bank.
<Tabs>
<TabItem value="python" label="Python">
```python
# Store a single fact
client.retain(
bank_id="my-bank",
content="Alice joined Google in March 2024 as a Senior ML Engineer"
)
# Store a conversation
conversation = """
User: What did you work on today?
Assistant: I reviewed the new ML pipeline architecture.
User: How did it look?
Assistant: Promising, but needs better error handling.
"""
client.retain(
bank_id="my-bank",
content=conversation,
context="Daily standup conversation"
)
# Batch retain multiple items
client.retain_batch(
bank_id="my-bank",
contents=[
{"content": "Bob prefers Python for data science"},
{"content": "Alice recommends using pytest for testing"},
{"content": "The team uses GitHub for code reviews"}
]
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```javascript
// Store a single fact
await client.retain({
bankId: 'my-bank',
content: 'Alice joined Google in March 2024 as a Senior ML Engineer'
});
// Store a conversation
await client.retain({
bankId: 'my-bank',
content: `
User: What did you work on today?
Assistant: I reviewed the new ML pipeline architecture.
User: How did it look?
Assistant: Promising, but needs better error handling.
`,
context: 'Daily standup conversation'
});
// Batch retain
await client.retainBatch({
bankId: 'my-bank',
contents: [
{ content: 'Bob prefers Python for data science' },
{ content: 'Alice recommends using pytest for testing' },
{ content: 'The team uses GitHub for code reviews' }
]
});
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Store a single fact
hindsight retain my-bank "Alice joined Google in March 2024 as a Senior ML Engineer"
# Store from a file
hindsight retain my-bank --file conversation.txt --context "Daily standup"
# Store multiple files
hindsight retain my-bank --files docs/*.md
```
</TabItem>
</Tabs>
**What happens:** Content is processed by an LLM to extract rich facts, identify entities, and build connections in a knowledge graph.
**See:** [Retain Details](./retain) for advanced options and parameters.
---
## Recall: Search Memories
Search for relevant memories using multi-strategy retrieval.
<Tabs>
<TabItem value="python" label="Python">
```python
# Basic search
results = client.recall(
bank_id="my-bank",
query="What does Alice do at Google?"
)
for result in results:
print(f"[{result['weight']:.2f}] {result['text']}")
# Search with options
results = client.recall(
bank_id="my-bank",
query="What happened last spring?",
budget="high", # More thorough graph traversal
max_tokens=8192, # Return more context
fact_type="world" # Only world facts
)
# Include entity information
results = client.recall(
bank_id="my-bank",
query="Tell me about Alice",
include_entities=True,
max_entity_tokens=500
)
# Check entity details
for entity in results["entities"]:
print(f"Entity: {entity['name']}")
print(f"Observations: {entity['observations']}")
```
</TabItem>
<TabItem value="node" label="Node.js">
```javascript
// Basic search
const results = await client.recall({
bankId: 'my-bank',
query: 'What does Alice do at Google?'
});
results.forEach(r => {
console.log(`[${r.weight.toFixed(2)}] ${r.text}`);
});
// Search with options
const detailedResults = await client.recall({
bankId: 'my-bank',
query: 'What happened last spring?',
budget: 'high',
maxTokens: 8192,
factType: 'world'
});
// Include entity information
const withEntities = await client.recall({
bankId: 'my-bank',
query: 'Tell me about Alice',
includeEntities: true,
maxEntityTokens: 500
});
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Basic search
hindsight recall my-bank "What does Alice do at Google?"
# Search with options
hindsight recall my-bank "What happened last spring?" \
--budget high \
--max-tokens 8192 \
--fact-type world
# Verbose output (shows weights and sources)
hindsight recall my-bank "Tell me about Alice" -v
```
</TabItem>
</Tabs>
**What happens:** Four search strategies (semantic, keyword, graph, temporal) run in parallel, results are fused and reranked.
**See:** [Recall Details](./recall) for tuning quality vs latency.
---
## Reflect: Reason with Personality
Generate personality-aware responses that form opinions based on evidence.
<Tabs>
<TabItem value="python" label="Python">
```python
# Basic reflect
response = client.reflect(
bank_id="my-bank",
query="Should we adopt TypeScript for our backend?"
)
print(response["text"])
print("\nBased on:", len(response["based_on"]["world"]), "facts")
print("New opinions:", len(response["new_opinions"]))
# Reflect with options
response = client.reflect(
bank_id="my-bank",
query="What are Alice's strengths for the team lead role?",
budget="high", # More thorough reasoning
include_entities=True
)
# Access formed opinions
for opinion in response["new_opinions"]:
print(f"Opinion: {opinion['text']}")
print(f"Confidence: {opinion['confidence']}")
# See which facts influenced the response
for fact in response["based_on"]["world"]:
print(f"[{fact['weight']:.2f}] {fact['text']}")
```
</TabItem>
<TabItem value="node" label="Node.js">
```javascript
// Basic reflect
const response = await client.reflect({
bankId: 'my-bank',
query: 'Should we adopt TypeScript for our backend?'
});
console.log(response.text);
console.log(`\nBased on: ${response.basedOn.world.length} facts`);
console.log(`New opinions: ${response.newOpinions.length}`);
// Reflect with options
const detailed = await client.reflect({
bankId: 'my-bank',
query: "What are Alice's strengths for the team lead role?",
budget: 'high',
includeEntities: true
});
// Access formed opinions
detailed.newOpinions.forEach(op => {
console.log(`Opinion: ${op.text}`);
console.log(`Confidence: ${op.confidence}`);
});
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Basic reflect
hindsight reflect my-bank "Should we adopt TypeScript for our backend?"
# Verbose output (shows sources and opinions)
hindsight reflect my-bank "What are Alice's strengths for the team lead role?" -v
# With higher reasoning budget
hindsight reflect my-bank "Analyze our tech stack" --budget high
```
</TabItem>
</Tabs>
**What happens:** Memories are recalled, bank personality is loaded, LLM reasons through evidence, new opinions are formed and stored.
**See:** [Reflect Details](./reflect) for personality configuration.
---
## Comparison
| Feature | Retain | Recall | Reflect |
|---------|--------|--------|---------|
| **Purpose** | Store information | Find information | Reason about information |
| **Input** | Raw text/documents | Search query | Question/prompt |
| **Output** | Memory IDs | Ranked facts | Reasoned response + opinions |
| **Uses LLM** | Yes (extraction) | No | Yes (generation) |
| **Forms opinions** | No | No | Yes |
| **Personality** | No | No | Yes |
---
## Next Steps
- [**Retain**](./retain) — Advanced options for storing memories
- [**Recall**](./recall) — Tuning search quality and performance
- [**Reflect**](./reflect) — Configuring personality and opinions
- [**Memory Banks**](./memory-banks) — Managing memory bank personality
---
## File: developer/retain.md
# Retain: How Hindsight Stores Memories
When you call `retain()`, Hindsight transforms conversations and documents into structured, searchable memories that preserve meaning and context.
## What Retain Does
```
Your Content
Extract Rich Facts
Identify Entities
Build Connections
Searchable Memory Bank
```
---
## Rich Fact Extraction
Hindsight doesn't just store what was said — it captures **why**, **how**, and **what it means**.
### What Gets Captured
When you retain "Alice joined Google last spring and was thrilled about the research opportunities", Hindsight extracts:
**The core facts:**
- Alice joined Google
- This happened last spring
**The emotions and meaning:**
- She was thrilled
- It represented an important opportunity
**The reasoning:**
- She chose it for the research opportunities
This rich extraction means you can later ask "Why did Alice join Google?" and get a meaningful answer, not just "she joined Google."
### Preserving Context
Traditional systems fragment information:
- "Bob suggested Summer Vibes"
- "Alice wanted something unique"
- "They chose Beach Beats"
Hindsight preserves the full narrative:
- "Alice and Bob discussed naming their summer party playlist. Bob suggested 'Summer Vibes' because it's catchy, but Alice wanted something unique. They ultimately decided on 'Beach Beats' for its playful tone."
This means search results include the full context, not disconnected fragments.
---
## Two Types of Facts
Hindsight distinguishes between **world** facts (about others) and **experience** (conversations and events):
| Type | Description | Example |
|-----------------|-----------------------------------|---------|
| **world** | Facts about people, places, things | "Alice works at Google" |
| **experience** | Conversations and events | "I recommended Python to Alice" |
This separation is important for `reflect()` — the bank can reason about what it knows versus what happened in conversations.
**Note:** Opinions aren't created during `retain()` — only during `reflect()` when the bank forms beliefs.
---
## Entity Recognition
Hindsight automatically identifies and tracks **entities** — the people, organizations, and concepts that matter.
### What Gets Recognized
- **People:** "Alice", "Dr. Smith", "Bob Chen"
- **Organizations:** "Google", "MIT", "OpenAI"
- **Places:** "Paris", "Central Park", "California"
- **Products & Concepts:** "Python", "TensorFlow", "machine learning"
### Entity Resolution
The same entity mentioned different ways gets unified:
- "Alice" + "Alice Chen" + "Alice C." → one person
- "Bob" + "Robert Chen" → one person (nickname resolution)
**Why it matters:** You can ask "What do I know about Alice?" and get everything, even if she was mentioned as "Alice Chen" in some conversations.
### Context-Aware Disambiguation
If "Alice" appears with "Google" and "Stanford" multiple times, a new "Alice" mentioning those is likely the same person. Hindsight uses co-occurrence patterns to disambiguate common names.
---
## Building Connections
Memories aren't isolated — Hindsight creates a **knowledge graph** with four types of connections:
### Entity Connections
All facts mentioning the same entity are linked together.
**Enables:** "Tell me everything about Alice" → retrieves all Alice-related facts
### Time-Based Connections
Facts close in time are connected, with stronger links for closer dates.
**Enables:** "What else happened around then?" → finds contextually related events
### Meaning-Based Connections
Semantically similar facts are linked, even if they use different words.
**Enables:** "Tell me about similar topics" → finds thematically related information
### Causal Connections
Cause-effect relationships are explicitly tracked.
**Enables:** "Why did this happen?" → trace reasoning chains
**Example:** "Alice felt burned out" ← caused by ← "She worked 80-hour weeks"
---
## Understanding Time
Hindsight tracks **two temporal dimensions**:
### When It Happened
For events (meetings, trips, milestones), Hindsight records when they occurred.
- "Alice got married in June 2024" → occurred in June 2024
For general facts (preferences, characteristics), there's no specific occurrence time.
- "Alice prefers Python" → ongoing preference
### When You Learned It
Hindsight also tracks when you told it each fact.
**Why both?**
Imagine in January 2025, someone tells you "Alice got married in June 2024":
- **Historical queries** work: "What did Alice do in 2024?" → finds the marriage
- **Recency ranking** works: Recent mentions get priority in search
- **Temporal reasoning** works: "What happened before her marriage?" → finds earlier events
Without this distinction, old information would either be unsearchable by date or treated as irrelevant.
---
## Entity Observations
As facts accumulate about an entity, Hindsight synthesizes **observations** — high-level summaries that capture what's known:
**From multiple facts:**
- "Alice works at Google"
- "Alice is a software engineer"
- "Alice specializes in ML"
**Hindsight creates:**
- "Alice is a software engineer at Google specializing in ML"
**Why it helps:** You can quickly understand an entity without reading through dozens of individual facts.
---
## What You Get
After `retain()` completes:
- **Structured facts** that preserve meaning, emotions, and reasoning
- **Unified entities** that resolve different name variations
- **Knowledge graph** with entity, temporal, semantic, and causal links
- **Temporal grounding** for both historical and recency-based queries
- **Background processing** that generates entity summaries
All stored in your isolated **memory bank**, ready for `recall()` and `reflect()`.
---
## Next Steps
- [**Recall**](./retrieval) — How multi-strategy search retrieves relevant memories
- [**Reflect**](./reflect) — How personality influences reasoning and opinion formation
- [API Reference](./api/retain) — Code examples for retaining memories
---
## File: developer/retrieval.md
# Recall: How Hindsight Retrieves Memories
When you call `recall()`, Hindsight uses multiple search strategies in parallel to find the most relevant memories, regardless of how you phrase your query.
## The Challenge of Memory Recall
Different queries need different search approaches:
- **"Alice works at Google"** → needs exact name matching
- **"Where does Alice work?"** → needs semantic understanding
- **"What did Alice do last spring?"** → needs temporal reasoning
- **"Why did Alice leave?"** → needs causal relationship tracing
No single search method handles all these well. Hindsight solves this with **TEMPR** — four complementary strategies that run in parallel.
---
## Four Search Strategies
### Semantic Search
**What it does:** Understands the *meaning* behind words, not just the words themselves.
**Best for:**
- Conceptual matches: "Alice's job" → "Alice works as a software engineer"
- Paraphrasing: "Bob's expertise" → "Bob specializes in machine learning"
- Synonyms: "meeting" matches "conference", "discussion", "gathering"
**Why it matters:** You can ask questions naturally without matching exact keywords.
---
### Keyword Search
**What it does:** Finds exact terms and names, even when they're spelled uniquely.
**Best for:**
- Proper nouns: "Google", "Alice Chen", "MIT"
- Technical terms: "PostgreSQL", "HNSW", "TensorFlow"
- Unique identifiers: URLs, product names, specific phrases
**Why it matters:** Ensures you never miss results that mention specific names or terms, even if they're semantically distant from your query.
---
### Graph Traversal
**What it does:** Follows connections between entities to find indirectly related information.
**Best for:**
- Indirect relationships: "What does Alice do?" → Alice → Google → Google's products
- Entity exploration: "Bob's colleagues" → Bob → co-workers → shared projects
- Multi-hop reasoning: "Alice's team's achievements"
**Why it matters:** Retrieves facts that aren't semantically or lexically similar but are **structurally connected** through the knowledge graph.
**Example:** Even if Alice and her manager are never mentioned together, graph traversal can find the manager through shared projects or team relationships.
---
### Temporal Search
**What it does:** Understands time expressions and filters by when events occurred.
**Best for:**
- Historical queries: "What did Alice do in 2023?"
- Time ranges: "What happened last spring?"
- Relative time: "What did Bob work on last year?"
- Before/after: "What happened before Alice joined Google?"
**How it works:** Combines semantic understanding with time filtering to find events within specific periods.
**Why it matters:** Enables precise historical queries without losing old information.
---
## Result Fusion
After the four strategies run, results are **fused together**:
- Memories appearing in **multiple strategies** rank higher (consensus)
- **Rank matters more than score** (robust across different scoring systems)
- Final results are **re-ranked** using a neural model that considers query-memory interaction
**Why fusion matters:** A fact that's both semantically similar AND mentions the right entity will rank higher than one that's only semantically similar.
---
## Token Budget Management
Hindsight is built for AI agents, not humans. Traditional search systems return "top-k" results, but agents don't think in terms of result counts—they think in tokens. An agent's context window is measured in tokens, and that's exactly how Hindsight measures results.
**How it works:**
- Top-ranked memories selected first
- Stops when token budget is exhausted
- You specify context budget, Hindsight fills it with the most relevant memories
**Parameters you control:**
- `max_tokens`: How much memory content to return (default: 4096 tokens)
- `budget`: Budget level for graph traversal (low, mid, high)
- `fact_type`: Filter by world, experience, opinion, or all
### Additional Context: Chunks and Entity Observations
For the most relevant memories, you can optionally retrieve additional context—each with its own token budget:
| Option | Parameters | Description |
|--------|------------|-------------|
| **Chunks** | `include_chunks`, `max_chunk_tokens` | Raw text chunks that generated the memories |
| **Entity Observations** | `include_entities`, `max_entity_tokens` | Related observations about entities mentioned in results |
This gives your agent richer context while maintaining precise control over total token consumption.
---
## How Recall Works
When you call `recall(query, bank_id)`:
1. **Parse** → Detect temporal expressions, understand intent
2. **Search** → Run 4 strategies in parallel
3. **Fuse** → Combine results, prioritizing consensus
4. **Rerank** → Neural reranking for final relevance
5. **Filter** → Select top memories within token budget
6. **Return** → Ranked, relevant memories
---
## Tuning Recall: Quality vs Latency
Different use cases require different trade-offs between **recall quality** and **response speed**. Two parameters control this:
### Budget: Graph Exploration Depth
Controls how many nodes to explore when traversing the knowledge graph:
| Budget | Nodes Explored | Best For | Trade-off |
|--------|----------------|----------|-----------|
| **low** | 100 nodes | Quick lookups, simple queries | Fast, may miss distant connections |
| **mid** | 300 nodes | Most queries, balanced | Good coverage, reasonable speed |
| **high** | 600 nodes | Complex multi-hop queries | Thorough, slower |
**Example:** "What did Alice's manager's team work on?" benefits from high budget to traverse Alice → manager → team → projects.
### Max Tokens: Context Window Size
Controls how much memory content to return:
| Max Tokens | ~Pages of Text | Best For | Trade-off |
|------------|----------------|----------|-----------|
| **2048** | ~2 pages | Focused answers, fast LLM | Fewer memories, faster |
| **4096** (default) | ~4 pages | Balanced context | Good coverage, standard |
| **8192** | ~8 pages | Comprehensive context | More memories, slower LLM |
**Example:** "Summarize everything about Alice" benefits from higher max_tokens to include more facts.
### Two Independent Dimensions
Budget and max_tokens control different aspects of recall:
| Parameter | What it controls | Latency impact | Example |
|-----------|------------------|----------------|---------|
| **Budget** | How deep to explore the graph | Search time | High budget finds Alice → manager → team → projects |
| **Max Tokens** | How much context to return | LLM processing time | High tokens returns more memories to the agent |
**They're independent.** Common combinations:
| Budget | Max Tokens | Use Case |
|--------|------------|----------|
| high | low | Deep search, return only the best results |
| low | high | Quick search, return everything found |
| high | high | Comprehensive research queries |
| low | low | Fast chatbot responses |
### Recommended Configurations
| Use Case | Budget | Max Tokens | Why |
|----------|--------|------------|-----|
| **Chatbot replies** | low | 2048 | Fast responses, focused context |
| **Document Q&A** | mid | 4096 | Balanced coverage and speed |
| **Research queries** | high | 8192 | Comprehensive, multi-hop reasoning |
| **Real-time search** | low | 2048 | Minimize latency |
---
## Why Multiple Strategies?
Consider the query: **"What did Alice think about Python last spring?"**
- **Semantic** finds facts about Alice's opinions on programming
- **Keyword** ensures "Python" is actually mentioned
- **Graph** connects Alice → opinions → programming languages
- **Temporal** filters to "last spring" timeframe
The **fusion** of all four gives you exactly what you're looking for, even though no single strategy would suffice.
---
## Next Steps
- [**Retain**](./retain) — How memories are stored with rich context
- [**Reflect**](./reflect) — How personality influences reasoning
---
## File: developer/reflect.md
# Reflect: How Hindsight Reasons with Disposition
When you call `reflect()`, Hindsight doesn't just retrieve facts — it **reasons** about them through the lens of the bank's unique disposition, forming new opinions and generating contextual responses.
## Why Reflect?
Most AI systems can retrieve facts, but they can't **reason** about them in a consistent way. Every response is generated fresh without a stable perspective or evolving beliefs.
### The Problem
Without reflect:
- **No consistent character**: "Should we adopt remote work?" gets a different answer each time based on the LLM's randomness
- **No opinion formation**: The system never develops beliefs based on accumulated evidence
- **No reasoning context**: Responses don't reflect what the bank has learned or its perspective
- **Generic responses**: Every AI sounds the same — no disposition, no point of view
### The Value
With reflect:
- **Consistent character**: A bank configured as "detail-oriented, cautious" will consistently emphasize risks and thorough planning
- **Evolving opinions**: As the bank learns more about a topic, its opinions strengthen, weaken, or change — just like a real expert
- **Contextual reasoning**: Responses reflect the bank's accumulated knowledge and perspective: "Based on what I know about your team's remote work success..."
- **Differentiated behavior**: Customer support bots sound diplomatic, code reviewers sound direct, creative assistants sound open-minded
### When to Use Reflect
| Use `recall()` when... | Use `reflect()` when... |
|------------------------|-------------------------|
| You need raw facts | You need reasoned interpretation |
| You're building your own reasoning | You want disposition-consistent responses |
| You need maximum control | You want the bank to "think" for itself |
| Simple fact lookup | Forming recommendations or opinions |
**Example:**
- `recall("Alice")` → Returns all Alice facts
- `reflect("Should we hire Alice?")` → Reasons about Alice's fit based on accumulated knowledge, weighs evidence, forms opinion
---
## The Reflect Process
1. **Recall** relevant memories based on the query
2. **Load** the bank's disposition traits and background
3. **Reason** about the memories through the disposition lens
4. **Form** new opinions with confidence scores
5. **Return** response, sources, and any new beliefs
---
## Disposition Framework (CARA)
When you create a memory bank, you can configure its disposition using **Big Five traits**. These traits influence how the bank interprets information and forms opinions:
You can also provide a natural language **background** that describes the bank's identity and perspective, which shapes how these traits are applied.
| Trait | Low | High |
|-------|-----|------|
| **Openness** | Prefers proven methods | Embraces new ideas |
| **Conscientiousness** | Flexible, spontaneous | Systematic, organized |
| **Extraversion** | Independent | Collaborative |
| **Agreeableness** | Direct, analytical | Diplomatic, harmonious |
| **Neuroticism** | Calm, optimistic | Risk-aware, cautious |
### Background: Natural Language Identity
Beyond numeric traits, you can provide a natural language **background** that describes the bank's identity:
```python
client.create_bank(
bank_id="my-bank",
background="I am a senior software architect with 15 years of distributed "
"systems experience. I prefer simplicity over cutting-edge technology.",
disposition={
"openness": 0.3, # Prefers proven methods
"conscientiousness": 0.9, # Highly organized
# ... other traits
}
)
```
The background provides context that shapes how disposition traits are applied:
- "I prefer simplicity" + low openness → consistently favors established solutions
- "15 years experience" → responses reference this expertise
- First-person perspective → creates consistent voice
### Bias Strength
The `bias_strength` parameter (0-1) controls how much disposition influences reasoning:
- **0.0**: Purely evidence-based
- **0.5**: Balanced disposition and evidence
- **1.0**: Strongly disposition-driven
---
## Opinion Formation
When `reflect()` encounters a question that warrants forming an opinion, disposition shapes the response.
### Same Facts, Different Opinions
Two banks with different dispositions, given identical facts about remote work:
**Bank A** (high openness, low conscientiousness):
> "Remote work unlocks creative flexibility and spontaneous innovation. The freedom to work from anywhere enables breakthrough thinking."
**Bank B** (low openness, high conscientiousness):
> "Remote work lacks the structure and accountability needed for consistent performance. In-person collaboration is more reliable."
**Same facts → Different conclusions** because disposition shapes interpretation.
---
## Opinion Evolution
Opinions aren't static — they evolve as new evidence arrives. Here's a real-world example with a database library:
| Event | What the bank learns | Opinion formed |
|-------|---------------------|----------------|
| **Day 1** | "Redis is open source under BSD license" | "Redis is excellent for caching — fast, reliable, and OSS-friendly" (confidence: 0.85) |
| **Day 2** | "Redis has great community support and documentation" | Opinion reinforced (confidence: 0.90) |
| **Day 30** | "Redis changed license to SSPL, restricting cloud usage" | "Redis is still technically strong, but license concerns for cloud deployments" (confidence: 0.65) |
| **Day 45** | "Valkey forked Redis under BSD license with Linux Foundation backing" | "Consider Valkey for new projects requiring true OSS; Redis for existing deployments" (confidence: 0.80) |
**Before the license change:**
> "Should we use Redis for our caching layer?"
> → "Yes, Redis is the industry standard — fast, battle-tested, and fully open source."
**After the license change:**
> "Should we use Redis for our caching layer?"
> → "It depends. For cloud deployments, consider Valkey (the BSD-licensed fork). For on-premise, Redis remains excellent technically."
This **continuous learning** ensures recommendations stay current with real-world changes.
---
## Disposition Presets by Use Case
Different use cases benefit from different disposition configurations:
| Use Case | Recommended Traits | Why |
|----------|-------------------|-----|
| **Customer Support** | High agreeableness<br/>Low neuroticism | Diplomatic, calm under pressure |
| **Code Review** | High conscientiousness<br/>Low agreeableness | Detail-oriented, direct feedback |
| **Creative Writing** | High openness<br/>High extraversion | Embraces novelty, expressive |
| **Risk Analysis** | High neuroticism<br/>High conscientiousness | Risk-aware, methodical |
| **Research Assistant** | High openness<br/>High conscientiousness | Curious, thorough |
---
## What You Get from Reflect
When you call `reflect()`:
**Returns:**
- **Response text** — Disposition-influenced answer
- **Based on** — Which memories were used (with relevance scores)
**Example:**
```json
{
"text": "Based on Alice's ML expertise and her work at Google, she'd be an excellent fit for the research team lead position...",
"based_on": {
"world": [
{"text": "Alice works at Google...", "weight": 0.95},
{"text": "Alice specializes in ML...", "weight": 0.88}
]
}
}
```
**Note:** New opinions are formed asynchronously in the background. They'll influence future `reflect()` calls but aren't returned directly.
---
## Why Disposition Matters
Without disposition, all AI assistants sound the same. With disposition:
- **Customer support bots** can be diplomatic and empathetic
- **Code review assistants** can be direct and thorough
- **Creative assistants** can be open to unconventional ideas
- **Risk analysts** can be appropriately cautious
Disposition creates **consistent character** across conversations while allowing opinions to **evolve with evidence**.
---
## Next Steps
- [**Retain**](./retain) — How rich facts are stored
- [**Recall**](./retrieval) — How multi-strategy search works
- [API Reference: Reflect](./api/reflect) — Code examples and usage
---
## File: developer/api/retain.md
# Ingest Data
Store memories, conversations, and documents into Hindsight.
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
:::
## Store a Single Memory
<Tabs>
<TabItem value="python" label="Python">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
client.retain(
bank_id="my-bank",
content="Alice works at Google as a software engineer"
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
await client.retain('my-bank', 'Alice works at Google as a software engineer');
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight memory put my-bank "Alice works at Google as a software engineer"
```
</TabItem>
</Tabs>
## Store with Context and Date
Add context and event dates for better retrieval:
<Tabs>
<TabItem value="python" label="Python">
```python
client.retain(
bank_id="my-bank",
content="Alice got promoted to senior engineer",
context="career update",
timestamp="2024-03-15T10:00:00Z"
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
await client.retain('my-bank', 'Alice got promoted to senior engineer', {
context: 'career update',
timestamp: '2024-03-15T10:00:00Z'
});
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight memory put my-bank "Alice got promoted" \
--context "career update" \
--event-date "2024-03-15"
```
</TabItem>
</Tabs>
The `timestamp` enables temporal queries like "What happened last spring?"
## Batch Ingestion
Store multiple memories in a single request:
<Tabs>
<TabItem value="python" label="Python">
```python
client.retain_batch(
bank_id="my-bank",
items=[
{"content": "Alice works at Google", "context": "career"},
{"content": "Bob is a data scientist at Meta", "context": "career"},
{"content": "Alice and Bob are friends", "context": "relationship"}
],
document_id="conversation_001"
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
await client.retainBatch('my-bank', [
{ content: 'Alice works at Google', context: 'career' },
{ content: 'Bob is a data scientist at Meta', context: 'career' },
{ content: 'Alice and Bob are friends', context: 'relationship' }
], { documentId: 'conversation_001' });
```
</TabItem>
</Tabs>
The `document_id` groups related memories for later management.
## Store from Files
<Tabs>
<TabItem value="cli" label="CLI">
```bash
# Single file
hindsight memory put-files my-bank document.txt
# Multiple files
hindsight memory put-files my-bank doc1.txt doc2.md notes.txt
# With document ID
hindsight memory put-files my-bank report.pdf --document-id "q4-report"
```
</TabItem>
</Tabs>
:::info How Retain Works
Learn about fact extraction, entity resolution, and graph construction in the [Retain Architecture](/developer/retain) guide.
:::
## Async Ingestion
For large batches, use async ingestion:
<Tabs>
<TabItem value="python" label="Python">
```python
# Start async ingestion
result = client.retain_batch(
bank_id="my-bank",
items=[...large batch...],
document_id="large-doc",
async_=True
)
# Result contains operation_id for tracking
print(result["operation_id"])
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Start async ingestion
const result = await client.retainBatch('my-bank', largeItems, {
documentId: 'large-doc',
async: true
});
console.log(result.operation_id);
```
</TabItem>
</Tabs>
## Best Practices
| Do | Don't |
|----|-------|
| Include context for better retrieval | Store raw unstructured dumps |
| Use document_id to group related content | Mix unrelated content in one batch |
| Add timestamp for temporal queries | Omit dates if time matters |
| Store conversations as they happen | Wait to batch everything |
---
## File: developer/api/recall.md
# Search Facts
Retrieve memories using multi-strategy search.
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
:::
## Basic Search
<Tabs>
<TabItem value="python" label="Python">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
client.recall(bank_id="my-bank", query="What does Alice do?")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
await client.recall('my-bank', 'What does Alice do?');
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight memory search my-bank "What does Alice do?"
```
</TabItem>
</Tabs>
## Search Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `query` | string | required | Natural language query |
| `types` | list | all | Filter: `world`, `experience`, `opinion` |
| `budget` | string | "mid" | Budget level: "low", "mid", "high" |
| `max_tokens` | int | 4096 | Token budget for results |
<Tabs>
<TabItem value="python" label="Python">
```python
results = client.recall(
bank_id="my-bank",
query="What does Alice do?",
types=["world", "experience"],
budget="high",
max_tokens=8000
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const results = await client.recall('my-bank', 'What does Alice do?', {
budget: 'high',
maxTokens: 8000
});
```
</TabItem>
</Tabs>
## Full-Featured Search
For more control, use the full-featured recall method:
<Tabs>
<TabItem value="python" label="Python">
```python
# Full response with trace info
response = client.recall_memories(
bank_id="my-bank",
query="What does Alice do?",
types=["world", "experience"],
budget="high",
max_tokens=8000,
trace=True,
include_entities=True,
max_entity_tokens=500
)
# Access results
for r in response["results"]:
print(f"{r['text']} (score: {r['weight']:.2f})")
# Access entity observations (if include_entities=True)
if "entities" in response:
for entity in response["entities"]:
print(f"Entity: {entity['name']}")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Full response with trace info
const response = await client.recallMemories('my-bank', {
query: 'What does Alice do?',
types: ['world', 'experience'],
budget: 'high',
maxTokens: 8000,
trace: true
});
// Access results
for (const r of response.results) {
console.log(`${r.text} (score: ${r.weight})`);
}
```
</TabItem>
</Tabs>
## Temporal Queries
Hindsight automatically detects time expressions and activates temporal search:
<Tabs>
<TabItem value="python" label="Python">
```python
# These queries activate temporal-graph retrieval
results = client.recall(bank_id="my-bank", query="What did Alice do last spring?")
results = client.recall(bank_id="my-bank", query="What happened in June?")
results = client.recall(bank_id="my-bank", query="Events from last year")
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight memory search my-bank "What did Alice do last spring?"
hindsight memory search my-bank "What happened between March and May?"
```
</TabItem>
</Tabs>
Supported temporal expressions:
| Expression | Parsed As |
|------------|-----------|
| "last spring" | March 1 - May 31 (previous year) |
| "in June" | June 1-30 (current/nearest year) |
| "last year" | Jan 1 - Dec 31 (previous year) |
| "last week" | 7 days ago - today |
| "between March and May" | March 1 - May 31 |
## Filter by Fact Type
Search specific memory networks:
<Tabs>
<TabItem value="python" label="Python">
```python
# Only world facts (objective information)
world_facts = client.recall(
bank_id="my-bank",
query="Where does Alice work?",
types=["world"]
)
# Only experience (conversations and events)
experience = client.recall(
bank_id="my-bank",
query="What have I recommended?",
types=["experience"]
)
# Only opinions (formed beliefs)
opinions = client.recall(
bank_id="my-bank",
query="What do I think about Python?",
types=["opinion"]
)
# World facts and experience (exclude opinions)
facts = client.recall(
bank_id="my-bank",
query="What happened?",
types=["world", "experience"]
)
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight memory search my-bank "Python" --fact-type opinion
hindsight memory search my-bank "Alice" --fact-type world,experience
```
</TabItem>
</Tabs>
:::info How Recall Works
Learn about the four search strategies (semantic, keyword, graph, temporal) and RRF fusion in the [Recall Architecture](/developer/retrieval) guide.
:::
## Token Budget Management
Hindsight is built for AI agents, not humans. Traditional search systems return "top-k" results, but agents don't think in terms of result counts—they think in tokens. An agent's context window is measured in tokens, and that's exactly how Hindsight measures results.
The `max_tokens` parameter lets you control how much of your agent's context budget to spend on memories:
```python
# Fill up to 4K tokens of context with relevant memories
results = client.recall(bank_id="my-bank", query="What do I know about Alice?", max_tokens=4096)
# Smaller budget for quick lookups
results = client.recall(bank_id="my-bank", query="Alice's email", max_tokens=500)
```
This design means you never have to guess whether 10 results or 50 results will fit your context. Just specify the token budget and Hindsight returns as many relevant memories as will fit.
### Additional Context: Chunks and Entity Observations
For the most relevant memories, you can optionally retrieve additional context—each with its own token budget:
| Option | Parameter | Description |
|--------|-----------|-------------|
| **Chunks** | `include_chunks`, `max_chunk_tokens` | Raw text chunks that generated the memories |
| **Entity Observations** | `include_entities`, `max_entity_tokens` | Related observations about entities mentioned in results |
```python
response = client.recall_memories(
bank_id="my-bank",
query="What does Alice do?",
max_tokens=4096, # Budget for memories
include_chunks=True,
max_chunk_tokens=2000, # Budget for raw chunks
include_entities=True,
max_entity_tokens=1000 # Budget for entity observations
)
# Access the additional context
chunks = response.get("chunks", {})
entities = response.get("entities", [])
```
This gives your agent richer context while maintaining precise control over total token consumption.
## Budget Levels
The `budget` parameter controls graph traversal depth:
- **"low"**: Fast, shallow search — good for simple lookups
- **"mid"**: Balanced — default for most queries
- **"high"**: Deep exploration — finds indirect connections
<Tabs>
<TabItem value="python" label="Python">
```python
# Quick lookup
results = client.recall(bank_id="my-bank", query="Alice's email", budget="low")
# Deep exploration
results = client.recall(bank_id="my-bank", query="How are Alice and Bob connected?", budget="high")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Quick lookup
const results = await client.recall('my-bank', "Alice's email", { budget: 'low' });
// Deep exploration
const deep = await client.recall('my-bank', 'How are Alice and Bob connected?', { budget: 'high' });
```
</TabItem>
</Tabs>
---
## File: developer/api/reflect.md
# Reflect
Generate personality-aware responses using retrieved memories.
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
:::
## Basic Usage
<Tabs>
<TabItem value="python" label="Python">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
client.reflect(bank_id="my-bank", query="What should I know about Alice?")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
await client.reflect('my-bank', 'What should I know about Alice?');
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight memory think my-bank "What should I know about Alice?"
```
</TabItem>
</Tabs>
## Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `query` | string | required | Question or prompt |
| `budget` | string | "low" | Budget level: "low", "mid", "high" |
| `context` | string | None | Additional context for the query |
<Tabs>
<TabItem value="python" label="Python">
```python
response = client.reflect(
bank_id="my-bank",
query="What do you think about remote work?",
budget="mid",
context="We're considering a hybrid work policy"
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const response = await client.reflect('my-bank', 'What do you think about remote work?', {
budget: 'mid',
context: "We're considering a hybrid work policy"
});
```
</TabItem>
</Tabs>
:::info How Reflect Works
Learn about personality-driven reasoning and opinion formation in the [Reflect Architecture](/developer/reflect) guide.
:::
## Opinion Formation
Reflect can form new opinions based on evidence:
<Tabs>
<TabItem value="python" label="Python">
```python
response = client.reflect(
bank_id="my-bank",
query="What do you think about Python vs JavaScript for data science?"
)
# Response might include:
# answer: "Based on what I know about data science workflows..."
# new_opinions: [
# {"text": "Python is better for data science", "id": "..."}
# ]
```
</TabItem>
</Tabs>
New opinions are automatically stored and influence future responses.
## Personality Influence
The bank's personality affects reflect responses:
| Trait | Effect on Reflect |
|-------|-----------------|
| High **Openness** | More willing to consider new ideas |
| High **Conscientiousness** | More structured, methodical responses |
| High **Extraversion** | More collaborative suggestions |
| High **Agreeableness** | More diplomatic, harmony-seeking |
| High **Neuroticism** | More risk-aware, cautious |
<Tabs>
<TabItem value="python" label="Python">
```python
# Create a bank with specific personality
client.create_bank(
bank_id="cautious-advisor",
background="I am a risk-aware financial advisor",
personality={
"openness": 0.3,
"conscientiousness": 0.9,
"neuroticism": 0.8,
"bias_strength": 0.7
}
)
# Reflect responses will reflect this personality
response = client.reflect(
bank_id="cautious-advisor",
query="Should I invest in crypto?"
)
# Response will likely emphasize risks and caution
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Create a bank with specific personality
await client.createBank('cautious-advisor', {
background: 'I am a risk-aware financial advisor',
personality: {
openness: 0.3,
conscientiousness: 0.9,
neuroticism: 0.8,
bias_strength: 0.7
}
});
// Reflect responses will reflect this personality
const response = await client.reflect('cautious-advisor', 'Should I invest in crypto?');
```
</TabItem>
</Tabs>
## Using Sources
The `facts_used` field shows which memories informed the response:
<Tabs>
<TabItem value="python" label="Python">
```python
response = client.reflect(bank_id="my-bank", query="Tell me about Alice")
print("Response:", response["answer"])
print("\nBased on:")
for fact in response.get("facts_used", []):
print(f" - {fact['text']} (relevance: {fact['weight']:.2f})")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const response = await client.reflect('my-bank', 'Tell me about Alice');
console.log('Response:', response.answer);
console.log('\nBased on:');
for (const fact of response.facts_used || []) {
console.log(` - ${fact.text} (relevance: ${fact.weight.toFixed(2)})`);
}
```
</TabItem>
</Tabs>
This enables:
- **Transparency** — users see why the bank said something
- **Verification** — check if the response is grounded in facts
- **Debugging** — understand retrieval quality
---
## File: developer/api/memory-banks.md
# Memory Bank
Configure memory bank personality, background, and behavior.
Memory banks have charateristics:
- Banks are completely isolated from each other.
- You don't need to pre-create it, Hindsight will create it for you with default settings.
- Banks have a profile that influences how they form opinions from memories. (optional)
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
:::
## Creating a Memory Bank
<Tabs>
<TabItem value="python" label="Python">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
client.create_bank(
bank_id="my-bank",
name="Research Assistant",
background="I am a research assistant specializing in machine learning",
personality={
"openness": 0.8,
"conscientiousness": 0.7,
"extraversion": 0.5,
"agreeableness": 0.6,
"neuroticism": 0.3,
"bias_strength": 0.5
}
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
await client.createBank('my-bank', {
name: 'Research Assistant',
background: 'I am a research assistant specializing in machine learning',
personality: {
openness: 0.8,
conscientiousness: 0.7,
extraversion: 0.5,
agreeableness: 0.6,
neuroticism: 0.3,
bias_strength: 0.5
}
});
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Set background
hindsight agent background my-bank "I am a research assistant specializing in ML"
# Set personality
hindsight agent personality my-bank \
--openness 0.8 \
--conscientiousness 0.7 \
--extraversion 0.5 \
--agreeableness 0.6 \
--neuroticism 0.3 \
--bias-strength 0.5
```
</TabItem>
</Tabs>
## Personality Traits (Big Five)
Each trait is scored 0.0 to 1.0:
| Trait | Low (0.0) | High (1.0) |
|-------|-----------|------------|
| **Openness** | Conventional, prefers proven methods | Curious, embraces new ideas |
| **Conscientiousness** | Flexible, spontaneous | Organized, systematic |
| **Extraversion** | Reserved, independent | Outgoing, collaborative |
| **Agreeableness** | Direct, analytical | Cooperative, diplomatic |
| **Neuroticism** | Calm, optimistic | Risk-aware, cautious |
### How Traits Affect Behavior
**Openness** influences how the bank weighs new vs. established ideas:
```python
# High openness bank
"Let's try this new framework—it looks promising!"
# Low openness bank
"Let's stick with the proven solution we know works."
```
**Conscientiousness** affects structure and thoroughness:
```python
# High conscientiousness bank
"Here's a detailed, step-by-step analysis..."
# Low conscientiousness bank
"Quick take: this should work, let's try it."
```
**Extraversion** shapes collaboration preferences:
```python
# High extraversion bank
"We should get the team together to discuss this."
# Low extraversion bank
"I'll analyze this independently and share my findings."
```
**Agreeableness** affects how disagreements are handled:
```python
# High agreeableness bank
"That's a valid point. Perhaps we can find a middle ground..."
# Low agreeableness bank
"Actually, the data doesn't support that conclusion."
```
**Neuroticism** influences risk assessment:
```python
# High neuroticism bank
"We should consider what could go wrong here..."
# Low neuroticism bank
"The risks seem manageable, let's proceed."
```
## Background
The background is a first-person narrative providing bank context:
<Tabs>
<TabItem value="python" label="Python">
```python
client.create_bank(
bank_id="financial-advisor",
background="""I am a conservative financial advisor with 20 years of experience.
I prioritize capital preservation over aggressive growth.
I have seen multiple market crashes and believe in diversification."""
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
await client.createBank('financial-advisor', {
background: `I am a conservative financial advisor with 20 years of experience.
I prioritize capital preservation over aggressive growth.
I have seen multiple market crashes and believe in diversification.`
});
```
</TabItem>
</Tabs>
Background influences:
- How questions are interpreted
- Perspective in responses
- Opinion formation context
## Getting Bank Profile
<Tabs>
<TabItem value="python" label="Python">
```python
# Using the low-level API
from hindsight_client_api import ApiClient, Configuration
from hindsight_client_api.api import DefaultApi
config = Configuration(host="http://localhost:8888")
api_client = ApiClient(config)
api = DefaultApi(api_client)
profile = api.get_bank_profile("my-bank")
print(f"Name: {profile.name}")
print(f"Background: {profile.background}")
print(f"Personality: {profile.personality}")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const profile = await client.getBankProfile('my-bank');
console.log(`Name: ${profile.name}`);
console.log(`Background: ${profile.background}`);
console.log(`Personality:`, profile.personality);
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight agent profile my-bank
```
</TabItem>
</Tabs>
## Default Values
If not specified, banks use neutral defaults:
```python
{
"openness": 0.5,
"conscientiousness": 0.5,
"extraversion": 0.5,
"agreeableness": 0.5,
"neuroticism": 0.5,
"bias_strength": 0.5,
"background": ""
}
```
## Personality Templates
Common personality configurations:
| Use Case | O | C | E | A | N | Bias |
|----------|---|---|---|---|---|------|
| **Customer Support** | 0.5 | 0.7 | 0.6 | 0.9 | 0.3 | 0.4 |
| **Code Reviewer** | 0.4 | 0.9 | 0.3 | 0.4 | 0.5 | 0.6 |
| **Creative Writer** | 0.9 | 0.4 | 0.7 | 0.6 | 0.5 | 0.7 |
| **Risk Analyst** | 0.3 | 0.9 | 0.3 | 0.4 | 0.8 | 0.6 |
| **Research Assistant** | 0.8 | 0.8 | 0.4 | 0.5 | 0.4 | 0.5 |
| **Neutral (default)** | 0.5 | 0.5 | 0.5 | 0.5 | 0.5 | 0.5 |
<Tabs>
<TabItem value="python" label="Python">
```python
# Customer support bank
client.create_bank(
bank_id="support",
background="I am a friendly customer support agent",
personality={
"openness": 0.5,
"conscientiousness": 0.7,
"extraversion": 0.6,
"agreeableness": 0.9, # Very diplomatic
"neuroticism": 0.3, # Calm under pressure
"bias_strength": 0.4
}
)
# Code reviewer bank
client.create_bank(
bank_id="reviewer",
background="I am a thorough code reviewer focused on quality",
personality={
"openness": 0.4, # Prefers proven patterns
"conscientiousness": 0.9, # Very thorough
"extraversion": 0.3,
"agreeableness": 0.4, # Direct feedback
"neuroticism": 0.5,
"bias_strength": 0.6
}
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Customer support bank
await client.createBank('support', {
background: 'I am a friendly customer support agent',
personality: {
openness: 0.5,
conscientiousness: 0.7,
extraversion: 0.6,
agreeableness: 0.9,
neuroticism: 0.3,
bias_strength: 0.4
}
});
// Code reviewer bank
await client.createBank('reviewer', {
background: 'I am a thorough code reviewer focused on quality',
personality: {
openness: 0.4,
conscientiousness: 0.9,
extraversion: 0.3,
agreeableness: 0.4,
neuroticism: 0.5,
bias_strength: 0.6
}
});
```
</TabItem>
</Tabs>
## Bank Isolation
Each bank has:
- **Separate memories** — banks don't share memories
- **Own personality** — traits are per-bank
- **Independent opinions** — formed from their own experiences
<Tabs>
<TabItem value="python" label="Python">
```python
# Store to bank A
client.retain(bank_id="bank-a", content="Python is great")
# Bank B doesn't see it
results = client.recall(bank_id="bank-b", query="Python")
# Returns empty
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Store to bank A
await client.retain('bank-a', 'Python is great');
// Bank B doesn't see it
const results = await client.recall('bank-b', 'Python');
// Returns empty
```
</TabItem>
</Tabs>
---
## File: developer/api/entities.md
# Entities
Entities are the people, organizations, places, and concepts that Hindsight automatically tracks across your memory bank.
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) and understand [how retain works](./retain).
:::
## Why Entities Matter
Entities improve recall quality in two ways:
1. **Co-occurrence tracking** — When entities appear together in facts, Hindsight builds a graph of relationships. This enables graph-based recall to find indirect connections.
2. **Observations** — Hindsight synthesizes high-level summaries about each entity from multiple facts. Including entity observations in recall provides richer context.
:::tip Include Entities in Recall
Use `include_entities=True` in your recall calls to get entity observations alongside fact results. See [Recall](./recall) for details.
:::
## What Are Entities?
When you retain information, Hindsight automatically identifies and tracks entities:
<Tabs>
<TabItem value="python" label="Python">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
client.retain(
bank_id="my-bank",
content="Alice works at Google in Mountain View. She specializes in TensorFlow."
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
await client.retain('my-bank', 'Alice works at Google in Mountain View. She specializes in TensorFlow.');
```
</TabItem>
</Tabs>
**Entities extracted:**
- **Alice** (person)
- **Google** (organization)
- **Mountain View** (location)
- **TensorFlow** (product)
## Entity Resolution
Multiple mentions are unified into a single entity:
- "Alice" + "Alice Chen" + "Alice C." → one person
- "Bob" + "Robert Chen" → one person (nickname)
- Context-aware: "Apple (company)" vs "apple (fruit)"
## List Entities
Get all entities tracked in a memory bank:
<Tabs>
<TabItem value="python" label="Python">
```python
# Using the low-level API
from hindsight_client_api import ApiClient, Configuration
from hindsight_client_api.api import DefaultApi
config = Configuration(host="http://localhost:8888")
api_client = ApiClient(config)
api = DefaultApi(api_client)
# List all entities
response = api.list_entities(bank_id="my-bank")
for entity in response.items:
print(f"{entity.canonical_name}: {entity.mention_count} mentions")
# List with pagination
response = api.list_entities(
bank_id="my-bank",
limit=50,
offset=0
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const apiClient = createClient(createConfig({ baseUrl: 'http://localhost:8888' }));
// List all entities
const response = await sdk.listEntities({
client: apiClient,
path: { bank_id: 'my-bank' }
});
for (const entity of response.data.items) {
console.log(`${entity.canonical_name}: ${entity.mention_count} mentions`);
}
// List with pagination
const paginated = await sdk.listEntities({
client: apiClient,
path: { bank_id: 'my-bank' },
query: { limit: 50, offset: 0 }
});
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# List all entities
hindsight entities list my-bank
# With limit
hindsight entities list my-bank --limit 50
```
</TabItem>
</Tabs>
## Get Entity Details
Retrieve detailed information about a specific entity:
<Tabs>
<TabItem value="python" label="Python">
```python
# Get entity details with observations
entity = api.get_entity(
bank_id="my-bank",
entity_id="entity-uuid"
)
print(f"Entity: {entity.canonical_name}")
print(f"First seen: {entity.first_seen}")
print(f"Mentions: {entity.mention_count}")
# Observations (synthesized summaries)
for obs in entity.observations:
print(f" - {obs.text}")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Get entity details
const entity = await sdk.getEntity({
client: apiClient,
path: { bank_id: 'my-bank', entity_id: 'entity-uuid' }
});
console.log(`Entity: ${entity.data.canonical_name}`);
console.log(`First seen: ${entity.data.first_seen}`);
console.log(`Mentions: ${entity.data.mention_count}`);
// Observations
for (const obs of entity.data.observations) {
console.log(` - ${obs.text}`);
}
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Get entity details
hindsight entities get my-bank entity-uuid
```
</TabItem>
</Tabs>
## Entity Observations
Observations are high-level summaries automatically synthesized from multiple facts:
**Facts about Alice:**
- "Alice works at Google"
- "Alice is a software engineer"
- "Alice specializes in ML"
**Observation created:**
- "Alice is a software engineer at Google specializing in ML"
Observations are generated in the background after retaining information.
## Regenerate Observations
Force regeneration of entity observations:
<Tabs>
<TabItem value="python" label="Python">
```python
# Regenerate observations for an entity
api.regenerate_entity_observations(
bank_id="my-bank",
entity_id="entity-uuid"
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Regenerate observations
await sdk.regenerateEntityObservations({
client: apiClient,
path: { bank_id: 'my-bank', entity_id: 'entity-uuid' }
});
```
</TabItem>
</Tabs>
## Entity Response Format
```json
{
"id": "entity-uuid",
"canonical_name": "Alice Chen",
"first_seen": "2024-01-15T10:30:00Z",
"last_seen": "2024-03-20T14:22:00Z",
"mention_count": 47,
"observations": [
{
"text": "Alice is a software engineer at Google specializing in ML",
"mentioned_at": "2024-03-20T15:00:00Z"
}
]
}
```
## Next Steps
- [**Memory Banks**](./memory-banks) — Configure bank personality
- [**Documents**](./documents) — Track document sources
- [**Operations**](./operations) — Monitor background tasks
---
## File: developer/api/documents.md
# Documents
Track and manage document sources in your memory bank. Documents provide traceability — knowing where memories came from.
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) and understand [how retain works](./retain).
:::
## What Are Documents?
Documents are containers for retained content. They help you:
- **Track sources** — Know which PDF, conversation, or file a memory came from
- **Update content** — Re-retain a document to update its facts
- **Delete in bulk** — Remove all memories from a document at once
- **Organize memories** — Group related facts by source
## Chunks
When you retain content, Hindsight splits it into chunks before extracting facts. These chunks are stored alongside the extracted memories, preserving the original text segments.
**Why chunks matter:**
- **Context preservation** — Chunks contain the raw text that generated facts, useful when you need the exact wording
- **Richer recall** — Including chunks in recall provides surrounding context for matched facts
:::tip Include Chunks in Recall
Use `include_chunks=True` in your recall calls to get the original text chunks alongside fact results. See [Recall](./recall) for details.
:::
## Retain with Document ID
Associate retained content with a document:
<Tabs>
<TabItem value="python" label="Python">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
# Retain with document ID
client.retain(
bank_id="my-bank",
content="Alice presented the Q4 roadmap...",
document_id="meeting-2024-03-15"
)
# Batch retain for a document
client.retain_batch(
bank_id="my-bank",
items=[
{"content": "Item 1: Product launch delayed to Q2"},
{"content": "Item 2: New hiring targets announced"},
{"content": "Item 3: Budget approved for ML team"}
],
document_id="meeting-2024-03-15"
)
# From file
with open("notes.txt") as f:
client.retain(
bank_id="my-bank",
content=f.read(),
document_id="notes-2024-03-15"
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
// Retain with document ID
await client.retain('my-bank', 'Alice presented the Q4 roadmap...', {
document_id: 'meeting-2024-03-15'
});
// Batch retain
await client.retainBatch('my-bank', [
{ content: 'Item 1: Product launch delayed to Q2' },
{ content: 'Item 2: New hiring targets announced' },
{ content: 'Item 3: Budget approved for ML team' }
], { documentId: 'meeting-2024-03-15' });
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Retain file with document ID
hindsight retain my-bank --file notes.txt --document-id notes-2024-03-15
# Batch retain directory
hindsight retain my-bank --files docs/*.md --document-id project-docs
```
</TabItem>
</Tabs>
## Update Documents
Re-retaining with the same document_id **replaces** the old content:
<Tabs>
<TabItem value="python" label="Python">
```python
# Original
client.retain(
bank_id="my-bank",
content="Project deadline: March 31",
document_id="project-plan"
)
# Update (deletes old facts, creates new ones)
client.retain(
bank_id="my-bank",
content="Project deadline: April 15 (extended)",
document_id="project-plan"
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Original
await client.retain('my-bank', 'Project deadline: March 31', {
document_id: 'project-plan'
});
// Update
await client.retain('my-bank', 'Project deadline: April 15 (extended)', {
document_id: 'project-plan'
});
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Original
hindsight retain my-bank "Project deadline: March 31" --document-id project-plan
# Update
hindsight retain my-bank "Project deadline: April 15 (extended)" --document-id project-plan
```
</TabItem>
</Tabs>
## List Documents
View all documents in a memory bank:
<Tabs>
<TabItem value="python" label="Python">
```python
# Using the low-level API
from hindsight_client_api import ApiClient, Configuration
from hindsight_client_api.api import DefaultApi
config = Configuration(host="http://localhost:8888")
api_client = ApiClient(config)
api = DefaultApi(api_client)
# List all documents
response = api.list_documents(bank_id="my-bank")
for doc in response.items:
print(f"{doc.id}: {doc.memory_unit_count} memories")
print(f" Created: {doc.created_at}")
# With pagination
response = api.list_documents(
bank_id="my-bank",
limit=50,
offset=0
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const apiClient = createClient(createConfig({ baseUrl: 'http://localhost:8888' }));
// List all documents
const response = await sdk.listDocuments({
client: apiClient,
path: { bank_id: 'my-bank' }
});
for (const doc of response.data.items) {
console.log(`${doc.id}: ${doc.memory_unit_count} memories`);
console.log(` Created: ${doc.created_at}`);
}
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# List documents
hindsight documents list my-bank
# With limit
hindsight documents list my-bank --limit 50
```
</TabItem>
</Tabs>
## Get Document Details
Retrieve a specific document with its content:
<Tabs>
<TabItem value="python" label="Python">
```python
# Get document
doc = api.get_document(
bank_id="my-bank",
document_id="meeting-2024-03-15"
)
print(f"Document: {doc.id}")
print(f"Original text: {doc.original_text[:200]}...")
print(f"Memories: {doc.memory_unit_count}")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Get document
const doc = await sdk.getDocument({
client: apiClient,
path: { bank_id: 'my-bank', document_id: 'meeting-2024-03-15' }
});
console.log(`Document: ${doc.data.id}`);
console.log(`Original text: ${doc.data.original_text.substring(0, 200)}...`);
console.log(`Memories: ${doc.data.memory_unit_count}`);
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Get document
hindsight documents get my-bank meeting-2024-03-15
```
</TabItem>
</Tabs>
## Delete Documents
Remove a document and all its memories:
<Tabs>
<TabItem value="python" label="Python">
```python
# Delete document (removes all associated memories)
api.delete_document(
bank_id="my-bank",
document_id="old-meeting"
)
# Bulk delete
for doc_id in ["old-1", "old-2", "old-3"]:
api.delete_document(bank_id="my-bank", document_id=doc_id)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Delete document
await sdk.deleteDocument({
client: apiClient,
path: { bank_id: 'my-bank', document_id: 'old-meeting' }
});
// Bulk delete
for (const docId of ['old-1', 'old-2', 'old-3']) {
await sdk.deleteDocument({
client: apiClient,
path: { bank_id: 'my-bank', document_id: docId }
});
}
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Delete document
hindsight documents delete my-bank old-meeting
# Confirm deletion
hindsight documents delete my-bank old-meeting --confirm
```
</TabItem>
</Tabs>
## Document Response Format
```json
{
"id": "meeting-2024-03-15",
"bank_id": "my-bank",
"original_text": "Alice presented the Q4 roadmap...",
"memory_unit_count": 12,
"created_at": "2024-03-15T14:00:00Z",
"retain_params": {
"context": "team meeting",
"event_date": "2024-03-15"
}
}
```
## Use Cases
### Meeting Notes
<Tabs>
<TabItem value="python" label="Python">
```python
from datetime import date
# Store meeting notes with date-based IDs
client.retain(
bank_id="team-memory",
content=meeting_transcript,
document_id=f"meeting-{date.today()}"
)
```
</TabItem>
</Tabs>
### Documentation
<Tabs>
<TabItem value="python" label="Python">
```python
from pathlib import Path
# Store docs with version tracking
docs_dir = Path("docs")
version = "1.0"
for file in docs_dir.glob("*.md"):
client.retain(
bank_id="docs-memory",
content=file.read_text(),
document_id=f"docs-{file.stem}-v{version}"
)
```
</TabItem>
</Tabs>
### Conversation History
<Tabs>
<TabItem value="python" label="Python">
```python
# Store chat history with session IDs
client.retain(
bank_id="chat-memory",
content=conversation,
document_id=f"session-{session_id}"
)
```
</TabItem>
</Tabs>
## Next Steps
- [**Entities**](./entities) — Track people, places, and concepts
- [**Operations**](./operations) — Monitor background tasks
- [**Memory Banks**](./memory-banks) — Configure bank settings
---
## File: developer/api/operations.md
# Operations
Monitor and manage long-running background tasks in Hindsight.
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) and understand [how retain works](./retain).
:::
## What Are Operations?
When you call `retain_batch` with `async=True`, Hindsight processes the content in the background and returns immediately with an operation ID. Operations let you track and manage these async retain tasks.
By default, async operations are executed in-process within the API service. This is managed automatically — you don't need to configure anything.
:::tip Scaling with Streaming
For high-throughput workloads, you can extend the task backend to use a streaming platform like Kafka. This enables scale-out processing across multiple workers and handles backpressure on the API.
:::
## Async Batch Retain
For large content batches, use async mode to avoid timeouts:
<Tabs>
<TabItem value="python" label="Python">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
client.retain_batch(
bank_id="my-bank",
items=[
{"content": doc1_text},
{"content": doc2_text},
],
retain_async=True
)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
await client.retainBatch('my-bank', [
{ content: doc1Text },
{ content: doc2Text },
], { async: true });
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight retain my-bank --files docs/*.md --async
```
</TabItem>
</Tabs>
## List Operations
View all operations for a memory bank:
<Tabs>
<TabItem value="python" label="Python">
```python
# Using the low-level API
from hindsight_client_api import ApiClient, Configuration
from hindsight_client_api.api import DefaultApi
config = Configuration(host="http://localhost:8888")
api_client = ApiClient(config)
api = DefaultApi(api_client)
# List all operations
response = api.list_operations(bank_id="my-bank")
for op in response.items:
print(f"{op.id}: {op.task_type} - {op.status}")
print(f" Items: {op.items_count}")
if op.error_message:
print(f" Error: {op.error_message}")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
const apiClient = createClient(createConfig({ baseUrl: 'http://localhost:8888' }));
// List all operations
const response = await sdk.listOperations({
client: apiClient,
path: { bank_id: 'my-bank' }
});
for (const op of response.data.items) {
console.log(`${op.id}: ${op.task_type} - ${op.status}`);
console.log(` Items: ${op.items_count}`);
if (op.error_message) {
console.log(` Error: ${op.error_message}`);
}
}
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# List all operations
hindsight operations list my-bank
# Filter by status
hindsight operations list my-bank --status running
# Watch all running operations
hindsight operations watch my-bank --all
```
</TabItem>
</Tabs>
## Cancel Operations
Stop a running or pending operation:
<Tabs>
<TabItem value="python" label="Python">
```python
# Cancel operation
api.cancel_operation(
bank_id="my-bank",
operation_id="op-abc123"
)
# Cancel all pending operations
response = api.list_operations(bank_id="my-bank")
for op in response.items:
if op.status == "pending":
api.cancel_operation(bank_id="my-bank", operation_id=op.id)
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
// Cancel operation
await sdk.cancelOperation({
client: apiClient,
path: { bank_id: 'my-bank', operation_id: 'op-abc123' }
});
// Cancel all pending
const ops = await sdk.listOperations({
client: apiClient,
path: { bank_id: 'my-bank' }
});
for (const op of ops.data.items) {
if (op.status === 'pending') {
await sdk.cancelOperation({
client: apiClient,
path: { bank_id: 'my-bank', operation_id: op.id }
});
}
}
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Cancel operation
hindsight operations cancel my-bank op-abc123
# Cancel all pending
hindsight operations cancel my-bank --all-pending
```
</TabItem>
</Tabs>
## Operation States
| State | Description |
|-------|-------------|
| **pending** | Queued, waiting to start |
| **running** | Currently processing |
| **completed** | Successfully finished |
| **failed** | Encountered an error |
| **cancelled** | Stopped by user |
## Monitoring Strategies
### Polling
<Tabs>
<TabItem value="python" label="Python">
```python
def wait_for_operations(api, bank_id, poll_interval=5):
"""Wait for all pending/running operations to complete."""
while True:
response = api.list_operations(bank_id=bank_id)
pending_or_running = [
op for op in response.items
if op.status in ['pending', 'running']
]
if not pending_or_running:
print("All operations completed!")
break
for op in pending_or_running:
print(f" {op.id}: {op.status} ({op.items_count} items)")
time.sleep(poll_interval)
# Use it
wait_for_operations(api, "my-bank")
```
</TabItem>
<TabItem value="node" label="Node.js">
```typescript
async function waitForOperations(apiClient: any, bankId: string, pollInterval = 5000) {
while (true) {
const response = await sdk.listOperations({
client: apiClient,
path: { bank_id: bankId }
});
const pendingOrRunning = response.data.items.filter(
(op: any) => ['pending', 'running'].includes(op.status)
);
if (pendingOrRunning.length === 0) {
console.log('All operations completed!');
break;
}
for (const op of pendingOrRunning) {
console.log(` ${op.id}: ${op.status} (${op.items_count} items)`);
}
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
}
// Use it
await waitForOperations(apiClient, 'my-bank');
```
</TabItem>
</Tabs>
## Performance Tips
**Use async for large batches:**
- Sync: < 100 items or < 100KB
- Async: > 100 items or > 100KB
**Monitor progress:**
- Check `items_count` field
- Poll every 5-10 seconds
**Handle failures:**
- Check `error_message` field for details
- Retry with exponential backoff
- Break large batches into smaller chunks
## Next Steps
- [**Documents**](./documents) — Track document sources
- [**Entities**](./entities) — Monitor entity tracking
- [**Memory Banks**](./memory-banks) — Configure bank settings
---
## File: developer/installation.md
# Installation
Hindsight can be deployed in three ways depending on your infrastructure and requirements.
## Prerequisites
### PostgreSQL with pgvector
Hindsight requires PostgreSQL with the **pgvector** extension for vector similarity search.
**By default**, Hindsight uses **pg0** — an embedded PostgreSQL that runs locally on your machine. This is convenient for development but **not recommended for production**.
**For production**, use an external PostgreSQL with pgvector:
- **Supabase** — Managed PostgreSQL with pgvector built-in
- **Neon** — Serverless PostgreSQL with pgvector
- **AWS RDS** / **Cloud SQL** / **Azure** — With pgvector extension enabled
- **Self-hosted** — PostgreSQL 14+ with pgvector installed
### LLM Provider
You need an LLM API key for fact extraction, entity resolution, and answer generation:
- **Groq** (recommended): Fast inference with `gpt-oss-20b`
- **OpenAI**: GPT-4o, GPT-4o-mini
- **Ollama**: Run models locally
See [Models](./models) for detailed comparison and configuration.
---
## Docker
**Best for**: Quick start, development, small deployments
### Single Container (Quickest)
Run everything in one container with embedded PostgreSQL:
```bash
docker run -p 8888:8888 -p 9999:9999 \
-e HINDSIGHT_API_LLM_PROVIDER=openai \
-e HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx \
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
ghcr.io/vectorize-io/hindsight
```
- **API Server**: http://localhost:8888
- **Control Plane** (Web UI): http://localhost:9999
---
## Helm / Kubernetes
**Best for**: Production deployments, auto-scaling, cloud environments
```bash
# Add Hindsight Helm repository
helm repo add hindsight https://vectorize-io.github.io/hindsight
helm repo update
# Install with built-in PostgreSQL
helm install hindsight hindsight/hindsight \
--set api.llm.provider=groq \
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
--set postgresql.enabled=true
# Or use external PostgreSQL
helm install hindsight hindsight/hindsight \
--set api.llm.provider=groq \
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
--set postgresql.enabled=false \
--set api.database.url=postgresql://user:pass@postgres.example.com:5432/hindsight
```
**Requirements**:
- Kubernetes cluster (GKE, EKS, AKS, or self-hosted)
- Helm 3+
See the [Helm chart documentation](https://github.com/vectorize-io/hindsight/tree/main/helm) for advanced configuration.
---
## Bare Metal (pip)
**Best for**: Custom deployments, integration into existing Python applications
### Install
```bash
pip install hindsight-all
```
### Run with Embedded Database
For development and testing, Hindsight can run with an embedded PostgreSQL (pg0):
```bash
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
hindsight-api
```
This creates a database in `~/.hindsight/data/` and starts the API on http://localhost:8888.
### Run with External PostgreSQL
For production, connect to your own PostgreSQL instance:
```bash
export HINDSIGHT_API_DATABASE_URL=postgresql://user:pass@localhost:5432/hindsight
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
hindsight-api
```
**Note**: The database must exist and have pgvector enabled (`CREATE EXTENSION vector;`).
### CLI Options
```bash
hindsight-api --port 9000 # Custom port (default: 8888)
hindsight-api --host 127.0.0.1 # Bind to localhost only
hindsight-api --workers 4 # Multiple worker processes
hindsight-api --mcp # Enable MCP server
hindsight-api --log-level debug # Verbose logging
```
---
## Next Steps
- [Configuration](./configuration.md) — Environment variables and settings
- [Models](./models.md) — ML models and providers
- [Metrics](./metrics.md) — Monitoring and observability
---
## File: developer/configuration.md
# Configuration
Complete reference for configuring Hindsight server through environment variables and configuration files.
## Environment Variables
Hindsight is configured entirely through environment variables, making it easy to deploy across different environments and container orchestration platforms.
### LLM Provider Configuration
Configure the LLM provider used for fact extraction, entity resolution, and reasoning operations.
#### Common LLM Settings
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `HINDSIGHT_API_LLM_PROVIDER` | LLM provider: `groq`, `openai`, `ollama` | `groq` | Yes |
| `HINDSIGHT_API_LLM_API_KEY` | API key for LLM provider | - | Yes (except ollama) |
| `HINDSIGHT_API_LLM_MODEL` | Model name | Provider-specific | No |
| `HINDSIGHT_API_LLM_BASE_URL` | Custom LLM endpoint | Provider default | No |
#### Provider-Specific Examples
**Groq (Recommended for Fast Inference)**
```bash
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=openai/gpt-oss-20b
```
**OpenAI**
```bash
export HINDSIGHT_API_LLM_PROVIDER=openai
export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=gpt-4o
```
**Ollama (Local, No API Key)**
```bash
export HINDSIGHT_API_LLM_PROVIDER=ollama
export HINDSIGHT_API_LLM_BASE_URL=http://localhost:11434/v1
export HINDSIGHT_API_LLM_MODEL=llama3.1
```
**OpenAI-Compatible Endpoints**
```bash
export HINDSIGHT_API_LLM_PROVIDER=openai
export HINDSIGHT_API_LLM_BASE_URL=https://your-endpoint.com/v1
export HINDSIGHT_API_LLM_API_KEY=your-api-key
export HINDSIGHT_API_LLM_MODEL=your-model-name
```
### Database Configuration
Configure the PostgreSQL database connection and behavior.
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `HINDSIGHT_API_DATABASE_URL` | PostgreSQL connection string | - | Yes* |
**\*Note**: If `DATABASE_URL` is not provided, the server will use embedded `pg0` (embedded PostGRE).
### MCP Server Configuration
Configure the Model Context Protocol (MCP) server for AI assistant integrations.
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `HINDSIGHT_API_MCP_ENABLED` | Enable MCP server | `true` | No |
```bash
# Enable MCP server (default)
export HINDSIGHT_API_MCP_ENABLED=true
# Disable MCP server
export HINDSIGHT_API_MCP_ENABLED=false
```
### Embeddings Configuration
Configure the embeddings provider for semantic search. By default, uses local SentenceTransformers models.
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local` or `tei` | `local` | No |
| `HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL` | Model name for local provider | `BAAI/bge-small-en-v1.5` | No |
| `HINDSIGHT_API_EMBEDDINGS_TEI_URL` | TEI server URL | - | Yes (if provider is `tei`) |
**Local Provider (Default)**
Uses SentenceTransformers to run embedding models locally. Good for development and smaller deployments.
```bash
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
export HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5
```
**TEI Provider (HuggingFace Text Embeddings Inference)**
Uses a remote [TEI server](https://github.com/huggingface/text-embeddings-inference) for high-performance inference. Recommended for production deployments.
```bash
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=tei
export HINDSIGHT_API_EMBEDDINGS_TEI_URL=http://localhost:8080
```
:::warning
All embedding models must produce 384-dimensional vectors to match the database schema.
:::
### Reranker Configuration
Configure the cross-encoder reranker for improving search result relevance. By default, uses local SentenceTransformers models.
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `HINDSIGHT_API_RERANKER_PROVIDER` | Provider: `local` or `tei` | `local` | No |
| `HINDSIGHT_API_RERANKER_LOCAL_MODEL` | Model name for local provider | `cross-encoder/ms-marco-MiniLM-L-6-v2` | No |
| `HINDSIGHT_API_RERANKER_TEI_URL` | TEI server URL | - | Yes (if provider is `tei`) |
**Local Provider (Default)**
Uses SentenceTransformers CrossEncoder to run reranking locally.
```bash
export HINDSIGHT_API_RERANKER_PROVIDER=local
export HINDSIGHT_API_RERANKER_LOCAL_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
```
**TEI Provider (HuggingFace Text Embeddings Inference)**
Uses a remote [TEI server](https://github.com/huggingface/text-embeddings-inference) with a reranker model.
```bash
export HINDSIGHT_API_RERANKER_PROVIDER=tei
export HINDSIGHT_API_RERANKER_TEI_URL=http://localhost:8081
```
:::tip
When using TEI, you can run separate servers for embeddings and reranking, or use a single server if it supports both operations with your chosen model.
:::
## Configuration Files
### .env File
The Hindsight API will look for a `.env` file:
```bash
# .env
# Database
HINDSIGHT_API_DATABASE_URL=postgresql://hindsight:hindsight_dev@localhost:5432/hindsight
# LLM
HINDSIGHT_API_LLM_PROVIDER=groq
HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
# Embeddings (optional, defaults to local)
# HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
# HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5
# Reranker (optional, defaults to local)
# HINDSIGHT_API_RERANKER_PROVIDER=local
# HINDSIGHT_API_RERANKER_LOCAL_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
```
---
For configuration issues not covered here, please [open an issue](https://github.com/your-repo/hindsight/issues) on GitHub.
---
## File: developer/models.md
# Models
Hindsight uses several machine learning models for different tasks.
## Overview
| Model Type | Purpose | Default | Configurable |
|------------|---------|---------|--------------|
| **Embedding** | Vector representations for semantic search | `BAAI/bge-small-en-v1.5` | Yes |
| **Cross-Encoder** | Reranking search results | `ms-marco-MiniLM-L-6-v2` | Yes |
| **LLM** | Fact extraction, reasoning, generation | Provider-specific | Yes |
All local models (embedding, cross-encoder) are automatically downloaded from HuggingFace on first run.
---
## Embedding Model
Converts text into dense vector representations for semantic similarity search.
**Default:** `BAAI/bge-small-en-v1.5` (384 dimensions, ~130MB)
**Alternatives:**
| Model | Dimensions | Use Case |
|-------|------------|----------|
| `BAAI/bge-small-en-v1.5` | 384 | Default, fast, good quality |
| `BAAI/bge-base-en-v1.5` | 768 | Higher accuracy, slower |
| `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` | 384 | Multilingual (50+ languages) |
**Configuration:**
```bash
export HINDSIGHT_API_EMBEDDING_MODEL=BAAI/bge-base-en-v1.5
export HINDSIGHT_API_EMBEDDING_DEVICE=cuda # or mps for Apple Silicon
export HINDSIGHT_API_EMBEDDING_BATCH_SIZE=64
```
---
## Cross-Encoder (Reranker)
Reranks initial search results to improve precision.
**Default:** `cross-encoder/ms-marco-MiniLM-L-6-v2` (~85MB)
**Alternatives:**
| Model | Use Case |
|-------|----------|
| `ms-marco-MiniLM-L-6-v2` | Default, fast |
| `ms-marco-MiniLM-L-12-v2` | Higher accuracy |
| `mmarco-mMiniLMv2-L12-H384-v1` | Multilingual |
**Configuration:**
```bash
export HINDSIGHT_API_RERANK_MODEL=cross-encoder/ms-marco-MiniLM-L-12-v2
export HINDSIGHT_API_RERANK_TOP_K=50 # How many results to rerank
export HINDSIGHT_API_RERANK_ENABLED=true # Set to false to disable
```
---
## LLM
Used for fact extraction, entity resolution, opinion generation, and answer synthesis.
**Supported providers:** Groq, OpenAI, Ollama
| Provider | Recommended Model | Best For |
|----------|-------------------|----------|
| **Groq** | `gpt-oss-20b` | Fast inference, high throughput (recommended) |
| **OpenAI** | `gpt-4o-mini` | Good quality, cost-effective |
| **OpenAI** | `gpt-4o` | Best quality |
| **Ollama** | `llama3.1` | Local deployment, privacy |
**Configuration:**
```bash
# Groq (recommended)
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=openai/gpt-oss-20b
# OpenAI
export HINDSIGHT_API_LLM_PROVIDER=openai
export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=gpt-4o-mini
# Ollama (local)
export HINDSIGHT_API_LLM_PROVIDER=ollama
export HINDSIGHT_API_LLM_BASE_URL=http://localhost:11434/v1
export HINDSIGHT_API_LLM_MODEL=llama3.1
```
**Note:** The LLM is the primary bottleneck for write operations. See [Performance](./performance) for optimization strategies.
---
## Model Comparison
| Provider | Model | Speed | Quality | Cost |
|----------|-------|-------|---------|------|
| Groq | gpt-oss-20b | Fast | Good | Free tier |
| OpenAI | gpt-4o-mini | Medium | Good | $0.15 / $0.60 per 1M tokens |
| OpenAI | gpt-4o | Slower | Best | $2.50 / $10.00 per 1M tokens |
| Ollama | llama3.1 | Varies | Good | Free (local) |
---
## File: developer/rag-vs-hindsight.md
# RAG vs Memory
Traditional RAG (Retrieval-Augmented Generation) retrieves documents similar to a query. Hindsight provides structured memory with temporal reasoning, entity understanding, and belief formation.
## Capability Comparison
| Capability | RAG | Hindsight |
|------------|-----|-----------|
| **Search strategy** | Semantic similarity only | Semantic + keyword + graph + temporal |
| **Multi-hop reasoning** | Limited to retrieved chunks | Graph traversal across entity relationships |
| **Temporal queries** | Keyword matching ("spring") | Date parsing and range filtering |
| **Entity understanding** | None | Entity resolution, observations, co-occurrence |
| **Belief formation** | Stateless | Opinions with confidence scores that evolve |
| **Personality** | None | Big Five traits influence interpretation |
## Architecture Comparison
### RAG
| Step | Operation |
|------|-----------|
| 1 | Embed query |
| 2 | Vector similarity search |
| 3 | Return top-k chunks |
| 4 | Generate response |
Single retrieval strategy. No state between queries.
### Hindsight
| Step | Operation |
|------|-----------|
| 1 | Parse query (extract temporal expressions, entities) |
| 2 | Execute 4 parallel retrievals: semantic, BM25, graph, temporal |
| 3 | Fuse results with RRF |
| 4 | Rerank with cross-encoder |
| 5 | Apply personality traits |
| 6 | Generate response |
Multiple retrieval strategies. Persistent state across sessions.
## Example Scenarios
### Multi-Hop Reasoning
**Stored facts:**
- "Alice is the tech lead on Project Atlas"
- "Project Atlas uses Kubernetes"
- "Kubernetes cluster had an outage Tuesday"
**Query:** "Was Alice affected by recent issues?"
| System | Result |
|--------|--------|
| RAG | Retrieves facts about Alice only (no semantic similarity to "issues") |
| Hindsight | Traverses Alice → Project Atlas → Kubernetes → outage via entity links |
### Temporal Queries
**Stored facts with timestamps:**
- March: "Alice started microservices migration"
- April: "Alice completed auth service"
- October: "Alice focusing on performance"
**Query:** "What did Alice do last spring?"
| System | Result |
|--------|--------|
| RAG | Returns all Alice facts regardless of date |
| Hindsight | Parses "last spring" → March-May, filters to that range |
### Entity Understanding
**Stored facts about a user across sessions:**
- "Pro subscription"
- "Mobile app crashes in settings"
- "Switched to annual billing"
- "Desktop app working fine"
**Query:** "What do you know about my account?"
| System | Result |
|--------|--------|
| RAG | Lists disconnected facts |
| Hindsight | Returns synthesized entity observations: subscription status, billing, known issues |
### Belief Evolution
**Week 1:** User struggles with async Python, succeeds with threads
**Week 3:** User asks about asyncio, implements async database calls
| System | Behavior |
|--------|----------|
| RAG | No memory of progression |
| Hindsight | Forms opinion "user prefers sync" (0.7) → updates to "user growing comfortable with async" (0.6) |
## When to Use Each
| Use Case | Recommended |
|----------|-------------|
| Document Q&A over static corpus | RAG |
| Search with no temporal requirements | RAG |
| AI assistants with persistent memory | Hindsight |
| Applications requiring entity tracking | Hindsight |
| Systems needing consistent personality | Hindsight |
| Temporal queries ("last month", "in 2023") | Hindsight |
---
## File: sdks/python.md
# Python Client
Official Python client for the Hindsight API.
## Installation
<Tabs>
<TabItem value="all-in-one" label="All-in-One (Recommended)">
The `hindsight-all` package includes embedded PostgreSQL, HTTP API server, and client:
```bash
pip install hindsight-all
```
</TabItem>
<TabItem value="client-only" label="Client Only">
If you already have a Hindsight server running:
```bash
pip install hindsight-client
```
</TabItem>
</Tabs>
## Quick Start
<Tabs>
<TabItem value="all-in-one" label="All-in-One">
```python
from hindsight import HindsightServer, HindsightClient
with HindsightServer(
llm_provider="openai",
llm_model="gpt-4.1-mini",
llm_api_key=os.environ["OPENAI_API_KEY"]
) as server:
client = HindsightClient(base_url=server.url)
# Retain a memory
client.retain(bank_id="my-agent", content="Alice works at Google")
# Recall memories
results = client.recall(bank_id="my-agent", query="What does Alice do?")
for r in results:
print(r.text)
# Reflect - generate response with personality
answer = client.reflect(bank_id="my-agent", query="Tell me about Alice")
print(answer.text)
```
</TabItem>
<TabItem value="client-only" label="Client Only">
```python
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
# Retain a memory
client.retain(bank_id="my-agent", content="Alice works at Google")
# Recall memories
results = client.recall(bank_id="my-agent", query="What does Alice do?")
for r in results:
print(r.text)
# Reflect - generate response with personality
answer = client.reflect(bank_id="my-agent", query="Tell me about Alice")
print(answer.text)
```
</TabItem>
</Tabs>
## Client Initialization
```python
from hindsight_client import Hindsight
client = Hindsight(
base_url="http://localhost:8888", # Hindsight API URL
timeout=30.0, # Request timeout in seconds
)
```
## Core Operations
### Retain (Store Memory)
```python
# Simple
client.retain(
bank_id="my-agent",
content="Alice works at Google as a software engineer",
)
# With options
from datetime import datetime
client.retain(
bank_id="my-agent",
content="Alice got promoted",
context="career update",
timestamp=datetime(2024, 1, 15),
document_id="conversation_001",
metadata={"source": "slack"},
)
```
### Retain Batch
```python
client.retain_batch(
bank_id="my-agent",
items=[
{"content": "Alice works at Google", "context": "career"},
{"content": "Bob is a data scientist", "context": "career"},
],
document_id="conversation_001",
retain_async=False, # Set True for background processing
)
```
### Recall (Search)
```python
# Simple - returns list of RecallResult
results = client.recall(
bank_id="my-agent",
query="What does Alice do?",
)
for r in results:
print(f"{r.text} (type: {r.type})")
# With options
results = client.recall(
bank_id="my-agent",
query="What does Alice do?",
types=["world", "opinion"], # Filter by fact type
max_tokens=4096,
budget="high", # low, mid, or high
)
```
### Recall with Full Response
```python
# Returns RecallResponse with entities and trace info
response = client.recall_memories(
bank_id="my-agent",
query="What does Alice do?",
types=["world", "experience"],
budget="mid",
max_tokens=4096,
trace=True,
include_entities=True,
max_entity_tokens=500,
)
print(f"Found {len(response.results)} memories")
for r in response.results:
print(f" - {r.text}")
# Access entities
if response.entities:
for entity in response.entities:
print(f"Entity: {entity.name}")
```
### Reflect (Generate Response)
```python
answer = client.reflect(
bank_id="my-agent",
query="What should I know about Alice?",
budget="low", # low, mid, or high
context="preparing for a meeting",
)
print(answer.text) # Generated response
print(answer.based_on) # Memories used
```
## Bank Management
### Create Bank
```python
client.create_bank(
bank_id="my-agent",
name="Assistant",
background="I am a helpful AI assistant",
personality={
"openness": 0.7,
"conscientiousness": 0.8,
"extraversion": 0.5,
"agreeableness": 0.6,
"neuroticism": 0.3,
"bias_strength": 0.5,
},
)
```
### List Memories
```python
response = client.list_memories(
bank_id="my-agent",
type="world", # Optional: filter by type
search_query="Alice", # Optional: text search
limit=100,
offset=0,
)
for memory in response.memories:
print(f"{memory.id}: {memory.text}")
```
## Async Support
All methods have async versions prefixed with `a`:
```python
from hindsight_client import Hindsight
async def main():
client = Hindsight(base_url="http://localhost:8888")
# Async retain
await client.aretain(bank_id="my-agent", content="Hello world")
# Async recall
results = await client.arecall(bank_id="my-agent", query="Hello")
for r in results:
print(r.text)
# Async reflect
answer = await client.areflect(bank_id="my-agent", query="What did I say?")
print(answer.text)
client.close()
asyncio.run(main())
```
## Response Types
The client exports response types for type hints:
```python
from hindsight_client import (
Hindsight,
RetainResponse,
RecallResponse,
RecallResult,
ReflectResponse,
BankProfileResponse,
PersonalityTraits,
)
```
## Context Manager
```python
from hindsight_client import Hindsight
with Hindsight(base_url="http://localhost:8888") as client:
client.retain(bank_id="my-agent", content="Hello")
results = client.recall(bank_id="my-agent", query="Hello")
# Client automatically closed
```
---
## File: sdks/nodejs.md
# Node.js Client
Official TypeScript/JavaScript client for the Hindsight API.
## Installation
```bash
npm install @vectorize-io/hindsight-client
```
## Quick Start
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
// Retain a memory
await client.retain('my-agent', 'Alice works at Google');
// Recall memories
const response = await client.recall('my-agent', 'What does Alice do?');
for (const r of response.results) {
console.log(r.text);
}
// Reflect - generate response with personality
const answer = await client.reflect('my-agent', 'Tell me about Alice');
console.log(answer.text);
```
## Client Initialization
```typescript
const client = new HindsightClient({
baseUrl: 'http://localhost:8888',
});
```
## Core Operations
### Retain (Store Memory)
```typescript
// Simple
await client.retain('my-agent', 'Alice works at Google');
// With options
await client.retain('my-agent', 'Alice got promoted', {
timestamp: new Date('2024-01-15'),
context: 'career update',
metadata: { source: 'slack' },
async: false, // Set true for background processing
});
```
### Retain Batch
```typescript
await client.retainBatch('my-agent', [
{ content: 'Alice works at Google', context: 'career' },
{ content: 'Bob is a data scientist', context: 'career' },
], {
documentId: 'conversation_001',
async: false,
});
```
### Recall (Search)
```typescript
// Simple - returns RecallResponse
const response = await client.recall('my-agent', 'What does Alice do?');
for (const r of response.results) {
console.log(`${r.text} (type: ${r.type})`);
}
// With options
const response = await client.recall('my-agent', 'What does Alice do?', {
types: ['world', 'opinion'], // Filter by fact type
maxTokens: 4096,
budget: 'high', // 'low', 'mid', or 'high'
trace: true,
});
```
### Reflect (Generate Response)
```typescript
const answer = await client.reflect('my-agent', 'What should I know about Alice?', {
budget: 'low', // 'low', 'mid', or 'high'
context: 'preparing for a meeting',
});
console.log(answer.text); // Generated response
console.log(answer.based_on); // Memories used
```
## Bank Management
### Create Bank
```typescript
await client.createBank('my-agent', {
name: 'Assistant',
background: 'I am a helpful AI assistant',
personality: {
openness: 0.7,
conscientiousness: 0.8,
extraversion: 0.5,
agreeableness: 0.6,
neuroticism: 0.3,
bias_strength: 0.5,
},
});
```
### Get Bank Profile
```typescript
const profile = await client.getBankProfile('my-agent');
console.log(profile.personality);
console.log(profile.background);
```
### List Memories
```typescript
const response = await client.listMemories('my-agent', {
type: 'world', // Optional filter
q: 'Alice', // Optional text search
limit: 100,
offset: 0,
});
for (const memory of response.memories) {
console.log(`${memory.id}: ${memory.text}`);
}
```
## TypeScript Types
The client exports all types for full TypeScript support:
```typescript
RetainResponse,
RecallResponse,
RecallResult,
ReflectResponse,
BankProfileResponse,
Budget,
} from '@vectorize-io/hindsight-client';
// Budget is a union type: 'low' | 'mid' | 'high'
const budget: Budget = 'mid';
```
## Advanced: Low-Level SDK
For advanced use cases, access the auto-generated SDK directly:
```typescript
const client = createClient(createConfig({ baseUrl: 'http://localhost:8888' }));
// Use sdk functions directly
const response = await sdk.recallMemories({
client,
path: { bank_id: 'my-agent' },
body: {
query: 'What does Alice do?',
budget: 'mid',
max_tokens: 4096,
},
});
```
## Error Handling
```typescript
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
try {
const response = await client.recall('unknown-agent', 'test');
} catch (error) {
console.error('Error:', error.message);
}
```
## Example: Full Workflow
```typescript
async function main() {
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
// Create a bank with personality
await client.createBank('demo', {
name: 'Demo Agent',
background: 'A helpful assistant for demos',
personality: {
openness: 0.8,
conscientiousness: 0.7,
extraversion: 0.6,
agreeableness: 0.8,
neuroticism: 0.2,
bias_strength: 0.5,
},
});
// Store some memories
await client.retain('demo', 'Alice works at Google');
await client.retain('demo', 'Bob is a data scientist at Google');
await client.retain('demo', 'Alice and Bob collaborate on ML projects');
// Search for memories
const searchResults = await client.recall('demo', 'Who works at Google?');
console.log('Search results:');
for (const r of searchResults.results) {
console.log(` - ${r.text}`);
}
// Generate a response
const answer = await client.reflect('demo', 'What do you know about the team?');
console.log('\nReflection:', answer.text);
}
main().catch(console.error);
```
---
## File: sdks/cli.md
# CLI Reference
The Hindsight CLI provides command-line access to memory operations and bank management.
## Installation
```bash
curl -fsSL https://raw.githubusercontent.com/vectorize-io/hindsight/refs/heads/main/hindsight-cli/install.sh | bash
```
## Configuration
Configure the API URL:
```bash
# Interactive configuration
hindsight configure
# Or set directly
hindsight configure --api-url http://localhost:8888
# Or use environment variable (highest priority)
export HINDSIGHT_API_URL=http://localhost:8888
```
## Core Commands
### Retain (Store Memory)
Store a single memory:
```bash
hindsight memory retain <bank_id> "Alice works at Google as a software engineer"
# With context
hindsight memory retain <bank_id> "Bob loves hiking" --context "hobby discussion"
# Queue for background processing
hindsight memory retain <bank_id> "Meeting notes" --async
```
### Retain Files
Bulk import from files:
```bash
# Single file
hindsight memory retain-files <bank_id> notes.txt
# Directory (recursive by default)
hindsight memory retain-files <bank_id> ./documents/
# With context
hindsight memory retain-files <bank_id> meeting-notes.txt --context "team meeting"
# Background processing
hindsight memory retain-files <bank_id> ./data/ --async
```
### Recall (Search)
Search memories using semantic similarity:
```bash
hindsight memory recall <bank_id> "What does Alice do?"
# With options
hindsight memory recall <bank_id> "hiking recommendations" \
--budget high \
--max-tokens 8192
# Filter by fact type
hindsight memory recall <bank_id> "query" --fact-type world,opinion
# Show trace information
hindsight memory recall <bank_id> "query" --trace
```
### Reflect (Generate Response)
Generate a response using memories and bank personality:
```bash
hindsight memory reflect <bank_id> "What do you know about Alice?"
# With additional context
hindsight memory reflect <bank_id> "Should I learn Python?" --context "career advice"
# Higher budget for complex questions
hindsight memory reflect <bank_id> "Summarize my week" --budget high
```
## Bank Management
### List Banks
```bash
hindsight bank list
```
### View Profile
```bash
hindsight bank profile <bank_id>
```
### View Statistics
```bash
hindsight bank stats <bank_id>
```
### Set Bank Name
```bash
hindsight bank name <bank_id> "My Assistant"
```
### Set Background
```bash
hindsight bank background <bank_id> "I am a helpful AI assistant interested in technology"
# Skip automatic personality inference
hindsight bank background <bank_id> "Background text" --no-update-personality
```
## Document Management
```bash
# List documents
hindsight document list <bank_id>
# Get document details
hindsight document get <bank_id> <document_id>
# Delete document and its memories
hindsight document delete <bank_id> <document_id>
```
## Entity Management
```bash
# List entities
hindsight entity list <bank_id>
# Get entity details
hindsight entity get <bank_id> <entity_id>
# Regenerate entity observations
hindsight entity regenerate <bank_id> <entity_id>
```
## Output Formats
```bash
# Pretty (default)
hindsight memory recall <bank_id> "query"
# JSON
hindsight memory recall <bank_id> "query" -o json
# YAML
hindsight memory recall <bank_id> "query" -o yaml
```
## Global Options
| Flag | Description |
|------|-------------|
| `-v, --verbose` | Show detailed output including request/response |
| `-o, --output <format>` | Output format: pretty, json, yaml |
| `--help` | Show help |
| `--version` | Show version |
## Interactive Explorer
Launch the TUI explorer for visual navigation:
```bash
hindsight explore
```
## Example Workflow
```bash
# Configure API URL
hindsight configure --api-url http://localhost:8888
# Store some memories
hindsight memory retain demo "Alice works at Google"
hindsight memory retain demo "Bob is a data scientist"
hindsight memory retain demo "Alice and Bob are colleagues"
# Search memories
hindsight memory recall demo "Who works with Alice?"
# Generate a response
hindsight memory reflect demo "What do you know about the team?"
# Check bank profile
hindsight bank profile demo
```
---
## File: sdks/mcp.md
# MCP Server
Model Context Protocol server for AI assistants like Claude Desktop.
## Setup
The MCP server is included in the Hindsight API. When running the API with MCP enabled, it exposes MCP tools at `/mcp/{bank_id}/sse`.
### Claude Desktop Configuration
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"hindsight": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8888/mcp/my-bank-id/sse"]
}
}
}
```
Replace `my-bank-id` with your memory bank ID.
## Available Tools
### retain
Store a memory:
```json
{
"name": "retain",
"arguments": {
"content": "User prefers Python for data analysis",
"context": "preferences"
}
}
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `content` | string | yes | Memory content to store |
| `context` | string | no | Category (default: 'general') |
### recall
Search memories:
```json
{
"name": "recall",
"arguments": {
"query": "What does the user do for work?"
}
}
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | yes | Natural language search query |
| `max_results` | integer | no | Max results (default: 10) |
## Usage Example
Once configured, Claude can use Hindsight naturally:
**User**: "Remember that I prefer morning meetings"
**Claude**: *Uses retain*
> "I've noted that you prefer morning meetings."
---
**User**: "What do you know about my preferences?"
**Claude**: *Uses recall*
> "Based on our conversations, you prefer morning meetings and like Python for data analysis."
---
## File: cookbook/index.md
# Cookbook
Practical patterns and recipes for building with Hindsight.
## Use Cases
### [Per-User Memory](/cookbook/per-user-memory)
The simplest pattern: give your agent persistent memory for each user. The agent remembers past conversations, preferences, and context across sessions.
**Use when:** Building chatbots, personal assistants, or any 1:1 user-to-agent interaction.
### [Support Agent with Shared Knowledge](/cookbook/support-agent-with-shared-knowledge)
Build a support agent that combines per-user memory with shared product documentation. Users get personalized support while you index docs only once.
**Use when:** Building multi-tenant support agents, RAG + memory applications, or any scenario needing user isolation with shared reference data.
---
## File: cookbook/per-user-memory.md
# Per-User Memory
The simplest pattern: give your agent persistent memory for each user. The agent remembers past conversations, user preferences, and context across sessions.
## The Problem
Without memory, every conversation starts from scratch:
```
Session 1: "I prefer dark mode and use Python"
Session 2: "What's my preferred language?" → Agent doesn't know
```
## The Solution: One Bank Per User
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ User A Bank │ │ User B Bank │ │ User C Bank │
│ │ │ │ │ │
│ - Conversations│ │ - Conversations│ │ - Conversations│
│ - Preferences │ │ - Preferences │ │ - Preferences │
│ - Context │ │ - Context │ │ - Context │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
100% isolated 100% isolated 100% isolated
```
Each user gets their own memory bank. Complete isolation, simple mental model.
## Implementation
### 1. Create a Bank When User Signs Up
```python
from hindsight import HindsightClient
client = HindsightClient()
def on_user_signup(user_id: str):
client.create_bank(
bank_id=f"user-{user_id}",
name=f"Memory for {user_id}"
)
```
### 2. Manage Conversation Sessions
Use `document_id` to group messages belonging to the same conversation. When you retain with the same `document_id`, Hindsight replaces the previous version (upsert behavior), keeping the memory up-to-date as the conversation evolves.
```python
class ConversationSession:
def __init__(self, user_id: str):
self.user_id = user_id
self.session_id = str(uuid.uuid4()) # Unique ID for this conversation
self.messages = []
def add_message(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
async def save(self, client: HindsightClient):
"""Save the entire conversation. Replaces previous version if session_id exists."""
await client.retain(
bank_id=f"user-{self.user_id}",
content=self.messages,
document_id=self.session_id # Same ID = upsert (replace old version)
)
```
### 3. Recall Context Before Responding
```python
async def get_context(user_id: str, query: str):
result = await client.recall(
bank_id=f"user-{user_id}",
query=query
)
return result.results
```
### 4. Complete Agent Loop
```python
async def handle_message(session: ConversationSession, user_message: str):
# 1. Add user message to session
session.add_message("user", user_message)
# 2. Recall relevant context from past conversations
context = await client.recall(
bank_id=f"user-{session.user_id}",
query=user_message
)
# 3. Build prompt with memory
prompt = f"""You are a helpful assistant with memory of past conversations.
## What you remember about this user
{format_results(context.results)}
## Current conversation
{format_messages(session.messages)}
"""
# 4. Generate response
response = await llm.complete(prompt)
# 5. Add assistant response to session
session.add_message("assistant", response)
# 6. Save the updated conversation (upserts based on session_id)
await session.save(client)
return response
```
### 5. Starting a New Conversation
```python
# Each new conversation gets a new session with a unique ID
session = ConversationSession(user_id="alice")
# Multiple exchanges in the same conversation
await handle_message(session, "Hi! I'm working on a Python project")
await handle_message(session, "Can you help me with async/await?")
# Start a new conversation later (new session_id)
new_session = ConversationSession(user_id="alice")
await handle_message(new_session, "Different topic today...")
```
## How Document ID Works
The `document_id` parameter is key to managing evolving conversations:
| Scenario | Behavior |
|----------|----------|
| First retain with `document_id="session_123"` | Creates new document |
| Retain again with same `document_id="session_123"` | **Replaces** previous version (upsert) |
| Retain with different `document_id="session_456"` | Creates separate document |
| Retain without `document_id` | Creates new document each time |
This upsert behavior means:
- You always retain the **full conversation** state
- Facts are re-extracted from the complete conversation
- No duplicate or stale facts from old versions
- Memory stays consistent as conversations evolve
## What Gets Remembered
Hindsight automatically extracts and connects:
- **Facts**: "User prefers Python", "User is building a CLI tool"
- **Entities**: People, projects, technologies mentioned
- **Relationships**: How entities relate to each other
- **Temporal context**: When things happened
You don't need to manually extract or structure this - just retain the conversations.
## When to Use This Pattern
**Good fit:**
- Chatbots and assistants
- Personal AI companions
- Any 1:1 user-to-agent interaction
**Consider adding shared knowledge if:**
- You have product docs or FAQs to reference
- Multiple users need access to the same information
- See [Support Agent with Shared Knowledge](./support-agent-with-shared-knowledge)
---
## File: cookbook/support-agent-with-shared-knowledge.md
# Support Agent with Shared Knowledge
This pattern shows how to build a support agent that combines **per-user memory** with **shared product knowledge** (RAG), giving users personalized support while leveraging a single source of truth for documentation.
## The Problem
You're building a support agent that needs to:
- Remember each user's history, preferences, and past issues
- Access shared product documentation
- Keep user data completely isolated from other users
A naive approach would index product docs into each user's memory bank, but this is expensive and wasteful (N copies for N users).
## The Solution: Multi-Bank Architecture
Create separate memory banks for different concerns:
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ User A Bank │ │ User B Bank │ │ Shared Docs │
│ │ │ │ │ Bank │
│ - Conversations│ │ - Conversations│ │ │
│ - Preferences │ │ - Preferences │ │ - Product docs │
│ - Past issues │ │ - Past issues │ │ - FAQs │
│ - Solutions │ │ - Solutions │ │ - Guides │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
└───────────────────────┴───────────────────────┘
Agent queries
multiple banks
```
**Key benefits:**
- Product docs indexed once, shared by all users
- User memory is 100% isolated
- Simple mental model, no complex filtering
## Implementation
### 1. Set Up Memory Banks
Create three types of banks:
```python
from hindsight import HindsightClient
client = HindsightClient()
# Shared knowledge bank (created once)
shared_bank = client.create_bank(
bank_id="product-docs",
name="Product Documentation"
)
# Per-user banks (created when user signs up)
def create_user_bank(user_id: str):
return client.create_bank(
bank_id=f"user-{user_id}",
name=f"Memory for {user_id}"
)
```
### 2. Index Product Documentation
Index your product docs into the shared bank (do this once, or on doc updates):
```python
# Index product documentation
client.retain(
bank_id="product-docs",
content=[
{
"role": "document",
"content": "# Pricing Tiers\n\nBasic: $10/mo...",
"metadata": {"source": "pricing.md"}
},
{
"role": "document",
"content": "# Getting Started\n\nTo set up...",
"metadata": {"source": "quickstart.md"}
}
]
)
```
### 3. Store User Conversations
After each support interaction, retain it in the user's bank:
```python
def save_conversation(user_id: str, messages: list):
client.retain(
bank_id=f"user-{user_id}",
content=messages # [{"role": "user", "content": "..."}, ...]
)
```
### 4. Query Multiple Banks at Support Time
When handling a user query, retrieve context from both banks:
```python
async def get_support_context(user_id: str, query: str):
# Get user's personal context
user_context = await client.recall(
bank_id=f"user-{user_id}",
query=query
)
# Get relevant product documentation
docs_context = await client.recall(
bank_id="product-docs",
query=query
)
return {
"user_history": user_context.results,
"documentation": docs_context.results
}
```
### 5. Build the Agent Prompt
Combine both contexts in your agent's prompt:
```python
def build_prompt(query: str, context: dict) -> str:
return f"""You are a helpful support agent.
## User's History
{format_results(context["user_history"])}
## Product Documentation
{format_results(context["documentation"])}
## Current Question
{query}
Use the user's history to personalize your response and the documentation
for accurate product information. If you find a solution, remember it for
future reference.
"""
```
## Promoting Learnings to Shared Knowledge
When the agent discovers a solution that's not in the docs, you can optionally promote it to a "learnings" bank:
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ User A Bank │ │ Shared Docs │ │ Learnings │
│ │ │ Bank │ │ Bank │
│ - Conversations│ │ │ │ │
│ - Preferences │ │ - Product docs │ │ - Verified │
│ - Past issues │ │ - FAQs │ │ solutions │
│ - Solutions │ │ - Guides │ │ - Workarounds │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
└───────────────────────┴───────────────────────┘
Agent queries
all three banks
```
```python
# Optional: Create a curated learnings bank
learnings_bank = client.create_bank(
bank_id="support-learnings",
name="Curated Support Learnings"
)
# After a successful resolution
def promote_learning(insight: str):
client.retain(
bank_id="support-learnings",
content=[{
"role": "system",
"content": insight,
"metadata": {"type": "verified_solution"}
}]
)
```
Then query three banks: user + docs + learnings.
## Complete Example
```python
from hindsight import HindsightClient
client = HindsightClient()
async def handle_support_request(user_id: str, query: str):
# 1. Recall from user's memory
user_recall = await client.recall(
bank_id=f"user-{user_id}",
query=query
)
# 2. Recall from shared docs
docs_recall = await client.recall(
bank_id="product-docs",
query=query
)
# 3. Recall from learnings (optional)
learnings_recall = await client.recall(
bank_id="support-learnings",
query=query
)
# 4. Build context for LLM
context = f"""
User History:
{format_results(user_recall.results)}
Product Docs:
{format_results(docs_recall.results)}
Known Solutions:
{format_results(learnings_recall.results)}
"""
# 5. Generate response with your LLM
response = await llm.complete(
system="You are a support agent...",
context=context,
query=query
)
# 6. Save the conversation to user's memory
await client.retain(
bank_id=f"user-{user_id}",
content=[
{"role": "user", "content": query},
{"role": "assistant", "content": response}
]
)
return response
```
## When to Use This Pattern
**Good fit:**
- Support agents with shared documentation
- Multi-tenant applications with shared reference data
- Any scenario needing user isolation + shared knowledge
**Consider alternatives if:**
- You need cross-user learning (users benefiting from other users' solutions)
- Entity relationships must span across users and docs
---
## File: api-reference/endpoints/add-bank-background.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Add/merge memory bank background"}
>
</Heading>
<MethodEndpoint
method={"post"}
path={"/v1/default/banks/{bank_id}/background"}
context={"endpoint"}
>
</MethodEndpoint>
Add new background information or merge with existing. LLM intelligently resolves conflicts, normalizes to first person, and optionally infers disposition traits.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={{"required":true,"content":{"application/json":{"schema":{"properties":{"content":{"type":"string","title":"Content","description":"New background information to add or merge"},"update_disposition":{"type":"boolean","title":"Update Disposition","description":"If true, infer disposition traits from the merged background (default: true)","default":true}},"type":"object","required":["content"],"title":"AddBackgroundRequest","description":"Request model for adding/merging background information.","example":{"content":"I was born in Texas","update_disposition":true}}}}}}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"background":{"type":"string","title":"Background"},"disposition":{"anyOf":[{"properties":{"skepticism":{"type":"integer","maximum":5,"minimum":1,"title":"Skepticism","description":"How skeptical vs trusting (1=trusting, 5=skeptical)"},"literalism":{"type":"integer","maximum":5,"minimum":1,"title":"Literalism","description":"How literally to interpret information (1=flexible, 5=literal)"},"empathy":{"type":"integer","maximum":5,"minimum":1,"title":"Empathy","description":"How much to consider emotional context (1=detached, 5=empathetic)"}},"type":"object","required":["skepticism","literalism","empathy"],"title":"DispositionTraits","description":"Disposition traits that influence how memories are formed and interpreted.","example":{"empathy":3,"literalism":3,"skepticism":3}},{"type":"null"}]}},"type":"object","required":["background"],"title":"BackgroundResponse","description":"Response model for background update.","example":{"background":"I was born in Texas. I am a software engineer with 10 years of experience.","disposition":{"empathy":3,"literalism":3,"skepticism":3}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/cancel-operation.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Cancel a pending async operation"}
>
</Heading>
<MethodEndpoint
method={"delete"}
path={"/v1/default/banks/{bank_id}/operations/{operation_id}"}
context={"endpoint"}
>
</MethodEndpoint>
Cancel a pending async operation by removing it from the queue
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"operation_id","in":"path","required":true,"schema":{"type":"string","title":"Operation Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/clear-bank-memories.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Clear memory bank memories"}
>
</Heading>
<MethodEndpoint
method={"delete"}
path={"/v1/default/banks/{bank_id}/memories"}
context={"endpoint"}
>
</MethodEndpoint>
Delete memory units for a memory bank. Optionally filter by type (world, experience, opinion) to delete only specific types. This is a destructive operation that cannot be undone. The bank profile (disposition and background) will be preserved.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional fact type filter (world, experience, opinion)","title":"Type"},"description":"Optional fact type filter (world, experience, opinion)"}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"success":{"type":"boolean","title":"Success"}},"type":"object","required":["success"],"title":"DeleteResponse","description":"Response model for delete operations.","example":{"success":true}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/create-or-update-bank.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Create or update memory bank"}
>
</Heading>
<MethodEndpoint
method={"put"}
path={"/v1/default/banks/{bank_id}"}
context={"endpoint"}
>
</MethodEndpoint>
Create a new agent or update existing agent with disposition and background. Auto-fills missing fields with defaults.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={{"required":true,"content":{"application/json":{"schema":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"disposition":{"anyOf":[{"properties":{"skepticism":{"type":"integer","maximum":5,"minimum":1,"title":"Skepticism","description":"How skeptical vs trusting (1=trusting, 5=skeptical)"},"literalism":{"type":"integer","maximum":5,"minimum":1,"title":"Literalism","description":"How literally to interpret information (1=flexible, 5=literal)"},"empathy":{"type":"integer","maximum":5,"minimum":1,"title":"Empathy","description":"How much to consider emotional context (1=detached, 5=empathetic)"}},"type":"object","required":["skepticism","literalism","empathy"],"title":"DispositionTraits","description":"Disposition traits that influence how memories are formed and interpreted.","example":{"empathy":3,"literalism":3,"skepticism":3}},{"type":"null"}]},"background":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Background"}},"type":"object","title":"CreateBankRequest","description":"Request model for creating/updating a bank.","example":{"background":"I am a creative software engineer with 10 years of experience","disposition":{"empathy":3,"literalism":3,"skepticism":3},"name":"Alice"}}}}}}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"bank_id":{"type":"string","title":"Bank Id"},"name":{"type":"string","title":"Name"},"disposition":{"properties":{"skepticism":{"type":"integer","maximum":5,"minimum":1,"title":"Skepticism","description":"How skeptical vs trusting (1=trusting, 5=skeptical)"},"literalism":{"type":"integer","maximum":5,"minimum":1,"title":"Literalism","description":"How literally to interpret information (1=flexible, 5=literal)"},"empathy":{"type":"integer","maximum":5,"minimum":1,"title":"Empathy","description":"How much to consider emotional context (1=detached, 5=empathetic)"}},"type":"object","required":["skepticism","literalism","empathy"],"title":"DispositionTraits","description":"Disposition traits that influence how memories are formed and interpreted.","example":{"empathy":3,"literalism":3,"skepticism":3}},"background":{"type":"string","title":"Background"}},"type":"object","required":["bank_id","name","disposition","background"],"title":"BankProfileResponse","description":"Response model for bank profile.","example":{"background":"I am a software engineer with 10 years of experience in startups","bank_id":"user123","disposition":{"empathy":3,"literalism":3,"skepticism":3},"name":"Alice"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/delete-document.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Delete a document"}
>
</Heading>
<MethodEndpoint
method={"delete"}
path={"/v1/default/banks/{bank_id}/documents/{document_id}"}
context={"endpoint"}
>
</MethodEndpoint>
Delete a document and all its associated memory units and links.
This will cascade delete:
- The document itself
- All memory units extracted from this document
- All links (temporal, semantic, entity) associated with those memory units
This operation cannot be undone.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/get-agent-stats.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Get statistics for memory bank"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/stats"}
context={"endpoint"}
>
</MethodEndpoint>
Get statistics about nodes and links for a specific agent
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/get-bank-profile.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Get memory bank profile"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/profile"}
context={"endpoint"}
>
</MethodEndpoint>
Get disposition traits and background for a memory bank. Auto-creates agent with defaults if not exists.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"bank_id":{"type":"string","title":"Bank Id"},"name":{"type":"string","title":"Name"},"disposition":{"properties":{"skepticism":{"type":"integer","maximum":5,"minimum":1,"title":"Skepticism","description":"How skeptical vs trusting (1=trusting, 5=skeptical)"},"literalism":{"type":"integer","maximum":5,"minimum":1,"title":"Literalism","description":"How literally to interpret information (1=flexible, 5=literal)"},"empathy":{"type":"integer","maximum":5,"minimum":1,"title":"Empathy","description":"How much to consider emotional context (1=detached, 5=empathetic)"}},"type":"object","required":["skepticism","literalism","empathy"],"title":"DispositionTraits","description":"Disposition traits that influence how memories are formed and interpreted.","example":{"empathy":3,"literalism":3,"skepticism":3}},"background":{"type":"string","title":"Background"}},"type":"object","required":["bank_id","name","disposition","background"],"title":"BankProfileResponse","description":"Response model for bank profile.","example":{"background":"I am a software engineer with 10 years of experience in startups","bank_id":"user123","disposition":{"empathy":3,"literalism":3,"skepticism":3},"name":"Alice"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/get-chunk.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Get chunk details"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/chunks/{chunk_id}"}
context={"endpoint"}
>
</MethodEndpoint>
Get a specific chunk by its ID
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"chunk_id","in":"path","required":true,"schema":{"type":"string","title":"Chunk Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"chunk_id":{"type":"string","title":"Chunk Id"},"document_id":{"type":"string","title":"Document Id"},"bank_id":{"type":"string","title":"Bank Id"},"chunk_index":{"type":"integer","title":"Chunk Index"},"chunk_text":{"type":"string","title":"Chunk Text"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["chunk_id","document_id","bank_id","chunk_index","chunk_text","created_at"],"title":"ChunkResponse","description":"Response model for get chunk endpoint.","example":{"bank_id":"user123","chunk_id":"user123_session_1_0","chunk_index":0,"chunk_text":"This is the first chunk of the document...","created_at":"2024-01-15T10:30:00Z","document_id":"session_1"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/get-document.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Get document details"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/documents/{document_id}"}
context={"endpoint"}
>
</MethodEndpoint>
Get a specific document including its original text
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"bank_id":{"type":"string","title":"Bank Id"},"original_text":{"type":"string","title":"Original Text"},"content_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Hash"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"},"memory_unit_count":{"type":"integer","title":"Memory Unit Count"}},"type":"object","required":["id","bank_id","original_text","content_hash","created_at","updated_at","memory_unit_count"],"title":"DocumentResponse","description":"Response model for get document endpoint.","example":{"bank_id":"user123","content_hash":"abc123","created_at":"2024-01-15T10:30:00Z","id":"session_1","memory_unit_count":15,"original_text":"Full document text here...","updated_at":"2024-01-15T10:30:00Z"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/get-entity.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Get entity details"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/entities/{entity_id}"}
context={"endpoint"}
>
</MethodEndpoint>
Get detailed information about an entity including observations (mental model).
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"canonical_name":{"type":"string","title":"Canonical Name"},"mention_count":{"type":"integer","title":"Mention Count"},"first_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Seen"},"last_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Seen"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"observations":{"items":{"properties":{"text":{"type":"string","title":"Text"},"mentioned_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mentioned At"}},"type":"object","required":["text"],"title":"EntityObservationResponse","description":"An observation about an entity."},"type":"array","title":"Observations"}},"type":"object","required":["id","canonical_name","mention_count","observations"],"title":"EntityDetailResponse","description":"Response model for entity detail endpoint.","example":{"canonical_name":"John","first_seen":"2024-01-15T10:30:00Z","id":"123e4567-e89b-12d3-a456-426614174000","last_seen":"2024-02-01T14:00:00Z","mention_count":15,"observations":[{"mentioned_at":"2024-01-15T10:30:00Z","text":"John works at Google"}]}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/get-graph.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Get memory graph data"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/graph"}
context={"endpoint"}
>
</MethodEndpoint>
Retrieve graph data for visualization, optionally filtered by type (world/experience/opinion). Limited to 1000 most recent items.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"nodes":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Nodes"},"edges":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Edges"},"table_rows":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Table Rows"},"total_units":{"type":"integer","title":"Total Units"}},"type":"object","required":["nodes","edges","table_rows","total_units"],"title":"GraphDataResponse","description":"Response model for graph data endpoint.","example":{"edges":[{"from":"1","to":"2","type":"semantic","weight":0.8}],"nodes":[{"id":"1","label":"Alice works at Google","type":"world"},{"id":"2","label":"Bob went hiking","type":"world"}],"table_rows":[{"context":"Work info","date":"2024-01-15 10:30","entities":"Alice (PERSON), Google (ORGANIZATION)","id":"abc12345...","text":"Alice works at Google"}],"total_units":2}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/health-endpoint-health-get.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Health check endpoint"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/health"}
context={"endpoint"}
>
</MethodEndpoint>
Checks the health of the API and database connection
<ParamsDetails
parameters={undefined}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/hindsight-http-api.info.mdx
<span
className={"theme-doc-version-badge badge badge--secondary"}
children={"Version: 1.0.0"}
>
</span>
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Hindsight HTTP API"}
>
</Heading>
HTTP API for Hindsight
<div
style={{"display":"flex","flexDirection":"column","marginBottom":"var(--ifm-paragraph-margin-bottom)"}}
>
<h3
style={{"marginBottom":"0.25rem"}}
>
Contact
</h3><span>
Memory System:
</span>
</div><div
style={{"marginBottom":"var(--ifm-paragraph-margin-bottom)"}}
>
<h3
style={{"marginBottom":"0.25rem"}}
>
License
</h3><a
href={"https://www.apache.org/licenses/LICENSE-2.0.html"}
>
Apache 2.0
</a>
</div>
---
## File: api-reference/endpoints/list-banks.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"List all memory banks"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks"}
context={"endpoint"}
>
</MethodEndpoint>
Get a list of all agents with their profiles
<ParamsDetails
parameters={undefined}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"banks":{"items":{"properties":{"bank_id":{"type":"string","title":"Bank Id"},"name":{"type":"string","title":"Name"},"disposition":{"properties":{"skepticism":{"type":"integer","maximum":5,"minimum":1,"title":"Skepticism","description":"How skeptical vs trusting (1=trusting, 5=skeptical)"},"literalism":{"type":"integer","maximum":5,"minimum":1,"title":"Literalism","description":"How literally to interpret information (1=flexible, 5=literal)"},"empathy":{"type":"integer","maximum":5,"minimum":1,"title":"Empathy","description":"How much to consider emotional context (1=detached, 5=empathetic)"}},"type":"object","required":["skepticism","literalism","empathy"],"title":"DispositionTraits","description":"Disposition traits that influence how memories are formed and interpreted.","example":{"empathy":3,"literalism":3,"skepticism":3}},"background":{"type":"string","title":"Background"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["bank_id","name","disposition","background"],"title":"BankListItem","description":"Bank list item with profile summary."},"type":"array","title":"Banks"}},"type":"object","required":["banks"],"title":"BankListResponse","description":"Response model for listing all banks.","example":{"banks":[{"background":"I am a software engineer","bank_id":"user123","created_at":"2024-01-15T10:30:00Z","disposition":{"empathy":3,"literalism":3,"skepticism":3},"name":"Alice","updated_at":"2024-01-16T14:20:00Z"}]}}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/list-documents.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"List documents"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/documents"}
context={"endpoint"}
>
</MethodEndpoint>
List documents with pagination and optional search. Documents are the source content from which memory units are extracted.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["items","total","limit","offset"],"title":"ListDocumentsResponse","description":"Response model for list documents endpoint.","example":{"items":[{"bank_id":"user123","content_hash":"abc123","created_at":"2024-01-15T10:30:00Z","id":"session_1","memory_unit_count":15,"text_length":5420,"updated_at":"2024-01-15T10:30:00Z"}],"limit":100,"offset":0,"total":50}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/list-entities.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"List entities"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/entities"}
context={"endpoint"}
>
</MethodEndpoint>
List all entities (people, organizations, etc.) known by the bank, ordered by mention count.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum number of entities to return","default":100,"title":"Limit"},"description":"Maximum number of entities to return"}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"items":{"items":{"properties":{"id":{"type":"string","title":"Id"},"canonical_name":{"type":"string","title":"Canonical Name"},"mention_count":{"type":"integer","title":"Mention Count"},"first_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Seen"},"last_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Seen"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["id","canonical_name","mention_count"],"title":"EntityListItem","description":"Entity list item with summary.","example":{"canonical_name":"John","first_seen":"2024-01-15T10:30:00Z","id":"123e4567-e89b-12d3-a456-426614174000","last_seen":"2024-02-01T14:00:00Z","mention_count":15}},"type":"array","title":"Items"}},"type":"object","required":["items"],"title":"EntityListResponse","description":"Response model for entity list endpoint.","example":{"items":[{"canonical_name":"John","first_seen":"2024-01-15T10:30:00Z","id":"123e4567-e89b-12d3-a456-426614174000","last_seen":"2024-02-01T14:00:00Z","mention_count":15}]}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/list-memories.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"List memory units"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/memories/list"}
context={"endpoint"}
>
</MethodEndpoint>
List memory units with pagination and optional full-text search. Supports filtering by type. Results are sorted by most recent first (mentioned_at DESC, then created_at DESC).
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["items","total","limit","offset"],"title":"ListMemoryUnitsResponse","description":"Response model for list memory units endpoint.","example":{"items":[{"context":"Work conversation","date":"2024-01-15T10:30:00Z","entities":"Alice (PERSON), Google (ORGANIZATION)","id":"550e8400-e29b-41d4-a716-446655440000","text":"Alice works at Google on the AI team","type":"world"}],"limit":100,"offset":0,"total":150}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/list-operations.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"List async operations"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/v1/default/banks/{bank_id}/operations"}
context={"endpoint"}
>
</MethodEndpoint>
Get a list of all async operations (pending and failed) for a specific agent, including error messages for failed operations
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/metrics-endpoint-metrics-get.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Prometheus metrics endpoint"}
>
</Heading>
<MethodEndpoint
method={"get"}
path={"/metrics"}
context={"endpoint"}
>
</MethodEndpoint>
Exports metrics in Prometheus format for scraping
<ParamsDetails
parameters={undefined}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/recall-memories.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Recall memory"}
>
</Heading>
<MethodEndpoint
method={"post"}
path={"/v1/default/banks/{bank_id}/memories/recall"}
context={"endpoint"}
>
</MethodEndpoint>
Recall memory using semantic similarity and spreading activation.
The type parameter is optional and must be one of:
- 'world': General knowledge about people, places, events, and things that happen
- 'experience': Memories about experience, conversations, actions taken, and tasks performed
- 'opinion': The bank's formed beliefs, perspectives, and viewpoints
Set include_entities=true to get entity observations alongside recall results.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={{"required":true,"content":{"application/json":{"schema":{"properties":{"query":{"type":"string","title":"Query"},"types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Types","description":"List of fact types to recall (defaults to all if not specified)"},"budget":{"default":"mid","type":"string","enum":["low","mid","high"],"title":"Budget","description":"Budget levels for recall/reflect operations."},"max_tokens":{"type":"integer","title":"Max Tokens","default":4096},"trace":{"type":"boolean","title":"Trace","default":false},"query_timestamp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query Timestamp","description":"ISO format date string (e.g., '2023-05-30T23:40:00')"},"include":{"description":"Options for including additional data (entities are included by default)","properties":{"entities":{"anyOf":[{"properties":{"max_tokens":{"type":"integer","title":"Max Tokens","description":"Maximum tokens for entity observations","default":500}},"type":"object","title":"EntityIncludeOptions","description":"Options for including entity observations in recall results."},{"type":"null"}],"description":"Include entity observations. Set to null to disable entity inclusion.","default":{"max_tokens":500}},"chunks":{"anyOf":[{"properties":{"max_tokens":{"type":"integer","title":"Max Tokens","description":"Maximum tokens for chunks (chunks may be truncated)","default":8192}},"type":"object","title":"ChunkIncludeOptions","description":"Options for including chunks in recall results."},{"type":"null"}],"description":"Include raw chunks. Set to {} to enable, null to disable (default: disabled)."}},"type":"object","title":"IncludeOptions"}},"type":"object","required":["query"],"title":"RecallRequest","description":"Request model for recall endpoint.","example":{"budget":"mid","include":{"entities":{"max_tokens":500}},"max_tokens":4096,"query":"What did Alice say about machine learning?","query_timestamp":"2023-05-30T23:40:00","trace":true,"types":["world","experience"]}}}}}}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"results":{"items":{"properties":{"id":{"type":"string","title":"Id"},"text":{"type":"string","title":"Text"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"entities":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Entities"},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context"},"occurred_start":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Occurred Start"},"occurred_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Occurred End"},"mentioned_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mentioned At"},"document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Id"},"metadata":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Metadata"},"chunk_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chunk Id"}},"type":"object","required":["id","text"],"title":"RecallResult","description":"Single recall result item.","example":{"chunk_id":"456e7890-e12b-34d5-a678-901234567890","context":"work info","document_id":"session_abc123","entities":["Alice","Google"],"id":"123e4567-e89b-12d3-a456-426614174000","mentioned_at":"2024-01-15T10:30:00Z","metadata":{"source":"slack"},"occurred_end":"2024-01-15T10:30:00Z","occurred_start":"2024-01-15T10:30:00Z","text":"Alice works at Google on the AI team","type":"world"}},"type":"array","title":"Results"},"trace":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Trace"},"entities":{"anyOf":[{"additionalProperties":{"properties":{"entity_id":{"type":"string","title":"Entity Id"},"canonical_name":{"type":"string","title":"Canonical Name"},"observations":{"items":{"properties":{"text":{"type":"string","title":"Text"},"mentioned_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mentioned At"}},"type":"object","required":["text"],"title":"EntityObservationResponse","description":"An observation about an entity."},"type":"array","title":"Observations"}},"type":"object","required":["entity_id","canonical_name","observations"],"title":"EntityStateResponse","description":"Current mental model of an entity."},"type":"object"},{"type":"null"}],"title":"Entities","description":"Entity states for entities mentioned in results"},"chunks":{"anyOf":[{"additionalProperties":{"properties":{"id":{"type":"string","title":"Id"},"text":{"type":"string","title":"Text"},"chunk_index":{"type":"integer","title":"Chunk Index"},"truncated":{"type":"boolean","title":"Truncated","description":"Whether the chunk text was truncated due to token limits","default":false}},"type":"object","required":["id","text","chunk_index"],"title":"ChunkData","description":"Chunk data for a single chunk."},"type":"object"},{"type":"null"}],"title":"Chunks","description":"Chunks for facts, keyed by chunk_id"}},"type":"object","required":["results"],"title":"RecallResponse","description":"Response model for recall endpoints.","example":{"chunks":{"456e7890-e12b-34d5-a678-901234567890":{"chunk_index":0,"id":"456e7890-e12b-34d5-a678-901234567890","text":"Alice works at Google on the AI team. She's been there for 3 years..."}},"entities":{"Alice":{"canonical_name":"Alice","entity_id":"123e4567-e89b-12d3-a456-426614174001","observations":[{"mentioned_at":"2024-01-15T10:30:00Z","text":"Alice works at Google on the AI team"}]}},"results":[{"chunk_id":"456e7890-e12b-34d5-a678-901234567890","context":"work info","entities":["Alice","Google"],"id":"123e4567-e89b-12d3-a456-426614174000","occurred_end":"2024-01-15T10:30:00Z","occurred_start":"2024-01-15T10:30:00Z","text":"Alice works at Google on the AI team","type":"world"}],"trace":{"num_results":1,"query":"What did Alice say about machine learning?","time_seconds":0.123}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/reflect.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Reflect and generate answer"}
>
</Heading>
<MethodEndpoint
method={"post"}
path={"/v1/default/banks/{bank_id}/reflect"}
context={"endpoint"}
>
</MethodEndpoint>
Reflect and formulate an answer using bank identity, world facts, and opinions.
This endpoint:
1. Retrieves experience (conversations and events)
2. Retrieves world facts relevant to the query
3. Retrieves existing opinions (bank's perspectives)
4. Uses LLM to formulate a contextual answer
5. Extracts and stores any new opinions formed
6. Returns plain text answer, the facts used, and new opinions
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={{"required":true,"content":{"application/json":{"schema":{"properties":{"query":{"type":"string","title":"Query"},"budget":{"default":"low","type":"string","enum":["low","mid","high"],"title":"Budget","description":"Budget levels for recall/reflect operations."},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context"},"include":{"description":"Options for including additional data (disabled by default)","properties":{"facts":{"anyOf":[{"properties":{},"type":"object","title":"FactsIncludeOptions","description":"Options for including facts (based_on) in reflect results."},{"type":"null"}],"description":"Include facts that the answer is based on. Set to {} to enable, null to disable (default: disabled)."}},"type":"object","title":"ReflectIncludeOptions"}},"type":"object","required":["query"],"title":"ReflectRequest","description":"Request model for reflect endpoint.","example":{"budget":"low","context":"This is for a research paper on AI ethics","include":{"facts":{}},"query":"What do you think about artificial intelligence?"}}}}}}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"text":{"type":"string","title":"Text"},"based_on":{"items":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"text":{"type":"string","title":"Text"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context"},"occurred_start":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Occurred Start"},"occurred_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Occurred End"}},"type":"object","required":["text"],"title":"ReflectFact","description":"A fact used in think response.","example":{"context":"healthcare discussion","id":"123e4567-e89b-12d3-a456-426614174000","occurred_end":"2024-01-15T10:30:00Z","occurred_start":"2024-01-15T10:30:00Z","text":"AI is used in healthcare","type":"world"}},"type":"array","title":"Based On","default":[]}},"type":"object","required":["text"],"title":"ReflectResponse","description":"Response model for think endpoint.","example":{"based_on":[{"id":"123","text":"AI is used in healthcare","type":"world"},{"id":"456","text":"I discussed AI applications last week","type":"experience"}],"text":"Based on my understanding, AI is a transformative technology..."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/regenerate-entity-observations.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Regenerate entity observations"}
>
</Heading>
<MethodEndpoint
method={"post"}
path={"/v1/default/banks/{bank_id}/entities/{entity_id}/regenerate"}
context={"endpoint"}
>
</MethodEndpoint>
Regenerate observations for an entity based on all facts mentioning it.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={undefined}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"canonical_name":{"type":"string","title":"Canonical Name"},"mention_count":{"type":"integer","title":"Mention Count"},"first_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Seen"},"last_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Seen"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"observations":{"items":{"properties":{"text":{"type":"string","title":"Text"},"mentioned_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mentioned At"}},"type":"object","required":["text"],"title":"EntityObservationResponse","description":"An observation about an entity."},"type":"array","title":"Observations"}},"type":"object","required":["id","canonical_name","mention_count","observations"],"title":"EntityDetailResponse","description":"Response model for entity detail endpoint.","example":{"canonical_name":"John","first_seen":"2024-01-15T10:30:00Z","id":"123e4567-e89b-12d3-a456-426614174000","last_seen":"2024-02-01T14:00:00Z","mention_count":15,"observations":[{"mentioned_at":"2024-01-15T10:30:00Z","text":"John works at Google"}]}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/retain-memories.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Retain memories"}
>
</Heading>
<MethodEndpoint
method={"post"}
path={"/v1/default/banks/{bank_id}/memories"}
context={"endpoint"}
>
</MethodEndpoint>
Retain memory items with automatic fact extraction.
This is the main endpoint for storing memories. It supports both synchronous and asynchronous processing
via the async parameter.
Features:
- Efficient batch processing
- Automatic fact extraction from natural language
- Entity recognition and linking
- Document tracking with automatic upsert (when document_id is provided on items)
- Temporal and semantic linking
- Optional asynchronous processing
The system automatically:
1. Extracts semantic facts from the content
2. Generates embeddings
3. Deduplicates similar facts
4. Creates temporal, semantic, and entity links
5. Tracks document metadata
When async=true:
- Returns immediately after queuing the task
- Processing happens in the background
- Use the operations endpoint to monitor progress
When async=false (default):
- Waits for processing to complete
- Returns after all memories are stored
Note: If a memory item has a document_id that already exists, the old document and its memory units will be deleted before creating new ones (upsert behavior). Items with the same document_id are grouped together for efficient processing.
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={{"required":true,"content":{"application/json":{"schema":{"properties":{"items":{"items":{"properties":{"content":{"type":"string","title":"Content"},"timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp"},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context"},"metadata":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Metadata"},"document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Id","description":"Optional document ID for this memory item."}},"type":"object","required":["content"],"title":"MemoryItem","description":"Single memory item for retain.","example":{"content":"Alice mentioned she's working on a new ML model","context":"team meeting","document_id":"meeting_notes_2024_01_15","metadata":{"channel":"engineering","source":"slack"},"timestamp":"2024-01-15T10:30:00Z"}},"type":"array","title":"Items"},"async":{"type":"boolean","title":"Async","description":"If true, process asynchronously in background. If false, wait for completion (default: false)","default":false}},"type":"object","required":["items"],"title":"RetainRequest","description":"Request model for retain endpoint.","example":{"async":false,"items":[{"content":"Alice works at Google","context":"work","document_id":"conversation_123"},{"content":"Bob went hiking yesterday","document_id":"conversation_123","timestamp":"2024-01-15T10:00:00Z"}]}}}}}}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"success":{"type":"boolean","title":"Success"},"bank_id":{"type":"string","title":"Bank Id"},"items_count":{"type":"integer","title":"Items Count"},"async":{"type":"boolean","title":"Async","description":"Whether the operation was processed asynchronously"}},"type":"object","required":["success","bank_id","items_count","async"],"title":"RetainResponse","description":"Response model for retain endpoint.","example":{"async":false,"bank_id":"user123","items_count":2,"success":true}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/endpoints/update-bank-disposition.api.mdx
<Heading
as={"h1"}
className={"openapi__heading"}
children={"Update memory bank disposition"}
>
</Heading>
<MethodEndpoint
method={"put"}
path={"/v1/default/banks/{bank_id}/profile"}
context={"endpoint"}
>
</MethodEndpoint>
Update bank's disposition traits (skepticism, literalism, empathy)
<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>
<ParamsDetails
parameters={[{"name":"bank_id","in":"path","required":true,"schema":{"type":"string","title":"Bank Id"}}]}
>
</ParamsDetails>
<RequestSchema
title={"Body"}
body={{"required":true,"content":{"application/json":{"schema":{"properties":{"disposition":{"properties":{"skepticism":{"type":"integer","maximum":5,"minimum":1,"title":"Skepticism","description":"How skeptical vs trusting (1=trusting, 5=skeptical)"},"literalism":{"type":"integer","maximum":5,"minimum":1,"title":"Literalism","description":"How literally to interpret information (1=flexible, 5=literal)"},"empathy":{"type":"integer","maximum":5,"minimum":1,"title":"Empathy","description":"How much to consider emotional context (1=detached, 5=empathetic)"}},"type":"object","required":["skepticism","literalism","empathy"],"title":"DispositionTraits","description":"Disposition traits that influence how memories are formed and interpreted.","example":{"empathy":3,"literalism":3,"skepticism":3}}},"type":"object","required":["disposition"],"title":"UpdateDispositionRequest","description":"Request model for updating disposition traits."}}}}}
>
</RequestSchema>
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"bank_id":{"type":"string","title":"Bank Id"},"name":{"type":"string","title":"Name"},"disposition":{"properties":{"skepticism":{"type":"integer","maximum":5,"minimum":1,"title":"Skepticism","description":"How skeptical vs trusting (1=trusting, 5=skeptical)"},"literalism":{"type":"integer","maximum":5,"minimum":1,"title":"Literalism","description":"How literally to interpret information (1=flexible, 5=literal)"},"empathy":{"type":"integer","maximum":5,"minimum":1,"title":"Empathy","description":"How much to consider emotional context (1=detached, 5=empathetic)"}},"type":"object","required":["skepticism","literalism","empathy"],"title":"DispositionTraits","description":"Disposition traits that influence how memories are formed and interpreted.","example":{"empathy":3,"literalism":3,"skepticism":3}},"background":{"type":"string","title":"Background"}},"type":"object","required":["bank_id","name","disposition","background"],"title":"BankProfileResponse","description":"Response model for bank profile.","example":{"background":"I am a software engineer with 10 years of experience in startups","bank_id":"user123","disposition":{"empathy":3,"literalism":3,"skepticism":3},"name":"Alice"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>
</StatusCodes>
---
## File: api-reference/index.md
# API Reference
Complete reference for Hindsight's HTTP and MCP APIs.
## HTTP API
The HTTP API reference is automatically generated from our OpenAPI specification. Browse the endpoints in the sidebar to see request/response details, parameters, and examples.
**Base URL:** `http://localhost:8888`
| Category | Endpoints |
|----------|-----------|
| **Memory Operations** | Store, search, list, delete memories |
| **Reasoning** | Think and generate personality-aware responses |
| **Memory bank Management** | Create, update, list memory banks and profiles |
| **Documents** | Manage document groupings |
| **Visualization** | Get entity graph data |
## MCP API
The MCP (Model Context Protocol) API exposes Hindsight tools for AI assistants like Claude Desktop.
| Tool | Description |
|------|-------------|
| `hindsight_search` | Search memories |
| `hindsight_think` | Generate personality-aware response |
| `hindsight_store` | Store new memory |
| `hindsight_agents` | List available memory banks |
[MCP Tools Reference →](/api-reference/mcp)
## OpenAPI / Swagger
Interactive API documentation available when the server is running:
- **Swagger UI:** [http://localhost:8888/docs](http://localhost:8888/docs)
- **OpenAPI JSON:** [http://localhost:8888/openapi.json](http://localhost:8888/openapi.json)
---
## File: api-reference/mcp.md
# MCP API
Model Context Protocol (MCP) tools exposed by the Hindsight MCP server.
## Endpoint
```
/mcp/{bank_id}/sse
```
The `bank_id` is extracted from the URL path and used for all tool operations. The MCP server uses Server-Sent Events (SSE) transport.
## Available Tools
### retain
Store a new memory.
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `content` | string | yes | Memory content to store |
| `context` | string | no | Category for the memory (default: 'general') |
**Example:**
```json
{
"name": "retain",
"arguments": {
"content": "User prefers Python for data analysis",
"context": "preferences"
}
}
```
**Response:**
```
Memory stored successfully
```
---
### recall
Search memories.
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | yes | Natural language search query |
| `max_results` | integer | no | Maximum results to return (default: 10) |
**Example:**
```json
{
"name": "recall",
"arguments": {
"query": "What does the user do for work?"
}
}
```
**Response:**
```json
{
"results": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"text": "User works at Google as a software engineer",
"type": "world",
"context": "work",
"event_date": null
}
]
}
```
---
## Usage Guidelines
**When to use `retain`:**
- User shares personal facts, preferences, or interests
- Important events or milestones are mentioned
- Decisions, opinions, or goals are stated
**When to use `recall`:**
- Start of conversation to get user context
- Before making recommendations
- To provide continuity across conversations
---
## File: changelog/index.md
# Changelog
Coming soon.
---
## File: developer/api/opinions.md
# Opinions
How memory banks form, store, and evolve beliefs.
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
:::
## What Are Opinions?
Opinions are beliefs formed by the memory bank based on evidence and personality. Unlike world facts (objective information received) or experience (conversations and events), opinions are **judgments** with confidence scores.
| Type | Example | Confidence |
|------|---------|------------|
| World Fact | "Python was created in 1991" | — |
| Experience | "I recommended Python to Bob" | — |
| Opinion | "Python is the best language for data science" | 0.85 |
## How Opinions Form
Opinions are created during `think` operations when the memory bank:
1. Retrieves relevant facts
2. Applies personality traits
3. Forms a judgment
4. Assigns a confidence score
```mermaid
graph LR
F[Facts] --> P[Personality Filter]
P --> J[Judgment]
J --> O[Opinion + Confidence]
O --> S[(Store)]
```
<Tabs>
<TabItem value="python" label="Python">
```python
# Ask a question that might form an opinion
answer = client.think(
agent_id="my-agent",
query="What do you think about functional programming?"
)
# Check if new opinions were formed
for opinion in answer["new_opinions"]:
print(f"New opinion: {opinion['text']}")
print(f"Confidence: {opinion['confidence']}")
```
</TabItem>
</Tabs>
## Searching Opinions
<Tabs>
<TabItem value="python" label="Python">
```python
# Search only opinions
opinions = client.search_memories(
agent_id="my-agent",
query="programming languages",
fact_type=["opinion"]
)
for op in opinions:
print(f"{op['text']} (confidence: {op['confidence_score']:.2f})")
```
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight memory search my-agent "programming" --fact-type opinion
```
</TabItem>
</Tabs>
## Opinion Evolution
Opinions change as new evidence arrives:
| Evidence Type | Effect |
|---------------|--------|
| **Reinforcing** | Confidence increases (+0.1) |
| **Weakening** | Confidence decreases (-0.15) |
| **Contradicting** | Opinion revised, confidence reset |
**Example evolution:**
```
t=0: "Python is best for data science" (0.70)
↓ New evidence: Python dominates ML libraries
t=1: "Python is best for data science" (0.85)
↓ New evidence: Julia is 10x faster for numerical computing
t=2: "Python is best for data science, though Julia is faster" (0.75)
↓ New evidence: Most teams still use Python
t=3: "Python is best for data science" (0.82)
```
## Personality Influence
Different personalities form different opinions from the same facts:
<Tabs>
<TabItem value="python" label="Python">
```python
# Create two memory banks with different personalities
client.create_agent(
agent_id="open-minded",
personality={"openness": 0.9, "conscientiousness": 0.3, "bias_strength": 0.7}
)
client.create_agent(
agent_id="conservative",
personality={"openness": 0.2, "conscientiousness": 0.9, "bias_strength": 0.7}
)
# Store the same facts to both
facts = [
"Rust has better memory safety than C++",
"C++ has a larger ecosystem and more libraries",
"Rust compile times are longer than C++"
]
for fact in facts:
client.store(agent_id="open-minded", content=fact)
client.store(agent_id="conservative", content=fact)
# Ask both the same question
q = "Should we rewrite our C++ codebase in Rust?"
answer1 = client.think(agent_id="open-minded", query=q)
# Likely: "Yes, Rust's safety benefits outweigh migration costs"
answer2 = client.think(agent_id="conservative", query=q)
# Likely: "No, C++'s ecosystem and our team's expertise make it the safer choice"
```
</TabItem>
</Tabs>
## Bias Strength
The `bias_strength` parameter (0-1) controls how much personality influences opinions:
| Value | Behavior |
|-------|----------|
| 0.0 | Pure evidence-based reasoning |
| 0.5 | Balanced personality + evidence |
| 1.0 | Strongly personality-driven |
```python
# Evidence-focused agent
client.create_agent(
agent_id="analyst",
personality={"bias_strength": 0.2} # Low bias
)
# Personality-driven agent
client.create_agent(
agent_id="advisor",
personality={"bias_strength": 0.8} # High bias
)
```
## Opinions in Think Responses
When `think` uses opinions, they appear in `based_on`:
```python
answer = client.think(agent_id="my-agent", query="What language should I learn?")
print("World facts used:")
for f in answer["based_on"]["world"]:
print(f" {f['text']}")
print("\nOpinions used:")
for o in answer["based_on"]["opinion"]:
print(f" {o['text']} (confidence: {o['confidence_score']})")
```
## Confidence Thresholds
Opinions below a confidence threshold may be:
- Excluded from responses
- Marked as uncertain
- Revised more easily
```python
# Low confidence opinions are held loosely
# "I think Python might be good for this" (0.45)
# High confidence opinions are stated firmly
# "Python is definitely the right choice" (0.92)
```
---
## File: developer/api/think-vs-search.md
# Think vs Search
When to use `search` vs `think`.
## Quick Comparison
| | Search | Think |
|---|--------|-------|
| **Returns** | Raw memory results | Generated response |
| **Use case** | Retrieval, lookup | Q&A, reasoning |
| **LLM calls** | 0 (retrieval only) | 1+ (generation) |
| **Speed** | Fast (~100-200ms) | Slower (~500-2000ms) |
| **Opinions** | Returns existing | Can form new ones |
| **Personality** | Not applied | Applied to response |
## When to Use Search
**Use Search when you need:**
- Raw facts for your own processing
- Fast retrieval without generation
- To populate context for another LLM
- To check what's in memory
- Debugging retrieval quality
```python
# Get raw facts to inject into your own prompt
results = client.search(agent_id="my-agent", query="Alice's preferences")
context = "\n".join([r["text"] for r in results])
# Use context in your own LLM call
```
**Examples:**
```python
# Lookup — just get the facts
results = client.search(agent_id="my-agent", query="Alice's email address")
# Context building — feed into another system
results = client.search(agent_id="my-agent", query="Recent project discussions")
context = format_for_prompt(results)
# Verification — check what's stored
results = client.search(agent_id="my-agent", query="What do I know about Bob?")
```
## When to Use Think
**Use Think when you need:**
- A natural language response
- Personality-aware answers
- Opinion formation
- Reasoning over multiple facts
- Source attribution
```python
# Get a complete answer with personality
answer = client.think(agent_id="my-agent", query="What should I recommend to Alice?")
print(answer["text"]) # Natural language response
print(answer["based_on"]) # Sources used
```
**Examples:**
```python
# Q&A — need a response, not just facts
answer = client.think(agent_id="my-agent", query="What does Alice do for work?")
# Reasoning — synthesize multiple facts
answer = client.think(agent_id="my-agent", query="How are Alice and Bob connected?")
# Opinion — agent forms a view
answer = client.think(agent_id="my-agent", query="What do you think about Python?")
# Recommendation — personality-influenced
answer = client.think(agent_id="my-agent", query="What book should I read next?")
```
## Performance Comparison
```mermaid
graph LR
subgraph Search
S1[Query] --> S2[4-way Retrieval]
S2 --> S3[RRF + Rerank]
S3 --> S4[Results]
end
subgraph Think
T1[Query] --> T2[4-way Retrieval]
T2 --> T3[RRF + Rerank]
T3 --> T4[Load Personality]
T4 --> T5[LLM Generation]
T5 --> T6[Store Opinions]
T6 --> T7[Response]
end
```
| Operation | Search | Think |
|-----------|--------|-------|
| Retrieval | ~100ms | ~100ms |
| Reranking | ~35ms | ~35ms |
| LLM Generation | — | ~500-1500ms |
| Opinion Storage | — | ~50ms |
| **Total** | **~135ms** | **~700-1700ms** |
## Hybrid Pattern
Use Search for context, Think for final response:
```python
# First: fast search to check relevance
results = client.search(agent_id="my-agent", query="Alice project status")
if len(results) > 0:
# Only call Think if we have relevant memories
answer = client.think(agent_id="my-agent", query="Summarize Alice's project status")
else:
answer = {"text": "I don't have information about Alice's projects."}
```
## Decision Flowchart
```mermaid
graph TD
A[Need memory access] --> B{Need natural language response?}
B -->|No| C[Use Search]
B -->|Yes| D{Need personality/opinions?}
D -->|No| E{Building context for another LLM?}
E -->|Yes| C
E -->|No| F[Use Think]
D -->|Yes| F
```
## Cost Considerations
| Factor | Search | Think |
|--------|--------|-------|
| API calls | 1 | 1 |
| LLM tokens | 0 | 500-2000 |
| Latency | Low | Medium |
| Cost | Low | Higher (LLM usage) |
If you're making many requests or building a high-throughput system, consider:
- Use Search for bulk operations
- Use Think for user-facing responses
- Cache Think responses when appropriate
---
## File: developer/development.md
# Development Guide
Guide to setting up a local development environment for contributing to Hindsight.
## Prerequisites
- Python 3.11+
- [uv](https://docs.astral.sh/uv/) - Fast Python package manager
- Docker and Docker Compose
- An LLM API key (OpenAI, Groq, or Ollama)
## Local Development Setup
### 1. Clone the Repository
```bash
git clone https://github.com/vectorize-io/hindsight.git
cd hindsight
```
### 2. Install Dependencies
```bash
uv sync
```
### 3. Start PostgreSQL
Start only the database via Docker:
```bash
cd docker && docker-compose up -d postgres
```
### 4. Configure Environment
```bash
cp .env.example .env
```
Edit `.env` with your LLM API key:
```bash
# Database (connects to Docker postgres)
HINDSIGHT_API_DATABASE_URL=postgresql://hindsight:hindsight_dev@localhost:5432/hindsight
# LLM Provider (choose one)
HINDSIGHT_API_LLM_PROVIDER=groq
HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
HINDSIGHT_API_LLM_MODEL=llama-3.1-70b-versatile
```
### 5. Start the API Server
```bash
./scripts/start-server.sh --env local
```
The server will be available at http://localhost:8888.
## Running Tests
```bash
# Run all tests
uv run pytest
# Run specific test file
uv run pytest tests/test_retrieval.py
# Run with verbose output
uv run pytest -v
```
## Code Generation
### Regenerate API Clients
When you modify the OpenAPI spec, regenerate the clients:
```bash
./scripts/generate-clients.sh
```
This generates:
- Python client in `hindsight-clients/python/`
- TypeScript client in `hindsight-clients/typescript/`
### Export OpenAPI Schema
```bash
./scripts/export-openapi.sh
```
## Project Structure
```
hindsight/
├── hindsight-api/ # Main API server
│ ├── hindsight_api/
│ │ ├── api/ # HTTP endpoints
│ │ ├── engine/ # Memory engine, retrieval, reasoning
│ │ └── web/ # Server entry point
│ └── tests/
├── hindsight-clients/ # Generated SDK clients
│ ├── python/
│ └── typescript/
├── hindsight-control-plane/ # Admin UI (Next.js)
├── docker/ # Docker Compose setup
└── scripts/ # Development scripts
```
## Contributing
1. Create a feature branch from `main`
2. Make your changes
3. Run tests: `uv run pytest`
4. Submit a pull request
## Troubleshooting
### Database Connection Issues
Ensure PostgreSQL is running:
```bash
docker-compose ps
```
Check database connectivity:
```bash
psql postgresql://hindsight:hindsight_dev@localhost:5432/hindsight
```
### ML Model Download
On first run, Hindsight downloads embedding and reranking models. This may take a few minutes. Models are cached in `~/.cache/huggingface/`.
### Port Conflicts
If port 8888 is in use:
```bash
HINDSIGHT_API_PORT=8889 ./scripts/start-server.sh --env local
```
---
## File: developer/mcp-server.md
# MCP Server
Hindsight includes a built-in [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that allows AI assistants to store and retrieve memories directly.
## Access
The MCP server is **enabled by default** and mounted at `/mcp` on the API server:
```
http://localhost:8888/mcp
```
To disable it, set the environment variable:
```bash
export HINDSIGHT_API_MCP_ENABLED=false
```
## Available Tools
### hindsight_put
Store information to a user's memory bank.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `bank_id` | string | Yes | Unique identifier for the user (e.g., `user_12345`, `alice@example.com`) |
| `content` | string | Yes | The fact or memory to store |
| `context` | string | Yes | Category for the memory (e.g., `personal_preferences`, `work_history`) |
| `explanation` | string | No | Why this memory is being stored |
**Example:**
```json
{
"name": "hindsight_put",
"arguments": {
"bank_id": "user_12345",
"content": "User prefers Python over JavaScript for backend development",
"context": "programming_preferences"
}
}
```
**When to use:**
- User shares personal facts, preferences, or interests
- Important events or milestones are mentioned
- Decisions, opinions, or goals are stated
- Work context or project details are discussed
---
### hindsight_search
Search a user's memory bank to provide personalized responses.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `bank_id` | string | Yes | Unique identifier for the user |
| `query` | string | Yes | Natural language search query |
| `max_tokens` | integer | No | Maximum tokens for results (default: 4096) |
| `explanation` | string | No | Why this search is being performed |
**Example:**
```json
{
"name": "hindsight_search",
"arguments": {
"bank_id": "user_12345",
"query": "What are the user's programming language preferences?"
}
}
```
**Response:**
```json
{
"results": [
{
"id": "fact_abc123",
"text": "User prefers Python over JavaScript for backend development",
"type": "world",
"context": "programming_preferences",
"event_date": null,
"document_id": null
}
]
}
```
**When to use:**
- Start of conversation to recall relevant context
- Before making recommendations
- When user asks about something they may have mentioned before
- To provide continuity across conversations
---
## Per-User Isolation
Both tools require a `bank_id` that uniquely identifies the user. Memories are strictly isolated per bank — one user cannot access another user's memories.
**Best practices:**
- Use consistent identifiers (user ID, email, session ID)
- Don't share `bank_id` between different users
- Only call these tools when you can identify the specific user
---
## Integration with AI Assistants
The MCP server can be used with any MCP-compatible AI assistant. For Claude Desktop integration using the CLI, see [MCP Server (CLI)](/sdks/mcp).
---
## File: developer/metrics.md
# Metrics
Hindsight exposes Prometheus metrics at `/metrics` for monitoring.
```bash
curl http://localhost:8888/metrics
```
## Available Metrics
### Request Metrics
| Metric | Type | Description |
|--------|------|-------------|
| `hindsight_http_requests_total` | Counter | Total HTTP requests (labels: method, endpoint, status_code) |
| `hindsight_http_request_duration_seconds` | Histogram | Request latency (labels: method, endpoint) |
### Memory Operations
| Metric | Type | Description |
|--------|------|-------------|
| `hindsight_retain_duration_seconds` | Histogram | Retain operation latency |
| `hindsight_retain_items_total` | Counter | Total items retained |
| `hindsight_recall_duration_seconds` | Histogram | Recall operation latency |
| `hindsight_recall_results_count` | Histogram | Number of results per recall |
| `hindsight_reflect_duration_seconds` | Histogram | Reflect operation latency |
### LLM Metrics
| Metric | Type | Description |
|--------|------|-------------|
| `hindsight_llm_requests_total` | Counter | LLM API requests (labels: provider, model, status) |
| `hindsight_llm_request_duration_seconds` | Histogram | LLM request latency |
| `hindsight_llm_tokens_total` | Counter | Tokens consumed (labels: provider, token_type) |
### Database Metrics
| Metric | Type | Description |
|--------|------|-------------|
| `hindsight_db_connections_active` | Gauge | Active database connections |
| `hindsight_db_connections_idle` | Gauge | Idle connections in pool |
| `hindsight_db_query_duration_seconds` | Histogram | Query latency (labels: query_type) |
### Memory Bank Metrics
| Metric | Type | Description |
|--------|------|-------------|
| `hindsight_bank_memory_units_total` | Gauge | Total memories per bank |
| `hindsight_bank_entities_total` | Gauge | Total entities per bank |
## Prometheus Configuration
```yaml
scrape_configs:
- job_name: 'hindsight'
static_configs:
- targets: ['localhost:8888']
```
---
## File: developer/performance.md
# Performance
Hindsight is designed for high-performance semantic memory operations at scale. This page covers performance characteristics, optimization strategies, and best practices.
## Overview
Hindsight's performance is optimized across three key operations:
- **Retain (Ingestion)**: Batch processing with async operations for large-scale memory storage
- **Recall (Search)**: Sub-second semantic search with configurable thinking budgets
- **Reflect (Reasoning)**: Personality-aware answer generation with controllable compute
## Design Philosophy: Optimized for Fast Reads
Hindsight is **architected from the ground up to prioritize read performance over write performance**. This design decision reflects the typical usage pattern of memory systems: memories are written once but read many times.
The system makes deliberate trade-offs to ensure **sub-second recall operations**:
- **Pre-computed embeddings**: All memory embeddings are generated and indexed during retention
- **Optimized vector search**: HNSW indexes enable fast approximate nearest neighbor search
- **Fact extraction at write time**: Complex LLM-based fact extraction happens during retention, not retrieval
- **Structured memory graphs**: Relationships and temporal information are resolved upfront
This means **Recall (search) operations are blazingly fast** because all the heavy lifting has already been done.
### Performance Comparison
| Operation | Typical Latency | Primary Bottleneck | Optimization Strategy |
|-----------|----------------|-------------------|----------------------|
| **Recall** | 100-600ms | Vector search, graph traversal | ✅ Already optimized |
| **Reflect** | 800-3000ms | LLM generation + search | Reduce search budget, use faster LLM |
| **Retain** | 500ms-2000ms per batch | **LLM fact extraction** | Use high-throughput LLM provider |
Hindsight is designed to ensure your **application's read path (recall/reflect) is always fast**, even if it means spending more time upfront during writes. This is the right trade-off for memory systems where:
- Memories are retained in background processes or during low-traffic periods
- Memories are queried frequently in user-facing, latency-sensitive contexts
- The ratio of reads to writes is high (typically 10:1 or higher)
---
## Retain Performance
**Retain (write) operations are inherently slower** because they involve LLM-based fact extraction, entity recognition, temporal reasoning, relationship mapping, and embedding generation. **The LLM is the primary bottleneck for write latency.**
### Hindsight Doesn't Need a Smart Model
The fact extraction process is structured and well-defined, so smaller, faster models work extremely well. Our recommended model is `gpt-oss-20b` (available via Groq and other providers).
To maximize retention throughput:
1. **Use high-throughput LLM providers**: Choose providers with high requests-per-minute (RPM) limits and low latency
- ✅ **Fast**: [Groq](https://groq.com) with `gpt-oss-20b` or other openai-oss models, self-hosted models on GPU clusters (vLLM, TGI)
- ⚠️ **Slower**: Standard cloud LLM providers with rate limits
2. **Batch your operations**: Group related content into batch requests. The only limit is the HTTP payload size — Hindsight automatically splits large batches into smaller, optimized chunks under the hood, so you don't have to worry about it.
3. **Use async mode for large datasets**: Queue operations in the background
4. **Parallel processing**: For very large datasets, use multiple concurrent retention requests with different `document_id` values
### Throughput
Typical ingestion performance:
| Mode | Items/second | Use Case |
|------|--------------|----------|
| Synchronous | ~50-100 | Real-time updates, small batches |
| Async (batched) | ~500-1000 | Bulk imports, background processing |
| Parallel async | ~2000-5000 | Large-scale data migration |
**Factors affecting throughput:**
- Document size and complexity
- LLM provider rate limits (for fact extraction)
- Database write performance
- Available CPU/memory resources
---
## Recall Performance
### Budget
The `budget` parameter controls the search depth and quality. Choose based on query complexity — comprehensive questions that need thorough analysis benefit from higher budgets:
| Budget | Latency | Memory Activation | Use Case |
|--------|---------|-------------------|----------|
| `low` | 100-300ms | ~10-50 facts | Quick lookups, real-time chat |
| `mid` | 300-600ms | ~50-200 facts | Standard queries, balanced performance |
| `high` | 500-1500ms | ~200-500 facts | Comprehensive questions, thorough analysis |
### Search Optimization
1. **Appropriate budgets**: Use lower budgets for simple queries, higher for comprehensive reasoning
2. **Limit result tokens**: Set `max_tokens` to control response size (default: 4096)
3. **Include entities/chunks**: Use `include_entities` and `include_chunks` to retrieve additional context when needed — each has its own token budget
### Database Performance
Hindsight uses PostgreSQL with pgvector for efficient vector search:
- **Index type**: HNSW for approximate nearest neighbor search
- **Typical query time**: 10-50ms for vector search on 100K+ facts
- **Scalability**: Tested with millions of facts per bank
## Reflect Performance
### Performance Characteristics
| Component | Latency | Description |
|-----------|---------|-------------|
| Memory search | 300-1000ms | Based on budget (low/mid/high) |
| LLM generation | 500-2000ms | Depends on provider and response length |
| **Total** | **800-3000ms** | Typical end-to-end latency |
### Optimization Strategies
1. **Budget selection**: Use lower budgets when context is sufficient
2. **Context provision**: Provide relevant `context` to reduce search requirements
3. **Streaming responses**: Use streaming APIs (when available) for faster time-to-first-token
4. **Caching**: Cache frequent queries at the application level
## Best Practices
### Operations
- **Use appropriate budgets**: Don't over-provision for simple queries; use higher budgets for comprehensive reasoning
- **Batch retain operations**: Group related content together for better efficiency
- **Cache frequent queries**: Cache at the application level for repeated queries
- **Profile with trace**: Use the `trace` parameter to identify slow operations
### Scaling
- **Horizontal scaling**: Deploy multiple API instances behind a load balancer with shared PostgreSQL
- **Concurrency**: 100+ simultaneous requests supported; memory search scales with CPU cores
- **LLM rate limits**: Distribute load across multiple API keys/providers (typically 60-500 RPM per key)
### Cost Optimization
- **Use efficient models**: `gpt-oss-20b` via Groq for retain — Hindsight doesn't need frontier models
- **Control token budgets**: Limit `max_tokens` for recall, use lower budgets when possible
- **Optimize chunks**: Larger chunks (1000-2000 tokens) are more efficient than many small ones
### Monitoring
- **Prometheus metrics**: Available at `/metrics` — track latency percentiles, throughput, and error rates
- **Key metrics**: `hindsight_recall_duration_seconds`, `hindsight_reflect_duration_seconds`, `hindsight_retain_items_total`
---
## File: developer/storage.md
# Storage
Hindsight uses PostgreSQL as its sole storage backend.
## Why PostgreSQL?
PostgreSQL provides all capabilities required for a semantic memory system in a single database:
| Capability | Implementation |
|------------|----------------|
| Vector search | pgvector extension with HNSW indexes |
| Full-text search | Built-in tsvector with GIN indexes |
| Relational data | Native PostgreSQL |
| JSON documents | JSONB with indexing |
| Graph queries | Recursive CTEs |
### Reduced System Dependencies
Building exclusively for PostgreSQL simplifies deployment and operations:
- Single connection string to configure
- Single backup and restore strategy
- Single monitoring target
- ACID transactions across all data types
- Single upgrade path
### No Storage Abstraction
Hindsight does not abstract storage behind a generic interface. This is a deliberate trade-off.
We believe PostgreSQL is becoming the standard database API. Its popularity, extension ecosystem, and modularity mean that PostgreSQL-compatible interfaces are appearing everywhere—from serverless offerings to distributed databases. Building for PostgreSQL today means compatibility with a growing ecosystem tomorrow.
Supporting multiple databases would increase flexibility but conflict with our core goals: Hindsight is fully open source and designed to be as simple as possible to run and use. Adding database abstractions introduces complexity in code, testing, documentation, and operations—complexity that we pass on to users.
By committing to PostgreSQL, we keep the system simple:
- One set of deployment instructions
- One set of performance characteristics to understand
- One codebase optimized for one backend
- No configuration decisions about which database to use
## Development with pg0
For local development, Hindsight uses **[pg0](https://github.com/vectorize-io/pg0)**—an embedded PostgreSQL distribution.
### What is pg0?
pg0 is a single binary containing:
- PostgreSQL server
- pgvector extension (pre-installed)
- Automatic initialization
### Behavior
When no `DATABASE_URL` is configured, Hindsight:
1. Downloads the pg0 binary for the current platform (macOS ARM, Linux x86_64/ARM64, Windows)
2. Starts an embedded PostgreSQL instance on port 5555
3. Initializes the schema
4. Stores data in `~/.hindsight/pg0/`
### Environments
| Environment | Database | Configuration |
|-------------|----------|---------------|
| Development | pg0 (embedded) | Automatic |
| Production | PostgreSQL 15+ | `DATABASE_URL` environment variable |
## Requirements
- PostgreSQL 15 or later
- pgvector 0.5.0 or later
Any PostgreSQL instance that satisfies these requirements should work. If you encounter issues with a specific setup, [open a GitHub issue](https://github.com/hindsight-ai/hindsight/issues).
### Tested Managed Services
- AWS RDS (PostgreSQL 15+)
- Google Cloud SQL
- Azure Database for PostgreSQL
- Supabase
- Neon
---
## File: sdks/langgraph.md
# LangGraph
Hindsight provides a `BaseStore` implementation for LangGraph's memory system.
## Installation
```bash
cd hindsight-langmem && uv pip install -e .
```
## Quick Start
```python
from hindsight_langmem import HindsightStore
# Create store
store = HindsightStore(
base_url="http://localhost:8888",
default_agent_id="my-agent",
)
# Store data
store.put(
namespace=("user", "preferences"),
key="language",
value={"language": "Python", "reason": "data science"}
)
# Retrieve data
item = store.get(namespace=("user", "preferences"), key="language")
print(item.value) # {"language": "Python", "reason": "data science"}
# Search
results = store.search(
namespace_prefix=("user",),
query="programming language",
limit=10
)
```
## How It Works
`HindsightStore` implements LangGraph's `BaseStore` interface:
- **Namespaces** map to Hindsight agent IDs (joined with `__`)
- **Keys** map to document IDs
- **Values** are stored as JSON in memory content
## BaseStore Interface
### put
Store an item:
```python
store.put(
namespace=("user", "session-123"),
key="preferences",
value={"theme": "dark", "language": "en"}
)
```
### get
Retrieve an item:
```python
item = store.get(namespace=("user", "session-123"), key="preferences")
if item:
print(item.value) # {"theme": "dark", "language": "en"}
print(item.created_at)
print(item.updated_at)
```
### search
Search within a namespace:
```python
results = store.search(
namespace_prefix=("user",),
query="theme preferences",
limit=10,
offset=0
)
for item in results:
print(f"{item.key}: {item.value}")
```
### delete
Delete an item:
```python
store.delete(namespace=("user", "session-123"), key="preferences")
```
## Async Support
All operations have async variants:
```python
await store.aput(namespace, key, value)
item = await store.aget(namespace, key)
results = await store.asearch(namespace_prefix, query)
await store.adelete(namespace, key)
```
## With LangGraph
```python
from langgraph.graph import StateGraph
from hindsight_langmem import HindsightStore
store = HindsightStore(base_url="http://localhost:8888")
# Use store in your graph
graph = StateGraph()
# ... configure graph with store
```
## Namespace Mapping
Namespaces are converted to Hindsight agent IDs:
| Namespace | bank ID |
|-----------|----------|
| `("user",)` | `user` |
| `("user", "session")` | `user__session` |
| `("app", "v1", "data")` | `app__v1__data` |
| `()` | `default_agent_id` |
Memory banks are created automatically if they don't exist.
---
## File: sdks/openai.md
# OpenAI
Drop-in replacement for the OpenAI Python client with automatic memory integration.
## Installation
```bash
cd hindsight-openai && uv pip install -e .
```
## Quick Start
```python
from hindsight_openai import configure, OpenAI
# Configure once
configure(
hindsight_api_url="http://localhost:8888",
agent_id="my-agent",
)
# Use OpenAI client normally
client = OpenAI(api_key="sk-...")
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "What did we discuss about AI?"}]
)
```
## How It Works
The wrapper intercepts OpenAI calls:
1. **Before**: Retrieves relevant memories and injects as system message
2. **After**: Stores conversation to Hindsight
Your code works exactly as before, but now has memory.
## Configuration
```python
configure(
hindsight_api_url="http://localhost:8888", # Hindsight API
agent_id="my-agent", # Required
store_conversations=True, # Store conversations
inject_memories=True, # Inject memories into prompts
document_id="session-123", # Group by document
enabled=True, # Master switch
)
```
## Memory Injection
When enabled, memories are automatically injected:
```python
# Your code
messages = [{"role": "user", "content": "What trails did Alice recommend?"}]
# What gets sent to OpenAI
messages = [
{
"role": "system",
"content": "Relevant context:\n- Alice loves hiking in Yosemite\n- Alice recommended Half Dome trail"
},
{"role": "user", "content": "What trails did Alice recommend?"}
]
```
## Async Support
```python
from hindsight_openai import configure, AsyncOpenAI
configure(hindsight_api_url="http://localhost:8888", agent_id="my-agent")
client = AsyncOpenAI(api_key="sk-...")
response = await client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Tell me about my preferences"}]
)
```
## Streaming
Fully supported:
```python
stream = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Tell me a story"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")
```
## Disable Temporarily
```python
from hindsight_openai import configure
configure(enabled=False) # Disable
configure(enabled=True) # Re-enable
```
---