Compare commits

...
21 Commits
Author SHA1 Message Date
DK09876 e521914f0f Fix example scripts: remove non-existent API attributes
- recall.py: remove .weight, fix entities iteration (dict not list)
- retain.mjs: remove result.async check
2025-12-17 12:14:43 -07:00
DK09876 7cb469ff75 Fix opinions.py: use actual API attributes instead of non-existent ones 2025-12-17 11:40:55 -07:00
DK09876 9118e7b4cb Fix main-methods.py: RecallResult and ReflectFact don't have weight attribute 2025-12-17 11:18:09 -07:00
DK09876 841a66f375 Fix async API client usage in documents.py example 2025-12-17 11:11:46 -07:00
DK09876 eb06adb2be Add documentation code validation CI job
- Use uv sync + uv run pattern (matches existing CI)
- Add requests to test dependencies for cleanup scripts
2025-12-17 10:48:38 -07:00
DK09876 3913788fd8 Fix: run cd in subshell so install runs from repo root 2025-12-17 10:40:10 -07:00
DK09876 6ea02eb023 Fix: use explicit shell expansion for wheel install 2025-12-17 10:35:01 -07:00
DK09876 55154384f6 Fix wheel path - uv build outputs to repo root dist/ 2025-12-17 10:24:52 -07:00
DK09876 19e4e2d635 Fix CI issue 2025-12-17 10:20:15 -07:00
DK09876 8f2396f04a Fix wheel glob expansion in test-doc-examples CI job 2025-12-17 10:15:13 -07:00
DK09876 bffc0ee0d0 Add documentation code validation system
- Create runnable example scripts in examples/api/ (19 files)
- Add CodeSnippet component for extracting marked sections
- Add raw-loader dependency for importing source files
- Create sample retain-new.mdx showing new approach
- Add README documenting coverage and gaps
2025-12-17 10:06:53 -07:00
Chris Bartholomew 476a62da47 Add Hindsight Cloud links to README and docs (#42)
- Add Hindsight Cloud link to README header
- Add Hindsight Cloud navbar item in docs
- Add callout in installation docs for managed alternative
2025-12-17 11:09:36 -05:00
Nicolò Boschi 5aaa769ab9 Release v0.1.8
- Update version to 0.1.8 in all components
- Python packages: hindsight-api, hindsight-dev, hindsight-dev/benchmarks, hindsight-all, hindsight-litellm
- Python client: hindsight-clients/python
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- Helm chart
2025-12-17 13:21:35 +01:00
Nicolò Boschi 04f01ab9ab fix: bank list response with no name banks 2025-12-17 13:21:16 +01:00
Nicolò Boschi 63f51385c4 fix: retain async fails (#40)
* fix: retain async fails

* fix: retain async fails
2025-12-17 13:17:38 +01:00
William Simmonds e468a4e19f fix: bank selector race condition when switching banks (#38) (#39) 2025-12-17 12:56:24 +01:00
Nicolò Boschi c0a0f447b7 Update README.md 2025-12-17 10:20:02 +01:00
Nicolò Boschi 84927ccc99 add run benchmarks instructions 2025-12-16 17:24:45 +01:00
Chris Latimer a6e8944ff0 README updates 2025-12-16 07:09:30 -07:00
Nicolò Boschi f6d890f6ed Release v0.1.7
- Update version to 0.1.7 in all components
- Python packages: hindsight-api, hindsight-dev, hindsight-dev/benchmarks, hindsight-all, hindsight-litellm
- Python client: hindsight-clients/python
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- Helm chart
2025-12-16 14:29:07 +01:00
Nicolò Boschi 1fa8d9150c ci: check compatibility with python 3.11, 3.12 and 3.13 (#35) 2025-12-16 14:28:45 +01:00
48 changed files with 2438 additions and 61 deletions
+116 -1
View File
@@ -38,6 +38,29 @@ jobs:
working-directory: ./${{ matrix.path }}
run: uv build
build-api-python-versions:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Build hindsight-api
working-directory: ./hindsight-api
run: uv build
build-typescript-client:
runs-on: ubuntu-latest
@@ -472,4 +495,96 @@ jobs:
- name: Run tests
working-directory: ./hindsight-integrations/litellm
run: uv run pytest tests -v
run: uv run pytest tests -v
test-doc-examples:
runs-on: ubuntu-latest
env:
HINDSIGHT_API_LLM_PROVIDER: groq
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
HINDSIGHT_API_URL: http://localhost:8888
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
prune-cache: false
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: package-lock.json
- name: Build and install API
working-directory: ./hindsight-api
run: |
uv build
uv sync --no-install-project --index-strategy unsafe-best-match
- name: Install Python client dependencies
working-directory: ./hindsight-clients/python
run: uv sync --extra test --index-strategy unsafe-best-match
- name: Install TypeScript client
run: |
npm ci --workspace=hindsight-clients/typescript
npm run build --workspace=hindsight-clients/typescript
- name: Create .env file
run: |
cat > .env << EOF
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
EOF
- name: Start API server
run: |
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
echo "Waiting for API server to be ready..."
for i in {1..60}; do
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
echo "API server is ready after ${i}s"
break
fi
if [ $i -eq 60 ]; then
echo "API server failed to start after 60s"
cat /tmp/api-server.log
exit 1
fi
sleep 1
done
- name: Run Python doc examples
working-directory: ./hindsight-clients/python
run: |
for f in ../../hindsight-docs/examples/api/*.py; do
echo "Running $f..."
uv run python "$f"
done
- name: Run Node.js doc examples
run: |
for f in hindsight-docs/examples/api/*.mjs; do
echo "Running $f..."
node "$f"
done
- name: Show API server logs
if: always()
run: |
echo "=== API Server Logs ==="
cat /tmp/api-server.log || echo "No API server log found"
+33 -9
View File
@@ -2,14 +2,13 @@
![Hindsight Banner](./hindsight-docs/static/img/banner.svg)
[Documentation](https://vectorize-io.github.io/hindsight) • [Paper](#coming-soon) • [Examples](https://github.com/vectorize-io/hindsight-cookbook)
[Documentation](https://hindsight.vectorize.io) • [Paper](https://arxiv.org/abs/2512.12818) • [Cookbook](https://hindsight.vectorize.io/cookbook) • [Hindsight Cloud](https://vectorize.io/hindsight/cloud)
[![CI](https://github.com/vectorize-io/hindsight/actions/workflows/release.yml/badge.svg)](https://github.com/vectorize-io/hindsight/actions/workflows/release.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PyPI - hindsight-api](https://img.shields.io/pypi/v/hindsight-api?label=hindsight-api)](https://pypi.org/project/hindsight-api/)
[![PyPI - hindsight-client](https://img.shields.io/pypi/v/hindsight-client?label=hindsight-client)](https://pypi.org/project/hindsight-client/)
[![npm - @vectorize-io/hindsight-client](https://img.shields.io/npm/v/@vectorize-io/hindsight-client)](https://www.npmjs.com/package/@vectorize-io/hindsight-client)
[![Slack Community](https://img.shields.io/badge/Slack-Join%20Community-4A154B?logo=slack)](https://join.slack.com/t/hindsight-space/shared_invite/zt-3klo21kua-VUCC_zHP5rIcXFB1_5yw6A)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
![PyPI - Downloads](https://img.shields.io/pypi/dm/hindsight-api?label=PyPI)
![NPM Downloads](https://img.shields.io/npm/dm/%40vectorize-io%2Fhindsight-client?logoColor=orange&label=NPM&color=blue&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F%40vectorize-io%2Fhindsight-client)
</div>
@@ -18,7 +17,7 @@
## What is Hindsight?
Hindsight™ is an agent memory system built to create smarter agents that learn over time. It eliminates the shortcomings of alternative techniques such as RAG and knowledge graph.
Hindsight™ is an agent memory system built to create smarter agents that learn over time. It eliminates the shortcomings of alternative techniques such as RAG and knowledge graph and delivers state-of-the-art performance on long term memory tasks.
Hindsight addresses common challenges that have frustrated AI engineers building agents to automate tasks and assist users with conversational interfaces. Many of these challenges stem directly from a lack of memory.
@@ -26,27 +25,48 @@ Hindsight addresses common challenges that have frustrated AI engineers building
- **Hallucinations:** Long term memory can be seeded with external knowledge to ground agent behavior in reliable sources to augment training data.
- **Cognitive Overload:** As workflows get complex, retrievals, tool calls, user messages and agent responses can grow to fill the context window leading to context rot. Short term memory optimization allows agents to reduce tokens and focus context by removing irrelevant details.
## How Hindsight Works
## How is Hindsight Different From Other Memory Systems?
![Overview](./hindsight-docs/static/img/hindsight-overview.webp)
Hindsight organizes memory into four networks to mimic the way human memory works:
Most agent memory implementation rely on basic vector search or sometimes use a knowledge graph. Hindsight uses biomimetic data structures to organize agent memories in a way that is more like how human memory works:
- **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.")
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.
Hindsight provides three simple methods to interact with the system:
- **Retain:** Provide information to Hindsight that you want it to remember
- **Recall:** Retrieve memories from Hindsight
- **Reflect:** Reflect on memories and experiences to generate new observations and insights from existing memories.
Memories in Hindsight are stored in banks (e.g. memory banks). When memories are retained, they are transformed to construct a series of search indexes, time series data, and entity/relationship graphs.
### Agent Memory That Learns
A key goal of Hindsight is to build agent memory that enables agents to learn and improve over time. This is the role of the `reflect` operation which provides the agent to form broader opinions and observations over time.
For example, imagine a product support agent that is helping a user troubleshoot a problem. It uses a `search-documentation` tool it found on an MCP server. Later in the conversation, the agent discovers that the documentation returned from the tool wasn't for the product the user was asking about. The agent now has an experience in its memory bank. And just like humans, we want that agent to learn from its experience.
As the agent gains more experiences, `reflect` allows the agent to form observations about what worked, what didn't, and what to do differently the next time it encounters a similar task.
---
## Memory Performance & Accuracy
Hindsight has achieved state-of-the-art performance on the LongMemEval benchmark, widely used to assess memory system performance across a variety of conversational
AI scenarios. The current reported performance of Hindsight and other agent memory solutions as of December 2025 is shown here:
![Overview](./hindsight-docs/static/img/hindsight-bench.jpg)
The benchmark performance data for Hindsight and GPT-4o (full context) have been reproduced by research collaborators at the Virginia Tech [Sanghani Center for Artificial Intelligence and Data Analytics](https://sanghani.cs.vt.edu/) and The Washington Post. Other scores are self-reported by software vendors.
A thorough examination of the techniques implemented in Hindsight and detailed breakdowns of benchmark performance are [available on arXiv](https://arxiv.org/abs/2512.12818). This research is currently being prepared for conference submission and the wider peer review process.
The benchmark results from this research can be inspected in our [visual benchmark explorer](https://hindsight-benchmarks.vercel.app). As additional improvements are made to Hindsight, new benchmark data will be available for review using this same tool.
## Quick Start
### Docker (recommended)
@@ -223,6 +243,10 @@ client.reflect(bank_id="my-bank", query="What should I know about Alice?")
- [Slack](https://join.slack.com/t/hindsight-space/shared_invite/zt-3klo21kua-VUCC_zHP5rIcXFB1_5yw6A)
- [GitHub Issues](https://github.com/vectorize-io/hindsight/issues)
---
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=vectorize-io/hindsight&type=date&legend=top-left)](https://www.star-history.com/#vectorize-io/hindsight&type=date&legend=top-left)
---
## Contributing
+2 -2
View File
@@ -2,8 +2,8 @@ apiVersion: v2
name: hindsight
description: Hindsight helm chart
type: application
version: 0.1.6
appVersion: "0.1.6"
version: 0.1.8
appVersion: "0.1.8"
keywords:
- ai
- memory
+137 -1
View File
@@ -1 +1,137 @@
# Memory
# Hindsight API
**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.
## Installation
```bash
pip install hindsight-api
```
## Quick Start
### Run the Server
```bash
# Set your LLM provider
export HINDSIGHT_API_LLM_PROVIDER=openai
export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx
# Start the server (uses embedded PostgreSQL by default)
hindsight-api
```
The server starts at http://localhost:8888 with:
- REST API for memory operations
- MCP server at `/mcp` for tool-use integration
### Use the Python API
```python
from hindsight_api import MemoryEngine
# Create and initialize the memory engine
memory = MemoryEngine()
await memory.initialize()
# Create a memory bank for your agent
bank = await memory.create_memory_bank(
name="my-assistant",
background="A helpful coding assistant"
)
# Store a memory
await memory.retain(
memory_bank_id=bank.id,
content="The user prefers Python for data science projects"
)
# Recall memories
results = await memory.recall(
memory_bank_id=bank.id,
query="What programming language does the user prefer?"
)
# Reflect with reasoning
response = await memory.reflect(
memory_bank_id=bank.id,
query="Should I recommend Python or R for this ML project?"
)
```
## CLI Options
```bash
hindsight-api --help
# Common options
hindsight-api --port 9000 # Custom port (default: 8888)
hindsight-api --host 127.0.0.1 # Bind to localhost only
hindsight-api --workers 4 # Multiple worker processes
hindsight-api --log-level debug # Verbose logging
```
## Configuration
Configure via environment variables:
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_DATABASE_URL` | PostgreSQL connection string | `pg0` (embedded) |
| `HINDSIGHT_API_LLM_PROVIDER` | `openai`, `groq`, `gemini`, `ollama` | `openai` |
| `HINDSIGHT_API_LLM_API_KEY` | API key for LLM provider | - |
| `HINDSIGHT_API_LLM_MODEL` | Model name | `gpt-4o-mini` |
| `HINDSIGHT_API_HOST` | Server bind address | `0.0.0.0` |
| `HINDSIGHT_API_PORT` | Server port | `8888` |
### Example with External PostgreSQL
```bash
export HINDSIGHT_API_DATABASE_URL=postgresql://user:pass@localhost:5432/hindsight
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
hindsight-api
```
## Docker
```bash
docker run --rm -it -p 8888:8888 \
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
ghcr.io/vectorize-io/hindsight:latest
```
## MCP Server
For local MCP integration without running the full API server:
```bash
hindsight-local-mcp
```
This runs a stdio-based MCP server that can be used directly with MCP-compatible clients.
## Key Features
- **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
## Documentation
Full documentation: [https://hindsight.vectorize.io](https://hindsight.vectorize.io)
- [Installation Guide](https://hindsight.vectorize.io/developer/installation)
- [Configuration Reference](https://hindsight.vectorize.io/developer/configuration)
- [API Reference](https://hindsight.vectorize.io/api-reference)
- [Python SDK](https://hindsight.vectorize.io/sdks/python)
## License
Apache 2.0
+16 -12
View File
@@ -506,9 +506,9 @@ class BankListItem(BaseModel):
"""Bank list item with profile summary."""
bank_id: str
name: str
name: str | None = None
disposition: DispositionTraits
background: str
background: str | None = None
created_at: str | None = None
updated_at: str | None = None
@@ -1452,18 +1452,22 @@ def _register_routes(app: FastAPI):
bank_id,
)
def parse_metadata(metadata):
"""Parse result_metadata which may be a string or dict."""
if metadata is None:
return {}
if isinstance(metadata, str):
return json.loads(metadata)
return metadata
return {
"bank_id": bank_id,
"operations": [
{
"id": str(row["operation_id"]),
"task_type": row["operation_type"],
"items_count": row["result_metadata"].get("items_count", 0)
if row["result_metadata"]
else 0,
"document_id": row["result_metadata"].get("document_id")
if row["result_metadata"]
else None,
"items_count": parse_metadata(row["result_metadata"]).get("items_count", 0),
"document_id": parse_metadata(row["result_metadata"]).get("document_id"),
"created_at": row["created_at"].isoformat(),
"status": row["status"],
"error_message": row["error_message"],
@@ -1499,7 +1503,7 @@ def _register_routes(app: FastAPI):
async with acquire_with_retry(pool) as conn:
# Check if operation exists and belongs to this memory bank
result = await conn.fetchrow(
"SELECT bank_id FROM async_operations WHERE id = $1 AND bank_id = $2", op_uuid, bank_id
"SELECT bank_id FROM async_operations WHERE operation_id = $1 AND bank_id = $2", op_uuid, bank_id
)
if not result:
@@ -1508,7 +1512,7 @@ def _register_routes(app: FastAPI):
)
# Delete the operation
await conn.execute("DELETE FROM async_operations WHERE id = $1", op_uuid)
await conn.execute("DELETE FROM async_operations WHERE operation_id = $1", op_uuid)
return {
"success": True,
@@ -1769,13 +1773,13 @@ def _register_routes(app: FastAPI):
async with acquire_with_retry(pool) as conn:
await conn.execute(
"""
INSERT INTO async_operations (id, bank_id, task_type, items_count)
INSERT INTO async_operations (operation_id, bank_id, operation_type, result_metadata)
VALUES ($1, $2, $3, $4)
""",
operation_id,
bank_id,
"retain",
len(contents),
json.dumps({"items_count": len(contents)}),
)
# Submit task to background queue
@@ -311,7 +311,7 @@ class MemoryEngine:
pool = await self._get_pool()
async with acquire_with_retry(pool) as conn:
result = await conn.fetchrow(
"SELECT id FROM async_operations WHERE id = $1", uuid.UUID(operation_id)
"SELECT operation_id FROM async_operations WHERE operation_id = $1", uuid.UUID(operation_id)
)
if not result:
# Operation was cancelled, skip processing
@@ -369,7 +369,7 @@ class MemoryEngine:
try:
pool = await self._get_pool()
async with acquire_with_retry(pool) as conn:
await conn.execute("DELETE FROM async_operations WHERE id = $1", uuid.UUID(operation_id))
await conn.execute("DELETE FROM async_operations WHERE operation_id = $1", uuid.UUID(operation_id))
except Exception as e:
logger.error(f"Failed to delete async operation record {operation_id}: {e}")
@@ -386,7 +386,7 @@ class MemoryEngine:
"""
UPDATE async_operations
SET status = 'failed', error_message = $2
WHERE id = $1
WHERE operation_id = $1
""",
uuid.UUID(operation_id),
truncated_error,
+3 -3
View File
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
[project]
name = "hindsight-api"
version = "0.1.6"
description = "Temporal + Semantic + Entity Memory System for AI agents using PostgreSQL"
version = "0.1.8"
description = "Hindsight: Agent Memory That Works Like Human Memory"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
@@ -25,7 +25,7 @@ dependencies = [
"greenlet>=3.2.4",
"psycopg2-binary>=2.9.11",
"transformers>=4.30.0,<4.46.0",
"torch>=2.0.0,<2.6.0",
"torch>=2.0.0",
"tiktoken>=0.12.0",
"httpx>=0.27.0",
"fastmcp>=2.3.0",
@@ -426,3 +426,185 @@ async def test_document_deletion(api_client):
f"/v1/default/banks/{test_bank_id}/documents/sales-report-q1-2024"
)
assert response.status_code == 404
@pytest.mark.asyncio
async def test_async_retain(api_client):
"""Test asynchronous retain functionality.
When async=true is passed, the retain endpoint should:
1. Return immediately with success and async_=true
2. Process the content in the background
3. Eventually store the memories
"""
import asyncio
test_bank_id = f"async_retain_test_{datetime.now().timestamp()}"
# Store memory with async=true
response = await api_client.post(
f"/v1/default/banks/{test_bank_id}/memories",
json={
"async": True,
"items": [
{
"content": "Alice is a senior engineer at TechCorp. She has been working on the authentication system for 5 years.",
"context": "team introduction"
}
]
}
)
assert response.status_code == 200
result = response.json()
assert result["success"] is True
assert result["async"] is True, "Response should indicate async processing"
assert result["items_count"] == 1
# Check operations endpoint to see the pending operation
response = await api_client.get(f"/v1/default/banks/{test_bank_id}/operations")
assert response.status_code == 200
ops_result = response.json()
assert "operations" in ops_result
# Wait for async processing to complete (poll with timeout)
max_wait_seconds = 30
poll_interval = 0.5
elapsed = 0
memories_found = False
while elapsed < max_wait_seconds:
# Check if memories are stored
response = await api_client.get(
f"/v1/default/banks/{test_bank_id}/memories/list",
params={"limit": 10}
)
assert response.status_code == 200
items = response.json()["items"]
if len(items) > 0:
memories_found = True
break
await asyncio.sleep(poll_interval)
elapsed += poll_interval
assert memories_found, f"Async retain did not complete within {max_wait_seconds} seconds"
# Verify we can recall the stored memory
response = await api_client.post(
f"/v1/default/banks/{test_bank_id}/memories/recall",
json={
"query": "Who works at TechCorp?",
"thinking_budget": 30
}
)
assert response.status_code == 200
search_results = response.json()
assert len(search_results["results"]) > 0, "Should find the asynchronously stored memory"
# Verify Alice is mentioned
found_alice = any("Alice" in r["text"] for r in search_results["results"])
assert found_alice, "Should find Alice in search results"
@pytest.mark.asyncio
async def test_async_retain_parallel(api_client):
"""Test multiple async retain operations running in parallel.
Verifies that:
1. Multiple async operations can be submitted concurrently
2. All operations complete successfully
3. The exact number of documents are processed
"""
import asyncio
test_bank_id = f"async_parallel_test_{datetime.now().timestamp()}"
num_documents = 5
# Prepare multiple documents to retain
documents = [
{
"content": f"Document {i}: This is test content about Person{i} who works at Company{i}.",
"context": f"test document {i}",
"document_id": f"doc_{i}"
}
for i in range(num_documents)
]
# Submit all async retain operations in parallel
async def submit_async_retain(doc):
return await api_client.post(
f"/v1/default/banks/{test_bank_id}/memories",
json={
"async": True,
"items": [doc]
}
)
# Run all submissions concurrently
responses = await asyncio.gather(*[submit_async_retain(doc) for doc in documents])
# Verify all submissions succeeded
for i, response in enumerate(responses):
assert response.status_code == 200, f"Document {i} submission failed"
result = response.json()
assert result["success"] is True
assert result["async"] is True
# Check operations endpoint - should show pending operations
response = await api_client.get(f"/v1/default/banks/{test_bank_id}/operations")
assert response.status_code == 200
# Wait for all async operations to complete (poll with timeout)
max_wait_seconds = 60
poll_interval = 1.0
elapsed = 0
all_docs_processed = False
while elapsed < max_wait_seconds:
# Check document count
response = await api_client.get(f"/v1/default/banks/{test_bank_id}/documents")
assert response.status_code == 200
docs = response.json()["items"]
if len(docs) >= num_documents:
all_docs_processed = True
break
await asyncio.sleep(poll_interval)
elapsed += poll_interval
assert all_docs_processed, f"Expected {num_documents} documents, but only {len(docs)} were processed within {max_wait_seconds} seconds"
# Verify exact document count
response = await api_client.get(f"/v1/default/banks/{test_bank_id}/documents")
assert response.status_code == 200
final_docs = response.json()["items"]
assert len(final_docs) == num_documents, f"Expected exactly {num_documents} documents, got {len(final_docs)}"
# Verify each document exists
doc_ids = {doc["id"] for doc in final_docs}
for i in range(num_documents):
assert f"doc_{i}" in doc_ids, f"Document doc_{i} not found"
# Verify memories were created for all documents
response = await api_client.get(
f"/v1/default/banks/{test_bank_id}/memories/list",
params={"limit": 100}
)
assert response.status_code == 200
memories = response.json()["items"]
assert len(memories) >= num_documents, f"Expected at least {num_documents} memories, got {len(memories)}"
# Verify we can recall content from different documents
for i in [0, num_documents - 1]: # Check first and last
response = await api_client.post(
f"/v1/default/banks/{test_bank_id}/memories/recall",
json={
"query": f"Who works at Company{i}?",
"thinking_budget": 30
}
)
assert response.status_code == 200
results = response.json()["results"]
assert len(results) > 0, f"Should find memories for document {i}"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "hindsight-cli"
version = "0.1.6"
version = "0.1.8"
edition = "2021"
authors = ["Hindsight Team"]
description = "A beautiful CLI for Hindsight - semantic memory system"
+2 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "hindsight-client"
version = "0.1.6"
version = "0.1.8"
description = "Python client for Hindsight - Semantic memory system with personality-driven thinking"
authors = [
{name = "Hindsight Team"}
@@ -20,6 +20,7 @@ dependencies = [
test = [
"pytest>=7.0.0",
"pytest-asyncio>=0.21.0",
"requests>=2.28.0",
]
[build-system]
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@vectorize-io/hindsight-client",
"version": "0.1.6",
"version": "0.1.8",
"description": "TypeScript client for Hindsight - Semantic memory system with personality-driven thinking",
"main": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hindsight-control-plane",
"version": "0.1.6",
"version": "0.1.8",
"private": true,
"scripts": {
"dev": "next dev",
@@ -1,7 +1,6 @@
"use client";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react";
import { BankSelector } from "@/components/bank-selector";
import { Sidebar } from "@/components/sidebar";
import { DataView } from "@/components/data-view";
@@ -10,7 +9,6 @@ import { EntitiesView } from "@/components/entities-view";
import { ThinkView } from "@/components/think-view";
import { SearchDebugView } from "@/components/search-debug-view";
import { BankProfileView } from "@/components/bank-profile-view";
import { useBank } from "@/lib/bank-context";
type NavItem = "recall" | "reflect" | "data" | "documents" | "entities" | "profile";
type DataSubTab = "world" | "experience" | "opinion";
@@ -19,19 +17,11 @@ export default function BankPage() {
const params = useParams();
const router = useRouter();
const searchParams = useSearchParams();
const { currentBank, setCurrentBank } = useBank();
const bankId = params.bankId as string;
const view = (searchParams.get("view") || "profile") as NavItem;
const subTab = (searchParams.get("subTab") || "world") as DataSubTab;
// Sync URL bank with context
useEffect(() => {
if (bankId && bankId !== currentBank) {
setCurrentBank(bankId);
}
}, [bankId, currentBank, setCurrentBank]);
const handleTabChange = (tab: NavItem) => {
router.push(`/banks/${bankId}?view=${tab}`);
};
+82
View File
@@ -0,0 +1,82 @@
# Hindsight Benchmarks
This directory contains benchmark suites for evaluating Hindsight's memory capabilities.
## Prerequisites
1. Set up your environment variables in `.env` at the project root:
```bash
cp .env.example .env
# Edit .env with your API keys
```
2. Make sure you have `uv` installed.
## Available Benchmarks
### LoComo
Tests conversational memory with multi-turn dialogues.
```bash
# Run from project root
./scripts/benchmarks/run-locomo.sh
# With options
./scripts/benchmarks/run-locomo.sh --max-conversations 10
./scripts/benchmarks/run-locomo.sh --skip-ingestion # Reuse existing data
./scripts/benchmarks/run-locomo.sh --use-think # Use think API
./scripts/benchmarks/run-locomo.sh --conversation conv-26 # Single conversation
```
**Options:**
- `--max-conversations N` - Limit number of conversations
- `--max-questions N` - Limit questions per conversation
- `--skip-ingestion` - Skip data ingestion, use existing
- `--use-think` - Use think API instead of search + LLM
- `--conversation NAME` - Run specific conversation only
- `--api-url URL` - Custom API URL (default: local memory)
- `--only-failed` - Retry only failed questions
- `--only-invalid` - Retry only invalid questions
### LongMemEval
Tests long-term memory across different categories.
```bash
# Run from project root
./scripts/benchmarks/run-longmemeval.sh
# With options
./scripts/benchmarks/run-longmemeval.sh --max-instances 50
./scripts/benchmarks/run-longmemeval.sh --category single-session-user
./scripts/benchmarks/run-longmemeval.sh --parallel 4 # Faster evaluation
```
**Options:**
- `--max-instances N` - Limit total questions
- `--max-instances-per-category N` - Limit per category
- `--skip-ingestion` - Skip data ingestion
- `--category NAME` - Filter by category:
- `single-session-user`
- `multi-session`
- `single-session-preference`
- `temporal-reasoning`
- `knowledge-update`
- `single-session-assistant`
- `--parallel N` - Parallel instances (default: 1)
- `--only-failed` - Retry failed questions
- `--fill` - Resume interrupted runs
## Visualizer
View benchmark results in a web UI:
```bash
./scripts/benchmarks/start-visualizer.sh
# Opens at http://localhost:8001
```
## Results
Results are saved in JSON format in each benchmark's `results/` directory.
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "hindsight-dev"
version = "0.1.6"
version = "0.1.8"
description = "Development utilities for Hindsight"
requires-python = ">=3.11"
dependencies = [
@@ -0,0 +1,71 @@
---
sidebar_position: 2
---
# Ingest Data (New Format)
This is a demo of the new code snippet approach. Code examples are pulled from executable script files.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import retainPy from '!!raw-loader!@site/examples/api/retain.py';
import retainMjs from '!!raw-loader!@site/examples/api/retain.mjs';
import retainSh from '!!raw-loader!@site/examples/api/retain.sh';
:::tip How This Works
The code examples below are extracted from actual runnable script files in `examples/api/`.
When CI runs these scripts, it validates the documentation is correct.
:::
## Store a Single Memory
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-basic" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-basic" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={retainSh} section="retain-basic" language="bash" />
</TabItem>
</Tabs>
## Store with Context
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-with-context" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-with-context" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={retainSh} section="retain-with-context" language="bash" />
</TabItem>
</Tabs>
## Batch Ingestion
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-batch" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-batch" language="javascript" />
</TabItem>
</Tabs>
## Async Ingestion
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-async" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-async" language="javascript" />
</TabItem>
</Tabs>
@@ -1,6 +1,10 @@
# Installation
Hindsight can be deployed in three ways depending on your infrastructure and requirements.
Hindsight can be deployed in several ways depending on your infrastructure and requirements.
:::tip Don't want to manage infrastructure?
**[Hindsight Cloud](https://vectorize.io/hindsight/cloud)** is a fully managed service that handles all infrastructure, scaling, and maintenance. We're onboarding design partners now — [request early access](https://vectorize.io/hindsight/cloud).
:::
## Prerequisites
@@ -16,7 +16,7 @@ This is ideal for:
### With uvx (recommended)
```bash
uvx hindsight-api@latest hindsight-local-mcp
uvx --from hindsight-api hindsight-local-mcp
```
### With pip
@@ -35,7 +35,7 @@ Add to your Claude Code MCP settings (`~/.claude/claude_desktop_config.json`):
"mcpServers": {
"hindsight": {
"command": "uvx",
"args": ["hindsight-api@latest", "hindsight-local-mcp"],
"args": ["--from", "hindsight-api", "hindsight-local-mcp"],
"env": {
"HINDSIGHT_API_LLM_API_KEY": "your-openai-key"
}
@@ -53,7 +53,7 @@ By default, memories are stored in a bank called `mcp`. To use a different bank:
"mcpServers": {
"hindsight": {
"command": "uvx",
"args": ["hindsight-api@latest", "hindsight-local-mcp"],
"args": ["--from", "hindsight-api", "hindsight-local-mcp"],
"env": {
"HINDSIGHT_API_LLM_API_KEY": "your-openai-key",
"HINDSIGHT_API_MCP_LOCAL_BANK_ID": "my-personal-memory"
+6
View File
@@ -174,6 +174,12 @@ const config: Config = {
label: 'Changelog',
className: 'navbar-item-changelog',
},
{
href: 'https://vectorize.io/hindsight/cloud',
position: 'right',
label: 'Hindsight Cloud',
className: 'navbar-item-cloud',
},
{
href: 'https://github.com/vectorize-io/hindsight',
position: 'right',
+82
View File
@@ -0,0 +1,82 @@
# API Documentation Examples
This directory contains runnable example scripts that serve as the source of truth for code samples in the documentation.
## How It Works
1. **Scripts are runnable** - Each file can be executed as a smoke test
2. **Markers define sections** - Code between `# [docs:section-name]` and `# [/docs:section-name]` markers is extracted
3. **Docs import at build time** - MDX files use `raw-loader` to import scripts, then `CodeSnippet` extracts marked sections
## File Structure
| File | Documentation | Description |
|------|---------------|-------------|
| `quickstart.py/mjs/sh` | quickstart.md | Getting started examples |
| `retain.py/mjs/sh` | retain.md | Memory ingestion examples |
| `recall.py/mjs/sh` | recall.md | Memory retrieval examples |
| `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 |
| `main-methods.py` | main-methods.md | Core method examples |
| `cli-reference.sh` | cli.md | CLI command examples |
## Running Examples
```bash
# Run all Python examples
for f in *.py; do python "$f"; done
# Run all Node.js examples
for f in *.mjs; do node "$f"; done
# Run all CLI examples
for f in *.sh; do bash "$f"; done
```
Requires a running Hindsight server at `http://localhost:8888` (or set `HINDSIGHT_API_URL`).
## What's NOT Covered
### 1. OpenAPI Auto-Generated Docs (`/api-reference/*`)
These pages are generated directly from the OpenAPI specification. The spec itself is the source of truth, and the generated docs reflect it automatically. No manual code examples to validate.
### 2. Interactive CLI Commands
| Command | Reason |
|---------|--------|
| `hindsight configure` | Requires interactive user input (prompts for API URL, credentials) |
| `hindsight configure --show` | Displays sensitive configuration, not suitable for automated tests |
### 3. Installation/Setup Instructions
Documentation sections covering `pip install`, `npm install`, or system setup are instructions, not executable code samples. These are validated by the CI environment setup itself.
### 4. Error Handling Examples
Some docs show error responses (e.g., "what happens when bank doesn't exist"). These require intentionally broken states that would fail smoke tests. Error behavior is covered by unit tests instead.
## Adding New Examples
1. Create or edit the appropriate script file
2. Add markers around the new code section:
```python
# [docs:my-new-section]
client.some_method(...)
# [/docs:my-new-section]
```
3. Reference in the MDX file:
```mdx
import myScript from '!!raw-loader!@site/examples/api/my-script.py';
<CodeSnippet code={myScript} section="my-new-section" language="python" />
```
4. Run the script locally to verify it works
## Marker Format
- **Python/Bash**: `# [docs:section-name]` / `# [/docs:section-name]`
- **JavaScript**: `// [docs:section-name]` / `// [/docs:section-name]`
Section names should be kebab-case and descriptive (e.g., `retain-with-context`, `recall-basic`).
+209
View File
@@ -0,0 +1,209 @@
#!/bin/bash
# CLI Reference examples for Hindsight
# Tests all documented CLI commands and flags
# Run: bash examples/api/cli-reference.sh
set -e
HINDSIGHT_URL="${HINDSIGHT_API_URL:-http://localhost:8888}"
BANK_ID="cli-test-bank"
DOC_ID="test-document-001"
# =============================================================================
# Setup
# =============================================================================
hindsight configure --api-url "$HINDSIGHT_URL"
# Create test data with a known document ID
hindsight memory retain "$BANK_ID" "Alice works at Google as a software engineer" --document-id "$DOC_ID"
hindsight memory retain "$BANK_ID" "Bob is a data scientist who collaborates with Alice" --document-id "$DOC_ID"
hindsight memory retain "$BANK_ID" "Alice and Bob work on machine learning projects"
# Wait a moment for processing
sleep 2
# =============================================================================
# Configuration (cli.md - Configuration section)
# =============================================================================
# [docs:cli-configure]
hindsight configure --api-url http://localhost:8888
# [/docs:cli-configure]
# =============================================================================
# Core Memory Commands (cli.md - Core Commands section)
# =============================================================================
# [docs:cli-retain-basic]
hindsight memory retain $BANK_ID "Alice works at Google as a software engineer"
# [/docs:cli-retain-basic]
# [docs:cli-retain-context]
hindsight memory retain $BANK_ID "Bob loves hiking" --context "hobby discussion"
# [/docs:cli-retain-context]
# [docs:cli-retain-async]
hindsight memory retain $BANK_ID "Meeting notes" --async
# [/docs:cli-retain-async]
# [docs:cli-recall-basic]
hindsight memory recall $BANK_ID "What does Alice do?"
# [/docs:cli-recall-basic]
# [docs:cli-recall-options]
hindsight memory recall $BANK_ID "hiking recommendations" \
--budget high \
--max-tokens 8192
# [/docs:cli-recall-options]
# [docs:cli-recall-fact-type]
hindsight memory recall $BANK_ID "query" --fact-type world,opinion
# [/docs:cli-recall-fact-type]
# [docs:cli-recall-trace]
hindsight memory recall $BANK_ID "query" --trace
# [/docs:cli-recall-trace]
# [docs:cli-reflect-basic]
hindsight memory reflect $BANK_ID "What do you know about Alice?"
# [/docs:cli-reflect-basic]
# [docs:cli-reflect-context]
hindsight memory reflect $BANK_ID "Should I learn Python?" --context "career advice"
# [/docs:cli-reflect-context]
# [docs:cli-reflect-budget]
hindsight memory reflect $BANK_ID "Summarize my week" --budget high
# [/docs:cli-reflect-budget]
# =============================================================================
# Bank Management (cli.md - Bank Management section)
# =============================================================================
# [docs:cli-bank-list]
hindsight bank list
# [/docs:cli-bank-list]
# [docs:cli-bank-profile]
hindsight bank profile $BANK_ID
# [/docs:cli-bank-profile]
# [docs:cli-bank-stats]
hindsight bank stats $BANK_ID
# [/docs:cli-bank-stats]
# [docs:cli-bank-name]
hindsight bank name $BANK_ID "My Assistant"
# [/docs:cli-bank-name]
# [docs:cli-bank-background]
hindsight bank background $BANK_ID "I am a helpful AI assistant interested in technology"
# [/docs:cli-bank-background]
# [docs:cli-bank-background-no-disposition]
hindsight bank background $BANK_ID "Background text" --no-update-disposition
# [/docs:cli-bank-background-no-disposition]
# =============================================================================
# Document Management (cli.md - Document Management section)
# =============================================================================
# [docs:cli-document-list]
hindsight document list $BANK_ID
# [/docs:cli-document-list]
# [docs:cli-document-get]
hindsight document get $BANK_ID $DOC_ID
# [/docs:cli-document-get]
# [docs:cli-document-delete]
# Create a temp document to delete
hindsight memory retain $BANK_ID "Temporary content" --document-id "temp-doc-to-delete"
sleep 1
hindsight document delete $BANK_ID temp-doc-to-delete
# [/docs:cli-document-delete]
# =============================================================================
# Entity Management (cli.md - Entity Management section)
# =============================================================================
# [docs:cli-entity-list]
hindsight entity list $BANK_ID
# [/docs:cli-entity-list]
# Get an entity ID from the list output and use it
ENTITY_ID=$(hindsight entity list $BANK_ID -o json 2>/dev/null | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "")
if [ -n "$ENTITY_ID" ]; then
# [docs:cli-entity-get]
hindsight entity get $BANK_ID $ENTITY_ID
# [/docs:cli-entity-get]
# [docs:cli-entity-regenerate]
hindsight entity regenerate $BANK_ID $ENTITY_ID
# [/docs:cli-entity-regenerate]
else
echo "No entities found yet, skipping entity get/regenerate"
fi
# =============================================================================
# Output Formats (cli.md - Output Formats section)
# =============================================================================
# [docs:cli-output-json]
hindsight memory recall $BANK_ID "query" -o json
# [/docs:cli-output-json]
# [docs:cli-output-yaml]
hindsight memory recall $BANK_ID "query" -o yaml
# [/docs:cli-output-yaml]
# =============================================================================
# Global Options (cli.md - Global Options section)
# =============================================================================
# [docs:cli-verbose]
hindsight memory recall $BANK_ID "Alice" -v
# [/docs:cli-verbose]
# [docs:cli-help]
hindsight --help
# [/docs:cli-help]
# [docs:cli-version]
hindsight --version
# [/docs:cli-version]
# =============================================================================
# Cleanup
# =============================================================================
curl -s -X DELETE "${HINDSIGHT_URL}/v1/default/banks/${BANK_ID}" > /dev/null
echo "cli-reference.sh: All examples passed"
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env node
/**
* Documents API examples for Hindsight (Node.js)
* Run: node examples/api/documents.mjs
*/
import { HindsightClient, sdk, createClient, createConfig } 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 });
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:document-retain]
// Retain with document ID
await client.retain('my-bank', 'Alice presented the Q4 roadmap...', {
document_id: 'meeting-2024-03-15'
});
// Batch retain
await client.retainBatch('my-bank', [
{ content: 'Item 1: Product launch delayed to Q2' },
{ content: 'Item 2: New hiring targets announced' },
{ content: 'Item 3: Budget approved for ML team' }
], { documentId: 'meeting-2024-03-15' });
// [/docs:document-retain]
// [docs:document-update]
// Original
await client.retain('my-bank', 'Project deadline: March 31', {
document_id: 'project-plan'
});
// Update
await client.retain('my-bank', 'Project deadline: April 15 (extended)', {
document_id: 'project-plan'
});
// [/docs:document-update]
// [docs:document-get]
const apiClient = createClient(createConfig({ baseUrl: 'http://localhost:8888' }));
// Get document to expand context from recall results
const { data: doc } = await sdk.getDocument({
client: apiClient,
path: { bank_id: 'my-bank', document_id: 'meeting-2024-03-15' }
});
console.log(`Document: ${doc.id}`);
console.log(`Original text: ${doc.original_text}`);
console.log(`Memory count: ${doc.memory_unit_count}`);
console.log(`Created: ${doc.created_at}`);
// [/docs:document-get]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await fetch(`${HINDSIGHT_URL}/v1/default/banks/my-bank`, { method: 'DELETE' });
console.log('documents.mjs: All examples passed');
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env python3
"""
Documents API examples for Hindsight.
Run: python examples/api/documents.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)
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:document-retain]
# Retain with document ID
client.retain(
bank_id="my-bank",
content="Alice presented the Q4 roadmap...",
document_id="meeting-2024-03-15"
)
# Batch retain for a document
client.retain_batch(
bank_id="my-bank",
items=[
{"content": "Item 1: Product launch delayed to Q2"},
{"content": "Item 2: New hiring targets announced"},
{"content": "Item 3: Budget approved for ML team"}
],
document_id="meeting-2024-03-15"
)
# [/docs:document-retain]
# [docs:document-update]
# Original
client.retain(
bank_id="my-bank",
content="Project deadline: March 31",
document_id="project-plan"
)
# Update (deletes old facts, creates new ones)
client.retain(
bank_id="my-bank",
content="Project deadline: April 15 (extended)",
document_id="project-plan"
)
# [/docs:document-update]
# [docs:document-get]
import asyncio
from hindsight_client_api import ApiClient, Configuration
from hindsight_client_api.api import DefaultApi
async def get_document_example():
config = Configuration(host="http://localhost:8888")
api_client = ApiClient(config)
api = DefaultApi(api_client)
# Get document to expand context from recall results
doc = await api.get_document(
bank_id="my-bank",
document_id="meeting-2024-03-15"
)
print(f"Document: {doc.id}")
print(f"Original text: {doc.original_text}")
print(f"Memory count: {doc.memory_unit_count}")
print(f"Created: {doc.created_at}")
asyncio.run(get_document_example())
# [/docs:document-get]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
print("documents.py: All examples passed")
+125
View File
@@ -0,0 +1,125 @@
#!/usr/bin/env python3
"""
Main Methods overview examples for Hindsight.
Run: python examples/api/main-methods.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)
# =============================================================================
# Doc Examples - Retain Section
# =============================================================================
# [docs:main-retain]
# Store a single fact
client.retain(
bank_id="my-bank",
content="Alice joined Google in March 2024 as a Senior ML Engineer"
)
# Store a conversation
conversation = """
User: What did you work on today?
Assistant: I reviewed the new ML pipeline architecture.
User: How did it look?
Assistant: Promising, but needs better error handling.
"""
client.retain(
bank_id="my-bank",
content=conversation,
context="Daily standup conversation"
)
# Batch retain multiple items
client.retain_batch(
bank_id="my-bank",
items=[
{"content": "Bob prefers Python for data science"},
{"content": "Alice recommends using pytest for testing"},
{"content": "The team uses GitHub for code reviews"}
]
)
# [/docs:main-retain]
# =============================================================================
# Doc Examples - Recall Section
# =============================================================================
# [docs:main-recall]
# Basic search
results = client.recall(
bank_id="my-bank",
query="What does Alice do at Google?"
)
for result in results.results:
print(f"- {result.text}")
# Search with options
results = client.recall(
bank_id="my-bank",
query="What happened last spring?",
budget="high", # More thorough graph traversal
max_tokens=8192, # Return more context
types=["world"] # Only world facts
)
# Include entity information
results = client.recall(
bank_id="my-bank",
query="Tell me about Alice",
include_entities=True,
max_entity_tokens=500
)
# Check entity details
for entity in results.entities or []:
print(f"Entity: {entity.name}")
print(f"Observations: {entity.observations}")
# [/docs:main-recall]
# =============================================================================
# Doc Examples - Reflect Section
# =============================================================================
# [docs:main-reflect]
# Basic reflect
response = client.reflect(
bank_id="my-bank",
query="Should we adopt TypeScript for our backend?"
)
print(response.text)
print("\nBased on:", len(response.based_on or []), "facts")
# Reflect with options
response = client.reflect(
bank_id="my-bank",
query="What are Alice's strengths for the team lead role?",
budget="high" # More thorough reasoning
)
# See which facts influenced the response
for fact in response.based_on or []:
print(f"- {fact.text}")
# [/docs:main-reflect]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
print("main-methods.py: All examples passed")
@@ -0,0 +1,47 @@
#!/usr/bin/env node
/**
* Memory Banks API examples for Hindsight (Node.js)
* Run: node examples/api/memory-banks.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 });
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:create-bank]
await client.createBank('my-bank', {
name: 'Research Assistant',
background: 'I am a research assistant specializing in machine learning',
disposition: {
skepticism: 4,
literalism: 3,
empathy: 3
}
});
// [/docs:create-bank]
// [docs:bank-background]
await client.createBank('financial-advisor', {
background: `I am a conservative financial advisor with 20 years of experience.
I prioritize capital preservation over aggressive growth.
I have seen multiple market crashes and believe in diversification.`
});
// [/docs:bank-background]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await fetch(`${HINDSIGHT_URL}/v1/default/banks/my-bank`, { method: 'DELETE' });
await fetch(`${HINDSIGHT_URL}/v1/default/banks/financial-advisor`, { method: 'DELETE' });
console.log('memory-banks.mjs: All examples passed');
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""
Memory Banks API examples for Hindsight.
Run: python examples/api/memory-banks.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)
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:create-bank]
client.create_bank(
bank_id="my-bank",
name="Research Assistant",
background="I am a research assistant specializing in machine learning",
disposition={
"skepticism": 4,
"literalism": 3,
"empathy": 3
}
)
# [/docs:create-bank]
# [docs:bank-background]
client.create_bank(
bank_id="financial-advisor",
background="""I am a conservative financial advisor with 20 years of experience.
I prioritize capital preservation over aggressive growth.
I have seen multiple market crashes and believe in diversification."""
)
# [/docs:bank-background]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/financial-advisor")
print("memory-banks.py: All examples passed")
+104
View File
@@ -0,0 +1,104 @@
#!/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",
disposition={"skepticism": 2, "literalism": 2, "empathy": 4}
)
client.create_bank(
bank_id="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")
@@ -0,0 +1,34 @@
#!/usr/bin/env node
/**
* Quickstart examples for Hindsight API (Node.js)
* Run: node examples/api/quickstart.mjs
*/
const HINDSIGHT_URL = process.env.HINDSIGHT_API_URL || 'http://localhost:8888';
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:quickstart-full]
import { HindsightClient } from '@vectorize-io/hindsight-client';
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
// Retain: Store information
await client.retain('my-bank', 'Alice works at Google as a software engineer');
// Recall: Search memories
await client.recall('my-bank', 'What does Alice do?');
// Reflect: Generate response
await client.reflect('my-bank', 'Tell me about Alice');
// [/docs:quickstart-full]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await fetch(`${HINDSIGHT_URL}/v1/default/banks/my-bank`, { method: 'DELETE' });
console.log('quickstart.mjs: All examples passed');
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env python3
"""
Quickstart examples for Hindsight API.
Run: python examples/api/quickstart.py
"""
import os
import requests
HINDSIGHT_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:quickstart-full]
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
# Retain: Store information
client.retain(bank_id="my-bank", content="Alice works at Google as a software engineer")
# Recall: Search memories
client.recall(bank_id="my-bank", query="What does Alice do?")
# Reflect: Generate disposition-aware response
client.reflect(bank_id="my-bank", query="Tell me about Alice")
# [/docs:quickstart-full]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
print("quickstart.py: All examples passed")
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# Quickstart examples for Hindsight CLI
# Run: bash examples/api/quickstart.sh
set -e
HINDSIGHT_URL="${HINDSIGHT_API_URL:-http://localhost:8888}"
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:quickstart-full]
# Retain: Store information
hindsight memory retain my-bank "Alice works at Google as a software engineer"
# Recall: Search memories
hindsight memory recall my-bank "What does Alice do?"
# Reflect: Generate response
hindsight memory reflect my-bank "Tell me about Alice"
# [/docs:quickstart-full]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
curl -s -X DELETE "${HINDSIGHT_URL}/v1/default/banks/my-bank" > /dev/null
echo "quickstart.sh: All examples passed"
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env node
/**
* Recall API examples for Hindsight (Node.js)
* Run: node examples/api/recall.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 for recall examples
await client.retain('my-bank', 'Alice works at Google as a software engineer');
await client.retain('my-bank', 'Alice loves hiking on weekends');
await client.retain('my-bank', 'Bob is a data scientist who works with Alice');
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:recall-basic]
const response = await client.recall('my-bank', 'What does Alice do?');
for (const r of response.results) {
console.log(`${r.text} (score: ${r.weight})`);
}
// [/docs:recall-basic]
// [docs:recall-with-options]
const detailedResponse = await client.recall('my-bank', 'What does Alice do?', {
types: ['world', 'experience'],
budget: 'high',
maxTokens: 8000,
trace: true
});
// Access results
for (const r of detailedResponse.results) {
console.log(`${r.text} (score: ${r.weight})`);
}
// [/docs:recall-with-options]
// [docs:recall-budget-levels]
// Quick lookup
const quickResults = await client.recall('my-bank', "Alice's email", { budget: 'low' });
// Deep exploration
const deepResults = await client.recall('my-bank', 'How are Alice and Bob connected?', { budget: 'high' });
// [/docs:recall-budget-levels]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await fetch(`${HINDSIGHT_URL}/v1/default/banks/my-bank`, { method: 'DELETE' });
console.log('recall.mjs: All examples passed');
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""
Recall API examples for Hindsight.
Run: python examples/api/recall.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 for recall examples
client.retain(bank_id="my-bank", content="Alice works at Google as a software engineer")
client.retain(bank_id="my-bank", content="Alice loves hiking on weekends")
client.retain(bank_id="my-bank", content="Bob is a data scientist who works with Alice")
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:recall-basic]
response = client.recall(bank_id="my-bank", query="What does Alice do?")
for r in response.results:
print(f"- {r.text}")
# [/docs:recall-basic]
# [docs:recall-with-options]
response = client.recall(
bank_id="my-bank",
query="What does Alice do?",
types=["world", "experience"],
budget="high",
max_tokens=8000,
trace=True,
include_entities=True,
max_entity_tokens=500
)
# Access results
for r in response.results:
print(f"- {r.text}")
# Access entity observations (if include_entities=True)
if response.entities:
for entity_id, entity in response.entities.items():
print(f"Entity: {entity.canonical_name}")
# [/docs:recall-with-options]
# [docs:recall-world-only]
# Only world facts (objective information)
world_facts = client.recall(
bank_id="my-bank",
query="Where does Alice work?",
types=["world"]
)
# [/docs:recall-world-only]
# [docs:recall-experience-only]
# Only experience (conversations and events)
experience = client.recall(
bank_id="my-bank",
query="What have I recommended?",
types=["experience"]
)
# [/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)
# Smaller budget for quick lookups
results = client.recall(bank_id="my-bank", query="Alice's email", max_tokens=500)
# [/docs:recall-token-budget]
# [docs:recall-include-entities]
response = client.recall(
bank_id="my-bank",
query="What does Alice do?",
max_tokens=4096, # Budget for memories
include_entities=True,
max_entity_tokens=1000 # Budget for entity observations
)
# Access the additional context
entities = response.entities or []
# [/docs:recall-include-entities]
# [docs:recall-budget-levels]
# Quick lookup
results = client.recall(bank_id="my-bank", query="Alice's email", budget="low")
# Deep exploration
results = client.recall(bank_id="my-bank", query="How are Alice and Bob connected?", budget="high")
# [/docs:recall-budget-levels]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
print("recall.py: All examples passed")
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
# Recall API examples for Hindsight CLI
# Run: bash examples/api/recall.sh
set -e
HINDSIGHT_URL="${HINDSIGHT_API_URL:-http://localhost:8888}"
# =============================================================================
# Setup (not shown in docs)
# =============================================================================
hindsight memory retain my-bank "Alice works at Google as a software engineer"
hindsight memory retain my-bank "Alice loves hiking on weekends"
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:recall-basic]
hindsight memory recall my-bank "What does Alice do?"
# [/docs:recall-basic]
# [docs:recall-with-options]
hindsight memory recall my-bank "hiking recommendations" \
--budget high \
--max-tokens 8192
# [/docs:recall-with-options]
# [docs:recall-fact-type]
hindsight memory recall my-bank "query" --fact-type world,opinion
# [/docs:recall-fact-type]
# [docs:recall-trace]
hindsight memory recall my-bank "query" --trace
# [/docs:recall-trace]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
curl -s -X DELETE "${HINDSIGHT_URL}/v1/default/banks/my-bank" > /dev/null
echo "recall.sh: All examples passed"
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env node
/**
* Reflect API examples for Hindsight (Node.js)
* Run: node examples/api/reflect.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 for reflect examples
await client.retain('my-bank', 'Alice works at Google as a software engineer');
await client.retain('my-bank', 'Alice has been working there for 5 years');
await client.retain('my-bank', 'Alice recently got promoted to senior engineer');
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:reflect-basic]
await client.reflect('my-bank', 'What should I know about Alice?');
// [/docs:reflect-basic]
// [docs:reflect-with-params]
const response = await client.reflect('my-bank', 'What do you think about remote work?', {
budget: 'mid',
context: "We're considering a hybrid work policy"
});
// [/docs:reflect-with-params]
// [docs:reflect-with-context]
// Context helps the LLM understand the current situation
const contextResponse = await client.reflect('my-bank', 'What do you think about the proposal?', {
context: "We're in a budget review meeting discussing Q4 spending"
});
// [/docs:reflect-with-context]
// [docs:reflect-disposition]
// Create a bank with specific disposition
await client.createBank('cautious-advisor', {
background: 'I am a risk-aware financial advisor',
disposition: {
skepticism: 5,
literalism: 4,
empathy: 2
}
});
// Reflect responses will reflect this disposition
const advisorResponse = await client.reflect('cautious-advisor', 'Should I invest in crypto?');
// [/docs:reflect-disposition]
// [docs:reflect-sources]
const sourcesResponse = await client.reflect('my-bank', 'Tell me about Alice');
console.log('Response:', sourcesResponse.text);
console.log('\nBased on:');
for (const fact of sourcesResponse.based_on || []) {
console.log(` - [${fact.type}] ${fact.text}`);
}
// [/docs:reflect-sources]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await fetch(`${HINDSIGHT_URL}/v1/default/banks/my-bank`, { method: 'DELETE' });
await fetch(`${HINDSIGHT_URL}/v1/default/banks/cautious-advisor`, { method: 'DELETE' });
console.log('reflect.mjs: All examples passed');
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Reflect API examples for Hindsight.
Run: python examples/api/reflect.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 for reflect examples
client.retain(bank_id="my-bank", content="Alice works at Google as a software engineer")
client.retain(bank_id="my-bank", content="Alice has been working there for 5 years")
client.retain(bank_id="my-bank", content="Alice recently got promoted to senior engineer")
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:reflect-basic]
client.reflect(bank_id="my-bank", query="What should I know about Alice?")
# [/docs:reflect-basic]
# [docs:reflect-with-params]
response = client.reflect(
bank_id="my-bank",
query="What do you think about remote work?",
budget="mid",
context="We're considering a hybrid work policy"
)
# [/docs:reflect-with-params]
# [docs:reflect-with-context]
# Context is passed to the LLM to help it understand the situation
response = client.reflect(
bank_id="my-bank",
query="What do you think about the proposal?",
context="We're in a budget review meeting discussing Q4 spending"
)
# [/docs:reflect-with-context]
# [docs:reflect-disposition]
# Create a bank with specific disposition
client.create_bank(
bank_id="cautious-advisor",
background="I am a risk-aware financial advisor",
disposition={
"skepticism": 5, # Very skeptical of claims
"literalism": 4, # Focuses on exact requirements
"empathy": 2 # Prioritizes facts over feelings
}
)
# Reflect responses will reflect this disposition
response = client.reflect(
bank_id="cautious-advisor",
query="Should I invest in crypto?"
)
# Response will likely emphasize risks and caution
# [/docs:reflect-disposition]
# [docs:reflect-sources]
response = client.reflect(bank_id="my-bank", query="Tell me about Alice")
print("Response:", response.text)
print("\nBased on:")
for fact in response.based_on or []:
print(f" - [{fact.type}] {fact.text}")
# [/docs:reflect-sources]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/cautious-advisor")
print("reflect.py: All examples passed")
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
# Reflect API examples for Hindsight CLI
# Run: bash examples/api/reflect.sh
set -e
HINDSIGHT_URL="${HINDSIGHT_API_URL:-http://localhost:8888}"
# =============================================================================
# Setup (not shown in docs)
# =============================================================================
hindsight memory retain my-bank "Alice works at Google as a software engineer"
hindsight memory retain my-bank "Alice has been working there for 5 years"
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:reflect-basic]
hindsight memory reflect my-bank "What do you know about Alice?"
# [/docs:reflect-basic]
# [docs:reflect-with-context]
hindsight memory reflect my-bank "Should I learn Python?" --context "career advice"
# [/docs:reflect-with-context]
# [docs:reflect-high-budget]
hindsight memory reflect my-bank "Summarize my week" --budget high
# [/docs:reflect-high-budget]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
curl -s -X DELETE "${HINDSIGHT_URL}/v1/default/banks/my-bank" > /dev/null
echo "reflect.sh: All examples passed"
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env node
/**
* Retain API examples for Hindsight (Node.js)
* Run: node examples/api/retain.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 });
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:retain-basic]
await client.retain('my-bank', 'Alice works at Google as a software engineer');
// [/docs:retain-basic]
// [docs:retain-with-context]
await client.retain('my-bank', 'Alice got promoted to senior engineer', {
context: 'career update',
timestamp: '2024-03-15T10:00:00Z'
});
// [/docs:retain-with-context]
// [docs:retain-batch]
await client.retainBatch('my-bank', [
{ content: 'Alice works at Google', context: 'career' },
{ content: 'Bob is a data scientist at Meta', context: 'career' },
{ content: 'Alice and Bob are friends', context: 'relationship' }
], { documentId: 'conversation_001' });
// [/docs:retain-batch]
// [docs:retain-async]
// Start async ingestion (returns immediately)
await client.retainBatch('my-bank', [
{ content: 'Large batch item 1' },
{ content: 'Large batch item 2' },
], {
documentId: 'large-doc',
async: true
});
// [/docs:retain-async]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await fetch(`${HINDSIGHT_URL}/v1/default/banks/my-bank`, { method: 'DELETE' });
console.log('retain.mjs: All examples passed');
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""
Retain API examples for Hindsight.
Run: python examples/api/retain.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)
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:retain-basic]
client.retain(
bank_id="my-bank",
content="Alice works at Google as a software engineer"
)
# [/docs:retain-basic]
# [docs:retain-with-context]
client.retain(
bank_id="my-bank",
content="Alice got promoted to senior engineer",
context="career update",
timestamp="2024-03-15T10:00:00Z"
)
# [/docs:retain-with-context]
# [docs:retain-batch]
client.retain_batch(
bank_id="my-bank",
items=[
{"content": "Alice works at Google", "context": "career"},
{"content": "Bob is a data scientist at Meta", "context": "career"},
{"content": "Alice and Bob are friends", "context": "relationship"}
],
document_id="conversation_001"
)
# [/docs:retain-batch]
# [docs:retain-async]
# Start async ingestion (returns immediately)
result = client.retain_batch(
bank_id="my-bank",
items=[
{"content": "Large batch item 1"},
{"content": "Large batch item 2"},
],
document_id="large-doc",
retain_async=True
)
# Check if it was processed asynchronously
print(result.var_async) # True
# [/docs:retain-async]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank")
print("retain.py: All examples passed")
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# Retain API examples for Hindsight CLI
# Run: bash examples/api/retain.sh
set -e
HINDSIGHT_URL="${HINDSIGHT_API_URL:-http://localhost:8888}"
# =============================================================================
# Doc Examples
# =============================================================================
# [docs:retain-basic]
hindsight memory retain my-bank "Alice works at Google as a software engineer"
# [/docs:retain-basic]
# [docs:retain-with-context]
hindsight memory retain my-bank "Alice got promoted" \
--context "career update"
# [/docs:retain-with-context]
# [docs:retain-async]
hindsight memory retain my-bank "Meeting notes" --async
# [/docs:retain-async]
# =============================================================================
# Cleanup (not shown in docs)
# =============================================================================
curl -s -X DELETE "${HINDSIGHT_URL}/v1/default/banks/my-bank" > /dev/null
echo "retain.sh: All examples passed"
+129
View File
@@ -0,0 +1,129 @@
#!/bin/bash
# Run all documentation example scripts
# Usage: ./examples/run-examples.sh [python|node|cli|all]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HINDSIGHT_URL="${HINDSIGHT_API_URL:-http://localhost:8888}"
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
passed=0
failed=0
skipped=0
run_python_examples() {
echo -e "${YELLOW}Running Python examples...${NC}"
for f in "$SCRIPT_DIR"/api/*.py; do
if [ -f "$f" ]; then
echo -n " $(basename "$f"): "
if python "$f" 2>&1; then
echo -e "${GREEN}PASSED${NC}"
((passed++))
else
echo -e "${RED}FAILED${NC}"
((failed++))
fi
fi
done
}
run_node_examples() {
echo -e "${YELLOW}Running Node.js examples...${NC}"
for f in "$SCRIPT_DIR"/api/*.mjs; do
if [ -f "$f" ]; then
echo -n " $(basename "$f"): "
if node "$f" 2>&1; then
echo -e "${GREEN}PASSED${NC}"
((passed++))
else
echo -e "${RED}FAILED${NC}"
((failed++))
fi
fi
done
}
run_cli_examples() {
echo -e "${YELLOW}Running CLI examples...${NC}"
# Check if hindsight CLI is available
if ! command -v hindsight &> /dev/null; then
echo -e " ${YELLOW}SKIPPED (hindsight CLI not installed)${NC}"
for f in "$SCRIPT_DIR"/api/*.sh; do
if [ -f "$f" ]; then
((skipped++))
fi
done
return
fi
for f in "$SCRIPT_DIR"/api/*.sh; do
if [ -f "$f" ]; then
echo -n " $(basename "$f"): "
if bash "$f" 2>&1; then
echo -e "${GREEN}PASSED${NC}"
((passed++))
else
echo -e "${RED}FAILED${NC}"
((failed++))
fi
fi
done
}
# Wait for server to be ready
wait_for_server() {
echo "Waiting for Hindsight server at $HINDSIGHT_URL..."
for i in {1..30}; do
if curl -s "$HINDSIGHT_URL/health" > /dev/null 2>&1; then
echo "Server is ready!"
return 0
fi
sleep 1
done
echo "Server not available after 30 seconds"
return 1
}
# Main
case "${1:-all}" in
python)
wait_for_server
run_python_examples
;;
node)
wait_for_server
run_node_examples
;;
cli)
wait_for_server
run_cli_examples
;;
all)
wait_for_server
run_python_examples
echo ""
run_node_examples
echo ""
run_cli_examples
;;
*)
echo "Usage: $0 [python|node|cli|all]"
exit 1
;;
esac
echo ""
echo "========================================"
echo -e "Results: ${GREEN}$passed passed${NC}, ${RED}$failed failed${NC}, ${YELLOW}$skipped skipped${NC}"
echo "========================================"
if [ $failed -gt 0 ]; then
exit 1
fi
+1
View File
@@ -22,6 +22,7 @@
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
"raw-loader": "^4.0.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"redocusaurus": "^2.5.0"
@@ -0,0 +1,110 @@
import React from 'react';
import CodeBlock from '@theme/CodeBlock';
interface CodeSnippetProps {
/** Raw file content (use raw-loader to import) */
code: string;
/** Section marker name (e.g., "retain-basic" for [docs:retain-basic]) */
section: string;
/** Language for syntax highlighting */
language: string;
/** Optional title for the code block */
title?: string;
}
/**
* Extracts a marked section from source code.
*
* Markers are in the format:
* - Start: `# [docs:section-name]` (Python/Bash) or `// [docs:section-name]` (JS/TS)
* - End: `# [/docs:section-name]` (Python/Bash) or `// [/docs:section-name]` (JS/TS)
*/
function extractSection(code: string, section: string): string {
// Match both Python/Bash (#) and JS/TS (//) comment styles
const startPattern = new RegExp(`(?:#|//)\\s*\\[docs:${section}\\]`);
const endPattern = new RegExp(`(?:#|//)\\s*\\[/docs:${section}\\]`);
const lines = code.split('\n');
let inSection = false;
const sectionLines: string[] = [];
for (const line of lines) {
if (startPattern.test(line)) {
inSection = true;
continue;
}
if (endPattern.test(line)) {
inSection = false;
continue;
}
if (inSection) {
sectionLines.push(line);
}
}
if (sectionLines.length === 0) {
console.warn(`CodeSnippet: Section "${section}" not found in code`);
return `// Section "${section}" not found`;
}
// Trim leading/trailing empty lines and normalize indentation
return trimAndNormalize(sectionLines);
}
/**
* Trims leading/trailing empty lines and removes common leading indentation.
*/
function trimAndNormalize(lines: string[]): string {
// Remove leading empty lines
while (lines.length > 0 && lines[0].trim() === '') {
lines.shift();
}
// Remove trailing empty lines
while (lines.length > 0 && lines[lines.length - 1].trim() === '') {
lines.pop();
}
if (lines.length === 0) return '';
// Find minimum indentation (ignoring empty lines)
const nonEmptyLines = lines.filter(l => l.trim() !== '');
if (nonEmptyLines.length === 0) return '';
const minIndent = Math.min(
...nonEmptyLines.map(line => {
const match = line.match(/^(\s*)/);
return match ? match[1].length : 0;
})
);
// Remove common indentation
return lines
.map(line => line.slice(minIndent))
.join('\n');
}
/**
* CodeSnippet component for embedding code from example files.
*
* Usage in MDX:
* ```mdx
* import CodeSnippet from '@site/src/components/CodeSnippet';
* import retainPy from '!!raw-loader!@site/examples/api/retain.py';
*
* <CodeSnippet code={retainPy} section="retain-basic" language="python" />
* ```
*/
export default function CodeSnippet({
code,
section,
language,
title
}: CodeSnippetProps): React.ReactElement {
const extractedCode = extractSection(code, section);
return (
<CodeBlock language={language} title={title}>
{extractedCode}
</CodeBlock>
);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

@@ -1,6 +1,6 @@
[project]
name = "hindsight-litellm"
version = "0.1.6"
version = "0.1.8"
description = "Universal LLM memory integration via LiteLLM - works with 100+ providers"
readme = "README.md"
requires-python = ">=3.10"
+1 -1
View File
@@ -1,6 +1,6 @@
# hindsight-all
All-in-one package for Hindsight - Semantic memory system with personality-driven thinking for AI agents.
All-in-one package for Hindsight - Agent Memory That Works Like Human Memory
## Quick Start
+2 -2
View File
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
[project]
name = "hindsight-all"
version = "0.1.6"
description = "All-in-one package for Hindsight - Semantic memory system with personality-driven thinking"
version = "0.1.8"
description = "Hindsight: Agent Memory That Works Like Human Memory - All-in-One Bundle"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
+41 -2
View File
@@ -13,7 +13,7 @@
},
"hindsight-clients/typescript": {
"name": "@vectorize-io/hindsight-client",
"version": "0.1.5",
"version": "0.1.8",
"license": "MIT",
"devDependencies": {
"@hey-api/openapi-ts": "^0.88.0",
@@ -25,7 +25,7 @@
}
},
"hindsight-control-plane": {
"version": "0.1.5",
"version": "0.1.8",
"license": "ISC",
"dependencies": {
"@radix-ui/react-checkbox": "^1.3.3",
@@ -105,6 +105,7 @@
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
"raw-loader": "^4.0.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"redocusaurus": "^2.5.0"
@@ -24244,6 +24245,44 @@
"node": ">=0.10.0"
}
},
"node_modules/raw-loader": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
"integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
"license": "MIT",
"dependencies": {
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0"
}
},
"node_modules/raw-loader/node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
Generated
+7 -5
View File
@@ -1141,7 +1141,7 @@ wheels = [
[[package]]
name = "hindsight-all"
version = "0.1.6"
version = "0.1.8"
source = { editable = "hindsight" }
dependencies = [
{ name = "hindsight-api" },
@@ -1165,7 +1165,7 @@ provides-extras = ["test"]
[[package]]
name = "hindsight-api"
version = "0.1.6"
version = "0.1.8"
source = { editable = "hindsight-api" }
dependencies = [
{ name = "alembic" },
@@ -1249,7 +1249,7 @@ requires-dist = [
{ name = "sentence-transformers", specifier = ">=3.0.0,<3.3.0" },
{ name = "sqlalchemy", specifier = ">=2.0.44" },
{ name = "tiktoken", specifier = ">=0.12.0" },
{ name = "torch", specifier = ">=2.0.0,<2.6.0" },
{ name = "torch", specifier = ">=2.0.0" },
{ name = "transformers", specifier = ">=4.30.0,<4.46.0" },
{ name = "uvicorn", specifier = ">=0.38.0" },
{ name = "wsproto", specifier = ">=1.0.0" },
@@ -1269,7 +1269,7 @@ dev = [
[[package]]
name = "hindsight-client"
version = "0.1.6"
version = "0.1.8"
source = { editable = "hindsight-clients/python" }
dependencies = [
{ name = "aiohttp" },
@@ -1284,6 +1284,7 @@ dependencies = [
test = [
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "requests" },
]
[package.metadata]
@@ -1294,6 +1295,7 @@ requires-dist = [
{ name = "pytest", marker = "extra == 'test'", specifier = ">=7.0.0" },
{ name = "pytest-asyncio", marker = "extra == 'test'", specifier = ">=0.21.0" },
{ name = "python-dateutil", specifier = ">=2.8.2" },
{ name = "requests", marker = "extra == 'test'", specifier = ">=2.28.0" },
{ name = "typing-extensions", specifier = ">=4.7.1" },
{ name = "urllib3", specifier = ">=2.1.0,<3.0.0" },
]
@@ -1301,7 +1303,7 @@ provides-extras = ["test"]
[[package]]
name = "hindsight-dev"
version = "0.1.6"
version = "0.1.8"
source = { editable = "hindsight-dev" }
dependencies = [
{ name = "hindsight-api" },