fix(docs): align Supermemory skill with current SDKs

This commit is contained in:
ved015 2026-08-23 20:07:39 +05:30
parent ded65fbbdd
commit 9263c1560e
2 changed files with 159 additions and 111 deletions

View file

@ -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

View file

@ -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