mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-11 03:37:56 +00:00
Rewrites 339 TypeScript calls across 50 pages from the rc.5 `method({ namespace, body })` form to the shipped `method(namespace, { ... })` form, and aligns field names with the live v5 spec: `attach` to `include`, `authUrl` to `authorization`, `lastSync` to `latestRun`, `deletedCount` to `count`, and the paginated `namespaces.list()`.
Renames container tags to namespaces across concepts, connectors, integrations and snippets. The namespace pages keep container tag in the description, search keywords and a rename note so old searches still land, and the v3 reference page points at v5.
The migration guide's SDK table now covers both 5.0.0 SDKs, and the SDK integration page uses the real client options (`baseUrl`, `timeoutInSeconds`, `maxRetries`) and error classes.
380 lines
9.8 KiB
Text
380 lines
9.8 KiB
Text
---
|
|
title: "Agno"
|
|
sidebarTitle: "Agno"
|
|
description: "Add persistent memory to Agno agents with Supermemory"
|
|
icon: "/icons/hugeicons/brain-01.svg"
|
|
---
|
|
|
|
Agno agents are stateless by default. Each conversation starts fresh. Supermemory changes that - your agents can remember users, recall past conversations, and build on previous interactions.
|
|
|
|
## What you can do
|
|
|
|
- Give agents access to user profiles and conversation history
|
|
- Store agent interactions for future sessions
|
|
- Let agents search memories to answer questions with context
|
|
|
|
## Setup
|
|
|
|
Install the packages:
|
|
|
|
```bash
|
|
pip install agno supermemory python-dotenv
|
|
```
|
|
|
|
Set up your environment:
|
|
|
|
```bash
|
|
# .env
|
|
SUPERMEMORY_API_KEY=your-supermemory-api-key
|
|
OPENAI_API_KEY=your-openai-api-key
|
|
```
|
|
|
|
<Note>Get your Supermemory API key from [console.supermemory.ai](https://console.supermemory.ai).</Note>
|
|
|
|
## Basic integration
|
|
|
|
Fetch user context before running an agent, then store the interaction after.
|
|
|
|
```python
|
|
from agno.agent import Agent
|
|
from agno.models.openai import OpenAIChat
|
|
from supermemory import Supermemory
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
memory = Supermemory()
|
|
|
|
def get_user_context(user_id: str, query: str) -> str:
|
|
"""Pull user profile and relevant memories."""
|
|
profile = memory.profile(user_id).profile
|
|
memories = memory.search(user_id, query=query, limit=5).results
|
|
|
|
static = [m.memory for m in profile.static]
|
|
dynamic = [m.memory for m in profile.dynamic]
|
|
|
|
return f"""
|
|
User background:
|
|
{chr(10).join(static) if static else 'No profile yet.'}
|
|
|
|
Recent activity:
|
|
{chr(10).join(dynamic) if dynamic else 'Nothing recent.'}
|
|
|
|
Related memories:
|
|
{chr(10).join([m.memory or m.chunk for m in memories[:5]]) if memories else 'None.'}
|
|
"""
|
|
|
|
def create_agent(user_id: str, task: str) -> Agent:
|
|
"""Create an agent with user context."""
|
|
context = get_user_context(user_id, task)
|
|
|
|
return Agent(
|
|
name="assistant",
|
|
model=OpenAIChat(id="gpt-4o"),
|
|
description=f"""You are a helpful assistant.
|
|
|
|
Here's what you know about this user:
|
|
{context}
|
|
|
|
Use this to personalize your responses.""",
|
|
markdown=True
|
|
)
|
|
|
|
def chat(user_id: str, message: str) -> str:
|
|
"""Run the agent and store the interaction."""
|
|
agent = create_agent(user_id, message)
|
|
response = agent.run(message)
|
|
|
|
# Save for next time
|
|
memory.add(
|
|
user_id,
|
|
content=f"User: {message}\nAssistant: {response.content}",
|
|
dreaming="instant"
|
|
)
|
|
|
|
return response.content
|
|
```
|
|
|
|
---
|
|
|
|
## Core concepts
|
|
|
|
### User profiles
|
|
|
|
Supermemory keeps two buckets of user info:
|
|
|
|
- **Static facts**: Things that stay consistent (name, preferences, expertise)
|
|
- **Dynamic context**: What they're focused on lately
|
|
|
|
```python
|
|
result = memory.profile("user_123")
|
|
|
|
print([m.memory for m in result.profile.static]) # ["Vegetarian", "Allergic to nuts"]
|
|
print([m.memory for m in result.profile.dynamic]) # ["Learning Italian cuisine", "Meal prepping"]
|
|
```
|
|
|
|
### Storing memories
|
|
|
|
Save interactions so future sessions have context:
|
|
|
|
```python
|
|
def store_chat(user_id: str, user_msg: str, agent_response: str):
|
|
memory.add(
|
|
user_id,
|
|
content=f"User asked: {user_msg}\nAgent said: {agent_response}",
|
|
metadata={"type": "conversation"},
|
|
dreaming="instant"
|
|
)
|
|
```
|
|
|
|
### Searching memories
|
|
|
|
Look up past interactions:
|
|
|
|
```python
|
|
results = memory.search(
|
|
"user_123",
|
|
query="pasta recipes we discussed",
|
|
search_mode="hybrid", # Searches memories + document chunks
|
|
limit=5
|
|
)
|
|
|
|
for r in results.results:
|
|
print(r.memory or r.chunk)
|
|
```
|
|
|
|
---
|
|
|
|
## Example: personal assistant with memory
|
|
|
|
An assistant that actually knows who it's talking to. Preferences stick around. Past conversations inform new ones.
|
|
|
|
```python
|
|
from agno.agent import Agent
|
|
from agno.models.openai import OpenAIChat
|
|
from supermemory import Supermemory
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
class PersonalAssistant:
|
|
def __init__(self):
|
|
self.memory = Supermemory()
|
|
|
|
def get_context(self, user_id: str, query: str) -> dict:
|
|
"""Fetch user profile and relevant history."""
|
|
profile = self.memory.profile(user_id).profile
|
|
memories = self.memory.search(user_id, query=query, threshold=0.5).results
|
|
|
|
return {
|
|
"profile": [m.memory for m in profile.static],
|
|
"recent": [m.memory for m in profile.dynamic],
|
|
"history": [m.memory or m.chunk for m in memories[:3]]
|
|
}
|
|
|
|
def build_description(self, context: dict) -> str:
|
|
"""Turn context into agent description."""
|
|
parts = ["You are a helpful personal assistant."]
|
|
|
|
if context["profile"]:
|
|
parts.append(f"About this user: {', '.join(context['profile'])}")
|
|
|
|
if context["recent"]:
|
|
parts.append(f"They're currently: {', '.join(context['recent'])}")
|
|
|
|
if context["history"]:
|
|
parts.append(f"Past conversations: {'; '.join(context['history'])}")
|
|
|
|
parts.append("Reference what you know about them when relevant.")
|
|
|
|
return "\n\n".join(parts)
|
|
|
|
def create_agent(self, context: dict) -> Agent:
|
|
return Agent(
|
|
name="assistant",
|
|
model=OpenAIChat(id="gpt-4o"),
|
|
description=self.build_description(context),
|
|
markdown=True
|
|
)
|
|
|
|
def chat(self, user_id: str, message: str) -> str:
|
|
"""Handle a message and remember the interaction."""
|
|
context = self.get_context(user_id, message)
|
|
agent = self.create_agent(context)
|
|
|
|
response = agent.run(message)
|
|
|
|
# Store for future sessions
|
|
self.memory.add(
|
|
user_id,
|
|
content=f"User: {message}\nAssistant: {response.content}",
|
|
metadata={"type": "chat"},
|
|
dreaming="instant"
|
|
)
|
|
|
|
return response.content
|
|
|
|
def teach(self, user_id: str, fact: str):
|
|
"""Store a preference or fact about the user."""
|
|
self.memory.add(
|
|
user_id,
|
|
content=fact,
|
|
metadata={"type": "preference"},
|
|
dreaming="instant"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
assistant = PersonalAssistant()
|
|
|
|
# Teach it some preferences
|
|
assistant.teach("user_1", "Prefers concise answers")
|
|
assistant.teach("user_1", "Works in software engineering")
|
|
|
|
# Chat
|
|
response = assistant.chat("user_1", "What's a good way to learn Rust?")
|
|
print(response)
|
|
```
|
|
|
|
---
|
|
|
|
## Using Agno tools with memory
|
|
|
|
Give your agent tools that can search and store memories directly.
|
|
|
|
```python
|
|
from agno.agent import Agent
|
|
from agno.models.openai import OpenAIChat
|
|
from agno.tools import tool
|
|
from supermemory import Supermemory
|
|
|
|
memory = Supermemory()
|
|
|
|
@tool
|
|
def search_memory(query: str, user_id: str) -> str:
|
|
"""Search for information in the user's memory.
|
|
|
|
Args:
|
|
query: What to look for
|
|
user_id: The user's ID
|
|
"""
|
|
results = memory.search(user_id, query=query, limit=5)
|
|
|
|
if not results.results:
|
|
return "Nothing relevant found in memory."
|
|
|
|
return "\n".join([r.memory or r.chunk for r in results.results])
|
|
|
|
@tool
|
|
def remember(content: str, user_id: str) -> str:
|
|
"""Store something important about the user.
|
|
|
|
Args:
|
|
content: What to remember
|
|
user_id: The user's ID
|
|
"""
|
|
memory.add(user_id, content=content, dreaming="instant")
|
|
return f"Remembered: {content}"
|
|
|
|
agent = Agent(
|
|
name="memory_agent",
|
|
model=OpenAIChat(id="gpt-4o"),
|
|
tools=[search_memory, remember],
|
|
description="""You are an assistant with memory.
|
|
|
|
When users share preferences or important info, use the remember tool.
|
|
When they ask about past conversations, search your memory first.""",
|
|
markdown=True
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Image context with memory
|
|
|
|
Agno handles images too. When users share photos, you can store what the agent saw for later.
|
|
|
|
```python
|
|
from agno.agent import Agent
|
|
from agno.models.openai import OpenAIChat
|
|
from agno.media import Image
|
|
from pathlib import Path
|
|
from supermemory import Supermemory
|
|
|
|
memory = Supermemory()
|
|
|
|
def analyze_and_remember(user_id: str, image_path: str, question: str) -> str:
|
|
"""Analyze an image, answer a question, and store the context."""
|
|
|
|
agent = Agent(
|
|
name="vision_agent",
|
|
model=OpenAIChat(id="gpt-4o"),
|
|
description="You analyze images and answer questions about them.",
|
|
markdown=True
|
|
)
|
|
|
|
# Get the agent's analysis
|
|
response = agent.run(question, images=[Image(filepath=Path(image_path))])
|
|
|
|
# Store the interaction with image context
|
|
memory.add(
|
|
user_id,
|
|
content=f"User shared an image and asked: {question}\nAnalysis: {response.content}",
|
|
metadata={"type": "image_analysis", "image": image_path},
|
|
dreaming="instant"
|
|
)
|
|
|
|
return response.content
|
|
```
|
|
|
|
---
|
|
|
|
## Metadata for filtering
|
|
|
|
Tags let you narrow down searches:
|
|
|
|
```python
|
|
# Store with metadata
|
|
memory.add(
|
|
"user_123",
|
|
content="User prefers dark mode interfaces",
|
|
dreaming="instant",
|
|
metadata={
|
|
"type": "preference",
|
|
"category": "ui",
|
|
"source": "onboarding"
|
|
}
|
|
)
|
|
|
|
# Search with filters
|
|
results = memory.search(
|
|
"user_123",
|
|
query="interface preferences",
|
|
filter={
|
|
"operator": "and",
|
|
"operands": [
|
|
{"field": "type", "operator": "eq", "value": "preference"},
|
|
{"field": "category", "operator": "eq", "value": "ui"}
|
|
]
|
|
}
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Related docs
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="User profiles" icon="/icons/hugeicons/user.svg" href="/recall/user-profiles">
|
|
How automatic profiling works
|
|
</Card>
|
|
<Card title="Search" icon="/icons/hugeicons/search-01.svg" href="/recall/search">
|
|
Filtering and search modes
|
|
</Card>
|
|
<Card title="LangChain" icon="/icons/hugeicons/link-01.svg" href="/integrations/langchain">
|
|
Memory for LangChain apps
|
|
</Card>
|
|
<Card title="CrewAI" icon="/icons/hugeicons/user-multiple.svg" href="/integrations/crewai">
|
|
Multi-agent systems with memory
|
|
</Card>
|
|
</CardGroup>
|