7792 lines
224 KiB
Text
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
|
|
```
|
|
|
|
|
|
---
|