mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
fix(docs): align Supermemory skill with current SDKs
This commit is contained in:
parent
ded65fbbdd
commit
9263c1560e
2 changed files with 159 additions and 111 deletions
|
|
@ -38,7 +38,7 @@ Provides semantic search with:
|
|||
|
||||
## Quick Integration Examples
|
||||
|
||||
### TypeScript (Vercel AI SDK)
|
||||
### TypeScript
|
||||
```typescript
|
||||
import { Supermemory } from 'supermemory';
|
||||
|
||||
|
|
@ -49,14 +49,19 @@ const client = new Supermemory({
|
|||
// 1. Retrieve personalized context
|
||||
const context = await client.profile({
|
||||
containerTag: "user_123",
|
||||
query: "What are my preferences?"
|
||||
q: "What are my preferences?"
|
||||
});
|
||||
|
||||
// 2. Enrich your prompt with context
|
||||
const systemMessage = `User Profile: ${context.profile}
|
||||
Relevant Memories: ${context.memories.join('\n')}`;
|
||||
const profileText = [
|
||||
...context.profile.static,
|
||||
...context.profile.dynamic,
|
||||
].join('\n');
|
||||
const relevantMemories = JSON.stringify(context.searchResults?.results ?? []);
|
||||
const systemMessage = `User Profile:\n${profileText}\n\nRelevant Memories:\n${relevantMemories}`;
|
||||
|
||||
// 3. Store new memories after conversation
|
||||
const conversationText = "User: I prefer dark mode.\nAssistant: I'll remember that.";
|
||||
await client.add({
|
||||
content: conversationText,
|
||||
containerTag: "user_123",
|
||||
|
|
@ -66,6 +71,8 @@ await client.add({
|
|||
|
||||
### Python
|
||||
```python
|
||||
import os
|
||||
|
||||
from supermemory import Supermemory
|
||||
|
||||
client = Supermemory(api_key=os.environ["SUPERMEMORY_API_KEY"])
|
||||
|
|
@ -73,10 +80,20 @@ client = Supermemory(api_key=os.environ["SUPERMEMORY_API_KEY"])
|
|||
# Retrieve context
|
||||
context = client.profile(
|
||||
container_tag="user_123",
|
||||
query="What are my preferences?"
|
||||
q="What are my preferences?"
|
||||
)
|
||||
|
||||
profile_text = "\n".join(
|
||||
(context.profile.static or []) + (context.profile.dynamic or [])
|
||||
)
|
||||
relevant_memories = "\n".join(
|
||||
result.memory
|
||||
for result in (context.search_results.results if context.search_results else [])
|
||||
if result.memory
|
||||
)
|
||||
|
||||
# Add memories
|
||||
conversation_text = "User: I prefer dark mode.\nAssistant: I'll remember that."
|
||||
client.add(
|
||||
content=conversation_text,
|
||||
container_tag="user_123",
|
||||
|
|
@ -101,14 +118,14 @@ Supermemory builds a **living knowledge graph** rather than static document stor
|
|||
3. **Graph Construction**: Builds relationships between memories (updates, extends, derives)
|
||||
4. **Semantic Retrieval**: Returns contextually relevant information, not just keyword matches
|
||||
|
||||
Processing times: PDFs take 1-2 minutes, videos 5-10 minutes for 100 pages.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. **Get API Key**: Sign up at [console.supermemory.ai](https://console.supermemory.ai)
|
||||
2. **Install SDK**: Supermemory works with the following SDKs natively:
|
||||
- **TypeScript/JavaScript**: `npm install supermemory` ([npm](https://www.npmjs.com/package/supermemory))
|
||||
- **Python**: `pip install supermemory` ([PyPI](https://pypi.org/project/supermemory/))
|
||||
- **TypeScript agent tools/middleware**: `npm install @supermemory/tools`
|
||||
- **Python OpenAI tools/middleware**: `pip install supermemory-openai-sdk`
|
||||
|
||||
Discover all available SDKs and community integrations at [supermemory.ai/docs](https://supermemory.ai/docs)
|
||||
3. **Set Environment Variable**: `export SUPERMEMORY_API_KEY="your_key"`
|
||||
|
|
@ -123,19 +140,19 @@ Supermemory supports two complementary integration styles:
|
|||
|
||||
| Path | When to use | Packages |
|
||||
|------|-------------|----------|
|
||||
| **Tools** | Model explicitly decides when to search, add, list, or forget | `@supermemory/tools` (TypeScript), `supermemory-openai-sdk` (Python) |
|
||||
| **Middleware** | Auto-inject profile context before each request and save conversations after | `@supermemory/tools` `withSupermemory`, `supermemory-openai-sdk` `with_supermemory` |
|
||||
| **Tools** | Model explicitly decides when to search, add, list, or forget | `@supermemory/tools/ai-sdk` or `@supermemory/ai-sdk` (TypeScript), `supermemory-openai-sdk` (Python) |
|
||||
| **Middleware** | Auto-inject profile context before each request and save conversations after | `@supermemory/tools/ai-sdk` (Vercel AI SDK), `@supermemory/tools/openai` (OpenAI), `supermemory-openai-sdk` (Python) |
|
||||
|
||||
**Tools (7 canonical operations):**
|
||||
|
||||
| Tool | Use when |
|
||||
|------|----------|
|
||||
| `searchMemories` / `search_memories` | Proactive hybrid recall before answering when user-specific context could help — not only when explicitly asked. Best for targeted lookups; returns memory IDs for `memoryForget`. |
|
||||
| `searchMemories` / `search_memories` | Proactive hybrid recall before answering when user-specific context could help — not only when explicitly asked. Hybrid returns both memory entries and source-document chunks. |
|
||||
| `addMemory` / `add_memory` | Store a single generalizable fact the user stated |
|
||||
| `getProfile` / `get_profile` | Load static + dynamic profile; pass `query` to scope search results to the current topic |
|
||||
| `documentList` / `document_list` | Browse stored **source documents** (conversations, URLs, files); returns **document IDs** |
|
||||
| `documentAdd` / `document_add` | Ingest raw content (text blob, conversation transcript, URL, notes) for **background processing** — memories are extracted automatically; use for substantial content, not single facts (`addMemory`) |
|
||||
| `documentDelete` / `document_delete` | **Hard delete** a document + all memories extracted from it (permanent) |
|
||||
| `documentDelete` / `document_delete` | Permanently delete a source document and soft-forget memories extracted from it |
|
||||
| `memoryForget` / `memory_forget` | **Soft delete** one learned profile fact by memory ID or exact content match |
|
||||
|
||||
### Removing information — three different mechanisms
|
||||
|
|
@ -144,18 +161,20 @@ Agents must pick the right removal path:
|
|||
|
||||
| User intent | Tool | What it removes | ID source |
|
||||
|-------------|------|-----------------|-----------|
|
||||
| "Forget that I like tea" / correct a wrong fact | `memoryForget` | One extracted profile memory (soft delete) | `memoryId` from `searchMemories` or `getProfile` |
|
||||
| "Delete that conversation" / remove a whole file or URL | `documentDelete` | Entire source document + all extracted memories (permanent) | `documentId` from `documentList` |
|
||||
| "Forget that I like tea" / correct a wrong fact | `memoryForget` | One extracted profile memory (soft delete) | Memory ID from a search result that contains `memory`, or query-backed `getProfile.searchResults` / `get_profile.search_results` |
|
||||
| "Delete that conversation" / remove a whole file or URL | `documentDelete` | Source document permanently; extracted memories are soft-forgotten | `documentId` from `documentList` |
|
||||
| User is vague ("forget what you know about my job") | `searchMemories` first → then `memoryForget` | Same as memoryForget | Search first, then use `memoryId` |
|
||||
|
||||
**Do not confuse IDs:** `memoryId` ≠ `documentId`. Profile memory IDs come from search/profile; document IDs come from document list.
|
||||
**Do not confuse IDs:** `memoryId` ≠ `documentId`. In hybrid results, only an item containing `memory` has a forgettable memory ID; an item containing `chunk` has a chunk ID. Static/dynamic profile entries are plain text, so use query-backed profile search results when you need an ID.
|
||||
|
||||
**Soft vs hard delete:** `memoryForget` hides a fact from profile/search but leaves source documents. `documentDelete` permanently removes the underlying stored content.
|
||||
**Soft vs hard delete:** `memoryForget` hides a fact from profile/search but leaves source documents. `documentDelete` permanently removes the underlying source and soft-forgets its extracted memories.
|
||||
|
||||
**When to use profile vs search vs documents:**
|
||||
- **`profile()` / `getProfile`**: Broad user context (static facts + recent dynamic memories). Use before responses when you want a holistic view of the user.
|
||||
- **`search()` / `searchMemories`**: Targeted recall — use proactively before answering when memory could improve the response, not only when the user says "search" or "what do you remember". Hybrid mode combines semantic + keyword search.
|
||||
- **`documents.*`**: Raw content management — list, add, or delete source documents before memory extraction runs.
|
||||
- **`search()` / `searchMemories`**: Targeted recall — use proactively before answering when memory could improve the response, not only when the user says "search" or "what do you remember". Hybrid mode returns both extracted memories and source-document chunks.
|
||||
- **`documents.*`**: Source management — list, add, or delete documents throughout their lifecycle.
|
||||
|
||||
With multiple configured container tags, `searchMemories`, `getProfile`, and `memoryForget` use the first tag because v4 memory operations are single-space. Add, list, and delete operations use the broader configured scope where supported.
|
||||
|
||||
**TypeScript (Vercel AI SDK):**
|
||||
```typescript
|
||||
|
|
@ -167,17 +186,26 @@ const tools = supermemoryTools(process.env.SUPERMEMORY_API_KEY!, {
|
|||
})
|
||||
```
|
||||
|
||||
The aggregate includes destructive tools. Select only the operations the agent needs, and expose `documentDelete` or `memoryForget` only when the agent is authorized to remove data.
|
||||
|
||||
**Python (OpenAI function calling):**
|
||||
```python
|
||||
import os
|
||||
|
||||
from supermemory_openai import SupermemoryTools
|
||||
|
||||
tools = SupermemoryTools(api_key, {"container_tags": ["user_123"]})
|
||||
tools = SupermemoryTools(
|
||||
os.environ["SUPERMEMORY_API_KEY"],
|
||||
{"container_tags": ["user_123"]},
|
||||
)
|
||||
definitions = tools.get_tool_definitions() # all 7 tools
|
||||
```
|
||||
|
||||
Filter `definitions` before passing them to a model if it should not be able to call `document_delete` or `memory_forget`.
|
||||
|
||||
**For Chatbots**: Use middleware (`withSupermemory` / `with_supermemory`) for automatic context injection, or pass tools to the model for explicit memory control
|
||||
|
||||
**For Knowledge Bases (RAG)**: Use `add()` / `documentAdd` for ingestion, then `searchMemories` with hybrid mode for retrieval
|
||||
**For Knowledge Bases (RAG)**: Use `add()` / `documentAdd` for text or URL ingestion, the SDK file-upload method for local files, then `searchMemories` with hybrid mode for retrieval
|
||||
|
||||
**For Task Assistants**: Combine `getProfile` with `searchMemories` for context-aware task completion
|
||||
|
||||
|
|
@ -195,9 +223,8 @@ definitions = tools.get_tool_definitions() # all 7 tools
|
|||
|
||||
1. **Container Tags**: Use consistent user/project IDs as containerTags for proper isolation
|
||||
2. **Metadata**: Add custom metadata for advanced filtering (source, type, timestamp)
|
||||
3. **Thresholds**: Start with `threshold: 0.3` for balanced precision/recall
|
||||
4. **Static Memories**: Mark permanent facts as `isStatic: true` for better performance
|
||||
5. **Batch Operations**: Use bulk endpoints for multiple documents
|
||||
3. **Thresholds**: The v4 search default is `0.6`; tune it only after checking retrieval quality
|
||||
4. **Batch Operations**: Use bulk endpoints for multiple documents
|
||||
|
||||
## Integration Ecosystem
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ npm install supermemory
|
|||
yarn add supermemory
|
||||
# or
|
||||
pnpm add supermemory
|
||||
|
||||
# Agent tools and Vercel AI SDK middleware
|
||||
npm install @supermemory/tools
|
||||
```
|
||||
|
||||
📦 View on npm: [https://www.npmjs.com/package/supermemory](https://www.npmjs.com/package/supermemory)
|
||||
|
|
@ -22,6 +25,9 @@ pnpm add supermemory
|
|||
pip install supermemory
|
||||
# Or for async support with aiohttp
|
||||
pip install 'supermemory[aiohttp]'
|
||||
|
||||
# OpenAI function tools and middleware
|
||||
pip install supermemory-openai-sdk
|
||||
```
|
||||
|
||||
📦 View on PyPI: [https://pypi.org/project/supermemory/](https://pypi.org/project/supermemory/)
|
||||
|
|
@ -44,6 +50,8 @@ const client = new Supermemory({
|
|||
|
||||
### Python
|
||||
```python
|
||||
import os
|
||||
|
||||
from supermemory import Supermemory
|
||||
|
||||
# Synchronous client
|
||||
|
|
@ -69,7 +77,7 @@ Add content to Supermemory for processing and memory extraction.
|
|||
#### TypeScript
|
||||
```typescript
|
||||
await client.add({
|
||||
content: string | URL, // Required: text, URL, or file path
|
||||
content: string, // Required: plaintext or a URL string
|
||||
containerTag?: string, // Optional: isolation identifier
|
||||
entityContext?: string, // Optional: context for memory extraction
|
||||
customId?: string, // Optional: your custom identifier
|
||||
|
|
@ -80,7 +88,7 @@ await client.add({
|
|||
#### Python
|
||||
```python
|
||||
client.add(
|
||||
content=str | url, # Required: text, URL, or file path
|
||||
content=str, # Required: plaintext or a URL string
|
||||
container_tag=str, # Optional: isolation identifier
|
||||
entity_context=str, # Optional: context for memory extraction
|
||||
custom_id=str, # Optional: your custom identifier
|
||||
|
|
@ -88,6 +96,8 @@ client.add(
|
|||
)
|
||||
```
|
||||
|
||||
`add()` does not read a local file path. Upload local files with `client.documents.uploadFile({ file })` in TypeScript or `client.documents.upload_file(file=...)` in Python; `filepath` is metadata, not a file upload.
|
||||
|
||||
#### Examples
|
||||
|
||||
**Add text content:**
|
||||
|
|
@ -137,7 +147,7 @@ const response = await client.profile({
|
|||
// Returns:
|
||||
// {
|
||||
// profile: {
|
||||
// static: string[], // Array of static memories (permanent facts)
|
||||
// static: string[], // Array of long-lived profile facts
|
||||
// dynamic: string[] // Array of dynamic memories (recent context)
|
||||
// },
|
||||
// searchResults?: { // Only included if q parameter was provided
|
||||
|
|
@ -161,18 +171,9 @@ response = client.profile(
|
|||
threshold=float # Optional: relevance threshold (0-1, default 0.5)
|
||||
)
|
||||
|
||||
# Returns dict:
|
||||
# {
|
||||
# "profile": {
|
||||
# "static": List[str], # Array of static memories (permanent facts)
|
||||
# "dynamic": List[str] # Array of dynamic memories (recent context)
|
||||
# },
|
||||
# "searchResults": { # Only included if q parameter was provided
|
||||
# "results": List[dict], # Search results
|
||||
# "total": int,
|
||||
# "timing": int
|
||||
# }
|
||||
# }
|
||||
# Returns a ProfileResponse model:
|
||||
# response.profile.static / response.profile.dynamic
|
||||
# response.search_results.results # only when q was provided
|
||||
```
|
||||
|
||||
#### Examples
|
||||
|
|
@ -203,15 +204,15 @@ console.log(response.profile.dynamic); // Recent dynamic memories
|
|||
|
||||
### `search()` - Semantic Search
|
||||
|
||||
Search across memories using semantic understanding, not just keywords. `client.search.memories()` and `client.search.documents()` still work (deprecated) but `client.search()` is the current, recommended call — Python keeps `client.search.memories()`.
|
||||
Search across memories using semantic retrieval. `client.search()` is the current TypeScript v4 call. Python uses `client.search.memories()` for the same v4 endpoint; the TypeScript `client.search.documents()` method is the legacy v3 document response.
|
||||
|
||||
#### TypeScript
|
||||
```typescript
|
||||
const response = await client.search({
|
||||
q: string, // Required: search query
|
||||
containerTag?: string, // Optional: filter by container tag
|
||||
limit?: number, // Optional: max results (default 10)
|
||||
threshold?: number, // Optional: similarity threshold (0-1, default 0.5)
|
||||
limit?: number, // Optional: max results (default 10, max 100)
|
||||
threshold?: number, // Optional: similarity threshold (0-1, default 0.6)
|
||||
searchMode?: "memories" | "hybrid" | "documents", // Optional: "memories" (default), "hybrid" (memories + document chunks), or "documents" (chunks only)
|
||||
filters?: FilterObject // Optional: advanced filtering
|
||||
});
|
||||
|
|
@ -237,18 +238,14 @@ const response = await client.search({
|
|||
response = client.search.memories(
|
||||
q=str, # Required: search query
|
||||
container_tag=str, # Optional: filter by container tag
|
||||
threshold=float, # Optional: similarity threshold (0-1, default 0.5)
|
||||
limit=int, # Optional: max results (default 50)
|
||||
threshold=float, # Optional: similarity threshold (0-1, default 0.6)
|
||||
limit=int, # Optional: max results (default 10, max 100)
|
||||
search_mode=str, # Optional: "memories" (default), "hybrid", or "documents"
|
||||
filters=dict # Optional: advanced filtering
|
||||
)
|
||||
|
||||
# Returns dict:
|
||||
# {
|
||||
# "results": List[dict], # Array of search results
|
||||
# "total": int,
|
||||
# "timing": int # Search time in milliseconds
|
||||
# }
|
||||
# Returns a SearchMemoriesResponse model:
|
||||
# response.results, response.total, response.timing
|
||||
```
|
||||
|
||||
#### Examples
|
||||
|
|
@ -262,17 +259,17 @@ const response = await client.search({
|
|||
});
|
||||
|
||||
response.results.forEach(result => {
|
||||
console.log(`Score: ${result.score}`);
|
||||
console.log(`Content: ${result.content}`);
|
||||
console.log(`Similarity: ${result.similarity}`);
|
||||
console.log(`Content: ${result.memory ?? result.chunk}`);
|
||||
});
|
||||
```
|
||||
|
||||
**Hybrid search for RAG (semantic + keyword):**
|
||||
**Hybrid search for RAG (memories + source chunks):**
|
||||
```typescript
|
||||
const response = await client.search({
|
||||
q: "authentication methods",
|
||||
containerTag: "docs",
|
||||
searchMode: "hybrid", // Combines semantic and keyword search for better RAG accuracy
|
||||
searchMode: "hybrid", // Returns both extracted memories and document chunks
|
||||
threshold: 0.3,
|
||||
limit: 10
|
||||
});
|
||||
|
|
@ -285,19 +282,20 @@ const response = await client.search({
|
|||
containerTag: "docs",
|
||||
threshold: 0.3,
|
||||
filters: {
|
||||
metadata: {
|
||||
type: "tutorial",
|
||||
category: "security"
|
||||
}
|
||||
AND: [
|
||||
{ key: "type", value: "tutorial" },
|
||||
{ key: "category", value: "security" }
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Search within specific document:**
|
||||
**Search within a filepath:**
|
||||
```typescript
|
||||
const response = await client.search({
|
||||
q: "rate limiting configuration",
|
||||
containerTag: "specific_project"
|
||||
containerTag: "specific_project",
|
||||
filepath: "/docs/api.md"
|
||||
});
|
||||
```
|
||||
|
||||
|
|
@ -308,32 +306,34 @@ Retrieve stored documents with optional filtering and pagination.
|
|||
#### TypeScript
|
||||
```typescript
|
||||
const docs = await client.documents.list({
|
||||
containerTag?: string, // Optional: filter by container
|
||||
limit?: number, // Optional: number of results (default 20)
|
||||
offset?: number, // Optional: pagination offset
|
||||
status?: string // Optional: filter by processing status
|
||||
containerTags?: string[], // Optional: filter by one or more containers
|
||||
limit?: number, // Optional: items per page (default 10)
|
||||
page?: number, // Optional: 1-based page number (default 1)
|
||||
includeContent?: boolean, // Optional: include source content (default false)
|
||||
sort?: "createdAt" | "updatedAt",
|
||||
order?: "asc" | "desc"
|
||||
});
|
||||
|
||||
// Returns:
|
||||
// {
|
||||
// documents: Array<{
|
||||
// memories: Array<{
|
||||
// id: string,
|
||||
// content: string,
|
||||
// status: string,
|
||||
// metadata: object,
|
||||
// createdAt: string
|
||||
// createdAt: string,
|
||||
// content?: string // only when includeContent=true
|
||||
// }>,
|
||||
// total: number
|
||||
// pagination: { currentPage, totalItems, totalPages, limit? }
|
||||
// }
|
||||
```
|
||||
|
||||
#### Python
|
||||
```python
|
||||
docs = client.documents.list(
|
||||
container_tag=str, # Optional: filter by container
|
||||
limit=int, # Optional: number of results (default 20)
|
||||
offset=int, # Optional: pagination offset
|
||||
status=str # Optional: filter by processing status
|
||||
container_tags=[str], # Optional: filter by one or more containers
|
||||
limit=int, # Optional: items per page (default 10)
|
||||
page=int, # Optional: 1-based page number (default 1)
|
||||
include_content=bool # Optional: include source content (default False)
|
||||
)
|
||||
```
|
||||
|
||||
|
|
@ -342,53 +342,39 @@ docs = client.documents.list(
|
|||
**List all documents for a user:**
|
||||
```typescript
|
||||
const docs = await client.documents.list({
|
||||
containerTag: "user_123",
|
||||
containerTags: ["user_123"],
|
||||
limit: 50
|
||||
});
|
||||
|
||||
docs.documents.forEach(doc => {
|
||||
docs.memories.forEach(doc => {
|
||||
console.log(`${doc.id}: ${doc.status}`);
|
||||
});
|
||||
```
|
||||
|
||||
**Paginated listing:**
|
||||
```typescript
|
||||
const page1 = await client.documents.list({ limit: 20, offset: 0 });
|
||||
const page2 = await client.documents.list({ limit: 20, offset: 20 });
|
||||
```
|
||||
|
||||
**Filter by status:**
|
||||
```typescript
|
||||
const processing = await client.documents.list({
|
||||
containerTag: "project_abc",
|
||||
status: "processing"
|
||||
});
|
||||
const page1 = await client.documents.list({ limit: 20, page: 1 });
|
||||
const page2 = await client.documents.list({ limit: 20, page: 2 });
|
||||
```
|
||||
|
||||
### `documents.delete()` - Delete Document
|
||||
|
||||
Remove a document and its associated memories.
|
||||
Permanently remove a source document. Memories extracted from that source are soft-forgotten so they no longer appear in profile or search.
|
||||
|
||||
#### TypeScript
|
||||
```typescript
|
||||
await client.documents.delete({
|
||||
docId: string // Required: document ID
|
||||
});
|
||||
await client.documents.delete(documentId);
|
||||
```
|
||||
|
||||
#### Python
|
||||
```python
|
||||
client.documents.delete(
|
||||
doc_id=str # Required: document ID
|
||||
)
|
||||
client.documents.delete(document_id)
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```typescript
|
||||
await client.documents.delete({
|
||||
docId: "doc_abc123"
|
||||
});
|
||||
await client.documents.delete("doc_abc123");
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
|
@ -414,11 +400,11 @@ const results = await client.search({
|
|||
q: "phone reviews",
|
||||
containerTag: "reviews",
|
||||
filters: {
|
||||
metadata: {
|
||||
rating: { $gte: 4.0 }, // Rating >= 4.0
|
||||
verified: true,
|
||||
tags: { $contains: "apple" }
|
||||
}
|
||||
AND: [
|
||||
{ key: "rating", value: "4.0", filterType: "numeric", numericOperator: ">=" },
|
||||
{ key: "verified", value: "true" },
|
||||
{ key: "tags", value: "apple", filterType: "array_contains" }
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
|
@ -472,33 +458,57 @@ await client.add({
|
|||
|
||||
### Vercel AI SDK
|
||||
|
||||
#### Agent tools (`@supermemory/tools` / `@supermemory/ai-sdk`)
|
||||
#### Agent tools (`@supermemory/tools/ai-sdk` / `@supermemory/ai-sdk`)
|
||||
|
||||
For models that call memory operations explicitly, use the 7-tool set instead of hand-rolling SDK calls:
|
||||
|
||||
```typescript
|
||||
import { generateText } from "ai"
|
||||
import { generateText, stepCountIs } from "ai"
|
||||
import { openai } from "@ai-sdk/openai"
|
||||
import { supermemoryTools } from "@supermemory/tools/ai-sdk"
|
||||
|
||||
const tools = supermemoryTools(process.env.SUPERMEMORY_API_KEY!, {
|
||||
const allTools = supermemoryTools(process.env.SUPERMEMORY_API_KEY!, {
|
||||
containerTags: ["user_123"],
|
||||
})
|
||||
|
||||
// Select the operations this agent is allowed to call.
|
||||
const tools = {
|
||||
searchMemories: allTools.searchMemories,
|
||||
addMemory: allTools.addMemory,
|
||||
getProfile: allTools.getProfile,
|
||||
documentList: allTools.documentList,
|
||||
documentAdd: allTools.documentAdd,
|
||||
}
|
||||
|
||||
const { text } = await generateText({
|
||||
model: openai("gpt-4o"),
|
||||
tools,
|
||||
stopWhen: stepCountIs(5),
|
||||
prompt: "What do you remember about my coffee preferences?",
|
||||
})
|
||||
```
|
||||
|
||||
Tools: `searchMemories`, `addMemory`, `getProfile`, `documentList`, `documentAdd`, `documentDelete`, `memoryForget`.
|
||||
|
||||
Use `searchMemories` for targeted hybrid recall; `getProfile` for broad static/dynamic user context; `documents.*` for raw content management.
|
||||
Use `searchMemories` for targeted hybrid recall; `getProfile` for broad static/dynamic user context; `documentList`, `documentAdd`, and `documentDelete` for source management. Hybrid search returns both extracted memories and source-document chunks.
|
||||
|
||||
If you configure multiple container tags, `searchMemories`, `getProfile`, and `memoryForget` use the first tag because v4 memory operations are single-space. Add, list, and delete operations use the broader configured scope where supported.
|
||||
|
||||
`supermemoryTools()` includes destructive operations. Expose `documentDelete` and `memoryForget` only when the agent is authorized to remove data, and require user confirmation when appropriate. `stopWhen` allows the model to consume tool results and produce a final answer instead of stopping immediately after the first tool call.
|
||||
|
||||
#### Middleware (`withSupermemory`)
|
||||
|
||||
For automatic profile injection and conversation saving without tool calls, use `withSupermemory` from `@supermemory/tools` (see package docs).
|
||||
For automatic profile injection and conversation saving without tool calls, import `withSupermemory` from `@supermemory/tools/ai-sdk`:
|
||||
|
||||
```typescript
|
||||
import { withSupermemory } from "@supermemory/tools/ai-sdk"
|
||||
import { openai } from "@ai-sdk/openai"
|
||||
|
||||
const modelWithMemory = withSupermemory(openai("gpt-4o"), {
|
||||
containerTag: "user_123",
|
||||
customId: "conversation_456",
|
||||
})
|
||||
```
|
||||
|
||||
#### Manual SDK integration
|
||||
|
||||
|
|
@ -515,11 +525,16 @@ async function chat(userId: string, message: string) {
|
|||
containerTag: userId,
|
||||
q: message
|
||||
});
|
||||
const profileText = [
|
||||
...context.profile.static,
|
||||
...context.profile.dynamic,
|
||||
].join('\n');
|
||||
const searchText = JSON.stringify(context.searchResults?.results ?? []);
|
||||
|
||||
// 2. Generate response with context
|
||||
const { text } = await generateText({
|
||||
model: openai('gpt-4'),
|
||||
system: `User Profile: ${context.profile}\n\nRelevant Context:\n${context.memories.map(m => m.content).join('\n')}`,
|
||||
system: `User Profile:\n${profileText}\n\nRelevant Context:\n${searchText}`,
|
||||
prompt: message
|
||||
});
|
||||
|
||||
|
|
@ -580,13 +595,22 @@ def create_memory_enhanced_agent(user_id: str):
|
|||
# Get user context
|
||||
context = memory.profile(
|
||||
container_tag=user_id,
|
||||
query="user preferences and history"
|
||||
q="user preferences and history"
|
||||
)
|
||||
|
||||
profile_text = "\n".join(
|
||||
(context.profile.static or []) + (context.profile.dynamic or [])
|
||||
)
|
||||
search_text = "\n".join(
|
||||
result.memory
|
||||
for result in (context.search_results.results if context.search_results else [])
|
||||
if result.memory
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
role="Personal Assistant",
|
||||
goal="Help the user with personalized assistance",
|
||||
backstory=f"User Context: {context['profile']}\n\nRecent interactions:\n{context['memories']}",
|
||||
backstory=f"User Context:\n{profile_text}\n\nRelevant memories:\n{search_text}",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
|
|
@ -632,9 +656,9 @@ await client.add({
|
|||
```
|
||||
|
||||
### 4. Appropriate Thresholds
|
||||
Start with default (0.5) and adjust based on results:
|
||||
Start with the v4 search default (`0.6`) and adjust based on results:
|
||||
- **0.3-0.5**: Broader recall, good for discovery
|
||||
- **0.5-0.7**: Balanced precision and recall
|
||||
- **0.5-0.7**: Balanced precision and recall; `0.6` is the default
|
||||
- **0.7-1.0**: High precision, fewer but more relevant results
|
||||
|
||||
### 5. Error Handling
|
||||
|
|
@ -660,7 +684,6 @@ try {
|
|||
- `entityContext`
|
||||
- `customId`
|
||||
- `threshold`
|
||||
- `docId`
|
||||
- `q`
|
||||
|
||||
### Python (snake_case)
|
||||
|
|
@ -668,15 +691,13 @@ try {
|
|||
- `entity_context`
|
||||
- `custom_id`
|
||||
- `threshold`
|
||||
- `doc_id`
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Batch Operations**: Add multiple documents in quick succession if needed
|
||||
2. **Async/Await**: Always use async operations to avoid blocking
|
||||
3. **Pagination**: Use `limit` and `offset` for large result sets
|
||||
3. **Pagination**: Use `limit` and 1-based `page` for large document lists
|
||||
4. **Caching**: Cache profile() results for short periods if making multiple calls
|
||||
5. **Processing Time**: Allow 1-2 minutes for PDFs, 5-10 minutes for videos
|
||||
|
||||
## Support
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue