diff --git a/README.md b/README.md index 1cb95c0..ee5fffc 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Full-featured example applications demonstrating Hindsight integration patterns: - **[sanity-blog-memory](./applications/sanity-blog-memory)** - Syncing Sanity CMS content to Hindsight - **[chat-sdk-multi-platform](./applications/chat-sdk-multi-platform)** - Cross-platform Slack + Discord bot with shared memory (Vercel Chat SDK) - **[stancetracker](./applications/stancetracker)** - Track political stances using AI-powered memory +- **[openclaw-memory](./applications/openclaw-memory)** - OpenClaw messaging gateway with automatic persistent memory ## Notebooks diff --git a/applications/openclaw-memory/.gitignore b/applications/openclaw-memory/.gitignore new file mode 100644 index 0000000..437873b --- /dev/null +++ b/applications/openclaw-memory/.gitignore @@ -0,0 +1,2 @@ +*.local.json +.hindsight/ diff --git a/applications/openclaw-memory/README.md b/applications/openclaw-memory/README.md new file mode 100644 index 0000000..acfacb2 --- /dev/null +++ b/applications/openclaw-memory/README.md @@ -0,0 +1,329 @@ +--- +description: "OpenClaw messaging gateway with automatic persistent memory via Hindsight" +tags: { sdk: "@vectorize-io/hindsight-openclaw", topic: "Agents" } +--- + +# OpenClaw + Hindsight Memory + +Give your OpenClaw agents persistent memory across Slack, Telegram, Discord, and every other channel they live in. The `@vectorize-io/hindsight-openclaw` plugin automatically captures every conversation and recalls relevant context before each agent response — no changes to your agents or prompts required. + +## What This Demonstrates + +- **Automatic retention** — every conversation is stored after each turn without the agent deciding what to save +- **Automatic recall** — relevant memories are injected into context before every agent response +- **Three backends** — Hindsight Cloud (managed), embedded local daemon, or self-hosted API +- **Per-user and per-channel memory isolation** — configurable via `dynamicBankGranularity` +- **Memory inspection** — browse and query stored memories from the terminal + +## Architecture + +``` +Slack / Telegram / Discord / any channel + │ + ▼ + OpenClaw Gateway + │ + hindsight-openclaw plugin + │ + ├─ Before each response ──→ auto-recall ──→ inject relevant memories + │ │ + │ Hindsight API + │ │ + └─ After each response ──→ auto-retain ──→ store conversation +``` + +The LLM you configure for memory extraction runs separately from your agent's LLM. Memory extraction happens in the background and never blocks the agent response. + +## Prerequisites + +1. **OpenClaw installed** with at least one messaging channel configured (Slack, Telegram, Discord, etc.) + +2. **A Hindsight backend** — pick one: + + | Option | Setup | + |--------|-------| + | **Hindsight Cloud** (easiest) | [Sign up](https://ui.hindsight.vectorize.io/signup) for a free `hsk_...` token | + | **Embedded daemon** (local, no extra services) | Just an LLM API key — the daemon starts automatically | + | **Self-hosted API** | Run Hindsight via Docker (see below) | + + For the self-hosted option: + ```bash + export OPENAI_API_KEY=your-key + + docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \ + -e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \ + -v $HOME/.hindsight-docker:/home/hindsight/.pg0 \ + ghcr.io/vectorize-io/hindsight:latest + ``` + +## Quick Start + +**Step 1: Install the plugin** + +```bash +openclaw plugins install @vectorize-io/hindsight-openclaw +``` + +**Step 2: Run the setup wizard** + +Pick the path that matches your backend: + +```bash +# Hindsight Cloud (paste your hsk_... token when prompted) +npx --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup \ + --mode cloud --token hsk_your_token + +# Embedded daemon with OpenAI +npx --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup \ + --mode embedded --provider openai --api-key sk-... + +# Embedded daemon with Claude Code (no separate API key needed) +npx --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup \ + --mode embedded --provider claude-code + +# Self-hosted API +npx --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup \ + --mode api --api-url http://localhost:8888 +``` + +Or run the interactive wizard (no flags) and it will prompt you: + +```bash +npx --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup +``` + +You can also use one of the example config files in `configs/` directly: + +```bash +cp configs/openclaw.cloud.example.json ~/.openclaw/openclaw.json +# edit to fill in your token +``` + +**Step 3: Start OpenClaw** + +```bash +openclaw gateway +``` + +You should see the plugin confirm the backend on startup: + +``` +[Hindsight] ✓ Using provider: openai, model: gpt-4o-mini +``` +or +``` +[Hindsight] External API mode enabled: https://api.hindsight.vectorize.io +[Hindsight] External API health check passed +``` + +## Try It Out + +Send a few messages through any connected channel, then start a new session: + +**Session 1 (Slack DM):** +``` +You: I'm building a TypeScript API and I prefer strict type checking over convenience +OpenClaw: Got it — I'll keep that in mind. What are you working on first? +``` + +**Session 2 (same or different channel):** +``` +You: What do you know about my project preferences? +OpenClaw: You're building a TypeScript API and you prefer strict type checking over convenience. +``` + +That's it. No tool calls, no prompting the agent to "remember" anything — Hindsight extracted the fact and recalled it automatically. + +## How It Works + +**Auto-retain:** After each agent turn, the plugin sends the conversation transcript to Hindsight. The memory engine extracts discrete facts, entities, and relationships and stores them in a bank keyed to the conversation context. + +**Auto-recall:** Before each agent response, the plugin queries Hindsight using the current user message. Relevant memories are prepended (or appended, or injected as a user message) into the agent's context. + +**Feedback loop prevention:** The plugin automatically strips `` tags before retaining, so recalled memories are never re-extracted as new facts. + +The minimal config that enables both behaviors: + +```json +{ + "plugins": { + "entries": { + "hindsight-openclaw": { + "enabled": true, + "config": { + "autoRecall": true, + "autoRetain": true, + "dynamicBankGranularity": ["agent", "user"] + } + } + } + } +} +``` + +## Configuration Reference + +| Key | Default | Description | +|-----|---------|-------------| +| `llmProvider` | — | LLM for memory extraction: `openai`, `anthropic`, `gemini`, `groq`, `ollama`, `claude-code`, `openai-codex` | +| `llmApiKey` | — | API key for the extraction LLM (omit for `claude-code` / `openai-codex`) | +| `llmModel` | provider default | Model override (e.g. `gpt-4o-mini`) | +| `hindsightApiUrl` | — | URL for Cloud or self-hosted Hindsight API | +| `hindsightApiToken` | — | Auth token for Hindsight Cloud | +| `autoRecall` | `true` | Inject memories before each agent response | +| `autoRetain` | `true` | Store conversations after each turn | +| `dynamicBankId` | `true` | Derive bank ID from conversation context | +| `dynamicBankGranularity` | `["agent","channel","user"]` | Which context fields determine the bank ID | +| `bankId` | — | Fixed bank name (when `dynamicBankId` is `false`) | +| `bankIdPrefix` | — | Prefix added to all dynamic bank IDs (e.g. `"prod"`) | +| `recallBudget` | `"mid"` | Retrieval effort: `"low"`, `"mid"`, or `"high"` | +| `recallMaxTokens` | `1024` | Max tokens for injected memories per turn | +| `recallInjectionPosition` | `"prepend"` | Where memories land: `"prepend"`, `"append"`, or `"user"` | + +## Configuration Patterns + +### Default: Per-agent + Per-channel + Per-user (the default) + +The default `dynamicBankGranularity` of `["agent", "channel", "user"]` means each unique combination of bot, conversation, and person gets its own isolated memory store. A Slack DM and a Telegram group chat involving the same user have separate memories. + +No config change needed — this is what the setup wizard configures. + +### Shared bank (all users share one brain) + +All conversations feed into one memory store — useful for a team bot that should remember decisions made by anyone: + +```json +{ + "config": { + "dynamicBankId": false, + "bankId": "my-team-bot" + } +} +``` + +See `configs/openclaw.external.example.json` for a full example of this pattern. + +### Per-user memory (shared across all channels) + +The same user gets the same memories whether they DM the bot or talk to it in a group channel: + +```json +{ + "config": { + "dynamicBankGranularity": ["user"] + } +} +``` + +### Per-agent team brain + +All users talking to the same agent share one memory pool — good for a project-scoped assistant: + +```json +{ + "config": { + "dynamicBankGranularity": ["agent"] + } +} +``` + +### Namespaced environments + +Prefix bank IDs to separate staging and production memories sharing the same backend: + +```json +{ + "config": { + "bankIdPrefix": "prod" + } +} +``` + +## Inspect Memory + +Check what the agent has stored: + +```bash +# Is the embedded daemon running? +uvx hindsight-embed@latest -p openclaw daemon status + +# Search stored memories +uvx hindsight-embed@latest -p openclaw memory recall openclaw "user preferences" + +# Browse the web UI (embedded mode only) +uvx hindsight-embed@latest -p openclaw ui +``` + +Or use the included helper: + +```bash +./scripts/inspect-memory.sh +``` + +Check gateway logs for memory operations: + +```bash +tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight + +# After conversations you should see: +# [Hindsight] Retained X messages for session ... +# [Hindsight] Auto-recall: Injecting X memories +``` + +## Core Files + +| File | Description | +|------|-------------| +| `configs/openclaw.embedded.example.json` | Full config for embedded daemon mode (OpenAI) | +| `configs/openclaw.cloud.example.json` | Config for Hindsight Cloud | +| `configs/openclaw.external.example.json` | Config for self-hosted Hindsight API | +| `scripts/setup.sh` | Interactive setup wrapper around `hindsight-openclaw-setup` | +| `scripts/inspect-memory.sh` | Quick memory inspection via CLI | + +## Common Issues + +**Plugin not found after install** + +```bash +openclaw plugins list | grep hindsight +# If missing, reinstall: +openclaw plugins install @vectorize-io/hindsight-openclaw +``` + +**Connection refused / health check failed** + +For embedded mode, the daemon starts automatically on `openclaw gateway`. If it fails, check the profile log: +```bash +tail -f ~/.hindsight/profiles/openclaw.log +``` + +For Cloud or external API mode, verify your token and URL are correct: +```bash +openclaw config get plugins.entries.hindsight-openclaw.config.hindsightApiUrl +``` + +**No memories recalled in the first session** + +Expected — there's nothing stored yet. Send a few messages, then start a new session. Memory extraction runs asynchronously after each turn, so it may take a moment after the conversation ends. + +**LLM API key not set (embedded mode)** + +The plugin no longer reads `OPENAI_API_KEY` from the environment automatically. Set it explicitly: + +```bash +openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai +openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \ + --ref-source env --ref-provider default --ref-id OPENAI_API_KEY +``` + +Or use a provider that needs no key: `--provider claude-code` or `--provider openai-codex`. + +**First launch takes several minutes** + +On the first run, `hindsight-embed` downloads Python packages including sentence-transformers (~3 GB). Subsequent launches use the cached packages. The plugin auto-retries during this window. + +## Built With + +- [OpenClaw](https://openclaw.ai) — self-hosted AI gateway for messaging platforms +- [@vectorize-io/hindsight-openclaw](https://www.npmjs.com/package/@vectorize-io/hindsight-openclaw) — Hindsight memory plugin for OpenClaw +- [Hindsight](https://vectorize.io/hindsight) — long-term memory for AI agents diff --git a/applications/openclaw-memory/configs/openclaw.cloud.example.json b/applications/openclaw-memory/configs/openclaw.cloud.example.json new file mode 100644 index 0000000..dddd602 --- /dev/null +++ b/applications/openclaw-memory/configs/openclaw.cloud.example.json @@ -0,0 +1,23 @@ +{ + "_note": "Hindsight Cloud mode — memory is managed by Hindsight Cloud, no local daemon or LLM API key needed. Copy the 'plugins' block into your ~/.openclaw/openclaw.json. Replace YOUR_CLOUD_TOKEN_HERE with the hsk_... token from https://ui.hindsight.vectorize.io/signup.", + "plugins": { + "entries": { + "hindsight-openclaw": { + "enabled": true, + "config": { + "hindsightApiUrl": "https://api.hindsight.vectorize.io", + "hindsightApiToken": "YOUR_CLOUD_TOKEN_HERE", + + "autoRecall": true, + "autoRetain": true, + "recallBudget": "mid", + "recallMaxTokens": 1024, + "recallInjectionPosition": "prepend", + + "dynamicBankId": true, + "dynamicBankGranularity": ["agent", "channel", "user"] + } + } + } + } +} diff --git a/applications/openclaw-memory/configs/openclaw.embedded.example.json b/applications/openclaw-memory/configs/openclaw.embedded.example.json new file mode 100644 index 0000000..df3f125 --- /dev/null +++ b/applications/openclaw-memory/configs/openclaw.embedded.example.json @@ -0,0 +1,24 @@ +{ + "_note": "Embedded daemon mode — Hindsight runs locally on this machine. Copy the 'plugins' block into your ~/.openclaw/openclaw.json (merge with existing content). Replace YOUR_OPENAI_KEY_HERE with your actual key, or use 'openclaw config set' with --ref-source env to avoid storing it in plaintext.", + "plugins": { + "entries": { + "hindsight-openclaw": { + "enabled": true, + "config": { + "llmProvider": "openai", + "llmApiKey": "YOUR_OPENAI_KEY_HERE", + "llmModel": "gpt-4o-mini", + + "autoRecall": true, + "autoRetain": true, + "recallBudget": "mid", + "recallMaxTokens": 1024, + "recallInjectionPosition": "prepend", + + "dynamicBankId": true, + "dynamicBankGranularity": ["agent", "channel", "user"] + } + } + } + } +} diff --git a/applications/openclaw-memory/configs/openclaw.external.example.json b/applications/openclaw-memory/configs/openclaw.external.example.json new file mode 100644 index 0000000..cb274f4 --- /dev/null +++ b/applications/openclaw-memory/configs/openclaw.external.example.json @@ -0,0 +1,22 @@ +{ + "_note": "Self-hosted Hindsight API mode — connects to a running Hindsight server (e.g. Docker on localhost:8888). Copy the 'plugins' block into your ~/.openclaw/openclaw.json. Set hindsightApiToken only if your server has auth enabled. This config also shows a shared-bank pattern (dynamicBankId: false) useful for team bots.", + "plugins": { + "entries": { + "hindsight-openclaw": { + "enabled": true, + "config": { + "hindsightApiUrl": "http://localhost:8888", + + "autoRecall": true, + "autoRetain": true, + "recallBudget": "mid", + "recallMaxTokens": 1024, + "recallInjectionPosition": "prepend", + + "dynamicBankId": false, + "bankId": "openclaw-shared" + } + } + } + } +} diff --git a/applications/openclaw-memory/scripts/inspect-memory.sh b/applications/openclaw-memory/scripts/inspect-memory.sh new file mode 100755 index 0000000..ce024d0 --- /dev/null +++ b/applications/openclaw-memory/scripts/inspect-memory.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# inspect-memory.sh — browse memories stored by hindsight-openclaw +# +# Usage: +# ./scripts/inspect-memory.sh + +set -euo pipefail + +PROFILE="openclaw" +EMBED_CMD="uvx hindsight-embed@latest" + +if ! command -v uvx &>/dev/null; then + echo "Error: 'uvx' not found in PATH." + echo "Install uv: https://docs.astral.sh/uv/getting-started/installation/" + echo "" + echo "Or run these commands manually:" + echo " openclaw plugins list | grep hindsight" + echo " tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight" + exit 1 +fi + +echo "=== Hindsight Memory Inspector ===" +echo "" + +# Daemon status +echo "--- Daemon status ---" +$EMBED_CMD -p $PROFILE daemon status 2>/dev/null || echo "(daemon not running — start with 'openclaw gateway')" +echo "" + +# Recent memories +echo "--- Recent memories (bank: $PROFILE) ---" +$EMBED_CMD -p $PROFILE memory list $PROFILE --limit 10 2>/dev/null || echo "(no memories found or daemon not running)" +echo "" + +# Interactive recall +echo "--- Search memories ---" +read -rp "Enter a search query (or press Enter to skip): " QUERY + +if [[ -n "$QUERY" ]]; then + echo "" + $EMBED_CMD -p $PROFILE memory recall $PROFILE "$QUERY" 2>/dev/null || echo "(search failed — is the daemon running?)" + echo "" +fi + +# Offer to open UI +read -rp "Open memory browser UI? [y/N] " OPEN_UI +if [[ "$OPEN_UI" =~ ^[Yy]$ ]]; then + echo "Opening UI..." + $EMBED_CMD -p $PROFILE ui +fi diff --git a/applications/openclaw-memory/scripts/setup.sh b/applications/openclaw-memory/scripts/setup.sh new file mode 100755 index 0000000..8eeb805 --- /dev/null +++ b/applications/openclaw-memory/scripts/setup.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# setup.sh — wrapper around hindsight-openclaw-setup +# +# Usage: +# ./scripts/setup.sh # interactive +# ./scripts/setup.sh --mode cloud # non-interactive (will prompt for token) +# ./scripts/setup.sh --help # full flag list + +set -euo pipefail + +# Check dependencies +if ! command -v openclaw &>/dev/null; then + echo "Error: 'openclaw' not found in PATH." + echo "Install OpenClaw first: https://openclaw.ai" + exit 1 +fi + +if ! command -v npx &>/dev/null; then + echo "Error: 'npx' not found in PATH." + echo "Install Node.js (https://nodejs.org) and try again." + exit 1 +fi + +# Install plugin if not already installed +if ! openclaw plugins list 2>/dev/null | grep -q "hindsight-openclaw"; then + echo "Installing @vectorize-io/hindsight-openclaw plugin..." + openclaw plugins install @vectorize-io/hindsight-openclaw +else + echo "Plugin already installed." +fi + +echo "" +echo "Running Hindsight setup wizard..." +echo "" + +# Pass all args through to the wizard +npx --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup "$@" + +echo "" +echo "Setup complete. Start OpenClaw with:" +echo "" +echo " openclaw gateway" +echo "" +echo "After a few conversations, run ./scripts/inspect-memory.sh to see what was stored." diff --git a/applications/pipecat-memory/README.md b/applications/pipecat-memory/README.md new file mode 100644 index 0000000..d1451a9 --- /dev/null +++ b/applications/pipecat-memory/README.md @@ -0,0 +1,192 @@ +--- +description: "Give Pipecat voice AI pipelines persistent memory across conversations using Hindsight" +tags: { sdk: "hindsight-pipecat", topic: "Voice AI" } +--- + +# Pipecat Memory + +Give [Pipecat](https://github.com/pipecat-ai/pipecat) voice AI pipelines persistent memory across conversations using Hindsight. A single `HindsightMemoryService` frame processor slots between your user context aggregator and LLM service — automatically recalling relevant context before each turn and retaining conversation content after. + +## What This Demonstrates + +- **Automatic recall** — Hindsight injects relevant memories into the LLM context before each turn +- **Session retention** — conversation turns are stored to Hindsight after each exchange +- **Cross-session continuity** — the pipeline remembers user preferences, past conversations, and context between sessions +- **Non-blocking retention** — memory writes are fire-and-forget, so they never delay the voice response +- **Drop-in integration** — one processor added to an existing pipeline, no other changes required + +## Architecture + +``` +┌────────────────────────────────────────────────────────┐ +│ Pipecat Pipeline │ +│ │ +│ transport.input() │ +│ │ │ +│ ▼ │ +│ STT service (speech → TranscriptionFrame) │ +│ │ │ +│ ▼ │ +│ LLMUserContextAggregator (builds LLMContext) │ +│ │ │ +│ ▼ │ +│ HindsightMemoryService ← recall → inject │ +│ │ └─ retain previous turn (async) │ +│ ▼ │ +│ LLM service (context → TextFrame) │ +│ │ │ +│ ▼ │ +│ LLMAssistantContextAggregator │ +│ │ │ +│ ▼ │ +│ TTS service (text → audio) │ +│ │ │ +│ ▼ │ +│ transport.output() │ +└────────────────────────────────────────────────────────┘ +``` + +## Prerequisites + +1. **Python 3.10+** + +2. **Pipecat** — install via pip with your desired extras (STT, TTS, LLM services) + +3. **Hindsight** — cloud or local + - [Hindsight Cloud](https://hindsight.vectorize.io) (sign up for an API key) + - Or run locally: `pip install hindsight-all && hindsight-api` + +## Quick Start + +### 1. Install dependencies + +```bash +pip install -r requirements.txt +``` + +### 2. Configure Hindsight + +For local Hindsight: +```bash +pip install hindsight-all +export HINDSIGHT_API_LLM_API_KEY=your-openai-key +hindsight-api # starts on http://localhost:8888 +``` + +For Hindsight Cloud: +```bash +export HINDSIGHT_URL=https://api.hindsight.vectorize.io +export HINDSIGHT_API_KEY=hsk_your_token_here +``` + +### 3. (Optional) Seed your memory bank + +To see recall working immediately without waiting for conversations to build up: + +```bash +python seed_memory.py +``` + +### 4. Add to your Pipecat pipeline + +```python +from pipecat.pipeline.pipeline import Pipeline +from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.processors.aggregators.llm_response import LLMUserContextAggregator, LLMAssistantContextAggregator +from hindsight_pipecat import HindsightMemoryService + +context = OpenAILLMContext( + messages=[{"role": "system", "content": "You are a helpful voice assistant."}] +) +user_aggregator = LLMUserContextAggregator(context) +assistant_aggregator = LLMAssistantContextAggregator(context) + +memory = HindsightMemoryService( + bank_id="pipecat", + hindsight_api_url="http://localhost:8888", # or your Cloud URL + # api_key="hsk_...", # for Hindsight Cloud +) + +pipeline = Pipeline([ + transport.input(), + stt_service, + user_aggregator, + memory, # ← inject here + llm_service, + assistant_aggregator, + tts_service, + transport.output(), +]) +``` + +## How It Works + +### On each `OpenAILLMContextFrame` + +When a new user turn arrives as an `OpenAILLMContextFrame`: + +1. **Retain** — if the context contains a complete previous turn (user message + assistant response) that hasn't been retained yet, it's sent to Hindsight asynchronously. This is fire-and-forget — it never delays the voice response. + +2. **Recall** — the latest user message is used as the search query. Hindsight retrieves the most relevant memories from past conversations. + +3. **Inject** — recalled memories are added as a `` system message at the top of the LLM context. If a memory message from a previous turn already exists, it's replaced rather than accumulated. + +4. **Forward** — the enriched context frame is pushed downstream to the LLM service. + +### Memory format in context + +``` + +Relevant memories from past conversations: +1. User's name is Alex and they prefer concise responses +2. User has a morning routine starting at 7am with news briefing +3. User prefers metric units (Celsius, kilometers) over imperial + +``` + +The LLM sees this context before generating each response. Over multiple sessions, the pipeline accumulates a growing picture of the user's preferences and history. + +## Configuration + +```python +HindsightMemoryService( + bank_id="pipecat", # Required: memory bank to use + hindsight_api_url="...", # Hindsight API URL + api_key="hsk_...", # API key (Hindsight Cloud) + recall_budget="mid", # "low", "mid", or "high" + recall_max_tokens=4096, # Max tokens for recall results + enable_recall=True, # Inject memories before LLM + enable_retain=True, # Store turns after each exchange +) +``` + +## Core Files + +| File | Description | +|------|-------------| +| `seed_memory.py` | Seeds sample user facts for demo purposes | +| `requirements.txt` | Python dependencies | +| `install.py` | Integration installer | +| `hindsight_pipecat/memory.py` | `HindsightMemoryService` frame processor | + +## Common Issues + +**No memories recalled on first conversation** + +Recall returns results only after something has been retained. Either: +- Run `seed_memory.py` to pre-populate facts, or +- Complete one full turn (user speaks, assistant responds) and then start a new session + +**Retention seems delayed** + +Retain is asynchronous (fire-and-forget) — it runs after the pipeline has already forwarded the frame. Facts retained in one turn are available for recall starting from the next turn. + +**Pipeline not recalling across sessions** + +Check that you're using the same `bank_id` across all pipeline instances. Each unique `bank_id` is an isolated memory store. + +## Built With + +- [Pipecat](https://github.com/pipecat-ai/pipecat) — real-time voice AI pipeline framework +- [Hindsight](https://hindsight.vectorize.io) — long-term memory for AI agents +- [hindsight-pipecat](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/pipecat) — Pipecat frame processor diff --git a/applications/pipecat-memory/requirements.txt b/applications/pipecat-memory/requirements.txt new file mode 100644 index 0000000..55d93d5 --- /dev/null +++ b/applications/pipecat-memory/requirements.txt @@ -0,0 +1,2 @@ +hindsight-pipecat>=0.1.0 +pipecat-ai>=0.0.100 diff --git a/applications/pipecat-memory/seed_memory.py b/applications/pipecat-memory/seed_memory.py new file mode 100644 index 0000000..58a6679 --- /dev/null +++ b/applications/pipecat-memory/seed_memory.py @@ -0,0 +1,75 @@ +"""Seed sample user facts into Hindsight for the Pipecat memory demo. + +Run this once before starting your Pipecat pipeline to pre-populate your +memory bank. Then start a conversation and ask something like "what's my +preferred response style?" to see Hindsight recall the right context. + +Usage: + python seed_memory.py # seed default facts + python seed_memory.py --reset # clear the bank first, then seed + +Prerequisites: + - pip install -r requirements.txt + - Hindsight running locally, or set HINDSIGHT_URL to your cloud endpoint + - Set HINDSIGHT_API_KEY if using Hindsight Cloud +""" + +import asyncio +import os +import sys + +from hindsight_client import Hindsight + +BANK_ID = os.environ.get("BANK_ID", "pipecat") +HINDSIGHT_URL = os.environ.get("HINDSIGHT_URL", "http://localhost:8888") +HINDSIGHT_API_KEY = os.environ.get("HINDSIGHT_API_KEY") + +SAMPLE_FACTS = [ + "User's name is Alex and they prefer concise responses", + "User is a software engineer working on a home automation system", + "User prefers metric units (Celsius, kilometers) over imperial", + "User's home assistant should address them by first name", + "User has a morning routine starting at 7am with news briefing", + "User's preferred wake-up alarm style is gradual, not abrupt", + "User has asked the assistant to remember grocery items when mentioned", + "User prefers voice responses to be under 30 seconds when possible", +] + + +async def reset_bank(client: Hindsight) -> None: + try: + await client.adelete_bank(bank_id=BANK_ID) + print(f"Cleared memory bank '{BANK_ID}'") + except Exception: + pass # Bank may not exist yet + + +async def main() -> None: + client_kwargs: dict = {"base_url": HINDSIGHT_URL, "timeout": 30.0} + if HINDSIGHT_API_KEY: + client_kwargs["api_key"] = HINDSIGHT_API_KEY + + client = Hindsight(**client_kwargs) + + if "--reset" in sys.argv: + await reset_bank(client) + + content = "\n".join(f"- {fact}" for fact in SAMPLE_FACTS) + await client.aretain( + bank_id=BANK_ID, + content=content, + document_id="seed-demo", + ) + + print(f"Seeded {len(SAMPLE_FACTS)} user facts into bank '{BANK_ID}'") + print() + print("Now start your Pipecat pipeline and try asking:") + print(" - 'what's my name?'") + print(" - 'what time do I wake up?'") + print(" - 'what units do I prefer?'") + print() + print("HindsightMemoryService will recall the relevant context before each LLM call.") + + +if __name__ == "__main__": + asyncio.run(main())