diff --git a/hindsight-docs/blog/2026-01-26-learning-capabilities.md b/hindsight-docs/blog/2026-01-26-learning-capabilities.md new file mode 100644 index 00000000..7ee22c2f --- /dev/null +++ b/hindsight-docs/blog/2026-01-26-learning-capabilities.md @@ -0,0 +1,284 @@ +--- +slug: learning-capabilities +title: "Agent memory that learns: observations and mental models" +authors: [hindsight] +image: /img/reflect-operation.webp +hide_table_of_contents: false +--- + +Today we're releasing Hindsight 0.4.0, which introduces two powerful learning capabilities for AI agents: **Observations** for automatic knowledge consolidation, and **Mental Models** for user-curated summaries. + + + +## Two Levels of Learning + +Hindsight 0.4.0 introduces a hierarchical learning system: + +| Level | What It Is | How It's Created | +|-------|------------|------------------| +| **Mental Models** | User-curated summaries for common queries | Manually created via API | +| **Observations** | Consolidated knowledge from facts | Automatically after retain | + +During `reflect`, the agent checks these in priority order — mental models first (your curated knowledge), then observations (automatic synthesis), then raw facts. + +--- + +## Observations: Automatic Knowledge Consolidation + +### Evolution from Entity Summaries and Opinions + +In Hindsight 0.3.0, we had two separate systems for synthesized knowledge: + +- **Entity summaries**: Per-entity summaries synthesized from related facts. Generated automatically for frequently-mentioned entities — if "Alice" appeared in many facts, you'd get a summary like "Alice is a software engineer at Google who joined in 2020 and leads the search team." Objective and entity-scoped. + +- **Opinions**: Beliefs formed during `reflect` operations, influenced by the bank's disposition traits. These captured subjective judgments with confidence scores, like "Python is best for data science" (confidence: 0.85). + +Both systems served their purpose well, but they operated independently. Entity summaries were entity-centric, opinions were belief-centric, and neither captured the full picture of how knowledge evolves over time. + +**Observations** unify these concepts into a single, more expressive system that captures patterns, preferences, and learnings as they emerge from accumulated evidence. + +### What Are Observations? + +Observations are **consolidated knowledge** synthesized from multiple facts. Unlike raw facts which are individual pieces of information, observations represent patterns and insights that emerge from accumulated evidence. + +| Raw Facts | Observation | +|-----------|--------------| +| "Alice prefers Python" | "Alice is a Python-focused developer who values readability and simplicity, recommends type hints, and prefers pytest for testing" | +| "Alice dislikes verbose code" | | +| "Alice recommends type hints" | | + +### Automatic Background Consolidation + +After every `retain()` call, Hindsight's consolidation engine runs automatically: + +1. **Analyzes new facts** against existing knowledge +2. **Detects patterns** across related information +3. **Synthesizes observations** that capture higher-order insights +4. **Tracks evidence** linking each observation to its supporting facts + +```mermaid +graph LR + A[New Facts] --> B[Consolidation Engine] + B --> C{Existing Observation?} + C -->|Yes| D[Refine Observation] + C -->|No| E[Create Observation] + D --> F[Observations] + E --> F +``` + +### Evidence-Based Evolution + +Observations evolve as new evidence arrives, capturing the full journey rather than just the current state: + +| Time | Fact | Observation | +|------|------|--------------| +| Week 1 | "User loves React" | "User prefers React for frontend development" | +| Week 2 | "User praises React's component model" | "User is enthusiastic about React, particularly its component model" | +| Week 3 | "User switched to Vue and won't use React anymore" | "User was previously a React enthusiast who appreciated its component model, but has now switched to Vue" | + +Notice how the final observation captures the **full journey** — not just "User prefers Vue" but the complete evolution. Your agent now understands: + +- The user deliberately moved away from React (it wasn't ignorance) +- They previously appreciated React's component model (relevant context) +- Recommending React tutorials would be inappropriate + +### Mission-Oriented Consolidation + +Observations are influenced by your bank's **mission**. When you set a mission, the consolidation engine focuses on extracting knowledge that serves that purpose: + +```python +client.create_bank( + bank_id="support-agent", + mission="You're a customer support agent - track customer preferences, " + "past issues, and communication styles." +) +``` + +With this mission, the engine prioritizes customer-relevant observations while skipping ephemeral details. Without a mission, it performs general-purpose consolidation. + +--- + +## Mental Models: User-Curated Knowledge + +While observations are created automatically, **mental models** give you explicit control over how your agent answers common questions. + +### What Are Mental Models? + +Mental models are **saved reflect responses** that you curate for your memory bank. When you create a mental model, Hindsight runs a reflect operation with your source query and stores the result. During future reflect calls, these pre-computed summaries are checked first. + +```mermaid +graph LR + A[Create Mental Model] --> B[Run Reflect] + B --> C[Store Result] + C --> D[Future Queries] + D --> E{Match Found?} + E -->|Yes| F[Return Mental Model] + E -->|No| G[Run Full Reflect] +``` + +### Why Use Mental Models? + +| Benefit | Description | +|---------|-------------| +| **Consistency** | Same answer every time for common questions | +| **Speed** | Pre-computed responses are returned instantly | +| **Quality** | Manually curated summaries you've reviewed | +| **Control** | Define exactly how key topics should be answered | + +### Two Ways to Use Mental Models + +Mental models work in two ways: + +1. **Automatic via Reflect**: During `reflect` calls, the agent automatically checks mental models first. If a relevant one exists, it's used to inform the response. + +2. **Direct Lookup**: Mental models work like a key-value store — you can retrieve them instantly by ID, bypassing the reflect reasoning loop entirely. + +```python +# Direct lookup by ID — instant response, no LLM call +mental_model = client.get_mental_model( + bank_id="my-bank", + mental_model_id="team-communication" +) +print(mental_model.content) # Pre-computed answer, ready to use +``` + +This is useful when you know exactly what mental model you need and want the fastest possible response — no LLM reasoning required, just a simple database lookup. + +### Creating Mental Models + +```python +# Create a mental model for a common question +response = client.create_mental_model( + bank_id="my-bank", + name="Team Communication Preferences", + source_query="How does the team prefer to communicate?", + tags=["team"] +) +``` + +### Automatic Refresh + +Mental models can automatically stay in sync with your observations: + +```python +# Mental model that refreshes when observations update +response = client.create_mental_model( + bank_id="my-bank", + name="Project Status", + source_query="What is the current project status?", + trigger={"refresh_after_consolidation": True} +) +``` + +--- + +## Directives: Compliance and Guardrails + +In addition to learning capabilities, **directives** provide hard rules that your agent must always follow during reflect operations. Unlike disposition traits which *influence* reasoning style, directives are absolute requirements that are enforced in every response. + +Use directives for compliance, privacy, and safety constraints: +- "Never provide medical diagnoses or treatment advice" +- "Always respond in formal English" +- "Never share personally identifiable information" +- "Always cite sources when making factual claims" + +Directives are injected into reflect prompts as hard constraints and are included in the response's `based_on` field. See the [Directives documentation](../developer/api/memory-banks#directives) for how to create and manage them. + +--- + +## What Changes from 0.3.0 + +### Unified Memory Types + +Opinions and entity summaries are now consolidated into observations: + +```python +# 0.3.0 - opinions via types, entity summaries via include_entities +response = client.recall( + bank_id="my-bank", + query="What do you think about Python?", + types=["opinion"], + include_entities=True # to get entity summaries +) + +# 0.4.0 - observations unify both +response = client.recall( + bank_id="my-bank", + query="What do you think about Python?", + types=["observation"] +) +``` + +### From Confidence Scores to Evidence Tracking + +Opinions had numeric confidence scores (0.0-1.0). Observations instead track: + +- **Supporting facts**: The evidence behind the observation +- **Last updated**: When the observation was last refined +- **Freshness**: Whether the observation reflects recent information + +This shift from a single score to evidence tracking means your agent can explain *why* it believes something, not just *how confident* it is. + +### Automatic vs On-Demand + +Entity summaries were created automatically for top entities, but opinions only formed during `reflect`. Observations are always consolidated automatically after `retain`, ensuring knowledge stays current without explicit queries. + +### Background Becomes Mission + +The bank's `background` field has been renamed to `mission`. During the migration, your existing background text is automatically copied to the mission field — no action needed. + +### Agentic Reflect + +The `reflect` operation is now agentic — it reasons more deeply by iteratively retrieving memories and consulting mental models and observations before formulating a response. This makes reflect significantly smarter, especially for complex questions that require synthesizing information across multiple topics. + +The trade-off is that reflect may take longer to respond. For latency-sensitive use cases, consider using `recall` directly when you just need to retrieve facts. + +### Data Migration + +**Important:** When upgrading to 0.4.0, existing opinions and entity summaries will be deleted. The consolidation engine will automatically create new observations from your existing facts. This is a one-time migration — your raw facts are preserved, and observations will be synthesized from them after the upgrade. + +### Migration Checklist + +**If you were using `types=["opinion"]` in recall:** + +1. Update to `types=["observation"]` +2. Observations combine both entity-centric summaries and belief-based insights + +**If you were using `include_entities=True` in recall:** + +1. Entity summaries are now included in observations +2. Use `types=["observation"]` to retrieve them + +**If you were relying on confidence scores:** + +1. Use the `based_on` field to access supporting evidence +2. The number and recency of supporting facts indicates strength + +**If you were setting `background` on banks:** + +1. The field is now called `mission` +2. Existing values are migrated automatically + +**No changes needed for reflect:** + +Observations are automatically included in reflect responses via the `based_on` field. + +--- + +## What's Next + +These learning capabilities are the foundation for more sophisticated agent memory capabilities we're exploring: + +- **Temporal reasoning**: Better understanding of how knowledge evolves over time +- **Selective consolidation**: Fine-grained control over what gets synthesized into observations +- **Consolidation insights**: Visibility into how observations are formed and updated + +--- + +**Resources:** +- [Recall API](../developer/api/recall) — retrieve observations alongside facts +- [Reflect API](../developer/api/reflect) — responses now include supporting observations +- [Mental Models API](../developer/api/mental-models) — create and manage curated summaries +- [Observations Guide](../developer/observations) — deep dive into knowledge consolidation +- [Directives](../developer/api/memory-banks#directives) — hard rules for compliance and guardrails +- [Full Changelog](../changelog) diff --git a/hindsight-docs/blog/authors.yml b/hindsight-docs/blog/authors.yml new file mode 100644 index 00000000..273f91e3 --- /dev/null +++ b/hindsight-docs/blog/authors.yml @@ -0,0 +1,3 @@ +hindsight: + name: Hindsight Team + url: https://github.com/vectorize-io/hindsight diff --git a/hindsight-docs/docs/sdks/cli.md b/hindsight-docs/docs/sdks/cli.md index 66abd491..4578def7 100644 --- a/hindsight-docs/docs/sdks/cli.md +++ b/hindsight-docs/docs/sdks/cli.md @@ -4,7 +4,7 @@ sidebar_position: 3 # CLI Reference -The Hindsight CLI provides command-line access to memory operations and bank management. All commands follow the [OpenAPI specification](/api), so you can use `--help` on any command to see all available options. +The Hindsight CLI provides command-line access to memory operations and bank management. All commands follow the [OpenAPI specification](/api-reference), so you can use `--help` on any command to see all available options. ## Installation diff --git a/hindsight-docs/docusaurus.config.ts b/hindsight-docs/docusaurus.config.ts index 944249b8..8fee9081 100644 --- a/hindsight-docs/docusaurus.config.ts +++ b/hindsight-docs/docusaurus.config.ts @@ -66,7 +66,6 @@ const config: Config = { { docs: { sidebarPath: './sidebars.ts', - editUrl: 'https://github.com/vectorize-io/hindsight/tree/main/hindsight-docs/', routeBasePath: '/', // Only show "next" version in development or when INCLUDE_CURRENT_VERSION=true // In production, only show released versions from versions.json @@ -97,7 +96,14 @@ const config: Config = { return config; })(), }, - blog: false, + blog: { + showReadingTime: true, + blogTitle: 'Hindsight Blog', + blogDescription: 'Updates, insights, and deep dives into agent memory', + postsPerPage: 10, + blogSidebarTitle: 'Recent posts', + blogSidebarCount: 'ALL', + }, theme: { customCss: './src/css/custom.css', }, @@ -151,7 +157,8 @@ const config: Config = { { hashed: true, docsRouteBasePath: '/', - indexBlog: false, + indexBlog: true, + blogRouteBasePath: '/blog', highlightSearchTermsOnTargetPage: false, }, ], @@ -206,6 +213,12 @@ const config: Config = { label: 'Cookbook', className: 'navbar-item-cookbook', }, + { + to: '/blog', + position: 'left', + label: 'Blog', + className: 'navbar-item-blog', + }, { type: 'doc', docId: 'changelog/index', diff --git a/hindsight-docs/examples/api/legacy/opinions.py b/hindsight-docs/examples/api/legacy/opinions.py index 7df0ee4e..a7133ce7 100644 --- a/hindsight-docs/examples/api/legacy/opinions.py +++ b/hindsight-docs/examples/api/legacy/opinions.py @@ -38,6 +38,33 @@ for opinion in response.results: # [/docs:opinion-search] +# [docs:recall-opinions-only] +# Only retrieve opinions (beliefs and preferences) +opinions = client.recall( + bank_id="my-bank", + query="What are my preferences?", + types=["opinion"] +) +# [/docs:recall-opinions-only] + + +# [docs:recall-include-entities] +# Include entity summaries in recall results +response = client.recall( + bank_id="my-bank", + query="What do I know about Alice?", + include_entities=True, + max_entity_tokens=500 +) + +# Results include both facts and entity summaries +for result in response.results: + print(f"- {result.text}") + if hasattr(result, 'entity_summary'): + print(f" Entity: {result.entity_summary}") +# [/docs:recall-include-entities] + + # [docs:opinion-disposition] # Bank disposition affects how opinions are formed # High skepticism = lower confidence, requires more evidence diff --git a/hindsight-docs/examples/api/memory-banks.mjs b/hindsight-docs/examples/api/memory-banks.mjs index a9d3d7cc..d9567325 100644 --- a/hindsight-docs/examples/api/memory-banks.mjs +++ b/hindsight-docs/examples/api/memory-banks.mjs @@ -39,6 +39,16 @@ await client.createBank('financial-advisor', { // [/docs:bank-mission] +// [docs:bank-background] +// Legacy snippet for v0.3 docs (background renamed to mission in v0.4) +await client.createBank('legacy-bank', { + name: 'Legacy Example', + mission: `I'm a personal assistant helping a software engineer. I should track their + project preferences, coding style, and technology choices.` +}); +// [/docs:bank-background] + + // ============================================================================= // Cleanup (not shown in docs) // ============================================================================= diff --git a/hindsight-docs/examples/api/memory-banks.py b/hindsight-docs/examples/api/memory-banks.py index 4afe4e5a..6a5934f4 100644 --- a/hindsight-docs/examples/api/memory-banks.py +++ b/hindsight-docs/examples/api/memory-banks.py @@ -43,6 +43,17 @@ client.create_bank( # [/docs:bank-mission] +# [docs:bank-background] +# Legacy snippet for v0.3 docs (background renamed to mission in v0.4) +client.create_bank( + bank_id="legacy-bank", + name="Legacy Example", + mission="""I'm a personal assistant helping a software engineer. I should track their + project preferences, coding style, and technology choices.""" +) +# [/docs:bank-background] + + # [docs:bank-with-disposition] client.create_bank( bank_id="architect-bank", diff --git a/hindsight-docs/examples/api/recall.py b/hindsight-docs/examples/api/recall.py index 04012921..1b3d41c5 100644 --- a/hindsight-docs/examples/api/recall.py +++ b/hindsight-docs/examples/api/recall.py @@ -147,6 +147,33 @@ response = client.recall( # [/docs:recall-tags-all] +# ============================================================================= +# Legacy snippets for v0.3 docs (kept for backward compatibility) +# ============================================================================= + +# [docs:recall-opinions-only] +# Legacy: opinions replaced by observations in v0.4+ +# Only retrieve opinions (beliefs and preferences) +opinions = client.recall( + bank_id="my-bank", + query="What are my preferences?", + types=["opinion"] +) +# [/docs:recall-opinions-only] + + +# [docs:recall-include-entities] +# Legacy: entity summaries replaced by observations in v0.4+ +# Include entity summaries in recall results +response = client.recall( + bank_id="my-bank", + query="What do I know about Alice?", + include_entities=True, + max_entity_tokens=500 +) +# [/docs:recall-include-entities] + + # ============================================================================= # Cleanup (not shown in docs) # ============================================================================= diff --git a/hindsight-docs/package.json b/hindsight-docs/package.json index 73252453..9be52cb5 100644 --- a/hindsight-docs/package.json +++ b/hindsight-docs/package.json @@ -5,7 +5,7 @@ "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", - "build": "docusaurus build", + "build": "INCLUDE_CURRENT_VERSION=true docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "clear": "docusaurus clear", diff --git a/hindsight-docs/src/css/custom.css b/hindsight-docs/src/css/custom.css index d6fe4300..13a6364a 100644 --- a/hindsight-docs/src/css/custom.css +++ b/hindsight-docs/src/css/custom.css @@ -1247,3 +1247,59 @@ ul[class*="suggestion"] { display: none !important; } +/* ===== Blog Styling ===== */ + +/* Hide TOC sidebar on blog post pages */ +.blog-post-page .col--3, +.blog-post-page [class*="tableOfContents"], +.blog-post-page aside[class*="toc"] { + display: none !important; +} + +/* Make blog post content full width when TOC is hidden */ +.blog-post-page .col--9 { + --ifm-col-width: 100%; + max-width: 100%; + flex-basis: 100%; +} + +/* Hide author avatar/icon on blog posts */ +[class*="blogPostAuthor"] img, +[class*="authorImage"], +.avatar__photo { + display: none !important; +} + +/* Blog author text visible in dark mode */ +[data-theme='dark'] [class*="blogPostAuthor"], +[data-theme='dark'] [class*="blogPostAuthor"] *, +[data-theme='dark'] .avatar__name, +[data-theme='dark'] .avatar__name a, +[data-theme='dark'] .avatar__subtitle, +[data-theme='dark'] [class*="authorName"], +[data-theme='dark'] [class*="blogPostData"] a, +[data-theme='dark'] [class*="blogPostInfo"] a { + color: #e2e8f0 !important; + -webkit-text-fill-color: #e2e8f0 !important; +} + +/* Blog navbar icon */ +@media (min-width: 997px) { + .navbar-item-blog::before { + display: inline-block; + width: 16px; + height: 16px; + margin-right: 6px; + vertical-align: middle; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + content: ''; + 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='M216 36H40a20 20 0 0 0-20 20v144a20 20 0 0 0 20 20h176a20 20 0 0 0 20-20V56a20 20 0 0 0-20-20Zm-4 160H44V60h168ZM68 92a12 12 0 0 1 12-12h96a12 12 0 0 1 0 24H80a12 12 0 0 1-12-12Zm0 36a12 12 0 0 1 12-12h96a12 12 0 0 1 0 24H80a12 12 0 0 1-12-12Zm0 36a12 12 0 0 1 12-12h96a12 12 0 0 1 0 24H80a12 12 0 0 1-12-12Z'/%3E%3C/svg%3E"); + } + + [data-theme='dark'] .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%3Cpath fill='%23ccc' d='M216 36H40a20 20 0 0 0-20 20v144a20 20 0 0 0 20 20h176a20 20 0 0 0 20-20V56a20 20 0 0 0-20-20Zm-4 160H44V60h168ZM68 92a12 12 0 0 1 12-12h96a12 12 0 0 1 0 24H80a12 12 0 0 1-12-12Zm0 36a12 12 0 0 1 12-12h96a12 12 0 0 1 0 24H80a12 12 0 0 1-12-12Zm0 36a12 12 0 0 1 12-12h96a12 12 0 0 1 0 24H80a12 12 0 0 1-12-12Z'/%3E%3C/svg%3E"); + } +} + diff --git a/hindsight-docs/versions.json b/hindsight-docs/versions.json index 325c996e..fe51488c 100644 --- a/hindsight-docs/versions.json +++ b/hindsight-docs/versions.json @@ -1 +1 @@ -["0.3"] +[] diff --git a/uv.lock b/uv.lock index 1803b558..a849e20c 100644 --- a/uv.lock +++ b/uv.lock @@ -1295,7 +1295,7 @@ wheels = [ [[package]] name = "hindsight-all" -version = "0.3.0" +version = "0.4.0" source = { editable = "hindsight" } dependencies = [ { name = "hindsight-api" }, @@ -1319,7 +1319,7 @@ provides-extras = ["test"] [[package]] name = "hindsight-api" -version = "0.3.0" +version = "0.4.0" source = { editable = "hindsight-api" } dependencies = [ { name = "aiohttp" }, @@ -1447,7 +1447,7 @@ dev = [ [[package]] name = "hindsight-client" -version = "0.3.0" +version = "0.4.0" source = { editable = "hindsight-clients/python" } dependencies = [ { name = "aiohttp" }, @@ -1481,7 +1481,7 @@ provides-extras = ["test"] [[package]] name = "hindsight-dev" -version = "0.3.0" +version = "0.4.0" source = { editable = "hindsight-dev" } dependencies = [ { name = "hindsight-api" }, @@ -1527,7 +1527,7 @@ dev = [ [[package]] name = "hindsight-embed" -version = "0.3.0" +version = "0.4.0" source = { editable = "hindsight-embed" } dependencies = [ { name = "httpx" },