|
| 1 | +--- |
| 2 | +sidebar_position: 12 |
| 3 | +title: "AutoGen Persistent Memory with Hindsight | Integration" |
| 4 | +description: "Add long-term memory to AutoGen agents with Hindsight. Provides FunctionTool instances for retain, recall, and reflect that plug directly into AutoGen's AssistantAgent." |
| 5 | +--- |
| 6 | + |
| 7 | +# AutoGen |
| 8 | + |
| 9 | +Persistent long-term memory for [AutoGen](https://microsoft.github.io/autogen/) agents via Hindsight. Provides `FunctionTool` instances that plug directly into AutoGen's `AssistantAgent`. |
| 10 | + |
| 11 | +## Features |
| 12 | + |
| 13 | +- **Memory Tools** — retain, recall, and reflect as AutoGen `FunctionTool` instances compatible with `AssistantAgent(tools=[...])` |
| 14 | +- **Async-Native** — Uses `aretain`, `arecall`, `areflect` directly — works seamlessly in AutoGen's async runtime |
| 15 | +- **Selective Tools** — Include only the tools you need with `include_retain/recall/reflect` flags |
| 16 | +- **Tag-Based Scoping** — Partition memories by topic, session, or user with tags |
| 17 | +- **Global Configuration** — Configure once with `configure()`, create tools anywhere |
| 18 | + |
| 19 | +## Installation |
| 20 | + |
| 21 | +```bash |
| 22 | +pip install hindsight-autogen autogen-agentchat "autogen-ext[openai]" |
| 23 | +``` |
| 24 | + |
| 25 | +`hindsight-autogen` pulls in `autogen-core` and `hindsight-client`. You also need `autogen-agentchat` for `AssistantAgent` and `autogen-ext[openai]` for the OpenAI model client. |
| 26 | + |
| 27 | +## Quick Start |
| 28 | + |
| 29 | +```python |
| 30 | +import asyncio |
| 31 | +from autogen_agentchat.agents import AssistantAgent |
| 32 | +from autogen_ext.models.openai import OpenAIChatCompletionClient |
| 33 | +from hindsight_client import Hindsight |
| 34 | +from hindsight_autogen import create_hindsight_tools |
| 35 | + |
| 36 | +async def main(): |
| 37 | + client = Hindsight(base_url="http://localhost:8888") |
| 38 | + await client.acreate_bank(bank_id="user-123") |
| 39 | + |
| 40 | + model_client = OpenAIChatCompletionClient(model="gpt-4o") |
| 41 | + tools = create_hindsight_tools(client=client, bank_id="user-123") |
| 42 | + |
| 43 | + agent = AssistantAgent( |
| 44 | + name="assistant", |
| 45 | + model_client=model_client, |
| 46 | + tools=tools, |
| 47 | + ) |
| 48 | + |
| 49 | + # Store a memory |
| 50 | + result = await agent.run(task="Remember that I prefer dark mode") |
| 51 | + print(result.messages[-1].content) |
| 52 | + |
| 53 | + # Hindsight processes retained content asynchronously (fact extraction, |
| 54 | + # entity resolution, embeddings). A brief pause ensures memories are |
| 55 | + # searchable before the next recall. In production, this delay is only |
| 56 | + # needed when retain and recall happen back-to-back in the same script. |
| 57 | + await asyncio.sleep(3) |
| 58 | + |
| 59 | + # Recall it later |
| 60 | + result = await agent.run(task="What are my UI preferences?") |
| 61 | + print(result.messages[-1].content) |
| 62 | + |
| 63 | + # Clean up |
| 64 | + await client.aclose() |
| 65 | + await model_client.close() |
| 66 | + |
| 67 | +asyncio.run(main()) |
| 68 | +``` |
| 69 | + |
| 70 | +:::tip Jupyter Notebooks |
| 71 | +If you're running in a Jupyter notebook, you don't need `asyncio.run()` — just use `await` directly in cells since the notebook already has an active event loop. |
| 72 | +::: |
| 73 | + |
| 74 | +The agent gets three tools it can call: |
| 75 | + |
| 76 | +- **`hindsight_retain`** — Store information to long-term memory |
| 77 | +- **`hindsight_recall`** — Search long-term memory for relevant facts |
| 78 | +- **`hindsight_reflect`** — Synthesize a reasoned answer from memories |
| 79 | + |
| 80 | +## Selecting Tools |
| 81 | + |
| 82 | +Include only the tools you need: |
| 83 | + |
| 84 | +```python |
| 85 | +tools = create_hindsight_tools( |
| 86 | + client=client, |
| 87 | + bank_id="user-123", |
| 88 | + include_retain=True, |
| 89 | + include_recall=True, |
| 90 | + include_reflect=False, # Omit reflect |
| 91 | +) |
| 92 | +``` |
| 93 | + |
| 94 | +## Global Configuration |
| 95 | + |
| 96 | +Instead of passing a client to every call, configure once: |
| 97 | + |
| 98 | +```python |
| 99 | +from hindsight_autogen import configure, create_hindsight_tools |
| 100 | + |
| 101 | +configure( |
| 102 | + hindsight_api_url="http://localhost:8888", |
| 103 | + api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var |
| 104 | + budget="mid", # Recall budget: low/mid/high |
| 105 | + max_tokens=4096, # Max tokens for recall results |
| 106 | + tags=["env:prod"], # Tags for stored memories |
| 107 | + recall_tags=["scope:global"], # Tags to filter recall |
| 108 | + recall_tags_match="any", # Tag match mode |
| 109 | +) |
| 110 | + |
| 111 | +# Now create tools without passing client — uses global config |
| 112 | +tools = create_hindsight_tools(bank_id="user-123") |
| 113 | +``` |
| 114 | + |
| 115 | +## Memory Scoping with Tags |
| 116 | + |
| 117 | +Use tags to partition memories by topic, session, or user: |
| 118 | + |
| 119 | +```python |
| 120 | +# Store memories tagged by source |
| 121 | +tools = create_hindsight_tools( |
| 122 | + client=client, |
| 123 | + bank_id="user-123", |
| 124 | + tags=["source:chat", "session:abc"], |
| 125 | + recall_tags=["source:chat"], |
| 126 | + recall_tags_match="any", |
| 127 | +) |
| 128 | +``` |
| 129 | + |
| 130 | +## Production Patterns |
| 131 | + |
| 132 | +### Error Handling |
| 133 | + |
| 134 | +Tools raise `HindsightError` on failure, which AutoGen surfaces to the agent as a tool error. Wrap agent calls for graceful degradation: |
| 135 | + |
| 136 | +```python |
| 137 | +from hindsight_autogen.errors import HindsightError |
| 138 | + |
| 139 | +try: |
| 140 | + result = await agent.run(task="What do you remember about me?") |
| 141 | +except HindsightError as e: |
| 142 | + print(f"Memory operation failed: {e}") |
| 143 | +``` |
| 144 | + |
| 145 | +### Bank Lifecycle |
| 146 | + |
| 147 | +Create banks before first use and clean up when done: |
| 148 | + |
| 149 | +```python |
| 150 | +async def main(): |
| 151 | + client = Hindsight(base_url="http://localhost:8888") |
| 152 | + |
| 153 | + # Create bank (idempotent) |
| 154 | + await client.acreate_bank(bank_id="user-123") |
| 155 | + |
| 156 | + tools = create_hindsight_tools(client=client, bank_id="user-123") |
| 157 | + # ... use tools ... |
| 158 | + |
| 159 | + # Optional: delete bank when no longer needed |
| 160 | + await client.adelete_bank(bank_id="user-123") |
| 161 | +``` |
| 162 | + |
| 163 | +### Multi-Agent Teams |
| 164 | + |
| 165 | +Give each agent its own memory bank, or share a bank across a team: |
| 166 | + |
| 167 | +```python |
| 168 | +# Per-agent memory |
| 169 | +researcher_tools = create_hindsight_tools(client=client, bank_id="researcher-memory") |
| 170 | +writer_tools = create_hindsight_tools(client=client, bank_id="writer-memory") |
| 171 | + |
| 172 | +# Shared team memory |
| 173 | +shared_tools = create_hindsight_tools( |
| 174 | + client=client, |
| 175 | + bank_id="team-shared", |
| 176 | + tags=["team:content"], |
| 177 | +) |
| 178 | +``` |
| 179 | + |
| 180 | +## API Reference |
| 181 | + |
| 182 | +### `create_hindsight_tools()` |
| 183 | + |
| 184 | +| Parameter | Default | Description | |
| 185 | +|---|---|---| |
| 186 | +| `bank_id` | *required* | Hindsight memory bank ID | |
| 187 | +| `client` | `None` | Pre-configured Hindsight client | |
| 188 | +| `hindsight_api_url` | `None` | API URL (used if no client provided) | |
| 189 | +| `api_key` | `None` | API key (used if no client provided) | |
| 190 | +| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) | |
| 191 | +| `max_tokens` | `4096` | Maximum tokens for recall results | |
| 192 | +| `tags` | `None` | Tags applied when storing memories | |
| 193 | +| `recall_tags` | `None` | Tags to filter when searching | |
| 194 | +| `recall_tags_match` | `"any"` | Tag matching mode (any/all/any\_strict/all\_strict) | |
| 195 | +| `retain_metadata` | `None` | Default metadata dict for retain operations | |
| 196 | +| `retain_document_id` | `None` | Default document\_id for retain (groups/upserts memories) | |
| 197 | +| `recall_types` | `None` | Fact types to filter (world, experience, opinion, observation) | |
| 198 | +| `recall_include_entities` | `False` | Include entity information in recall results | |
| 199 | +| `reflect_context` | `None` | Additional context for reflect operations | |
| 200 | +| `reflect_max_tokens` | `None` | Max tokens for reflect results (defaults to `max_tokens`) | |
| 201 | +| `reflect_response_schema` | `None` | JSON schema to constrain reflect output format | |
| 202 | +| `reflect_tags` | `None` | Tags to filter memories used in reflect (defaults to `recall_tags`) | |
| 203 | +| `reflect_tags_match` | `None` | Tag matching for reflect (defaults to `recall_tags_match`) | |
| 204 | +| `include_retain` | `True` | Include the retain (store) tool | |
| 205 | +| `include_recall` | `True` | Include the recall (search) tool | |
| 206 | +| `include_reflect` | `True` | Include the reflect (synthesize) tool | |
| 207 | + |
| 208 | +### `configure()` |
| 209 | + |
| 210 | +| Parameter | Default | Description | |
| 211 | +|---|---|---| |
| 212 | +| `hindsight_api_url` | Production API | Hindsight API URL | |
| 213 | +| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication | |
| 214 | +| `budget` | `"mid"` | Default recall budget level | |
| 215 | +| `max_tokens` | `4096` | Default max tokens for recall | |
| 216 | +| `tags` | `None` | Default tags for retain operations | |
| 217 | +| `recall_tags` | `None` | Default tags to filter recall | |
| 218 | +| `recall_tags_match` | `"any"` | Default tag matching mode | |
| 219 | + |
| 220 | +## Requirements |
| 221 | + |
| 222 | +- Python >= 3.10 |
| 223 | +- autogen-core >= 0.4.0 |
| 224 | +- hindsight-client >= 0.4.0 |
0 commit comments