Compare commits

...
Author SHA1 Message Date
Nicolò Boschi 618bcd6e67 fix 2026-01-19 16:48:18 +01:00
Nicolò Boschi 2ad3a26344 fix examples 2026-01-19 14:57:43 +01:00
Nicolò Boschi 1c0d7fe563 doc: mental models 2026-01-19 14:51:34 +01:00
42 changed files with 1587 additions and 609 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
# AGENTS.md
See [CLAUDE.md](./CLAUDE.md) for project documentation and coding conventions.
See [CLAUDE.md](./CLAUDE.md) for project documentation and coding conventions.
+2 -3
View File
@@ -7,8 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
Hindsight is an agent memory system that provides long-term memory for AI agents using biomimetic data structures. Memories are organized as:
- **World facts**: General knowledge ("The sky is blue")
- **Experience facts**: Personal experiences ("I visited Paris in 2023")
- **Opinion facts**: Beliefs with confidence scores ("Paris is beautiful" - 0.9 confidence)
- **Observations**: Complex mental models derived from reflection
- **Mental models**: Structured knowledge containers derived from reflection with evidence-grounded observations
## Development Commands
@@ -101,7 +100,7 @@ cd hindsight-control-plane && npm run dev
Main operations:
- **Retain**: Store memories, extracts facts/entities/relationships
- **Recall**: Retrieve memories via 4 parallel strategies (semantic, BM25, graph, temporal) + reranking
- **Reflect**: Deep analysis forming new opinions/observations (disposition-aware)
- **Reflect**: Deep analysis with agentic reasoning loop (disposition-aware)
### Database
PostgreSQL with pgvector. Schema managed via Alembic migrations in `hindsight-api/hindsight_api/alembic/`. Migrations run automatically on API startup.
+4 -3
View File
@@ -33,8 +33,9 @@ Most agent memory implementation rely on basic vector search or sometimes use a
- **World:** Facts about the world ("The stove gets hot")
- **Experiences:** Agent's own experiences ("I touched the stove and it really hurt")
- **Opinion:** Beliefs with confidence scores ("I shouldn't touch the stove again" - .99 confidence)
- **Observation:** Complex mental models derived by reflecting on facts and experiences ("Curling irons, ovens, and fire are also hot. I shouldn't touch those either.")
- **Mental Models:** Structured knowledge containers derived by reflecting on facts and experiences ("Curling irons, ovens, and fire are also hot. I shouldn't touch those either.")
Mental models are evidence-grounded—every observation links back to the exact quotes from memories that support it.
Memories in Hindsight are stored in banks (i.e. memory banks). When memories are added to Hindsight, they are pushed into either the world facts or experiences memory pathway. They are then represented as a combination of entities, relationships, and time series with sparse/dense vector representations to aid in later recall.
@@ -208,7 +209,7 @@ The final output is trimmed as needed to fit within the token limit.
### Reflect
The reflect operation is used to perform a more thorough analysis of existing memories. This allows the agent to form new connections between memories which are then persisted as opinions and/or observations. When building agents, the reflect operation is a key capability to enable the agent to learn from its experiences.
The reflect operation is used to perform a more thorough analysis of existing memories. This allows the agent to form new connections between memories which are then persisted as mental models. When building agents, the reflect operation is a key capability to enable the agent to learn from its experiences.
For example, the `reflect` operation can be used to support use cases such as:
+3 -3
View File
@@ -2,7 +2,7 @@
**Memory System for AI Agents** — Temporal + Semantic + Entity Memory Architecture using PostgreSQL with pgvector.
Hindsight gives AI agents persistent memory that works like human memory: it stores facts, tracks entities and relationships, handles temporal reasoning ("what happened last spring?"), and forms opinions based on configurable disposition traits.
Hindsight gives AI agents persistent memory that works like human memory: it stores facts, tracks entities and relationships, handles temporal reasoning ("what happened last spring?"), and builds mental models based on configurable disposition traits.
## Installation
@@ -120,8 +120,8 @@ This runs a stdio-based MCP server that can be used directly with MCP-compatible
- **Multi-Strategy Retrieval (TEMPR)** — Semantic, keyword, graph, and temporal search combined with RRF fusion
- **Entity Graph** — Automatic entity extraction and relationship tracking
- **Temporal Reasoning** — Native support for time-based queries
- **Disposition Traits** — Configurable skepticism, literalism, and empathy influence opinion formation
- **Three Memory Types** — World facts, bank actions, and formed opinions with confidence scores
- **Disposition Traits** — Configurable skepticism, literalism, and empathy influence reasoning
- **Two Memory Types** — World facts and experience facts with mental models for higher-level understanding
## Documentation
+1 -1
View File
@@ -23,7 +23,7 @@ await client.retain('my-bank', 'Alice works at Google in Mountain View.');
// Recall memories
const results = await client.recall('my-bank', 'Where does Alice work?');
// Reflect and get an opinion
// Reflect with reasoning and mental models
const response = await client.reflect('my-bank', 'What do you think about Alice\'s career?');
```
@@ -0,0 +1,387 @@
---
slug: introducing-mental-models
title: "Introducing Mental Models"
authors: [nicoloboschi]
hide_table_of_contents: true
---
# Introducing mental models
We're excited to announce **Mental Models**, a fundamental redesign of how Hindsight agents form, organize, and evolve their beliefs. This replaces the previous opinions and observations system with a more powerful, evidence-grounded architecture.
<!-- truncate -->
---
## The reflect agent needs more power
When you call `reflect()`, you're asking the agent to reason—not just retrieve facts, but think about them, form judgments, and provide contextual answers. But effective reasoning requires more than raw memories. The agent needs:
- **A sense of purpose**: What is this agent for? What should it pay attention to?
- **Organized knowledge**: Not scattered facts, but structured understanding of key topics
- **Evolving beliefs**: The ability to form, refine, and update views based on accumulated evidence
This is where **Mission** and **Mental Models** come in.
### Mission: defining agent purpose
Every memory bank can now have a **mission**—a natural language description of what the agent is for:
```python
client.set_mission(
bank_id="pm-agent",
mission="Be a PM for the engineering team, tracking sprint progress, team capacity, and technical decisions"
)
```
The mission is foundational. It tells the agent:
- What topics are important to track
- How to interpret incoming information
- What kind of mental models to build automatically
Without a mission, the agent has no compass. With one, it knows what matters.
**Note:** A mission is required to use mental models, but mental models themselves are optional. You can still use `reflect()` without setting a mission—the agent will reason over raw memories as before. Mental models add an additional layer of structured understanding on top.
---
## Mental models: structured understanding
Mental models are **organized knowledge containers** that give the Reflect agent a broader, structured understanding of important topics. Instead of reasoning over raw memories alone, the agent can draw on synthesized knowledge about key people, projects, concepts, and decisions.
```mermaid
graph LR
Q[Query] --> A[Reflect Agent]
A <--> MM[Mental Models]
A <--> M[Memories]
A --> R[Response]
```
The agent runs a reasoning loop, deciding which tools to use based on the query. It can explore mental models, search memories, drill into documents, or create new mental models when it discovers important patterns. Each mental model groups observations about a topic with full provenance—the agent doesn't just know something, it knows *why* it knows it.
### What about opinions and observations?
In earlier versions, Hindsight formed beliefs through **opinions** (beliefs with confidence scores) and **observations** (entity-specific patterns). Mental models build on these concepts while adding:
- **Organization**: All observations about a topic grouped together
- **Evidence trail**: Every belief links back to source memories with exact quotes
- **Version history**: Track how beliefs evolve over time
### What's in a mental model?
Each mental model contains:
- **Name**: Human-readable identifier ("Alice", "Tech Stack Decisions")
- **Description**: One-liner for quick scanning
- **Observations**: List of beliefs with evidence
- **Version**: Current version number
- **Tags**: For scoped visibility
### Evidence-grounded observations
Every observation now requires **exact quotes** from source memories:
```json
{
"title": "Strong ML expertise",
"content": "Alice has deep machine learning knowledge, particularly in transformer architectures and production ML systems.",
"evidence": [
{
"memory_id": "mem_abc123",
"quote": "Alice implemented our BERT-based classifier that reduced inference latency by 40%",
"relevance": "Demonstrates practical transformer expertise",
"timestamp": "2025-11-15T10:30:00Z"
},
{
"memory_id": "mem_def456",
"quote": "Alice's talk on production ML pipelines was the highlight of the engineering offsite",
"relevance": "Shows recognition of ML systems knowledge",
"timestamp": "2025-12-02T14:00:00Z"
}
],
"trend": "strengthening"
}
```
The system **verifies** that quoted text actually exists in the source memories, ensuring observations are always grounded in real data.
### Computed trends
Instead of numeric confidence values, mental models use computed trends based on evidence patterns:
- **new**: Recently formed, limited evidence
- **strengthening**: Recent evidence supports this observation
- **stable**: Consistent evidence over time
- **weakening**: Recent evidence contradicts or is absent
- **stale**: No recent evidence, may be outdated
Trends are determined by analyzing evidence timestamps and recency patterns.
---
## How reflect uses mental models
The Reflect agent is now **agentic**—it actively explores and drills down into information as needed. When answering a query, the agent can:
1. **List mental models** to see what structured knowledge is available
2. **Read a mental model** to get synthesized observations about a topic
3. **Drill into evidence** by following an observation's source memories
4. **Expand to full context** by loading the original document chunk
The agent decides how deep to go based on the query—simple questions may only need mental model summaries, while complex decisions may require drilling down to source documents.
### Agentic tools
During reflect, the agent has access to:
- `list_mental_models()` — See available mental models
- `get_mental_model(id)` — Read observations and evidence
- `recall(query)` — Search raw memories
- `learn(name, description)` — Create a new mental model to track a discovered pattern
This makes reflect a reasoning loop, not a single retrieval step.
---
## Five types of mental models
Mental models can be created through different pathways, each serving a specific purpose:
### 1. Structural (mission-derived)
Created automatically from the bank's mission statement. If your agent's mission is "Be a PM for the engineering team", Hindsight generates structural models for concepts any PM would need to track: Team Members, Sprint Goals, Technical Debt.
```python
client.set_mission(
bank_id="pm-agent",
mission="Be a PM for the engineering team, tracking sprint progress and team capacity"
)
# Automatically creates: "Team Members", "Sprint Goals", "Blockers", etc.
```
### 2. Emergent (data-discovered)
Created automatically when patterns emerge in the data. If "Alice" is mentioned frequently across many memories, Hindsight promotes her to a mental model and synthesizes observations about her.
### 3. Pinned (user-created)
Created explicitly by users for topics they want the agent to track:
```python
client.create_mental_model(
bank_id="my-agent",
name="Product Roadmap",
description="Track product priorities and feature decisions"
)
# Content generated by analyzing relevant memories
```
### 4. Learned (agent-created)
Created by the reflect agent during reasoning when it identifies topics worth tracking long-term. As part of the agentic reflect loop, the agent doesn't just answer queries—it also considers whether this is a topic it should understand more deeply going forward.
For example, if a user asks "What are customers saying about our new pricing?" and the agent finds scattered feedback across many memories, it might decide: "Customer feedback on pricing is something I should track systematically." It then creates a "Pricing Feedback" mental model, which will be populated with synthesized observations during the next refresh.
This makes the agent proactive about building its own knowledge structure based on what users actually care about.
### 5. Directive (hard rules)
User-defined constraints that the agent must follow. Unlike other mental models, directives are never modified by the system:
```python
client.create_mental_model(
bank_id="support-agent",
name="Response Guidelines",
subtype="directive",
observations=[
{"title": "Always respond in French", "content": "All customer responses must be in French regardless of input language"},
{"title": "Never mention competitors", "content": "Do not reference or compare to competitor products"}
]
)
```
Directives are injected into the system prompt during reflect with a "(MANDATORY)" marker.
---
## Tags and scoping
Mental models support tags for multi-user scenarios. Tags let you create separate sets of mental models within the same bank and scope which ones are used during reflect—useful when a single bank serves multiple users who need personalized mental models.
### Which types support tags
- **Structural** and **Emergent**: Tags are applied during refresh via the `tags` parameter
- **Pinned** and **Learned**: Tags are set at creation time
- **Directive**: Tags are set at creation time and used to scope which directives apply during reflect
### Applying tags
When refreshing, pass tags to apply them to newly created models:
```python
# Create structural/emergent models with tags for a specific user
client.refresh_mental_models(
bank_id="my-agent",
tags=["user_alice"]
)
# Create a pinned model for a user
client.create_mental_model(
bank_id="my-agent",
name="Alice's Preferences",
description="Track Alice's communication preferences",
tags=["user_alice"]
)
# Create a directive scoped to a user
client.create_mental_model(
bank_id="my-agent",
name="Alice's Guidelines",
subtype="directive",
tags=["user_alice"],
observations=[
{"title": "Use formal tone", "content": "Alice prefers formal business communication"}
]
)
```
### Filtering by tags
List mental models with tag filtering:
```python
# Get all models for a specific user
models = client.list_mental_models(
bank_id="my-agent",
tags=["user_alice"],
tags_match="any" # "any", "all", "any_strict", "all_strict"
)
```
When calling reflect with tags, both memories and directives are filtered to that scope:
```python
# Reflect using only Alice's context
response = client.reflect(
bank_id="my-agent",
query="What should I focus on today?",
tags=["user_alice"]
)
# Only Alice's memories, mental models, and directives are considered
```
This enables a single bank to serve multiple users with personalized mental model sets.
---
## Refreshing mental models
Mental model refresh is **manual**—you decide when to update observations based on new memories. The API provides flexibility to refresh at different granularities:
```python
# Refresh all mental models in a bank
client.refresh_mental_models(bank_id="my-agent")
# Refresh only structural models (mission-derived)
client.refresh_mental_models(bank_id="my-agent", subtype="structural")
# Refresh only emergent models (data-discovered)
client.refresh_mental_models(bank_id="my-agent", subtype="emergent")
# Refresh a single mental model
client.refresh_mental_model(bank_id="my-agent", model_id="alice")
```
All refresh operations run asynchronously and return an `operation_id` you can use to track progress.
### Freshness API
Each mental model includes a `freshness` field that tells you whether it's up to date:
```python
model = client.get_mental_model(bank_id="my-agent", model_id="alice")
print(model.freshness)
# {
# "is_up_to_date": false,
# "last_refresh_at": "2025-12-01T10:30:00Z",
# "memories_since_refresh": 47,
# "reasons": ["new_memories", "mission_changed"]
# }
```
The `reasons` field tells you what changed since the last refresh:
- **never_refreshed**: Model was just created and has no observations yet
- **new_memories**: New memories have been retained since last refresh
- **mission_changed**: The bank's mission was updated
- **disposition_changed**: The bank's disposition traits changed
- **directives_changed**: Directive mental models were added/modified
This lets you build your own refresh strategy—refresh on a schedule, after a threshold of new memories, or on-demand when users query specific topics.
---
## How mental models update
The refresh process is a well-defined multi-phase pipeline that ensures observations stay grounded in evidence.
### Phase 1: Update existing observations
For each current observation, the system searches for new supporting or contradicting evidence. New quotes are added to the evidence list, and observations with strong contradictions are flagged for removal.
### Phase 2: Seed new candidates
The system samples recent memories and asks the LLM to identify new patterns worth tracking—skipping anything already covered by existing observations.
### Phase 3: Evidence hunt
For each candidate observation, parallel searches find supporting and contradicting evidence across the memory bank.
### Phase 4: Validate quotes
The LLM extracts exact quotes from memories. The system then verifies these quotes actually exist in the source memories (using fuzzy matching to handle minor variations). Observations without verified evidence are discarded.
### Phase 5: Merge and finalize
The LLM compares updated existing observations with validated new ones, deciding what to keep, remove, or merge. The final observation list becomes the new version.
Each refresh creates a new version, so you can always see how understanding evolved over time.
---
## Version history
Every refresh creates a new version, preserving the full history:
```python
# List all versions
versions = client.list_mental_model_versions(bank_id="my-agent", model_id="alice")
# Get specific historical version
v2 = client.get_mental_model_version(bank_id="my-agent", model_id="alice", version=2)
```
This enables:
- **Auditing**: See how beliefs evolved over time
- **Debugging**: Understand why an agent's perspective changed
- **Rollback**: Compare current vs. historical understanding
---
## Migration from opinions/observations
If you're upgrading from a previous version:
**What happens automatically:**
- Existing opinion and observation records are deleted (they lack the evidence structure required by mental models)
- The `background` bank field is replaced by `mission`
**What you need to do:**
- Set a mission for banks that should have mental models: `client.set_mission(bank_id, mission="...")`
- Call `client.refresh_mental_models(bank_id)` to generate initial mental models from existing memories
- Update any code that searched for `fact_type='opinion'` to use the mental models API instead
---
## Try it out
Mental models are available in Hindsight 0.4.0. We'd love to hear your feedback—please share your experience and suggestions on [GitHub](https://github.com/vectorize-io/hindsight/issues).
+4
View File
@@ -0,0 +1,4 @@
nicoloboschi:
name: Nicolò Boschi
url: https://github.com/nicoloboschi
image_url: https://github.com/nicoloboschi.png
@@ -127,7 +127,7 @@ for r in results.results:
## Reflect: Generate Insights
The `reflect` operation performs a more thorough analysis of existing memories. This allows the agent to form new connections between memories which are then persisted as opinions and/or observations.
The `reflect` operation runs an agentic reasoning loop over memories and mental models. The agent explores structured knowledge, searches memories, and may create new mental models when it discovers important patterns.
Example use cases:
- An AI Project Manager reflecting on what risks need to be mitigated
@@ -142,12 +142,12 @@ print(response)
## Memory Types
Hindsight organizes memory into four networks to mimic human memory:
Hindsight organizes memory into two types:
- **World**: Facts about the world ("The stove gets hot")
- **Experiences**: Agent's own experiences ("I touched the stove and it really hurt")
- **Opinion**: Beliefs with confidence scores ("I shouldn't touch the stove again" - .99 confidence)
- **Observation**: Complex mental models derived by reflecting on facts and experiences
- **Experience**: Agent's own experiences and conversations ("I touched the stove and it really hurt")
For structured knowledge, Hindsight uses **mental models**—organized containers with evidence-grounded observations. See [Mental Models](/developer/mental-models) for details.
## Cleanup
+1 -1
View File
@@ -78,7 +78,7 @@ The backup includes:
- Memory banks and their configuration
- Documents and chunks
- Entities and their relationships
- Memory units (facts, experiences, opinions, observations)
- Memory units (world facts, experiences)
- Entity cooccurrences and memory links
:::note Consistency
@@ -91,18 +91,18 @@ This means:
- Observations stay up-to-date as new information is retained
- The system prioritizes entities that matter most to your memory bank
### Observations vs Opinions
### Entity observations vs mental models
Observations are **objective summaries**—they synthesize facts without any bias or perspective. This is different from [opinions](./opinions), which are influenced by the memory bank's disposition.
Entity observations are **brief summaries** attached to specific entities. [Mental models](./mental-models) are richer structured knowledge containers with evidence-grounded observations.
| | Observations | Opinions |
| | Entity Observations | Mental Models |
|---|---|---|
| **Purpose** | Summarize what's known about an entity | Express the bank's perspective on a topic |
| **Disposition influence** | No | Yes |
| **Scope** | Per-entity | Any topic |
| **Generation** | Automatic (top entities) | On-demand via reflect |
| **Purpose** | Quick entity context | Structured understanding of topics |
| **Evidence** | No | Yes (exact quotes from memories) |
| **Scope** | Per-entity | Any topic (people, projects, concepts) |
| **Generation** | Automatic (top entities) | Manual refresh or agent-created |
### Using Observations
### Using observations
Observations are included in recall results when you set `include_entities=True`. They provide quick context about key entities without retrieving all underlying facts.
@@ -87,9 +87,9 @@ hindsight recall my-bank "Tell me about Alice" -v
---
## Reflect: Reason with Disposition
## Reflect: Reason with Mental Models
Generate disposition-aware responses that form opinions based on evidence.
Generate reasoned responses using mental models and memories.
<Tabs>
<TabItem value="python" label="Python">
@@ -104,7 +104,7 @@ Generate disposition-aware responses that form opinions based on evidence.
# Basic reflect
hindsight reflect my-bank "Should we adopt TypeScript for our backend?"
# Verbose output (shows sources and opinions)
# Verbose output (shows sources and mental models)
hindsight reflect my-bank "What are Alice's strengths for the team lead role?" -v
# With higher reasoning budget
@@ -114,9 +114,9 @@ hindsight reflect my-bank "Analyze our tech stack" --budget high
</TabItem>
</Tabs>
**What happens:** Memories are recalled, bank disposition is loaded, LLM reasons through evidence, new opinions are formed and stored.
**What happens:** The agent explores mental models and memories, reasons through evidence with disposition, and may create new mental models when it discovers important patterns.
**See:** [Reflect Details](./reflect) for disposition configuration.
**See:** [Reflect Details](./reflect) for mental models and disposition configuration.
---
@@ -126,9 +126,9 @@ hindsight reflect my-bank "Analyze our tech stack" --budget high
|---------|--------|--------|---------|
| **Purpose** | Store information | Find information | Reason about information |
| **Input** | Raw text/documents | Search query | Question/prompt |
| **Output** | Memory IDs | Ranked facts | Reasoned response + opinions |
| **Output** | Memory IDs | Ranked facts | Reasoned response |
| **Uses LLM** | Yes (extraction) | No | Yes (generation) |
| **Forms opinions** | No | No | Yes |
| **Uses mental models** | No | No | Yes |
| **Disposition** | No | No | Yes |
---
@@ -137,5 +137,5 @@ hindsight reflect my-bank "Analyze our tech stack" --budget high
- [**Retain**](./retain) — Advanced options for storing memories
- [**Recall**](./recall) — Tuning search quality and performance
- [**Reflect**](./reflect) — Configuring disposition and opinions
- [**Reflect**](./reflect) — Configuring mental models and disposition
- [**Memory Banks**](./memory-banks) — Managing memory bank disposition
@@ -56,17 +56,17 @@ hindsight bank disposition my-bank \
</TabItem>
</Tabs>
## Background and Disposition
## Mission and Disposition
Background and disposition are optional settings that influence how the bank forms opinions during [reflect](./reflect) operations.
Mission and disposition are optional settings that influence how the bank reasons during [reflect](./reflect) operations.
:::info
Background and disposition only affect the `reflect` operation (opinion formation). They do not impact `retain`, `recall`, or other memory operations.
Mission and disposition only affect the `reflect` operation. They do not impact `retain`, `recall`, or other memory operations.
:::
### Background
### Mission
The background is a first-person narrative providing context for opinion formation:
The mission is a natural language description of what the agent is for. It's required for using [mental models](./mental-models):
<Tabs>
<TabItem value="python" label="Python">
@@ -79,7 +79,7 @@ The background is a first-person narrative providing context for opinion formati
### Disposition Traits
Disposition traits influence how opinions are formed during reflection. Each trait is scored 1 to 5:
Disposition traits influence how the agent reasons during reflection. Each trait is scored 1 to 5:
| Trait | Low (1) | High (5) |
|-------|---------|----------|
@@ -0,0 +1,281 @@
---
sidebar_position: 6
---
# Mental Models
Manage mental models—structured knowledge containers that give agents broader understanding of important topics.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import mentalModelsPy from '!!raw-loader!@site/examples/api/mental-models.py';
import mentalModelsSh from '!!raw-loader!@site/examples/api/mental-models.sh';
:::info How Mental Models Work
Learn about the different types, observations, and refresh process in the [Mental Models Architecture](/developer/mental-models) guide.
:::
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) and set a mission for your bank.
:::
## Set mission
A mission is required before using mental models. It defines what the agent should track:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-set-mission" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-set-mission" language="bash" />
</TabItem>
</Tabs>
---
## List mental models
List all mental models for a bank, optionally filtered by subtype or tags:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-list" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-list" language="bash" />
</TabItem>
</Tabs>
### Response fields
| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique identifier |
| `name` | string | Human-readable name |
| `description` | string | One-liner description |
| `subtype` | string | One of: structural, emergent, pinned, learned, directive |
| `observations` | array | List of observations with evidence |
| `tags` | array | Tags for scoping |
| `version` | int | Current version number |
| `freshness` | object | Freshness status (null for directives) |
| `created_at` | string | ISO timestamp |
| `last_updated` | string | ISO timestamp of last change |
---
## Get mental model
Get a specific mental model by ID:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-get" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-get" language="bash" />
</TabItem>
</Tabs>
### Observation structure
Each observation contains:
| Field | Type | Description |
|-------|------|-------------|
| `title` | string | Short summary (5-10 words) |
| `content` | string | Detailed explanation |
| `evidence` | array | Supporting quotes from memories |
| `trend` | string | new, strengthening, stable, weakening, stale |
| `created_at` | string | When observation was formed |
### Evidence structure
| Field | Type | Description |
|-------|------|-------------|
| `memory_id` | string | Source memory ID |
| `quote` | string | Exact quote from memory |
| `relevance` | string | Why this supports the observation |
| `timestamp` | string | When the memory was created |
---
## Create mental model
Create a pinned or directive mental model:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-create" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-create" language="bash" />
</TabItem>
</Tabs>
### Request fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Human-readable name |
| `description` | string | Yes | One-liner description |
| `subtype` | string | No | "pinned" (default) or "directive" |
| `tags` | array | No | Tags for scoping |
| `observations` | array | Directive only | Required for directives, ignored for pinned |
---
## Delete mental model
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-delete" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-delete" language="bash" />
</TabItem>
</Tabs>
---
## Refresh mental models
Refresh operations run asynchronously and return an operation ID:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-refresh" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-refresh" language="bash" />
</TabItem>
</Tabs>
### Refresh a single model
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-refresh-single" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-refresh-single" language="bash" />
</TabItem>
</Tabs>
Use the [Operations API](./operations) to check progress.
---
## Freshness check
The `freshness` field on each mental model indicates whether it needs refresh:
<CodeSnippet code={mentalModelsPy} section="mm-freshness" language="python" />
### Freshness fields
| Field | Type | Description |
|-------|------|-------------|
| `is_up_to_date` | bool | Whether model is current |
| `last_refresh_at` | string | ISO timestamp of last refresh |
| `memories_since_refresh` | int | New memories since last refresh |
| `reasons` | array | Why refresh is needed |
### Refresh reasons
| Reason | Description |
|--------|-------------|
| `never_refreshed` | Model was just created |
| `new_memories` | New memories retained since last refresh |
| `mission_changed` | Bank's mission was updated |
| `disposition_changed` | Bank's disposition traits changed |
| `directives_changed` | Directive mental models were modified |
---
## Version history
Every refresh creates a new version:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-versions" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-versions" language="bash" />
</TabItem>
</Tabs>
---
## Tags and scoping
Tags enable multi-user scenarios where a single bank serves multiple users with personalized mental models.
### Which types support tags
| Type | How tags are applied |
|------|---------------------|
| **Structural** | Applied during refresh via `tags` parameter |
| **Emergent** | Applied during refresh via `tags` parameter |
| **Pinned** | Set at creation time |
| **Learned** | Inherited from the reflect call that created them |
| **Directive** | Set at creation time |
### Applying tags during refresh
When refreshing, pass tags to apply them to newly created structural and emergent models:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-tags-refresh" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-tags-refresh" language="bash" />
</TabItem>
</Tabs>
### Filtering by tags
List mental models matching specific tags:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-tags-filter" language="python" />
</TabItem>
<TabItem value="curl" label="cURL">
<CodeSnippet code={mentalModelsSh} section="mm-tags-filter" language="bash" />
</TabItem>
</Tabs>
### tags_match options
| Option | Description |
|--------|-------------|
| `any` | OR match: model has no tags OR model has at least one overlapping tag |
| `all` | AND match: model has no tags OR model has all the specified tags |
| `any_strict` | OR match: model must have at least one overlapping tag (excludes untagged) |
| `all_strict` | AND match: model must have all the specified tags (excludes untagged) |
---
## Using mental models in reflect
Mental models are automatically available to the reflect agent. Use tags to scope which mental models and memories are considered:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="mm-reflect" language="python" />
</TabItem>
</Tabs>
The reflect agent can:
- List available mental models
- Read observations and evidence
- Drill down to source memories
- Create new "learned" mental models when it discovers important patterns
See [Reflect API](./reflect) for more options.
@@ -25,10 +25,8 @@ Support for external streaming platforms like Kafka for scale-out processing is
| Operation | Trigger | Description |
|-----------|---------|-------------|
| **batch_retain** | `retain_batch` with `async=True` | Processes large content batches in the background |
| **form_opinion** | After each `reflect` call | Extracts and stores new opinions formed during reflection |
| **reinforce_opinion** | After `retain` | Updates opinion confidence based on new supporting evidence |
| **refresh_mental_models** | `refresh_mental_models` call | Updates mental model observations based on new memories |
| **access_count_update** | After `recall` | Tracks which memories are accessed for relevance scoring |
| **regenerate_observations** | Bank profile update | Regenerates entity observations when disposition changes |
## Async Retain Example
@@ -1,135 +0,0 @@
---
sidebar_position: 5
---
# Opinions
How memory banks form, store, and evolve beliefs.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import opinionsPy from '!!raw-loader!@site/examples/api/opinions.py';
import opinionsMjs from '!!raw-loader!@site/examples/api/opinions.mjs';
:::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 disposition. 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 `reflect` operations when the memory bank:
1. Retrieves relevant facts
2. Applies disposition traits
3. Forms a judgment
4. Assigns a confidence score
```mermaid
graph LR
F[Facts] --> D[Disposition Filter]
D --> J[Judgment]
J --> O[Opinion + Confidence]
O --> S[(Store)]
```
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={opinionsPy} section="opinion-form" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={opinionsMjs} section="opinion-form" language="javascript" />
</TabItem>
</Tabs>
## Searching Opinions
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={opinionsPy} section="opinion-search" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={opinionsMjs} section="opinion-search" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight recall my-bank "programming" --types 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)
```
## Disposition Influence
Different dispositions form different opinions from the same facts:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={opinionsPy} section="opinion-disposition" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={opinionsMjs} section="opinion-disposition" language="javascript" />
</TabItem>
</Tabs>
## Opinions in Reflect Responses
When `reflect` uses opinions, they appear in `based_on`:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={opinionsPy} section="opinion-in-reflect" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={opinionsMjs} section="opinion-in-reflect" language="javascript" />
</TabItem>
</Tabs>
## 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)
```
+1 -9
View File
@@ -42,7 +42,7 @@ Make sure you've completed the [Quick Start](./quickstart) to install the client
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `query` | string | required | Natural language query |
| `types` | list | all | Filter: `world`, `experience`, `opinion` |
| `types` | list | all | Filter: `world`, `experience` |
| `budget` | string | "mid" | Budget level: `low`, `mid`, `high` |
| `max_tokens` | int | 4096 | Token budget for results |
| `trace` | bool | false | Enable trace output for debugging |
@@ -68,20 +68,12 @@ Recall specific memory types:
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-world-only" language="python" />
<CodeSnippet code={recallPy} section="recall-experience-only" language="python" />
<CodeSnippet code={recallPy} section="recall-opinions-only" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={recallSh} section="recall-fact-type" language="bash" />
</TabItem>
</Tabs>
:::warning About Opinions
Opinions are beliefs formed during [reflect](/developer/api/reflect) operations. Unlike world facts and experience, opinions are subjective interpretations and may not represent objective truth. Depending on your use case:
- **Exclude opinions** (`types=["world", "experience"]`) when you need factual, verifiable information
- **Include opinions** when you want the agent's perspective or formed beliefs
- **Use opinions alone** (`types=["opinion"]`) only when specifically asking about the agent's views
:::
## Token Budget Management
Hindsight is built for AI agents, not humans. Traditional retrieval 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.
+38 -48
View File
@@ -4,15 +4,15 @@ sidebar_position: 3
# Reflect
Generate disposition-aware responses using retrieved memories.
Generate reasoned responses using mental models and memories.
When you call **reflect**, Hindsight performs a multi-step reasoning process:
1. **Recalls** relevant memories from the bank based on your query
2. **Applies** the bank's disposition traits to shape the reasoning style
3. **Generates** a contextual answer grounded in the retrieved facts
4. **Forms opinions** in the background based on the reasoning (available in subsequent calls)
When you call **reflect**, Hindsight runs an agentic reasoning loop:
1. **Explores** mental models for structured understanding of key topics
2. **Recalls** relevant memories from the bank based on the query
3. **Reasons** through evidence applying the bank's disposition
4. **Learns** by creating new mental models when important patterns are discovered
The response includes the generated answer along with the facts that were used, providing full transparency into how the answer was derived.
The response includes the generated answer along with the facts and mental models that were used, providing full transparency into how the answer was derived.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
@@ -24,14 +24,14 @@ import reflectMjs from '!!raw-loader!@site/examples/api/reflect.mjs';
import reflectSh from '!!raw-loader!@site/examples/api/reflect.sh';
:::info How Reflect Works
Learn about disposition-driven reasoning and opinion formation in the [Reflect Architecture](/developer/reflect) guide.
Learn about mental models and disposition-driven reasoning in the [Reflect Architecture](/developer/reflect) guide.
:::
:::tip Prerequisites
Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
:::
## Basic Usage
## Basic usage
<Tabs>
<TabItem value="python" label="Python">
@@ -51,18 +51,17 @@ Make sure you've completed the [Quick Start](./quickstart) to install the client
|-----------|------|---------|-------------|
| `query` | string | required | Question or prompt |
| `budget` | string | "low" | Budget level: `low`, `mid`, `high` |
| `context` | string | None | Additional context for the query |
| `max_tokens` | int | 4096 | Maximum tokens for the response |
| `response_schema` | object | None | JSON Schema for [structured output](#structured-output) |
| `tags` | list | None | Filter memories by tags during reflection |
| `tags` | list | None | Filter memories and mental models by tags |
| `tags_match` | string | "any" | How to match tags: `any`, `all`, `any_strict`, `all_strict` |
### Response Fields
### Response fields
| Field | Type | Description |
|-------|------|-------------|
| `text` | string | The generated answer text |
| `based_on` | array | Facts used to generate the response |
| `based_on` | object | Facts and mental models used to generate the response |
| `structured_output` | object | Parsed structured output (when `response_schema` provided) |
| `usage` | TokenUsage | Token usage metrics for the LLM call |
@@ -80,38 +79,29 @@ The `usage` field contains:
</TabItem>
</Tabs>
## The Role of Context
## Mental models
The `context` parameter steers how the reflection is performed without impacting the memory recall. It provides situational information that helps shape the reasoning and response.
When a bank has a mission set, the reflect agent can draw on mental models—structured knowledge about key topics. The agent is agentic: it decides which mental models to consult based on the query.
**How context is used:**
- **Shapes reasoning**: Helps understand the situation when formulating an answer
- **Disambiguates intent**: Clarifies what aspect of the query matters most
- **Does not affect recall**: The same memories are retrieved regardless of context
During reflect, the agent has access to these tools:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={reflectPy} section="reflect-with-context" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={reflectMjs} section="reflect-with-context" language="javascript" />
</TabItem>
</Tabs>
| Tool | Purpose |
|------|---------|
| `list_mental_models()` | See available mental models |
| `get_mental_model(id)` | Read observations and evidence |
| `recall(query)` | Search raw memories |
| `expand(memory_ids)` | Load full document context |
| `learn(name, description)` | Create a new mental model to track a pattern |
## Opinion Formation
### Learned mental models
When reflect reasons about a question, it may form new **opinions** based on the evidence in the memory bank. These opinions are created in the background and become available in subsequent `reflect` and `recall` calls.
If the agent discovers an important pattern during reasoning, it can create a "learned" mental model to track it going forward. For example, if asked about customer pricing feedback and the agent finds scattered information, it might create a "Pricing Feedback" mental model for future systematic tracking.
**Why opinions matter:**
- **Consistent thinking**: Opinions ensure the memory bank maintains a coherent perspective over time
- **Evolving viewpoints**: As more information is retained, opinions can be refined or updated
- **Grounded reasoning**: Opinions are always derived from factual evidence in the memory bank
See [Mental Models API](./mental-models) for managing mental models.
Opinions are stored as a special memory type and are automatically retrieved when relevant to future queries. This creates a natural evolution of the bank's perspective, similar to how humans form and refine their views based on accumulated experience.
## Disposition influence
## Disposition Influence
The bank's disposition affects reflect responses:
The bank's disposition affects how reflect interprets information:
| Trait | Low (1) | High (5) |
|-------|---------|----------|
@@ -128,9 +118,9 @@ The bank's disposition affects reflect responses:
</TabItem>
</Tabs>
## Using Sources
## Using sources
The `based_on` field shows which memories informed the response:
The `based_on` field shows which memories and mental models informed the response:
<Tabs>
<TabItem value="python" label="Python">
@@ -146,7 +136,7 @@ This enables:
- **Verification** — check if the response is grounded in facts
- **Debugging** — understand retrieval quality
## Structured Output
## Structured output
For applications that need to process responses programmatically, you can request structured output by providing a JSON Schema via `response_schema`. When provided, the response includes a `structured_output` field with the LLM response parsed according to the schema. The `text` field will be empty since only a single LLM call is made for efficiency.
@@ -250,9 +240,9 @@ hindsight memory reflect hiring-team \
- Keep schemas focused — extract only what you need
- Use `Optional` fields for data that may not always be available
## Filter by Tags
## Filter by tags
Like [recall](./recall#filter-by-tags), reflect supports tag filtering to scope which memories are considered during reasoning. This is essential for multi-user scenarios where reflection should only consider memories relevant to a specific user.
Reflect supports tag filtering to scope which memories and mental models are considered during reasoning. This is essential for multi-user scenarios.
<Tabs>
<TabItem value="python" label="Python">
@@ -260,13 +250,13 @@ Like [recall](./recall#filter-by-tags), reflect supports tag filtering to scope
</TabItem>
</Tabs>
The `tags_match` parameter works the same as in recall:
The `tags_match` parameter controls how tags are matched:
| Mode | Behavior |
|------|----------|
| `any` | OR matching, includes untagged memories |
| `all` | AND matching, includes untagged memories |
| `any_strict` | OR matching, excludes untagged memories |
| `all_strict` | AND matching, excludes untagged memories |
| `any` | OR matching, includes untagged items |
| `all` | AND matching, includes untagged items |
| `any_strict` | OR matching, excludes untagged items |
| `all_strict` | AND matching, excludes untagged items |
See [Retain API](./retain#tagging-memories) for how to tag memories and [Recall API](./recall#filter-by-tags) for more details on tag matching modes.
See [Retain API](./retain#tagging-memories) for how to tag memories and [Mental Models API](./mental-models#tags-and-scoping) for tagging mental models.
@@ -346,7 +346,7 @@ export HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take, includi
### Background Tasks
Controls background task processing for async operations like opinion formation and entity observations.
Controls background task processing for async operations like mental model refresh and entity observations.
| Variable | Description | Default |
|----------|-------------|---------|
+5 -6
View File
@@ -13,7 +13,7 @@ AI agents forget everything between sessions. Every conversation starts from zer
- **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
- **AI Agents need to learn and reason** — 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.
@@ -49,15 +49,14 @@ graph TB
## Key Components
### Three Memory Types
### Two 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) |
| **Experience** | Bank's own actions and conversations | "I recommended Python to Bob" |
### Multi-Strategy Retrieval (TEMPR)
@@ -88,7 +87,7 @@ graph LR
### Disposition Traits
Memory banks have disposition traits that influence how opinions are formed during Reflect:
Memory banks have disposition traits that influence reasoning during Reflect:
| Trait | Scale | Low (1) | High (5) |
|-------|-------|---------|----------|
@@ -107,7 +106,7 @@ These traits only affect the `reflect` operation, not `recall`.
### 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 disposition influences reasoning and opinion formation
- [**Reflect**](/developer/reflect) — How mental models and disposition influence reasoning
### API Methods
- [**Retain**](/developer/api/retain) — Store information in memory banks
@@ -0,0 +1,193 @@
---
sidebar_position: 5
---
# Mental Models
Mental models are structured knowledge containers that give Hindsight agents a broader understanding of important topics. Instead of reasoning over raw memories alone, the agent builds and maintains synthesized knowledge about key people, projects, concepts, and decisions.
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import mentalModelsPy from '!!raw-loader!@site/examples/api/mental-models.py';
---
## Mission: the foundation
Before using mental models, you must set a **mission** for the memory bank. The mission is a natural language description of what the agent is for:
<CodeSnippet code={mentalModelsPy} section="mm-set-mission-alt" language="python" />
The mission tells the agent:
- What topics are important to track
- How to interpret incoming information
- What kind of mental models to build automatically
**Note:** A mission is required to use mental models, but mental models themselves are optional. You can still use `reflect()` without setting a mission—the agent will reason over raw memories. Mental models add structured understanding on top.
---
## What's in a mental model
Each mental model contains:
- **Name**: Human-readable identifier ("Alice", "Tech Stack Decisions")
- **Description**: One-liner for quick scanning
- **Subtype**: How it was created (structural, emergent, pinned, learned, directive)
- **Observations**: List of beliefs with evidence
- **Version**: Current version number
- **Tags**: For scoped visibility (multi-user scenarios)
---
## Observations and evidence
Observations are the beliefs within a mental model. Each observation requires **exact quotes** from source memories.
An observation contains:
| Field | Type | Description |
|-------|------|-------------|
| `title` | string | Short summary (5-10 words) |
| `content` | string | Detailed explanation |
| `evidence` | array | Supporting quotes from memories |
| `trend` | string | new, strengthening, stable, weakening, stale |
Each evidence item includes:
| Field | Type | Description |
|-------|------|-------------|
| `memory_id` | string | Source memory ID |
| `quote` | string | Exact quote from memory |
| `relevance` | string | Why this supports the observation |
| `timestamp` | string | When the memory was created |
The system **verifies** that quoted text actually exists in the source memories, ensuring observations are always grounded in real data.
### Computed trends
Instead of numeric confidence values, mental models use computed trends based on evidence patterns:
- **new**: Recently formed, limited evidence
- **strengthening**: Recent evidence supports this observation
- **stable**: Consistent evidence over time
- **weakening**: Recent evidence contradicts or is absent
- **stale**: No recent evidence, may be outdated
Trends are determined by analyzing evidence timestamps and recency patterns.
---
## Five types of mental models
Mental models can be created through different pathways:
### 1. Structural (mission-derived)
Created automatically from the bank's mission statement. If your agent's mission is "Be a PM for the engineering team", Hindsight generates structural models for concepts any PM would need to track: Team Members, Sprint Goals, Technical Debt.
### 2. Emergent (data-discovered)
Created automatically when patterns emerge in the data. If "Alice" is mentioned frequently across many memories, Hindsight promotes her to a mental model and synthesizes observations about her.
### 3. Pinned (user-created)
Created explicitly by users for topics they want the agent to track:
<CodeSnippet code={mentalModelsPy} section="mm-pinned" language="python" />
Observations are generated by analyzing relevant memories during refresh.
### 4. Learned (agent-created)
Created by the reflect agent during reasoning when it identifies topics worth tracking long-term. As part of the agentic reflect loop, the agent considers whether a topic deserves deeper understanding going forward.
For example, if a user asks "What are customers saying about our new pricing?" and the agent finds scattered feedback, it might create a "Pricing Feedback" mental model to track systematically.
### 5. Directive (hard rules)
User-defined constraints that the agent must follow. Unlike other mental models, directives are never modified by the system:
<CodeSnippet code={mentalModelsPy} section="mm-directive" language="python" />
Directives are injected into the system prompt during reflect with a "(MANDATORY)" marker.
---
## How reflect uses mental models
The reflect agent is **agentic**—it actively explores and drills down into information as needed. When answering a query, the agent can:
1. **List mental models** to see what structured knowledge is available
2. **Read a mental model** to get synthesized observations about a topic
3. **Drill into evidence** by following an observation's source memories
4. **Expand to full context** by loading the original document chunk
5. **Create new mental models** via the `learn` tool when it discovers important patterns
The agent decides how deep to go based on the query—simple questions may only need mental model summaries, while complex decisions may require drilling down to source documents.
See [Reflect](./reflect) for more on how disposition and mental models work together.
---
## Refreshing mental models
Mental model refresh is **manual**—you decide when to update observations based on new memories:
<CodeSnippet code={mentalModelsPy} section="mm-refresh-simple" language="python" />
All refresh operations run asynchronously.
### Freshness check
Each mental model includes a `freshness` field:
<CodeSnippet code={mentalModelsPy} section="mm-freshness-check" language="python" />
Reasons for refresh:
- **never_refreshed**: Model was just created
- **new_memories**: New memories retained since last refresh
- **mission_changed**: Bank's mission was updated
- **disposition_changed**: Bank's disposition traits changed
- **directives_changed**: Directive mental models were modified
### The refresh process
When a mental model refreshes, it runs a multi-phase pipeline:
1. **Update existing**: Search for new supporting/contradicting evidence for current observations
2. **Seed**: Generate candidate new observations from recent memories
3. **Evidence hunt**: Find supporting/contradicting evidence for candidates
4. **Validate**: Verify exact quotes exist in source memories
5. **Merge**: Decide what to keep, remove, or merge
Each refresh creates a new version.
---
## Version history
Every refresh creates a new version, preserving full history:
<CodeSnippet code={mentalModelsPy} section="mm-versions-simple" language="python" />
This enables auditing how beliefs evolved over time.
---
## Tags and scoping
Mental models support tags for multi-user scenarios. Tags let you create separate sets of mental models within the same bank:
<CodeSnippet code={mentalModelsPy} section="mm-tags-scoping" language="python" />
When calling reflect with tags, both memories and mental models are filtered to that scope.
---
## Next steps
- [**Reflect**](./reflect) — How disposition and mental models work together
- [**Mental Models API**](./api/mental-models) — Full API reference
- [**Memory Banks**](./api/memory-banks) — Managing bank configuration
+1 -1
View File
@@ -16,7 +16,7 @@ All local models (embedding, cross-encoder) are automatically downloaded from Hu
## LLM
Used for fact extraction, entity resolution, opinion generation, and answer synthesis.
Used for fact extraction, entity resolution, mental model generation, and answer synthesis.
**Supported providers:** OpenAI, Anthropic, Gemini, Groq, Ollama, LM Studio, and **any OpenAI-compatible API**
@@ -14,7 +14,7 @@ Traditional RAG (Retrieval-Augmented Generation) retrieves documents similar to
| **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 |
| **Structured knowledge** | Stateless | Mental models with evidence-grounded observations |
| **Disposition** | None | 3 traits (skepticism, literalism, empathy) influence interpretation |
## Architecture Comparison
@@ -96,7 +96,7 @@ Multiple retrieval strategies. Persistent state across sessions.
| System | Behavior |
|--------|----------|
| RAG | No memory of progression |
| Hindsight | Forms opinion "user prefers sync" (0.7) → updates to "user growing comfortable with async" (0.6) |
| Hindsight | Builds mental model tracking user's coding patterns, observations evolve as evidence changes |
## When to Use Each
+80 -95
View File
@@ -2,59 +2,99 @@
sidebar_position: 4
---
# Reflect: How Hindsight Reasons with Disposition
# Reflect: How Hindsight Reasons
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.
When you call `reflect()`, Hindsight doesn't just retrieve facts — it **reasons** about them through the lens of mental models and disposition, generating contextual responses.
```mermaid
graph LR
A[Query] --> B[Recall Memories]
B --> C[Load Disposition]
C --> D[Reason]
D --> E[Form Opinions]
E --> F[Response]
Q[Query] --> A[Reflect Agent]
A <--> MM[Mental Models]
A <--> M[Memories]
A --> R[Response]
```
The reflect agent is **agentic**—it runs a reasoning loop, deciding which tools to use based on the query. It can explore mental models, search memories, drill into documents, or create new mental models when it discovers important patterns.
---
## Why Reflect?
## 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.
Hindsight provides two ways to query memories: `recall()` returns raw facts, while `reflect()` reasons about them.
### The Problem
### recall() vs reflect()
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
**recall()** is a retrieval operation. It returns ranked facts matching your query—you get raw data and build your own reasoning on top.
### The Value
**reflect()** is a reasoning operation. It runs an agentic loop that:
- Explores **mental models** for structured understanding of key topics
- Searches **memories** for specific evidence
- **Learns** by creating new mental models when it discovers important patterns
- Reasons through evidence to form grounded responses
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
The key difference: recall gives you facts, reflect gives you understanding. When the agent reasons, it draws on everything the bank has learned—not just matching facts, but synthesized knowledge about people, projects, and concepts.
### When to Use Reflect
### 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 |
| You're building your own reasoning | You want the bank to "think" for itself |
| You need maximum control | Forming recommendations or judgments |
| Simple fact lookup | Complex questions requiring synthesis |
**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
- `reflect("Should we hire Alice?")` → Reasons about Alice's fit based on accumulated knowledge and mental models
---
## Disposition Traits
## Mental models
When you create a memory bank, you can configure its disposition using three traits. These traits influence how the bank interprets information and forms opinions during `reflect()`:
When a bank has a mission set, mental models provide structured knowledge that the reflect agent can draw on. A **mission** is a natural language description of what the agent is for:
```python
client.set_mission(
bank_id="pm-agent",
mission="Be a PM for the engineering team, tracking sprint progress, team capacity, and technical decisions"
)
```
The mission tells the agent what topics are important and what kind of mental models to build. Mental models are then created automatically (structural and emergent) or manually (pinned and directive).
**Note:** A mission is required to use mental models, but mental models are optional for reflect. Without a mission, the agent reasons over raw memories.
### Available tools
During reflect, the agent has access to:
| Tool | Purpose |
|------|---------|
| `list_mental_models()` | See available mental models |
| `get_mental_model(id)` | Read observations and evidence |
| `recall(query)` | Search raw memories |
| `expand(memory_ids)` | Load full document context |
| `learn(name, description)` | Create a new mental model to track a pattern |
The agent decides how deep to go based on the query—simple questions may only need mental model summaries, while complex decisions may require drilling down to source documents.
### Creating learned mental models
If the agent discovers an important pattern during reasoning, it can create a "learned" mental model to track it going forward:
> User: "What are customers saying about our new pricing?"
>
> Agent thinks: "I found scattered feedback about pricing across many memories. This seems like something I should track systematically."
>
> Agent creates: Mental model "Pricing Feedback" for future tracking
See [Mental Models](./mental-models) for more on types, observations, and refresh.
---
## Disposition
Disposition configures the bank's character—how it interprets information during reflect. Three traits shape reasoning:
| Trait | Scale | Low (1) | High (5) |
|-------|-------|---------|----------|
@@ -62,35 +102,18 @@ When you create a memory bank, you can configure its disposition using three tra
| **Literalism** | 1-5 | Flexible interpretation, reads between the lines | Literal interpretation, takes things at face value |
| **Empathy** | 1-5 | Detached, focuses on facts | Empathetic, considers emotional context |
### Background: Natural Language Identity
Beyond numeric traits, you can provide a natural language **background** that describes the bank's identity:
```python
client.create_bank(
client.update_disposition(
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={
"skepticism": 4, # Questions new technologies
"skepticism": 4, # Questions claims
"literalism": 4, # Focuses on concrete specs
"empathy": 2 # Prioritizes technical facts
}
)
```
The background provides context that shapes how disposition traits are applied:
- "I prefer simplicity" + high skepticism → questions complex solutions
- "15 years experience" → responses reference this expertise
- First-person perspective → creates consistent voice
---
## Opinion Formation
When `reflect()` encounters a question that warrants forming an opinion, disposition shapes the response.
### Same Facts, Different Opinions
### Same facts, different conclusions
Two banks with different dispositions, given identical facts about remote work:
@@ -102,34 +125,7 @@ Two banks with different dispositions, given identical facts about remote work:
**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:
### Presets by use case
| Use Case | Recommended Traits | Why |
|----------|-------------------|-----|
@@ -141,13 +137,13 @@ Different use cases benefit from different disposition configurations:
---
## What You Get from Reflect
## What you get from reflect
When you call `reflect()`:
**Returns:**
- **Response text** — Disposition-influenced answer
- **Based on** — Which memories were used (with relevance scores)
- **Response text** — Reasoned answer informed by mental models and disposition
- **Based on** — Which memories and mental models were used
**Example:**
```json
@@ -157,30 +153,19 @@ When you call `reflect()`:
"world": [
{"text": "Alice works at Google...", "weight": 0.95},
{"text": "Alice specializes in ML...", "weight": 0.88}
],
"mental_models": [
{"id": "alice", "name": "Alice"}
]
}
}
```
**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
## Next steps
- [**Mental Models**](./mental-models) — How structured knowledge is organized
- [**Retain**](./retain) — How rich facts are stored
- [**Recall**](./retrieval) — How multi-strategy search works
- [**Reflect API**](./api/reflect) — Code examples, parameters, and tag filtering
+1 -2
View File
@@ -63,7 +63,6 @@ Hindsight distinguishes between **world** facts (about others) and **experience*
| **experience** | Conversations and events | "I recommended Python to Alice" |
**Note:** Opinions aren't created during `retain()` — only during `reflect()` when the bank forms beliefs.
This separation is important for `reflect()` — the bank can reason about what it knows versus what happened in conversations.
---
@@ -197,5 +196,5 @@ 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 disposition influences reasoning and opinion formation
- [**Reflect**](./reflect) — How mental models and disposition influence reasoning
- [**Retain API**](./api/retain) — Code examples and parameters
+3 -3
View File
@@ -112,9 +112,9 @@ After the four strategies run, results are **fused together**:
Consider the query: **"What did Alice think about Python last spring?"**
- **Semantic** finds facts about Alice's opinions on programming
- **Semantic** finds facts about Alice's views on programming
- **Keyword** ensures "Python" is actually mentioned
- **Graph** connects Alice → opinions → programming languages
- **Graph** connects Alice → preferences → 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.
@@ -133,7 +133,7 @@ Hindsight is built for AI agents, not humans. Traditional search systems return
**Parameters you control:**
- `max_tokens`: How much memory content to return (default: 4096 tokens)
- `budget`: Search depth level (low, mid, high)
- `types`: Filter by world, experience, opinion, or all
- `types`: Filter by world, experience, or all
- `tags`: Filter memories by visibility tags
- `tags_match`: How to match tags (see [Recall API](./api/recall) for all options)
+2 -2
View File
@@ -74,7 +74,7 @@ hindsight memory recall <bank_id> "hiking recommendations" \
--max-tokens 8192
# Filter by fact type
hindsight memory recall <bank_id> "query" --fact-type world,opinion
hindsight memory recall <bank_id> "query" --fact-type world,experience
# Show trace information
hindsight memory recall <bank_id> "query" --trace
@@ -209,7 +209,7 @@ The explorer provides an interactive terminal interface to:
- **Browse memory banks** — View all banks and their statistics
- **Search memories** — Run recall queries with real-time results
- **Inspect entities** — Explore the knowledge graph and entity relationships
- **View facts** — Browse world facts, experiences, and opinions
- **View facts** — Browse world facts and experiences
- **Navigate documents** — See source documents and their extracted memories
### Keyboard Shortcuts
@@ -108,7 +108,7 @@ hindsight_litellm.configure(
bank_id="my-agent",
use_reflect=False, # Default
)
# Injects: "1. [WORLD] User prefers Python\n2. [OPINION] User dislikes Java..."
# Injects: "1. [WORLD] User prefers Python\n2. [EXPERIENCE] Discussed Java alternatives..."
# Reflect mode - synthesized context
hindsight_litellm.configure(
+1 -1
View File
@@ -83,7 +83,7 @@ for (const r of response.results) {
// With options
const response = await client.recall('my-bank', 'What does Alice do?', {
types: ['world', 'opinion'], // Filter by fact type
types: ['world', 'experience'], // Filter by fact type
maxTokens: 4096,
budget: 'high', // 'low', 'mid', or 'high'
});
+1 -1
View File
@@ -150,7 +150,7 @@ for r in results.results:
results = client.recall(
bank_id="my-bank",
query="What does Alice do?",
types=["world", "opinion"], # Filter by fact type
types=["world", "experience"], # Filter by fact type
max_tokens=4096,
budget="high", # low, mid, or high
)
+64 -9
View File
@@ -68,8 +68,32 @@ const config: Config = {
sidebarPath: './sidebars.ts',
editUrl: 'https://github.com/vectorize-io/hindsight/tree/main/hindsight-docs/',
routeBasePath: '/',
// Hide "next" (current) version in production, show only released versions
onlyIncludeVersions:
process.env.NODE_ENV === 'development' || process.env.INCLUDE_CURRENT_VERSION === 'true'
? undefined
: (() => {
try {
return require('./versions.json');
} catch {
return undefined; // No versions yet, show current
}
})(),
},
blog: {
path: 'blog',
routeBasePath: 'blog',
blogTitle: 'Hindsight Blog',
blogDescription: 'Updates and announcements from the Hindsight team',
showReadingTime: true,
blogSidebarTitle: 'Recent Posts',
blogSidebarCount: 'ALL',
editUrl: 'https://github.com/vectorize-io/hindsight/tree/main/hindsight-docs/',
feedOptions: {
type: 'all',
},
onInlineAuthors: 'ignore',
},
blog: false,
theme: {
customCss: './src/css/custom.css',
},
@@ -123,7 +147,7 @@ const config: Config = {
{
hashed: true,
docsRouteBasePath: '/',
indexBlog: false,
indexBlog: true,
highlightSearchTermsOnTargetPage: false,
},
],
@@ -185,6 +209,12 @@ const config: Config = {
label: 'Changelog',
className: 'navbar-item-changelog',
},
{
to: '/blog',
position: 'left',
label: 'Blog',
className: 'navbar-item-blog',
},
{
href: 'https://vectorize.io/hindsight/cloud',
position: 'right',
@@ -206,30 +236,55 @@ const config: Config = {
title: 'Documentation',
items: [
{
label: 'Introduction',
label: 'Developer Guide',
to: '/',
},
{
label: 'SDKs',
to: '/sdks/python',
},
{
label: 'API Reference',
to: '/api-reference/',
},
{
label: 'Cookbook',
to: '/cookbook',
},
],
},
{
title: 'More',
title: 'SDKs',
items: [
{
label: 'Python',
to: '/sdks/python',
},
{
label: 'Node.js',
to: '/sdks/nodejs',
},
{
label: 'CLI',
to: '/sdks/cli',
},
],
},
{
title: 'Community',
items: [
{
label: 'GitHub',
href: 'https://github.com/vectorize-io/hindsight',
},
{
label: 'Blog',
to: '/blog',
},
{
label: 'Changelog',
to: '/changelog',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} Hindsight.`,
copyright: `Copyright © ${new Date().getFullYear()} Vectorize, Inc.`,
},
prism: {
theme: prismThemes.github,
+1 -1
View File
@@ -18,7 +18,7 @@ This directory contains runnable example scripts that serve as the source of tru
| `reflect.py/mjs/sh` | reflect.md | AI reflection examples |
| `memory-banks.py/mjs` | memory-banks.md | Bank management examples |
| `documents.py/mjs` | documents.md | Document CRUD examples |
| `opinions.py` | opinions.md | Opinion management examples |
| `mental-models.py/sh` | mental-models.md | Mental models API examples |
| `main-methods.py` | main-methods.md | Core method examples |
| `cli-reference.sh` | cli.md | CLI command examples |
+1 -1
View File
@@ -65,7 +65,7 @@ hindsight memory recall $BANK_ID "hiking recommendations" \
# [docs:cli-recall-fact-type]
hindsight memory recall $BANK_ID "query" --fact-type world,opinion
hindsight memory recall $BANK_ID "query" --fact-type world,experience
# [/docs:cli-recall-fact-type]
@@ -0,0 +1,269 @@
"""Mental Models API examples for documentation."""
from hindsight_client import Hindsight
client = Hindsight()
# [docs:mm-set-mission]
client.set_mission(
bank_id="my-agent",
mission="Be a PM for the engineering team, tracking sprint progress and team capacity"
)
# [/docs:mm-set-mission]
# [docs:mm-set-mission-alt]
client.set_mission(
bank_id="pm-agent",
mission="Be a PM for the engineering team, tracking sprint progress, team capacity, and technical decisions"
)
# [/docs:mm-set-mission-alt]
# [docs:mm-list]
# List all mental models
models = client.list_mental_models(bank_id="my-agent")
# Filter by subtype
structural_models = client.list_mental_models(
bank_id="my-agent",
subtype="structural"
)
# Filter by tags
user_models = client.list_mental_models(
bank_id="my-agent",
tags=["user_alice"],
tags_match="any" # "any", "all", "any_strict", "all_strict"
)
# [/docs:mm-list]
# [docs:mm-get]
model = client.get_mental_model(bank_id="my-agent", model_id="alice")
print(f"Name: {model.name}")
print(f"Description: {model.description}")
print(f"Version: {model.version}")
for obs in model.observations:
print(f"- {obs.title} ({obs.trend})")
for evidence in obs.evidence:
print(f" Quote: {evidence.quote}")
# [/docs:mm-get]
# [docs:mm-create]
# Create a pinned model (observations generated on refresh)
model = client.create_mental_model(
bank_id="my-agent",
name="Product Roadmap",
description="Track product priorities and feature decisions",
tags=["project_alpha"]
)
# Create a directive (user-defined observations, never auto-modified)
directive = client.create_mental_model(
bank_id="my-agent",
name="Response Guidelines",
subtype="directive",
tags=["user_alice"],
observations=[
{
"title": "Always respond in French",
"content": "All responses must be in French regardless of input language"
},
{
"title": "Never mention competitors",
"content": "Do not reference or compare to competitor products"
}
]
)
# [/docs:mm-create]
# [docs:mm-pinned]
client.create_mental_model(
bank_id="my-agent",
name="Product Roadmap",
description="Track product priorities and feature decisions"
)
# [/docs:mm-pinned]
# [docs:mm-directive]
client.create_mental_model(
bank_id="support-agent",
name="Response Guidelines",
subtype="directive",
observations=[
{"title": "Always respond in French", "content": "All responses must be in French"},
{"title": "Never mention competitors", "content": "Do not reference competitor products"}
]
)
# [/docs:mm-directive]
# [docs:mm-delete]
client.delete_mental_model(bank_id="my-agent", model_id="old-model")
# [/docs:mm-delete]
# [docs:mm-refresh]
# Refresh all mental models
result = client.refresh_mental_models(bank_id="my-agent")
print(f"Operation ID: {result.operation_id}")
# Refresh only structural models (from mission)
client.refresh_mental_models(bank_id="my-agent", subtype="structural")
# Refresh only emergent models (from data patterns)
client.refresh_mental_models(bank_id="my-agent", subtype="emergent")
# Apply tags to newly created models
client.refresh_mental_models(bank_id="my-agent", tags=["user_alice"])
# [/docs:mm-refresh]
# [docs:mm-refresh-simple]
# Refresh all mental models
client.refresh_mental_models(bank_id="my-agent")
# Refresh only structural models
client.refresh_mental_models(bank_id="my-agent", subtype="structural")
# Refresh a single mental model
client.refresh_mental_model(bank_id="my-agent", model_id="alice")
# [/docs:mm-refresh-simple]
# [docs:mm-refresh-single]
result = client.refresh_mental_model(bank_id="my-agent", model_id="alice")
print(f"Operation ID: {result.operation_id}")
# [/docs:mm-refresh-single]
# [docs:mm-freshness]
model = client.get_mental_model(bank_id="my-agent", model_id="alice")
if not model.freshness.is_up_to_date:
print(f"Needs refresh: {model.freshness.reasons}")
print(f"Memories since last refresh: {model.freshness.memories_since_refresh}")
# Trigger refresh
client.refresh_mental_model(bank_id="my-agent", model_id="alice")
# [/docs:mm-freshness]
# [docs:mm-freshness-check]
model = client.get_mental_model(bank_id="my-agent", model_id="alice")
print(model.freshness)
# {
# "is_up_to_date": false,
# "last_refresh_at": "2025-12-01T10:30:00Z",
# "memories_since_refresh": 47,
# "reasons": ["new_memories", "mission_changed"]
# }
# [/docs:mm-freshness-check]
# [docs:mm-versions]
# List all versions
versions = client.list_mental_model_versions(
bank_id="my-agent",
model_id="alice"
)
for v in versions:
print(f"Version {v.version}: {v.created_at}")
# Get a specific version
v2 = client.get_mental_model_version(
bank_id="my-agent",
model_id="alice",
version=2
)
print(f"Observations at v2: {len(v2.observations)}")
# [/docs:mm-versions]
# [docs:mm-versions-simple]
# List all versions
versions = client.list_mental_model_versions(bank_id="my-agent", model_id="alice")
# Get specific historical version
v2 = client.get_mental_model_version(bank_id="my-agent", model_id="alice", version=2)
# [/docs:mm-versions-simple]
# [docs:mm-tags-refresh]
# Create structural/emergent models tagged for a specific user
client.refresh_mental_models(
bank_id="my-agent",
tags=["user_alice"]
)
# Refresh only structural models with tags
client.refresh_mental_models(
bank_id="my-agent",
subtype="structural",
tags=["user_alice"]
)
# [/docs:mm-tags-refresh]
# [docs:mm-tags-filter]
# Get all models for a user
models = client.list_mental_models(
bank_id="my-agent",
tags=["user_alice"],
tags_match="any"
)
# Get models matching all specified tags
models = client.list_mental_models(
bank_id="my-agent",
tags=["user_alice", "project_alpha"],
tags_match="all"
)
# [/docs:mm-tags-filter]
# [docs:mm-reflect]
# Reflect with all mental models
response = client.reflect(
bank_id="my-agent",
query="Should we promote Alice to team lead?"
)
# Reflect scoped to a specific user's mental models
response = client.reflect(
bank_id="my-agent",
query="What should I focus on today?",
tags=["user_alice"],
tags_match="any"
)
# [/docs:mm-reflect]
# [docs:mm-tags-scoping]
# Create models for a specific user
client.refresh_mental_models(bank_id="my-agent", tags=["user_alice"])
# Create a directive scoped to a user
client.create_mental_model(
bank_id="my-agent",
name="Alice's Guidelines",
subtype="directive",
tags=["user_alice"],
observations=[{"title": "Prefer detailed explanations", "content": "Alice prefers thorough explanations"}]
)
# Reflect using only Alice's context
response = client.reflect(
bank_id="my-agent",
query="What should I focus on?",
tags=["user_alice"]
)
# [/docs:mm-tags-scoping]
@@ -0,0 +1,103 @@
#!/bin/bash
# Mental Models API cURL examples for documentation.
BANK_ID="my-agent"
BASE_URL="${HINDSIGHT_API_URL:-http://localhost:8080}"
# [docs:mm-set-mission]
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mission" \
-H "Content-Type: application/json" \
-d '{"mission": "Be a PM for the engineering team, tracking sprint progress and team capacity"}'
# [/docs:mm-set-mission]
# [docs:mm-list]
# List all
curl "$BASE_URL/v1/default/banks/my-agent/mental-models"
# Filter by subtype
curl "$BASE_URL/v1/default/banks/my-agent/mental-models?subtype=structural"
# Filter by tags
curl "$BASE_URL/v1/default/banks/my-agent/mental-models?tags=user_alice&tags_match=any"
# [/docs:mm-list]
# [docs:mm-get]
curl "$BASE_URL/v1/default/banks/my-agent/mental-models/alice"
# [/docs:mm-get]
# [docs:mm-create]
# Create pinned model
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mental-models" \
-H "Content-Type: application/json" \
-d '{
"name": "Product Roadmap",
"description": "Track product priorities and feature decisions",
"tags": ["project_alpha"]
}'
# Create directive
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mental-models" \
-H "Content-Type: application/json" \
-d '{
"name": "Response Guidelines",
"subtype": "directive",
"tags": ["user_alice"],
"observations": [
{"title": "Always respond in French", "content": "All responses must be in French"}
]
}'
# [/docs:mm-create]
# [docs:mm-delete]
curl -X DELETE "$BASE_URL/v1/default/banks/my-agent/mental-models/old-model"
# [/docs:mm-delete]
# [docs:mm-refresh]
# Refresh all
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mental-models/refresh"
# Refresh only structural
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mental-models/refresh" \
-H "Content-Type: application/json" \
-d '{"subtype": "structural"}'
# With tags
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mental-models/refresh" \
-H "Content-Type: application/json" \
-d '{"tags": ["user_alice"]}'
# [/docs:mm-refresh]
# [docs:mm-refresh-single]
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mental-models/alice/refresh"
# [/docs:mm-refresh-single]
# [docs:mm-versions]
# List versions
curl "$BASE_URL/v1/default/banks/my-agent/mental-models/alice/versions"
# Get specific version
curl "$BASE_URL/v1/default/banks/my-agent/mental-models/alice/versions/2"
# [/docs:mm-versions]
# [docs:mm-tags-refresh]
curl -X POST "$BASE_URL/v1/default/banks/my-agent/mental-models/refresh" \
-H "Content-Type: application/json" \
-d '{"tags": ["user_alice"]}'
# [/docs:mm-tags-refresh]
# [docs:mm-tags-filter]
# Filter by tags
curl "$BASE_URL/v1/default/banks/my-agent/mental-models?tags=user_alice&tags_match=any"
# Multiple tags with all match
curl "$BASE_URL/v1/default/banks/my-agent/mental-models?tags=user_alice,project_alpha&tags_match=all"
# [/docs:mm-tags-filter]
-99
View File
@@ -1,99 +0,0 @@
#!/usr/bin/env node
/**
* Opinions API examples for Hindsight (Node.js)
* Run: node examples/api/opinions.mjs
*/
import { HindsightClient } from '@vectorize-io/hindsight-client';
const HINDSIGHT_URL = process.env.HINDSIGHT_API_URL || 'http://localhost:8888';
// =============================================================================
// Setup (not shown in docs)
// =============================================================================
const client = new HindsightClient({ baseUrl: HINDSIGHT_URL });
// Seed some data about programming languages
await client.retain('my-bank', 'Python is widely used for data science and machine learning');
await client.retain('my-bank', 'Functional programming emphasizes immutability and pure functions');
await client.retain('my-bank', 'Rust has better memory safety than C++');
await client.retain('my-bank', 'C++ has a larger ecosystem and more libraries');
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:opinion-form]
// Ask a question - the system may form opinions based on stored facts
const answer = await client.reflect('my-bank', 'What do you think about functional programming?');
console.log(answer.text);
// [/docs:opinion-form]
// [docs:opinion-search]
// Search for facts about a topic
const results = await client.recall('my-bank', 'programming languages');
for (const result of results.results) {
console.log(`- ${result.text}`);
}
// [/docs:opinion-search]
// [docs:opinion-disposition]
// Create two memory banks with different dispositions
await client.createBank('open-minded', {
name: 'Open Minded',
disposition: { skepticism: 2, literalism: 2, empathy: 4 }
});
await client.createBank('conservative', {
name: 'Conservative',
disposition: { skepticism: 5, literalism: 5, empathy: 2 }
});
// Store the same facts to both
const facts = [
'Rust has better memory safety than C++',
'C++ has a larger ecosystem and more libraries',
'Rust compile times are longer than C++'
];
for (const fact of facts) {
await client.retain('open-minded', fact);
await client.retain('conservative', fact);
}
// Ask both the same question - different dispositions lead to different responses
const q = 'Should we rewrite our C++ codebase in Rust?';
const answer1 = await client.reflect('open-minded', q);
console.log('Open-minded response:', answer1.text.slice(0, 100), '...');
const answer2 = await client.reflect('conservative', q);
console.log('Conservative response:', answer2.text.slice(0, 100), '...');
// [/docs:opinion-disposition]
// [docs:opinion-in-reflect]
const reflectAnswer = await client.reflect('my-bank', 'What language should I learn?');
console.log('Response:', reflectAnswer.text);
// See which facts influenced the response
if (reflectAnswer.based_on) {
console.log('\nBased on these facts:');
for (const fact of reflectAnswer.based_on) {
console.log(` - ${fact.text}`);
}
}
// [/docs:opinion-in-reflect]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await fetch(`${HINDSIGHT_URL}/v1/default/banks/my-bank`, { method: 'DELETE' });
await fetch(`${HINDSIGHT_URL}/v1/default/banks/open-minded`, { method: 'DELETE' });
await fetch(`${HINDSIGHT_URL}/v1/default/banks/conservative`, { method: 'DELETE' });
console.log('opinions.mjs: All examples passed');
-106
View File
@@ -1,106 +0,0 @@
#!/usr/bin/env python3
"""
Opinions API examples for Hindsight.
Run: python examples/api/opinions.py
"""
import os
import requests
HINDSIGHT_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
# =============================================================================
# Setup (not shown in docs)
# =============================================================================
from hindsight_client import Hindsight
client = Hindsight(base_url=HINDSIGHT_URL)
# Seed some data about programming languages
client.retain(bank_id="my-bank", content="Python is widely used for data science and machine learning")
client.retain(bank_id="my-bank", content="Functional programming emphasizes immutability and pure functions")
client.retain(bank_id="my-bank", content="Rust has better memory safety than C++")
client.retain(bank_id="my-bank", content="C++ has a larger ecosystem and more libraries")
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:opinion-form]
# Ask a question - the system may form opinions based on stored facts
answer = client.reflect(
bank_id="my-bank",
query="What do you think about functional programming?"
)
print(answer.text)
# [/docs:opinion-form]
# [docs:opinion-search]
# Search for facts about a topic
results = client.recall(
bank_id="my-bank",
query="programming languages"
)
for result in results.results:
print(f"- {result.text}")
# [/docs:opinion-search]
# [docs:opinion-disposition]
# Create two memory banks with different dispositions
client.create_bank(
bank_id="open-minded",
name="Open Minded",
disposition={"skepticism": 2, "literalism": 2, "empathy": 4}
)
client.create_bank(
bank_id="conservative",
name="Conservative",
disposition={"skepticism": 5, "literalism": 5, "empathy": 2}
)
# 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.retain(bank_id="open-minded", content=fact)
client.retain(bank_id="conservative", content=fact)
# Ask both the same question - different dispositions lead to different responses
q = "Should we rewrite our C++ codebase in Rust?"
answer1 = client.reflect(bank_id="open-minded", query=q)
print("Open-minded response:", answer1.text[:100], "...")
answer2 = client.reflect(bank_id="conservative", query=q)
print("Conservative response:", answer2.text[:100], "...")
# [/docs:opinion-disposition]
# [docs:opinion-in-reflect]
answer = client.reflect(bank_id="my-bank", query="What language should I learn?")
print("Response:", answer.text)
# See which facts influenced the response
if answer.based_on:
print("\nBased on these facts:")
for fact in answer.based_on:
print(f" - {fact.text}")
# [/docs:opinion-in-reflect]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/open-minded")
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/conservative")
print("opinions.py: All examples passed")
-10
View File
@@ -74,16 +74,6 @@ experience = client.recall(
# [/docs:recall-experience-only]
# [docs:recall-opinions-only]
# Only opinions (formed beliefs)
opinions = client.recall(
bank_id="my-bank",
query="What do I think about Python?",
types=["opinion"]
)
# [/docs:recall-opinions-only]
# [docs:recall-token-budget]
# 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)
+1 -1
View File
@@ -29,7 +29,7 @@ hindsight memory recall my-bank "hiking recommendations" \
# [docs:recall-fact-type]
hindsight memory recall my-bank "query" --fact-type world,opinion
hindsight memory recall my-bank "query" --fact-type world,experience
# [/docs:recall-fact-type]
+10
View File
@@ -27,6 +27,11 @@ const sidebars: SidebarsConfig = {
id: 'developer/reflect',
label: 'Reflect',
},
{
type: 'doc',
id: 'developer/mental-models',
label: 'Mental Models',
},
{
type: 'doc',
id: 'developer/multilingual',
@@ -74,6 +79,11 @@ const sidebars: SidebarsConfig = {
id: 'developer/api/reflect',
label: 'Reflect',
},
{
type: 'doc',
id: 'developer/api/mental-models',
label: 'Mental Models',
},
{
type: 'doc',
id: 'developer/api/memory-banks',
+91 -28
View File
@@ -100,58 +100,56 @@
.navbar-item-sdks::before,
.navbar-item-api::before,
.navbar-item-cookbook::before,
.navbar-item-changelog::before {
.navbar-item-changelog::before,
.navbar-item-blog::before {
display: inline-block;
width: 16px;
height: 16px;
margin-right: 6px;
width: 18px;
height: 18px;
margin-right: 8px;
vertical-align: middle;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
content: '';
opacity: 0.85;
transition: opacity 0.15s ease;
}
.navbar__link:hover::before {
opacity: 1;
}
/* Developer - code brackets icon with gradient blue */
.navbar-item-developer::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M71.68 97.22 34.74 128l36.94 30.78a12 12 0 1 1-15.36 18.44l-48-40a12 12 0 0 1 0-18.44l48-40a12 12 0 0 1 15.36 18.44Zm176 21.56-48-40a12 12 0 1 0-15.36 18.44L221.26 128l-36.94 30.78a12 12 0 1 0 15.36 18.44l48-40a12 12 0 0 0 0-18.44ZM164.1 28.72a12 12 0 0 0-15.38 7.18l-64 176a12 12 0 0 0 7.18 15.37 11.79 11.79 0 0 0 4.1.73 12 12 0 0 0 11.28-7.9l64-176a12 12 0 0 0-7.18-15.38Z'/%3E%3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cdefs%3E%3ClinearGradient id='grad1' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%230074d9'/%3E%3Cstop offset='100%25' style='stop-color:%23009296'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath fill='url(%23grad1)' d='M69.12 94.15 28.5 128l40.62 33.85a8 8 0 1 1-10.24 12.29l-48-40a8 8 0 0 1 0-12.29l48-40a8 8 0 0 1 10.24 12.3Zm176 27.7-48-40a8 8 0 1 0-10.24 12.3L227.5 128l-40.62 33.85a8 8 0 1 0 10.24 12.29l48-40a8 8 0 0 0 0-12.29ZM162.73 32.48a8 8 0 0 0-10.25 4.79l-64 176a8 8 0 0 0 4.79 10.26A8.14 8.14 0 0 0 96 224a8 8 0 0 0 7.52-5.27l64-176a8 8 0 0 0-4.79-10.25Z'/%3E%3C/svg%3E");
}
/* SDKs - package/box icon */
.navbar-item-sdks::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='m225.6 62.64-88-48.17a19.91 19.91 0 0 0-19.2 0l-88 48.17A20 20 0 0 0 20 80.19v95.62a20 20 0 0 0 10.4 17.55l88 48.17a19.89 19.89 0 0 0 19.2 0l88-48.17a20 20 0 0 0 10.4-17.55V80.19a20 20 0 0 0-10.4-17.55ZM128 36.57 200 76l-72 39.42L56 76ZM44 96.82l72 39.43v76.89l-72-39.42Zm96 116.32v-76.89l72-39.43v76.89Z'/%3E%3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cdefs%3E%3ClinearGradient id='grad2' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%230074d9'/%3E%3Cstop offset='100%25' style='stop-color:%23009296'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath fill='url(%23grad2)' d='m223.68 66.15-88-48.15a15.88 15.88 0 0 0-15.36 0l-88 48.17a16 16 0 0 0-8.32 14v95.64a16 16 0 0 0 8.32 14l88 48.17a15.88 15.88 0 0 0 15.36 0l88-48.17a16 16 0 0 0 8.32-14V80.18a16 16 0 0 0-8.32-14.03ZM128 32l80.34 44-29.77 16.3-80.35-44Zm0 88L47.66 76l33.9-18.56 80.34 44ZM40 90l80 43.78v85.79l-80-43.75Zm96 129.57v-85.75L216 90v85.78Z'/%3E%3C/svg%3E");
}
/* API Reference - document with brackets */
.navbar-item-api::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M180.49 143.51a12 12 0 0 1 0 17l-24 24a12 12 0 0 1-17-17L155 152l-15.52-15.51a12 12 0 0 1 17-17ZM112.49 120.49a12 12 0 0 0-17 0l-24 24a12 12 0 0 0 0 17l24 24a12 12 0 0 0 17-17L97 153l15.52-15.51a12 12 0 0 0-.03-17ZM220 88v24a12 12 0 0 1-24 0v-16h-44a12 12 0 0 1-12-12V40H60v68a12 12 0 0 1-24 0V40a20 20 0 0 1 20-20h96a12 12 0 0 1 8.49 3.52l56 56A12 12 0 0 1 220 88Zm-60-8h23L160 57Zm-4 132H60v-12a12 12 0 0 0-24 0v12a20 20 0 0 0 20 20h100a12 12 0 0 0 0-24Zm64-44a12 12 0 0 0-12 12v36h-44a12 12 0 0 0 0 24h44a20 20 0 0 0 20-20v-40a12 12 0 0 0-8-12Z'/%3E%3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cdefs%3E%3ClinearGradient id='grad3' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%230074d9'/%3E%3Cstop offset='100%25' style='stop-color:%23009296'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath fill='url(%23grad3)' d='M213.66 82.34l-56-56A8 8 0 0 0 152 24H56a16 16 0 0 0-16 16v176a16 16 0 0 0 16 16h144a16 16 0 0 0 16-16V88a8 8 0 0 0-2.34-5.66ZM160 51.31 188.69 80H160ZM200 216H56V40h88v48a8 8 0 0 0 8 8h48v120Zm-42.34-77.66a8 8 0 0 1 0 11.32l-24 24a8 8 0 0 1-11.32-11.32L140.69 144l-18.35-18.34a8 8 0 0 1 11.32-11.32Zm-48-11.32a8 8 0 0 1 0 11.32L91.31 156.69l18.35 18.35a8 8 0 0 1-11.32 11.32l-24-24a8 8 0 0 1 0-11.32l24-24a8 8 0 0 1 11.32 0Z'/%3E%3C/svg%3E");
}
/* Cookbook - book icon */
.navbar-item-cookbook::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M224 44H160a43.86 43.86 0 0 0-32 13.85A43.86 43.86 0 0 0 96 44H32a20 20 0 0 0-20 20v128a20 20 0 0 0 20 20h64a20 20 0 0 1 20 20 12 12 0 0 0 24 0 20 20 0 0 1 20-20h64a20 20 0 0 0 20-20V64a20 20 0 0 0-20-20ZM96 188H36V68h60a20 20 0 0 1 20 20v108.69A43.74 43.74 0 0 0 96 188Zm124 0h-60a43.74 43.74 0 0 0-20 8.69V88a20 20 0 0 1 20-20h60Z'/%3E%3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cdefs%3E%3ClinearGradient id='grad4' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%230074d9'/%3E%3Cstop offset='100%25' style='stop-color:%23009296'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath fill='url(%23grad4)' d='M208 24H72a32 32 0 0 0-32 32v168a8 8 0 0 0 8 8h144a8 8 0 0 0 0-16H56a16 16 0 0 1 16-16h136a8 8 0 0 0 8-8V32a8 8 0 0 0-8-8Zm-8 160H72a31.82 31.82 0 0 0-16 4.29V56a16 16 0 0 1 16-16h128Z'/%3E%3C/svg%3E");
}
/* Changelog - clipboard/list icon */
.navbar-item-changelog::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M140 80v41.21l34.17 20.5a12 12 0 1 1-12.34 20.58l-40-24A12 12 0 0 1 116 128V80a12 12 0 0 1 24 0Zm-12-52a99.38 99.38 0 0 0-70.76 29.34c-4.69 4.74-9 9.37-13.24 14V64a12 12 0 0 0-24 0v40a12 12 0 0 0 12 12h40a12 12 0 0 0 0-24H53.41c4.24-5.95 8.53-11.93 13.49-16.95A76 76 0 1 1 52 128a12 12 0 0 0-24 0 100 100 0 1 0 100-100Z'/%3E%3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cdefs%3E%3ClinearGradient id='grad5' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%230074d9'/%3E%3Cstop offset='100%25' style='stop-color:%23009296'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath fill='url(%23grad5)' d='M200 32h-40a48 48 0 0 0-96 0H56a16 16 0 0 0-16 16v168a16 16 0 0 0 16 16h144a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16Zm-72-8a32 32 0 0 1 32 32H96a32 32 0 0 1 32-32Zm72 192H56V48h24v8a8 8 0 0 0 8 8h80a8 8 0 0 0 8-8v-8h24Zm-32-104a8 8 0 0 1-8 8H96a8 8 0 0 1 0-16h64a8 8 0 0 1 8 8Zm0 32a8 8 0 0 1-8 8H96a8 8 0 0 1 0-16h64a8 8 0 0 1 8 8Zm0 32a8 8 0 0 1-8 8H96a8 8 0 0 1 0-16h64a8 8 0 0 1 8 8Z'/%3E%3C/svg%3E");
}
/* Dark mode icons */
[data-theme='dark'] .navbar-item-developer::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M71.68 97.22 34.74 128l36.94 30.78a12 12 0 1 1-15.36 18.44l-48-40a12 12 0 0 1 0-18.44l48-40a12 12 0 0 1 15.36 18.44Zm176 21.56-48-40a12 12 0 1 0-15.36 18.44L221.26 128l-36.94 30.78a12 12 0 1 0 15.36 18.44l48-40a12 12 0 0 0 0-18.44ZM164.1 28.72a12 12 0 0 0-15.38 7.18l-64 176a12 12 0 0 0 7.18 15.37 11.79 11.79 0 0 0 4.1.73 12 12 0 0 0 11.28-7.9l64-176a12 12 0 0 0-7.18-15.38Z'/%3E%3C/svg%3E");
/* Blog - article/newspaper icon */
.navbar-item-blog::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cdefs%3E%3ClinearGradient id='grad6' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%230074d9'/%3E%3Cstop offset='100%25' style='stop-color:%23009296'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath fill='url(%23grad6)' d='M216 40H40a16 16 0 0 0-16 16v144a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16Zm0 160H40V56h176v144ZM184 96a8 8 0 0 1-8 8H80a8 8 0 0 1 0-16h96a8 8 0 0 1 8 8Zm0 32a8 8 0 0 1-8 8H80a8 8 0 0 1 0-16h96a8 8 0 0 1 8 8Zm0 32a8 8 0 0 1-8 8H80a8 8 0 0 1 0-16h96a8 8 0 0 1 8 8Z'/%3E%3C/svg%3E");
}
[data-theme='dark'] .navbar-item-sdks::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='m225.6 62.64-88-48.17a19.91 19.91 0 0 0-19.2 0l-88 48.17A20 20 0 0 0 20 80.19v95.62a20 20 0 0 0 10.4 17.55l88 48.17a19.89 19.89 0 0 0 19.2 0l88-48.17a20 20 0 0 0 10.4-17.55V80.19a20 20 0 0 0-10.4-17.55ZM128 36.57 200 76l-72 39.42L56 76ZM44 96.82l72 39.43v76.89l-72-39.42Zm96 116.32v-76.89l72-39.43v76.89Z'/%3E%3C/svg%3E");
}
[data-theme='dark'] .navbar-item-api::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M180.49 143.51a12 12 0 0 1 0 17l-24 24a12 12 0 0 1-17-17L155 152l-15.52-15.51a12 12 0 0 1 17-17ZM112.49 120.49a12 12 0 0 0-17 0l-24 24a12 12 0 0 0 0 17l24 24a12 12 0 0 0 17-17L97 153l15.52-15.51a12 12 0 0 0-.03-17ZM220 88v24a12 12 0 0 1-24 0v-16h-44a12 12 0 0 1-12-12V40H60v68a12 12 0 0 1-24 0V40a20 20 0 0 1 20-20h96a12 12 0 0 1 8.49 3.52l56 56A12 12 0 0 1 220 88Zm-60-8h23L160 57Zm-4 132H60v-12a12 12 0 0 0-24 0v12a20 20 0 0 0 20 20h100a12 12 0 0 0 0-24Zm64-44a12 12 0 0 0-12 12v36h-44a12 12 0 0 0 0 24h44a20 20 0 0 0 20-20v-40a12 12 0 0 0-8-12Z'/%3E%3C/svg%3E");
}
[data-theme='dark'] .navbar-item-cookbook::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M224 44H160a43.86 43.86 0 0 0-32 13.85A43.86 43.86 0 0 0 96 44H32a20 20 0 0 0-20 20v128a20 20 0 0 0 20 20h64a20 20 0 0 1 20 20 12 12 0 0 0 24 0 20 20 0 0 1 20-20h64a20 20 0 0 0 20-20V64a20 20 0 0 0-20-20ZM96 188H36V68h60a20 20 0 0 1 20 20v108.69A43.74 43.74 0 0 0 96 188Zm124 0h-60a43.74 43.74 0 0 0-20 8.69V88a20 20 0 0 1 20-20h60Z'/%3E%3C/svg%3E");
}
[data-theme='dark'] .navbar-item-changelog::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M140 80v41.21l34.17 20.5a12 12 0 1 1-12.34 20.58l-40-24A12 12 0 0 1 116 128V80a12 12 0 0 1 24 0Zm-12-52a99.38 99.38 0 0 0-70.76 29.34c-4.69 4.74-9 9.37-13.24 14V64a12 12 0 0 0-24 0v40a12 12 0 0 0 12 12h40a12 12 0 0 0 0-24H53.41c4.24-5.95 8.53-11.93 13.49-16.95A76 76 0 1 1 52 128a12 12 0 0 0-24 0 100 100 0 1 0 100-100Z'/%3E%3C/svg%3E");
}
/* Dark mode - same gradient icons work well on dark backgrounds */
}
/* GitHub icon link */
@@ -460,6 +458,7 @@ div[class*="codeBlockContent"] .prism-code {
max-width: 100%;
}
/* Page title with gradient */
article h1,
.markdown h1,
@@ -500,7 +499,7 @@ article p {
}
/* Links with gradient */
article a:not(.button):not([class*="hash-link"]) {
article a:not(.button):not([class*="hash-link"]):not([class*="author"]):not([class*="avatar"]) {
background: var(--hindsight-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
@@ -509,6 +508,14 @@ article a:not(.button):not([class*="hash-link"]) {
font-weight: 500;
}
/* Blog author links - ensure visible */
[class*="author"] a,
[class*="blogPost"] [class*="author"] {
color: var(--ifm-font-color-base) !important;
-webkit-text-fill-color: var(--ifm-font-color-base) !important;
background: none !important;
}
/* Links containing code - the code inherits the transparent text-fill from the link */
article a code {
-webkit-text-fill-color: #3396e8 !important;
@@ -622,11 +629,67 @@ th {
/* Footer */
.footer {
background: #09090b !important;
border-top: 1px solid var(--ifm-toc-border-color);
padding: 3rem 0 2rem;
}
.footer__links {
margin-bottom: 2rem;
}
.footer__title {
font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-weight: 700;
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #a1a1aa !important;
margin-bottom: 1rem;
}
.footer__item {
margin-bottom: 0.5rem;
}
.footer__link-item {
font-size: 0.875rem;
color: #d4d4d8 !important;
transition: color 0.15s ease;
}
.footer__link-item:hover {
color: #ffffff !important;
text-decoration: none;
}
.footer__copyright {
font-size: 0.8125rem;
color: #71717a !important;
border-top: 1px solid #27272a;
padding-top: 1.5rem;
margin-top: 1rem;
}
/* Light mode footer - keep dark style */
[data-theme='light'] .footer {
background: #09090b !important;
}
[data-theme='light'] .footer__title {
color: #a1a1aa !important;
}
[data-theme='light'] .footer__link-item {
color: #d4d4d8 !important;
}
[data-theme='light'] .footer__link-item:hover {
color: #ffffff !important;
}
[data-theme='light'] .footer__copyright {
color: #71717a !important;
}
/* Tabs styling */
+4 -4
View File
@@ -78,7 +78,7 @@ Here's what happens under the hood when you call `completion()`:
│ # Relevant Memories │
│ 1. [WORLD] User prefers pytest for testing │
│ 2. [WORLD] User is building a FastAPI app │
│ 3. [OPINION] User likes type hints │
│ 3. [WORLD] User likes type hints │
│ """}, │
│ {"role": "user", "content": "Help me with my Python project"} │
│ ] │
@@ -137,7 +137,7 @@ hindsight_litellm.configure(
max_memories=None, # Maximum memories to inject (None = unlimited)
max_memory_tokens=4096, # Maximum tokens for memory context
recall_budget="mid", # Recall budget: "low", "mid", "high"
fact_types=["world", "agent"], # Filter fact types to inject
fact_types=["world", "experience"], # Filter fact types to inject
# Optional - Bank Configuration
bank_name="My Agent", # Human-readable display name for the memory bank
@@ -182,7 +182,7 @@ hindsight_litellm.configure(
bank_id="my-agent",
use_reflect=False, # Default
)
# Injects: "1. [WORLD] User prefers Python\n2. [OPINION] User dislikes Java..."
# Injects: "1. [WORLD] User prefers Python\n2. [EXPERIENCE] User struggled with Java..."
# Reflect mode - synthesized context
hindsight_litellm.configure(
@@ -240,7 +240,7 @@ for m in memories:
# Output:
# - [world] User is building a FastAPI project
# - [opinion] User prefers Python over JavaScript
# - [world] User prefers Python over JavaScript
```
### Reflect - Get synthesized context
+1 -1
View File
@@ -108,7 +108,7 @@ messages = [
messages = [
{
"role": "system",
"content": "Relevant context from your memory:\n\n1. User prefers Python for its simplicity\n (Date: 2024-01-15)\n (Type: opinion)"
"content": "Relevant context from your memory:\n\n1. User prefers Python for its simplicity\n (Date: 2024-01-15)\n (Type: world)"
},
{"role": "user", "content": "What's my favorite programming language?"}
]