diff --git a/README.md b/README.md index 36e862f6..f7e7fd18 100644 --- a/README.md +++ b/README.md @@ -134,13 +134,23 @@ You can find them here: - OpenCode plugin: https://github.com/supermemoryai/opencode-supermemory - Hermes agent (Supermemory memory provider): https://github.com/NousResearch/hermes-agent -### MCP - Quick install +### MCP -```bash -npx -y install-mcp@latest https://mcp.supermemory.ai/mcp --client claude --oauth=yes +Server URL: + +```text +https://mcp.supermemory.ai/mcp ``` -Replace `claude` with your client: `cursor`, `windsurf`, `vscode`, etc. +```json +{ + "mcpServers": { + "supermemory": { + "url": "https://mcp.supermemory.ai/mcp" + } + } +} +``` Read more about our MCP here - https://supermemory.ai/docs/supermemory-mcp/mcp @@ -271,7 +281,7 @@ const agent = new Agent(withSupermemory(config, "user-123", { mode: "full" })); ```typescript // Hybrid (default) — RAG + Memory in one query -const results = await client.search.memories({ +const results = await client.search({ q: "how do I deploy?", containerTag: "user_123", searchMode: "hybrid", @@ -279,7 +289,7 @@ const results = await client.search.memories({ // Returns deployment docs (RAG) + user's deploy preferences (Memory) // Memories only -const results = await client.search.memories({ +const results = await client.search({ q: "user preferences", containerTag: "user_123", searchMode: "memories", @@ -313,8 +323,8 @@ Real-time webhooks. Documents automatically processed, chunked, and searchable. |---|---| | `client.add()` | Store content — text, conversations, URLs, HTML | | `client.profile()` | User profile + optional search in one call | -| `client.search.memories()` | Hybrid search across memories and documents | -| `client.search.documents()` | Document search with metadata filters | +| `client.search()` | Hybrid search across memories and documents (`searchMode`) | +| `client.search.documents()` | Document search with metadata filters (legacy v3 response shape) | | `client.documents.uploadFile()` | Upload PDFs, images, videos, code | | `client.documents.list()` | List and filter documents | | `client.settings.update()` | Configure memory extraction and chunking | diff --git a/README.zh-CN.md b/README.zh-CN.md index 7cd710fb..7440320b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -110,13 +110,23 @@ Supermemory 已经为 Claude Code、OpenCode、OpenClaw、Hermes 提供了开箱 - OpenCode 插件:https://github.com/supermemoryai/opencode-supermemory - Hermes agent(Supermemory 作为记忆 provider):https://github.com/NousResearch/hermes-agent -### MCP——一键安装 +### MCP -```bash -npx -y install-mcp@latest https://mcp.supermemory.ai/mcp --client claude --oauth=yes +服务地址: + +```text +https://mcp.supermemory.ai/mcp ``` -把 `claude` 换成你用的客户端即可:`cursor`、`windsurf`、`vscode` 等等。 +```json +{ + "mcpServers": { + "supermemory": { + "url": "https://mcp.supermemory.ai/mcp" + } + } +} +``` 更多 MCP 细节见:https://supermemory.ai/docs/supermemory-mcp/mcp @@ -247,7 +257,7 @@ const agent = new Agent(withSupermemory(config, "user-123", { mode: "full" })); ```typescript // 混合检索(默认)——一次查询同时跑 RAG 和记忆 -const results = await client.search.memories({ +const results = await client.search({ q: "how do I deploy?", containerTag: "user_123", searchMode: "hybrid", @@ -255,7 +265,7 @@ const results = await client.search.memories({ // 返回部署文档(RAG)+ 该用户的部署偏好(记忆) // 只查记忆 -const results = await client.search.memories({ +const results = await client.search({ q: "user preferences", containerTag: "user_123", searchMode: "memories", @@ -289,8 +299,8 @@ const { profile } = await client.profile({ containerTag: "user_123" }); |---|---| | `client.add()` | 存储内容——文本、对话、URL、HTML | | `client.profile()` | 一次调用返回用户画像 + 可选检索 | -| `client.search.memories()` | 跨记忆和文档的混合检索 | -| `client.search.documents()` | 带元数据过滤的文档检索 | +| `client.search()` | 跨记忆和文档的混合检索(`searchMode`) | +| `client.search.documents()` | 带元数据过滤的文档检索(旧版 v3 响应格式) | | `client.documents.uploadFile()` | 上传 PDF、图片、视频、代码 | | `client.documents.list()` | 列出和筛选文档 | | `client.settings.update()` | 配置记忆抽取与切分策略 | diff --git a/apps/docs/add-memories/examples/basic.mdx b/apps/docs/add-memories/examples/basic.mdx deleted file mode 100644 index 02cac11e..00000000 --- a/apps/docs/add-memories/examples/basic.mdx +++ /dev/null @@ -1,278 +0,0 @@ ---- -title: "Basic Usage" -description: "Simple examples of adding text content to Supermemory" ---- - -Learn how to add basic text content to Supermemory with simple, practical examples. - -## Add Simple Text - -The most basic operation - adding plain text content. - - - -```typescript TypeScript -const response = await client.add({ - content: "Artificial intelligence is transforming how we work and live" -}); - -console.log(response); -// Output: { id: "abc123", status: "queued" } -``` - -```python Python -response = client.add( - content="Artificial intelligence is transforming how we work and live" -) - -print(response) -# Output: {"id": "abc123", "status": "queued"} -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "Artificial intelligence is transforming how we work and live" - }' -``` - - - -## Add with Container Tags - -Group related content using container tags. - - - -```typescript TypeScript -const response = await client.add({ - content: "Q4 2024 revenue exceeded projections by 15%", - containerTag: "financial_reports" -}); - -console.log(response.id); -// Output: xyz789 -``` - -```python Python -response = client.add( - content="Q4 2024 revenue exceeded projections by 15%", - container_tag="financial_reports" -) - -print(response['id']) -# Output: xyz789 -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "Q4 2024 revenue exceeded projections by 15%", - "containerTag": "financial_reports" - }' - -# Response: {"id": "xyz789", "status": "queued"} -``` - - - -## Add with Metadata - -Attach metadata for better search and filtering. - - - -```typescript TypeScript -await client.add({ - content: "New onboarding flow reduces drop-off by 30%", - containerTag: "product_updates", - metadata: { - impact: "high", - team: "product" - } -}); -``` - -```python Python -client.add( - content="New onboarding flow reduces drop-off by 30%", - container_tag="product_updates", - metadata={ - "impact": "high", - "team": "product" - } -) -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "New onboarding flow reduces drop-off by 30%", - "containerTag": "product_updates", - "metadata": {"impact": "high", "team": "product"} - }' -``` - - - -## Add Multiple Documents - -Process multiple related documents. - - - -```typescript TypeScript -const notes = [ - "API redesign discussion", - "Security audit next month", - "New hire starting Monday" -]; - -const results = await Promise.all( - notes.map(note => - client.add({ - content: note, - containerTag: "meeting_2024_01_15" - }) - ) -); -``` - -```python Python -notes = [ - "API redesign discussion", - "Security audit next month", - "New hire starting Monday" -] - -for note in notes: - client.add( - content=note, - container_tag="meeting_2024_01_15" - ) -``` - -```bash cURL -# Add each note with separate requests -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "API redesign discussion", "containerTag": "meeting_2024_01_15"}' -``` - - - -## Add URLs - -Process web pages, YouTube videos, and other URLs automatically. - - - -```typescript TypeScript -// Web page -await client.add({ - content: "https://example.com/article", - containerTag: "articles" -}); - -// YouTube video (auto-transcribed) -await client.add({ - content: "https://youtube.com/watch?v=dQw4w9WgXcQ", - containerTag: "videos" -}); - -// Google Docs -await client.add({ - content: "https://docs.google.com/document/d/abc123/edit", - containerTag: "docs" -}); -``` - -```python Python -# Web page -client.add( - content="https://example.com/article", - container_tag="articles" -) - -# YouTube video (auto-transcribed) -client.add( - content="https://youtube.com/watch?v=dQw4w9WgXcQ", - container_tag="videos" -) - -# Google Docs -client.add( - content="https://docs.google.com/document/d/abc123/edit", - container_tag="docs" -) -``` - -```bash cURL -# Web page -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "https://example.com/article", "containerTag": "articles"}' - -# YouTube video -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "https://youtube.com/watch?v=dQw4w9WgXcQ", "containerTag": "videos"}' -``` - - - -## Add Markdown Content - -Supermemory preserves markdown formatting. - - - -```typescript TypeScript -const markdown = ` -# Project Documentation - -## Features -- **Real-time sync** -- **AI search** -- **Enterprise security** -`; - -await client.add({ - content: markdown, - containerTag: "docs" -}); -``` - -```python Python -markdown = """ -# Project Documentation - -## Features -- **Real-time sync** -- **AI search** -- **Enterprise security** -""" - -client.add( - content=markdown, - container_tag="docs" -) -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "# Project Documentation\n\n## Features\n- **Real-time sync**\n- **AI search**", "containerTag": "docs"}' -``` - - diff --git a/apps/docs/add-memories/examples/file-upload.mdx b/apps/docs/add-memories/examples/file-upload.mdx deleted file mode 100644 index 7d79d36e..00000000 --- a/apps/docs/add-memories/examples/file-upload.mdx +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: "File Upload" -description: "Upload PDFs, images, and other files to Supermemory" ---- - -Upload files directly to Supermemory for automatic content extraction and processing. - -## Upload a PDF - -Extract text from PDFs with OCR support. - - - -```typescript TypeScript -const file = fs.createReadStream('document.pdf'); - -const response = await client.documents.uploadFile({ - file: file, - containerTags: 'documents' -}); - -console.log(response.id); -// Output: pdf_123 -``` - -```python Python -with open('document.pdf', 'rb') as file: - response = client.documents.upload_file( - file=file, - container_tags='documents' - ) - -print(response['id']) -# Output: pdf_123 -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents/file" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -F "file=@document.pdf" \ - -F "containerTags=documents" - -# Response: {"id": "pdf_123", "status": "processing"} -``` - - - -## Upload Images with OCR - -Extract text from images. - - - -```typescript TypeScript -const image = fs.createReadStream('screenshot.png'); - -await client.documents.uploadFile({ - file: image, - containerTags: 'images' -}); -``` - -```python Python -with open('screenshot.png', 'rb') as file: - client.documents.upload_file( - file=file, - container_tags='images' - ) -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents/file" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -F "file=@screenshot.png" \ - -F "containerTags=images" -``` - - - -## Browser File Upload - -Handle browser file uploads. - - - -```javascript JavaScript -const formData = new FormData(); -formData.append('file', fileInput.files[0]); -formData.append('containerTags', 'uploads'); - -const response = await fetch('https://api.supermemory.ai/v3/documents/file', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${API_KEY}` - }, - body: formData -}); - -const result = await response.json(); -console.log(result.id); -``` - -```typescript React -function handleUpload(file: File) { - const formData = new FormData(); - formData.append('file', file); - formData.append('containerTags', 'uploads'); - - return fetch('https://api.supermemory.ai/v3/documents/file', { - method: 'POST', - headers: { 'Authorization': `Bearer ${API_KEY}` }, - body: formData - }); -} -``` - -```bash cURL -# Browser uploads use FormData, same as file upload -curl -X POST "https://api.supermemory.ai/v3/documents/file" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -F "file=@document.pdf" \ - -F "containerTags=uploads" -``` - - - -## Upload Multiple Files - -Batch upload with rate limiting. - - - -```typescript TypeScript -for (const file of files) { - const stream = fs.createReadStream(file); - - await client.documents.uploadFile({ - file: stream, - containerTags: 'batch' - }); - - // Rate limit - await new Promise(r => setTimeout(r, 1000)); -} -``` - -```python Python -import time - -for file_path in files: - with open(file_path, 'rb') as file: - client.documents.upload_file( - file=file, - container_tags='batch' - ) - - time.sleep(1) # Rate limit -``` - -```bash cURL -# Upload each file separately with delays -for file in *.pdf; do - curl -X POST "https://api.supermemory.ai/v3/documents/file" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -F "file=@$file" \ - -F "containerTags=batch" - - sleep 1 # Rate limit -done -``` - - - -## Supported File Types - -### Documents -| Format | Extensions | Processing | -|--------|------------|------------| -| PDF | .pdf | Text extraction, OCR for scanned pages | -| Microsoft Word | .doc, .docx | Full text and formatting extraction | -| Plain Text | .txt, .md | Direct text processing | -| CSV | .csv | Structured data extraction | - -### Images -| Format | Extensions | Processing | -|--------|------------|------------| -| JPEG | .jpg, .jpeg | OCR text extraction | -| PNG | .png | OCR text extraction | -| GIF | .gif | OCR for static images | -| WebP | .webp | OCR text extraction | - -### Size Limits -- **Maximum file size**: 50MB -- **Recommended size**: < 10MB for optimal processing -- **Large files**: May take longer to process diff --git a/apps/docs/add-memories/overview.mdx b/apps/docs/add-memories/overview.mdx deleted file mode 100644 index be96185a..00000000 --- a/apps/docs/add-memories/overview.mdx +++ /dev/null @@ -1,249 +0,0 @@ ---- -title: "Add Memories Overview" -description: "Add content to Supermemory through text, files, or URLs" -sidebarTitle: "Overview" ---- - -Add any type of content to Supermemory - text, files, URLs, images, videos, and more. Everything is automatically processed into searchable memories that form part of your intelligent knowledge graph. - -## Prerequisites - -Before adding memories, you need to set up the Supermemory client: - -- **Install the SDK** for your language -- **Get your API key** from [Supermemory Console](https://console.supermemory.ai) -- **Initialize the client** with your API key - - - -```bash npm -npm install supermemory -``` - -```bash pip -pip install supermemory -``` - - - - - -```typescript TypeScript -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! -}); -``` - -```python Python -from supermemory import Supermemory -import os - -client = Supermemory( - api_key=os.environ.get("SUPERMEMORY_API_KEY") -) -``` - - - -## Quick Start - - - -```typescript TypeScript -// Add text content -const result = await client.add({ - content: "Machine learning enables computers to learn from data", - containerTag: "ai-research", - metadata: { priority: "high" } -}); - -console.log(result); -// Output: { id: "abc123", status: "queued" } -``` - -```python Python -# Add text content -result = client.add( - content="Machine learning enables computers to learn from data", - container_tags=["ai-research"], - metadata={"priority": "high"} -) - -print(result) -# Output: {"id": "abc123", "status": "queued"} -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "Machine learning enables computers to learn from data", - "containerTag": "ai-research", - "metadata": {"priority": "high"} - }' - -# Response: {"id": "abc123", "status": "queued"} -``` - - - -## Key Concepts - - -**New to Supermemory?** Read [How Supermemory Works](/how-it-works) to understand the knowledge graph architecture and the distinction between documents and memories. - - -### Quick Overview -- **Documents**: Raw content you upload (PDFs, URLs, text) -- **Memories**: Searchable chunks created automatically with relationships -- **Container Tags**: Group related content for better context -- **Metadata**: Additional information for filtering - -### Content Sources - -Add content through three methods: - -1. **Direct Text**: Send text content directly via API -2. **File Upload**: Upload PDFs, images, videos for extraction -3. **URL Processing**: Automatic extraction from web pages and platforms - -## Endpoints - - -Remember, these endpoints add documents. Memories are inferred by Supermemory. - - -### Add Content - -`POST /v3/documents` - -Add text content, URLs, or any supported format. - - - -```typescript TypeScript -await client.add({ - content: "Your content here", - containerTag: "project" -}); -``` - -```python Python -client.add( - content="Your content here", - container_tags=["project"] -) -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "Your content here", "containerTag": "project"}' -``` - - - -### Upload File - -`POST /v3/documents/file` - -Upload files directly for processing. - - - -```typescript TypeScript -await client.documents.uploadFile({ - file: fileStream, - containerTag: "project" -}); -``` - -```python Python -client.documents.upload_file( - file=open('file.pdf', 'rb'), - container_tags='project' -) -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/documents/file" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -F "file=@document.pdf" \ - -F "containerTags=project" -``` - - - -### Update Memory - -`PATCH /v3/documents/{id}` - -Update existing document content or metadata. Content changes trigger reindexing; metadata-only updates do not. - - - -```typescript TypeScript -await client.documents.update("doc_id", { - content: "Updated content" -}); -``` - -```python Python -client.documents.update("doc_id", { - "content": "Updated content" -}) -``` - -```bash cURL -curl -X PATCH "https://api.supermemory.ai/v3/documents/doc_id" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "Updated content"}' -``` - - - -## Supported Content Types - -### Documents -- PDF with OCR support -- Google Docs, Sheets, Slides -- Notion pages -- Microsoft Office files - -### Media -- Images (JPG, PNG, GIF, WebP) with OCR - -### Web Content -- Twitter/X posts -- YouTube videos with captions - -### Text Formats -- Plain text -- Markdown -- CSV files - - Refer to the [connectors guide](/connectors/overview) to learn how you can connect Google Drive, Notion, and OneDrive and sync files in real-time. - -## Response Format - -```json -{ - "id": "D2Ar7Vo7ub83w3PRPZcaP1", - "status": "queued" -} -``` - -- **`id`**: Unique document identifier -- **`status`**: Processing state (`queued`, `processing`, `done`) - - - -## Next Steps - -- [Memory Operations](/memory-operations) - Track status, list, update, and delete memories -- [Search Memories](/search) - Search your content diff --git a/apps/docs/add-memories/parameters.mdx b/apps/docs/add-memories/parameters.mdx deleted file mode 100644 index dedfad0e..00000000 --- a/apps/docs/add-memories/parameters.mdx +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: "Parameters" -description: "Complete reference for add memory parameters" ---- - -Detailed parameter documentation for adding memories to Supermemory. - -## Request Parameters - -### Required Parameters - - - The content to process into memories. Can be: - - Plain text content - - URL to process - - HTML content - - Markdown text - - ```json - { - "content": "Machine learning is a subset of AI..." - } - ``` - - **URL Examples:** - ```json - { - "content": "https://youtube.com/watch?v=dQw4w9WgXcQ" - } - ``` - - -### Optional Parameters - - - **Recommended.** Single tag to group related memories. Improves search performance. - - Default: `"sm_project_default"` - - ```json - { - "containerTag": "project_alpha" - } - ``` - - - Use `containerTag` (singular) for better performance than `containerTags` (array). - - - - - Additional metadata as key-value pairs. Values must be strings, numbers, or booleans. - - ```json - { - "metadata": { - "source": "research-paper", - "author": "John Doe", - "priority": 1, - "reviewed": true - } - } - ``` - - **Restrictions:** - - No nested objects - - No arrays as values - - Keys must be strings - - Values: string, number, or boolean only - - - - Your own identifier for the document. Enables deduplication and updates. - - **Maximum length:** 255 characters - - ```json - { - "customId": "doc_2024_01_research_ml" - } - ``` - - **Use cases:** - - Prevent duplicate uploads - - Update existing documents - - Sync with external systems - - - - Raw content to store alongside processed content. Useful for preserving original formatting. - - ```json - { - "content": "# Machine Learning\n\nML is a subset of AI...", - "raw": "# Machine Learning\n\nML is a subset of AI..." - } - ``` - - -## File Upload Parameters - -For `POST /v3/documents/file` endpoint: - - - The file to upload. Supported formats: - - **Documents:** PDF, DOC, DOCX, TXT, MD - - **Images:** JPG, PNG, GIF, WebP - - **Videos:** MP4, WebM, AVI - - **Maximum size:** 50MB - - - - Container tag for the uploaded file (sent as form field). - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/file" \ - -F "file=@document.pdf" \ - -F "containerTags=research" - ``` - - - -## Container Tag Patterns - -### Recommended Patterns - -```typescript -// By user -"user_123" - -// By project -"project_alpha" - -// By organization and type -"org_456_research" - -// By time period -"2024_q1_reports" - -// By data source -"slack_channel_general" -``` - -### Performance Considerations - -```typescript -// ✅ FAST: Single tag -{ "containerTag": "project_alpha" } - -// ⚠️ SLOWER: Multiple tags -{ "containerTags": ["project_alpha", "backend", "auth"] } - -// ❌ AVOID: Too many tags -{ "containerTags": ["tag1", "tag2", "tag3", "tag4", "tag5"] } -``` diff --git a/apps/docs/agents-and-mcp.mdx b/apps/docs/agents-and-mcp.mdx new file mode 100644 index 00000000..4098137f --- /dev/null +++ b/apps/docs/agents-and-mcp.mdx @@ -0,0 +1,248 @@ +--- +title: "Agents, skills and MCP" +description: "Set up coding agents to integrate Supermemory — CLI, skill, and docs MCP." +sidebarTitle: "Agents, skills and MCP" +icon: "bot" +--- + +This page is for **building with Supermemory** using coding agents: scaffolding a project, following the real API, and searching product docs. + +It is **not** the consumer Memory MCP (give Claude/Cursor long-term memory about *you*). That is a separate product surface — see [Supermemory MCP](/supermemory-mcp/mcp). + +| Path | How | For | +|---|---|---| +| **CLI** | `npx supermemory` | Setup, smoke tests, agent-driven integration | +| **Skill** | `npx skills add … --skill supermemory` | Teach the agent the real API surface | +| **Docs MCP** | `https://supermemory.ai/docs/mcp` | Search these docs while the agent codes | + +## CLI + +Agents (and humans) can set things up from the terminal easily using our CLI + +```bash +npx supermemory +``` + +Useful for coding agents: + +```bash +npx supermemory setup # detect project, launch/print integration flow +npx supermemory setup --prompt # print integration prompt only +npx supermemory setup --json # machine-readable output +npx supermemory help --json # agent-readable command catalog +npx supermemory help --all +``` + +Also available for smoke tests against your key: `add`, `search`, `profile`, `docs`, `tags`, `config`, `whoami`. Auth via first-run credentials or `SUPERMEMORY_API_KEY`. + +```bash +npx supermemory add "User prefers TypeScript" --tag user_123 +npx supermemory search "language preference" --tag user_123 +npx supermemory profile --tag user_123 +``` + +## Skill + +Install the official skill so the agent uses the real endpoints, auth, and `containerTag` rules instead of hallucinating APIs: + +```bash +npx skills add https://github.com/supermemoryai/skills --skill supermemory +``` + +Source: [github.com/supermemoryai/skills](https://github.com/supermemoryai/skills). + + +Best combo for coding agents: **skill** + **docs MCP** + **`npx supermemory setup`**. + + +## Docs MCP + +Remote MCP that lets the agent **search Supermemory documentation** while it implements an integration. + +Server URL: + +```text +https://supermemory.ai/docs/mcp +``` + +### Setup by client + + + + Add to `~/.cursor/mcp.json`: + + ```json + { + "mcpServers": { + "supermemory-docs": { + "url": "https://supermemory.ai/docs/mcp" + } + } + } + ``` + + + + ```bash + claude mcp add --transport http supermemory-docs https://supermemory.ai/docs/mcp + ``` + + Or project `.mcp.json`: + + ```json + { + "mcpServers": { + "supermemory-docs": { + "type": "http", + "url": "https://supermemory.ai/docs/mcp" + } + } + } + ``` + + + + ```bash + codex mcp add supermemory-docs --url https://supermemory.ai/docs/mcp + ``` + + Or `~/.codex/config.toml`: + + ```toml + [mcp_servers.supermemory-docs] + url = "https://supermemory.ai/docs/mcp" + ``` + + + + ```json + { + "mcp": { + "supermemory-docs": { + "type": "remote", + "url": "https://supermemory.ai/docs/mcp", + "enabled": true + } + } + } + ``` + + + + Add to `.vscode/mcp.json`: + + ```json + { + "servers": { + "supermemory-docs": { + "type": "http", + "url": "https://supermemory.ai/docs/mcp" + } + } + } + ``` + + + + ```json + { + "mcpServers": { + "supermemory-docs": { + "url": "https://supermemory.ai/docs/mcp" + } + } + } + ``` + + Stdio-only clients can proxy: + + ```json + { + "mcpServers": { + "supermemory-docs": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://supermemory.ai/docs/mcp"] + } + } + } + ``` + + + +### Starter prompt (docs + setup) + +```text +You are integrating Supermemory into my app. + +- Use the supermemory-docs MCP (or https://supermemory.ai/docs/llms.txt) before inventing endpoints. +- Prefer `npx supermemory setup` / the supermemory skill for correct auth, containerTag, and SDK usage. +- Canonical writes: POST /v3/documents · search: POST /v4/search · profile: POST /v4/profile +- Auth: Authorization: Bearer $SUPERMEMORY_API_KEY only +- Always scope with containerTag (singular) on write and search +- For demos use dreaming: "instant" when memories must be ready right after status done +``` + +### Integrate prompt (optional) + +If the skill is not installed, paste a fuller prompt so the agent asks the right product questions: + + +```` +You are integrating Supermemory into my application. Supermemory provides user memory, semantic search, and automatic knowledge extraction for AI applications. + +Note: You can always reference the documentation by using the **supermemory-docs MCP** or content on **supermemory.ai/docs**. Prefer `npx supermemory setup` / `npx supermemory help --json` when scaffolding. + +CANONICAL API SURFACE (use these, nothing else): + +- Auth header: `Authorization: Bearer $SUPERMEMORY_API_KEY` — the only supported auth header +- Write content: POST https://api.supermemory.ai/v3/documents +- Search: POST https://api.supermemory.ai/v4/search +- Profile + search: POST https://api.supermemory.ai/v4/profile +- Settings: PATCH https://api.supermemory.ai/v3/settings +- Scoping: `containerTag` (singular string) in the JSON body — never in a header +- SDK: `client.add()`, `client.search()`, `client.profile()` + +DO NOT USE — deprecated, undocumented, or fabricated: + +- Endpoints: /v1/anything, /v3/memories, /v3/search (use /v3/documents and /v4/search) +- Headers: x-supermemory-api-key, x-api-key, x-sm-user-id (for API auth) +- Body keys: containerTags (plural) on writes as the only scope, userId, spaces +- Mixing: `rerank` and `rewriteQuery` on /v4/search only — never on /v3/search + +SCOPING IS LOAD-BEARING. Every write and every search MUST include `containerTag`. + +Prefer for tutorials: +- Ingest conversations with customId + dreaming: "instant" when you need memories immediately +- Wait until document status is done before search +- search with searchMode: "documents" for RAG, search (+ relatedMemories) for the graph, profile for always-on context + +STEP 1: Ask what I'm building, integration style (AI SDK / OpenAI / Direct SDK / API), data model (user/org/both), profiles yes/no. +STEP 2: Install supermemory (npm/pip), set SUPERMEMORY_API_KEY from https://console.supermemory.ai +STEP 3: Generate complete working code. + +DOCS: https://supermemory.ai/docs +```` + + +## Memory MCP (different product) + +Want your **assistant** to remember you across chats (save/recall/profile in Claude, Cursor, etc.)? That is the **Memory MCP**, not the docs MCP: + +→ [Supermemory MCP](/supermemory-mcp/mcp) + +## Next steps + + + + Conversation + document ingest, RAG, graph, profile, harness. + + + Persistent memory for assistants — separate from docs setup. + + + Claude Code, OpenClaw, Codex, Hermes, and more. + + + withSupermemory and memory tools in app code. + + diff --git a/apps/docs/ai-sdk/examples.mdx b/apps/docs/ai-sdk/examples.mdx deleted file mode 100644 index 9eabbae9..00000000 --- a/apps/docs/ai-sdk/examples.mdx +++ /dev/null @@ -1,357 +0,0 @@ ---- -title: "AI SDK Examples" -description: "Complete examples showing how to use Supermemory with Vercel AI SDK" -sidebarTitle: "Examples" ---- - -This page provides comprehensive examples of using Supermemory with the Vercel AI SDK, covering Memory Tools and User Profiles approaches. - -## Personal Assistant with Memory Tools - -Build an AI assistant that remembers user preferences and past interactions: - - - -```typescript Next.js API Route -import { streamText } from 'ai' -import { createAnthropic } from '@ai-sdk/anthropic' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const anthropic = createAnthropic({ - apiKey: process.env.ANTHROPIC_API_KEY! -}) - -export async function POST(request: Request) { - const { messages } = await request.json() - - const result = await streamText({ - model: anthropic('claude-3-sonnet-20240229'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!), - system: `You are a helpful personal assistant. When users share information about themselves, - remember it using the addMemory tool. When they ask questions, search your memories to provide - personalized responses. Always be proactive about remembering important details.` - }) - - return result.toAIStreamResponse() -} -``` - -```typescript Client Component -'use client' - -import { useChat } from 'ai/react' - -export default function PersonalAssistant() { - const { messages, input, handleInputChange, handleSubmit } = useChat() - - return ( -
-
- {messages.map((message) => ( -
-

{message.content}

-
- ))} -
- -
- -
-
- ) -} -``` - -
- -**Example conversation:** -- User: "I'm allergic to peanuts and I love Italian food" -- AI: *Uses addMemory tool* "I've remembered that you're allergic to peanuts and love Italian food!" -- User: "Suggest a restaurant for dinner" -- AI: *Uses searchMemories tool* "Based on what I know about you, I'd recommend an Italian restaurant that's peanut-free..." - -## Customer Support with Context - -Build a customer support system that remembers customer history: - -```typescript -import { streamText } from 'ai' -import { createOpenAI } from '@ai-sdk/openai' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, customerId } = await request.json() - - const result = await streamText({ - model: openai('gpt-5'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: [customerId] - }), - system: `You are a customer support agent. Before responding to any query: - 1. Search for the customer's previous interactions and issues - 2. Remember any new information shared in this conversation - 3. Provide personalized help based on their history - 4. Always be empathetic and solution-focused` - }) - - return result.toAIStreamResponse() -} -``` - -## Multi-User Learning Assistant - -Build an assistant that learns from multiple users but keeps data separate: - -```typescript -import { streamText } from 'ai' -import { createAnthropic } from '@ai-sdk/anthropic' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const anthropic = createAnthropic({ - apiKey: process.env.ANTHROPIC_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, userId, courseId } = await request.json() - - const result = await streamText({ - model: anthropic('claude-3-haiku-20240307'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: [userId] - }), - system: `You are a learning assistant. Help students with their coursework by: - 1. Remembering their learning progress and struggles - 2. Searching for relevant information from their past sessions - 3. Providing personalized explanations based on their learning style - 4. Tracking topics they've mastered vs topics they need more help with` - }) - - return result.toAIStreamResponse() -} -``` - -## Research Assistant with File Processing - -Combine file upload with memory tools for research assistance: - - - -```typescript API Route -import { streamText } from 'ai' -import { createOpenAI } from '@ai-sdk/openai' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, projectId } = await request.json() - - const result = await streamText({ - model: openai('gpt-5'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: [projectId] - }), - system: `You are a research assistant. You can: - 1. Search through uploaded research papers and documents - 2. Remember key findings and insights from conversations - 3. Help synthesize information across multiple sources - 4. Track research progress and important discoveries` - }) - - return result.toAIStreamResponse() -} -``` - -```typescript File Upload Handler -import { addMemory } from '@supermemory/tools' - -export async function POST(request: Request) { - const formData = await request.formData() - const file = formData.get('file') as File - const projectId = formData.get('projectId') as string - - // Upload file and add to memory - const memory = await addMemory({ - apiKey: process.env.SUPERMEMORY_API_KEY!, - content: file, // Supermemory handles file processing - title: file.name, - headers: { - 'x-sm-conversation-id': projectId - } - }) - - return Response.json({ - success: true, - message: "Document uploaded and processed for research", - memoryId: memory.id - }) -} -``` - - - -## Code Assistant with Project Memory - -Create a coding assistant that remembers your codebase and preferences: - -```typescript -import { streamText } from 'ai' -import { createAnthropic } from '@ai-sdk/anthropic' -import { - supermemoryTools, - searchMemoriesTool, - addMemoryTool -} from '@supermemory/tools/ai-sdk' - -const anthropic = createAnthropic({ - apiKey: process.env.ANTHROPIC_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, repositoryId } = await request.json() - - const result = await streamText({ - model: anthropic('claude-3-sonnet-20240229'), - messages, - tools: { - // Use individual tools for more control - searchMemories: searchMemoriesTool(process.env.SUPERMEMORY_API_KEY!, { - headers: { - 'x-sm-conversation-id': `repo-${repositoryId}` - } - }), - addMemory: addMemoryTool(process.env.SUPERMEMORY_API_KEY!, { - headers: { - 'x-sm-conversation-id': `repo-${repositoryId}` - } - }), - // Add custom tools - executeCode: { - description: 'Execute code in a sandbox environment', - parameters: z.object({ - code: z.string(), - language: z.string() - }), - execute: async ({ code, language }) => { - // Your code execution logic - return { result: "Code executed successfully" } - } - } - }, - system: `You are a coding assistant with memory. You can: - 1. Remember coding patterns and preferences from past conversations - 2. Search through previous code examples and solutions - 3. Track project architecture and design decisions - 4. Learn from debugging sessions and common issues` - }) - - return result.toAIStreamResponse() -} -``` - -## Advanced: Custom Tool Integration - -Combine Supermemory tools with your own custom tools: - -```typescript -import { streamText } from 'ai' -import { createOpenAI } from '@ai-sdk/openai' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' -import { z } from 'zod' - -const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! -}) - -// Custom tool for calendar integration -const calendarTool = { - description: 'Create calendar events', - parameters: z.object({ - title: z.string(), - date: z.string(), - duration: z.number() - }), - execute: async ({ title, date, duration }) => { - // Your calendar API integration - return { eventId: "cal_123", message: "Event created" } - } -} - -export async function POST(request: Request) { - const { messages } = await request.json() - - const result = await streamText({ - model: openai('gpt-5'), - messages, - tools: { - // Spread Supermemory tools - ...supermemoryTools(process.env.SUPERMEMORY_API_KEY!), - // Add custom tools - createEvent: calendarTool, - }, - system: `You are a personal assistant that can remember information and - manage calendars. When users mention events or appointments: - 1. Remember the details using addMemory - 2. Create calendar events using createEvent - 3. Search for conflicts using searchMemories` - }) - - return result.toAIStreamResponse() -} -``` - -## Environment Setup - -For all examples, ensure you have these environment variables: - -```bash .env.local -SUPERMEMORY_API_KEY=your_supermemory_key -OPENAI_API_KEY=your_openai_key -ANTHROPIC_API_KEY=your_anthropic_key -``` - -## Best Practices - -### Memory Tools -- Use descriptive memory content for better search results -- Include context in your system prompts about when to use each tool -- Use project headers to separate different use cases -- Implement error handling for tool failures - -### General Tips -- Start with simple examples and gradually add complexity -- Use the search functionality to avoid duplicate memories -- Implement proper authentication for production use -- Consider rate limiting for high-volume applications - -## Next Steps - - - - Advanced memory management with full API control - - - - Automatic personalization with user profiles - - diff --git a/apps/docs/ai-sdk/infinite-chat.mdx b/apps/docs/ai-sdk/infinite-chat.mdx deleted file mode 100644 index 4d67a86d..00000000 --- a/apps/docs/ai-sdk/infinite-chat.mdx +++ /dev/null @@ -1,216 +0,0 @@ ---- -title: "Infinite Chat" -description: "Unlimited context for chat applications with automatic memory management" -sidebarTitle: "Infinite Chat" ---- - -Infinite Chat provides unlimited context for chat applications with automatic memory management. - -## Setup - -```typescript -import { streamText } from "ai" - -const infiniteChat = createAnthropic({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.anthropic.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) - -const result = await streamText({ - model: infiniteChat("claude-3-sonnet"), - messages: [ - { role: "user", content: "Hello! Remember that I love TypeScript." } - ] -}) -``` - -## Provider Configuration - -### Named Providers - - - -```typescript OpenAI -const infiniteChat = createOpenAI({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.openai.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) - -const result = await streamText({ - model: infiniteChat("gpt-5"), - messages: [...] -}) -``` - -```typescript Anthropic -const infiniteChat = createAnthropic({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.anthropic.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) - -const result = await streamText({ - model: infiniteChat("claude-3-sonnet"), - messages: [...] -}) -``` - -```typescript Google -const infiniteChat = createGoogleGenerativeAI({ - baseUrl: 'https://api.supermemory.ai/v3/https://generativelanguage.googleapis.com/v1beta', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) - -const result = await streamText({ - model: infiniteChat("gemini-pro"), - messages: [...] -}) -``` - -```typescript Groq -const infiniteChat = createGroq({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.groq.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) - -const result = await streamText({ - model: infiniteChat("mixtral-8x7b"), - messages: [...] -}) -``` - - - -### Custom Provider URL - -```typescript -const infiniteChat = createOpenAI({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.openai.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) -``` - -## Example Usage - -```typescript -import { streamText } from "ai" - -const infiniteChat = createOpenAI({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.openai.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) - -const result = await streamText({ - model: infiniteChat("gpt-5"), - messages: [ - { role: "user", content: "What did we discuss yesterday?" } - ] -}) - -return result.toAIStreamResponse() -``` - -## Configuration Options - -```typescript -interface ConfigWithProviderName { - providerName: 'openai' | 'anthropic' | 'openrouter' | - 'deepinfra' | 'groq' | 'google' | 'cloudflare' - providerApiKey: string - headers?: Record -} - -interface ConfigWithProviderUrl { - providerUrl: string - providerApiKey: string - headers?: Record -} -``` - -### Custom Headers - -Add user IDs, conversation IDs, or other metadata: - -```typescript -const infiniteChat = createOpenAI({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.openai.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) -``` - -## Comparison with Memory Tools - -| Feature | Infinite Chat | Memory Tools | -|---------|--------------|--------------| -| Memory Management | Automatic | Manual | -| Context Handling | Automatic | Manual | -| Tool Calls | None | searchMemories, addMemory, fetchMemory | -| Best For | Chat apps | AI agents | -| Setup Complexity | Simple | Moderate | - -## Headers - -Add user and conversation context: - -```typescript -const infiniteChat = createOpenAI({ - baseUrl: 'https://api.supermemory.ai/v3/https://api.openai.com/v1', - apiKey: 'your-provider-api-key', - headers: { - 'x-supermemory-api-key': 'supermemory-api-key', - 'x-sm-conversation-id': 'conversation-id' - } -}) -``` - -## Comparison - -| Feature | Infinite Chat | Memory Tools | -|---------|--------------|-------------| -| Memory Management | Automatic | Manual | -| Context Handling | Automatic | Manual | -| Tool Calls | None | searchMemories, addMemory, fetchMemory | -| Best For | Chat apps | AI agents | - -## Next Steps - - - - Explore explicit memory control - - - - See complete implementations - - diff --git a/apps/docs/ai-sdk/memory-tools.mdx b/apps/docs/ai-sdk/memory-tools.mdx deleted file mode 100644 index f48d04f7..00000000 --- a/apps/docs/ai-sdk/memory-tools.mdx +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: "Memory Tools" -description: "Add memory capabilities to your AI agents with Vercel AI SDK tools" -sidebarTitle: "Memory Tools" ---- - -Memory tools allow AI agents to search, add, and fetch memories. - -## Setup - -```typescript -import { streamText } from "ai" -import { createOpenAI } from "@ai-sdk/openai" -import { supermemoryTools } from "@supermemory/tools/ai-sdk" - -const openai = createOpenAI({ - apiKey: "YOUR_OPENAI_KEY" -}) - -const result = await streamText({ - model: openai("gpt-5"), - prompt: "Remember that my name is Alice", - tools: supermemoryTools("YOUR_SUPERMEMORY_KEY") -}) -``` - -## Available Tools - -### Search Memories - -Semantic search through user memories: - -```typescript -const result = await streamText({ - model: openai("gpt-5"), - prompt: "What are my dietary preferences?", - tools: supermemoryTools("API_KEY") -}) - -// The AI will automatically call searchMemories tool -// Example tool call: -// searchMemories({ informationToGet: "dietary preferences and restrictions" }) -``` - -### Add Memory - -Store new information: - -```typescript -const result = await streamText({ - model: anthropic("claude-3-sonnet"), - prompt: "Remember that I'm allergic to peanuts", - tools: supermemoryTools("API_KEY") -}) - -// The AI will automatically call addMemory tool -// Example tool call: -// addMemory({ memory: "User is allergic to peanuts" }) -``` - -### Fetch Memory - -Retrieve specific memory by ID: - -```typescript -const result = await streamText({ - model: openai("gpt-5"), - prompt: "Get the details of memory abc123", - tools: supermemoryTools("API_KEY") -}) - -// The AI will automatically call fetchMemory tool -// Example tool call: -// fetchMemory({ memoryId: "abc123" }) -``` - -## Using Individual Tools - -For more control, import tools separately: - -```typescript -import { - searchMemoriesTool, - addMemoryTool, - fetchMemoryTool -} from "@supermemory/tools/ai-sdk" - -// Use only search tool -const result = await streamText({ - model: openai("gpt-5"), - prompt: "What do you know about me?", - tools: { - searchMemories: searchMemoriesTool("API_KEY", { - projectId: "personal" - }) - } -}) - -// Combine with custom tools -const result = await streamText({ - model: anthropic("claude-3"), - prompt: "Help me with my calendar", - tools: { - searchMemories: searchMemoriesTool("API_KEY"), - // Your custom tools - createEvent: yourCustomTool, - sendEmail: anotherCustomTool - } -}) -``` - -## Tool Results - -Each tool returns a result object: - -```typescript -// searchMemories result -{ - success: true, - results: [...], // Array of memories - count: 5 -} - -// addMemory result -{ - success: true, - memory: { id: "mem_123", ... } -} - -// fetchMemory result -{ - success: true, - memory: { id: "mem_123", content: "...", ... } -} -``` - -## Next Steps - - - - Automatic personalization with profiles - - - - See more complete examples - - diff --git a/apps/docs/ai-sdk/npm.mdx b/apps/docs/ai-sdk/npm.mdx deleted file mode 100644 index 88ced6c2..00000000 --- a/apps/docs/ai-sdk/npm.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "NPM link" -url: "https://www.npmjs.com/package/@supermemory/tools" -icon: npm ---- diff --git a/apps/docs/ai-sdk/overview.mdx b/apps/docs/ai-sdk/overview.mdx deleted file mode 100644 index b4d6aad9..00000000 --- a/apps/docs/ai-sdk/overview.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: "AI SDK Integration" -description: "Use Supermemory with Vercel AI SDK for seamless memory management" -sidebarTitle: "Overview" ---- - -The Supermemory AI SDK provides native integration with Vercel's AI SDK through two approaches: **User Profiles** for automatic personalization and **Memory Tools** for agent-based interactions. - - - Check out the NPM page for more details - - -## Installation - -```bash -npm install @supermemory/tools -``` - -## User Profiles with Middleware - -Automatically inject user profiles into every LLM call for instant personalization. Customize how memories are formatted with the `promptTemplate` option for XML-based prompting, custom branding, or model-specific formatting. - -```typescript -import { generateText } from "ai" -import { withSupermemory } from "@supermemory/tools/ai-sdk" -import { openai } from "@ai-sdk/openai" - -// Wrap your model with Supermemory - profiles are automatically injected -const modelWithMemory = withSupermemory(openai("gpt-5"), { - containerTag: "user-123", - customId: "conversation-456", -}) - -const result = await generateText({ - model: modelWithMemory, - messages: [{ role: "user", content: "What do you know about me?" }] -}) -// The model automatically has the user's profile context! -``` - - - **Memory saving is enabled by default** (`addMemory: "always"`). New conversations are persisted automatically. To opt out, set `addMemory: "never"`: - - ```typescript - const modelWithMemory = withSupermemory(openai("gpt-5"), { - containerTag: "user-123", - customId: "conversation-456", - addMemory: "never", - }) - ``` - - -```typescript -``` - -## Memory Tools - -Add memory capabilities to AI agents with search, add, and fetch operations. - -```typescript -import { streamText } from "ai" -import { createAnthropic } from "@ai-sdk/anthropic" -import { supermemoryTools } from "@supermemory/tools/ai-sdk" - -const anthropic = createAnthropic({ - apiKey: "YOUR_ANTHROPIC_KEY" -}) - -const result = await streamText({ - model: anthropic("claude-3-sonnet"), - prompt: "Remember that my name is Alice", - tools: supermemoryTools("YOUR_SUPERMEMORY_KEY") -}) -``` - -## When to Use - -| Approach | Use Case | -|----------|----------| -| User Profiles | Personalized LLM responses with automatic user context | -| Memory Tools | AI agents that need explicit memory control | - -## Next Steps - - - - Automatic personalization with profiles - - - - Agent-based memory management - - diff --git a/apps/docs/ai-sdk/user-profiles.mdx b/apps/docs/ai-sdk/user-profiles.mdx deleted file mode 100644 index c0027aa2..00000000 --- a/apps/docs/ai-sdk/user-profiles.mdx +++ /dev/null @@ -1,357 +0,0 @@ ---- -title: "User Profiles with AI SDK" -description: "Automatically inject user profiles into LLM calls for instant personalization" -sidebarTitle: "User Profiles" ---- - -## Overview - -The `withSupermemory` middleware automatically injects user profiles into your LLM calls, providing instant personalization without manual prompt engineering or API calls. - - - **New to User Profiles?** Read the [conceptual overview](/user-profiles) to understand what profiles are and why they're powerful for LLM personalization. - - -## Quick Start - -```typescript -import { generateText } from "ai" -import { withSupermemory } from "@supermemory/tools/ai-sdk" -import { openai } from "@ai-sdk/openai" - -// Wrap any model with Supermemory middleware -const modelWithMemory = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conversation-456", -}) - -// Use normally - profiles are automatically injected! -const result = await generateText({ - model: modelWithMemory, - messages: [{ role: "user", content: "Help me with my current project" }] -}) - -// The model knows about the user's background, skills, and current work! -``` - -## How It Works - -The `withSupermemory` middleware: - -1. **Intercepts** your LLM calls before they reach the model -2. **Fetches** the user's profile based on the container tag -3. **Injects** profile data into the system prompt automatically -4. **Forwards** the enhanced prompt to your LLM - -All of this happens transparently - you write code as if using a normal model, but get personalized responses. - - - **Memory saving is enabled by default** (`addMemory: "always"`). New conversations are persisted automatically. To opt out, set `addMemory: "never"`: - - ```typescript - const model = withSupermemory(openai("gpt-5"), { - containerTag: "user-123", - customId: "conversation-456", - addMemory: "never", - }) - ``` - - -## Memory Search Modes - -Configure how the middleware retrieves and uses memory: - -### Profile Mode (Default) - -Retrieves the user's complete profile without query-specific search. Best for general personalization. - -```typescript -// Default behavior - profile mode -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", -}) - -// Or explicitly specify -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - mode: "profile", -}) - -const result = await generateText({ - model, - messages: [{ role: "user", content: "What do you know about me?" }] -}) -// Response uses full user profile for context -``` - -### Query Mode - -Searches memories based on the user's specific message. Best for finding relevant information. - -```typescript -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - mode: "query", -}) - -const result = await generateText({ - model, - messages: [{ - role: "user", - content: "What was that Python script I wrote last week?" - }] -}) -// Searches for memories about Python scripts from last week -``` - -### Full Mode - -Combines profile AND query-based search for comprehensive context. Best for complex interactions. - -```typescript -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - mode: "full", -}) - -const result = await generateText({ - model, - messages: [{ - role: "user", - content: "Help me debug this similar to what we did before" - }] -}) -// Uses both profile (user's expertise) AND search (previous debugging sessions) -``` - -## Custom Prompt Templates - -Customize how memories are formatted and injected into the system prompt using the `promptTemplate` option. This is useful for: -- Using XML-based prompting (e.g., for Claude models) -- Custom branding (removing "supermemories" references) -- Controlling how your agent describes where information comes from - -```typescript -import { generateText } from "ai" -import { withSupermemory, type MemoryPromptData } from "@supermemory/tools/ai-sdk" -import { openai } from "@ai-sdk/openai" - -const customPrompt = (data: MemoryPromptData) => ` - -Here is some information about your past conversations with the user: -${data.userMemories} -${data.generalSearchMemories} - -`.trim() - -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - mode: "full", - promptTemplate: customPrompt, -}) - -const result = await generateText({ - model, - messages: [{ role: "user", content: "What do you know about me?" }] -}) -``` - -### MemoryPromptData Interface - -The `MemoryPromptData` object passed to your template function provides: - -- `userMemories`: Pre-formatted markdown combining static profile facts (name, preferences, goals) and dynamic context (current projects, recent interests) -- `generalSearchMemories`: Pre-formatted search results based on semantic similarity to the current query (empty string if mode is "profile") -- `searchResults`: Raw search results array (`Array<{ memory: string; metadata?: Record }>`) for traversing, filtering, or selectively including results based on metadata - -### XML-Based Prompting for Claude - -Claude models perform better with XML-structured prompts: - -```typescript -const claudePrompt = (data: MemoryPromptData) => ` - - - ${data.userMemories} - - - ${data.generalSearchMemories} - - - -Use the above context to provide personalized responses. -`.trim() - -const model = withSupermemory(anthropic("claude-3-sonnet"), { - containerTag: "user-123", - customId: "conv-1", - mode: "full", - promptTemplate: claudePrompt, -}) -``` - -### Filtering Search Results - -Use `searchResults` to traverse the raw data and pick what's important: - -```typescript -const selectivePrompt = (data: MemoryPromptData) => { - const relevant = data.searchResults.filter( - (r) => (r.metadata?.score as number) > 0.7 - ) - return ` - -${data.userMemories} - - -${relevant.map((r) => `- ${r.memory}`).join("\n")} - -`.trim() -} - -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - mode: "full", - promptTemplate: selectivePrompt, -}) -``` - -### Custom Branding - -Remove "supermemories" references and use your own branding: - -```typescript -const brandedPrompt = (data: MemoryPromptData) => ` -You are an AI assistant with access to the user's personal knowledge base. - -User Profile: -${data.userMemories} - -Relevant Context: -${data.generalSearchMemories} - -Use this information to provide personalized and contextually relevant responses. -`.trim() - -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - promptTemplate: brandedPrompt, -}) -``` - -### Default Template - -If no `promptTemplate` is provided, the default format is used: - -```typescript -const defaultPrompt = (data: MemoryPromptData) => - `User Supermemories: \n${data.userMemories}\n${data.generalSearchMemories}`.trim() -``` - -## Verbose Logging - -Enable detailed logging to see exactly what's happening: - -```typescript -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - verbose: true, // Enable detailed logging -}) - -const result = await generateText({ - model, - messages: [{ role: "user", content: "Where do I live?" }] -}) - -// Console output: -// [supermemory] Searching memories for container: user-123 -// [supermemory] User message: Where do I live? -// [supermemory] System prompt exists: false -// [supermemory] Found 3 memories -// [supermemory] Memory content: You live in San Francisco, California... -// [supermemory] Creating new system prompt with memories -``` - -## Comparison with Direct API - -The AI SDK middleware abstracts away the complexity of manual profile management: - - - - ```typescript - // Simple setup - const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", - }) - - // Use normally - const result = await generateText({ - model, - messages: [{ role: "user", content: "Help me" }] - }) - ``` - - - - ```typescript - // Manual profile fetching - const profileRes = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { /* ... */ }, - body: JSON.stringify({ containerTag: "user-123" }) - }) - const profile = await profileRes.json() - - // Manual prompt construction - const systemPrompt = `User Profile:\n${profile.profile.static?.join('\n')}` - - // Manual LLM call with profile - const result = await generateText({ - model: openai("gpt-4"), - messages: [ - { role: "system", content: systemPrompt }, - { role: "user", content: "Help me" } - ] - }) - ``` - - - -## Limitations - -- **Beta Feature**: The `withSupermemory` middleware is currently in beta -- **Container Tag Required**: You must provide a valid container tag -- **API Key Required**: Ensure `SUPERMEMORY_API_KEY` is set in your environment - -## Next Steps - - - - Understand how profiles work conceptually - - - - Add explicit memory operations to your agents - - - - Explore the underlying profile API - - - - View the package on NPM - - - - - **Pro Tip**: Start with profile mode for general personalization, then experiment with query and full modes as you understand your use case better. - diff --git a/apps/docs/api-reference/connections.mdx b/apps/docs/api-reference/connections.mdx new file mode 100644 index 00000000..47a606cf --- /dev/null +++ b/apps/docs/api-reference/connections.mdx @@ -0,0 +1,17 @@ +--- +title: "Connections" +sidebarTitle: "Overview" +description: "External connectors — create, configure, sync, and manage resources." +icon: "book-open" +--- + +Connections pull content from Notion, Google Drive, Gmail, OneDrive, S3, GitHub, and more. + +| Area | Endpoints | +| --- | --- | +| Create / delete | `POST/DELETE /v3/connections/{provider}` | +| List / get | `POST /v3/connections/list`, `GET …/{connectionId}` | +| Configure / resources | `POST …/configure`, `GET …/resources` | +| Sync / documents | `POST …/import`, `POST …/documents` | + +**Guides:** [Connectors overview](/connectors/overview) · provider pages under Connectors diff --git a/apps/docs/api-reference/container-tags.mdx b/apps/docs/api-reference/container-tags.mdx new file mode 100644 index 00000000..ce8c6f28 --- /dev/null +++ b/apps/docs/api-reference/container-tags.mdx @@ -0,0 +1,18 @@ +--- +title: "Container tags" +sidebarTitle: "Overview" +description: "Multi-tenant containers — settings, merge, and delete." +icon: "book-open" +--- + +`containerTag` is the primary multi-tenant key (user id, workspace id, etc.). These endpoints manage settings and lifecycle for a tag. + +| Endpoint | Use when | +| --- | --- | +| `GET /v3/container-tags/{containerTag}` | Read tag settings | +| `PATCH /v3/container-tags/{containerTag}` | Update tag settings | +| `DELETE /v3/container-tags/{containerTag}` | Delete a container and its data | +| `POST /v3/container-tags/merge` | Merge one tag into another | +| `GET /v3/container-tags/merge/{mergeId}` | Poll merge status | + +**Guide:** [Container tags](/concepts/container-tags) · [Filtering](/concepts/filtering) diff --git a/apps/docs/api-reference/documents.mdx b/apps/docs/api-reference/documents.mdx new file mode 100644 index 00000000..5f3d0441 --- /dev/null +++ b/apps/docs/api-reference/documents.mdx @@ -0,0 +1,21 @@ +--- +title: "Documents" +sidebarTitle: "Overview" +description: "List, get status, update, delete, and inspect ingested documents." +icon: "book-open" +--- + +Documents are the unit of ingestion. Adds return immediately with `status: "queued"`; poll until `done` before relying on search or profiles. + +| Endpoint | Use when | +| --- | --- | +| `GET /v3/documents/{id}` | Status + metadata for one document | +| `POST /v3/documents/list` | Filter and paginate documents | +| `GET /v3/documents/processing` | Currently processing items | +| `PATCH /v3/documents/{id}` | Update content or metadata | +| `DELETE /v3/documents/{id}` | Delete by id or customId | +| `DELETE /v3/documents/bulk` | Bulk delete | +| `GET /v3/documents/{id}/chunks` | Inspect RAG chunks | +| `GET /v3/documents/{id}/file-url` | Presigned URL for uploaded files | + +**Guide:** [Document operations](/ingestion/document-operations) diff --git a/apps/docs/api-reference/ingest.mdx b/apps/docs/api-reference/ingest.mdx new file mode 100644 index 00000000..6159cc11 --- /dev/null +++ b/apps/docs/api-reference/ingest.mdx @@ -0,0 +1,21 @@ +--- +title: "Ingest" +sidebarTitle: "Overview" +description: "Add documents, files, batches, and conversations to Supermemory." +icon: "book-open" +--- + +Send raw content into the processing pipeline. Supermemory extracts memories, chunks for RAG, and updates profiles asynchronously. + +| Endpoint | Use when | +| --- | --- | +| `POST /v3/documents` | Text, URLs, or structured content | +| `POST /v3/documents/file` | Binary file upload | +| `POST /v3/documents/batch` | Many documents in one request | +| `POST /v4/conversations` | Chat sessions with turn-aware ingest | + +**Guides:** [Add memories](/ingestion/add-memories) · [Quickstart](/quickstart) + + +Use a stable `customId` (conversation id, doc id) so re-sends upsert instead of duplicating. Pass `dreaming: "instant"` when the next step is memory search or profiles. + diff --git a/apps/docs/api-reference/memories.mdx b/apps/docs/api-reference/memories.mdx new file mode 100644 index 00000000..bbe47ff5 --- /dev/null +++ b/apps/docs/api-reference/memories.mdx @@ -0,0 +1,20 @@ +--- +title: "Memories" +sidebarTitle: "Overview" +description: "Create, list, update, and forget extracted memory entries (v4)." +icon: "book-open" +--- + +These endpoints operate on **extracted memories**, not raw documents. + +| Endpoint | Use when | +| --- | --- | +| `POST /v4/memories` | Write memories directly (skip document pipeline) | +| `POST /v4/memories/list` | List with history / versions | +| `PATCH /v4/memories` | Update (creates a new version) | +| `DELETE /v4/memories` | Forget a specific memory | +| `POST /v4/memories/forget-matching` | Forget by natural-language match | + +For document-level CRUD, use [Documents](/api-reference/documents). For pipeline ingest, use [Ingest](/api-reference/ingest). + +**Guide:** [Memory operations](/recall/memory-operations) diff --git a/apps/docs/api-reference/overview.mdx b/apps/docs/api-reference/overview.mdx new file mode 100644 index 00000000..776eb5fc --- /dev/null +++ b/apps/docs/api-reference/overview.mdx @@ -0,0 +1,68 @@ +--- +title: "API Reference" +description: "Interactive reference for the Supermemory HTTP API — ingest, search, profiles, memories, connectors, and settings." +icon: "unplug" +--- + +This is the **contract-level** reference for Supermemory: methods, paths, parameters, and the playground. + +For narrative guides (when to use what, patterns, SDKs), start with the [Quickstart](/quickstart) and [Using supermemory](/ingestion/add-memories). + +## Base URL + +``` +https://api.supermemory.ai +``` + +Self-hosted: use your instance URL (for example `http://localhost:6767`). See [Self-hosting](/self-hosting/overview). + +## Authentication + +All endpoints use a Bearer API key. Create one in the [developer console](https://console.supermemory.ai). + +```bash +Authorization: Bearer sm_... +``` + +Details: [API keys & auth](/authentication). + +## Mental model + +| Group | What it does | +| --- | --- | +| **Ingest** | Add documents, files, batches, and conversations into the pipeline | +| **Documents** | Get status, list, update, delete, chunks, and file URLs | +| **Search** | Semantic recall — memories, documents, or hybrid | +| **Profiles** | Static + dynamic facts for a container (user / entity) | +| **Memories** | Create, list, update, and forget extracted memory entries | +| **Container tags** | Multi-tenant settings, merge, and delete for a container | +| **Connections** | OAuth connectors (Drive, Notion, Gmail, …) and sync | +| **Settings** | Org-level customization, buckets, and reset | + +Same `containerTag` scopes ingest, search, and profiles — one engine, multiple ways out. + +## Suggested order + +1. **Ingest** — `POST /v3/documents` (SDK: `client.add`) +2. **Documents** — `GET /v3/documents/{id}` until `status: "done"` +3. **Search** — `POST /v4/search` +4. **Profiles** — `POST /v4/profile` + +Full walkthrough with conversation + document examples: [Quickstart](/quickstart). + +## SDKs + +Official clients wrap this API: + +- TypeScript: `npm install supermemory` +- Python: `pip install supermemory` + +See [Supermemory SDK](/integrations/supermemory-sdk). + +Playground snippets come from the OpenAPI spec: official **TypeScript / Python SDK** samples via `x-codeSamples`, plus cURL. (After API deploy — until then you may still see generic HTTP snippets.) + +SDK generation is migrating off Stainless SaaS to **stlc** soon; documented OpenAPI samples will then be produced by the SDK build instead of a hand-maintained map. + +## OpenAPI + +Spec (live): [https://api.supermemory.ai/v3/openapi](https://api.supermemory.ai/v3/openapi) diff --git a/apps/docs/api-reference/profiles.mdx b/apps/docs/api-reference/profiles.mdx new file mode 100644 index 00000000..9410bec5 --- /dev/null +++ b/apps/docs/api-reference/profiles.mdx @@ -0,0 +1,15 @@ +--- +title: "Profiles" +sidebarTitle: "Profiles overview" +description: "Entity profiles — static and dynamic facts for a container." +icon: "id-card" +--- + +Profiles summarize what Supermemory knows about a user or entity in a `containerTag`. + +| Endpoint | Use when | +| --- | --- | +| `POST /v4/profile` | Fetch static + dynamic profile for a container | +| `POST /v4/profile/buckets` | Profile organized by custom buckets | + +**Guides:** [User profiles API](/recall/user-profiles) · [Concepts](/concepts/user-profiles) · [Buckets](/user-profiles/buckets) diff --git a/apps/docs/api-reference/search.mdx b/apps/docs/api-reference/search.mdx new file mode 100644 index 00000000..03fb068d --- /dev/null +++ b/apps/docs/api-reference/search.mdx @@ -0,0 +1,19 @@ +--- +title: "Recall" +sidebarTitle: "Overview" +description: "Semantic search over memories, document chunks, or both — plus user profiles." +icon: "book-open" +--- + +Get context back out of Supermemory: search extracted memories / documents, or fetch a user profile. + +| Endpoint | Role | +| --- | --- | +| `POST /v4/search` | Primary recall — `searchMode`: `memories`, `documents`, or `hybrid` | +| `POST /v3/search` | Document / SuperRAG-oriented search | +| `POST /v4/profile` | Static + dynamic profile for a container | +| `POST /v4/profile/buckets` | Profile organized by custom buckets | + +Prefer **v4** with `searchMode: "hybrid"` unless you only need document chunks or only extracted memories. + +**Guides:** [Search](/recall/search) · [User profiles](/recall/user-profiles) · [SuperRAG](/concepts/super-rag) · [Memory vs RAG](/concepts/memory-vs-rag) diff --git a/apps/docs/api-reference/settings.mdx b/apps/docs/api-reference/settings.mdx new file mode 100644 index 00000000..6c3308b0 --- /dev/null +++ b/apps/docs/api-reference/settings.mdx @@ -0,0 +1,17 @@ +--- +title: "Settings" +sidebarTitle: "Overview" +description: "Organization settings, profile buckets, and data reset." +icon: "book-open" +--- + +Org-level configuration for extraction, customization, and profile buckets. + +| Endpoint | Use when | +| --- | --- | +| `GET /v3/settings` | Read org settings | +| `PATCH /v3/settings` | Update org settings | +| `POST /v3/settings/suggest-buckets` | Suggest profile buckets | +| `POST /v3/settings/reset` | Reset organization data (destructive) | + +**Guide:** [Customization](/concepts/customization) diff --git a/apps/docs/authentication.mdx b/apps/docs/authentication.mdx index 0046ef93..d0cf4274 100644 --- a/apps/docs/authentication.mdx +++ b/apps/docs/authentication.mdx @@ -1,6 +1,7 @@ --- -title: "Authentication" -description: "API keys, scoped keys, and connector branding." +title: "API keys & auth" +description: "Org API keys, container-scoped keys, and connector branding." +sidebarTitle: "API keys" icon: "key" --- @@ -55,65 +56,65 @@ This works for Google Drive, Notion, and OneDrive. See the full setup in [Custom --- -## Scoped API Keys +## Scoped API keys - - Scoped keys are restricted to a single `containerTag`. They can only access documents and search within that container — useful for giving limited access to specific projects, users, or tenants without exposing your full API key. +Scoped keys are restricted to one or more `containerTag`s. They can only access documents and search within those containers — use them to give a client, session, or tenant limited access without shipping your org master key. - **Allowed endpoints:** `/v3/documents`, `/v3/memories`, `/v4/memories`, `/v3/search`, `/v4/search`, `/v4/profile` +Pairs with [container tags](/concepts/container-tags) for multi-tenant isolation. - ### Create a scoped key +**Allowed endpoints:** `/v3/documents`, `/v3/memories`, `/v4/memories`, `/v3/search`, `/v4/search`, `/v4/profile` - ```bash - curl https://api.supermemory.ai/v3/auth/scoped-key \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer YOUR_API_KEY' \ - -d '{ - "containerTag": "my-project", - "name": "my-key-name", - "expiresInDays": 30 - }' - ``` +Scoped keys **cannot** read billing, manage org settings, or mint further keys. - ### Parameters +### Create a scoped key - | Parameter | Required | Default | Description | - | --------------------- | -------- | ----------------------- | ------------------------------------------------ | - | `containerTag` | Yes | — | Alphanumeric, hyphens, underscores, colons, dots | - | `name` | No | `scoped_{containerTag}` | Display name for the key | - | `expiresInDays` | No | — | 1–365 days | - | `rateLimitMax` | No | `500` | Max requests per window (1–10,000) | - | `rateLimitTimeWindow` | No | `60000` | Window in milliseconds (1–3,600,000) | - - ### Response - - ```json - { - "key": "sm_orgId_...", - "id": "key-id", - "name": "scoped_my-project", +```bash +curl https://api.supermemory.ai/v3/auth/scoped-key \ + --request POST \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Bearer YOUR_API_KEY' \ + -d '{ "containerTag": "my-project", - "expiresAt": "2026-03-08T00:00:00.000Z", - "allowedEndpoints": ["/v3/documents", "/v3/memories", "/v4/memories", "/v3/search", "/v4/search", "/v4/profile"] - } - ``` + "name": "my-key-name", + "expiresInDays": 30 + }' +``` - Use the returned key exactly like a normal API key — it just won't work outside its container scope. +### Parameters - ### Disable a scoped key +| Parameter | Required | Default | Description | +| --- | --- | --- | --- | +| `containerTag` | Yes | — | Alphanumeric, hyphens, underscores, colons, dots | +| `name` | No | `scoped_{containerTag}` | Display name for the key | +| `expiresInDays` | No | — | 1–365 days | +| `rateLimitMax` | No | `500` | Max requests per window (1–10,000) | +| `rateLimitTimeWindow` | No | `60000` | Window in milliseconds (1–3,600,000) | - To revoke a scoped key, send a `DELETE` request with the `id` returned at creation time. This disables the key immediately — any subsequent requests using it will get a `401`. Memories and container tags are **not** affected. +### Response - ```bash - curl https://api.supermemory.ai/v3/auth/scoped-key/KEY_ID \ - --request DELETE \ - --header 'Authorization: Bearer YOUR_API_KEY' - ``` +```json +{ + "key": "sm_orgId_...", + "id": "key-id", + "name": "scoped_my-project", + "containerTag": "my-project", + "expiresAt": "2026-03-08T00:00:00.000Z", + "allowedEndpoints": ["/v3/documents", "/v3/memories", "/v4/memories", "/v3/search", "/v4/search", "/v4/profile"] +} +``` - **Response:** +Use the returned key like a normal API key — it just will not work outside its container scope. - ```json - { "success": true } - ``` - \ No newline at end of file +### Disable a scoped key + +Revoke with the `id` from creation. Subsequent requests get `401`. Memories and container tags are **not** deleted. + +```bash +curl https://api.supermemory.ai/v3/auth/scoped-key/KEY_ID \ + --request DELETE \ + --header 'Authorization: Bearer YOUR_API_KEY' +``` + +```json +{ "success": true } +``` \ No newline at end of file diff --git a/apps/docs/changelog/developer-platform.mdx b/apps/docs/changelog/developer-platform.mdx deleted file mode 100644 index eef2ce83..00000000 --- a/apps/docs/changelog/developer-platform.mdx +++ /dev/null @@ -1,212 +0,0 @@ ---- -title: "Developer Platform" -description: "API updates, new endpoints, and SDK releases" ---- - - -API updates, new endpoints, SDK releases, and developer-focused features. - -## April 13, 2026 - -- **Google Drive scoped sync:** New connections default to a **hosted folder/file picker** after OAuth; only chosen items sync. Use `metadata.syncScope: "full"` to sync the whole Drive. Import jobs **skip** scoped connections until a selection exists. - -## March 18, 2026 - -- **Supermemory CLI:** New command-line tool for managing memories, documents, profiles, tags, connectors, and API keys directly from the terminal. -- **PPTX Support:** PowerPoint files (`.pptx`) are now a supported content type for ingestion. -- **Multiple containerTags on Scoped API Keys:** Scoped API keys can now be assigned to multiple container tags, allowing a single key to access several spaces. -- **Documents Page in Console:** New dedicated documents browser in the console for viewing, filtering, and managing all ingested content. -- **`@supermemory/tools` v1.4.1:** Now exposes raw `searchResults` in `MemoryPromptData`, giving full control over how retrieved memories are formatted in prompts. - -## March 12, 2026 - -- **Audio Extraction:** Ingest audio files with automatic transcription powered by Gemini 2.5 Flash. Audio content is transcribed, chunked, and indexed like any other document. -- **Delete Connection Without Documents:** Disconnect an external source (Google Drive, Notion, etc.) without deleting the documents it synced. -- **Org-Level Overage Toggle:** Control overage billing per-organization with a new toggle in the billing settings. -- **Retry Failed Documents:** Documents that previously failed ingestion can now be retried by re-submitting with the same `customId`. -- **Copyable Team Invite Link:** Team management page now includes a shareable invite link. - -## March 9, 2026 - -- **Delete Scoped API Keys:** New `DELETE` endpoint to disable scoped API keys programmatically. -- **`supermemory-agent-framework` Python Package:** Official Python package for using Supermemory with Microsoft's Agent Framework — memory tools and middleware out of the box. -- **OpenAI SDK Backfill:** Improved compatibility across `supermemory-openai-sdk` (Python) and `@supermemory/tools` (TypeScript) OpenAI integrations. -- **Bulk Delete in Nova:** Bulk document deletion now available in the Nova app interface. - -## March 5, 2026 - -- **`extends` Relation Type:** Memory graph now supports `extends` as a relation type, enabling richer knowledge graph connections between documents. -- **Interactive Memory Graph in MCP:** The MCP server now includes an interactive graph visualization app for exploring memory connections from any MCP-compatible client. -- **Plugin Auth Connect Page:** New OAuth-style connect page for plugin integrations (Claude Code, OpenCode, OpenClaw). -- **ViaSocket Integration:** New integration guide for connecting Supermemory with ViaSocket automation workflows. - -## March 2, 2026 - -- **Configurable Vector Stores:** Bring your own vector store — Supermemory now supports pluggable vector backends beyond the default. -- **List Memories Endpoint:** New `GET /v3/documents` endpoint with pagination, filtering by container tag, status, and metadata. - -## February 26, 2026 - -- **Self-Hostable Supermemory:** Run the full Supermemory stack on your own infrastructure with Docker. -- **Console v2:** Complete redesign of the developer console with new navigation, improved billing, and a unified project view. -- **No More 120 Memory Limit:** The previous cap of 120 memories per container tag has been removed. Store unlimited memories. - -## February 22, 2026 - -- **Supermemory Skill for Claude Code:** Install with `npx skills add supermemoryai/skills` — teaches Claude to proactively recommend and implement Supermemory when building AI apps that need persistent memory, user profiles, or semantic search. Includes ready-to-use TypeScript and Python examples. -- **Metadata Filtering for Profiles:** User profile search now supports metadata-based filtering for more targeted profile queries. -- **List Documents with Multiple Container Tags:** New `operator` parameter to query documents spanning multiple container tags. -- **Deprecate `include: chunks`:** The `include: chunks` parameter in `/v4/search` is deprecated in favor of the `hybrid` search mode. - -## February 9, 2026 - -- **Unified Organizations:** Consumer and developer organizations merged into a single org type. All orgs can now access both Nova and the developer API. -- **Credits-Based Usage Display:** Billing now shows token usage in a credits-based format. -- **Nova Spaces with Multi-Select:** Spaces in Nova now support multi-select, replacing "All Spaces" with scoped "Nova Spaces." - -## February 6, 2026 - -- **Scoped API Keys for Container Tags:** Create API keys scoped to specific container tags for fine-grained access control per space. -- **DELETE Endpoint for Container Tags:** New endpoint to delete container tags and their associated document relationships. -- **Container Tag-Level Context Prompts:** Set custom context prompts per container tag to control how memories are extracted and summarized within each space. - -## February 3, 2026 - -- **New Integration Docs:** Added guides for LangGraph, OpenAI Agents SDK, CrewAI, Agno, Mastra, and LangChain — covering all major AI agent frameworks. -- **Claude Code Integration:** Official integration page for using Supermemory as persistent memory in Claude Code. -- **Entity Context Documentation:** New docs on how entity extraction and context enrichment work in the memory pipeline. -- **Authentication Docs:** Comprehensive authentication page with code examples for API key auth, OAuth, and scoped keys. - -## January 25, 2026 - -- **Plugin Authentication System:** New auth system for external tool integrations, enabling secure plugin-to-API connections. -- **Enterprise Plan Support:** Enterprise tier now available in the console with dedicated billing and support options. -- **Plugin Catalog:** Dedicated plugin page with auth flows for Claude Code, OpenCode, and OpenClaw integrations. -- **`@supermemory/tools` — Strict Mode:** Strict mode support for OpenAI function calling, ensuring schema-validated tool calls. - -## January 14, 2026 - -- **Hybrid PDF Pipeline:** PDF extraction now uses Mistral OCR 3 with Gemini fallback for significantly improved accuracy on scanned documents and complex layouts. -- **Halfvec Embeddings:** Embedding storage optimized with half-precision vectors, reducing storage costs while maintaining search quality. -- **Spaces Creation with Emoji:** Create and customize spaces with emoji identifiers in Nova. - -## January 8, 2026 - -- **Gmail Connector:** New connector to sync Gmail threads into Supermemory. Threads are stored in R2 for reliable processing of large mailboxes. -- **Container Tag Filters:** Filter documents by container tag in list and search endpoints. -- **Pagination Improvements:** Improved pagination and document view across the console. -- **`supermemory-pipecat` Python Package:** New SDK for integrating Supermemory with Pipecat voice AI pipelines, including Gemini Live speech-to-speech support. -- **`@supermemory/tools` — Prompt Templates:** Customize how memory context is formatted in AI SDK integrations with the new `promptTemplate` option. - -## December 30, 2025 - -- **MCP 4.0:** Major MCP server update with session configuration, project-aware tools on every init, and backward-compatible 3.0 support. Includes the new `context` prompt for automatic user profile injection. -- **S3 Connector:** New connector to sync documents from Amazon S3 buckets, with console UI for bucket configuration. -- **Memory Graph Revamp:** Complete rewrite of `@supermemory/memory-graph` with improved visualization and performance. - -## December 24, 2025 - -- **`@supermemory/tools` — Vercel AI SDK v5/v6:** Now supports both Vercel AI SDK v5 and v6, with automatic version detection. -- **Conversation Support in SDKs:** `supermemory` (TypeScript) and `supermemory-openai-sdk` (Python) now support the conversations API for multi-turn chat with memory. -- **MemoryBench:** New open-source benchmark suite for evaluating memory systems, with documentation and CLI. - -## December 17, 2025 - -- **Hybrid Search Mode:** New `hybrid` search mode in `/v4/search` combining semantic and keyword search for better recall on technical queries. - -## December 9, 2025 - -- **Firecrawl Integration:** Web crawling powered by Firecrawl for more reliable extraction of website content, with fallback support. -- **Custom GitHub Credentials:** Bring your own GitHub OAuth app credentials for the GitHub connector, enabling private repo access. -- **API Key Expiration Emails:** API keys now trigger email notifications before expiration. -- **Connector Sync Logs:** Connection syncs now produce detailed logs visible in the console. - -## December 2, 2025 - -- **Organization Deletion:** Organizations can now be fully deleted from the console, including all associated data. -- **Billing Page Redesign:** New billing layout with invoicing support and improved usage visibility. -- **Console Onboarding Improvements:** Streamlined onboarding flow for new users. - -## December 5, 2025 - -- **`@supermemory/tools` — Browser API Key Support:** `apiKey` can now be passed via options instead of relying on `process.env`, enabling browser-based usage of the tools package. - -## November 17, 2025 - -- **Web Crawler Connector:** New connector to crawl and index entire websites with configurable depth and URL patterns. -- **`@supermemory/memory-graph` Package:** New package for building interactive graph visualizations of memory connections, with a standalone playground. -- **OpenAI Responses API Support:** `@supermemory/tools` OpenAI integration now supports the Responses API. -- **`supermemory-openai-sdk` — Python Middleware:** New `withSupermemory` middleware for the Python OpenAI SDK, enabling transparent memory injection into OpenAI API calls. -- **Browser Extension Webpage Capture:** Chrome extension can now capture full webpage content with markdown conversion, not just bookmarks. -- **Bulk Memory Optimization:** Memory creation now uses bulk inserts for significantly faster batch ingestion. - -## October 27, 2025 - -- **Enhanced Filtering Capabilities:** Major improvements to the search filtering API with new `string_contains` filter type for partial string matching, `ignoreCase` option for case-insensitive string operations, and improved negation support across all filter types including proper numeric equality negation. The implementation also includes enhanced SQL injection protection and wildcard escaping for improved security. - -## September 17, 2025 - -- **Forgotten Memories Search:** New `include.forgottenMemories` parameter in v4 search API allows searching through memories that have been explicitly forgotten or expired. Set to `true` to include forgotten memories in search results, helping recover previously archived information. - -## September 14, 2025 - -- **Enhanced Delete API:** `DELETE /v3/documents/:id` endpoint now supports both internal document ID and customId for flexible document deletion. Developers can now delete documents using the same customId provided during creation, improving API consistency with other endpoints. -- **API Terminology Clarification:** Refined API terminology from "memories" to "documents" for improved developer clarity. New `/v3/documents/*` endpoints provide more intuitive naming while maintaining full backward compatibility via automatic redirects from `/v3/memories/*`. No action required from existing integrations. - -## September 13, 2025 - -- **Documentation v2.0:** Complete rewrite with comprehensive API references, cookbook recipes, and production-ready examples for TypeScript, Python, and cURL -- **AI SDK Integration:** New `@supermemory/tools/ai-sdk` package for native Vercel AI SDK integration with memory tools and infinite chat capabilities -- **Bulk Delete Endpoint:** New `DELETE /v3/documents/bulk` endpoint for efficient memory management - -## September 5, 2025 - -- **Memory Search Endpoint:** New `/v4/search` endpoint optimized for conversational AI and memory retrieval (vs document search) -- **Advanced Memory Management:** Enhanced update/delete operations with better filtering and batch processing capabilities - -## August 30, 2025 - -- **MCP (Model Context Protocol) Server:** Launch of supermemory MCP server for AI model integrations with full project support and auto-detection -- **Enhanced Filtering API:** Improved SQL-based filtering with array_contains, numeric operators, and complex AND/OR logic - -## August 15, 2025 - -- **Memory Router Proxy:** Enhanced proxy functionality for LLM requests with automatic context management and token optimization -- **Search Algorithm Updates:** Configurable similarity thresholds, reranking, and query rewriting for better result quality - -## April 30, 2025 - -- **Comprehensive API Documentation:** New interactive API references with detailed parameter explanations and response schemas -- **Container Tags System:** Enhanced organizational grouping for better memory isolation and user-scoped content -- **Auto Content Type Detection:** Automatic processing of PDFs, images, videos, and web content regardless of URL extensions - -## April 28, 2025 - -- **Google Drive Connector API:** New endpoints for programmatic Google Drive integration and file syncing - -## April 25, 2025 - -- **Search Threshold Controls:** New `documentThreshold` and `chunkThreshold` parameters for fine-tuning search sensitivity -- **Document-Specific Search:** New `docId` parameter to search within specific large documents -- **Enhanced Chunk Control:** `onlyMatchingChunks` parameter for precise result filtering - -## April 24, 2025 - -- **Query Rewriting API:** Automatic query expansion and intent matching for better search results -- **Search Context Options:** New `includeFullDocs` and `includeSummary` parameters for comprehensive document retrieval - -## April 18, 2025 - -- **Enhanced Content Processing:** Improved ingestion pipeline supporting direct URL processing for images, videos, and PDFs -- **Stable Web Ingestion:** More reliable processing of website URLs with better content extraction - -## April 14, 2025 - -- **Team API Endpoints:** New endpoints for team management and permission control -- **Enhanced Analytics API:** Better observability with detailed usage metrics and performance data - -## February 1, 2025 - -- **Multi-Space Search:** Search across multiple container tags simultaneously with array parameter support -- **API Versioning:** Migration to `/v1` endpoints with improved versioning strategy -- **Interactive API Playground:** New testing interface for all endpoints with live examples diff --git a/apps/docs/changelog/overview.mdx b/apps/docs/changelog/overview.mdx deleted file mode 100644 index 77ca603d..00000000 --- a/apps/docs/changelog/overview.mdx +++ /dev/null @@ -1,779 +0,0 @@ ---- -title: "Changelog" -sidebarTitle: "Supermemory" -description: "New updates and improvements to Supermemory" ---- - - - -### Instant dreaming - -New `dreaming` parameter on `POST /v3/documents` and `POST /v3/documents/batch`. Default `"dynamic"` groups related documents together so memories form from coherent, logical units. Set `"dreaming": "instant"` to process a single document on its own — bills one extra operation per document. Omit the parameter and behavior is unchanged. - - - - - -### Google Drive: scoped sync by default - -New Google Drive connections default to **folder and file** scope: after OAuth, users complete a hosted picker; only selected items sync. Set `metadata.syncScope` to `"full"` on connection creation to sync the entire Drive without the picker. Scoped connections without a saved selection are skipped by import jobs until setup is finished. - - - - - -### Supermemory CLI - -New command-line tool for managing memories, documents, profiles, tags, connectors, and API keys directly from the terminal. - -### `@supermemory/tools` v1.4.1 - -Now exposes raw `searchResults` in `MemoryPromptData`, giving full control over how retrieved memories are formatted in prompts. - -### PPTX & Audio Ingestion - -PowerPoint files (`.pptx`) are now a supported content type. Audio files are automatically transcribed via Gemini 2.5 Flash, chunked, and indexed. - -### Multi-containerTag Scoped API Keys - -Scoped API keys can now be assigned to multiple container tags — one key, multiple spaces. - -### Console: Documents Page - -New dedicated documents browser in the console for viewing, filtering, and managing all ingested content. - - - - - -### Delete Scoped API Keys - -New `DELETE` endpoint to disable scoped API keys programmatically. - -### `supermemory-agent-framework` Python Package - -Official Python package for using Supermemory with Microsoft's Agent Framework — memory tools and middleware out of the box. - -### Interactive Memory Graph in MCP - -The MCP server now includes an interactive graph visualization app for exploring memory connections from any MCP-compatible client. - -### More Integrations - -- **ViaSocket** — new integration guide for automation workflows. -- **Plugin Auth Connect Page** — OAuth-style connect page for Claude Code, OpenCode, and OpenClaw. -- **OpenAI SDK Backfill** — improved compatibility across TypeScript and Python SDKs. - -### Other - -- **Retry failed documents** by re-submitting with the same `customId`. -- **Delete connection without documents** — disconnect a source without deleting synced content. -- **Org-level overage toggle** in billing settings. -- **Copyable team invite link** on the team management page. -- **`extends` relation type** in memory graph for richer knowledge graph connections. -- **Bulk delete** in the Nova app interface. - - - - - -### Configurable Vector Stores - -Bring your own vector store — Supermemory now supports pluggable vector backends beyond the default. - -### List Memories Endpoint - -New `GET /v3/documents` endpoint with pagination, filtering by container tag, status, and metadata. - - - - - -### Self-Hostable Supermemory - -Run the full Supermemory stack on your own infrastructure with Docker. - -### Console v2 - -Complete redesign of the developer console with new navigation, improved billing, and a unified project view that merges consumer and developer organizations. - -### No More 120 Memory Limit - -The previous cap of 120 memories per container tag has been removed. Store unlimited memories. - - - - - -### Supermemory Skill for Claude Code - -Install with `npx skills add supermemoryai/skills` — teaches Claude to proactively recommend and implement Supermemory when building AI apps. Includes TypeScript and Python examples. - -### API Improvements - -- **Metadata filtering for profiles** — target profile queries by metadata fields. -- **List documents with multiple container tags** — new `operator` parameter. -- **Deprecate `include: chunks`** in `/v4/search` in favor of the `hybrid` search mode. -- **Content deduplication** in search results to reduce token usage. - - - - - -### Unified Organizations - -Consumer and developer organizations merged into a single org type. All orgs can now access both Nova and the developer API. - -### Credits-Based Usage Display - -Billing now shows token usage in a credits-based format. - -### Nova Spaces with Multi-Select - -Spaces in Nova support multi-select, replacing "All Spaces" with scoped "Nova Spaces." - - - - - -### Scoped API Keys for Container Tags - -Create API keys scoped to specific container tags for fine-grained access control per space. - -### DELETE Endpoint for Container Tags - -New endpoint to delete container tags and their associated document relationships. - -### Container Tag-Level Context Prompts - -Set custom context prompts per container tag to control how memories are extracted and summarized within each space. - - - - - -### New Framework Integration Docs - -Added guides for LangGraph, OpenAI Agents SDK, CrewAI, Agno, Mastra, LangChain, and Claude Code — covering all major AI agent frameworks. - -### Entity Context & Authentication Docs - -New docs on entity extraction, context enrichment, and comprehensive authentication examples (API key, OAuth, scoped keys). - - - - - -### Plugin Authentication System - -New auth system for external tool integrations, enabling secure plugin-to-API connections. Dedicated plugin page with auth flows for Claude Code, OpenCode, and OpenClaw. - -### Enterprise Plan Support - -Enterprise tier now available in the console. - -### `@supermemory/tools` — Strict Mode - -Strict mode support for OpenAI function calling, ensuring schema-validated tool calls. - - - - - -### Hybrid PDF Pipeline - -PDF extraction now uses Mistral OCR 3 with Gemini fallback for significantly improved accuracy on scanned documents and complex layouts. - -### Halfvec Embeddings - -Embedding storage optimized with half-precision vectors, reducing storage costs while maintaining search quality. - -### Spaces Creation with Emoji - -Create and customize spaces with emoji identifiers in Nova. - - - - - -### Gmail Connector - -New connector to sync Gmail threads into Supermemory. Threads are stored in R2 for reliable processing of large mailboxes. - -### `supermemory-pipecat` Python Package - -New SDK for Pipecat voice AI pipelines, including Gemini Live speech-to-speech support. - -### `@supermemory/tools` — Prompt Templates - -Customize how memory context is formatted in AI SDK integrations with the new `promptTemplate` option. - -### Other - -- **Container tag filters** in list and search endpoints. -- **Pagination improvements** across the console. - - - - - -### MCP 4.0 - -Major MCP server update with session configuration, project-aware tools on every init, and backward-compatible 3.0 support. New `context` prompt for automatic user profile injection into AI conversations. - -### S3 Connector - -New connector to sync documents from Amazon S3 buckets, with console UI for bucket configuration. - -### Memory Graph Revamp - -Complete rewrite of `@supermemory/memory-graph` with improved visualization and performance. - - - - - -### `@supermemory/tools` — AI SDK v5/v6 - -Now supports both Vercel AI SDK v5 and v6 with automatic version detection. - -### Conversation Support in SDKs - -`supermemory` (TypeScript) and `supermemory-openai-sdk` (Python) now support the conversations API for multi-turn chat with memory. - -### MemoryBench - -New open-source benchmark suite for evaluating memory systems, with documentation and CLI. - - - - - -### Hybrid Search Mode - -New `hybrid` search mode in `/v4/search` combining semantic and keyword search for better recall on technical queries. - - - - - -### Firecrawl Integration - -Web crawling powered by Firecrawl for more reliable extraction of website content, with fallback support. - -### Custom GitHub Credentials - -Bring your own GitHub OAuth app credentials for the GitHub connector, enabling private repo access. - -### API Key Expiration Emails - -API keys now trigger email notifications before expiration. - -### Connector Sync Logs - -Connection syncs now produce detailed logs visible in the console. - - - - - -### `@supermemory/tools` — Browser API Key Support - -`apiKey` can now be passed via options instead of relying on `process.env`, enabling browser-based usage. - - - - - -### Organization Deletion - -Organizations can now be fully deleted from the console, including all associated data. - -### Billing Page Redesign - -New billing layout with invoicing support and improved usage visibility. - -### Console Onboarding Improvements - -Streamlined onboarding flow for new users. - - - - - -### Web Crawler Connector - -New connector to crawl and index entire websites with configurable depth and URL patterns. - -### `@supermemory/memory-graph` Package - -New package for building interactive graph visualizations of memory connections, with a standalone playground. - -### OpenAI Responses API Support - -`@supermemory/tools` OpenAI integration now supports the Responses API. - -### `supermemory-openai-sdk` — Python Middleware - -New `withSupermemory` middleware for the Python OpenAI SDK, enabling transparent memory injection into OpenAI API calls. - -### Browser Extension Webpage Capture - -Chrome extension can now capture full webpage content with markdown conversion. - -### Bulk Memory Optimization - -Memory creation now uses bulk inserts for significantly faster batch ingestion. - - - - - -### Enhanced Filtering - -New `string_contains` filter type for partial string matching, `ignoreCase` option for case-insensitive operations, and improved negation support. Enhanced SQL injection protection. - -### `withSupermemory` for OpenAI SDK - -New `withSupermemory` wrapper for the OpenAI TypeScript SDK — transparent memory injection with automatic assistant response capture. - -### Zapier & n8n Integration Pages - -New integration guides for connecting Supermemory with Zapier and n8n automation workflows. - - - - - -### `@supermemory/tools` — AI SDK `withSupermemory` - -New `withSupermemory` language model wrapper for Vercel AI SDK that automatically injects memory context and captures assistant responses. - -### Raycast Extension - -New Raycast extension for quick memory access and addition from the macOS launcher. - -### User Profiles API - -New `/v4/profile` endpoint for retrieving AI-generated user profiles derived from memory interactions, with container tag scoping. - -### Other - -- **DOCX support** — Word documents can now be ingested. -- **Project selection for connectors** — assign Google Drive, Notion, and OneDrive connections to specific projects. -- **Multiple models in consumer chat** — model switcher with system prompt improvements. -- **Organization settings** — configure Supermemory behavior (chunking, extraction, memory limits) per org. - - - - - -### Forgotten Memories Search - -New `include.forgottenMemories` parameter in v4 search API to search through memories that have been explicitly forgotten or expired. - -### Enhanced Delete API - -`DELETE /v3/documents/:id` now supports both internal document ID and `customId`. - -### API Terminology Update - -Renamed "memories" to "documents" for developer clarity. New `/v3/documents/*` endpoints with full backward compatibility via automatic redirects from `/v3/memories/*`. - -### Console Revamp - -New console design with dark/light mode, org switcher, billing invoices, space selector with search, and memory list with multi-delete. - -### Other - -- **New filters** — revamped filtering UI in the console. -- **Onboarding redesign** — new step-based onboarding with code samples. -- **Configurable chunking** — set chunk size and algorithm per org. - - - - - -### Documentation v2.0 - -Complete rewrite with comprehensive API references, cookbook recipes, and production-ready examples for TypeScript, Python, and cURL. - -### `@supermemory/tools` Package - -New tools package for native Vercel AI SDK and OpenAI integration with memory tools and infinite chat. Plus `openai-python-sdk` for Python middleware. - -### Batch Add & Bulk Delete - -New `POST /v3/documents/batch` for batch ingestion and `DELETE /v3/documents/bulk` for bulk deletion. - -### Memory Forgetfulness System - -Full lifecycle management with `forgetAfter` dates and forgotten memory filtering. - -### Video Uploads - -Video files can now be ingested with automatic content extraction. - - - - - -### MCP Connection Flow Redesign - -Step-based UI for connecting MCP clients with v1 migration support. One-click install for Cursor. - -### Claude.ai & t3.chat Extension Support - -Browser extension now integrates directly with Claude.ai and t3.chat for automatic memory search during conversations. - -### Waitlist Removed - -Supermemory is now open to all users — no more waitlist. - - - - - -### New Landing Page & Developer Page - -Redesigned marketing pages with developer-focused content, SEO improvements, and mobile responsiveness. - -### Direct Webpage Ingestion - -Ingest web content with `` tags for targeted extraction. - -### Usage Limits Dashboard - -Billing usage and limits now visible directly in the console dashboard. - -### Other - -- **Allow all CORS origins** for easier API integration. -- **Single `containerTag` in add memory** — simpler API for basic use cases. -- **Improved MCP project handling** — better project scoping in the MCP server. - - - - - -### New Consumer App - -Complete rewrite of the consumer-facing app — new chat experience with slide-out window, masonry memory grid with infinite scroll, PWA support, and mobile-responsive menu bar. - -### Memory Graph with WebGL - -Graph rendering now uses WebGL for smooth visualization of thousands of memory connections. Search highlights relevant nodes with zoom. - -### Chat Rewrite - -New chat system with memory-aware conversations, regeneration, copy buttons, and the ability to add memories through chat. - -### Dynamic Node Relations - -Memory graph now supports `update`, `extend`, and `derive` relation types. Memories can be inferred from multiple parent documents. - - - - - -### PDF Support for Google Drive - -Google Drive connector now processes PDF files alongside Docs, Sheets, and Slides. - -### Encrypted Connector Credentials - -Google Drive, OneDrive, and Notion client secrets are now encrypted at rest. - -### Bulk Memory Delete - -New endpoint for deleting multiple memories at once. - -### Self-Host Support - -Initial self-hosting support — run Supermemory on your own infrastructure. - - - - - -### Console Migrated to Cloudflare - -Console app moved from Vercel to Cloudflare Workers for improved performance and lower latency. - -### Autumn Payments Integration - -Billing system integrated with Autumn for subscription management, waitlist early access, and usage tracking. - -### New Developer Dashboard - -Redesigned developer dashboard with API key display in code snippets, limits visualization, and MCP installation instructions. - - - - - -### Consumer App v0 - -First version of the consumer app with chat, memory browsing, project management, and profile view. New consumer-oriented landing page. - -### MCP → Agents SDK - -MCP server migrated to the Agents SDK architecture for better reliability and project support. - -### New Billing - -Revamped billing page with upgrade buttons and plan management. - - - - - -### Memory Graph Rewrite - -Complete rewrite of the graph visualization — faster rendering, better layout, and interactive exploration. - -### Onboarding - -New guided onboarding flow for first-time console users. - -### Notion Webhooks - -Real-time sync for Notion connections via webhook integration. - - - - - -### Landing Page Rewrite - -New marketing site with glass UI design, rewritten pricing page, and dedicated MCP page. - -### Billing Page - -New billing page with upgrade buttons and plan comparison. - -### PostHog Analytics - -Analytics tracking added across the console and landing page. - - - - - -### OneDrive Connector - -New connector for syncing OneDrive files with webhook-based real-time updates. - -### Connectors BYOK - -Bring your own API keys for connector integrations (Google Drive, OneDrive, Notion). - -### Google Sheets & Slides - -Google Drive connector now supports Sheets and Slides alongside Docs. - - - - - -### Console Dashboard - -First version of the dashboard overview page with memory analytics, container tag distribution charts, and usage metrics. - -### Google Drive Webhooks - -Real-time sync — Google Drive changes are automatically detected and processed. - -### Sentry Integration - -Error monitoring added across the console and API. - - - - - -### Launch-Ready API - -Console reached launchable state with login page improvements, auth fixes, and the first version of the new dashboard with React Query. - -### Infinite Chat - -Memory Router proxy with automatic context compression for infinite-length conversations with LLMs. - -### Container Tags in Search - -Filter search results by container tags for scoped memory retrieval. - -### Google Docs MD Export - -Google Drive connector switched from PDF to Markdown export for better content fidelity. - - - - - -### API v3 - -New `/v3/` endpoints replacing v2 — cleaner routes, updated memory endpoint, and new update/delete operations. - -### OneDrive Connector - -Initial OneDrive integration for syncing files into Supermemory. - -### Connections Architecture - -New connection-document relationship model for tracking which connector synced which document. - - - - - -### Comprehensive API Documentation - -New interactive API references on Mintlify with detailed parameter explanations, response schemas, and bearer auth. - -### Container Tags System - -Enhanced organizational grouping for better memory isolation and user-scoped content. - -### Auto Content Type Detection - -Automatic processing of PDFs, images, videos, and web content regardless of URL extensions. - - - - - -### Google Drive Connector - -New endpoints for programmatic Google Drive integration and file syncing. - - - - - -### Search Improvements - -- **`documentThreshold` and `chunkThreshold`** — fine-tune search sensitivity. -- **`docId` parameter** — search within specific large documents. -- **`onlyMatchingChunks`** — precise result filtering. -- **`endUserId` filtering** — scope search to specific users. -- **Reranking** — improved result quality with a reranking step. - - - - - -### Supermemory MCP Server - -First version of the MCP server for AI model integrations. - -### Personalisation - -AI-generated personalization based on user memory patterns. - -### List Memories Endpoint - -First version of the list memories API with pagination. - - - - - -### Team API - -Organization invites and user management endpoints. - -### Analytics API - -Hourly analytics tracking with detailed usage metrics. - -### Content Processing Pipeline - -New ingestion workflow with status tracking: `queued` → `extracting` → `chunking` → `embedding` → `done`. - - - - - -### Connections System - -First version of the connectors architecture — sync external data sources into Supermemory. - -### Tag-Based Filtering - -Filter memories by tags in search and list operations. - -### Advanced Analytics - -Request tracking, error counts, and usage metrics per organization. - - - - - -### Supermemory API v2 - -The platform begins — Cloudflare Workers API with auth, ingestion workflows, vector search, and organization support. Built on Hono, Drizzle ORM, and Cloudflare D1/Hyperdrive. - - - - - -### Supermemory v2 Release - -Major release of the consumer web app with new import tools (CSV, Markdown/Obsidian), improved hybrid search with date relevancy, batch delete, and space management (edit/delete names). - -### Docs Site Launch - -First version of the documentation site with API reference, getting started guide, and pricing page. - - - - - -### Supermemory v1 — Major Update - -New consumer app version with canvas/note editor, text-to-speech on AI answers, PWA support, improved Telegram bot with Markdown, and memory queue processing. Extension gets drag-and-dismiss features. - - - - - -### ProductHunt Launch - -Supermemory launches on ProductHunt. Features at launch: shareable spaces, Twitter thread import, AI chat with citations, onboarding flow, recommended items, chat history, and keyboard shortcuts. - - - - - -### Multi-Turn Chat & Canvas - -Added multi-turn conversations, canvas with drag-and-drop, Telegram bot, vector lookup 2x speedup, and the first version of the Chrome extension. - - - - - -### Backend Rewrite to Hono - -Backend migrated from Next.js API routes to Hono on Cloudflare Workers. Landing page redesign, browser rendering for web content extraction. - - - - - -### Supermemory v1 Launch - -First public release — spaces, chat with AI, Twitter bookmarks import, Chrome extension with save-from-page, notes editor, and search across all saved content. - - - - - -### Supermemory is Born - -Initial monorepo setup with auth, Chrome extension, AI chat with citations using OpenAI embeddings, and the first version of the web app. - - diff --git a/apps/docs/changelog/plugins.mdx b/apps/docs/changelog/plugins.mdx deleted file mode 100644 index f11aaefb..00000000 --- a/apps/docs/changelog/plugins.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: "Plugin changelog" -sidebarTitle: "Plugins" -description: "Recent updates and improvements to Supermemory plugins" ---- - - - -### OpenCode entity context - -OpenCode now sends entity context with memory operations, so saved context can stay tied to the active project and conversation. The entity-context prompt was also moved out of the API client for cleaner reuse across capture and compaction flows. - -### Cursor session auth - -Cursor now starts the auth flow from the session hook when needed, and the OAuth success screen uses the Cursor-branded callback path. - - - - - -### Claude Code update notices - -Claude Code now surfaces plugin update notices during sessions and includes the latest package/version metadata. - -### OpenCode context prompt - -OpenCode gained an entity-context prompt so memory recall and capture can carry more precise source context. - - - - - -### Claude Code marketplace polish - -The Claude Code plugin manifest was polished for the official marketplace listing, including refreshed metadata and naming. - -### Codex update notices - -Codex now checks for plugin updates during session start and shows a user-visible notice when a newer version is available. - - - - - -### Claude Code rename migration - -Claude Code completed the rename to the `supermemory` plugin while keeping migration safe for users already on the new plugin name. Configuration also supports custom `baseUrl` values for local or self-hosted Supermemory installs. - -### Cursor web OAuth - -Cursor OAuth now routes through the Supermemory web app, keeping the plugin auth flow consistent with the rest of the integrations. - - - - - -### Codex auth and status tooling - -Codex added status, logout, and web-auth flows, plus Windows-safe auth URL opening and entity context for saved memories. The installer now includes a `supermemory-status` skill so Codex can report connection, hook, config, and installed-skill health from inside a session. - -### OAuth status refinements - -Codex and OpenCode integration status now renders more clearly in the Supermemory app during OAuth connection and setup. - - - - - -### Claude Code recall reasoning - -Claude Code gained reasoned per-turn memory recall with auto-approve support, refreshed bundled scripts, and updated skill names for `supermemory-save` and `supermemory-search`. - -### Cursor session hooks - -Cursor session hooks now load reliably and persist real project sessions into the correct container. - -### OpenClaw and Hermes memory attribution - -Saved plugin memories now parse source attribution more accurately, and the dashboard shows the correct plugin logos and recent-memory rows for OpenClaw and Hermes. - - diff --git a/apps/docs/company-brain/automations.mdx b/apps/docs/company-brain/automations.mdx new file mode 100644 index 00000000..7279bac0 --- /dev/null +++ b/apps/docs/company-brain/automations.mdx @@ -0,0 +1,97 @@ +--- +title: "Automations and Proactiveness" +sidebarTitle: "Automations" +description: "Scheduled work Company Brain runs on its own, and when it speaks without being asked" +icon: "bot" +--- + +import { SlackThread, SlackMessage, Mention, ChannelRef } from "/snippets/slack-message.mdx"; + +Company Brain doesn't only answer when you @mention it. It can run recurring work on a schedule, and it can speak in a thread on its own when it has something genuinely worth saying. Both are opt-in, both are rate-limited, and both read from exactly the same [permissions graph](/company-brain/permissions) as a normal question — neither is a backdoor around it. + +## Automations + +An automation is a prompt that runs on a schedule and posts the result somewhere. You write it once, in plain language: + + + + supermemory every Monday at 9am, post a digest of what shipped last week and what's still open, to product. + + + Got it — scheduled. First digest posts Monday, 9:00 AM, to product. + + + + + + The automation wakes up at its set time — no one has to trigger it. + + + It reads using only **org-shared** connections and channel memory — never a person's personal credentials, even if the person who created the automation has better personal access. This is what keeps a scheduled post from silently acting as a specific teammate. + + + Before posting, it re-confirms it can still see the destination channel. + + + If anything above is unclear — a connection broke, visibility can't be verified — it skips that run rather than posting a guess. Silence beats a wrong digest. + + + +**Who can target what:** + +| Destination | Who can create it | Reads from | +|---|---|---| +| Public channel | Any member | Org-shared connections, public channel memory | +| Private channel | Admins only | Org-shared connections, that channel's memory | +| DM to yourself | The owner of that DM | Your personal + org connections, your employee memory | + +Common shapes worth stealing: + +- A Monday-morning digest of open items and unanswered questions +- A daily Sentry error recap in `#eng` +- A weekly "what changed across our connected tools" summary + +Anyone can create and manage their own automations; admins can manage everyone's. Ask Company Brain in Slack to set one up, or manage the full list from the web app. + +## Proactiveness (chime-in) + +Chime-in is different from an automation: there's no schedule, and no one asked. Company Brain is simply present in a channel — because an admin invited it — and it speaks up when staying quiet would waste someone's time. + +**What actually earns a chime-in:** + +- It has to add something the room doesn't already have — a fact, a correction, a next step — not agreement or a restatement of what's already visible. +- It has to come from somewhere it's genuinely allowed to look: [connected tools](/company-brain/connectors) or that room's own memory, same as any other answer. +- If it isn't confident the answer is actually correct, it says nothing. A wrong guess is worse than silence, so uncertainty resolves to silence, not a hedge. + + +```text Worth chiming in +"is prod down? customers are pinging me" +→ correlates against Sentry, replies with what's actually elevated right now +``` + +```text Not worth it +"finally shipped this 🎉" (screenshot, no question) +→ stays quiet — there's nothing to add +``` + + +**Guardrails that keep it from becoming noise:** + +- **Rate-limited.** It won't speak repeatedly in the same thread or channel in a short window, even if it technically could add something each time. +- **Invite-only rooms.** It never joins a channel on its own — only places an admin already invited it into. +- **Same graph as a normal answer.** A private channel's chime-in only ever draws on that channel's memory and public channel memory — never another private channel, never someone else's employee memory. + +An explicit @mention always skips this judgment call entirely — naming it is you deciding it should speak, so it does. + + +Automations and chime-in both write back to memory the same way a normal conversation does: a public channel's automation output lands in public channel memory, a private channel's chime-in stays scoped to that channel's memory. + + + + + Real scenarios — support, incidents, digests, and more. + + + Wire up the tools automations and chime-in draw from. + + diff --git a/apps/docs/company-brain/connectors.mdx b/apps/docs/company-brain/connectors.mdx new file mode 100644 index 00000000..388dbaa0 --- /dev/null +++ b/apps/docs/company-brain/connectors.mdx @@ -0,0 +1,64 @@ +--- +title: "Connectors" +sidebarTitle: "Connectors" +description: "Bring knowledge in with data connectors, and act in live tools with tool connectors" +icon: "plug" +--- + +Company Brain has two kinds of connectors. They look similar on the connections page, but they do different jobs: + +| | Data connectors | Tool connectors | +|---|---|---| +| **What they do** | Bring knowledge *in* | Let the agent *act* in the tool | +| **Examples** | Google Drive, Notion, OneDrive | GitHub, Linear, Sentry, Plain, PostHog, Granola | +| **Result** | Docs land in public channel memory and stay searchable | Live reads and writes (list PRs, create issues, check errors) | +| **When it runs** | Background sync on a schedule | In the moment you ask | + +## Data connectors + +Data connectors sync existing files and docs into **public channel memory** so answers are grounded in real material — roadmaps, specs, handbooks, design docs. + +How it works: + +1. An admin connects a source (Drive, Notion workspace, OneDrive, and similar). +2. Company Brain fetches, chunks, embeds, and indexes the content in the background. +3. It re-syncs on a schedule automatically — you don't re-upload when a doc changes. + +Connecting a data source is a **team-level action**. What comes in is visible org-wide, same as anything from a public channel — see the [permissions graph](/company-brain/permissions) for exactly who can read what. + + +A data connector is only as useful as the docs you point it at. Start with the handful of sources people actually re-read — product specs, the handbook, the latest roadmap — rather than every folder in Drive. + + +## Tool connectors + +Tool connectors are live integrations (MCP-based under the hood). They don't just index past content — they read and act in the tool *right now*: + +- **GitHub** — open PRs, recent commits, repo context +- **Linear** — find or create issues, check status +- **Sentry** — what's actually erroring in prod +- **Plain** — customer support tickets and history +- **PostHog** — product analytics +- **Granola** — meeting notes and decisions +- **Custom servers** — wire up your own MCP endpoint when the catalog doesn't cover a tool + +You can also connect tools at two scopes — **Organization (shared)** or **Personal (yours)**. The full rule of thumb lives on [The permissions graph](/company-brain/permissions): reads prefer your personal connection and fall back to the org one; writes always run under your own account so the action is attributed to you. + +If neither you nor the org has a tool connected, but a teammate does, Company Brain can ask them to **lease** temporary access for that one request — see [Leasing](/company-brain/permissions#leasing-borrowing-access-for-one-request). + +## Which one do I need? + +- **"What's in our Q2 roadmap?"** → data connector (Drive/Notion/OneDrive already synced) +- **"What are my open PRs?"** or **"Create a Linear issue"** → tool connector (GitHub / Linear) +- **"What did we decide in the Acme call?"** → tool connector that also brings knowledge in (Granola), or a data connector if notes live in Drive/Notion + +You almost always want both: data connectors for the long-lived knowledge base, tool connectors for the live work happening this week. + + + + Scheduled digests and unprompted replies that use these connections. + + + Walkthroughs of support, incidents, PRs, meetings, and more. + + diff --git a/apps/docs/company-brain/outside-slack.mdx b/apps/docs/company-brain/outside-slack.mdx new file mode 100644 index 00000000..ba968a85 --- /dev/null +++ b/apps/docs/company-brain/outside-slack.mdx @@ -0,0 +1,52 @@ +--- +title: "Using Outside Slack" +sidebarTitle: "Outside Slack" +description: "Reach the same permissions graph from Claude Code, ChatGPT, Cursor, or any MCP client" +icon: "globe" +--- + +Slack is the default surface, not the only one. Company Brain speaks MCP, so the same graph — your employee memory, the private channels you're in, public channel memory — is reachable from any MCP client: Claude Code, ChatGPT, Cursor, or anything else that speaks the protocol. + +## Connect + +Same endpoint as [Supermemory MCP](/supermemory-mcp/mcp) — there's no separate Company Brain server to point at: + +```text +https://mcp.supermemory.ai/mcp +``` + +OAuth by default — your client discovers the authorization server and prompts you to sign in. Prefer an API key instead? Any key starting with `sm_` skips OAuth entirely. + + +What changes isn't the URL, it's what shows up once you're connected. If your account belongs to an org with Company Brain, you get more than your own project spaces — your employee memory, the private channels you're in, and public channel memory all become available as workspaces, carrying your role and the exact same read/write access Slack already enforces. + + +## Pick a workspace + +Once connected, ask it what's available — it returns every container tag you have access to: your employee memory, each private channel memory you belong to, and public channel memory. Select one to make it the active workspace for the session; everything after that scopes to it automatically. + +**Example:** from Claude Code, "what can I access in Acme's Company Brain?" surfaces your options as a picker — your employee memory, `#eng`'s private channel memory if you're in it, public channel memory. Pick one, and every search or save for the rest of the session happens inside it — the same as asking from that room in Slack. + +## Tools + +| Tool | What it does | +|---|---| +| `listContainerTags` | Everything you're allowed to read, with names and counts | +| `select-workspace` / `set-active-tag` | Pick which one is active for this session | +| `recall` | Search the active workspace, plus a profile summary when you're in your employee memory | +| `save-memory` | Write back to the active workspace | +| `memory-graph` | An interactive, visual map of a workspace's memories | +| `whoAmI` | Your role, access type, and active workspace — useful for sanity-checking what a client can actually see | + +## Same graph, same guardrails + +Nothing here is a side door. What you can reach follows the exact same [permissions graph](/company-brain/permissions) as Slack — an admin can restrict a member's connection to specific container tags the same way they'd scope a Slack channel invite, and every read or write is checked against that before it runs. + + + + What each container tag actually is, and who can read it. + + + Base setup, auth, and personal project spaces on the same server. + + diff --git a/apps/docs/company-brain/overview.mdx b/apps/docs/company-brain/overview.mdx new file mode 100644 index 00000000..c0f0629b --- /dev/null +++ b/apps/docs/company-brain/overview.mdx @@ -0,0 +1,94 @@ +--- +title: "What is Supermemory Company Brain?" +sidebarTitle: "Overview" +description: "A super agent, with all the knowledge and tools of your team" +icon: "brain" +--- + +import { SlackThread, SlackMessage, Mention, ChannelRef, AgentLink } from "/snippets/slack-message.mdx"; + +Supermemory Company Brain is a super agent with shared memory for your team that you can **ask questions** and that can **act in your tools**. It pulls from the work you already do - Slack threads, docs, GitHub, Linear - And can pretty much act as a real employee in your team. + + + + Meetings, decisions, projects, and who owns what — kept current as your connected sources sync. + + + Pulls your open PRs, finds a Linear issue, or answers in a Slack channel — not just recites text back. + + + +## A quick example of its capabilities + +It'll answer a question, actually go do the work, or just jump into a conversation on its own when it's got something worth saying — like a coworker would, not a search bar. You can configure how funny and unhinged it is, or how of it you want. + +### Ask it anything + + + + supermemory what did we decide about pricing for the company brain + + + You and mahesh decided yesterday that it stays at **$400/mo**, usage based only. we landed on that in a product huddle + + + +### Put it to work + + + + supermemory is the Stripe webhook timeout from Sentry already tracked anywhere? + + + nope, nothing yet — just opened **ENG-847** for it, added the sentry issue to it, and put it on Sam since they were the last one in `webhooks/stripe.ts` and their beautiful code broke it ☠️. here you go, should probably fix it asap. + + + +### Let it speak up on its own + + + + is prod down? a couple of customers are pinging me + + + not fully down — `api/search` is just elevated, 42 errors in the last 15 min (SM-2041), and Kush is on it. probably that deploy from this morning. Only one user has complained on support and i already replied to them saying it's being investigated. + + + +You don't need to mention it. It speaks up when it has something to add. It's smart and proactive! + +## Same knowledge, useful everywhere + +It's your team's knowledge — it doesn't have to stay in Slack. Take it wherever you're actually working: + +- **Your coding agent** — ask Claude Code or Cursor mid-session what the team decided, why a file looks the way it does, or who to ping about it, without tabbing over to Slack. +- **Your own tools, via MCP** — Company Brain speaks MCP, so if whatever you're building can speak MCP too, it can ask. Plug it into an internal tool, a script, whatever you need. + +Same permissions graph everywhere, no exceptions — asking from Claude Code doesn't get you anything asking from Slack wouldn't. + +```text +> is the stripe webhook thing from earlier actually fixed? +yep — Sam shipped it in ENG-847 about an hour ago, Sentry's been quiet since +``` + +This knowledge can be used wherever you and your teammates go — see [Using outside Slack](/company-brain/outside-slack) for how to connect. + +## Use it your way + +Company Brain isn't locked to one model or one voice. Two things you control directly: + +- **Any model, no markup** — bring your own LLM and pay nothing extra for inference. +- **Its tonality** — configure how it talks, from buttoned-up professional to fully unhinged. Make it sound like your team, not a generic chatbot. + +## Where to go next + +Company Brain has a handful of ideas worth understanding before you set it up: Our permissioning setup, how to configure it, proactiveness, automations, and more. + + + + What's remembered where, and who can read it. + + + Get your team's workspace running. + + diff --git a/apps/docs/company-brain/permissions.mdx b/apps/docs/company-brain/permissions.mdx new file mode 100644 index 00000000..e51c6f55 --- /dev/null +++ b/apps/docs/company-brain/permissions.mdx @@ -0,0 +1,91 @@ +--- +title: "The Permissions Graph" +sidebarTitle: "Permissions" +description: "What Company Brain remembers, who it's visible to, and how tool access is scoped" +icon: "shield-check" +--- + +Company Brain isn't split into "a shared brain" and "a private brain." It's a graph: memory is written to the narrowest room a conversation happened in, and what a given conversation can *read* depends on where it's happening and who's asking. Nothing here is silent — every install, channel read, and temporary access grant requires an explicit accept from a real person. + +## Three memories, not two + + + + One per person. Built from your DMs with the bot and what it learns about you over time. Only visible from your own DM. + + + One per private channel. Scoped to that room — visible to anyone in it, to no one outside it. + + + One per organization. Anything durable from a public channel lands here. The whole org can draw on it. + + + +A message writes to exactly one of these — whichever room it happened in. + +## What a conversation can read + +Writing is narrow; reading is broader, and it widens the more private the room is: + +| Asking from | Can read | +|---|---| +| A public channel | Public channel memory | +| A private channel | That channel's memory + public channel memory | +| A DM with the bot | Your employee memory + public channel memory + every private channel memory you belong to | + +```mermaid +flowchart LR + Pub["Public channel memory
(the whole org)"] + Priv["Private channel memory
(that room's members)"] + Emp["Employee memory
(you, in DM)"] + + Priv -.reads.-> Pub + Emp -.reads.-> Pub + Emp -.reads.-> Priv +``` + +A DM is the widest seat in the room precisely because it's the most private one — the bot answers you there with everything *you* could see, stitched together. A public channel is the opposite: the whole org can read it, so it only ever draws on what the whole org is allowed to know. + + +If you're not in a private channel, its memory doesn't exist for you — not even by inference in a DM. The bot only ever reads with the asker's own access, so it can't surface something you couldn't otherwise see. + + +**Example:** you DM the bot asking "what did we decide about the Acme deal?" It can draw on the public `#sales` channel, the private `#acme-deal` channel if you're in it, and anything it's learned about you directly — and it'll cite which one the answer came from. Ask the same question in `#general`, a public channel, and it can only answer from what `#general` and other public channels already know — the private `#acme-deal` context simply isn't in scope there. + +## Tool access follows you, not the connection + +Tools like GitHub and Linear can be connected two ways — **Organization (shared)**, set up once by an admin as a fallback the whole team can read from, or **Personal (yours)**, your own connection for your own reads and actions. Both show up on the same connections page; it's one tool catalog, connected at two possible scopes. + +Whichever scope answered, the result is still bounded by what *you* could already see or do in that tool yourself — Company Brain never gets a standing key to "everything Linear knows." If you're not on a private Linear team, the bot can't surface those issues to you either, even through the org-shared connection. + +| | Reads | Writes | +|---|---|---| +| **Behavior** | Try your personal connection first, then fall back to org-shared | Always run under your own connection | +| **Why** | Gives you the fullest access you're entitled to | Attributes the action to a real person, never a shared service account | + +Admins can also act through the org-shared connection directly, for the cases where that's the point. + +## Leasing: borrowing access for one request + +Sometimes a request needs a tool neither you nor the org has connected — but a teammate has it connected personally. Rather than failing, Company Brain can ask that teammate directly: it posts a card in Slack asking them to approve or deny lending access for that one request. + +- Nothing is granted silently — a real person has to accept the card. +- Access is short-lived and scoped to the single request that triggered it, not standing access to your account. +- The teammate can say no, and the request simply doesn't go through. + + +Leasing is a fallback of last resort — it only comes up when nobody's connected the tool at the org level yet. See [Connectors](/company-brain/connectors) to close that gap for good. + + +## API keys inherit the same graph + +A scoped or agent API key can only reach what its owner could already reach by asking directly. A member can't mint a key that reads another member's employee memory or a private channel they're not in — the graph above applies identically whether a person is asking or a key is. + + + + Set up the data and tool connections this page describes. + + + How scheduled runs and unprompted replies respect the same graph. + + diff --git a/apps/docs/company-brain/setup.mdx b/apps/docs/company-brain/setup.mdx new file mode 100644 index 00000000..1244c643 --- /dev/null +++ b/apps/docs/company-brain/setup.mdx @@ -0,0 +1,87 @@ +--- +title: "Setup and Onboarding" +sidebarTitle: "Setup" +description: "Creating a team workspace and installing it into Slack" +icon: "rocket" +--- + +Setting up Company Brain is two admin steps: create the workspace, then install it into Slack. Everyone else joins on their own after that — see [Greeting new teammates](/company-brain/use-cases/greeting). + +## 1. Create your team workspace + +Creating a workspace sets up your shared **Team Brain** and your private **My Brain** in one step. + + + + Head to [app.supermemory.ai](https://app.supermemory.ai) and create an account. + + + On the **About** step, switch from **Personal** to **Team**. + + + Team workspaces are invite-only during the private beta. Not invited yet? Email **support@supermemory.com**, or start Personal and invite your team once you're in. + + + ![Personal/Team toggle on sign-up, with the private-beta invite notice for Team](/images/company-brain/signup-team-toggle.png) + + + Enter your domain (for example `acme.com`) and confirm. Supermemory researches the company from there and seeds a starting profile, before any source finishes syncing. + + ![Company domain step — Supermemory researches the company from the domain to set up its Brain](/images/company-brain/signup-company-domain.png) + + + All three run in parallel with research, and none of them block it: + + - **Add to Slack** — kicks off the install flow below. + - **Connect apps** — Linear, Granola, Sentry, and more. + - **Invite teammates** — now, not later. No per-seat pricing, so invite everyone in your Slack. + + ![Research in progress, with Add to Slack and Connect apps available alongside it](/images/company-brain/signup-research-connect.png) + + + Supermemory's already learned a real amount about your company by the time research finishes. Watch Slack for a DM from it walking you through what it can do. + + ![The finished research — real notes about the company and founder, ready to search](/images/company-brain/signup-research-complete.png) + + + + +**Try it:** ask `What does {your company} do?` — you should get a real answer from the seeded profile. + + +## 2. Install into Slack (admin) + + + + Go to [app.slack.com](https://app.slack.com) to create one first — Company Brain installs into an existing workspace, it doesn't create one for you. + + ![Naming a new Slack workspace](/images/company-brain/slack-create-workspace.png) + + + + + + Click **Install to Slack**. Not an admin? This triggers Slack's own request-to-install flow instead. + + + The web app hands off immediately — "we've DM'd you in Slack." + + + The agent creates `#company-brain`, posts an intro there, and announces itself once in `#general`. + + + You approve each channel with a tap — it never joins one silently. + + + Invite people with a picker, a workspace-wide toggle, or email. + + + + + + What member join looks like from a new hire's side. + + + What each person can see once they're in. + + diff --git a/apps/docs/company-brain/use-cases/acting-in-tools.mdx b/apps/docs/company-brain/use-cases/acting-in-tools.mdx new file mode 100644 index 00000000..029d282b --- /dev/null +++ b/apps/docs/company-brain/use-cases/acting-in-tools.mdx @@ -0,0 +1,54 @@ +--- +title: "Acting in Tools" +sidebarTitle: "Acting in Tools" +description: "List open PRs, create Linear issues — actions run under your own account" +icon: "wrench" +--- + +import { SlackThread, SlackMessage, Mention, AgentLink } from "/snippets/slack-message.mdx"; + +## The scenario + +You don't just want to *know* something — you want Company Brain to do the next step in GitHub or Linear for you. + +## What happens + +### Read from a tool + + + + supermemory what are my open PRs in the web repo? + + + You have **3 open PRs** on `supermemory/web`: + - `#1199` staff custom MCP connection cards — review requested + - `#1197` company brain onboarding research UI — changes requested + - `#1181` brain connections board — approved, not merged + + + +### Write to a tool + + + + supermemory create a Linear issue: fix the onboarding redirect + + + Created **ENG-842** — *Fix the onboarding redirect* in Engineering, assigned to you. Open in Linear + + + +## What's really going on + +Both turns use [tool connectors](/company-brain/connectors) (GitHub, Linear). Reads try your **personal** connection first and fall back to the org-shared one. **Writes always run under your own account** — so the Linear issue is attributed to you, never silently as "the org." + +If you haven't connected the tool and neither has the org, Company Brain can ask a teammate to [lease](/company-brain/permissions#leasing-borrowing-access-for-one-request) temporary access for that one request. + + + + Personal vs org tools, and how leasing works. + + + Connect GitHub, Linear, and the rest. + + diff --git a/apps/docs/company-brain/use-cases/greeting.mdx b/apps/docs/company-brain/use-cases/greeting.mdx new file mode 100644 index 00000000..9d78e943 --- /dev/null +++ b/apps/docs/company-brain/use-cases/greeting.mdx @@ -0,0 +1,50 @@ +--- +title: "Greeting New Teammates" +sidebarTitle: "Greeting Teammates" +description: "Connect card, welcome DM, and first answer — activation on day one" +icon: "user-plus" +--- + +import { SlackThread, SlackMessage, BOT_AVATAR } from "/snippets/slack-message.mdx"; + +## The scenario + +A new hire joins the Slack workspace. They shouldn't need a web signup form or a long handbook read before Company Brain is useful — the whole first experience happens in Slack. + +## What happens + +They get a connect card, tap **Connect me**, and receive a welcome DM: + + + + Welcome to **Acme**. Here's what I know, what I can access, and what I keep private. + + Try one of these: + 1. What does Acme do? + 2. Who owns onboarding? + 3. Where do we track bugs? + + + What does Acme do? + + + Acme builds memory infrastructure for AI apps — shared context for teams and agents. *(from the company profile your admin seeded at setup)* + + + +Right after the first answer, they're prompted to connect personal tools (Linear, Notion) so day-two questions can hit live data. + +## What's really going on + +This is the [member join flow](/company-brain/setup) told as a scenario. Tapping **Connect me** creates a passwordless account from their Slack email, provisions their private [employee memory](/company-brain/permissions), and consumes a seat. The three starter questions are seeded so the first useful answer happens on the first tap — that's the activation moment. + +No web app required for the new hire. Admins still do the one-time workspace + Slack install on the web. + + + + The full admin + member flow. + + + Employee memory vs. public and private channel memory. + + diff --git a/apps/docs/company-brain/use-cases/incidents.mdx b/apps/docs/company-brain/use-cases/incidents.mdx new file mode 100644 index 00000000..15aaac6f --- /dev/null +++ b/apps/docs/company-brain/use-cases/incidents.mdx @@ -0,0 +1,46 @@ +--- +title: "Incidents & Downtime Chatter" +sidebarTitle: "Incidents" +description: "Answer 'is prod down?' from live Sentry, and post scheduled error digests" +icon: "triangle-alert" +--- + +import { SlackThread, SlackMessage, AgentLink } from "/snippets/slack-message.mdx"; + +## The scenario + +Someone drops a vague "is prod down?" in `#eng`. Company Brain correlates it with what's actually failing right now — and a separate automation keeps a daily error digest flowing without anyone asking. + +## What happens + + + + is prod down? a couple of customers are pinging me + + + Not a full outage — **`api/search` is elevated** (42 errors in the last 15m, mostly `timeout on vectorize`). Sentry issue SM-2041. Deploy from this morning is the likely culprit; rollback candidate is `af61880`. + + + +Or, without anyone asking, a scheduled automation posts every morning: + + + + **Daily error digest** — 3 issues new since yesterday, 1 still spiking (`api/search` timeout). Full list in Sentry. + + + +## What's really going on + +The first exchange is a [chime-in](/company-brain/automations) (or an @mention — either works) that hits the **Sentry** [tool connector](/company-brain/connectors) for live error data. The second is an [automation](/company-brain/automations): a recurring prompt on a cron that posts to a channel using org-shared connections only, so it never runs as a specific person. + +If the channel is private, only an admin can target it with an automation, and the bot fails closed if it can't verify visibility. + + + + Connect Sentry (and friends) for live incident context. + + + Schedule digests and understand chime-in. + + diff --git a/apps/docs/company-brain/use-cases/knowledge-recall.mdx b/apps/docs/company-brain/use-cases/knowledge-recall.mdx new file mode 100644 index 00000000..d0cfc0ff --- /dev/null +++ b/apps/docs/company-brain/use-cases/knowledge-recall.mdx @@ -0,0 +1,43 @@ +--- +title: "Answering from Your Docs" +sidebarTitle: "From Docs" +description: "Ask about roadmaps, specs, and handbooks in plain language" +icon: "book" +--- + +import { SlackThread, SlackMessage, Mention } from "/snippets/slack-message.mdx"; + +## The scenario + +The Q2 roadmap lives in Notion. Nobody wants to dig for the link mid-conversation — they just ask. + +## What happens + + + + supermemory what's in our Q2 roadmap? + + + Three themes for Q2: + 1. **Company Brain GA** — Slack bot, connectors, automations + 2. **Memory Router v2** — lower latency, better multi-tenant isolation + 3. **Enterprise SSO + audit log** + + Full doc: *Q2 Roadmap* in Notion (last updated Jun 3). + + + +## What's really going on + +This is a [data connector](/company-brain/connectors) (Notion, Google Drive, or OneDrive) feeding [public channel memory](/company-brain/permissions). Content is fetched, chunked, embedded, and re-synced on a schedule — so when the roadmap changes in Notion, answers stay current without anyone re-uploading. + +Same pattern works for handbooks, design docs, RFCs, and "where do we document X?" style questions. If it doesn't know, it says so rather than guessing. + + + + Bring Drive, Notion, and OneDrive into public channel memory. + + + Who can see what once it's indexed. + + diff --git a/apps/docs/company-brain/use-cases/long-horizon-research.mdx b/apps/docs/company-brain/use-cases/long-horizon-research.mdx new file mode 100644 index 00000000..c7c9c669 --- /dev/null +++ b/apps/docs/company-brain/use-cases/long-horizon-research.mdx @@ -0,0 +1,47 @@ +--- +title: "Long-Horizon Research" +sidebarTitle: "Long-Horizon Research" +description: "Questions that need many sources synthesized into one answer" +icon: "telescope" +--- + +import { SlackThread, SlackMessage, Mention } from "/snippets/slack-message.mdx"; + +## The scenario + +Some questions aren't a quick lookup. They need pulling information from a lot of distinct places — docs, tickets, meetings, code, past Slack threads — and synthesizing it into one coherent answer. Closer to a research project than "what's the pricing?" + +## What it will look like + + + + supermemory prepare a brief on how we've handled enterprise SSO requests over the last two quarters — who asked, what we promised, what's still open, and what engineering thinks the real effort is + + + **Enterprise SSO — two-quarter brief** + + - **Demand:** 6 serious asks (Acme, Globex, Initech, …). Three converted to paid pilots. + - **Promises made:** Okta + Azure AD for pilots; custom SAML called "roadmap" in two decks. + - **Still open:** Globex blocked on SCIM; Initech waiting on audit-log export. + - **Eng view:** ~6 weeks for Okta/Azure path (from `#eng` thread Mar 18 + Linear ENG-610); SCIM is the long pole. + + Sources: Q1/Q2 enterprise notes, Linear ENG-610, Granola "SSO planning", `#sales` threads. Want this as a Linear doc? + + + +## What's really going on + +Today, a single turn can already hit multiple [connectors](/company-brain/connectors) and channel memory in one answer. Long-horizon research is for the cases where that isn't enough — the work needs more time, more parallel digging, and a structured synthesis step before it replies. + +We're deliberately not documenting an internal "spawn N children" mechanism here. What matters for you: ask a research-shaped question, get a sourced brief back, without you having to run six separate searches. + +Until it ships, break big questions into smaller ones (docs, then tickets, then "summarize what we have") — Company Brain already handles each of those well. + + + + What single-turn knowledge recall looks like today. + + + Pulling decisions out of synced notes. + + diff --git a/apps/docs/company-brain/use-cases/meeting-recall.mdx b/apps/docs/company-brain/use-cases/meeting-recall.mdx new file mode 100644 index 00000000..2cf4c415 --- /dev/null +++ b/apps/docs/company-brain/use-cases/meeting-recall.mdx @@ -0,0 +1,38 @@ +--- +title: "Meeting Recall" +sidebarTitle: "Meeting Recall" +description: "Ask what was decided in a meeting and get the answer from synced notes" +icon: "calendar-check" +--- + +import { SlackThread, SlackMessage, Mention } from "/snippets/slack-message.mdx"; + +## The scenario + +Someone missed the Acme call — or was there and forgot the outcome. They ask in Slack and get the decision, with a path back to the source notes. + +## What happens + + + + supermemory what did we decide in the meeting with Acme? + + + Acme is moving to annual billing at the current rate, with a 90-day pilot on the enterprise SSO add-on. Follow-up owned by **Priya**, due Friday. *(from Granola notes, Acme QBR — Jun 11)* + + + +## What's really going on + +Meeting notes come in through a [connector](/company-brain/connectors) — Granola for live meeting notes, or Drive/Notion if notes land there. Once synced, they live in [public channel memory](/company-brain/permissions), so anyone on the team can ask about them. The answer cites the source so you can open the original notes and verify. + +Ask about a decision, an owner, a date, or "what did we promise them" — plain language is fine. + + + + Why meeting notes land in public channel memory. + + + Connect Granola, Drive, or Notion. + + diff --git a/apps/docs/company-brain/use-cases/meeting-scheduling.mdx b/apps/docs/company-brain/use-cases/meeting-scheduling.mdx new file mode 100644 index 00000000..5274e027 --- /dev/null +++ b/apps/docs/company-brain/use-cases/meeting-scheduling.mdx @@ -0,0 +1,42 @@ +--- +title: "Meeting Scheduling" +sidebarTitle: "Scheduling" +description: "Find free time and send a calendar invite from Slack" +icon: "calendar-plus" +--- + +import { SlackThread, SlackMessage, Mention } from "/snippets/slack-message.mdx"; + + +**Coming soon.** Calendar scheduling isn't in Company Brain yet — there's no calendar connector in the catalog today. This page shows the experience we're building toward, using a real exchange from our own team. + + +## The scenario + +A teammate needs help and doesn't want to play calendar ping-pong. They ask in Slack; Company Brain checks availability and offers to book the slot. + +## What it will look like + + + + Dhravya are you free this afternoon? need some help with dev setup + + + Dhravya is free at **2:00 PM**. Sending an invite to block **20 mins** on both your calendars. + + + +## What's really going on + +When this ships, it will be a [tool connector](/company-brain/connectors) against the calendar — same personal-vs-org rules and [write-under-your-account](/company-brain/permissions) attribution as Linear or GitHub. Creating an invite is a write, so it runs as the person who has the calendar connected (or via an explicit [lease](/company-brain/permissions#leasing-borrowing-access-for-one-request) if someone else is lending access for that one request). + +Until then: ask Company Brain for *context* around scheduling ("who's the right person for dev setup?" / "when did we last pair on this?") and book the time the usual way. + + + + How personal tools and leasing will apply to calendar. + + + Back to all scenarios — including what's shipped today. + + diff --git a/apps/docs/company-brain/use-cases/overview.mdx b/apps/docs/company-brain/use-cases/overview.mdx new file mode 100644 index 00000000..13742132 --- /dev/null +++ b/apps/docs/company-brain/use-cases/overview.mdx @@ -0,0 +1,47 @@ +--- +title: "What You Can Do" +sidebarTitle: "Overview" +description: "Real scenarios for Company Brain — from Slack answers to sandbox debugging" +icon: "sparkles" +--- + +Company Brain is most useful when it shows up in the work you already do. These walkthroughs are short, concrete scenarios — each one is a real exchange, what the bot is actually doing under the hood, and which concept page to read if you want the full picture. + +## Shipped today + + + + Customer question in Slack; Company Brain chimes in with the answer. + + + "Is prod down?" answered from live Sentry, plus scheduled digests. + + + "What did we decide with Acme?" from synced meeting notes. + + + Roadmaps, specs, and handbooks — asked in plain language. + + + List open PRs, create a Linear issue — under your own account. + + + Connect card, welcome DM, first answer — activation on day one. + + + Actually run the failing test in an isolated workspace. + + + +## Coming soon + + + + Questions that need many sources synthesized into one answer. + + + Find free time and send a calendar invite from Slack. + + + +If you're still setting things up, start with [What is Company Brain?](/company-brain/overview) and work through the Concepts section first — the walkthroughs assume those ideas. diff --git a/apps/docs/company-brain/use-cases/sandbox-debugging.mdx b/apps/docs/company-brain/use-cases/sandbox-debugging.mdx new file mode 100644 index 00000000..a3d70fb0 --- /dev/null +++ b/apps/docs/company-brain/use-cases/sandbox-debugging.mdx @@ -0,0 +1,49 @@ +--- +title: "Sandbox Debugging" +sidebarTitle: "Sandbox" +description: "Hand it a failing test — it runs the code in an isolated workspace and reports back" +icon: "terminal" +--- + +import { SlackThread, SlackMessage, Mention } from "/snippets/slack-message.mdx"; + +## The scenario + +A test is failing and the stack trace alone isn't enough. You want Company Brain to actually run the code, not just describe what it *would* do. + +## What happens + + + + supermemory the `permissions.lease` unit test is failing on main — can you reproduce and tell me why? + + + Reproduced in a sandbox against `main`. + + **Failure:** `permissions.lease` expects temporary access to expire in 15 minutes, but the fixture still asserts 30. + **Cause:** the default was shortened in `#1188`; the unit test wasn't updated. + **Fix:** point the assertion at the shared default so it can't drift again. + + + +## What's really going on + +Company Brain spins up an **isolated workspace**, checks out what it needs, runs the command, and reads the output. It's not guessing from static code alone — it's executing. + +Guardrails are intentional, so it's safe to hand real tasks to: + +- No `git push`, no deploys +- No elevated privileges (`sudo` and similar are blocked) +- No reaching arbitrary internal network addresses +- No long-running dev servers + +Think of it as a sealed workbench: useful for reproduce / inspect / explain loops, not for shipping changes on your behalf. + + + + When the next step is a Linear issue or a PR lookup. + + + All the scenario walkthroughs. + + diff --git a/apps/docs/company-brain/use-cases/support-escalation.mdx b/apps/docs/company-brain/use-cases/support-escalation.mdx new file mode 100644 index 00000000..4f4e825b --- /dev/null +++ b/apps/docs/company-brain/use-cases/support-escalation.mdx @@ -0,0 +1,81 @@ +--- +title: "From Support Ticket to Code Fix" +sidebarTitle: "Escalation" +description: "A Plain ticket gets triaged in Slack, and an @mention hands the fix to Cursor" +icon: "bug" +--- + +import { SlackThread, SlackMessage, Mention, FileAttachment, AgentLink, SlackUnfurl, SlackButton } from "/snippets/slack-message.mdx"; + +## The scenario + +A customer files a ticket through Plain. It lands in `#support`, gets triaged with context Company Brain already has lying around, and — instead of someone manually filing a bug and waiting — an @mention hands the whole thing straight to Cursor. + +## What happens + + + + New conversation: rewriteQuery param not working +
+ **Jordan Alvarez** (acme-corp.io) sent a **new message**. + + hi team, just tried the `rewriteQuery` param on the v3 search endpoint and it doesn't seem to actually do anything — tried a few different values, results look identical either way. can someone take a look + +
+ + Confirmed, this is a real one — a couple of people have also flagged it on GitHub over the last week. +
+
+ Quick context: v3 search is deprecated, but we've committed to legacy support through end of year, so it's still worth fixing rather than telling people to migrate. Most likely cause is a change Adam shipped last week to cut down query-rewrite costs — looks like it short-circuits before `rewriteQuery` gets applied in some cases. +
+
+ cursor can you take this one? Full context attached. +
+
+ +
+ + Agent thread started +
+ Reproducing against the v3 search test suite now. +
+ + Fixed — `rewriteQuery` was getting skipped by the new cost short-circuit whenever a query was already cached. Pushed on #2312. +
+
+ **Resolution:** +
+ • Scoped the short-circuit to skip only the rewrite step, not the whole `rewriteQuery` path +
+ • Added a regression test covering `rewriteQuery` against a cache hit +
+
+ **Repository:** `supermemoryai/mono` +
+
+ Open in Web + Open in Desktop +
+ + Dhravya I'll let you review that and let the customer know we have a fix ready. +
+ Please do it ASAP — it's an enterprise customer! +
+
+ +## What's really going on + +The first two turns are the same pattern as [Automatic Support](/company-brain/use-cases/support): the bot is already a member of `#support`, so it [chimes in](/company-brain/automations) unprompted, correlating the ticket against known GitHub issues and whatever it knows about the codebase and the v3 deprecation timeline. + +The handoff to Cursor is different. That's not a chime-in — it's an explicit `@mention`, and Cursor is wired in as a [tool connector](/company-brain/connectors) (a custom MCP server, same as GitHub or Linear under the hood) that can act, not just answer. Naming it by name is what triggers the write: Company Brain hands off the attached context and Cursor opens its own agent thread against the repo, the same way a mention of GitHub or Linear in [Acting in Tools](/company-brain/use-cases/acting-in-tools) triggers a write rather than a read. Nothing happens in the codebase without that explicit ask. + +Whether that handoff is even possible follows the same [permissions](/company-brain/permissions) rules as any other tool: it runs under whichever connection — personal or org-shared — is actually wired up for Cursor, and it's scoped to what that connection can see. + + + + How @mentions trigger writes instead of reads. + + + Wire up Plain, GitHub, and custom MCP servers like Cursor. + + diff --git a/apps/docs/company-brain/use-cases/support.mdx b/apps/docs/company-brain/use-cases/support.mdx new file mode 100644 index 00000000..72a2851f --- /dev/null +++ b/apps/docs/company-brain/use-cases/support.mdx @@ -0,0 +1,38 @@ +--- +title: "Automatic Support" +sidebarTitle: "Support" +description: "Company Brain chimes in on customer questions with answers from docs and tickets" +icon: "headset" +--- + +import { SlackThread, SlackMessage } from "/snippets/slack-message.mdx"; + +## The scenario + +A customer question lands in `#support`. Nobody has to @mention the bot — it already has the answer from past tickets and the help docs. + +## What happens + + + + customer on the Pro plan is asking if they can export their full memory graph as CSV — do we support that? + + + Yes — **Settings → Export → Full graph (CSV)**. Available on Pro and above. Same answer went out on ticket PLN-1842 last week if you want the exact wording. + + + +## What's really going on + +This is [proactiveness (chime-in)](/company-brain/automations) plus a connected support tool (Plain) and public channel memory. The bot is already a member of `#support` (an admin invited it — it never joins on its own). It decided the answer was clear enough to speak without being asked, pulled the export path from docs in public channel memory, and cited a recent ticket from Plain. + +Same channel scope rules apply: a public support channel writes durable learnings back to public channel memory; a private support channel keeps them scoped to that room's own memory. See [Permissions](/company-brain/permissions). + + + + How chime-in decides when to speak. + + + Wire up Plain and your help docs. + + diff --git a/apps/docs/concepts/container-tags.mdx b/apps/docs/concepts/container-tags.mdx index 71b8b0d7..0fa27719 100644 --- a/apps/docs/concepts/container-tags.mdx +++ b/apps/docs/concepts/container-tags.mdx @@ -1,6 +1,6 @@ --- title: "Container Tags" -sidebarTitle: "Container Tags" +sidebarTitle: "Container tags" description: "The isolation boundary that groups and partitions memories by user, project, or any logical scope" icon: "folder" --- @@ -32,7 +32,7 @@ await client.add({ }); // Later, retrieve only Alex's memories -const results = await client.search.memories({ +const results = await client.search({ q: "what are the user's UI preferences?", containerTag: "user_alex", }); @@ -103,7 +103,7 @@ The same tag flows through the entire lifecycle of a memory. Pass it consistentl await client.add({ content: "Q1 planning notes", containerTag: "project_q1" }); // Search within the same container -await client.search.memories({ q: "planning", containerTag: "project_q1" }); +await client.search({ q: "planning", containerTag: "project_q1" }); // List everything in the container await client.documents.list({ containerTags: ["project_q1"] }); @@ -170,7 +170,10 @@ Keep tags **deterministic** — derive them directly from IDs you already have ( Combine container tags with metadata filters for precise retrieval. - + + Mint keys that can only touch one container — multi-tenant clients without the org master key. + + See container tags in action across the add API. diff --git a/apps/docs/concepts/content-types.mdx b/apps/docs/concepts/content-types.mdx index 473fad67..9aafa528 100644 --- a/apps/docs/concepts/content-types.mdx +++ b/apps/docs/concepts/content-types.mdx @@ -1,11 +1,11 @@ --- title: "Supported Content Types" -sidebarTitle: "Content Types" +sidebarTitle: "Multi-modal ingestion" description: "All the content formats Supermemory can ingest and process" icon: "file-stack" --- -Supermemory automatically extracts and indexes content from various formats. Just send it—we handle the rest. See [Add Memories](/add-memories) to learn how to ingest content via the API. +Supermemory automatically extracts and indexes content from various formats. There are two entry points: `client.add()` for text and URLs, `client.documents.uploadFile()` for actual files. See [Add Memories](/ingestion/add-memories) to learn how to ingest content via the API. ## Text Content @@ -14,7 +14,7 @@ Raw text, conversations, notes, or any string content. ```typescript await client.add({ content: "User prefers dark mode and uses vim keybindings", - containerTags: ["user_123"] + containerTag: "user_123" }); ``` @@ -29,11 +29,11 @@ Send a URL and Supermemory fetches, extracts, and indexes the content. ```typescript await client.add({ content: "https://docs.example.com/api-reference", - containerTags: ["documentation"] + containerTag: "documentation" }); ``` -**Extracts:** Article text, headings, metadata. Strips navigation, ads, boilerplate. +**Extracts:** Article text, headings, metadata. Strips navigation, ads, boilerplate. URL extraction is powered by [Markdowner](https://md.dhr.wtf). --- @@ -41,11 +41,15 @@ await client.add({ ### PDF +Files are binary, so they go through `uploadFile`, not `add` — pass a stream, not base64: + ```typescript -await client.add({ - content: pdfBase64, - contentType: "pdf", - title: "Q4 Financial Report" +import fs from 'fs'; + +await client.documents.uploadFile({ + file: fs.createReadStream('report.pdf'), + containerTag: "user_123", + metadata: JSON.stringify({ title: "Q4 Financial Report" }) }); ``` @@ -53,17 +57,13 @@ await client.add({ ### Microsoft Office -| Format | Extension | Content Type | -|--------|-----------|--------------| -| Word | `.docx` | `docx` | -| Excel | `.xlsx` | `xlsx` | -| PowerPoint | `.pptx` | `pptx` | +Word, Excel, and PowerPoint files upload the same way — Supermemory detects the type from the file itself: ```typescript -await client.add({ - content: docxBase64, - contentType: "docx", - title: "Product Roadmap" +await client.documents.uploadFile({ + file: fs.createReadStream('roadmap.docx'), + containerTag: "user_123", + metadata: JSON.stringify({ title: "Product Roadmap" }) }); ``` @@ -78,18 +78,20 @@ Automatically handled via [Google Drive connector](/connectors/google-drive): ## Code & Markdown +Both are plain text, so they go through `add` like any other string content — no file upload needed: + ```typescript // Markdown await client.add({ content: markdownContent, - contentType: "md", - title: "README.md" + containerTag: "user_123", + metadata: { title: "README.md" } }); -// Code files (auto-detected language) +// Code (language auto-detected) await client.add({ content: codeContent, - contentType: "code", + containerTag: "user_123", metadata: { language: "typescript" } }); ``` @@ -102,11 +104,15 @@ Code is chunked using [code-chunk](https://github.com/supermemoryai/code-chunk), ## Images +`fileType: "image"` and `mimeType` are both required so Supermemory knows exactly how to process it: + ```typescript -await client.add({ - content: imageBase64, - contentType: "image", - title: "Architecture Diagram" +await client.documents.uploadFile({ + file: fs.createReadStream('diagram.png'), + fileType: "image", + mimeType: "image/png", + containerTag: "user_123", + metadata: JSON.stringify({ title: "Architecture Diagram" }) }); ``` @@ -118,19 +124,24 @@ await client.add({ ## Audio & Video +Video has a dedicated `fileType`; audio is uploaded the same way and detected from the file itself: + ```typescript -// Audio -await client.add({ - content: audioBase64, - contentType: "audio", - title: "Customer Call Recording" +// Video +await client.documents.uploadFile({ + file: fs.createReadStream('demo.mp4'), + fileType: "video", + mimeType: "video/mp4", + containerTag: "user_123", + metadata: JSON.stringify({ title: "Product Demo" }) }); -// Video -await client.add({ - content: videoBase64, - contentType: "video", - title: "Product Demo" +// Audio +await client.documents.uploadFile({ + file: fs.createReadStream('call-recording.mp3'), + mimeType: "audio/mpeg", + containerTag: "user_123", + metadata: JSON.stringify({ title: "Customer Call Recording" }) }); ``` @@ -142,13 +153,15 @@ await client.add({ ## Structured Data +JSON and CSV are text — stringify and send them through `add()`, no file upload needed. + ### JSON ```typescript await client.add({ content: JSON.stringify(userData), - contentType: "json", - title: "User Profile Data" + containerTag: "user_123", + metadata: { title: "User Profile Data", format: "json" } }); ``` @@ -157,8 +170,8 @@ await client.add({ ```typescript await client.add({ content: csvContent, - contentType: "csv", - title: "Sales Data Q4" + containerTag: "user_123", + metadata: { title: "Sales Data Q4", format: "csv" } }); ``` @@ -166,26 +179,33 @@ await client.add({ ## File Upload -For binary files, encode as base64: +For any binary file, use `uploadFile` — it accepts a stream, not base64: ```typescript -import { readFileSync } from 'fs'; +import fs from 'fs'; -const file = readFileSync('./document.pdf'); -const base64 = file.toString('base64'); - -await client.add({ - content: base64, - contentType: "pdf", - title: "document.pdf" +await client.documents.uploadFile({ + file: fs.createReadStream('./document.pdf'), + containerTag: "user_123", + metadata: JSON.stringify({ title: "document.pdf" }) }); ``` +No Node `fs` access? `uploadFile` also accepts a web `File`, a `fetch` `Response`, or the SDK's `toFile` helper: + +```typescript +import Supermemory, { toFile } from 'supermemory'; + +await client.documents.uploadFile({ file: new File(['my bytes'], 'file') }); +await client.documents.uploadFile({ file: await fetch('https://somesite/file') }); +await client.documents.uploadFile({ file: await toFile(Buffer.from('my bytes'), 'file') }); +``` + --- ## Auto-Detection -If you don't specify `contentType`, Supermemory auto-detects: +`add()` tells URLs and plain text apart on its own — no extra flag needed: ```typescript // URL detected automatically @@ -195,9 +215,7 @@ await client.add({ content: "https://example.com/page" }); await client.add({ content: "User said they prefer email contact" }); ``` - -For binary content (files), always specify `contentType` for reliable processing. - +For files, `uploadFile` detects type from the file itself in most cases. `fileType` only exists to force specific processing — and it's required (along with `mimeType`) for images and video. --- @@ -209,6 +227,8 @@ For binary content (files), always specify `contentType` for reliable processing | Files | 50MB | | URLs | Fetched content up to 10MB | +**Typical processing time:** text is near-instant; PDFs take 1-5s; images 2-10s; video 10s+; webpages 1-3s. Text content is chunked at the sentence level with a 2-sentence overlap between chunks. + For large files, consider chunking or using [connectors](/connectors/overview) for automatic sync. @@ -218,7 +238,7 @@ For large files, consider chunking or using [connectors](/connectors/overview) f ## Next Steps - + Upload content via the API diff --git a/apps/docs/concepts/customization.mdx b/apps/docs/concepts/customization.mdx index 73bf6ad2..122433ba 100644 --- a/apps/docs/concepts/customization.mdx +++ b/apps/docs/concepts/customization.mdx @@ -1,6 +1,6 @@ --- title: "Customizing for Your Use Case" -sidebarTitle: "Customization" +sidebarTitle: "Customizing" description: "Configure Supermemory's behavior for your specific application" icon: "settings-2" --- @@ -70,6 +70,16 @@ await client.settings.update({ +### Related settings + +`shouldLLMFilter` must be `true` for any of these to take effect — using them without it returns a 400 error. + +| Setting | Type | Limits | +|---------|------|--------| +| `categories` | `string[]` | 1-50 chars each. If omitted, 3-5 categories are auto-generated | +| `includeItems` / `excludeItems` | `string[]` | 1-20 chars each item | +| `filterPrompt` | `string` | 1-750 characters | + --- ## Entity Context @@ -193,7 +203,7 @@ Settings are organization-wide. Changes apply to new content only—existing mem ## Next Steps - + See your custom settings in action diff --git a/apps/docs/concepts/filtering.mdx b/apps/docs/concepts/filtering.mdx index d222e849..cb158583 100644 --- a/apps/docs/concepts/filtering.mdx +++ b/apps/docs/concepts/filtering.mdx @@ -1,8 +1,8 @@ --- title: "Organizing & Filtering Memories" -sidebarTitle: "Multi-Tenancy / Filtering" +sidebarTitle: "Metadata filtering" description: "Use container tags and metadata to organize and retrieve memories" -icon: "users" +icon: "filter" --- Supermemory provides two ways to organize your memories: @@ -29,21 +29,22 @@ Container tags create isolated memory spaces. Use them to separate memories by u ```typescript await client.add({ content: "Meeting notes from Q1 planning", - containerTags: ["user_123"] + containerTag: "user_123" }); ``` ### Searching with Tags ```typescript -const results = await client.search.documents({ +const results = await client.search({ q: "planning notes", - containerTags: ["user_123"] + containerTag: "user_123", + searchMode: "documents" }); ``` -Container tags use **exact array matching**. A memory tagged `["user_123", "project_a"]` won't match a search for just `["user_123"]`. +Each search is scoped to a single container tag. Passing `containerTag: "user_123"` restricts results to memories stored in that container. ### Recommended Patterns @@ -60,34 +61,34 @@ Container tags use **exact array matching**. A memory tagged `["user_123", "proj // Multi-tenant SaaS - isolate by organization and user await client.add({ content: "Company policy document", - containerTags: ["org_acme_user_john"] + containerTag: "org_acme_user_john" }); // Search only within that user's org context - const results = await client.search.documents({ + const results = await client.search({ q: "vacation policy", - containerTags: ["org_acme_user_john"] + containerTag: "org_acme_user_john", + searchMode: "documents" }); // Project-based isolation await client.add({ content: "Sprint 5 retrospective notes", - containerTags: ["project_mobile_app"] + containerTag: "project_mobile_app" }); // Time-based segmentation await client.add({ content: "Q1 2024 financial report", - containerTags: ["user_cfo_2024_q1"] + containerTag: "user_cfo_2024_q1" }); ``` **API field differences:** - | Endpoint | Field | Type | - |----------|-------|------| - | `/v3/search` | `containerTags` | Array | - | `/v4/search` | `containerTag` | String | - | `/v3/documents/list` | `containerTags` | Array | + | Operation | Field | Type | + |-----------|-------|------| + | Search | `containerTag` | String | + | Documents list | `containerTags` | Array | @@ -102,7 +103,7 @@ Metadata lets you attach custom properties to memories and filter by them later. ```typescript await client.add({ content: "Technical design document for auth system", - containerTags: ["user_123"], + containerTag: "user_123", metadata: { category: "engineering", priority: "high", @@ -116,9 +117,10 @@ await client.add({ Filters must be wrapped in `AND` or `OR` arrays: ```typescript -const results = await client.search.documents({ +const results = await client.search({ q: "design document", - containerTags: ["user_123"], + containerTag: "user_123", + searchMode: "documents", filters: { AND: [ { key: "category", value: "engineering" }, @@ -142,8 +144,9 @@ const results = await client.search.documents({ Use `AND` and `OR` for complex queries: ```typescript -const results = await client.search.documents({ +const results = await client.search({ q: "meeting notes", + searchMode: "documents", filters: { AND: [ { key: "type", value: "meeting" }, @@ -163,8 +166,9 @@ const results = await client.search.documents({ Use `negate: true` to exclude matches: ```typescript -const results = await client.search.documents({ +const results = await client.search({ q: "documentation", + searchMode: "documents", filters: { AND: [ { key: "status", value: "draft", negate: true } @@ -178,8 +182,9 @@ const results = await client.search.documents({ **String contains (substring search):** ```typescript // Find documents with "machine learning" in the description - const results = await client.search.documents({ + const results = await client.search({ q: "AI research", + searchMode: "documents", filters: { AND: [ { @@ -196,8 +201,9 @@ const results = await client.search.documents({ **Numeric comparisons:** ```typescript // Find high-priority items created after a specific date - const results = await client.search.documents({ + const results = await client.search({ q: "tasks", + searchMode: "documents", filters: { AND: [ { @@ -220,8 +226,9 @@ const results = await client.search.documents({ **Array contains (check array membership):** ```typescript // Find documents where a specific user is a participant - const results = await client.search.documents({ + const results = await client.search({ q: "meeting notes", + searchMode: "documents", filters: { AND: [ { @@ -237,8 +244,9 @@ const results = await client.search.documents({ **Complex nested filters:** ```typescript // (category = "tech" OR category = "science") AND status != "archived" - const results = await client.search.documents({ + const results = await client.search({ q: "research papers", + searchMode: "documents", filters: { AND: [ { @@ -265,9 +273,10 @@ const results = await client.search.documents({ **User's work documents from 2024:** ```typescript - const results = await client.search.documents({ + const results = await client.search({ q: "quarterly report", - containerTags: ["user_123"], + containerTag: "user_123", + searchMode: "documents", filters: { AND: [ { key: "category", value: "work" }, @@ -280,9 +289,10 @@ const results = await client.search.documents({ **Team meeting notes with specific participants:** ```typescript - const results = await client.search.documents({ + const results = await client.search({ q: "sprint planning", - containerTags: ["project_alpha"], + containerTag: "project_alpha", + searchMode: "documents", filters: { AND: [ { key: "type", value: "meeting" }, @@ -299,8 +309,9 @@ const results = await client.search.documents({ **Exclude drafts and deprecated content:** ```typescript - const results = await client.search.documents({ + const results = await client.search({ q: "documentation", + searchMode: "documents", filters: { AND: [ { key: "status", value: "draft", negate: true }, @@ -322,7 +333,7 @@ const results = await client.search.documents({ ```typescript await client.add({ content: "Your content here", - containerTags: ["user_123"], // Isolation + containerTag: "user_123", // Isolation metadata: { key: "value" } // Custom properties }); ``` @@ -330,9 +341,10 @@ await client.add({ ### When Searching ```typescript -const results = await client.search.documents({ +const results = await client.search({ q: "search query", - containerTags: ["user_123"], // Must match exactly + containerTag: "user_123", // Scopes results to this container + searchMode: "documents", filters: { // Optional metadata filters AND: [{ key: "status", value: "published" }] } @@ -345,15 +357,35 @@ const results = await client.search.documents({ - Max length: 64 characters - No spaces or special characters +### Query Complexity Limits + +- Maximum 200 conditions per query +- Maximum 8 levels of nested `AND`/`OR` expressions + + +If you need more conditions than these limits allow, break your query into multiple requests or use broader search terms with post-processing. + + +### Searching Within a Document + +Use `docId` to scope a search to chunks within one large document — useful for books, podcasts, or other long-form content: + +```typescript +const results = await client.search({ + q: "machine learning", + docId: "doc_123" +}); +``` + --- ## Next Steps - + Apply filters in search queries - + Add content with container tags and metadata diff --git a/apps/docs/concepts/graph-memory.mdx b/apps/docs/concepts/graph-memory.mdx index 9080ce4f..3430cc95 100644 --- a/apps/docs/concepts/graph-memory.mdx +++ b/apps/docs/concepts/graph-memory.mdx @@ -1,146 +1,189 @@ --- -title: "How Graph Memory Works" -sidebarTitle: "Graph Memory" -description: "Automatic memory evolution, knowledge updates, and intelligent forgetting" +title: "Graph memory" +sidebarTitle: "Graph memory" +description: "How facts connect, update, and stay true — memory relationships, temporal truth, and automatic forgetting." icon: "vector-square" --- -Supermemory builds a living knowledge graph where memories connect to other memories. Unlike traditional knowledge graphs with entity-relation-entity triples, Supermemory's graph is **facts built on top of other facts**. +**How understanding is stored and stays true over time.** -## Memory Relationships +Supermemory builds a **living knowledge graph of facts on top of other facts** — not a static folder of embeddings, and not classic entity–relation–entity triples you maintain by hand. -When you add content, Supermemory extracts facts and automatically connects them to existing memories through three relationship types: +The **pipeline** that turns a chat or file into memories is [How it works](/concepts/how-it-works). -### Updates: Information Changes +This page is the **model**: what a memory is, how edges form, and why agents utilize supermemory's graph -When new information contradicts existing knowledge: +## Try it -``` -Memory 1: "Alex works at Google as a software engineer" -Memory 2: "Alex just started at Stripe as a PM" - ↓ -Memory 2 UPDATES Memory 1 -``` - -The system tracks which memory is latest with `isLatest`, so searches return current information while preserving history. - -### Extends: Information Enriches - -When new information adds detail without replacing: - -``` -Memory 1: "Alex works at Stripe as a PM" -Memory 2: "Alex focuses on payments infrastructure and leads a team of 5" - ↓ -Memory 2 EXTENDS Memory 1 -``` - -Both memories remain valid—searches get richer context. - -### Derives: Information Infers - -When Supermemory infers new facts from patterns: - -``` -Memory 1: "Alex is a PM at Stripe" -Memory 2: "Alex frequently discusses payment APIs and fraud detection" - ↓ -Derived: "Alex likely works on Stripe's core payments product" -``` - -These inferences surface insights you didn't explicitly state. - ---- - -## Automatic Memory Extraction - -From a single conversation, Supermemory extracts multiple connected memories: - -**Input:** -> "Had a great call with Alex. He's enjoying the new PM role at Stripe, though the -> payments infrastructure work is intense. He moved to Seattle for the job—got a -> place in Capitol Hill. Wants to grab dinner next time I'm in town." - -**Extracted memories:** -- Alex works at Stripe as a PM -- Alex works on payments infrastructure *(extends role memory)* -- Alex lives in Seattle, Capitol Hill *(new fact)* -- Alex wants to meet for dinner *(episodic)* - -Each fact is connected to related memories automatically. - ---- - -## Automatic Forgetting - -Supermemory knows when memories become irrelevant: - -**Time-based forgetting**: Temporary facts are automatically forgotten when they expire. - -``` -"I have an exam tomorrow" - ↓ - After the exam date passes → automatically forgotten - -"Meeting with Alex at 3pm today" - ↓ - After today → automatically forgotten -``` - -**Contradiction resolution**: When new facts contradict old ones, the Update relationship ensures searches return current information. - -**Noise filtering**: Casual, non-meaningful content doesn't become permanent memories. - ---- - -## Memory Types - -Supermemory distinguishes memory types automatically: - -| Type | Example | Behavior | -|------|---------|----------| -| **Facts** | "Alex is a PM at Stripe" | Persists until updated | -| **Preferences** | "Alex prefers morning meetings" | Strengthens with repetition | -| **Episodes** | "Met Alex for coffee Tuesday" | Decays unless significant | - ---- - -## What You Don't Do - -All of this is automatic. You don't: -- Define relationships manually -- Tag memory types -- Clean up old memories -- Resolve contradictions - -Just add content and search naturally: +Get a key from the [developer console](https://console.supermemory.ai) — **API Keys → Create API Key** — then add a memory and pull it back with related edges: ```typescript +import Supermemory from "supermemory"; + +const client = new Supermemory({ apiKey: "sm_..." }); // from console.supermemory.ai → API Keys + await client.add({ - content: "Alex mentioned he just started at Stripe" + content: "Alex mentioned he just started at Stripe", + containerTag: "user_123", }); const results = await client.search({ - query: "where does Alex work?" + q: "where does Alex work?", + containerTag: "user_123", + include: { relatedMemories: true }, }); -// → Stripe (latest), previously Google (historical) ``` ---- +Full walkthrough with a live example: [Quickstart](/quickstart). -## Learn More +![](/images/graph-view.png) + +## Documents vs memories + +| | **Documents** | **Memories** | +|---|---|---| +| **What** | Raw input you send | Facts Supermemory extracts | +| **Examples** | PDF, chat log, Drive file, URL | “Alex is a PM at Stripe” | +| **Role** | Source of truth for RAG / SuperRAG | Personal and entity state over time | +| **Lifecycle** | You add / update / delete | Graph updates, extends, derives, forgets | + +Think of documents as books you hand the system. Memories are the insights it keeps — connected to each other as new content arrives. + + +Uploading a long PDF does more than store bytes: Supermemory derives many memories and links them to what it already knows about that entity or user. Chunks of the document remain available for [SuperRAG](/concepts/super-rag) grounding. + + +## Properties and rules of memories + +1. Memories are atomic - Each memory has enough information and context about one particular topic +2. They always build on top of each other - with `updates`, the model knows the history, a memory `extends` from other memories, and new facts are derived (`derives` relation) from existing knowledg.e + +## Memory relationships + +![](/images/memories-inferred.png) + +When content is processed, new facts connect to existing ones through three relationship types. + +### Updates — information changes + +New fact **replaces** what was true before for search purposes; history can remain for audit. + +```text +Memory 1: "Alex works at Google as a software engineer" +Memory 2: "Alex just started at Stripe as a PM" + → Memory 2 UPDATES Memory 1 +``` + +`isLatest` (and related graph fields) keep retrieval on the current fact without erasing the past. + +### Extends — information enriches + +New fact **adds detail** without invalidating the old one. + +```text +Memory 1: "Alex works at Stripe as a PM" +Memory 2: "Alex focuses on payments and leads a team of 5" + → Memory 2 EXTENDS Memory 1 +``` + +Both stay valid; context gets richer. + +### Derives — information infers + +Supermemory **infers** a fact you never stated in one place, from patterns across memories. + +```text +Memory 1: "Alex is a PM at Stripe" +Memory 2: "Alex frequently discusses payment APIs and fraud detection" + → Derived: "Alex likely works on Stripe's core payments product" +``` + +That is the same class of “entity chain” you see in the [quickstart](/quickstart) (gift → VP of Product → Sarah → Tokyo offsite). Search can expose edges via `include.relatedMemories` — see [Search API](/recall/search). + +## Automatic extraction (one input → many facts) + +**Input:** + +> Had a great call with Alex. He's enjoying the new PM role at Stripe, though the payments work is intense. He moved to Seattle for the job—Capitol Hill. Wants dinner next time I'm in town. + +**Example extracted memories:** + +- Alex works at Stripe as a PM +- Alex works on payments infrastructure *(extends role)* +- Alex lives in Seattle, Capitol Hill +- Alex wants to meet for dinner *(episodic)* + +You do not define schema or draw edges. You [add content](/ingestion/add-memories); the graph updates. + +## Dreaming keeps the graph alive + +Ingest is not a one-shot snapshot. After (and alongside) indexing, **dreaming** continues building the graph: extracting facts, linking related memories, resolving updates, and producing derives you never stated in one place. + +By default Supermemory uses **`dreaming: "dynamic"`** — related documents are grouped so memories form from **coherent units** (e.g. a real multi-turn session), not each isolated write in isolation. That is why production quality is higher when you keep a stable `customId` on conversations and let dynamic dreaming do its job. + +Use **`dreaming: "instant"`** when this document must hit the graph immediately (demos, “search right after add”). That path processes the document alone and costs an extra operation. + +How to set the flag, statuses, and when `done` means what: [How it works → Dreaming](/concepts/how-it-works#dreaming-how-memories-enter-the-graph) and [Processing modes](/ingestion/add-memories#processing-modes). + +## Memory types + +| Type | Example | Behavior | +| --- | --- | --- | +| **Facts** | “Alex is a PM at Stripe” | Persists until updated | +| **Preferences** | “Alex prefers morning meetings” | Strengthens with repetition | +| **Episodes** | “Met Alex for coffee Tuesday” | Decays unless significant | + +## Automatic forgetting + +- **Time-based** — temporary facts drop after they expire (“exam tomorrow”, “meeting at 3pm today”). +- **Contradiction** — updates win for “what’s true now.” +- **Noise filtering** — casual, non-meaningful chatter is less likely to become durable memory. + +For explicit product controls (forget, review low-confidence derives), see [Forget & update](/recall/memory-operations) and [Memory review](/recall/memory-review). + +## What you don’t do + +You do **not** hand-maintain the graph. You: + +1. Ingest under a [container tag](/concepts/container-tags) +2. Wait for the [pipeline](/concepts/how-it-works) when needed +3. [Search](/recall/search) or load a [profile](/recall/user-profiles) + +```typescript +await client.add({ + content: "Alex mentioned he just started at Stripe", + containerTag: "user_123", +}); + +const results = await client.search({ + q: "where does Alex work?", + containerTag: "user_123", + include: { relatedMemories: true }, +}); +// Prefer latest work fact (Stripe); history remains in the graph +``` + +## Related in the docs + +| If you need… | Go to | +| --- | --- | +| Pipeline statuses, dreaming, documents in | [How it works](/concepts/how-it-works) | +| Memory vs document retrieval | [Memory vs RAG](/concepts/memory-vs-rag) · [SuperRAG](/concepts/super-rag) | +| Always-on summary of a user | [Profiles](/concepts/user-profiles) | +| Isolation / tenants | [Multi-tenancy](/concepts/container-tags) | +| API: add / search / forget | [Ingestion](/ingestion/add-memories) · [Search](/recall/search) · [Forget & update](/recall/memory-operations) | - - Deep dive into the architecture + + Ingest pipeline, statuses, and outputs. - When to use memory vs document retrieval + When to use memory vs document retrieval. - - Automatic summaries from the graph + + Static + dynamic context built from the graph. - - Start building your knowledge graph + + See entity chains in a full conversation + document flow. diff --git a/apps/docs/concepts/how-it-works.mdx b/apps/docs/concepts/how-it-works.mdx index 9404347d..39bb9328 100644 --- a/apps/docs/concepts/how-it-works.mdx +++ b/apps/docs/concepts/how-it-works.mdx @@ -1,152 +1,182 @@ --- title: "How Supermemory Works" -description: "Understanding the knowledge graph architecture that powers intelligent memory" +sidebarTitle: "How it works" +description: "From a file or chat turn to something you can search — the ingest pipeline, statuses, and outputs." icon: "cpu" --- - -Supermemory isn't just another document storage system. It's designed to mirror how human memory actually works - forming connections, evolving over time, and generating insights from accumulated knowledge. - -![](/images/graph-view.png) - -## The Mental Model - -Traditional systems store files. Supermemory creates a living knowledge graph. +At it's core, supermemory is powered by a custom learning model and a graph database that we built internally. - - - Static files in folders - - No connections between content - - Search matches keywords - - Information stays frozen + + Decides what and how to learn, what is important, when to forget, creating relations, etc. - - - - Dynamic knowledge graph - - Rich relationships between memories - - Semantic understanding - - Information evolves and connects + + Where the learnings are actually stored, optimized for search. Fact-based temporal graph that has Vector, FTS, and graph built in. -## Documents vs Memories +But, you don't have to think about the above. The interface for users is as simple as it gets. -Understanding this distinction is crucial to using Supermemory effectively. - -### Documents: Your Raw Input - -Documents are what you provide - the raw materials: -- PDF files you upload -- Web pages you save -- Text you paste -- Images with text -- Videos to transcribe - -Think of documents as books you hand to Supermemory. See [Content Types](/concepts/content-types) for the full list of supported formats. - -### Memories: Intelligent Knowledge Units - -Memories are what Supermemory creates - the understanding: -- Semantic chunks with meaning -- Embedded for similarity search -- Connected through relationships -- Dynamically updated over time - -Think of memories as the insights and connections your brain makes after reading those books. - - -**Key Insight**: When you upload a 50-page PDF, Supermemory doesn't just store it. It breaks it into hundreds of interconnected memories, each understanding its context and relationships to your other knowledge. - - - -## Memory Relationships - -![](/images/memories-inferred.png) - -The graph connects memories through three types of relationships. For a deeper dive into how these relationships work, see [Graph Memory](/concepts/graph-memory). - -### Updates: Information Changes - -When new information contradicts or updates existing knowledge, Supermemory creates an "update" relationship. - - -```text Original Memory -"You work at Supermemory as a content engineer" -``` - -```text New Memory (Updates Original) -"You now work at Supermemory as the CMO" -``` - - -The system tracks which memory is latest with an `isLatest` field, ensuring searches return current information. - -### Extends: Information Enriches - -When new information adds to existing knowledge without replacing it, Supermemory creates an "extends" relationship. - -Continuing our "working at supermemory" analogy, a memory about what you work on would extend the memory about your role given above. - - -```text Original Memory -"You work at Supermemory as the CMO" -``` - -```text New Memory (Extension) - Separate From Previous -"Your work consists of ensuring the docs are up to date, making marketing campaigns, SEO, etc." -``` - - -Both memories remain valid and searchable, providing richer context. - -### Derives: Information Infers - -The most sophisticated relationship - when Supermemory infers new connections from patterns in your knowledge. - - -```text Memory 1 -"Dhravya is the founder of Supermemory" -``` - -```text Memory 2 -"Dhravya frequently discusses AI and machine learning innovations" -``` - -```text Derived Memory -"Supermemory is likely an AI-focused company" -``` - - -These inferences help surface insights you might not have explicitly stated. - -## Processing Pipeline - -Understanding the pipeline helps you optimize your usage: - -| Stage | What Happens | -|-------|-------------| -| **Queued** | Document waiting to process -| **Extracting** | Content being extracted | -| **Chunking** | Creating memory chunks | -| **Embedding** | Generating vectors | -| **Indexing** | Building relationships | -| **Done** | Fully searchable | - - -**Tip**: Larger documents and videos take longer. A 100-page PDF might take 1-2 minutes, while a 1-hour video could take 5-10 minutes. - - - -## Next Steps - -Now that you understand how Supermemory works: +## Get started in under a minute - - Start adding content to your knowledge graph + + From the [developer console](https://console.supermemory.ai) — **API Keys → Create API Key**. `console.supermemory.ai` is where keys and usage live. - - - Learn to query your knowledge effectively + + Install the SDK, drop in your key, add a memory, and search it — right below, or the full [ingest → retrieve loop](/using-supermemory). + + + + +```bash TypeScript +npm install supermemory +``` + +```typescript TypeScript +import Supermemory from "supermemory"; + +const client = new Supermemory({ apiKey: "sm_..." }); // from console.supermemory.ai → API Keys + +await client.add({ content: "The user loves Paris.", containerTag: "user_123" }); + +const { results } = await client.search({ + q: "where does the user want to travel?", + containerTag: "user_123", +}); +``` + +```python Python +from supermemory import Supermemory + +client = Supermemory(api_key="sm_...") # from console.supermemory.ai → API Keys + +client.add(content="The user loves Paris.", container_tag="user_123") + +results = client.search( + q="where does the user want to travel?", + container_tag="user_123", +) +``` + +```bash curl +curl -X POST https://api.supermemory.ai/v3/documents \ + -H "Authorization: Bearer sm_..." \ + -H "Content-Type: application/json" \ + -d '{ + "content": "The user loves Paris.", + "containerTag": "user_123" + }' +``` + + +## What you send: documents + +A **document** is raw input — whatever you hand Supermemory: + +- Conversation transcripts and messages +- Text, markdown, HTML +- PDFs, images, audio/video, code +- URLs and connector items (Drive, Notion, Gmail, …) + +You do not pre-chunk or pick an embedding model. See [Multi-modal ingestion](/concepts/content-types) for formats, and [Add context](/ingestion/add-memories) for the API. + +Supermemory handles the ingestion and extraction for you. This also gives us a big advantage for quality - The engine extracts it in an optimized way with Contextual Chunking and other features for better quality search and memory generation. + +> Use a stable **`customId`** when the same conversation or file will be updated later (sessions, connector syncs). That identity also drives [diff billing](/overview/billing#full-discount-on-already-seen-tokens-diff-billing) on re-ingest. + +## What the pipeline does + +| Stage | What happens | +| --- | --- | +| **Queued** | Accepted; waiting to run | +| **Extracting** | Text / OCR / transcription / page fetch | +| **Chunking** | Splits content for retrieval (type-aware where needed) | +| **Embedding** | Vectors for similarity search | +| **Indexing** | Makes chunks and derived structure searchable | +| **Done** | Document path is ready for search | + +```typescript +const doc = await client.add({ + content: conversationText, + containerTag: "user_123", + customId: "chat_session_1", +}); + +// Poll until ready +const status = await client.documents.get(doc.id); +// status.status → "queued" | "extracting" | ... | "done" | "failed" +``` + +Larger PDFs and long video take longer. Short chat turns usually finish in seconds. + +## Dreaming (how memories enter the graph) + +Document **status `done`** means chunks are indexed for search. **Memories** — the graph facts, updates, and derives — come from a second phase called **dreaming**. + +This is when the content is passed through the memory model and merged, arranged and organized for the future. + +Pass `dreaming` on [add](/ingestion/add-memories): + +| Mode | Default? | Behavior | When to use | +| --- | --- | --- | --- | +| **`dynamic`** | Yes | Related documents are grouped so memories form from **coherent units**, not one isolated write at a time. Graph quality is higher for real multi-turn / multi-doc flows. Memory extraction may continue **after** `status: "done"`. | Production agents, connectors, ongoing sessions | +| **`instant`** | No | This document is dreamed **on its own, right away**. Memories are available as soon as processing finishes for that doc. Bills **one extra [operation](/overview/billing)** per document. | Demos, quickstarts, “I need the graph now” | + +```typescript +// Production default — omit or set explicitly +await client.add({ + content: conversationText, + containerTag: "user_123", + customId: "chat_session_1", + dreaming: "dynamic", +}); + +// Need memories immediately (e.g. tutorial) +await client.add({ + content: conversationText, + containerTag: "user_123", + customId: "chat_session_1", + dreaming: "instant", +}); +``` + +**Rule of thumb:** prefer **`dynamic`** for quality and cost in real apps, use **`instant`** when the next step is a memory search or profile that must reflect this document immediately (as in the [quickstart](/quickstart)). Keeping it dynamic helps it pair better with other memories and better connections, inferences to be made. + +How those memories connect and stay true over time is [Graph memory](/concepts/graph-memory). API detail: [Processing modes](/ingestion/add-memories#processing-modes). + +## What you get out + +After the pipeline runs, the same document leads to three things -> Chunks, Memories and Profile. (in the same `containerTag`): + +| Output | Role | Go deeper | +| --- | --- | --- | +| **Document chunks** | Grounding in the raw source (RAG / SuperRAG) | [SuperRAG](/concepts/super-rag), [Search API](/recall/search) | +| **Memories** | Extracted facts in a living graph — updates, links, time | [Graph memory](/concepts/graph-memory) | +| **Profile** | A sample of memories, static + dynamic summary for always-on context | [Profiles](/concepts/user-profiles), [Profile API](/recall/user-profiles) | + +Supermemory does **not** only store the file. It derives **memories** (understanding) and keeps **chunks** (the source) so you can personalize *and* ground. That distinction is the core of [Memory vs RAG](/concepts/memory-vs-rag). + +## Isolation and identity + +- **`containerTag`** — hard isolation boundary (user, tenant, project). See [Container tags](/concepts/container-tags). +- **Metadata** — soft dimensions *inside* a tag for filtering. See [Metadata filtering](/concepts/filtering). +- **Scoped API keys** — credentials that cannot cross a container. See [API keys](/authentication#scoped-api-keys). + +## Next steps + + + + How facts connect, update, and stay true over time. + + + Formats, extractors, and what you can send. + + + API: add, customId, files, dreaming, status. + + + Query documents and memories after the pipeline finishes. diff --git a/apps/docs/concepts/memory-vs-rag.mdx b/apps/docs/concepts/memory-vs-rag.mdx index bc08e94f..2ef9ea08 100644 --- a/apps/docs/concepts/memory-vs-rag.mdx +++ b/apps/docs/concepts/memory-vs-rag.mdx @@ -216,10 +216,10 @@ client.add( ### 3. Hybrid Retrieval ```python # Search combines both approaches -results = client.documents.search( - query="What phone should I recommend?", - container_tags=["user_123"], # Gets user memories - # Also searches general knowledge +results = client.search.memories( + q="What phone should I recommend?", + container_tag="user_123", # Gets user memories + search_mode="hybrid", # Also searches general knowledge ) # Results include: @@ -250,10 +250,10 @@ Supermemory provides both capabilities in a unified platform, ensuring your agen Our managed RAG solution - + Start ingesting content - + Query your memories and documents diff --git a/apps/docs/concepts/multi-tenancy-examples.mdx b/apps/docs/concepts/multi-tenancy-examples.mdx new file mode 100644 index 00000000..86074ed0 --- /dev/null +++ b/apps/docs/concepts/multi-tenancy-examples.mdx @@ -0,0 +1,134 @@ +--- +title: "Multi-tenancy Examples" +sidebarTitle: "Examples" +description: "Common container tag and metadata patterns for personal agents, company agents, email assistants, and support platforms" +icon: "list-checks" +--- + +A few common shapes multi-tenancy takes in practice, combining [container tags](/concepts/container-tags) for isolation with [metadata filters](/concepts/filtering) for organization within a boundary. + +--- + +## Personal agent + +A single container tag per user is enough — there's no shared data to leak, so metadata is optional. + +```typescript +await client.add({ + content: "User prefers morning workouts and vegetarian meals", + containerTag: "user_123", +}); + +const results = await client.search({ + q: "workout preferences", + containerTag: "user_123", +}); +``` + +--- + +## Company agent (shared + personal memory) + +A company-wide assistant usually needs two kinds of containers: one **shared** container the whole org reads from, and one **personal** container per employee that nobody else can see. + +```typescript +// Shared org knowledge — visible to everyone at the company +await client.add({ + content: "Q3 roadmap: ship the mobile app redesign by end of August", + containerTag: "org_acme_shared", + metadata: { team: "product", type: "roadmap" }, +}); + +// Personal memory — only this employee's agent should see this +await client.add({ + content: "Prefers async updates over meetings", + containerTag: "org_acme_user_alex", +}); +``` + +Inside the shared container, use metadata to scope queries to a team rather than creating a container tag per team: + +```typescript +const results = await client.search({ + q: "roadmap updates", + containerTag: "org_acme_shared", + searchMode: "documents", + filters: { + AND: [{ key: "team", value: "product" }], + }, +}); +``` + +An employee's agent typically queries both containers — their personal one plus the shared one — and merges the results, since the container tag boundary is per-request rather than per-user. + +--- + +## Email assistant + +One container tag per user, with metadata carrying email-specific properties like label, sender, or folder — so the assistant can answer things like *"find the Spotify email tagged Promotional"*. + +```typescript +await client.add({ + content: "Your Spotify Premium receipt for July — $11.99 charged", + containerTag: "user_123", + metadata: { + source: "gmail", + sender: "no-reply@spotify.com", + label: "Promotional", + }, +}); + +const results = await client.search({ + q: "spotify", + containerTag: "user_123", + searchMode: "documents", + filters: { + AND: [ + { key: "source", value: "gmail" }, + { key: "label", value: "Promotional" }, + ], + }, +}); +``` + +--- + +## Multi-tenant support platform + +Each customer gets their own container tag, and metadata tracks ticket-level fields like status and priority — so "open, high-priority tickets" is a filter, not a new tag, and it can never accidentally include another customer's tickets. + +```typescript +await client.add({ + content: "Customer reports checkout button unresponsive on Safari", + containerTag: "org_customer_442", + metadata: { status: "open", priority: "high", channel: "chat" }, +}); + +const results = await client.search({ + q: "checkout issue", + containerTag: "org_customer_442", + searchMode: "documents", + filters: { + AND: [ + { key: "status", value: "open" }, + { key: "priority", value: "high" }, + ], + }, +}); +``` + +--- + +## Next steps + + + + Why container tags and metadata are separate mechanisms. + + + How isolation works, naming rules, and access control. + + + Metadata filter types, combining `AND`/`OR`, and query limits. + + diff --git a/apps/docs/concepts/multi-tenancy.mdx b/apps/docs/concepts/multi-tenancy.mdx new file mode 100644 index 00000000..9d6a9e04 --- /dev/null +++ b/apps/docs/concepts/multi-tenancy.mdx @@ -0,0 +1,114 @@ +--- +title: "Multi-tenancy Overview" +sidebarTitle: "Overview" +description: "How Supermemory isolates and organizes memories across users, tenants, and projects" +icon: "users" +--- + +Most apps built on Supermemory serve more than one user, customer, or tenant out of a single Supermemory organization. Multi-tenancy is how you keep those memories apart — so User A's data is never visible to User B, and so you can still slice and query within a user's own data by things like category, status, or date. + +Supermemory gives you two complementary tools for this: + + + + **Isolation.** A container tag is a hard boundary — its own namespace. Memories in one tag are never returned by a search scoped to another tag. + + + **Organization.** Metadata is a set of custom key/value properties on a memory that you filter by — category, priority, date, participants, anything you define. + + + +They solve different problems, and most production apps use both together. + +--- + +## Why two mechanisms + +It's tempting to reach for one tool and make it do everything, but tags and metadata aren't interchangeable — they answer different questions. + +| Question | Answer | +|----------|--------| +| "Which tenant does this memory belong to?" | **Container tag** | +| "Within this tenant's memories, which ones match `status: open`?" | **Metadata filter** | +| "Can this API key even see tenant X's data?" | **Container tag** (enforced as an access boundary) | +| "Find memories tagged `engineering` created after March" | **Metadata filter** | + +A container tag decides **whether a memory is reachable at all** for a given request. Metadata decides **which of the reachable memories match**. Filtering never crosses a container tag boundary — you can't use metadata to peek into another tenant's container. + +--- + +## How they work together + +A typical multi-tenant write scopes the memory to a tenant with a container tag, then attaches metadata for finer-grained querying later: + +```typescript +await client.add({ + content: "Customer requested a refund for order #4821", + containerTag: "org_acme", // isolates to the "acme" tenant + metadata: { + category: "support", + status: "open", + priority: "high", + }, +}); +``` + +And a search combines both: the container tag restricts *which tenant's data* is in scope, and filters narrow down *which memories within that tenant* come back: + +```typescript +const results = await client.search({ + q: "refund request", + containerTag: "org_acme", + searchMode: "documents", + filters: { + AND: [ + { key: "category", value: "support" }, + { key: "status", value: "open" }, + ], + }, +}); +``` + + +Container tags are **required** for isolation and validated as an access boundary. Metadata filters are **optional** — a search with just `containerTag` and no `filters` still only returns that tenant's memories. + + +--- + +## Choosing your boundary + +Container tags are the layer that should map to your actual tenancy model — pick the level that matches what "one isolated space" means in your app: + +| Pattern | Example | Use case | +|---------|---------|----------| +| Per-user | `user_{userId}` | Consumer app, personal memory per user | +| Per-tenant/org | `org_{orgId}` | B2B SaaS, one container per customer org | +| Hierarchical | `org:{orgId}:user:{userId}` | Multi-level — isolate by org, and optionally drill into a user within it | +| Per-project | `project_{projectId}` | Workspace- or project-scoped content | + +Everything *within* that boundary — categories, statuses, dates, custom fields — is metadata, not a new tag. Don't create a new container tag for every property you want to filter on; that's what metadata is for. + +--- + +## Access control + +Container tags aren't just organizational — they're enforced as an authorization boundary. API keys and org members can be restricted to specific tags, so a request for a tag outside the caller's allowed set is rejected with `403 Forbidden` rather than silently filtered. See [Container Tags → Access control](/concepts/container-tags#access-control) for the details. + +--- + +## Next steps + + + + Personal agents, company agents, email assistants, and support platforms. + + + How isolation works, naming rules, and access control. + + + Metadata filter types, combining `AND`/`OR`, and query limits. + + + Mint keys that can only touch one container tag. + + diff --git a/apps/docs/concepts/rules.mdx b/apps/docs/concepts/rules.mdx new file mode 100644 index 00000000..735c9227 --- /dev/null +++ b/apps/docs/concepts/rules.mdx @@ -0,0 +1,305 @@ +--- +title: "Rules of supermemory" +description: "Best practices and things to consider when using supermemory in your system" +sidebarTitle: "Rules of supermemory" +icon: "gavel" +--- + +Supermemory provides powerful primitives and the full context stack for building AI agents. This page collects rules of thumb from building and running supermemory in production. They aren't hard constraints, just shortcuts that save you time, cost, and confusing search results. + +## Thinking about ingestion + +### What to ingest, and what not to + +#### Send what you would send to a human for memory + +Treat supermemory as a database for human-like understanding of knowledge and search. You should be feeding it unstructured data like documents, chat conversations, or even images, videos, and websites. You should not be ingesting database records or CSVs, since those are more structured. + +Although supermemory _does_ support learning from long-horizon structured data, typically the right approach is to give an agent tools to traverse the structure directly. + +Agents benefit most from having a _general_ idea of the topic alongside tools to look through the data. For example, knowing "this company uses PostHog and has three products (API, Console, and Landing Page)" helps the agent navigate the PostHog data more effectively. + +#### A quick test for where information belongs + +| Context | Test result | Where it goes | +| --- | --- | --- | +| "Sarah prefers async updates and is being promoted to VP of Product" | A colleague would remember this | supermemory: [memory search](/recall/search) + profile | +| The Q3 planning doc, support tickets, the API changelog | A colleague would look it up by meaning | supermemory: ingested as documents, recalled with document search | +| Invoice #4821, total \$1,340.50, status `paid` | Queried by ID, summed in reports | your database | +| "Answer in the user's language. Never quote internal pricing." | Every request needs it, verbatim | system prompt | + +Two things about this table that trip people up. + +**"Remember" and "look up" are both supermemory, but different reads.** You [ingest documents](/ingestion/add-memories); the pipeline derives memories from them and maintains a profile per [container tag](/concepts/how-it-works). `client.search({ searchMode: "memories" })` recalls the derived facts. `client.search({ searchMode: "documents" })` recalls the source material itself. A support agent usually needs both: memories for "this customer runs self-hosted and already tried reinstalling", documents for the actual troubleshooting guide. + +**Supermemory is not your system of record.** There's no SQL over memories, no joins, no aggregates, no querying by primary key. Keep transactional data in your database, and ingest the narrative *around* it ("the customer disputed invoice #4821 and churned over it") so your AI understands what the rows mean. + +#### Ingest with SuperRag when you just need search + +When you know you only want search, you can cut costs by 5x. Just set `taskType` when ingesting: + + + +```typescript TypeScript +await client.add({ + content: "testing", + containerTag: "test", + taskType: "superrag" +}); +``` + +```python Python +client.add( + content="testing", + container_tag="test", + task_type="superrag" +) +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v3/documents" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "content": "testing", + "containerTag": "test", + "taskType": "superrag" + }' +``` + + + +#### Use hybrid mode when searching over SuperRag content + +`hybrid` mode makes it much easier to get complete results from supermemory when you have both memories and documents. + + + +```typescript TypeScript +const results = await client.search({ + q: "test", + searchMode: "hybrid" +}); +``` + +```python Python +results = client.search.memories( + q="test", + search_mode="hybrid" +) +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v4/search" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "q": "test", + "searchMode": "hybrid" + }' +``` + + + +The response comes back in this shape: + +```ts +({ memory: string } | { chunk: string })[] +``` + +Use `item.memory || item.chunk` when reading results. + +#### Keep documents medium-sized + +While supermemory can handle documents with 400k+ tokens, sending smaller, self-contained documents produces better-quality learnings. The internal learning agent and "dreaming" jobs reflect on memories to build relations between them. If documents are too long, fewer memories get generated and fewer relations get made. + +We also recommend ingesting documents sequentially within a single `containerTag` where possible, since that's how supermemory determines what came first (used for `updates` relations and temporal reasoning). + +#### Handling single-threaded chatbots + +Many agent harnesses, like `openclaw`, `hermes`, and other single-threaded custom agents, run one long conversation with compaction. Some tips for managing single-threaded (and other long-running) conversations: + +1. **Send a `customId` when you can**: a sessionId, conversationId, document ID, or any representation of a "session" in your application. +2. **Generate one if you don't have one**, e.g. the current 4-hour window: `${new Date().toISOString().slice(0,10)}-${new Date().getHours()>>2}`. Adjust the window size based on traffic per container. +3. **Send the same prefix**: keep the start of the document identical across ingests under the same `customId` so supermemory can diff cleanly. You can either resend the full growing transcript each time, or send only the new turns since your last ingest. Just don't mix the two for the same `customId`. + +``` +Ingestion 1: +Assistant: Hey, how are you? +User: I'm fine. + +Ingestion 2 (full transcript): +Assistant: Hey, how are you? +User: I'm fine. +Assistant: Anything I can help with today? + +Ingestion 2 (delta only): +Assistant: Anything I can help with today? +``` + +You're only billed for the new (diff) content you send, so doing this well improves performance, cuts cost, and keeps usage simple. + +## Architecture and design + +#### Let supermemory handle the learning + +Don't pass content through an additional LLM before sending it to supermemory. Supermemory does that learning automatically. Because the engine already knows what it knows, it can contextually summarize, update, and forget information as needed. + +#### Configure what you want it to learn + +Ground it with `entityContext` to prevent drift over time. Picture a third person watching a conversation between two people: what do they remember, and about whom? Giving supermemory context about the entity itself helps ground its learnings and prevents drift and decay over time. + + + +```typescript TypeScript +const user = auth.user.name; +await client.add({ + content: "Hey, I'm doing great!", + containerTag: user, + entityContext: `User is ${user}, talking to assistant Kira` +}); // -> supermemory learns "Dhravya is doing great" +``` + +```python Python +user = auth.user.name +client.add( + content="Hey, I'm doing great!", + container_tag=user, + entity_context=f"User is {user}, talking to assistant Kira" +) # -> supermemory learns "Dhravya is doing great" +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v3/documents" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "content": "Hey, I'\''m doing great!", + "containerTag": "dhravya", + "entityContext": "User is dhravya, talking to assistant Kira" + }' +``` + + + +#### Use containerTags, don't over-stuff a single one + +Use a containerTag wherever there's a hard permission boundary. + +- **Don't**: ingest everything into one container and filter through it with metadata. +- **Do**: give each user their own container, and still filter by metadata inside it if needed. + +There's little correlation between the number of items in a container and its quality or latency. Supermemory is built for multi-tenant workloads and supports up to 1M documents and 10M memories per container. + +#### Use metadata filtering for detailed scoping inside containers + +You'll often want to ingest and search with filtering inside a single container. Say the engineering team ingests this: + + + +```typescript TypeScript +await client.add({ + content: "The team prefers TypeScript", + metadata: { team: "Engineering" }, + containerTag: "org-supermemory", + filterByMetadata: { team: "Engineering" } +}); +``` + +```python Python +client.add( + content="The team prefers TypeScript", + metadata={"team": "Engineering"}, + container_tag="org-supermemory", + filter_by_metadata={"team": "Engineering"} +) +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v3/documents" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "content": "The team prefers TypeScript", + "metadata": { "team": "Engineering" }, + "containerTag": "org-supermemory", + "filterByMetadata": { "team": "Engineering" } + }' +``` + + + +> Tip: `filterByMetadata` ensures a fact like "the team prefers TypeScript" is only built on top of the engineering team's knowledge. + +Later, the research team ingests this, with the same `containerTag` but different `metadata`: + +```json +{ + "content": "The team prefers Python", + "metadata": { "team": "Research" }, + "containerTag": "org-supermemory", + "filterByMetadata": { "team": "Research" } +} +``` + +This keeps research's and engineering's memories from mixing, even though they share a `containerTag`. When searching: + + + +```typescript TypeScript +const results = await client.search({ + q: "preferred language", + containerTag: "org-supermemory", + searchMode: "documents", + filters: { + AND: [{ key: "team", value: "research" }] + } +}); // -> "python" +``` + +```python Python +results = client.search.documents( + q="preferred language", + container_tag="org-supermemory", + filters={ + "AND": [{"key": "team", "value": "research"}] + } +) # -> "python" +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v3/search" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "q": "preferred language", + "containerTag": "org-supermemory", + "filters": { + "AND": [{ "key": "team", "value": "research" }] + } + }' +``` + + + +## Thinking about harness + +Think about how to bring memory back into the harness itself. + +#### Embrace a little noise + +You might want to hyper-optimize everything that goes into the model's prompt, but counterintuitively, you sometimes want to embrace noise, since true personalization comes from distinctive information. + +Example: a user says "hi" and the LLM responds "Hey Dhravya! How's it going? How's the new office coming along?" instead of something generic. + +Supermemory is designed for this: it returns an average of 10 tokens per fact, so even 50 facts is just 500 tokens of context, cheap enough to stay generous. + +#### Tools, hooks, and making the choice + +Think about how supermemory fits into your harness. Example, a personal agent: + +- **Session start hook** → load profile +- **On-message hook** → enrich the prompt with search +- **On-stop hook** → save the conversation + +Play around with these options in our [playground](https://console.supermemory.ai/playground), and read more in [this post on memory at the harness level](https://dhravya.dev/writing/memory-on-the-harness-level/). diff --git a/apps/docs/concepts/super-rag.mdx b/apps/docs/concepts/super-rag.mdx index ebe538bf..f4de2789 100644 --- a/apps/docs/concepts/super-rag.mdx +++ b/apps/docs/concepts/super-rag.mdx @@ -18,11 +18,10 @@ When you add content, Supermemory: 5. **Builds relationships** — Connects new knowledge to existing memories ```typescript -// Just add content — Supermemory handles the rest -await client.add({ - content: pdfBase64, - contentType: "pdf", - title: "Technical Documentation" +// Just upload — Supermemory handles the rest +await client.documents.uploadFile({ + file: fs.createReadStream('technical-documentation.pdf'), + metadata: JSON.stringify({ title: "Technical Documentation" }) }); ``` @@ -30,6 +29,63 @@ No chunking strategies to configure. No embedding models to choose. It just work --- +## Ingesting as pure SuperRAG (`taskType: "superrag"`) + +By default, every `client.add()` call runs on the **memory** path (`taskType: "memory"`): Supermemory chunks and embeds the content for retrieval, *and* runs it through the memory pipeline — extracting facts, updating the profile, and linking it into the knowledge graph. + +If you're ingesting content that's purely reference material — documentation, a large PDF, a knowledge base article — and you don't need Supermemory to derive personal facts or update a profile from it, set `taskType: "superrag"`. It skips the memory pipeline entirely and only does the chunk → embed → index work needed to make the content searchable. + + + +```typescript TypeScript +await client.add({ + content: "...", // e.g. a long internal wiki page + containerTag: "docs_kb", + taskType: "superrag", +}); +``` + +```python Python +client.add( + content="...", + container_tag="docs_kb", + task_type="superrag", +) +``` + +```bash cURL +curl -X POST "https://api.supermemory.ai/v3/documents" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "content": "...", + "containerTag": "docs_kb", + "taskType": "superrag" + }' +``` + + + +| | `taskType: "memory"` (default) | `taskType: "superrag"` | +|---|---|---| +| Chunking, embedding, indexing | ✅ | ✅ — searchable immediately via `searchMode: "documents"` | +| Fact extraction into memories | ✅ | ❌ skipped | +| Profile (`static`/`dynamic`/buckets) updates | ✅ | ❌ skipped | +| Graph linking (updates/extends/derives) | ✅ | ❌ skipped | +| Price per ingested token | Full rate | **5x cheaper** | + + +`taskType: "superrag"` is a **5x discount on ingested tokens** — `sm_superrag_text`/`sm_superrag_rich` are priced at 20% of `sm_tokens_text`/`sm_tokens_rich`. See [Billing → Memory vs SuperRAG tokens](/overview/billing#memory-vs-superrag-tokens) for the exact rates. + + + +Content ingested as `superrag` is retrievable via document search (`searchMode: "documents"`), but it will **never** surface as a memory, contribute to a user's profile, or connect into the knowledge graph. Use it for reference material you want searchable, not for anything that should shape what Supermemory knows about a user — that still needs the default `taskType: "memory"`. + + +When you're searching over a mix of both, `searchMode: "hybrid"` (below) is what pulls memory-path facts and superrag-path document chunks into one result set. More ingestion guidance: [Rules of supermemory → Ingest with SuperRag when you just need search](/concepts/rules#ingest-with-superrag-when-you-just-need-search). + +--- + ## Smart Chunking by Content Type Different content types need different chunking strategies. Supermemory applies the optimal approach automatically: @@ -170,7 +226,13 @@ You focus on building your product. Supermemory handles the RAG complexity. When to use each approach - + Search parameters and optimization + + Exact meter rates for memory vs SuperRAG tokens + + + `taskType` and other ingestion parameters + diff --git a/apps/docs/concepts/user-profiles.mdx b/apps/docs/concepts/user-profiles.mdx index 211b4dda..4be4f8b9 100644 --- a/apps/docs/concepts/user-profiles.mdx +++ b/apps/docs/concepts/user-profiles.mdx @@ -1,12 +1,16 @@ --- title: "User Profiles" -sidebarTitle: "User Profiles" +sidebarTitle: "Profiles" description: "Automatically maintained context about your users" icon: "circle-user" --- User profiles are **automatically maintained collections of facts about your users** that Supermemory builds from all their interactions. Think of it as a persistent "about me" document that's always up-to-date. +Each `containerTag` gets it's own profile. + +> Note: It's called "user" profile, but in reality it can be anything - an agent, organization, etc. + No search needed — comprehensive user info always ready @@ -30,6 +34,40 @@ Traditional memory systems rely entirely on search: **Profiles provide the foundation**: Instead of searching for basic context, profiles give your LLM a complete picture of who the user is. +![Search adds context to the prompt after a round trip; a profile rides along with every prompt for free](/images/user-profiles-vs-search.png) + +A pure search architecture means every turn pays a `search(prompt)` round trip before the agent can respond. A profile is attached once and sits alongside every user prompt and agent output — no extra call, no latency, and no risk of the query missing something important. + +--- + +## Non-literal-matching use cases + +Semantic search retrieves content that's *similar to the query* — it's built for questions like "what did we discuss about the migration?" It's a poor fit for facts that should be known **regardless of what's being asked**, because there's rarely a query that's semantically close to them. + +The clearest example is the user's own name. If someone tells your agent "call me Dhravya, not my full name" once during onboarding, that fact has almost nothing in common — vector-wise — with "help me plan a trip to Japan" or "review this PR." A search for either of those queries will not surface the name preference, because search only returns what's relevant to the query, and a name preference isn't relevant to trip planning or code review — it should just always be there. + +```typescript +// Weeks earlier, during onboarding +await client.add({ + content: "Call me Dhravya, not my full first name", + containerTag: "user_123", +}); + +// Later — an unrelated query +const results = await client.search({ + q: "help me plan a trip to Japan", + containerTag: "user_123", +}); +// The name preference won't be in `results` — it's not semantically +// related to trip planning, so search correctly leaves it out. + +// But it's always in the profile, independent of the query: +const { profile } = await client.profile({ containerTag: "user_123" }); +console.log(profile.static); // ["User goes by Dhravya, not their full name", ...] +``` + +This is the general pattern: names, pronouns, timezone, tone/format preferences, role, and other facts that should color *every* response — not just responses to a matching query — belong in the profile, not left to be caught by search. If your agent needs to "just know" something at all times, that's a strong signal it belongs in the profile rather than relying on a lucky semantic match. + --- ## Static vs Dynamic @@ -54,17 +92,42 @@ Recent context and temporary states: --- +## Buckets + +Static and dynamic split facts by how long-lived they are. **Buckets** split them by *topic* — a third, independent axis you define, like `preferences`, `goals`, or `work`. As content is ingested, a classifier sorts each fact into the buckets it matches. + +Every org starts with a default `preferences` bucket. Add your own in console settings at the organization level, or per space — space buckets are add-only, so a container tag always keeps every org-level bucket. + +```typescript +const { profile } = await client.profile({ + containerTag: "user_123", + include: ["buckets"], + buckets: ["preferences", "goals"], // optional — omit for all configured buckets +}); + +console.log(profile.buckets.preferences); +console.log(profile.buckets.goals); +``` + +Bucket descriptions steer the classifier, so a precise description ("explicit first-person preferences only, exclude inferred traits") produces cleaner buckets than a vague one. Buckets are separate from [`filterPrompt`](/concepts/customization), which controls what gets ingested at all — buckets only organize facts that already made it into the profile. + + + Request bucketed profiles, create buckets at the org or space level, get AI-generated suggestions, and see validation limits. + + +--- + ## How It Works Profiles are built automatically through ingestion: -1. **Ingest content** — Users [add documents](/add-memories), chat, or any content +1. **Ingest content** — Users [add documents](/ingestion/add-memories), chat, or any content 2. **Extract facts** — AI analyzes content for facts about the user 3. **Update profile** — System adds, updates, or removes facts 4. **Always current** — Profiles reflect the latest information -You don't manually manage profiles — they build themselves as users interact. Start by [adding content](/add-memories) to see profiles in action. +You don't manually manage profiles — they build themselves as users interact. Start by [adding content](/ingestion/add-memories) to see profiles in action. --- @@ -90,6 +153,36 @@ User asks: **"Can you help me debug this?"** --- +## Filtering Profiles + +Not many people realize this, but profiles support the same [metadata filtering](/concepts/filtering) as memory and document search. A profile is synthesized from the underlying memories in a container tag, so any `AND`/`OR` metadata filter you'd pass to `search` also narrows which memories are eligible to contribute to `static`, `dynamic`, and `buckets`. + +```typescript +// Only build the profile from memories tagged as onboarding data +const { profile } = await client.profile({ + containerTag: "user_123", + filters: { + AND: [{ key: "source", value: "onboarding" }], + }, +}); +``` + +This is useful when a container tag mixes memories from several sources or contexts and you only want one of them reflected in the profile — for example, a support agent that should only see profile facts derived from support tickets, not from an internal wiki synced into the same container: + +```typescript +const { profile } = await client.profile({ + containerTag: "org_customer_442", + filters: { + AND: [{ key: "channel", value: "support_ticket" }], + }, + include: ["static", "dynamic"], +}); +``` + +Filters apply on top of the search query too — combine `q` and `filters` to scope both the profile synthesis and the accompanying search results in one call. See [Filtering Profiles](/recall/user-profiles#filtering-profiles) for the full parameter reference. + +--- + ## Use Cases ### Personalized AI Assistants @@ -126,16 +219,19 @@ Profiles provide: preferred languages, coding style, current project context. ## Next Steps - + Fetch and use profiles via the API + + Create and configure topical buckets + How the underlying knowledge graph works Automatic profile injection with AI SDK - + Build profiles by adding content diff --git a/apps/docs/connectors/github.mdx b/apps/docs/connectors/github.mdx index 82a547f7..e3a9fb63 100644 --- a/apps/docs/connectors/github.mdx +++ b/apps/docs/connectors/github.mdx @@ -1,7 +1,7 @@ --- title: "GitHub Connector" description: "Connect GitHub repositories to sync documentation files into your Supermemory knowledge base" -icon: "github" +icon: "/images/github-icon.svg" --- Connect GitHub repositories to sync documentation files into your Supermemory knowledge base with OAuth authentication, webhook support, and automatic incremental syncing. @@ -25,7 +25,7 @@ The GitHub connector requires a **Scale Plan** or **Enterprise Plan**. const connection = await client.connections.create('github', { redirectUrl: 'https://yourapp.com/auth/github/callback', - containerTags: ['user-123', 'github-sync'], + containerTag: 'user-123', documentLimit: 5000, metadata: { source: 'github', @@ -48,7 +48,7 @@ The GitHub connector requires a **Scale Plan** or **Enterprise Plan**. connection = client.connections.create( 'github', redirect_url='https://yourapp.com/auth/github/callback', - container_tags=['user-123', 'github-sync'], + container_tag='user-123', document_limit=10000, metadata={ 'source': 'github', @@ -68,7 +68,7 @@ The GitHub connector requires a **Scale Plan** or **Enterprise Plan**. -H "Content-Type: application/json" \ -d '{ "redirectUrl": "https://yourapp.com/auth/github/callback", - "containerTags": ["user-123", "github-sync"], + "containerTag": "user-123", "documentLimit": 5000, "metadata": { "source": "github", @@ -95,7 +95,7 @@ After the user grants permissions, GitHub redirects to your callback URL. The co Unlike other connectors, GitHub requires repository selection before syncing begins. This gives your users control over which repositories to index. -**Generic Endpoints:** GitHub uses the generic resource management endpoints (Get Resources and Configure Connection) that work for any provider supporting resource management. See [Managing Connection Resources](/memory-api/connectors/managing-resources) for detailed API documentation. +**Generic Endpoints:** GitHub uses the generic resource management endpoints (Get Resources and Configure Connection) that work for any provider supporting resource management. See [Managing Connection Resources](/connectors/managing-resources) for detailed API documentation. diff --git a/apps/docs/connectors/gmail.mdx b/apps/docs/connectors/gmail.mdx index 2921bc8a..73e5063e 100644 --- a/apps/docs/connectors/gmail.mdx +++ b/apps/docs/connectors/gmail.mdx @@ -25,7 +25,7 @@ Connect Gmail to automatically sync email threads into your supermemory knowledg const connection = await client.connections.create('gmail', { redirectUrl: 'https://yourapp.com/auth/gmail/callback', - containerTags: ['user-123', 'gmail-sync'], + containerTag: 'user-123', documentLimit: 5000, metadata: { source: 'gmail', @@ -48,7 +48,7 @@ Connect Gmail to automatically sync email threads into your supermemory knowledg connection = client.connections.create( 'gmail', redirect_url='https://yourapp.com/auth/gmail/callback', - container_tags=['user-123', 'gmail-sync'], + container_tag='user-123', document_limit=5000, metadata={ 'source': 'gmail', @@ -68,7 +68,7 @@ Connect Gmail to automatically sync email threads into your supermemory knowledg -H "Content-Type: application/json" \ -d '{ "redirectUrl": "https://yourapp.com/auth/gmail/callback", - "containerTags": ["user-123", "gmail-sync"], + "containerTag": "user-123", "documentLimit": 5000, "metadata": { "source": "gmail", @@ -90,7 +90,7 @@ After user grants permissions, Google redirects to your callback URL. The connec ```typescript // Get connection details const connection = await client.connections.getByTags('gmail', { - containerTags: ['user-123', 'gmail-sync'] + containerTags: ['user-123'] }); console.log('Connected email:', connection.email); @@ -98,7 +98,7 @@ After user grants permissions, Google redirects to your callback URL. The connec // List synced email threads const documents = await client.documents.list({ - containerTags: ['user-123', 'gmail-sync'] + containerTags: ['user-123'] }); console.log(`Synced ${documents.memories.length} email threads`); @@ -109,7 +109,7 @@ After user grants permissions, Google redirects to your callback URL. The connec # Get connection details connection = client.connections.get_by_tags( 'gmail', - container_tags=['user-123', 'gmail-sync'] + container_tags=['user-123'] ) print(f'Connected email: {connection.email}') @@ -117,7 +117,7 @@ After user grants permissions, Google redirects to your callback URL. The connec # List synced email threads documents = client.documents.list( - container_tags=['user-123', 'gmail-sync'] + container_tags=['user-123'] ) print(f'Synced {len(documents.memories)} email threads') @@ -130,7 +130,7 @@ After user grants permissions, Google redirects to your callback URL. The connec -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "containerTags": ["user-123", "gmail-sync"], + "containerTags": ["user-123"], "provider": "gmail" }' @@ -139,7 +139,7 @@ After user grants permissions, Google redirects to your callback URL. The connec -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "containerTags": ["user-123", "gmail-sync"], + "containerTags": ["user-123"], "source": "gmail" }' ``` @@ -177,9 +177,10 @@ Each synced thread includes searchable metadata: You can filter searches using these metadata fields: ```typescript -const results = await client.search.documents({ +const results = await client.search({ q: "project update", - containerTags: ['user-123'], + containerTag: 'user-123', + searchMode: "documents", filters: JSON.stringify({ AND: [ { key: "type", value: "gmail_thread", negate: false }, @@ -408,7 +409,7 @@ await client.connections.deleteByProvider('gmail', { const newConnection = await client.connections.create('gmail', { redirectUrl: 'https://yourapp.com/auth/gmail/callback', - containerTags: ['user-123'] + containerTag: 'user-123' }); // User must re-authenticate diff --git a/apps/docs/connectors/google-drive.mdx b/apps/docs/connectors/google-drive.mdx index 9c3ac2a5..45cde2e0 100644 --- a/apps/docs/connectors/google-drive.mdx +++ b/apps/docs/connectors/google-drive.mdx @@ -1,7 +1,7 @@ --- title: "Google Drive Connector" description: "Connect Google Drive to sync documents into your Supermemory knowledge base" -icon: "google-drive" +icon: "/images/google-drive-icon.svg" --- Connect Google Drive to sync documents into your Supermemory knowledge base with OAuth authentication and custom app support. @@ -33,7 +33,7 @@ If you use scoped sync and the user has not finished the picker yet, **scheduled const connection = await client.connections.create('google-drive', { redirectUrl: 'https://yourapp.com/auth/google-drive/callback', - containerTags: ['user-123', 'gdrive-sync'], + containerTag: 'user-123', documentLimit: 3000, metadata: { source: 'google-drive', @@ -57,7 +57,7 @@ If you use scoped sync and the user has not finished the picker yet, **scheduled connection = client.connections.create( 'google-drive', redirect_url='https://yourapp.com/auth/google-drive/callback', - container_tags=['user-123', 'gdrive-sync'], + container_tag='user-123', document_limit=3000, metadata={ 'source': 'google-drive', @@ -78,7 +78,7 @@ If you use scoped sync and the user has not finished the picker yet, **scheduled -H "Content-Type: application/json" \ -d '{ "redirectUrl": "https://yourapp.com/auth/google-drive/callback", - "containerTags": ["user-123", "gdrive-sync"], + "containerTag": "user-123", "documentLimit": 3000, "metadata": { "source": "google-drive", @@ -105,7 +105,7 @@ After the user grants permissions, Google redirects through Supermemory to finis ```typescript // Get connection details const connection = await client.connections.getByTags('google-drive', { - containerTags: ['user-123', 'gdrive-sync'] + containerTags: ['user-123'] }); ``` @@ -114,13 +114,13 @@ After the user grants permissions, Google redirects through Supermemory to finis # Get connection details connection = client.connections.get_by_tags( 'google-drive', - container_tags=['user-123', 'gdrive-sync'] + container_tags=['user-123'] ) # List synced documents documents = client.connections.list_documents( 'google-drive', - container_tags=['user-123', 'gdrive-sync'] + container_tags=['user-123'] ) ``` @@ -131,7 +131,7 @@ After the user grants permissions, Google redirects through Supermemory to finis -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "containerTags": ["user-123", "gdrive-sync"], + "containerTags": ["user-123"], "provider": "google-drive" }' @@ -140,7 +140,7 @@ After the user grants permissions, Google redirects through Supermemory to finis -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "containerTags": ["user-123", "gdrive-sync"], + "containerTags": ["user-123"], "source": "google-drive" }' ``` @@ -154,6 +154,10 @@ Based on the API type definitions, Google Drive documents are identified with th - `google_slide` - Google Slides - `google_sheet` - Google Sheets + +Drive documents are converted to markdown before ingestion. This conversion is lossy — some formatting may not be preserved. + + ## Connection Management ### List All Connections diff --git a/apps/docs/connectors/granola.mdx b/apps/docs/connectors/granola.mdx index b2659fb9..92b878f3 100644 --- a/apps/docs/connectors/granola.mdx +++ b/apps/docs/connectors/granola.mdx @@ -42,7 +42,7 @@ The console limits connector setup to 500 documents. Use the API setup below for metadata: { apiKey: process.env.GRANOLA_API_KEY! }, - containerTags: ['org-123', 'meeting-notes'], + containerTag: 'org-123', documentLimit: 1000 }); @@ -61,7 +61,7 @@ The console limits connector setup to 500 documents. Use the API setup below for metadata={ 'apiKey': os.environ["GRANOLA_API_KEY"] }, - container_tags=['org-123', 'meeting-notes'], + container_tag='org-123', document_limit=1000 ) @@ -77,7 +77,7 @@ The console limits connector setup to 500 documents. Use the API setup below for "metadata": { "apiKey": "'"$GRANOLA_API_KEY"'" }, - "containerTags": ["org-123", "meeting-notes"], + "containerTag": "org-123", "documentLimit": 1000 }' ``` @@ -93,7 +93,7 @@ For Granola, provider-specific fields are passed inside the top-level `metadata` | Parameter | Location | Required | Description | |-----------|----------|----------|-------------| | `apiKey` | `metadata.apiKey` | Yes | Granola API key from **Settings > Connectors > API keys** | -| `containerTags` | top-level | No | Tags for organizing imported notes by user, organization, project, or tenant | +| `containerTag` | top-level | No | Tag for organizing imported notes by user, organization, project, or tenant | | `documentLimit` | top-level | No | Maximum notes to sync per connection (default: 10,000) | @@ -126,9 +126,10 @@ Each synced note includes searchable metadata: You can filter searches using these metadata fields: ```typescript -const results = await client.search.documents({ +const results = await client.search({ q: "customer onboarding discussion", - containerTags: ['org-123'], + containerTag: 'org-123', + searchMode: "documents", filters: JSON.stringify({ AND: [ { key: "type", value: "granola", negate: false }, diff --git a/apps/docs/memory-api/connectors/managing-resources.mdx b/apps/docs/connectors/managing-resources.mdx similarity index 100% rename from apps/docs/memory-api/connectors/managing-resources.mdx rename to apps/docs/connectors/managing-resources.mdx diff --git a/apps/docs/connectors/notion.mdx b/apps/docs/connectors/notion.mdx index 60428274..421714a3 100644 --- a/apps/docs/connectors/notion.mdx +++ b/apps/docs/connectors/notion.mdx @@ -1,7 +1,7 @@ --- title: "Notion Connector" description: "Sync Notion pages, databases, and blocks with real-time webhooks and workspace integration" -icon: "notion" +icon: "/images/notion-icon.svg" --- Connect Notion workspaces to automatically sync pages, databases, and content blocks into your Supermemory knowledge base. Supports real-time updates, rich formatting, and database properties. @@ -20,7 +20,7 @@ Connect Notion workspaces to automatically sync pages, databases, and content bl const connection = await client.connections.create('notion', { redirectUrl: 'https://yourapp.com/auth/notion/callback', - containerTags: ['user-123', 'notion-workspace'], + containerTag: 'user-123', documentLimit: 2000, metadata: { source: 'notion', @@ -43,7 +43,7 @@ Connect Notion workspaces to automatically sync pages, databases, and content bl connection = client.connections.create( 'notion', redirect_url='https://yourapp.com/auth/notion/callback', - container_tags=['user-123', 'notion-workspace'], + container_tag='user-123', document_limit=2000, metadata={ 'source': 'notion', @@ -63,7 +63,7 @@ Connect Notion workspaces to automatically sync pages, databases, and content bl -H "Content-Type: application/json" \ -d '{ "redirectUrl": "https://yourapp.com/auth/notion/callback", - "containerTags": ["user-123", "notion-workspace"], + "containerTag": "user-123", "documentLimit": 2000, "metadata": { "source": "notion", @@ -86,7 +86,7 @@ After user grants workspace access, Notion redirects to your callback URL. The c ```typescript // Check connection details const connection = await client.connections.getByTags('notion', { - containerTags: ['user-123', 'notion-workspace'] + containerTags: ['user-123'] }); console.log('Connected workspace:', connection.email); @@ -94,7 +94,7 @@ After user grants workspace access, Notion redirects to your callback URL. The c // List synced pages and databases const documents = await client.connections.listDocuments('notion', { - containerTags: ['user-123', 'notion-workspace'] + containerTags: ['user-123'] }); ``` @@ -103,7 +103,7 @@ After user grants workspace access, Notion redirects to your callback URL. The c # Check connection details connection = client.connections.get_by_tags( 'notion', - container_tags=['user-123', 'notion-workspace'] + container_tags=['user-123'] ) print(f'Connected workspace: {connection.email}') @@ -112,7 +112,7 @@ After user grants workspace access, Notion redirects to your callback URL. The c # List synced pages and databases documents = client.connections.list_documents( 'notion', - container_tags=['user-123', 'notion-workspace'] + container_tags=['user-123'] ) ``` @@ -122,7 +122,7 @@ After user grants workspace access, Notion redirects to your callback URL. The c curl -X POST "https://api.supermemory.ai/v3/connections/notion/connection" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{"containerTags": ["user-123", "notion-workspace"]}' + -d '{"containerTags": ["user-123"]}' # Response includes connection details: # { @@ -138,7 +138,7 @@ After user grants workspace access, Notion redirects to your callback URL. The c curl -X POST "https://api.supermemory.ai/v3/connections/notion/documents" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{"containerTags": ["user-123", "notion-workspace"]}' + -d '{"containerTags": ["user-123"]}' # Response: Array of document objects with sync status # [ @@ -261,7 +261,7 @@ For production deployments, create your own Notion integration: // Then create connections using your custom integration const connection = await client.connections.create('notion', { redirectUrl: 'https://yourapp.com/callback', - containerTags: ['org-456', 'user-789'], + containerTag: 'user-789', metadata: { customIntegration: true } }); ``` @@ -279,7 +279,7 @@ For production deployments, create your own Notion integration: connection = client.connections.create( 'notion', redirect_url='https://yourapp.com/callback', - container_tags=['org-456', 'user-789'], + container_tag='user-789', metadata={'customIntegration': True} ) ``` @@ -399,9 +399,10 @@ const projectEntries = documents.filter(doc => ); // Database properties become searchable metadata -const projectWithStatus = await client.search.documents({ +const projectWithStatus = await client.search({ q: "machine learning project", - containerTags: ['user-123'], + containerTag: 'user-123', + searchMode: "documents", filters: JSON.stringify({ AND: [ { key: "status", value: "In Progress", negate: false }, diff --git a/apps/docs/connectors/onedrive.mdx b/apps/docs/connectors/onedrive.mdx index f9449520..fcd1ca3a 100644 --- a/apps/docs/connectors/onedrive.mdx +++ b/apps/docs/connectors/onedrive.mdx @@ -1,7 +1,7 @@ --- title: "OneDrive Connector" description: "Sync Microsoft Office documents from OneDrive with scheduled synchronization and business account support" -icon: "microsoft" +icon: "/images/microsoft-icon.svg" --- @@ -22,7 +22,7 @@ const client = new Supermemory({ const connection = await client.connections.create('onedrive', { redirectUrl: 'https://yourapp.com/auth/onedrive/callback', - containerTags: ['user-123', 'onedrive-sync'], + containerTag: 'user-123', documentLimit: 1500, metadata: { source: 'onedrive', @@ -46,7 +46,7 @@ client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) connection = client.connections.create( 'onedrive', redirect_url='https://yourapp.com/auth/onedrive/callback', - container_tags=['user-123', 'onedrive-sync'], + container_tag='user-123', document_limit=1500, metadata={ 'source': 'onedrive', @@ -67,7 +67,7 @@ curl -X POST "https://api.supermemory.ai/v3/connections/onedrive" \ -H "Content-Type: application/json" \ -d '{ "redirectUrl": "https://yourapp.com/auth/onedrive/callback", - "containerTags": ["user-123", "onedrive-sync"], + "containerTag": "user-123", "documentLimit": 1500, "metadata": { "source": "onedrive", @@ -95,26 +95,26 @@ After user grants permissions, Microsoft redirects to your callback URL. The con ```typescript Typescript // Check connection details const connection = await client.connections.getByTags('onedrive', { - containerTags: ['user-123', 'onedrive-sync'] + containerTags: ['user-123'] }); // List synced Office documents const documents = await client.connections.listDocuments('onedrive', { - containerTags: ['user-123', 'onedrive-sync'] + containerTags: ['user-123'] }); ``` ```python Python # Check connection details connection = client.connections.get_by_tags( 'onedrive', - container_tags=['user-123', 'onedrive-sync'] + container_tags=['user-123'] ) # List synced Office documents documents = client.connections.list_documents( 'onedrive', - container_tags=['user-123', 'onedrive-sync'] + container_tags=['user-123'] ) ``` ```bash cURL @@ -123,7 +123,7 @@ After user grants permissions, Microsoft redirects to your callback URL. The con -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "containerTags": ["user-123", "onedrive-sync"], + "containerTags": ["user-123"], "provider": "onedrive" }' @@ -132,7 +132,7 @@ After user grants permissions, Microsoft redirects to your callback URL. The con -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "containerTags": ["user-123", "onedrive-sync"], + "containerTags": ["user-123"], "source": "onedrive" }' ``` @@ -268,7 +268,7 @@ For production deployments, configure your own Microsoft application: // Then create connections using your custom app const connection = await client.connections.create('onedrive', { redirectUrl: 'https://yourapp.com/callback', - containerTags: ['org-456', 'user-789'], + containerTag: 'user-789', metadata: { customApp: true } }); ``` @@ -284,7 +284,7 @@ For production deployments, configure your own Microsoft application: connection = client.connections.create( 'onedrive', redirect_url='https://yourapp.com/callback', - container_tags=['org-456', 'user-789'], + container_tag='user-789', metadata={'customApp': True} ) ``` diff --git a/apps/docs/connectors/overview.mdx b/apps/docs/connectors/overview.mdx index 1c114040..5b40ef2b 100644 --- a/apps/docs/connectors/overview.mdx +++ b/apps/docs/connectors/overview.mdx @@ -10,7 +10,7 @@ Connect external platforms to automatically sync documents into supermemory. Sup ## Supported Connectors - + **Google Docs, Slides, Sheets** Real-time sync via webhooks. Supports shared drives, nested folders, and collaborative documents. @@ -22,20 +22,20 @@ Connect external platforms to automatically sync documents into supermemory. Sup Real-time sync via Pub/Sub webhooks. Syncs threads with full conversation history and metadata. - + **Pages, Databases, Blocks** Instant sync of workspace content. Handles rich formatting, embeds, and database properties. - + **Word, Excel, PowerPoint** Scheduled sync every 4 hours. Supports personal and business accounts with file versioning. - + **GitHub Repositories** Real-time incremental sync via webhooks. Supports documentation files in repositories. @@ -69,7 +69,7 @@ const client = new Supermemory({ const connection = await client.connections.create('notion', { redirectUrl: 'https://yourapp.com/callback', - containerTags: ['user-123', 'workspace-alpha'], + containerTag: 'user-123', documentLimit: 5000, metadata: { department: 'sales' } }); @@ -90,7 +90,7 @@ client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) connection = client.connections.create( 'notion', redirect_url='https://yourapp.com/callback', - container_tags=['user-123', 'workspace-alpha'], + container_tag='user-123', document_limit=5000, metadata={'department': 'sales'} ) @@ -108,7 +108,7 @@ curl -X POST "https://api.supermemory.ai/v3/connections/notion" \ -H "Content-Type: application/json" \ -d '{ "redirectUrl": "https://yourapp.com/callback", - "containerTags": ["user-123", "workspace-alpha"], + "containerTag": "user-123", "documentLimit": 5000, "metadata": {"department": "sales"} }' @@ -140,7 +140,7 @@ const client = new Supermemory({ // List all connections using SDK const connections = await client.connections.list({ - containerTags: ['user-123', 'workspace-alpha'] + containerTags: ['user-123'] }); connections.forEach(conn => { @@ -152,7 +152,7 @@ connections.forEach(conn => { // List synced documents (memories) using SDK const memories = await client.documents.list({ - containerTags: ['user-123', 'workspace-alpha'] + containerTags: ['user-123'] }); console.log(`Synced ${memories.memories.length} documents`); @@ -167,7 +167,7 @@ client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) # List all connections using SDK connections = client.connections.list( - container_tags=['user-123', 'workspace-alpha'] + container_tags=['user-123'] ) for conn in connections: @@ -177,7 +177,7 @@ for conn in connections: print(f'Created: {conn.created_at}') # List synced documents (memories) using SDK -memories = client.documents.list(container_tags=['user-123', 'workspace-alpha']) +memories = client.documents.list(container_tags=['user-123']) print(f'Synced {len(memories.memories)} documents') # Output: Synced 45 documents @@ -188,7 +188,7 @@ print(f'Synced {len(memories.memories)} documents') curl -X POST "https://api.supermemory.ai/v3/connections/list" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{"containerTags": ["user-123", "workspace-alpha"]}' + -d '{"containerTags": ["user-123"]}' # Response: [{"id": "conn_abc", "provider": "notion", "email": "user@example.com", ...}] @@ -196,7 +196,7 @@ curl -X POST "https://api.supermemory.ai/v3/connections/list" \ curl -X POST "https://api.supermemory.ai/v3/documents/list" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{"containerTags": ["user-123", "workspace-alpha"]}' + -d '{"containerTags": ["user-123"]}' # Response: {"results": [...], "totalCount": 45} ``` @@ -368,3 +368,18 @@ curl -X DELETE "https://api.supermemory.ai/v3/connections/conn_abc123?deleteDocu ``` + +## Custom OAuth Applications + +By default, Supermemory uses its own OAuth applications to connect to third-party providers. You can configure your own OAuth app credentials via `PATCH /v3/settings` for tighter control over data access — useful for enterprise customers. + +1. Create the OAuth application on the provider's developer console: + - Google: [console.developers.google.com/apis/credentials/oauthclient](https://console.developers.google.com/apis/credentials/oauthclient) + - Notion: [notion.so/my-integrations](https://www.notion.so/my-integrations) + - OneDrive: [Azure Portal → App registrations](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsMenu) +2. For Google Drive specifically: choose application type **Web application**, and enable the Google Drive API under "APIs and Services" in the Cloud Console. Google also requires verification/approval before custom keys work in production. +3. Set the redirect URL to `https://api.supermemory.ai/v3/connections/auth/callback/{provider}` (for example, `.../auth/callback/google-drive`). + + +Enabling custom keys for a provider applies to all new connections for that provider — existing connections will need to be re-authorized. + diff --git a/apps/docs/connectors/s3.mdx b/apps/docs/connectors/s3.mdx index 438c5d44..12d9a285 100644 --- a/apps/docs/connectors/s3.mdx +++ b/apps/docs/connectors/s3.mdx @@ -1,7 +1,7 @@ --- title: "S3 Connector" description: "Connect Amazon S3 or S3-compatible storage to sync files into your Supermemory knowledge base" -icon: "aws" +icon: "database" --- Connect Amazon S3 buckets or S3-compatible storage services (MinIO, DigitalOcean Spaces, Cloudflare R2, Tigris) to sync files into your Supermemory knowledge base. @@ -28,7 +28,7 @@ The S3 connector requires a **Scale Plan** or higher. You can also create S3 con bucket: 'my-documents-bucket', region: 'us-east-1' }, - containerTags: ['org-123'] + containerTag: 'org-123' }); ``` @@ -47,7 +47,7 @@ The S3 connector requires a **Scale Plan** or higher. You can also create S3 con 'bucket': 'my-documents-bucket', 'region': 'us-east-1' }, - container_tags=['org-123', 's3-sync'] + container_tag='org-123' ) ``` @@ -63,7 +63,7 @@ The S3 connector requires a **Scale Plan** or higher. You can also create S3 con "bucket": "my-documents-bucket", "region": "us-east-1" }, - "containerTags": ["org-123"] + "containerTag": "org-123" }' ``` @@ -82,7 +82,7 @@ For S3, provider-specific connection fields are passed inside the top-level `met | `endpoint` | `metadata.endpoint` | No | Custom endpoint for S3-compatible services | | `prefix` | `metadata.prefix` | No | Key prefix filter (e.g., `documents/`) | | `containerTagRegex` | `metadata.containerTagRegex` | No | Regex to extract container tags from file paths | -| `containerTags` | top-level | No | Tags for organizing connections | +| `containerTag` | top-level | No | Tag for organizing this connection | | `documentLimit` | top-level | No | Maximum documents to sync (default: 10,000) | @@ -103,7 +103,7 @@ const connection = await client.connections.create('s3', { region: 'auto', endpoint: 'https://minio.example.com' }, - containerTags: ['minio-sync'] + containerTag: 'minio-sync' }); ``` @@ -126,7 +126,7 @@ const connection = await client.connections.create('s3', { region: 'auto', endpoint: 'https://.r2.cloudflarestorage.com' }, - containerTags: ['r2-sync'] + containerTag: 'r2-sync' }); ``` @@ -147,7 +147,7 @@ const connection = await client.connections.create('s3', { region: 'us-east-1', prefix: 'documents/engineering/' // Only syncs files under this path }, - containerTags: ['engineering-docs'] + containerTag: 'engineering-docs' }); ``` @@ -164,7 +164,7 @@ const connection = await client.connections.create('s3', { region: 'us-east-1', containerTagRegex: 'users/(?[^/]+)/' }, - containerTags: ['user-files'] + containerTag: 'user-files' }); // File: users/user-123/documents/notes.md → container tag: user-123 diff --git a/apps/docs/connectors/troubleshooting.mdx b/apps/docs/connectors/troubleshooting.mdx index 67d67652..14ad22d7 100644 --- a/apps/docs/connectors/troubleshooting.mdx +++ b/apps/docs/connectors/troubleshooting.mdx @@ -78,7 +78,7 @@ curl -X POST "https://api.supermemory.ai/v3/documents/list" \ // correct - exact match with OAuth app settings const connection = await client.connections.create('notion', { redirectUrl: 'https://yourapp.com/auth/notion/callback', - containerTags: ['user-123'] + containerTag: 'user-123' }); // Wrong - URL doesn't match @@ -122,7 +122,7 @@ await client.connections.deleteByProvider('google-drive', { const newConnection = await client.connections.create('google-drive', { redirectUrl: 'https://yourapp.com/callback', - containerTags: ['user-123'] + containerTag: 'user-123' }); // User must re-authenticate @@ -138,7 +138,7 @@ window.location.href = newConnection.authLink; ```typescript const connection = await client.connections.create('onedrive', { redirectUrl: 'https://yourapp.com/callback', - containerTags: ['user-123'], + containerTag: 'user-123', documentLimit: 500 // Start with fewer documents }); ``` @@ -215,7 +215,7 @@ await client.connections.deleteByProvider('gmail', { const newConnection = await client.connections.create('gmail', { redirectUrl: 'https://yourapp.com/callback', - containerTags: ['user-123'] + containerTag: 'user-123' }); ``` diff --git a/apps/docs/connectors/web-crawler.mdx b/apps/docs/connectors/web-crawler.mdx index 1fb0e18e..36808bb0 100644 --- a/apps/docs/connectors/web-crawler.mdx +++ b/apps/docs/connectors/web-crawler.mdx @@ -25,7 +25,7 @@ The web crawler connector requires a **Scale Plan** or **Enterprise Plan**. const connection = await client.connections.create('web-crawler', { redirectUrl: 'https://yourapp.com/callback', - containerTags: ['user-123', 'website-sync'], + containerTag: 'user-123', documentLimit: 5000, metadata: { startUrl: 'https://docs.example.com' @@ -48,7 +48,7 @@ The web crawler connector requires a **Scale Plan** or **Enterprise Plan**. connection = client.connections.create( 'web-crawler', redirect_url='https://yourapp.com/callback', - container_tags=['user-123', 'website-sync'], + container_tag='user-123', document_limit=5000, metadata={ 'startUrl': 'https://docs.example.com' @@ -68,7 +68,7 @@ The web crawler connector requires a **Scale Plan** or **Enterprise Plan**. -H "Content-Type: application/json" \ -d '{ "redirectUrl": "https://yourapp.com/callback", - "containerTags": ["user-123", "website-sync"], + "containerTag": "user-123", "documentLimit": 5000, "metadata": { "startUrl": "https://docs.example.com" @@ -96,7 +96,7 @@ Unlike other connectors, the web crawler doesn't require OAuth authentication. T ```typescript // Check connection details const connection = await client.connections.getByTags('web-crawler', { - containerTags: ['user-123', 'website-sync'] + containerTags: ['user-123'] }); console.log('Start URL:', connection.metadata?.startUrl); @@ -104,7 +104,7 @@ Unlike other connectors, the web crawler doesn't require OAuth authentication. T // List synced web pages const documents = await client.connections.listDocuments('web-crawler', { - containerTags: ['user-123', 'website-sync'] + containerTags: ['user-123'] }); console.log(`Synced ${documents.length} web pages`); @@ -115,7 +115,7 @@ Unlike other connectors, the web crawler doesn't require OAuth authentication. T # Check connection details connection = client.connections.get_by_tags( 'web-crawler', - container_tags=['user-123', 'website-sync'] + container_tags=['user-123'] ) print(f'Start URL: {connection.metadata.get("startUrl")}') @@ -124,7 +124,7 @@ Unlike other connectors, the web crawler doesn't require OAuth authentication. T # List synced web pages documents = client.connections.list_documents( 'web-crawler', - container_tags=['user-123', 'website-sync'] + container_tags=['user-123'] ) print(f'Synced {len(documents)} web pages') @@ -136,7 +136,7 @@ Unlike other connectors, the web crawler doesn't require OAuth authentication. T curl -X POST "https://api.supermemory.ai/v3/connections/web-crawler/connection" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{"containerTags": ["user-123", "website-sync"]}' + -d '{"containerTags": ["user-123"]}' # Response includes connection details: # { @@ -151,7 +151,7 @@ Unlike other connectors, the web crawler doesn't require OAuth authentication. T curl -X POST "https://api.supermemory.ai/v3/connections/web-crawler/documents" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{"containerTags": ["user-123", "website-sync"]}' + -d '{"containerTags": ["user-123"]}' # Response: Array of document objects # [ diff --git a/apps/docs/cookbook/ai-sdk-integration.mdx b/apps/docs/cookbook/ai-sdk-integration.mdx deleted file mode 100644 index d6853210..00000000 --- a/apps/docs/cookbook/ai-sdk-integration.mdx +++ /dev/null @@ -1,354 +0,0 @@ ---- -title: "AI SDK Integration" -description: "Complete examples showing how to use Supermemory with Vercel AI SDK for building intelligent applications" ---- - -This page provides comprehensive examples of using Supermemory with the Vercel AI SDK, covering Memory Tools and User Profiles approaches. - -## Personal Assistant with Memory Tools - -Build an AI assistant that remembers user preferences and past interactions: - - - -```typescript Next.js API Route -import { streamText } from 'ai' -import { createAnthropic } from '@ai-sdk/anthropic' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const anthropic = createAnthropic({ - apiKey: process.env.ANTHROPIC_API_KEY! -}) - -export async function POST(request: Request) { - const { messages } = await request.json() - - const result = await streamText({ - model: anthropic('claude-3-sonnet-20240229'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!), - system: `You are a helpful personal assistant. When users share information about themselves, - remember it using the addMemory tool. When they ask questions, search your memories to provide - personalized responses. Always be proactive about remembering important details.` - }) - - return result.toAIStreamResponse() -} -``` - -```typescript Client Component -'use client' - -import { useChat } from 'ai/react' - -export default function PersonalAssistant() { - const { messages, input, handleInputChange, handleSubmit } = useChat() - - return ( -
-
- {messages.map((message) => ( -
-

{message.content}

-
- ))} -
- -
- -
-
- ) -} -``` - -
- -**Example conversation:** -- User: "I'm allergic to peanuts and I love Italian food" -- AI: *Uses addMemory tool* "I've remembered that you're allergic to peanuts and love Italian food!" -- User: "Suggest a restaurant for dinner" -- AI: *Uses searchMemories tool* "Based on what I know about you, I'd recommend an Italian restaurant that's peanut-free..." - -## Customer Support with Context - -Build a customer support system that remembers customer history: - -```typescript -import { streamText } from 'ai' -import { createOpenAI } from '@ai-sdk/openai' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, customerId } = await request.json() - - const result = await streamText({ - model: openai('gpt-5'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: [customerId] - }), - system: `You are a customer support agent. Before responding to any query: - 1. Search for the customer's previous interactions and issues - 2. Remember any new information shared in this conversation - 3. Provide personalized help based on their history - 4. Always be empathetic and solution-focused` - }) - - return result.toAIStreamResponse() -} -``` - -## Multi-User Learning Assistant - -Build an assistant that learns from multiple users but keeps data separate: - -```typescript -import { streamText } from 'ai' -import { createAnthropic } from '@ai-sdk/anthropic' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const anthropic = createAnthropic({ - apiKey: process.env.ANTHROPIC_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, userId, courseId } = await request.json() - - const result = await streamText({ - model: anthropic('claude-3-haiku-20240307'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: [userId] - }), - system: `You are a learning assistant. Help students with their coursework by: - 1. Remembering their learning progress and struggles - 2. Searching for relevant information from their past sessions - 3. Providing personalized explanations based on their learning style - 4. Tracking topics they've mastered vs topics they need more help with` - }) - - return result.toAIStreamResponse() -} -``` - -## Research Assistant with File Processing - -Combine file upload with memory tools for research assistance: - - - -```typescript API Route -import { streamText } from 'ai' -import { createOpenAI } from '@ai-sdk/openai' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, projectId } = await request.json() - - const result = await streamText({ - model: openai('gpt-5'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: [projectId] - }), - system: `You are a research assistant. You can: - 1. Search through uploaded research papers and documents - 2. Remember key findings and insights from conversations - 3. Help synthesize information across multiple sources - 4. Track research progress and important discoveries` - }) - - return result.toAIStreamResponse() -} -``` - -```typescript File Upload Handler -import { addMemory } from '@supermemory/tools' - -export async function POST(request: Request) { - const formData = await request.formData() - const file = formData.get('file') as File - const projectId = formData.get('projectId') as string - - // Upload file and add to memory - const memory = await addMemory({ - apiKey: process.env.SUPERMEMORY_API_KEY!, - content: file, // Supermemory handles file processing - title: file.name, - headers: { - 'x-sm-conversation-id': projectId - } - }) - - return Response.json({ - success: true, - message: "Document uploaded and processed for research", - memoryId: memory.id - }) -} -``` - - - -## Code Assistant with Project Memory - -Create a coding assistant that remembers your codebase and preferences: - -```typescript -import { streamText } from 'ai' -import { createAnthropic } from '@ai-sdk/anthropic' -import { - supermemoryTools, - searchMemoriesTool, - addMemoryTool -} from '@supermemory/tools/ai-sdk' - -const anthropic = createAnthropic({ - apiKey: process.env.ANTHROPIC_API_KEY! -}) - -export async function POST(request: Request) { - const { messages, repositoryId } = await request.json() - - const result = await streamText({ - model: anthropic('claude-3-sonnet-20240229'), - messages, - tools: { - // Use individual tools for more control - searchMemories: searchMemoriesTool(process.env.SUPERMEMORY_API_KEY!, { - headers: { - } - }), - addMemory: addMemoryTool(process.env.SUPERMEMORY_API_KEY!, { - headers: { - } - }), - // Add custom tools - executeCode: { - description: 'Execute code in a sandbox environment', - parameters: z.object({ - code: z.string(), - language: z.string() - }), - execute: async ({ code, language }) => { - // Your code execution logic - return { result: "Code executed successfully" } - } - } - }, - system: `You are a coding assistant with memory. You can: - 1. Remember coding patterns and preferences from past conversations - 2. Search through previous code examples and solutions - 3. Track project architecture and design decisions - 4. Learn from debugging sessions and common issues` - }) - - return result.toAIStreamResponse() -} -``` - -## Advanced: Custom Tool Integration - -Combine Supermemory tools with your own custom tools: - -```typescript -import { streamText } from 'ai' -import { createOpenAI } from '@ai-sdk/openai' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' -import { z } from 'zod' - -const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! -}) - -// Custom tool for calendar integration -const calendarTool = { - description: 'Create calendar events', - parameters: z.object({ - title: z.string(), - date: z.string(), - duration: z.number() - }), - execute: async ({ title, date, duration }) => { - // Your calendar API integration - return { eventId: "cal_123", message: "Event created" } - } -} - -export async function POST(request: Request) { - const { messages } = await request.json() - - const result = await streamText({ - model: openai('gpt-5'), - messages, - tools: { - // Spread Supermemory tools - ...supermemoryTools(process.env.SUPERMEMORY_API_KEY!), - // Add custom tools - createEvent: calendarTool, - }, - system: `You are a personal assistant that can remember information and - manage calendars. When users mention events or appointments: - 1. Remember the details using addMemory - 2. Create calendar events using createEvent - 3. Search for conflicts using searchMemories` - }) - - return result.toAIStreamResponse() -} -``` - -## Environment Setup - -For all examples, ensure you have these environment variables: - -```bash .env.local -SUPERMEMORY_API_KEY=your_supermemory_key -OPENAI_API_KEY=your_openai_key -ANTHROPIC_API_KEY=your_anthropic_key -``` - -## Best Practices - -### Memory Tools -- Use descriptive memory content for better search results -- Include context in your system prompts about when to use each tool -- Use project headers to separate different use cases -- Implement error handling for tool failures - -### General Tips -- Start with simple examples and gradually add complexity -- Use the search functionality to avoid duplicate memories -- Implement proper authentication for production use -- Consider rate limiting for high-volume applications - -## Next Steps - - - - Advanced memory management with full API control - - - - Automatic personalization with user profiles - - diff --git a/apps/docs/cookbook/chat-with-gdrive.mdx b/apps/docs/cookbook/chat-with-gdrive.mdx deleted file mode 100644 index fd7e217b..00000000 --- a/apps/docs/cookbook/chat-with-gdrive.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Chat with Google Drive" -url: "https://supermemory.ai/blog/building-an-ai-compliance-chatbot-with-supermemory-and-google-drive/" ---- diff --git a/apps/docs/cookbook/customer-support.mdx b/apps/docs/cookbook/customer-support.mdx deleted file mode 100644 index 01ad0e8e..00000000 --- a/apps/docs/cookbook/customer-support.mdx +++ /dev/null @@ -1,1047 +0,0 @@ ---- -title: "Customer Support Bot" -description: "Build an intelligent support system that remembers customer history and provides personalized help" ---- - -Create a customer support system that remembers every interaction, tracks issues across conversations, and provides personalized support based on customer history and preferences. - -## What You'll Build - -A customer support bot that: -- **Remembers customer history** across all conversations and channels -- **Tracks ongoing issues** and follows up automatically -- **Provides personalized responses** based on customer tier and preferences -- **Escalates complex issues** to human agents with full context -- **Learns from resolutions** to improve future responses - -## Prerequisites - -- Node.js 18+ or Python 3.8+ -- Supermemory API key -- OpenAI API key -- Customer database or CRM integration -- Basic understanding of customer support workflows - -## Implementation - -### Step 1: Customer Context Management - - - - ```typescript lib/customer-context.ts - import { Supermemory } from 'supermemory' - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }) - - interface Customer { - id: string - email: string - name: string - tier: 'free' | 'pro' | 'enterprise' - joinDate: string - preferences?: Record - } - - interface SupportTicket { - id: string - customerId: string - subject: string - status: 'open' | 'pending' | 'resolved' | 'closed' - priority: 'low' | 'medium' | 'high' | 'urgent' - category: string - createdAt: string - updatedAt: string - assignedAgent?: string - } - - export class CustomerContextManager { - private getContainerTag(customerId: string): string { - return `customer_${customerId}` - } - - async addInteraction(customerId: string, interaction: { - type: 'chat' | 'email' | 'phone' | 'ticket' - content: string - channel: string - outcome?: 'resolved' | 'escalated' | 'pending' - agentId?: string - metadata?: Record - }) { - try { - const result = await client.add({ - content: `${interaction.type.toUpperCase()}: ${interaction.content}`, - containerTag: this.getContainerTag(customerId), - metadata: { - type: 'customer_interaction', - interactionType: interaction.type, - channel: interaction.channel, - outcome: interaction.outcome, - agentId: interaction.agentId, - timestamp: new Date().toISOString(), - ...interaction.metadata - } - }) - - return result - } catch (error) { - console.error('Failed to add customer interaction:', error) - throw error - } - } - - async getCustomerHistory(customerId: string, limit: number = 10) { - try { - const memories = await client.documents.list({ - containerTags: [this.getContainerTag(customerId)], - limit, - sort: 'updatedAt', - order: 'desc' - }) - - return memories.memories.map(memory => ({ - id: memory.id, - content: memory.content, - type: memory.metadata?.interactionType || 'unknown', - channel: memory.metadata?.channel, - outcome: memory.metadata?.outcome, - timestamp: memory.metadata?.timestamp || memory.createdAt, - agentId: memory.metadata?.agentId - })) - } catch (error) { - console.error('Failed to get customer history:', error) - throw error - } - } - - async searchCustomerContext(customerId: string, query: string) { - try { - const results = await client.search.memories({ - q: query, - containerTag: this.getContainerTag(customerId), - threshold: 0.6, - limit: 5, - rerank: true - }) - - return results.results.map(result => ({ - content: result.memory, - similarity: result.similarity, - metadata: result.metadata - })) - } catch (error) { - console.error('Failed to search customer context:', error) - throw error - } - } - - async trackIssue(customerId: string, issue: { - subject: string - description: string - category: string - priority: 'low' | 'medium' | 'high' | 'urgent' - status: 'open' | 'pending' | 'resolved' - }) { - try { - const issueContent = `ISSUE: ${issue.subject}\n\nDescription: ${issue.description}\nCategory: ${issue.category}\nPriority: ${issue.priority}\nStatus: ${issue.status}` - - const result = await client.add({ - content: issueContent, - containerTag: this.getContainerTag(customerId), - metadata: { - type: 'support_issue', - subject: issue.subject, - category: issue.category, - priority: issue.priority, - status: issue.status, - createdAt: new Date().toISOString() - } - }) - - return result - } catch (error) { - console.error('Failed to track issue:', error) - throw error - } - } - - async updateIssueStatus(issueId: string, status: 'open' | 'pending' | 'resolved' | 'closed', resolution?: string) { - try { - // Note: In a real implementation, you'd update the memory - // For now, we'll add a status update - const memory = await client.documents.get(issueId) - const customerId = memory.containerTags?.[0]?.replace('customer_', '') || '' - - const updateContent = `ISSUE UPDATE: ${memory.metadata?.subject}\nStatus changed to: ${status}${resolution ? `\nResolution: ${resolution}` : ''}` - - return await this.addInteraction(customerId, { - type: 'ticket', - content: updateContent, - channel: 'internal', - outcome: status === 'resolved' ? 'resolved' : 'pending', - metadata: { - originalIssueId: issueId, - statusUpdate: true - } - }) - } catch (error) { - console.error('Failed to update issue status:', error) - throw error - } - } - } - ``` - - - - ```python customer_context.py - from supermemory import Supermemory - import os - from typing import Dict, List, Any, Optional - from datetime import datetime - from enum import Enum - - class InteractionType(Enum): - CHAT = "chat" - EMAIL = "email" - PHONE = "phone" - TICKET = "ticket" - - class Priority(Enum): - LOW = "low" - MEDIUM = "medium" - HIGH = "high" - URGENT = "urgent" - - class Status(Enum): - OPEN = "open" - PENDING = "pending" - RESOLVED = "resolved" - CLOSED = "closed" - - class CustomerContextManager: - def __init__(self): - self.client = Supermemory(api_key=os.getenv("SUPERMEMORY_API_KEY")) - - def _get_container_tag(self, customer_id: str) -> str: - return f"customer_{customer_id}" - - def add_interaction(self, customer_id: str, interaction: Dict[str, Any]) -> Dict: - """Add a customer interaction to memory""" - try: - content = f"{interaction['type'].upper()}: {interaction['content']}" - - result = self.client.add( - content=content, - container_tag=self._get_container_tag(customer_id), - metadata={ - 'type': 'customer_interaction', - 'interactionType': interaction['type'], - 'channel': interaction['channel'], - 'outcome': interaction.get('outcome'), - 'agentId': interaction.get('agentId'), - 'timestamp': datetime.now().isoformat(), - **interaction.get('metadata', {}) - } - ) - return result - except Exception as e: - print(f"Failed to add customer interaction: {e}") - raise - - def get_customer_history(self, customer_id: str, limit: int = 10) -> List[Dict]: - """Get customer interaction history""" - try: - memories = self.client.documents.list( - container_tags=[self._get_container_tag(customer_id)], - limit=limit, - sort='updatedAt', - order='desc' - ) - - return [ - { - 'id': memory.id, - 'content': memory.content, - 'type': memory.metadata.get('interactionType', 'unknown') if memory.metadata else 'unknown', - 'channel': memory.metadata.get('channel') if memory.metadata else None, - 'outcome': memory.metadata.get('outcome') if memory.metadata else None, - 'timestamp': memory.metadata.get('timestamp', memory.created_at) if memory.metadata else memory.created_at, - 'agentId': memory.metadata.get('agentId') if memory.metadata else None - } - for memory in memories.memories - ] - except Exception as e: - print(f"Failed to get customer history: {e}") - raise - - def search_customer_context(self, customer_id: str, query: str) -> List[Dict]: - """Search customer's interaction history""" - try: - results = self.client.search.memories( - q=query, - container_tag=self._get_container_tag(customer_id), - threshold=0.6, - limit=5, - rerank=True - ) - - return [ - { - 'content': result.memory, - 'similarity': result.similarity, - 'metadata': result.metadata - } - for result in results.results - ] - except Exception as e: - print(f"Failed to search customer context: {e}") - raise - - def track_issue(self, customer_id: str, issue: Dict[str, str]) -> Dict: - """Track a customer support issue""" - try: - issue_content = f"""ISSUE: {issue['subject']} - -Description: {issue['description']} -Category: {issue['category']} -Priority: {issue['priority']} -Status: {issue['status']}""" - - result = self.client.add( - content=issue_content, - container_tag=self._get_container_tag(customer_id), - metadata={ - 'type': 'support_issue', - 'subject': issue['subject'], - 'category': issue['category'], - 'priority': issue['priority'], - 'status': issue['status'], - 'createdAt': datetime.now().isoformat() - } - ) - return result - except Exception as e: - print(f"Failed to track issue: {e}") - raise - - def update_issue_status(self, issue_id: str, status: str, resolution: Optional[str] = None) -> Dict: - """Update the status of a support issue""" - try: - # Get original issue - memory = self.client.documents.get(issue_id) - customer_id = (memory.container_tags[0] if memory.container_tags else '').replace('customer_', '') - - update_content = f"ISSUE UPDATE: {memory.metadata.get('subject', 'Unknown')}\nStatus changed to: {status}" - if resolution: - update_content += f"\nResolution: {resolution}" - - return self.add_interaction(customer_id, { - 'type': 'ticket', - 'content': update_content, - 'channel': 'internal', - 'outcome': 'resolved' if status == 'resolved' else 'pending', - 'metadata': { - 'originalIssueId': issue_id, - 'statusUpdate': True - } - }) - except Exception as e: - print(f"Failed to update issue status: {e}") - raise - ``` - - - -### Step 2: Support API with Context - - - - ```typescript app/api/support/chat/route.ts - import { streamText } from 'ai' - import { createOpenAI } from '@ai-sdk/openai' - import { CustomerContextManager } from '@/lib/customer-context' - - const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! - }) - - const contextManager = new CustomerContextManager() - - interface Customer { - id: string - name: string - email: string - tier: 'free' | 'pro' | 'enterprise' - joinDate: string - } - - export async function POST(request: Request) { - const { - message, - customerId, - customer, - conversationHistory = [], - agentId - } = await request.json() - - try { - // Get customer history and context - const [history, contextResults] = await Promise.all([ - contextManager.getCustomerHistory(customerId, 5), - contextManager.searchCustomerContext(customerId, message) - ]) - - // Build customer context - const customerContext = ` -CUSTOMER PROFILE: -- Name: ${customer.name} -- Email: ${customer.email} -- Tier: ${customer.tier.toUpperCase()} -- Member since: ${customer.joinDate} - -RECENT INTERACTIONS (Last 5): -${history.map(h => `- ${h.timestamp}: ${h.type.toUpperCase()} - ${h.content.substring(0, 100)}...`).join('\n')} - -RELEVANT CONTEXT: -${contextResults.map(c => `- ${c.content.substring(0, 150)}... (${(c.similarity * 100).toFixed(1)}% relevant)`).join('\n')} - `.trim() - - // Determine if escalation is needed - const escalationKeywords = ['angry', 'frustrated', 'cancel', 'refund', 'legal', 'complaint', 'manager', 'supervisor'] - const needsEscalation = escalationKeywords.some(keyword => - message.toLowerCase().includes(keyword) - ) || customer.tier === 'enterprise' - - const systemPrompt = `You are a helpful customer support agent with access to complete customer history and context. - -CUSTOMER CONTEXT: -${customerContext} - -SUPPORT GUIDELINES: -1. **Personalization**: Address the customer by name and reference their tier/history when relevant -2. **Context Awareness**: Use previous interactions to inform your response -3. **Tier-Specific Service**: - - Free: Standard support, guide to self-service resources - - Pro: Priority support, detailed explanations, proactive suggestions - - Enterprise: White-glove service, immediate escalation path, dedicated attention - -4. **Issue Tracking**: If this is a new issue, categorize it (billing, technical, account, product) -5. **Escalation**: ${needsEscalation ? 'This interaction may need human agent escalation - provide helpful response but prepare escalation summary' : 'Handle directly unless customer specifically requests human agent'} - -RESPONSE STYLE: -- Professional but friendly -- Reference specific details from customer history when relevant -- Provide actionable next steps -- Include relevant links or resources for their tier level - -If you cannot resolve the issue completely, prepare a clear summary for escalation to human agents.` - - const messages = [ - { role: 'system' as const, content: systemPrompt }, - ...conversationHistory, - { role: 'user' as const, content: message } - ] - - const result = await streamText({ - model: openai('gpt-5'), - messages, - temperature: 0.3, - maxTokens: 800, - onFinish: async (completion) => { - // Store this interaction - await contextManager.addInteraction(customerId, { - type: 'chat', - content: `Customer: ${message}\nAgent: ${completion.text}`, - channel: 'web_chat', - outcome: needsEscalation ? 'escalated' : 'resolved', - agentId, - metadata: { - customerTier: customer.tier, - needsEscalation, - responseLength: completion.text.length - } - }) - - // If this looks like a new issue, track it - if (message.length > 50 && !contextResults.some(c => c.similarity > 0.8)) { - const issueCategory = categorizeIssue(message) - const priority = determinePriority(customer.tier, message) - - await contextManager.trackIssue(customerId, { - subject: message.substring(0, 100), - description: message, - category: issueCategory, - priority, - status: needsEscalation ? 'pending' : 'open' - }) - } - } - }) - - return result.toAIStreamResponse({ - data: { - needsEscalation, - customerTier: customer.tier, - contextCount: contextResults.length - } - }) - - } catch (error) { - console.error('Support chat error:', error) - return Response.json( - { error: 'Failed to process support request', details: error.message }, - { status: 500 } - ) - } - } - - function categorizeIssue(message: string): string { - const categories = { - billing: ['bill', 'charge', 'payment', 'refund', 'price', 'cost'], - technical: ['error', 'bug', 'broken', 'not working', 'crash', 'slow'], - account: ['login', 'password', 'access', 'settings', 'profile'], - product: ['feature', 'how to', 'tutorial', 'help', 'guide'] - } - - const messageLower = message.toLowerCase() - - for (const [category, keywords] of Object.entries(categories)) { - if (keywords.some(keyword => messageLower.includes(keyword))) { - return category - } - } - - return 'general' - } - - function determinePriority(tier: string, message: string): 'low' | 'medium' | 'high' | 'urgent' { - const urgentKeywords = ['urgent', 'critical', 'emergency', 'down', 'broken'] - const highKeywords = ['important', 'asap', 'soon', 'problem'] - - const messageLower = message.toLowerCase() - - if (urgentKeywords.some(keyword => messageLower.includes(keyword))) { - return 'urgent' - } - - if (tier === 'enterprise') { - return highKeywords.some(keyword => messageLower.includes(keyword)) ? 'urgent' : 'high' - } - - if (tier === 'pro') { - return highKeywords.some(keyword => messageLower.includes(keyword)) ? 'high' : 'medium' - } - - return 'low' - } - ``` - - - - ```python support_api.py - from fastapi import FastAPI, HTTPException - from fastapi.responses import StreamingResponse - from pydantic import BaseModel - from typing import List, Dict, Any, Optional - import openai - from customer_context import CustomerContextManager - import json - import os - import re - - app = FastAPI() - - openai_client = openai.AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY")) - context_manager = CustomerContextManager() - - class Customer(BaseModel): - id: str - name: str - email: str - tier: str - joinDate: str - - class SupportRequest(BaseModel): - message: str - customerId: str - customer: Customer - conversationHistory: List[Dict[str, str]] = [] - agentId: Optional[str] = None - - def categorize_issue(message: str) -> str: - """Categorize support issue based on message content""" - categories = { - 'billing': ['bill', 'charge', 'payment', 'refund', 'price', 'cost'], - 'technical': ['error', 'bug', 'broken', 'not working', 'crash', 'slow'], - 'account': ['login', 'password', 'access', 'settings', 'profile'], - 'product': ['feature', 'how to', 'tutorial', 'help', 'guide'] - } - - message_lower = message.lower() - - for category, keywords in categories.items(): - if any(keyword in message_lower for keyword in keywords): - return category - - return 'general' - - def determine_priority(tier: str, message: str) -> str: - """Determine issue priority based on tier and message content""" - urgent_keywords = ['urgent', 'critical', 'emergency', 'down', 'broken'] - high_keywords = ['important', 'asap', 'soon', 'problem'] - - message_lower = message.lower() - - if any(keyword in message_lower for keyword in urgent_keywords): - return 'urgent' - - if tier == 'enterprise': - return 'urgent' if any(keyword in message_lower for keyword in high_keywords) else 'high' - - if tier == 'pro': - return 'high' if any(keyword in message_lower for keyword in high_keywords) else 'medium' - - return 'low' - - @app.post("/support/chat") - async def support_chat(request: SupportRequest): - try: - # Get customer history and context - history = context_manager.get_customer_history(request.customerId, 5) - context_results = context_manager.search_customer_context(request.customerId, request.message) - - # Build customer context - customer_context = f""" -CUSTOMER PROFILE: -- Name: {request.customer.name} -- Email: {request.customer.email} -- Tier: {request.customer.tier.upper()} -- Member since: {request.customer.joinDate} - -RECENT INTERACTIONS (Last 5): -{chr(10).join([f"- {h['timestamp']}: {h['type'].upper()} - {h['content'][:100]}..." for h in history])} - -RELEVANT CONTEXT: -{chr(10).join([f"- {c['content'][:150]}... ({c['similarity']*100:.1f}% relevant)" for c in context_results])} - """.strip() - - # Determine if escalation is needed - escalation_keywords = ['angry', 'frustrated', 'cancel', 'refund', 'legal', 'complaint', 'manager', 'supervisor'] - needs_escalation = any(keyword in request.message.lower() for keyword in escalation_keywords) or request.customer.tier == 'enterprise' - - system_prompt = f"""You are a helpful customer support agent with access to complete customer history and context. - -CUSTOMER CONTEXT: -{customer_context} - -SUPPORT GUIDELINES: -1. **Personalization**: Address the customer by name and reference their tier/history when relevant -2. **Context Awareness**: Use previous interactions to inform your response -3. **Tier-Specific Service**: - - Free: Standard support, guide to self-service resources - - Pro: Priority support, detailed explanations, proactive suggestions - - Enterprise: White-glove service, immediate escalation path, dedicated attention - -4. **Issue Tracking**: If this is a new issue, categorize it (billing, technical, account, product) -5. **Escalation**: {'This interaction may need human agent escalation - provide helpful response but prepare escalation summary' if needs_escalation else 'Handle directly unless customer specifically requests human agent'} - -RESPONSE STYLE: -- Professional but friendly -- Reference specific details from customer history when relevant -- Provide actionable next steps -- Include relevant links or resources for their tier level - -If you cannot resolve the issue completely, prepare a clear summary for escalation to human agents.""" - - messages = [ - {"role": "system", "content": system_prompt}, - *request.conversationHistory, - {"role": "user", "content": request.message} - ] - - response = await openai_client.chat.completions.create( - model="gpt-5", - messages=messages, - temperature=0.3, - max_tokens=800, - stream=True - ) - - async def generate(): - full_response = "" - async for chunk in response: - if chunk.choices[0].delta.content: - content = chunk.choices[0].delta.content - full_response += content - yield f"data: {json.dumps({'content': content})}\n\n" - - # Store interaction after completion - context_manager.add_interaction(request.customerId, { - 'type': 'chat', - 'content': f"Customer: {request.message}\nAgent: {full_response}", - 'channel': 'web_chat', - 'outcome': 'escalated' if needs_escalation else 'resolved', - 'agentId': request.agentId, - 'metadata': { - 'customerTier': request.customer.tier, - 'needsEscalation': needs_escalation, - 'responseLength': len(full_response) - } - }) - - # Track new issues - if len(request.message) > 50 and not any(c['similarity'] > 0.8 for c in context_results): - issue_category = categorize_issue(request.message) - priority = determine_priority(request.customer.tier, request.message) - - context_manager.track_issue(request.customerId, { - 'subject': request.message[:100], - 'description': request.message, - 'category': issue_category, - 'priority': priority, - 'status': 'pending' if needs_escalation else 'open' - }) - - yield f"data: {json.dumps({'done': True, 'needsEscalation': needs_escalation})}\n\n" - - return StreamingResponse(generate(), media_type="text/plain") - - except Exception as e: - raise HTTPException(status_code=500, detail=f"Support chat error: {str(e)}") - - if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) - ``` - - - -### Step 3: Support Dashboard Interface - -```tsx app/support/page.tsx -'use client' - -import { useState, useEffect } from 'react' -import { useChat } from 'ai/react' -import { CustomerContextManager } from '@/lib/customer-context' - -interface Customer { - id: string - name: string - email: string - tier: 'free' | 'pro' | 'enterprise' - joinDate: string -} - -interface SupportTicket { - id: string - subject: string - status: 'open' | 'pending' | 'resolved' | 'closed' - priority: 'low' | 'medium' | 'high' | 'urgent' - category: string - createdAt: string -} - -export default function SupportDashboard() { - const [selectedCustomer, setSelectedCustomer] = useState(null) - const [customerHistory, setCustomerHistory] = useState([]) - const [tickets, setTickets] = useState([]) - const [showEscalation, setShowEscalation] = useState(false) - const [agentId] = useState('agent_001') // In real app, get from auth - - const contextManager = new CustomerContextManager() - - const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({ - api: '/api/support/chat', - body: { - customerId: selectedCustomer?.id, - customer: selectedCustomer, - agentId - }, - onFinish: (message, { data }) => { - if (data?.needsEscalation) { - setShowEscalation(true) - } - // Refresh customer history - if (selectedCustomer) { - loadCustomerHistory(selectedCustomer.id) - } - } - }) - - // Mock customers - in real app, fetch from your customer database - const mockCustomers: Customer[] = [ - { - id: 'cust_001', - name: 'Sarah Johnson', - email: 'sarah@example.com', - tier: 'pro', - joinDate: '2023-06-15' - }, - { - id: 'cust_002', - name: 'TechCorp Inc', - email: 'support@techcorp.com', - tier: 'enterprise', - joinDate: '2022-03-20' - }, - { - id: 'cust_003', - name: 'Mike Chen', - email: 'mike@startup.com', - tier: 'free', - joinDate: '2024-01-10' - } - ] - - const loadCustomerHistory = async (customerId: string) => { - try { - const history = await contextManager.getCustomerHistory(customerId, 10) - setCustomerHistory(history) - } catch (error) { - console.error('Failed to load customer history:', error) - } - } - - const handleCustomerSelect = async (customer: Customer) => { - setSelectedCustomer(customer) - await loadCustomerHistory(customer.id) - setShowEscalation(false) - } - - const getTierColor = (tier: string) => { - switch (tier) { - case 'enterprise': return 'bg-purple-100 text-purple-800' - case 'pro': return 'bg-blue-100 text-blue-800' - case 'free': return 'bg-gray-100 text-gray-800' - default: return 'bg-gray-100 text-gray-800' - } - } - - const getPriorityColor = (priority: string) => { - switch (priority) { - case 'urgent': return 'bg-red-100 text-red-800' - case 'high': return 'bg-orange-100 text-orange-800' - case 'medium': return 'bg-yellow-100 text-yellow-800' - case 'low': return 'bg-green-100 text-green-800' - default: return 'bg-gray-100 text-gray-800' - } - } - - return ( -
- {/* Customer List Sidebar */} -
-
-

Customers

-
-
- {mockCustomers.map((customer) => ( -
handleCustomerSelect(customer)} - className={`p-4 cursor-pointer hover:bg-gray-50 ${ - selectedCustomer?.id === customer.id ? 'bg-blue-50 border-r-2 border-blue-500' : '' - }`} - > -
-
{customer.name}
- - {customer.tier} - -
-
{customer.email}
-
- Member since {customer.joinDate} -
-
- ))} -
-
- - {/* Main Content */} -
- {selectedCustomer ? ( - <> - {/* Customer Header */} -
-
-
-

{selectedCustomer.name}

-

{selectedCustomer.email}

-
-
- - {selectedCustomer.tier.toUpperCase()} Customer - - {showEscalation && ( -
- Needs Escalation -
- )} -
-
-
- -
- {/* Chat Area */} -
- {/* Messages */} -
- {messages.length === 0 && ( -
-
Welcome to Support Chat
-

- Start a conversation with {selectedCustomer.name} -

-
-

Customer Tier: {selectedCustomer.tier}

-

Join Date: {selectedCustomer.joinDate}

-
-
- )} - - {messages.map((message) => ( -
-
-
- - {message.role === 'user' ? selectedCustomer.name : 'Support Agent'} - - - {new Date().toLocaleTimeString()} - -
-
{message.content}
-
-
- ))} - - {isLoading && ( -
-
-
-
- Agent is typing... -
-
-
- )} -
- - {/* Chat Input */} -
-
- - -
-
-
- - {/* Customer History Sidebar */} -
-
-

Customer History

-
-
- {customerHistory.map((interaction, index) => ( -
-
- {interaction.type} - - {new Date(interaction.timestamp).toLocaleDateString()} - -
-

- {interaction.content.length > 100 - ? `${interaction.content.substring(0, 100)}...` - : interaction.content - } -

- {interaction.outcome && ( -
- - {interaction.outcome} - -
- )} -
- ))} - - {customerHistory.length === 0 && ( -
-

No previous interactions

-
- )} -
-
-
- - ) : ( -
-
-
Customer Support
-

Select a customer to start a support conversation

-
-
- )} -
-
- ) -} -``` - -## Testing Your Support System - -### Step 4: Test Support Scenarios - -1. **Test Customer Tiers**: - - Free tier: Basic responses, self-service guidance - - Pro tier: Detailed help, proactive suggestions - - Enterprise: White-glove service, escalation readiness - -2. **Test Memory & Context**: - - Ask about a previous issue - - Reference customer preferences - - Follow up on unresolved tickets - -3. **Test Escalation Triggers**: - - Use keywords like "angry", "manager", "refund" - - Test enterprise customer automatic escalation - -This comprehensive customer support recipe provides the foundation for building intelligent, context-aware support systems that improve customer satisfaction through personalized service. - ---- - -*Customize this recipe based on your specific support workflows and customer needs.* diff --git a/apps/docs/cookbook/document-qa.mdx b/apps/docs/cookbook/document-qa.mdx deleted file mode 100644 index 5aa071eb..00000000 --- a/apps/docs/cookbook/document-qa.mdx +++ /dev/null @@ -1,877 +0,0 @@ ---- -title: "Document Q&A System" -description: "Build a chatbot that answers questions from your documents with citations and source references" ---- - -Create a powerful document Q&A system that can ingest PDFs, text files, and web pages, then answer questions with accurate citations. Perfect for documentation sites, research databases, or internal knowledge bases. - -## What You'll Build - -A document Q&A system that: -- **Ingests multiple file types** (PDFs, DOCX, text, URLs) -- **Answers questions accurately** with source citations -- **Provides source references** with page numbers and document titles -- **Handles follow-up questions** with conversation context -- **Supports multiple document collections** for different topics - -## Prerequisites - -- Node.js 18+ or Python 3.8+ -- Supermemory API key -- OpenAI API key -- Basic understanding of file handling - -## Implementation - -### Step 1: Document Processing System - - - - ```typescript lib/document-processor.ts - import { Supermemory } from 'supermemory' - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }) - - interface DocumentUpload { - file: File - collection: string - metadata?: Record - } - - export class DocumentProcessor { - async uploadDocument({ file, collection, metadata = {} }: DocumentUpload) { - try { - const formData = new FormData() - formData.append('file', file) - formData.append('containerTags', JSON.stringify([collection])) - formData.append('metadata', JSON.stringify({ - originalName: file.name, - fileType: file.type, - uploadedAt: new Date().toISOString(), - ...metadata - })) - - const response = await fetch('/api/upload-document', { - method: 'POST', - body: formData - }) - - if (!response.ok) { - throw new Error(`Upload failed: ${response.statusText}`) - } - - return await response.json() - } catch (error) { - console.error('Document upload error:', error) - throw error - } - } - - async uploadURL({ url, collection, metadata = {} }: { url: string, collection: string, metadata?: Record }) { - try { - const result = await client.add({ - content: url, - containerTag: collection, - metadata: { - type: 'url', - originalUrl: url, - uploadedAt: new Date().toISOString(), - ...metadata - } - }) - - return result - } catch (error) { - console.error('URL upload error:', error) - throw error - } - } - - async getDocumentStatus(documentId: string) { - try { - const memory = await client.documents.get(documentId) - return { - id: memory.id, - status: memory.status, - title: memory.title, - progress: memory.metadata?.progress || 0 - } - } catch (error) { - console.error('Status check error:', error) - throw error - } - } - - async listDocuments(collection: string) { - try { - const memories = await client.documents.list({ - containerTags: [collection], - limit: 50, - sort: 'updatedAt', - order: 'desc' - }) - - return memories.memories.map(memory => ({ - id: memory.id, - title: memory.title || memory.metadata?.originalName || 'Untitled', - type: memory.metadata?.fileType || memory.metadata?.type || 'unknown', - uploadedAt: memory.metadata?.uploadedAt, - status: memory.status, - url: memory.metadata?.originalUrl - })) - } catch (error) { - console.error('List documents error:', error) - throw error - } - } - } - ``` - - ```typescript app/api/upload-document/route.ts - import { NextRequest, NextResponse } from 'next/server' - import { Supermemory } from 'supermemory' - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }) - - export async function POST(request: NextRequest) { - try { - const formData = await request.formData() - const file = formData.get('file') as File - const containerTags = JSON.parse(formData.get('containerTags') as string) - const metadata = JSON.parse(formData.get('metadata') as string || '{}') - - if (!file) { - return NextResponse.json({ error: 'No file provided' }, { status: 400 }) - } - - const result = await client.documents.uploadFile({ - file: file, - containerTags: JSON.stringify(containerTags), - metadata: JSON.stringify(metadata) - }) - - return NextResponse.json({ - success: true, - documentId: result.id, - message: 'Document uploaded successfully' - }) - - } catch (error) { - console.error('Upload error:', error) - return NextResponse.json( - { error: 'Upload failed', details: error.message }, - { status: 500 } - ) - } - } - ``` - - - - ```python document_processor.py - from supermemory import Supermemory - import os - import json - from typing import Dict, List, Any, Optional - import requests - from datetime import datetime - - class DocumentProcessor: - def __init__(self): - self.client = Supermemory(api_key=os.getenv("SUPERMEMORY_API_KEY")) - - def upload_file(self, file_path: str, collection: str, metadata: Dict[str, Any] = None) -> Dict: - """Upload a local file to Supermemory""" - if metadata is None: - metadata = {} - - try: - with open(file_path, 'rb') as file: - result = self.client.documents.upload_file( - file=file, - container_tags=collection, - metadata=json.dumps({ - 'originalName': os.path.basename(file_path), - 'fileType': os.path.splitext(file_path)[1], - 'uploadedAt': datetime.now().isoformat(), - **metadata - }) - ) - return result - except Exception as e: - print(f"File upload error: {e}") - raise - - def upload_url(self, url: str, collection: str, metadata: Dict[str, Any] = None) -> Dict: - """Upload URL content to Supermemory""" - if metadata is None: - metadata = {} - - try: - result = self.client.add( - content=url, - container_tag=collection, - metadata={ - 'type': 'url', - 'originalUrl': url, - 'uploadedAt': datetime.now().isoformat(), - **metadata - } - ) - return result - except Exception as e: - print(f"URL upload error: {e}") - raise - - def get_document_status(self, document_id: str) -> Dict: - """Check document processing status""" - try: - memory = self.client.documents.get(document_id) - return { - 'id': memory.id, - 'status': memory.status, - 'title': memory.title, - 'progress': memory.metadata.get('progress', 0) if memory.metadata else 0 - } - except Exception as e: - print(f"Status check error: {e}") - raise - - def list_documents(self, collection: str) -> List[Dict]: - """List all documents in a collection""" - try: - memories = self.client.documents.list( - container_tags=[collection], - limit=50, - sort='updatedAt', - order='desc' - ) - - return [ - { - 'id': memory.id, - 'title': (memory.title or - memory.metadata.get('originalName') or - 'Untitled' if memory.metadata else 'Untitled'), - 'type': (memory.metadata.get('fileType') or - memory.metadata.get('type') or - 'unknown' if memory.metadata else 'unknown'), - 'uploadedAt': memory.metadata.get('uploadedAt') if memory.metadata else None, - 'status': memory.status, - 'url': memory.metadata.get('originalUrl') if memory.metadata else None - } - for memory in memories.memories - ] - except Exception as e: - print(f"List documents error: {e}") - raise - ``` - - - -### Step 2: Q&A API with Citations - - - - ```typescript app/api/qa/route.ts - import { streamText } from 'ai' - import { createOpenAI } from '@ai-sdk/openai' - import { Supermemory } from 'supermemory' - - const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! - }) - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }) - - export async function POST(request: Request) { - const { question, collection, conversationHistory = [] } = await request.json() - - try { - // Search for relevant documents - const searchResults = await client.search.documents({ - q: question, - containerTags: [collection], - limit: 8, - rerank: true, - includeFullDocs: false, - includeSummary: true, - onlyMatchingChunks: false, - chunkThreshold: 0.7 - }) - - if (searchResults.results.length === 0) { - return Response.json({ - answer: "I couldn't find any relevant information in the uploaded documents to answer your question.", - sources: [], - confidence: 0 - }) - } - - // Prepare context from search results - const context = searchResults.results.map((result, index) => { - const chunks = result.chunks - .filter(chunk => chunk.isRelevant) - .slice(0, 3) - .map(chunk => chunk.content) - .join('\n\n') - - return `[Document ${index + 1}: "${result.title}"]\n${chunks}` - }).join('\n\n---\n\n') - - // Prepare sources for citation - const sources = searchResults.results.map((result, index) => ({ - id: result.documentId, - title: result.title, - type: result.type, - relevantChunks: result.chunks.filter(chunk => chunk.isRelevant).length, - score: result.score, - citationNumber: index + 1 - })) - - const messages = [ - ...conversationHistory, - { - role: 'user' as const, - content: question - } - ] - - const result = await streamText({ - model: openai('gpt-5'), - messages, - system: `You are a helpful document Q&A assistant. Answer questions based ONLY on the provided document context. - -CONTEXT FROM DOCUMENTS: -${context} - -INSTRUCTIONS: -1. Answer the question using ONLY the information from the provided documents -2. Include specific citations in your response using [Document X] format -3. If the documents don't contain enough information, say so clearly -4. Be accurate and quote directly when possible -5. If multiple documents support a point, cite all relevant ones -6. Maintain a helpful, professional tone - -CITATION FORMAT: -- Use [Document 1], [Document 2], etc. to cite sources -- Place citations after the relevant information -- Example: "The process involves three steps [Document 1]. However, some experts recommend a four-step approach [Document 3]." - -If the question cannot be answered from the provided documents, respond with: "I don't have enough information in the provided documents to answer this question accurately."`, - temperature: 0.1, - maxTokens: 1000 - }) - - return result.toAIStreamResponse({ - data: { - sources, - searchResultsCount: searchResults.results.length, - totalResults: searchResults.total - } - }) - - } catch (error) { - console.error('Q&A error:', error) - return Response.json( - { error: 'Failed to process question', details: error.message }, - { status: 500 } - ) - } - } - ``` - - - - ```python qa_api.py - from fastapi import FastAPI, HTTPException - from fastapi.responses import StreamingResponse - from pydantic import BaseModel - from typing import List, Dict, Any, Optional - import openai - from supermemory import Supermemory - import json - import os - - app = FastAPI() - - openai_client = openai.AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY")) - supermemory_client = Supermemory(api_key=os.getenv("SUPERMEMORY_API_KEY")) - - class QARequest(BaseModel): - question: str - collection: str - conversationHistory: List[Dict[str, str]] = [] - - class QAResponse(BaseModel): - answer: str - sources: List[Dict[str, Any]] - confidence: float - searchResultsCount: int - - @app.post("/qa") - async def answer_question(request: QARequest): - try: - # Search for relevant documents - search_results = supermemory_client.search.documents( - q=request.question, - container_tags=[request.collection], - limit=8, - rerank=True, - include_full_docs=False, - include_summary=True, - only_matching_chunks=False, - chunk_threshold=0.7 - ) - - if not search_results.results: - return QAResponse( - answer="I couldn't find any relevant information in the uploaded documents to answer your question.", - sources=[], - confidence=0, - searchResultsCount=0 - ) - - # Prepare context from search results - context_parts = [] - sources = [] - - for index, result in enumerate(search_results.results): - relevant_chunks = [ - chunk.content for chunk in result.chunks - if chunk.is_relevant - ][:3] - - chunk_text = '\n\n'.join(relevant_chunks) - context_parts.append(f'[Document {index + 1}: "{result.title}"]\n{chunk_text}') - - sources.append({ - 'id': result.document_id, - 'title': result.title, - 'type': result.type, - 'relevantChunks': len([c for c in result.chunks if c.is_relevant]), - 'score': result.score, - 'citationNumber': index + 1 - }) - - context = '\n\n---\n\n'.join(context_parts) - - # Prepare messages - messages = [ - { - "role": "system", - "content": f"""You are a helpful document Q&A assistant. Answer questions based ONLY on the provided document context. - -CONTEXT FROM DOCUMENTS: -{context} - -INSTRUCTIONS: -1. Answer the question using ONLY the information from the provided documents -2. Include specific citations in your response using [Document X] format -3. If the documents don't contain enough information, say so clearly -4. Be accurate and quote directly when possible -5. If multiple documents support a point, cite all relevant ones -6. Maintain a helpful, professional tone - -CITATION FORMAT: -- Use [Document 1], [Document 2], etc. to cite sources -- Place citations after the relevant information -- Example: "The process involves three steps [Document 1]. However, some experts recommend a four-step approach [Document 3]." - -If the question cannot be answered from the provided documents, respond with: "I don't have enough information in the provided documents to answer this question accurately." """ - } - ] - - # Add conversation history - messages.extend(request.conversationHistory) - messages.append({"role": "user", "content": request.question}) - - # Get AI response - response = await openai_client.chat.completions.create( - model="gpt-5", - messages=messages, - temperature=0.1, - max_tokens=1000 - ) - - answer = response.choices[0].message.content - - return QAResponse( - answer=answer, - sources=sources, - confidence=min(search_results.results[0].score if search_results.results else 0, 1.0), - searchResultsCount=len(search_results.results) - ) - - except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to process question: {str(e)}") - - if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) - ``` - - - -### Step 3: Frontend Interface - -```tsx app/qa/page.tsx -'use client' - -import { useState, useRef } from 'react' -import { useChat } from 'ai/react' -import { DocumentProcessor } from '@/lib/document-processor' - -interface Document { - id: string - title: string - type: string - status: string - uploadedAt: string -} - -interface Source { - id: string - title: string - citationNumber: number - score: number - relevantChunks: number -} - -export default function DocumentQA() { - const [collection, setCollection] = useState('default-docs') - const [documents, setDocuments] = useState([]) - const [sources, setSources] = useState([]) - const [isUploading, setIsUploading] = useState(false) - const [uploadProgress, setUploadProgress] = useState>({}) - const fileInputRef = useRef(null) - - const processor = new DocumentProcessor() - - const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({ - api: '/api/qa', - body: { - collection - }, - onFinish: (message, { data }) => { - if (data?.sources) { - setSources(data.sources) - } - } - }) - - const handleFileUpload = async (event: React.ChangeEvent) => { - const files = event.target.files - if (!files || files.length === 0) return - - setIsUploading(true) - const newProgress: Record = {} - - try { - for (const file of Array.from(files)) { - newProgress[file.name] = 0 - setUploadProgress({ ...newProgress }) - - await processor.uploadDocument({ - file, - collection, - metadata: { - uploadedBy: 'user', - category: 'qa-document' - } - }) - - newProgress[file.name] = 100 - setUploadProgress({ ...newProgress }) - } - - // Refresh document list - await loadDocuments() - - // Clear file input - if (fileInputRef.current) { - fileInputRef.current.value = '' - } - - } catch (error) { - console.error('Upload failed:', error) - alert('Upload failed: ' + error.message) - } finally { - setIsUploading(false) - setUploadProgress({}) - } - } - - const loadDocuments = async () => { - try { - const docs = await processor.listDocuments(collection) - setDocuments(docs) - } catch (error) { - console.error('Failed to load documents:', error) - } - } - - const formatSources = (sources: Source[]) => { - if (!sources || sources.length === 0) return null - - return ( -
-

Sources:

-
- {sources.map((source) => ( -
- - Document {source.citationNumber} - - {source.title} - - ({source.relevantChunks} relevant chunks, {(source.score * 100).toFixed(1)}% match) - -
- ))} -
-
- ) - } - - return ( -
-
- {/* Document Management Panel */} -
-
-

Document Collection

- - {/* Collection Selector */} -
- - setCollection(e.target.value)} - className="w-full p-2 border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500" - placeholder="e.g., company-docs" - /> -
- - {/* File Upload */} -
- - -
- - {/* Upload Progress */} - {Object.keys(uploadProgress).length > 0 && ( -
- {Object.entries(uploadProgress).map(([filename, progress]) => ( -
-
- {filename} - {progress}% -
-
-
-
-
- ))} -
- )} - - {/* Document List */} -
- {documents.map((doc) => ( -
-
{doc.title}
-
- {doc.type} • {doc.status} -
-
- ))} -
- - -
-
- - {/* Q&A Interface */} -
-
-

Ask Questions

- - {/* Messages */} -
- {messages.length === 0 && ( -
- Upload documents and ask questions to get started! - -
-

Try asking:

-
    -
  • "What are the main findings?"
  • -
  • "Summarize the key points"
  • -
  • "What does section 3 say about...?"
  • -
-
-
- )} - - {messages.map((message) => ( -
-
{message.content}
- - {message.role === 'assistant' && sources.length > 0 && ( - formatSources(sources) - )} -
- ))} - - {isLoading && ( -
-
-
- Searching documents and generating answer... -
-
- )} -
- - {/* Input */} -
- - -
- - {documents.length === 0 && ( -

- Upload documents first to enable questions -

- )} -
-
-
-
- ) -} -``` - -## Testing Your Q&A System - -### Step 4: Test Document Processing - -1. **Upload Test Documents**: - - Upload a PDF manual or research paper - - Add a few web articles via URL - - Upload some text files with different topics - -2. **Test Question Types**: - ``` - Factual: "What is the definition of X mentioned in the documents?" - Analytical: "What are the pros and cons of approach Y?" - Comparative: "How does method A compare to method B?" - Summarization: "Summarize the main findings" - ``` - -3. **Verify Citations**: - - Check that citations appear in responses - - Verify citation numbers match source list - - Ensure sources show relevant metadata - -## Production Considerations - -### Performance Optimization - -```typescript -// Implement caching for frequently asked questions -const cacheKey = `qa:${collection}:${hashQuery(question)}` -const cachedResponse = await redis.get(cacheKey) - -if (cachedResponse) { - return JSON.parse(cachedResponse) -} - -// Cache response for 1 hour -await redis.setex(cacheKey, 3600, JSON.stringify(response)) -``` - -### Advanced Features - -1. **Follow-up Questions**: - ```typescript - // Track conversation context - const conversationHistory = messages.slice(-6) // Last 3 exchanges - ``` - -2. **Answer Confidence Scoring**: - ```typescript - const confidence = calculateConfidence({ - searchScore: searchResults.results[0]?.score || 0, - resultCount: searchResults.results.length, - chunkRelevance: avgChunkRelevance - }) - ``` - -3. **Multi-language Support**: - ```typescript - // Detect document language and adapt search - const detectedLanguage = await detectLanguage(question) - const searchResults = await client.search.documents({ - q: question, - filters: { - AND: [{ key: 'language', value: detectedLanguage }] - } - }) - ``` - -This recipe provides a complete foundation for building document Q&A systems with accurate citations and source tracking. - ---- - -*Customize this recipe based on your specific document types and use cases.* diff --git a/apps/docs/cookbook/inf-chat-blog.mdx b/apps/docs/cookbook/inf-chat-blog.mdx deleted file mode 100644 index f5c2fcbe..00000000 --- a/apps/docs/cookbook/inf-chat-blog.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Extending context windows in LLMs" -url: "https://supermemory.ai/blog/extending-context-windows-in-llms/" ---- diff --git a/apps/docs/cookbook/overview.mdx b/apps/docs/cookbook/overview.mdx deleted file mode 100644 index a36dcfb6..00000000 --- a/apps/docs/cookbook/overview.mdx +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: "Cookbook" -description: "Complete examples and recipes for building with Supermemory" -sidebarTitle: "Overview" ---- - -The Supermemory Cookbook provides complete, production-ready examples that show how to build real applications with Supermemory. Each recipe includes full implementation details, best practices, and common patterns. - -## Available Recipes - - - - Build an AI assistant that remembers user preferences and context across conversations - - - - Create a chatbot that answers questions from your documents with citations - - - - Build a support system that remembers customer history and provides personalized help - - - - Complete examples using Vercel AI SDK with Supermemory tools - - - -## Coming Soon - -We're working on more comprehensive recipes. Have a suggestion? [Let us know!](mailto:support@supermemory.ai) - - - - Organize and search through research papers and notes - - - - Build a personalized learning system with user isolation - - - - Create an AI assistant for your codebase and documentation - - - - Process and search through meeting recordings and notes - - - - -## Getting Help - -Can't find what you're looking for? - -- Browse [Search](/search) for specific feature usage -- Check the [AI SDK Examples](/cookbook/ai-sdk-integration) for complete implementations -- Reach out to [support](mailto:support@supermemory.ai) for help - -## Contributing Recipes - -Have a great Supermemory use case? We'd love to add it to the cookbook! - -[Suggest a recipe →](mailto:support@supermemory.ai?subject=Cookbook%20Recipe%20Suggestion) diff --git a/apps/docs/cookbook/perplexity-supermemory.mdx b/apps/docs/cookbook/perplexity-supermemory.mdx deleted file mode 100644 index 04bf0f2a..00000000 --- a/apps/docs/cookbook/perplexity-supermemory.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Perplexity with memory" -url: "https://supermemory.ai/blog/build-your-own-perplexity-in-15-minutes-with-supermemory/" ---- diff --git a/apps/docs/cookbook/personal-assistant.mdx b/apps/docs/cookbook/personal-assistant.mdx deleted file mode 100644 index 59c3e057..00000000 --- a/apps/docs/cookbook/personal-assistant.mdx +++ /dev/null @@ -1,864 +0,0 @@ ---- -title: "Personal AI Assistant" -description: "Build an AI assistant that remembers user preferences, habits, and context across conversations" ---- - -Build a personal AI assistant that learns and remembers everything about the user - their preferences, habits, work context, and conversation history. - -## What You'll Build - -A personal AI assistant that: -- **Remembers user preferences** (dietary restrictions, work schedule, communication style) -- **Maintains context** across multiple chat sessions -- **Provides personalized recommendations** based on user history -- **Handles multiple conversation topics** while maintaining context - -## Choose Your Implementation - - - - Thoroughly tested, production-ready. Uses FastAPI + Streamlit + OpenAI. - - - Modern React approach. Uses Next.js + Vercel AI SDK + Supermemory tools. - - - -## Prerequisites - -- **Python 3.8+** or **Node.js 18+** -- **Supermemory API key** ([get one here](https://console.supermemory.ai)) -- **OpenAI API key** ([get one here](https://platform.openai.com/api-keys)) - - -Never hardcode API keys in your code. Use environment variables. - - ---- - -## Python Implementation - -### Step 1: Project Setup - -```bash -mkdir personal-ai && cd personal-ai -python -m venv venv -source venv/bin/activate # On Windows: venv\Scripts\activate -pip install supermemory openai fastapi uvicorn python-dotenv streamlit requests -``` - -Create a `.env` file: - -```bash -SUPERMEMORY_API_KEY=your_supermemory_key_here -OPENAI_API_KEY=your_openai_key_here -``` - -### Step 2: Backend (FastAPI) - -Create `main.py`. Let's build it step by step: - -#### Import Dependencies - -```python -from fastapi import FastAPI, HTTPException -from fastapi.responses import StreamingResponse -from openai import AsyncOpenAI -from supermemory import Supermemory -import json -import os -import uuid -from dotenv import load_dotenv -``` - -- **FastAPI**: Web framework for building the API endpoint -- **StreamingResponse**: Enables real-time response streaming (words appear as they're generated) -- **AsyncOpenAI**: OpenAI client that supports async/await for non-blocking operations -- **Supermemory**: Client for storing and retrieving long-term memories -- **uuid**: Creates stable, deterministic user IDs from emails - -#### Initialize Application and Clients - -```python -load_dotenv() -app = FastAPI() - -openai_client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY")) -supermemory_client = Supermemory(api_key=os.getenv("SUPERMEMORY_API_KEY")) -``` - -`load_dotenv()` loads API keys from your `.env` file into environment variables. We create two clients: -- **OpenAI client**: Handles conversations and generates responses -- **Supermemory client**: Stores and retrieves user-specific memories - -These are separate because you can swap providers independently (e.g., switch from OpenAI to Anthropic without changing memory logic). - -#### Define System Prompt - -```python -SYSTEM_PROMPT = """You are a highly personalized AI assistant. - -MEMORY MANAGEMENT: -1. When users share personal information, store it immediately -2. Search for relevant context before responding -3. Use past conversations to inform current responses - -Always be helpful while respecting privacy.""" -``` - -This prompt guides the assistant's behavior. It tells the AI to: -- Be proactive about learning user preferences -- Always search memory before responding -- Respect privacy boundaries - -The system prompt is injected at the start of every conversation, so the AI consistently follows these rules. - -#### Create Identity Helpers - -```python -def normalize_email(email: str) -> str: - return (email or "").strip().lower() - -def stable_user_id_from_email(email: str) -> str: - norm = normalize_email(email) - if not norm: - raise ValueError("Email is required") - return uuid.uuid5(uuid.NAMESPACE_DNS, norm).hex -``` - -**Why normalize?** `"User@Mail.com"` and `" user@mail.com "` should map to the same person. We trim whitespace and lowercase to ensure consistency. - -**Why UUIDv5?** It's deterministic—same email always produces the same ID. This means: -- User memories persist across sessions -- No raw emails in logs or database tags -- Privacy-preserving yet stable identity - -We use `uuid.NAMESPACE_DNS` as the namespace to ensure uniqueness. - -#### Memory Search Function - -```python -async def search_user_memories(query: str, container_tag: str) -> str: - try: - results = supermemory_client.search.memories( - q=query, - container_tag=container_tag, - limit=5 - ) - if results.results: - context = "\n".join([r.memory for r in results.results]) - return f"Relevant memories:\n{context}" - return "No relevant memories found." - except Exception as e: - return f"Error searching memories: {e}" -``` - -This searches the user's memory store for context relevant to their current message. - -**Parameters:** -- `q`: The search query (usually the user's latest message) -- `container_tag`: Isolates memories per user (e.g., `user_abc123`) -- `limit=5`: Returns top 5 most relevant memories - -**Why search before responding?** The AI can provide personalized answers based on what it knows about the user (e.g., dietary preferences, work context, communication style). - -**Error handling:** If memory search fails, we return a fallback message instead of crashing. The conversation continues even if memory has a hiccup. - -#### Memory Storage Function - -```python -async def add_user_memory(content: str, container_tag: str, email: str = None): - try: - supermemory_client.add( - content=content, - container_tag=container_tag, - metadata={"type": "personal_info", "email": normalize_email(email) if email else None} - ) - except Exception as e: - print(f"Error adding memory: {e}") -``` - -Stores new information about the user. - -**Parameters:** -- `content`: The text to remember -- `container_tag`: User isolation tag -- `metadata`: Additional context (type of info, associated email) - -**Why metadata?** Makes it easier to filter and organize memories later (e.g., "show me all personal_info memories"). - -**Error handling:** We log errors but don't crash. Failing to save one memory shouldn't break the entire conversation. - -#### Main Chat Endpoint - -```python -@app.post("/chat") -async def chat_endpoint(data: dict): - messages = data.get("messages", []) - email = data.get("email") - - if not messages: - raise HTTPException(status_code=400, detail="No messages provided") - if not email: - raise HTTPException(status_code=400, detail="Email required") -``` - -This endpoint receives the chat request. It expects: -- `messages`: Full conversation history `[{role: "user", content: "..."}]` -- `email`: User's email for identity - -**Why require email?** Without it, we can't create a stable user ID, meaning no persistent personalization. - -#### Derive User Identity - -```python - try: - user_id = stable_user_id_from_email(email) - except ValueError as e: - raise HTTPException(status_code=400, detail=str(e)) - - container_tag = f"user_{user_id}" -``` - -Convert email → stable user ID → container tag. - -The container tag (`user_abc123`) isolates this user's memories from everyone else's. Each user has their own "memory box." - -#### Search and Inject Memories - -```python - user_message = messages[-1]["content"] - memory_context = await search_user_memories(user_message, container_tag) - - enhanced_messages = [ - {"role": "system", "content": f"{SYSTEM_PROMPT}\n\n{memory_context}"} - ] + messages -``` - -We take the user's latest message, search for relevant memories, then inject them into the system prompt. - -**Example:** -``` -Original: "What should I eat for breakfast?" - -Enhanced system message: -"You are a helpful assistant... [system prompt] - -Relevant memories: -- User is vegetarian -- User works out at 6 AM -- User prefers quick meals" -``` - -Now the AI can answer: "Try overnight oats with plant-based protein—perfect for post-workout!" - -#### Stream OpenAI Response - -```python - try: - response = await openai_client.chat.completions.create( - model="gpt-5", - messages=enhanced_messages, - temperature=0.7, - stream=True - ) -``` - -**Key parameters:** -- `model="gpt-5"`: Fast, capable model -- `messages`: Full conversation + memory context -- `temperature=0.7`: Balanced creativity (0=deterministic, 1=creative) -- `stream=True`: Enables word-by-word streaming - -**Why stream?** Users see responses appear in real-time instead of waiting for the complete answer. Much better UX. - -#### Handle Streaming - -```python - async def generate(): - try: - async for chunk in response: - if chunk.choices[0].delta.content: - content = chunk.choices[0].delta.content - yield f"data: {json.dumps({'content': content})}\n\n" - except Exception as e: - yield f"data: {json.dumps({'error': str(e)})}\n\n" -``` - -This async generator: -1. Receives chunks from OpenAI as they're generated -2. Extracts the text content from each chunk -3. Formats it as Server-Sent Events (SSE): `data: {...}\n\n` -4. Yields it to the client - -**SSE format** is a web standard for server→client streaming. The frontend can process each chunk as it arrives. - -#### Optional Memory Storage - -```python - if "remember this" in user_message.lower(): - await add_user_memory(user_message, container_tag, email=email) -``` - -After streaming completes, check if the user explicitly asked to remember something. If yes, store it. - -**Why opt-in?** Gives users control over what gets remembered. You could also make this automatic based on content analysis. - -#### Return Streaming Response - -```python - return StreamingResponse(generate(), media_type="text/plain") - - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) -``` - -`StreamingResponse` keeps the HTTP connection open and sends chunks as they're generated. The frontend receives them in real-time. - -#### Local Development Server - -```python -if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) -``` - -Run with `python main.py` and the server starts on port 8000. `0.0.0.0` means it accepts connections from any IP (useful for testing from other devices). - -### Step 3: Frontend (Streamlit) - -Create `streamlit_app.py`: - - - -```python -import streamlit as st -import requests -import json -import uuid - -st.set_page_config(page_title="Personal AI Assistant", page_icon="🤖", layout="wide") - -def normalize_email(email: str) -> str: - return (email or "").strip().lower() - -def stable_user_id_from_email(email: str) -> str: - return uuid.uuid5(uuid.NAMESPACE_DNS, normalize_email(email)).hex - -# Session state -if 'messages' not in st.session_state: - st.session_state.messages = [] -if 'user_name' not in st.session_state: - st.session_state.user_name = None -if 'email' not in st.session_state: - st.session_state.email = None -if 'user_id' not in st.session_state: - st.session_state.user_id = None - -st.title("🤖 Personal AI Assistant") -st.markdown("*Your AI that learns and remembers*") - -with st.sidebar: - st.header("👤 User Profile") - - if not st.session_state.user_name or not st.session_state.email: - name = st.text_input("What should I call you?") - email = st.text_input("Email", placeholder="you@example.com") - - if st.button("Get Started"): - if name and email: - st.session_state.user_name = name - st.session_state.email = normalize_email(email) - st.session_state.user_id = stable_user_id_from_email(st.session_state.email) - st.session_state.messages.append({ - "role": "user", - "content": f"Hi! My name is {name}." - }) - st.rerun() - else: - st.warning("Please enter both fields.") - else: - st.write(f"**Name:** {st.session_state.user_name}") - st.write(f"**Email:** {st.session_state.email}") - if st.button("Reset Conversation"): - st.session_state.messages = [] - st.rerun() - -if st.session_state.user_name and st.session_state.email: - for message in st.session_state.messages: - with st.chat_message(message["role"]): - st.markdown(message["content"]) - - if prompt := st.chat_input("Message..."): - st.session_state.messages.append({"role": "user", "content": prompt}) - with st.chat_message("user"): - st.markdown(prompt) - - with st.chat_message("assistant"): - try: - response = requests.post( - "http://localhost:8000/chat", - json={ - "messages": st.session_state.messages, - "email": st.session_state.email - }, - stream=True, - timeout=30 - ) - - if response.status_code == 200: - full_response = "" - for line in response.iter_lines(): - if line: - try: - data = json.loads(line.decode('utf-8').replace('data: ', '')) - if 'content' in data: - full_response += data['content'] - except: - continue - - st.markdown(full_response) - st.session_state.messages.append({"role": "assistant", "content": full_response}) - else: - st.error(f"Error: {response.status_code}") - except Exception as e: - st.error(f"Error: {e}") -else: - st.info("Please enter your profile in the sidebar") -``` - - - -### Step 4: Run It - -Terminal 1 - Start backend: -```bash -python main.py -``` - -Terminal 2 - Start frontend: -```bash -streamlit run streamlit_app.py -``` - -Open `http://localhost:8501` in your browser. - ---- - -## TypeScript Implementation - -### Step 1: Project Setup - -```bash -npx create-next-app@latest personal-ai --typescript --tailwind --app -cd personal-ai -npm install @supermemory/tools ai @ai-sdk/openai -``` - -Create `.env.local`: - -```bash -SUPERMEMORY_API_KEY=your_supermemory_key_here -OPENAI_API_KEY=your_openai_key_here -``` - -### Step 2: API Route - -Create `app/api/chat/route.ts`. Let's break it down: - -#### Import Dependencies - -```typescript -import { streamText } from 'ai' -import { createOpenAI } from '@ai-sdk/openai' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' -``` - -- **streamText**: Vercel AI SDK function that handles streaming responses and tool calling -- **createOpenAI**: Factory function to create an OpenAI provider -- **supermemoryTools**: Pre-built tools for memory search and storage - -#### Initialize OpenAI Provider - -```typescript -const openai = createOpenAI({ - apiKey: process.env.OPENAI_API_KEY! -}) -``` - -Creates an OpenAI provider configured with your API key. The `!` tells TypeScript "this definitely exists" (because we set it in `.env.local`). - -This provider object will be passed to `streamText` to specify which AI model to use. - -#### Define System Prompt - -```typescript -const SYSTEM_PROMPT = `You are a highly personalized AI assistant. - -When users share personal information, remember it using the addMemory tool. -Before responding, search your memories using searchMemories to provide personalized help. -Always be helpful while respecting privacy.` -``` - -This guides the AI's behavior and tells it: -- **When to use tools**: Search memories before responding, add memories when users share info -- **Personality**: Be helpful and personalized -- **Boundaries**: Respect privacy - -The AI SDK uses this to decide when to call `searchMemories` and `addMemory` tools automatically. - -#### Create POST Handler - -```typescript -export async function POST(req: Request) { - try { - const { messages, email } = await req.json() -``` - -Next.js App Router convention: export an async function named after the HTTP method. This handles POST requests to `/api/chat`. - -We extract: -- `messages`: Chat history array `[{role, content}]` -- `email`: User identifier - -#### Validate Input - -```typescript - if (!messages?.length) { - return new Response('No messages provided', { status: 400 }) - } - if (!email) { - return new Response('Email required', { status: 400 }) - } -``` - -**Why validate?** Prevents crashes from malformed requests. We need: -- At least one message to respond to -- An email to isolate user memories - -Without email, we can't maintain personalization across sessions. - -#### Create Container Tag - -```typescript - const containerTag = `user_${email.toLowerCase().trim()}` -``` - -Convert email to a container tag for memory isolation. - -**Simpler than Python**: We skip UUID generation here for simplicity. In production, you might want to hash the email for privacy: - -```typescript -// Optional: More privacy-preserving approach -import crypto from 'crypto' -const containerTag = `user_${crypto.createHash('sha256').update(email).digest('hex').slice(0, 16)}` -``` - -#### Call streamText with Tools - -```typescript - const result = streamText({ - model: openai('gpt-5'), - messages, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: [containerTag] - }), - system: SYSTEM_PROMPT - }) -``` - -This is where the magic happens! Let's break down each parameter: - -**`model: openai('gpt-5')`** -- Specifies which AI model to use -- The AI SDK handles the API calls - -**`messages`** -- Full conversation history -- Format: `[{role: "user"|"assistant", content: "..."}]` - -**`tools: supermemoryTools(...)`** -- Gives the AI access to memory operations -- The AI SDK automatically: - - Decides when to call tools based on the conversation - - Calls `searchMemories` when it needs context - - Calls `addMemory` when users share information - - Handles tool execution and error handling - -**`containerTags: [containerTag]`** -- Scopes all memory operations to this specific user -- Ensures User A can't access User B's memories - -**`system: SYSTEM_PROMPT`** -- Guides the AI's behavior and tool usage - -**How tools work:** -1. User: "Remember that I'm vegetarian" -2. AI SDK detects this is memory-worthy -3. Automatically calls `addMemory("User is vegetarian")` -4. Stores in Supermemory with the user's container tag -5. Responds: "Got it, I'll remember that!" - -Later: -1. User: "What should I eat?" -2. AI SDK calls `searchMemories("food preferences")` -3. Retrieves: "User is vegetarian" -4. Responds: "How about a delicious veggie stir-fry?" - -**No manual tool handling needed!** The AI SDK manages the entire flow. - -#### Return Streaming Response - -```typescript - return result.toAIStreamResponse() -``` - -`toAIStreamResponse()` converts the streaming result into a format the frontend can consume. It: -- Sets appropriate headers for streaming -- Formats data for the `useChat` hook -- Handles errors gracefully - -This returns immediately (doesn't wait for completion), and chunks stream to the client as they're generated. - -#### Error Handling - -```typescript - } catch (error: any) { - console.error('Chat error:', error) - return new Response(error.message, { status: 500 }) - } -} -``` - -Catches any errors (API failures, tool errors, etc.) and returns a clean error response. - -**Why log to console?** In production, you'd send this to a monitoring service (Sentry, DataDog, etc.) to track issues. - ---- - -**Key Differences from Python:** - -| Aspect | Python | TypeScript | -|--------|--------|------------| -| **Memory Search** | Manual `search_user_memories()` call | AI SDK calls `searchMemories` tool automatically | -| **Memory Add** | Manual `add_user_memory()` call | AI SDK calls `addMemory` tool automatically | -| **Tool Decision** | You decide when to search/add | AI decides based on conversation context | -| **Streaming** | Manual SSE formatting | `toAIStreamResponse()` handles it | -| **Error Handling** | Try/catch in each function | AI SDK handles tool errors | - -**Python = Manual Control** -You explicitly search and add memories. More control, more code. - -**TypeScript = AI-Driven** -The AI decides when to use tools. Less code, more "magic." - -### Step 3: Chat UI - -Replace `app/page.tsx`: - - - -```typescript -'use client' -import { useChat } from 'ai/react' -import { useState } from 'react' - -export default function ChatPage() { - const [email, setEmail] = useState('') - const [userName, setUserName] = useState('') - const [tempEmail, setTempEmail] = useState('') - const [tempName, setTempName] = useState('') - - const { messages, input, handleInputChange, handleSubmit } = useChat({ - api: '/api/chat', - body: { email } - }) - - if (!email) { - return ( -
-
-

🤖 Personal AI Assistant

- setTempName(e.target.value)} - className="w-full px-4 py-2 border rounded-lg" - /> - setTempEmail(e.target.value)} - className="w-full px-4 py-2 border rounded-lg" - /> - -
-
- ) - } - - return ( -
-
- {messages.map((message) => ( -
-

{message.content}

-
- ))} -
- -
- - -
-
- ) -} -``` - -
- -### Step 4: Run It - -```bash -npm run dev -``` - -Open `http://localhost:3000` - ---- - -## Testing Your Assistant - -Try these conversations to test memory: - -**Personal Preferences:** -``` -User: "I'm Sarah, a product manager. I prefer brief responses." -[Later] -User: "What's a good way to prioritize features?" -Assistant: [Should reference PM role and brevity preference] -``` - -**Dietary & Lifestyle:** -``` -User: "Remember I'm vegan and work out at 6 AM." -[Later] -User: "Suggest a quick breakfast." -Assistant: [Should suggest vegan options for pre/post workout] -``` - -**Work Context:** -``` -User: "I'm working on a React project with TypeScript." -[Later] -User: "Help me with state management." -Assistant: [Should suggest TypeScript-specific solutions] -``` - -## Verify Memory Storage - -### Python - -Create `check_memories.py`: - -```python -from supermemory import Supermemory -import os -from dotenv import load_dotenv - -load_dotenv() -client = Supermemory(api_key=os.getenv("SUPERMEMORY_API_KEY")) - -# Replace with your user_id from console logs -user_id = "your_user_id_here" -container_tag = f"user_{user_id}" - -memories = client.documents.list( - container_tags=[container_tag], - limit=20, - sort="updatedAt", - order="desc" -) - -print(f"Found {len(memories.memories)} memories:") -for i, memory in enumerate(memories.memories): - full = client.documents.get(id=memory.id) - print(f"\n{i + 1}. {full.content}") -``` - -### TypeScript - -Create `scripts/check-memories.ts`: - -```typescript -const userId = "your_user_id_here" -const containerTag = `user_${userId}` - -const response = await fetch('https://api.supermemory.ai/v3/memories', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - containerTags: [containerTag], - limit: 20, - sort: 'updatedAt', - order: 'desc' - }) -}) - -const data = await response.json() -console.log(`Found ${data.memories?.length || 0} memories`) -``` - -## Troubleshooting - -**Memory not persisting?** -- Verify container tags are consistent -- Check API key has write permissions -- Ensure email is properly normalized - -**Responses not personalized?** -- Increase search limit to find more memories -- Check that memories are being added -- Verify system prompt guides tool usage - -**Performance issues?** -- Reduce search limits -- Implement caching for frequent queries -- Use appropriate thresholds - ---- - -*Built with Supermemory. Customize based on your needs.* diff --git a/apps/docs/docs.json b/apps/docs/docs.json index d3a62eff..e72c74df 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -3,9 +3,10 @@ "api": { "examples": { "defaults": "required", - "languages": ["javascript", "python", "curl"] + "languages": ["typescript", "python", "bash"], + "prefill": true }, - "openapi": "https://api.supermemory.ai/v3/openapi" + "openapi": "https://api.supermemory.ai/v4/openapi" }, "colors": { "dark": "#1E3A8A", @@ -13,7 +14,7 @@ "primary": "#1E3A8A" }, "contextual": { - "options": ["copy", "view", "chatgpt", "claude"] + "options": ["copy", "view", "assistant", "chatgpt", "claude"] }, "favicon": "/favicon.png", "fonts": { @@ -43,6 +44,10 @@ "name": "supermemory | Memory API for the AI era", "navbar": { "links": [ + { + "href": "https://supermemory.ai/changelog", + "label": "Changelog" + }, { "href": "mailto:support@supermemory.com", "label": "Support" @@ -56,29 +61,23 @@ }, "navigation": { "tabs": [ + { + "tab": "Overview", + "pages": ["index"] + }, { "icon": "code", "anchors": [ { - "anchor": "Your Dashboard", - "href": "https://console.supermemory.ai", - "icon": "play" - }, - { - "anchor": "Developer Platform", + "anchor": "Developer Platform (API)", "pages": [ { "group": "Getting Started", - "pages": ["intro", "quickstart", "vibe-coding"] - }, - { - "group": "Self-Hosting", "pages": [ - "self-hosting/overview", - "self-hosting/quickstart", - "self-hosting/configuration", - "self-hosting/embeddings", - "self-hosting/local-vs-enterprise" + "overview/what-is-supermemory", + "overview/comparison", + "quickstart", + "agents-and-mcp" ] }, { @@ -87,41 +86,47 @@ "concepts/how-it-works", "concepts/graph-memory", "concepts/content-types", - "concepts/super-rag", - "concepts/memory-vs-rag", - "concepts/container-tags", - "concepts/filtering", - "concepts/user-profiles", - "concepts/customization", - "authentication" + { + "group": "Retrieval", + "icon": "search", + "pages": ["concepts/super-rag", "concepts/memory-vs-rag"] + }, + { + "group": "Multi-tenancy and filtering", + "icon": "users", + "pages": [ + "concepts/multi-tenancy", + "concepts/multi-tenancy-examples", + "concepts/container-tags", + "concepts/filtering" + ] + }, + { + "group": "User Profiles", + "icon": "id-card", + "pages": ["concepts/user-profiles", "user-profiles/buckets"] + } ] }, { "group": "Using supermemory", "pages": [ - "add-memories", - "search", - "user-profiles", + "using-supermemory", + "authentication", + "concepts/customization", { - "group": "Manage Content", - "icon": "folder-cog", + "group": "Ingestion", + "icon": "download", "pages": [ - "document-operations", - "memory-operations", - "memory-review" + "ingestion/add-memories", + "ingestion/document-operations" ] }, - "overview/use-cases" - ] - }, - { - "group": "Connectors and sync", - "pages": [ - "connectors/overview", { "group": "Connectors", "icon": "plug", "pages": [ + "connectors/overview", "connectors/notion", "connectors/google-drive", "connectors/gmail", @@ -129,11 +134,80 @@ "connectors/s3", "connectors/granola", "connectors/github", - "connectors/web-crawler" + "connectors/web-crawler", + "connectors/troubleshooting", + "connectors/managing-resources" ] }, - "connectors/troubleshooting", - "memory-api/connectors/managing-resources" + { + "group": "Recall", + "icon": "upload", + "pages": [ + "recall/search", + "recall/user-profiles", + "recall/memory-operations", + "recall/memory-review" + ] + }, + { + "group": "SMFS", + "icon": "database", + "pages": [ + "smfs/overview", + "smfs/install", + "smfs/mount", + "smfs/bash-tool", + "smfs/bash-tool-python", + { + "group": "Providers", + "icon": "cloud", + "pages": [ + "smfs/providers/daytona", + "smfs/providers/e2b", + "smfs/providers/vercel", + "smfs/providers/cloudflare" + ] + }, + "smfs/examples" + ] + }, + "concepts/rules" + ] + }, + { + "group": "Deployment", + "pages": [ + { + "group": "Supermemory local", + "icon": "server", + "pages": [ + "self-hosting/overview", + "self-hosting/quickstart", + "self-hosting/configuration", + "self-hosting/embeddings", + "self-hosting/providers", + "self-hosting/local-vs-enterprise" + ] + } + ] + }, + { + "group": "Other resources", + "pages": [ + { + "group": "Benchmarking", + "icon": "flask-conical", + "pages": [ + "memorybench/overview", + "memorybench/extend-benchmark", + "memorybench/extend-provider", + "memorybench/memscore" + ] + }, + "overview/billing", + "overview/security", + "overview/use-cases", + "overview/analytics" ] }, { @@ -148,49 +222,9 @@ } ] }, - { - "anchor": "Supermemory MCP", - "icon": "terminal", - "pages": [ - "supermemory-mcp/mcp", - "supermemory-mcp/setup", - { - "group": "Setups", - "icon": "layers", - "pages": ["supermemory-mcp/claude-desktop"] - } - ] - }, - { - "anchor": "SMFS", - "icon": "database", - "pages": [ - "smfs/overview", - "smfs/install", - "smfs/mount", - "smfs/bash-tool", - "smfs/bash-tool-python", - { - "group": "Providers", - "icon": "cloud", - "pages": [ - "smfs/providers/daytona", - "smfs/providers/e2b", - "smfs/providers/vercel", - "smfs/providers/cloudflare" - ] - }, - "smfs/examples" - ] - } - ], - "tab": "Developer Platform" - }, - { - "icon": "plug", - "anchors": [ { "anchor": "API Integrations", + "icon": "plug", "pages": [ "integrations/supermemory-sdk", "integrations/ai-sdk", @@ -207,6 +241,7 @@ "integrations/memory-graph", "integrations/claude-memory", "integrations/pipecat", + "integrations/cartesia", "integrations/n8n", "integrations/viasocket", "integrations/zapier", @@ -216,123 +251,214 @@ "pages": ["migration/tools-v2-upgrade"] } ] + }, + { + "anchor": "API Reference", + "icon": "unplug", + "openapi": "https://api.supermemory.ai/v4/openapi", + "pages": [ + "api-reference/overview", + "authentication", + { + "group": "Ingest", + "icon": "download", + "pages": [ + "api-reference/ingest", + "POST /v3/documents", + "POST /v3/documents/file", + "POST /v3/documents/batch", + "POST /v4/conversations", + "GET /v3/documents/{id}" + ] + }, + { + "group": "Recall", + "icon": "search", + "pages": [ + "api-reference/search", + "POST /v4/search", + "POST /v3/search", + "api-reference/profiles", + "POST /v4/profile", + "POST /v4/profile/buckets" + ] + }, + { + "group": "Documents", + "icon": "file-text", + "pages": [ + "api-reference/documents", + "POST /v3/documents/list", + "GET /v3/documents/processing", + "PATCH /v3/documents/{id}", + "DELETE /v3/documents/{id}", + "DELETE /v3/documents/bulk", + "GET /v3/documents/{id}/chunks", + "GET /v3/documents/{id}/file-url" + ] + }, + { + "group": "Memories", + "icon": "database", + "pages": [ + "api-reference/memories", + "POST /v4/memories", + "POST /v4/memories/list", + "PATCH /v4/memories", + "DELETE /v4/memories", + "POST /v4/memories/forget-matching" + ] + }, + { + "group": "Container tags", + "icon": "tags", + "pages": [ + "api-reference/container-tags", + "GET /v3/container-tags/{containerTag}", + "PATCH /v3/container-tags/{containerTag}", + "DELETE /v3/container-tags/{containerTag}", + "POST /v3/container-tags/merge", + "GET /v3/container-tags/merge/{mergeId}" + ] + }, + { + "group": "Connections", + "icon": "plug", + "pages": [ + "api-reference/connections", + "POST /v3/connections/{provider}", + "POST /v3/connections/list", + "GET /v3/connections/{connectionId}", + "POST /v3/connections/{connectionId}/configure", + "GET /v3/connections/{connectionId}/resources", + "POST /v3/connections/{provider}/import", + "POST /v3/connections/{provider}/documents", + "POST /v3/connections/{provider}/connection", + "DELETE /v3/connections/{connectionId}", + "DELETE /v3/connections/{provider}" + ] + }, + { + "group": "Settings", + "icon": "settings", + "pages": [ + "api-reference/settings", + "GET /v3/settings", + "PATCH /v3/settings", + "POST /v3/settings/suggest-buckets", + "POST /v3/settings/reset" + ] + } + ] } ], - "tab": "API Integrations" + "tab": "Developer Platform" }, { "icon": "puzzle", "anchors": [ { - "anchor": "Plugins", + "anchor": "Plugins and MCP", + "icon": "puzzle", "pages": [ - "integrations/openclaw", - "integrations/claude-code", - "integrations/opencode", - "integrations/codex", - "integrations/hermes" - ] - } - ], - "tab": "Plugins" - }, - { - "icon": "book-open", - "anchors": [ - { - "anchor": "API Reference", - "icon": "unplug", - "openapi": "https://api.supermemory.ai/v3/openapi" - } - ], - "tab": "API Reference" - }, - { - "icon": "flask-conical", - "anchors": [ - { - "anchor": "MemoryBench", - "icon": "flask-conical", - "pages": [ - "memorybench/overview", - "memorybench/github", { - "group": "Getting Started", - "pages": ["memorybench/installation", "memorybench/quickstart"] - }, - { - "group": "Development", + "group": "Supermemory MCP", + "icon": "terminal", "pages": [ - "memorybench/architecture", - "memorybench/extend-provider", - "memorybench/extend-benchmark", - "memorybench/contributing" + "supermemory-mcp/mcp", + "supermemory-mcp/setup", + { + "group": "Setups", + "icon": "layers", + "pages": ["supermemory-mcp/claude-desktop"] + } ] }, { - "group": "Reference", + "group": "Plugins", + "icon": "puzzle", "pages": [ - "memorybench/memscore", - "memorybench/cli", - "memorybench/integrations" + "integrations/openclaw", + "integrations/claude-code", + "integrations/opencode", + "integrations/codex", + "integrations/hermes" ] } ] } ], - "tab": "MemoryBench" + "tab": "Plugins and MCP" }, { - "icon": "chef-hat", - "anchors": [ + "tab": "Company Brain", + "groups": [ { - "anchor": "Cookbook", - "icon": "chef-hat", + "group": "Concepts", "pages": [ - "cookbook/overview", - { - "group": "Quick Start Recipes", - "pages": [ - "cookbook/personal-assistant", - "cookbook/document-qa", - "cookbook/customer-support", - "cookbook/ai-sdk-integration", - "cookbook/perplexity-supermemory", - "cookbook/chat-with-gdrive" - ] - } + "company-brain/overview", + "company-brain/setup", + "company-brain/permissions", + "company-brain/connectors", + "company-brain/automations", + "company-brain/outside-slack" + ] + }, + { + "group": "What you can do", + "pages": [ + "company-brain/use-cases/overview", + "company-brain/use-cases/support", + "company-brain/use-cases/incidents", + "company-brain/use-cases/support-escalation", + "company-brain/use-cases/meeting-recall", + "company-brain/use-cases/knowledge-recall", + "company-brain/use-cases/acting-in-tools", + "company-brain/use-cases/greeting", + "company-brain/use-cases/sandbox-debugging", + "company-brain/use-cases/long-horizon-research", + "company-brain/use-cases/meeting-scheduling" ] } - ], - "tab": "Cookbook" - }, - { - "icon": "list-ordered", - "anchors": [ - { - "anchor": "Changelog", - "pages": ["changelog/overview", "changelog/plugins"] - } - ], - "tab": "Changelog" + ] } ] }, "redirects": [ { - "destination": "/changelog/overview", + "destination": "/agents-and-mcp", + "permanent": true, + "source": "/vibe-coding" + }, + { + "destination": "/overview/what-is-supermemory", + "permanent": true, + "source": "/intro" + }, + { + "destination": "/", "permanent": true, "source": "/changelog/developer-platform" }, + { + "destination": "/", + "permanent": true, + "source": "/changelog/overview" + }, + { + "destination": "/", + "permanent": true, + "source": "/changelog/plugins" + }, { "destination": "/integrations/openclaw", "permanent": true, "source": "/integrations/clawdbot" }, { - "destination": "/intro", - "permanent": false, - "source": "/" + "destination": "/", + "permanent": true, + "source": "/introduction" }, { "destination": "/concepts/how-it-works", @@ -425,62 +551,62 @@ "source": "/search/filtering" }, { - "destination": "/add-memories", + "destination": "/ingestion/add-memories", "permanent": true, "source": "/add-memories/overview" }, { - "destination": "/add-memories", + "destination": "/ingestion/add-memories", "permanent": true, "source": "/add-memories/parameters" }, { - "destination": "/add-memories", + "destination": "/ingestion/add-memories", "permanent": true, "source": "/memory-api/ingesting" }, { - "destination": "/add-memories", + "destination": "/ingestion/add-memories", "permanent": true, "source": "/add-memories/examples/basic" }, { - "destination": "/add-memories", + "destination": "/ingestion/add-memories", "permanent": true, "source": "/add-memories/examples/file-upload" }, { - "destination": "/search", + "destination": "/recall/search", "permanent": true, "source": "/search/overview" }, { - "destination": "/search", + "destination": "/recall/search", "permanent": true, "source": "/search/parameters" }, { - "destination": "/search", + "destination": "/recall/search", "permanent": true, "source": "/search/response-schema" }, { - "destination": "/search", + "destination": "/recall/search", "permanent": true, "source": "/search/query-rewriting" }, { - "destination": "/search", + "destination": "/recall/search", "permanent": true, "source": "/search/reranking" }, { - "destination": "/search", + "destination": "/recall/search", "permanent": true, "source": "/search/examples/document-search" }, { - "destination": "/search", + "destination": "/recall/search", "permanent": true, "source": "/search/examples/memory-search" }, @@ -490,12 +616,12 @@ "source": "/user-profiles/overview" }, { - "destination": "/user-profiles", + "destination": "/recall/user-profiles", "permanent": true, "source": "/user-profiles/api" }, { - "destination": "/user-profiles", + "destination": "/recall/user-profiles", "permanent": true, "source": "/user-profiles/examples" }, @@ -505,37 +631,37 @@ "source": "/user-profiles/use-cases" }, { - "destination": "/add-memories", + "destination": "/ingestion/add-memories", "permanent": true, "source": "/update-delete-memories/overview" }, { - "destination": "/document-operations", + "destination": "/ingestion/document-operations", "permanent": true, "source": "/memory-api/track-progress" }, { - "destination": "/document-operations", + "destination": "/ingestion/document-operations", "permanent": true, "source": "/list-memories/overview" }, { - "destination": "/document-operations", + "destination": "/ingestion/document-operations", "permanent": true, "source": "/list-memories/examples/basic" }, { - "destination": "/document-operations", + "destination": "/ingestion/document-operations", "permanent": true, "source": "/list-memories/examples/filtering" }, { - "destination": "/document-operations", + "destination": "/ingestion/document-operations", "permanent": true, "source": "/list-memories/examples/pagination" }, { - "destination": "/document-operations", + "destination": "/ingestion/document-operations", "permanent": true, "source": "/list-memories/examples/monitoring" }, @@ -545,13 +671,288 @@ "source": "/org-settings" }, { - "destination": "/add-memories", + "destination": "/ingestion/add-memories", "permanent": true, "source": "/memory-api/overview" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/ai-sdk/examples" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/ai-sdk/npm" + }, + { + "destination": "/connectors/overview", + "permanent": true, + "source": "/memory-api/connectors/advanced/bring-your-own-key" + }, + { + "destination": "/connectors/overview", + "permanent": true, + "source": "/memory-api/connectors/creating-connection" + }, + { + "destination": "/connectors/overview", + "permanent": true, + "source": "/memory-api/connectors/overview" + }, + { + "destination": "/connectors/google-drive", + "permanent": true, + "source": "/memory-api/connectors/google-drive" + }, + { + "destination": "/connectors/managing-resources", + "permanent": true, + "source": "/memory-api/connectors/managing-resources" + }, + { + "destination": "/ingestion/add-memories", + "permanent": true, + "source": "/memory-api/creation/adding-memories" + }, + { + "destination": "/ingestion/document-operations", + "permanent": true, + "source": "/memory-api/creation/status" + }, + { + "destination": "/concepts/content-types", + "permanent": true, + "source": "/memory-api/features/auto-multi-modal" + }, + { + "destination": "/concepts/customization", + "permanent": true, + "source": "/memory-api/features/content-cleaner" + }, + { + "destination": "/concepts/filtering", + "permanent": true, + "source": "/memory-api/features/filtering" + }, + { + "destination": "/recall/search", + "permanent": true, + "source": "/memory-api/features/query-rewriting" + }, + { + "destination": "/recall/search", + "permanent": true, + "source": "/memory-api/features/reranking" + }, + { + "destination": "/overview/what-is-supermemory", + "permanent": true, + "source": "/memory-api/introduction" + }, + { + "destination": "/integrations/claude-memory", + "permanent": true, + "source": "/memory-api/sdks/anthropic-claude-memory" + }, + { + "destination": "/integrations/supermemory-sdk", + "permanent": true, + "source": "/memory-api/sdks/python" + }, + { + "destination": "/integrations/supermemory-sdk", + "permanent": true, + "source": "/memory-api/sdks/typescript" + }, + { + "destination": "/integrations/supermemory-sdk", + "permanent": true, + "source": "/memory-api/sdks/supermemory-npm" + }, + { + "destination": "/integrations/supermemory-sdk", + "permanent": true, + "source": "/memory-api/sdks/supermemory-pypi" + }, + { + "destination": "/recall/search", + "permanent": true, + "source": "/memory-api/searching/searching-memories" + }, + { + "destination": "/integrations/memory-graph", + "permanent": true, + "source": "/memory-graph/npm" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/memory-router/overview" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/memory-router/usage" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/memory-router/with-memory-api" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/model-enhancement/context-extender" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/model-enhancement/getting-started" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/model-enhancement/identifying-users" + }, + { + "destination": "/integrations/openai", + "permanent": true, + "source": "/openai-sdks/usage" + }, + { + "destination": "/overview/comparison", + "permanent": true, + "source": "/overview/why-supermemory" + }, + { + "destination": "/supermemory-mcp/mcp", + "permanent": true, + "source": "/supermemory-mcp/introduction" + }, + { + "destination": "/supermemory-mcp/mcp", + "permanent": true, + "source": "/supermemory-mcp/technology" + }, + { + "destination": "/", + "permanent": true, + "source": "/cookbook/overview" + }, + { + "destination": "/", + "permanent": true, + "source": "/cookbook/document-qa" + }, + { + "destination": "/", + "permanent": true, + "source": "/cookbook/ai-sdk-integration" + }, + { + "destination": "/", + "permanent": true, + "source": "/cookbook/customer-support" + }, + { + "destination": "/", + "permanent": true, + "source": "/cookbook/personal-assistant" + }, + { + "destination": "https://supermemory.ai/blog/building-an-ai-compliance-chatbot-with-supermemory-and-google-drive/", + "permanent": true, + "source": "/cookbook/chat-with-gdrive" + }, + { + "destination": "https://supermemory.ai/blog/extending-context-windows-in-llms/", + "permanent": true, + "source": "/cookbook/inf-chat-blog" + }, + { + "destination": "https://supermemory.ai/blog/build-your-own-perplexity-in-15-minutes-with-supermemory/", + "permanent": true, + "source": "/cookbook/perplexity-supermemory" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/architecture" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/cli" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/contributing" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/github" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/installation" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/integrations" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/quickstart" + }, + { + "destination": "/", + "permanent": true, + "source": "/memorybench/supported-models" + }, + { + "destination": "/ingestion/add-memories", + "permanent": true, + "source": "/add-memories" + }, + { + "destination": "/ingestion/document-operations", + "permanent": true, + "source": "/document-operations" + }, + { + "destination": "/recall/search", + "permanent": true, + "source": "/search" + }, + { + "destination": "/recall/user-profiles", + "permanent": true, + "source": "/user-profiles" + }, + { + "destination": "/recall/memory-operations", + "permanent": true, + "source": "/memory-operations" + }, + { + "destination": "/recall/memory-review", + "permanent": true, + "source": "/memory-review" + }, + { + "destination": "/overview/analytics", + "permanent": true, + "source": "/analytics" } ], "styling": { "eyebrows": "breadcrumbs" }, - "theme": "mint" + "theme": "aspen" } diff --git a/apps/docs/images/building-blocks/brain-head.png b/apps/docs/images/building-blocks/brain-head.png new file mode 100644 index 00000000..ca45624f Binary files /dev/null and b/apps/docs/images/building-blocks/brain-head.png differ diff --git a/apps/docs/images/building-blocks/connectors.svg b/apps/docs/images/building-blocks/connectors.svg new file mode 100644 index 00000000..1e0cb5f3 --- /dev/null +++ b/apps/docs/images/building-blocks/connectors.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/building-blocks/document-retrieval.svg b/apps/docs/images/building-blocks/document-retrieval.svg new file mode 100644 index 00000000..a4f0434c --- /dev/null +++ b/apps/docs/images/building-blocks/document-retrieval.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/building-blocks/extractor.svg b/apps/docs/images/building-blocks/extractor.svg new file mode 100644 index 00000000..15f68299 --- /dev/null +++ b/apps/docs/images/building-blocks/extractor.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/building-blocks/file-systems.svg b/apps/docs/images/building-blocks/file-systems.svg new file mode 100644 index 00000000..9df5f4fa --- /dev/null +++ b/apps/docs/images/building-blocks/file-systems.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/building-blocks/hermes.svg b/apps/docs/images/building-blocks/hermes.svg new file mode 100644 index 00000000..76669e00 --- /dev/null +++ b/apps/docs/images/building-blocks/hermes.svg @@ -0,0 +1 @@ +NousResearch \ No newline at end of file diff --git a/apps/docs/images/building-blocks/memory-router.svg b/apps/docs/images/building-blocks/memory-router.svg new file mode 100644 index 00000000..ead37487 --- /dev/null +++ b/apps/docs/images/building-blocks/memory-router.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/building-blocks/qualitative-analysis.svg b/apps/docs/images/building-blocks/qualitative-analysis.svg new file mode 100644 index 00000000..17c3e2d6 --- /dev/null +++ b/apps/docs/images/building-blocks/qualitative-analysis.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/building-blocks/user-profiles.svg b/apps/docs/images/building-blocks/user-profiles.svg new file mode 100644 index 00000000..9ed53870 --- /dev/null +++ b/apps/docs/images/building-blocks/user-profiles.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/company-brain/cursor-icon.png b/apps/docs/images/company-brain/cursor-icon.png new file mode 100644 index 00000000..cd75c37d Binary files /dev/null and b/apps/docs/images/company-brain/cursor-icon.png differ diff --git a/apps/docs/images/company-brain/dhravya-slack-icon.jpg b/apps/docs/images/company-brain/dhravya-slack-icon.jpg new file mode 100644 index 00000000..42def4ae Binary files /dev/null and b/apps/docs/images/company-brain/dhravya-slack-icon.jpg differ diff --git a/apps/docs/images/company-brain/plain-icon.png b/apps/docs/images/company-brain/plain-icon.png new file mode 100644 index 00000000..b15aa9b8 Binary files /dev/null and b/apps/docs/images/company-brain/plain-icon.png differ diff --git a/apps/docs/images/company-brain/signup-company-domain.png b/apps/docs/images/company-brain/signup-company-domain.png new file mode 100644 index 00000000..9bbdf7db Binary files /dev/null and b/apps/docs/images/company-brain/signup-company-domain.png differ diff --git a/apps/docs/images/company-brain/signup-research-complete.png b/apps/docs/images/company-brain/signup-research-complete.png new file mode 100644 index 00000000..905fdb41 Binary files /dev/null and b/apps/docs/images/company-brain/signup-research-complete.png differ diff --git a/apps/docs/images/company-brain/signup-research-connect.png b/apps/docs/images/company-brain/signup-research-connect.png new file mode 100644 index 00000000..90038254 Binary files /dev/null and b/apps/docs/images/company-brain/signup-research-connect.png differ diff --git a/apps/docs/images/company-brain/signup-team-toggle.png b/apps/docs/images/company-brain/signup-team-toggle.png new file mode 100644 index 00000000..60bc734d Binary files /dev/null and b/apps/docs/images/company-brain/signup-team-toggle.png differ diff --git a/apps/docs/images/company-brain/slack-create-workspace.png b/apps/docs/images/company-brain/slack-create-workspace.png new file mode 100644 index 00000000..5b8d8593 Binary files /dev/null and b/apps/docs/images/company-brain/slack-create-workspace.png differ diff --git a/apps/docs/images/company-brain/supermemory-slack-icon.png b/apps/docs/images/company-brain/supermemory-slack-icon.png new file mode 100644 index 00000000..5dde938c Binary files /dev/null and b/apps/docs/images/company-brain/supermemory-slack-icon.png differ diff --git a/apps/docs/images/github-icon.svg b/apps/docs/images/github-icon.svg new file mode 100644 index 00000000..b8798789 --- /dev/null +++ b/apps/docs/images/github-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/docs/images/google-drive-icon.svg b/apps/docs/images/google-drive-icon.svg new file mode 100644 index 00000000..2545c0c3 --- /dev/null +++ b/apps/docs/images/google-drive-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/docs/images/intro-company-brain-card.jpg b/apps/docs/images/intro-company-brain-card.jpg new file mode 100644 index 00000000..4a11fc83 Binary files /dev/null and b/apps/docs/images/intro-company-brain-card.jpg differ diff --git a/apps/docs/images/intro-company-brain.jpg b/apps/docs/images/intro-company-brain.jpg new file mode 100644 index 00000000..d0cc883e Binary files /dev/null and b/apps/docs/images/intro-company-brain.jpg differ diff --git a/apps/docs/images/intro-developer-platform.png b/apps/docs/images/intro-developer-platform.png new file mode 100644 index 00000000..19385039 Binary files /dev/null and b/apps/docs/images/intro-developer-platform.png differ diff --git a/apps/docs/images/intro-plugins-full.jpg b/apps/docs/images/intro-plugins-full.jpg new file mode 100644 index 00000000..f053934a Binary files /dev/null and b/apps/docs/images/intro-plugins-full.jpg differ diff --git a/apps/docs/images/intro-plugins.jpg b/apps/docs/images/intro-plugins.jpg new file mode 100644 index 00000000..a7aed837 Binary files /dev/null and b/apps/docs/images/intro-plugins.jpg differ diff --git a/apps/docs/images/intro-self-hosting.png b/apps/docs/images/intro-self-hosting.png new file mode 100644 index 00000000..4df59558 Binary files /dev/null and b/apps/docs/images/intro-self-hosting.png differ diff --git a/apps/docs/images/microsoft-icon.svg b/apps/docs/images/microsoft-icon.svg new file mode 100644 index 00000000..2ed8660d --- /dev/null +++ b/apps/docs/images/microsoft-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/docs/images/notion-icon.svg b/apps/docs/images/notion-icon.svg new file mode 100644 index 00000000..3802f016 --- /dev/null +++ b/apps/docs/images/notion-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/docs/images/readme-memory-graph.png b/apps/docs/images/readme-memory-graph.png new file mode 100644 index 00000000..de596e0f Binary files /dev/null and b/apps/docs/images/readme-memory-graph.png differ diff --git a/apps/docs/images/supermemory-mcp/claude-desktop/step-1.jpg b/apps/docs/images/supermemory-mcp/claude-desktop/step-1.jpg new file mode 100644 index 00000000..0f4b7dbd Binary files /dev/null and b/apps/docs/images/supermemory-mcp/claude-desktop/step-1.jpg differ diff --git a/apps/docs/images/supermemory-mcp/claude-desktop/step-1.png b/apps/docs/images/supermemory-mcp/claude-desktop/step-1.png deleted file mode 100644 index 242cef7f..00000000 Binary files a/apps/docs/images/supermemory-mcp/claude-desktop/step-1.png and /dev/null differ diff --git a/apps/docs/images/supermemory-mcp/claude-desktop/step-2.png b/apps/docs/images/supermemory-mcp/claude-desktop/step-2.png index f6a30341..72aa02fd 100644 Binary files a/apps/docs/images/supermemory-mcp/claude-desktop/step-2.png and b/apps/docs/images/supermemory-mcp/claude-desktop/step-2.png differ diff --git a/apps/docs/images/supermemory-mcp/claude-desktop/step-3.png b/apps/docs/images/supermemory-mcp/claude-desktop/step-3.png index 9467a059..085bd376 100644 Binary files a/apps/docs/images/supermemory-mcp/claude-desktop/step-3.png and b/apps/docs/images/supermemory-mcp/claude-desktop/step-3.png differ diff --git a/apps/docs/images/supermemory-mcp/claude-desktop/step-4.png b/apps/docs/images/supermemory-mcp/claude-desktop/step-4.png index 70799e83..e706290a 100644 Binary files a/apps/docs/images/supermemory-mcp/claude-desktop/step-4.png and b/apps/docs/images/supermemory-mcp/claude-desktop/step-4.png differ diff --git a/apps/docs/images/user-profiles-vs-search.png b/apps/docs/images/user-profiles-vs-search.png new file mode 100644 index 00000000..d4689582 Binary files /dev/null and b/apps/docs/images/user-profiles-vs-search.png differ diff --git a/apps/docs/images/what-is-supermemory-engine.jpg b/apps/docs/images/what-is-supermemory-engine.jpg new file mode 100644 index 00000000..49dd3df0 Binary files /dev/null and b/apps/docs/images/what-is-supermemory-engine.jpg differ diff --git a/apps/docs/index.mdx b/apps/docs/index.mdx new file mode 100644 index 00000000..bdc43c1b --- /dev/null +++ b/apps/docs/index.mdx @@ -0,0 +1,90 @@ +--- +title: "Introduction" +description: "Context infrastructure for AI agents" +mode: "custom" +--- + +export const HeroCard = ({ imageUrl, title, description, href }) => { + return ( + +
+ {title} +
+
+

+ {title} +

+

+ {description} +

+
+
+ ) +} + +
+
+
+

+ supermemory +

+

+ Context infrastructure for AI agents. Use it with the API, your tools, your team, or run it yourself. +

+ +
+ +
+ + + + +
+
+
diff --git a/apps/docs/add-memories.mdx b/apps/docs/ingestion/add-memories.mdx similarity index 89% rename from apps/docs/add-memories.mdx rename to apps/docs/ingestion/add-memories.mdx index 7d34221f..39d7c103 100644 --- a/apps/docs/add-memories.mdx +++ b/apps/docs/ingestion/add-memories.mdx @@ -1,15 +1,11 @@ --- title: "Ingesting context to supermemory" -sidebarTitle: "Add context" +sidebarTitle: "API" description: "Add text, files, and URLs to Supermemory" icon: "plus" --- -Send any raw content to Supermemory — conversations, documents, files, URLs. We extract the memories automatically. - - -**Use `customId`** to identify your content (conversation ID, document ID, etc.). This enables updates and prevents duplicates. - +Send any raw content to Supermemory — conversations, documents, files, URLs. We extract the memories automatically. Pass `customId` to identify content and avoid duplicates, and `taskType: "superrag"` if you just need it searchable, not remembered — that's [5x cheaper](#memory-vs-superrag-ingestion) per token. ## Quick Start @@ -73,6 +69,10 @@ Send any raw content to Supermemory — conversations, documents, files, URLs. W { "id": "abc123", "status": "queued" } ``` + +If an irrecoverable processing error occurs, the document is automatically deleted after 2 minutes. + + --- ## Updating Content @@ -155,7 +155,7 @@ Upload PDFs, images, and documents directly. await client.documents.uploadFile({ file: fs.createReadStream('document.pdf'), - containerTags: 'user_123' + containerTag: 'user_123' }); ``` @@ -164,7 +164,7 @@ Upload PDFs, images, and documents directly. with open('document.pdf', 'rb') as file: client.documents.upload_file( file=file, - container_tags='user_123' + container_tag='user_123' ) ``` @@ -173,7 +173,7 @@ Upload PDFs, images, and documents directly. curl -X POST "https://api.supermemory.ai/v3/documents/file" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -F "file=@document.pdf" \ - -F "containerTags=user_123" + -F "containerTag=user_123" ``` @@ -202,6 +202,7 @@ Upload PDFs, images, and documents directly. | `filterByMetadata` | object | Filter which existing memories are used as context during ingestion. See [Filtered Writes](#filtered-writes) | | `entityContext` | string | Context for memory extraction on this container tag. Max 1500 chars. See [Customization](/concepts/customization#entity-context) | | `dreaming` | `"dynamic" \| "instant"` | Processing mode. Default `"dynamic"`. `"instant"` processes each document on its own and bills one extra operation. See [Processing Modes](#processing-modes) | +| `taskType` | `"memory" \| "superrag"` | Pipeline to run. Default `"memory"`. `"superrag"` skips fact extraction and profile updates, doing only chunk/embed/index — at 5x cheaper per token. See [SuperRAG ingestion](/concepts/super-rag#ingesting-as-pure-superrag-tasktype-superrag) | @@ -280,6 +281,8 @@ Upload PDFs, images, and documents directly. ## Processing Modes +### Dreaming: dynamic vs instant + The `dreaming` parameter controls how Supermemory turns a document into memories. - `"dynamic"` (default) — groups related documents together so memories form from coherent, logical units rather than one isolated entry at a time. @@ -292,6 +295,22 @@ The `dreaming` parameter controls how Supermemory turns a document into memories } ``` +### Memory vs SuperRAG ingestion + +The `taskType` parameter controls whether that content also feeds the memory pipeline. + +- `"memory"` (default) — chunks/embeds for search **and** extracts facts, updates the user's profile, and links into the graph. +- `"superrag"` — chunks/embeds for search only. No fact extraction, no profile updates. Priced at **5x cheaper per token** than `"memory"`. + +```json +{ + "content": "...", + "taskType": "superrag" +} +``` + +Use `"superrag"` for reference material you want searchable but that shouldn't shape what Supermemory knows about a user. Full explanation: [SuperRAG → Ingesting as pure SuperRAG](/concepts/super-rag#ingesting-as-pure-superrag-tasktype-superrag). + --- ## Filtered Writes @@ -477,6 +496,6 @@ console.log(doc.status); // "queued" | "processing" | "done" ## Next Steps -- [Search Memories](/search) — Query your content -- [User Profiles](/user-profiles) — Get user context +- [Search Memories](/recall/search) — Query your content +- [User Profiles](/recall/user-profiles) — Get user context - [Organizing & Filtering](/concepts/filtering) — Container tags and metadata diff --git a/apps/docs/document-operations.mdx b/apps/docs/ingestion/document-operations.mdx similarity index 97% rename from apps/docs/document-operations.mdx rename to apps/docs/ingestion/document-operations.mdx index ecf4c54d..03a1ea99 100644 --- a/apps/docs/document-operations.mdx +++ b/apps/docs/ingestion/document-operations.mdx @@ -290,6 +290,6 @@ Check documents currently being processed. ## Next Steps -- [Memory Operations](/memory-operations) — Advanced v4 memory operations -- [Search](/search) — Query your memories -- [Ingesting Content](/add-memories) — Add new content +- [Memory Operations](/recall/memory-operations) — Advanced v4 memory operations +- [Search](/recall/search) — Query your memories +- [Ingesting Content](/ingestion/add-memories) — Add new content diff --git a/apps/docs/integrations/agent-framework.mdx b/apps/docs/integrations/agent-framework.mdx index 52965718..2fe19114 100644 --- a/apps/docs/integrations/agent-framework.mdx +++ b/apps/docs/integrations/agent-framework.mdx @@ -2,7 +2,7 @@ title: "Microsoft Agent Framework" sidebarTitle: "MS Agent Framework" description: "Add persistent memory to Microsoft Agent Framework agents with Supermemory" -icon: "microsoft" +icon: "/images/microsoft-icon.svg" --- Microsoft's [Agent Framework](https://github.com/microsoft/agent-framework) is a Python framework for building AI agents with tools, handoffs, and context providers. Supermemory integrates natively as a context provider, tool set, or middleware — so your agents remember users across sessions. @@ -318,10 +318,10 @@ except SupermemoryConfigurationError as e: ## Related docs - + How automatic profiling works - + Filtering and search modes diff --git a/apps/docs/integrations/agno.mdx b/apps/docs/integrations/agno.mdx index eeeb621e..87248559 100644 --- a/apps/docs/integrations/agno.mdx +++ b/apps/docs/integrations/agno.mdx @@ -368,10 +368,10 @@ results = memory.search.memories( ## Related docs - + How automatic profiling works - + Filtering and search modes diff --git a/apps/docs/integrations/claude-code.mdx b/apps/docs/integrations/claude-code.mdx index 34532ae6..8d290930 100644 --- a/apps/docs/integrations/claude-code.mdx +++ b/apps/docs/integrations/claude-code.mdx @@ -16,12 +16,35 @@ icon: "/images/claude-code-icon.svg" [supermemory](https://github.com/supermemoryai/claude-supermemory) is a Claude Code plugin that gives your AI persistent memory across sessions. Your agent remembers what you worked on — across sessions, across projects. -**Prefer to keep everything on your machine?** This plugin works with [self-hosted Supermemory](/self-hosting/overview) — run `npx supermemory local`, then `export SUPERMEMORY_API_URL="http://localhost:6767"` and use the API key printed on first boot. +**Prefer to keep everything on your machine?** This plugin works with [self-hosted Supermemory](/self-hosting/overview) — run `npx supermemory local`, then set `baseUrl` in project config (or point your install at your local API) and use the API key printed on first boot. -## Get Your API Key +## Install the Plugin -Create a Supermemory API key from the [API Keys](https://console.supermemory.ai/keys) page, then add it to your shell profile so it persists across sessions: +> **Requires Node.js 18+** on your PATH — the memory hooks run as Node scripts. + +```bash +# Add the plugin marketplace +/plugin marketplace add supermemoryai/claude-supermemory + +# Install the plugin +/plugin install supermemory +``` + + +**Migrating from the old `claude-supermemory` plugin name?** It was renamed to `supermemory` and will not update in place: + +```bash +/plugin marketplace update supermemory-plugins +/plugin install supermemory@supermemory-plugins +# Only if the old plugin is still installed: +/plugin uninstall claude-supermemory@supermemory-plugins +``` + + +## Authenticate + +Create a Supermemory API key from [app.supermemory.ai](https://app.supermemory.ai) (or [API Keys](https://console.supermemory.ai/keys)), then add it to your shell profile: @@ -44,70 +67,81 @@ Create a Supermemory API key from the [API Keys](https://console.supermemory.ai/ -## Install the Plugin - -```bash -# Add the plugin marketplace -/plugin marketplace add supermemoryai/claude-supermemory - -# Install the plugin -/plugin install supermemory -``` - ## How It Works Once installed, the plugin runs automatically: -- **Context Injection** — On session start, relevant memories are fetched and injected into Claude's context. This includes user preferences, project knowledge, and past interactions. -- **Auto-Capture** — Tool usage is captured and stored during the session for future context. - -### What Gets Captured - -| Tool | Captured As | -| ----- | --------------------------------------------------- | -| Edit | `Edited src/auth.ts: "old code..." → "new code..."` | -| Write | `Created src/new-file.ts (500 chars)` | -| Bash | `Ran: npm test (SUCCESS/FAILED)` | -| Task | `Spawned agent: explore codebase` | +- **Reasoned recall** — Before each turn, Claude decides whether recalling memory would help the current message, and only searches when it is worth it. +- **Auto-capture** — Conversations and important tool usage are saved for later sessions. +- **Team memory** — Project knowledge is shared separately from personal memories. +- **Explicit skills** — Ask Claude to search or save memories when you need control. ## Commands -### /supermemory:logout - -Log out from Supermemory and clear saved credentials. - -``` -/supermemory:logout -``` +| Command | Description | +| --- | --- | +| `/supermemory:index` | Index codebase architecture and patterns | +| `/supermemory:project-config` | Configure project-level settings | +| `/supermemory:logout` | Clear saved credentials | +| `/supermemory:session` | Show a clickable URL for the current session document | +| `/supermemory:status` | Show authentication status | ## Configuration ### Environment Variables ```bash -SUPERMEMORY_CC_API_KEY=sm_... # Required -SUPERMEMORY_SKIP_TOOLS=Read,Glob,Grep # Tools to not capture (optional) -SUPERMEMORY_DEBUG=true # Enable debug logging (optional) +SUPERMEMORY_CC_API_KEY=sm_... # Required +SUPERMEMORY_DEBUG=true # Optional: enable debug logging ``` -### Settings File +### Global Settings Create `~/.supermemory-claude/settings.json`: ```json { - "skipTools": ["Read", "Glob", "Grep", "TodoWrite"], - "captureTools": ["Edit", "Write", "Bash", "Task"], - "maxContextMemories": 10, - "maxProjectMemories": 20, - "debug": false + "maxProfileItems": 5, + "signalExtraction": true, + "signalKeywords": ["remember", "architecture", "decision", "bug", "fix"], + "signalTurnsBefore": 3, + "includeTools": ["Edit", "Write"] } ``` +| Option | Description | +| --- | --- | +| `maxProfileItems` | Max memories in context (default: 5) | +| `recallDirective` | Override the built-in reasoned-recall instruction | +| `signalExtraction` | Only capture important turns (default: false) | +| `signalKeywords` | Keywords that trigger capture | +| `signalTurnsBefore` | Context turns before a signal (default: 3) | +| `includeTools` | Tools to explicitly capture | + +### Project Config + +Per-repo overrides in `.claude/.supermemory-claude/config.json`. Run `/supermemory:project-config` or create manually: + +```json +{ + "apiKey": "sm_...", + "baseUrl": "https://api.supermemory.ai", + "repoContainerTag": "my-team-project", + "signalExtraction": true +} +``` + +| Option | Description | +| --- | --- | +| `apiKey` | Project-specific API key | +| `baseUrl` | Supermemory API URL (use for self-hosted) | +| `personalContainerTag` | Override personal container | +| `repoContainerTag` | Override team container tag | + ## Next Steps - + Source code, issues, and detailed README. diff --git a/apps/docs/integrations/claude-memory.mdx b/apps/docs/integrations/claude-memory.mdx index 4487cb77..ba7fb90c 100644 --- a/apps/docs/integrations/claude-memory.mdx +++ b/apps/docs/integrations/claude-memory.mdx @@ -121,6 +121,10 @@ All memory paths must start with `/memories/`: /memories/context/current.txt # Current context ``` + +Paths are normalized for storage: `/memories/preferences` is stored as `--memories--preferences`. + + ## Commands Reference ### View (Read/List) @@ -256,6 +260,15 @@ SUPERMEMORY_API_KEY=your_supermemory_key ANTHROPIC_API_KEY=your_anthropic_key ``` +## Comparison with Other Approaches + +| Feature | Claude Memory Tool | OpenAI SDK Tools | AI SDK Tools | +|---------|-------------------|------------------|--------------| +| Automatic memory | ✅ Claude decides | ❌ Manual control | ❌ Manual control | +| Filesystem metaphor | ✅ Files/directories | ❌ Flat storage | ❌ Flat storage | +| Path organization | ✅ Hierarchical | ❌ Tags only | ❌ Tags only | +| Integration | Anthropic SDK only | OpenAI SDK only | Vercel AI SDK | + ## Next Steps diff --git a/apps/docs/integrations/codex.mdx b/apps/docs/integrations/codex.mdx index 0b86c82c..00896015 100644 --- a/apps/docs/integrations/codex.mdx +++ b/apps/docs/integrations/codex.mdx @@ -7,16 +7,36 @@ icon: "terminal" [codex-supermemory](https://github.com/supermemoryai/codex-supermemory) wires Supermemory into the [OpenAI Codex CLI](https://github.com/openai/codex) via hooks and skills. Your agent gets **two layers of memory**: -- **Implicit** (hooks) — automatically recalls context before each prompt and captures conversations after each session. +- **Implicit** (hooks) — automatically recalls context before each prompt and captures conversations incrementally during the session. - **Explicit** (skills) — lets you or the agent save, search, and manage memories on demand. **Prefer to keep everything on your machine?** This plugin works with [self-hosted Supermemory](/self-hosting/overview) — run `npx supermemory local`, then `export SUPERMEMORY_API_URL="http://localhost:6767"` (or set `baseUrl` in `~/.codex/supermemory.json`) and use the API key printed on first boot. -## Get Your API Key +## Install the Plugin -Create a Supermemory API key from the [API Keys](https://console.supermemory.ai/keys) page, then export it in your shell profile: +```bash +npx codex-supermemory@latest install +``` + +This command: + +- Copies hook and skill scripts to `~/.codex/supermemory/` +- Enables `codex_hooks` in `~/.codex/config.toml` +- Registers `UserPromptSubmit` (recall) and `Stop` (flush) hooks in `~/.codex/hooks.json` +- Installs explicit memory skills under `~/.codex/skills/` + +Restart Codex CLI after installing. + +## Authenticate + +**Browser auth is preferred.** Start Codex CLI — on your first prompt a browser window opens to authenticate with Supermemory. + +Alternatively: + +- Use `$supermemory-login` / `/supermemory-login` inside Codex +- Or set an API key from [API Keys](https://console.supermemory.ai/keys): @@ -39,38 +59,26 @@ Create a Supermemory API key from the [API Keys](https://console.supermemory.ai/ -## Install the Plugin - -```bash -npx codex-supermemory@latest install -``` - -This command: -- Copies hook and skill scripts to `~/.codex/supermemory/` -- Enables `codex_hooks = true` in `~/.codex/config.toml` -- Registers `UserPromptSubmit` (recall) and `Stop` (capture) hooks in `~/.codex/hooks.json` -- Installs `supermemory-search`, `supermemory-save`, `supermemory-forget`, and `supermemory-status` skills to `~/.codex/skills/` - -Restart Codex CLI after installing. - ## How It Works -Once installed, the plugin runs automatically on every Codex session: +Once installed, the plugin runs on every Codex session: -- **Recall** — Before each prompt, relevant memories and your user profile are fetched from Supermemory and injected as additional context. -- **Capture** — After each session ends, the conversation transcript is ingested into Supermemory, scoped to the current project and user. -- **Privacy** — Content wrapped in `...` tags is redacted before storage. +| Hook | Event | What it does | +|------|-------|--------------| +| `recall` | `UserPromptSubmit` | Captures new turns (every N prompts), searches Supermemory, injects memories + profile as `additionalContext` | +| `flush` | `Stop` | Captures any remaining turns at session end so nothing is lost | + +- **Incremental capture** — Memories are saved every N turns (default: 3) so mid-session context is available for later prompts in the same session. +- **Privacy** — Content wrapped in `...` is redacted before storage. ### Memory Scopes -Memories are tagged with two container tags per session, auto-derived from your environment: - | Tag | Derived from | Description | |-----|-------------|-------------| -| User | `git config user.email` (hashed) | Memories shared across all your projects | -| Project | Current working directory (hashed) | Memories scoped to the current repo | +| User | `git config user.email` (hashed) | Preferences and workflows across projects | +| Project | Git common directory (hashed) | Repo-scoped knowledge (worktrees share by default) | -Tags are generated automatically — no configuration needed. You can override them in `~/.codex/supermemory.json` if needed: +Override tags in `~/.codex/supermemory.json` if needed: ```json { @@ -79,18 +87,21 @@ Tags are generated automatically — no configuration needed. You can override t } ``` -## Explicit Memory Skills +Set `SUPERMEMORY_ISOLATE_WORKTREES=true` to keep each worktree isolated. -The installer includes four skills that Codex auto-discovers from `~/.codex/skills/`. They use the same `SUPERMEMORY_CODEX_API_KEY` as the hooks — no separate login needed. +## Explicit Memory Skills | Skill | Description | |-------|-------------| -| `supermemory-search` | Search your memories by natural-language query | -| `supermemory-save` | Save important project knowledge to memory | +| `supermemory-search` | Search memories by natural-language query | +| `supermemory-save` | Save important project knowledge | | `supermemory-forget` | Remove outdated or incorrect memories | -| `supermemory-status` | Check Supermemory connection, hook, config, and skill status | +| `supermemory-profile` | Show remembered profile facts | +| `supermemory-status` | Check connection, hooks, config, and skills | +| `supermemory-login` | Re-authenticate with Supermemory | +| `supermemory-logout` | Remove saved local credentials | -These skills let you interact with memory explicitly — for example: +Example prompts: ``` > Remember that this project uses Vitest for unit tests and Playwright for E2E. @@ -105,27 +116,13 @@ These skills let you interact with memory explicitly — for example: npx codex-supermemory status ``` -Expected output when everything is configured: - -``` -codex-supermemory status: - - API key: ✓ set (SUPERMEMORY_CODEX_API_KEY) - Hook scripts: ✓ installed at ~/.codex/supermemory - hooks.json: ✓ registered (implicit memory) - Skills: ✓ installed (supermemory-search, supermemory-save, supermemory-forget, supermemory-status) - config.toml: ✓ exists - -All good! Memory is active. -``` - ## Uninstall ```bash npx codex-supermemory uninstall ``` -This removes the hook registrations and skill scripts from `~/.codex/supermemory/`, removes skill directories from `~/.codex/skills/`, and disables `codex_hooks` in `~/.codex/config.toml`. Your existing memories in Supermemory are preserved. +This removes hook registrations and skill scripts. Your existing memories in Supermemory are preserved. ## Configuration @@ -134,29 +131,33 @@ Create `~/.codex/supermemory.json` to override defaults: ```json { "apiKey": "sm_...", + "baseUrl": "https://api.supermemory.ai", "similarityThreshold": 0.6, "maxMemories": 5, "maxProfileItems": 5, "injectProfile": true, "containerTagPrefix": "codex", + "autoSaveEveryTurns": 3, + "signalExtraction": false, "debug": false } ``` | Option | Default | Description | |--------|---------|-------------| -| `apiKey` | — | API key (overrides env var) | +| `apiKey` | — | API key (env / browser auth preferred) | +| `baseUrl` | `https://api.supermemory.ai` | API base URL (`SUPERMEMORY_API_URL` overrides) | | `similarityThreshold` | `0.6` | Minimum match score for recall (0–1) | | `maxMemories` | `5` | Max memories injected per prompt | | `maxProfileItems` | `5` | Max profile facts injected per prompt | | `injectProfile` | `true` | Include user profile in context | -| `containerTagPrefix` | `"codex"` | Prefix for container tags | +| `containerTagPrefix` | `"codex"` | Prefix for auto-generated container tags | +| `autoSaveEveryTurns` | `3` | Save memories every N turns | +| `signalExtraction` | `false` | Only capture turns with signal keywords | | `debug` | `false` | Write debug logs to `~/.codex-supermemory.log` | ## Logging -Enable debug logging to trace hook activity: - ```bash export SUPERMEMORY_DEBUG=true tail -f ~/.codex-supermemory.log @@ -165,7 +166,7 @@ tail -f ~/.codex-supermemory.log ## Next Steps - + Source code, issues, and detailed README. diff --git a/apps/docs/integrations/convex.mdx b/apps/docs/integrations/convex.mdx index 37130a84..92f106e5 100644 --- a/apps/docs/integrations/convex.mdx +++ b/apps/docs/integrations/convex.mdx @@ -74,7 +74,7 @@ export const addMemory = action({ export const searchMemories = action({ args: { userId: v.string(), query: v.string(), limit: v.optional(v.number()) }, handler: async (ctx, { userId, query, limit }) => { - return await memory.search.memories({ + return await memory.search({ q: query, containerTag: userId, searchMode: "hybrid", @@ -193,10 +193,10 @@ export const listMemories = query({ ## Related docs - + How automatic profiling works - + Filtering and search modes diff --git a/apps/docs/integrations/crewai.mdx b/apps/docs/integrations/crewai.mdx index f4fdc9c4..92c9772b 100644 --- a/apps/docs/integrations/crewai.mdx +++ b/apps/docs/integrations/crewai.mdx @@ -323,10 +323,10 @@ results = memory.search.memories( ## Related docs - + How automatic profiling works - + Filtering and search modes diff --git a/apps/docs/integrations/hermes.mdx b/apps/docs/integrations/hermes.mdx index 0b8efea5..d45811cb 100644 --- a/apps/docs/integrations/hermes.mdx +++ b/apps/docs/integrations/hermes.mdx @@ -48,12 +48,14 @@ Once configured, the provider runs through Hermes’s normal memory lifecycle: ## Tools -| Tool | Description | -|------|-------------| -| `supermemory_store` | Store an explicit memory. | -| `supermemory_search` | Search by semantic similarity. | -| `supermemory_forget` | Forget a memory by ID or best-match query. | -| `supermemory_profile` | Retrieve persistent profile and recent context. | +Kebab-case names are registered for the agent; snake_case aliases remain supported. + +| Tool | Alias | Description | +|------|-------|-------------| +| `supermemory-save` | `supermemory_store` | Store an explicit memory. | +| `supermemory-search` | `supermemory_search` | Search by semantic similarity. | +| `supermemory-forget` | `supermemory_forget` | Forget a memory by ID or best-match query. | +| `supermemory-profile` | `supermemory_profile` | Retrieve persistent profile and recent context. | ## Commands @@ -139,7 +141,7 @@ If you run your own supermemory API, set **`base_url`** (and any other host-spec ## Next Steps - + Full config table, env vars, and multi-container details. @@ -148,4 +150,4 @@ If you run your own supermemory API, set **`base_url`** (and any other host-spec -Questions about the API or product? [Discord](https://supermemory.link/discord) · [support@supermemory.com](mailto:support@supermemory.com) · [Developer docs](/intro) +Questions about the API or product? [Discord](https://supermemory.link/discord) · [support@supermemory.com](mailto:support@supermemory.com) · [Developer docs](/overview/what-is-supermemory) diff --git a/apps/docs/integrations/langchain.mdx b/apps/docs/integrations/langchain.mdx index 6c9eee9a..5d8e69c7 100644 --- a/apps/docs/integrations/langchain.mdx +++ b/apps/docs/integrations/langchain.mdx @@ -373,10 +373,10 @@ for note in notes: ## Next Steps - + Deep dive into automatic user profiling - + Advanced search patterns and filtering diff --git a/apps/docs/integrations/langgraph.mdx b/apps/docs/integrations/langgraph.mdx index e67cdaec..47cfe284 100644 --- a/apps/docs/integrations/langgraph.mdx +++ b/apps/docs/integrations/langgraph.mdx @@ -408,11 +408,11 @@ app = graph.compile(checkpointer=checkpointer) ## Next steps - + Deep dive into automatic user profiling - + Advanced search patterns and filtering diff --git a/apps/docs/integrations/mastra.mdx b/apps/docs/integrations/mastra.mdx index db526de4..089816f4 100644 --- a/apps/docs/integrations/mastra.mdx +++ b/apps/docs/integrations/mastra.mdx @@ -480,7 +480,7 @@ const agent = new Agent(withSupermemory( Use with Vercel AI SDK for streamlined development - + Learn about user profile management diff --git a/apps/docs/integrations/openai-agents-sdk.mdx b/apps/docs/integrations/openai-agents-sdk.mdx index ebd59863..97754759 100644 --- a/apps/docs/integrations/openai-agents-sdk.mdx +++ b/apps/docs/integrations/openai-agents-sdk.mdx @@ -418,10 +418,10 @@ results = memory.search.memories( ## Related docs - + How automatic profiling works - + Filtering and search modes diff --git a/apps/docs/integrations/openai.mdx b/apps/docs/integrations/openai.mdx index 80751d74..1d131396 100644 --- a/apps/docs/integrations/openai.mdx +++ b/apps/docs/integrations/openai.mdx @@ -658,7 +658,7 @@ npm run lint Use with Vercel AI SDK for streamlined development - + Direct API access for advanced memory management diff --git a/apps/docs/integrations/openclaw.mdx b/apps/docs/integrations/openclaw.mdx index aacc7ef0..5704d3d4 100644 --- a/apps/docs/integrations/openclaw.mdx +++ b/apps/docs/integrations/openclaw.mdx @@ -5,10 +5,6 @@ description: "OpenClaw Supermemory Plugin — works across Telegram, WhatsApp, D icon: "/images/openclaw-logo.jpg" --- - -This integration requires the **Supermemory Pro plan**. [Upgrade here](https://console.supermemory.ai/billing). - - [OpenClaw](https://github.com/supermemoryai/openclaw-supermemory) is a multi-platform AI messaging gateway that connects to WhatsApp, Telegram, Discord, Slack, iMessage, and other messaging channels. The Supermemory plugin gives OpenClaw memory across every channel. @@ -17,8 +13,6 @@ This integration requires the **Supermemory Pro plan**. [Upgrade here](https://c ## Install the Plugin -Get started by installing the plugin with a single command. - ```bash openclaw plugins install @supermemory/openclaw-supermemory ``` @@ -31,9 +25,10 @@ Run the setup command and enter your API key when prompted. ```bash openclaw supermemory setup +openclaw gateway restart ``` -Enter your API key from [console.supermemory.ai](https://console.supermemory.ai). That's it. +Enter your API key from [app.supermemory.ai](https://app.supermemory.ai/?view=integrations). That's it. @@ -41,6 +36,7 @@ Enter your API key from [console.supermemory.ai](https://console.supermemory.ai) ```bash openclaw supermemory setup-advanced + openclaw gateway restart ``` This lets you configure: container tag, auto-recall, auto-capture, capture mode, custom container tags, and more. @@ -61,7 +57,7 @@ Once installed, the plugin runs automatically with zero interaction. ### AI Tools -The AI can use these tools autonomously during conversations. +The AI can use these tools autonomously during conversations. With custom container tags enabled, all tools support a `containerTag` parameter. | Tool | Description | |------|-------------| @@ -92,13 +88,25 @@ openclaw supermemory profile # View user profile openclaw supermemory wipe # Delete all memories (requires confirmation) ``` + + ### Configuration Options + Set API key (and, for self-hosted instances, the base URL) via environment variables: + + ```bash + export SUPERMEMORY_OPENCLAW_API_KEY="sm_..." + export SUPERMEMORY_BASE_URL="http://localhost:6767" # optional + ``` + + Or configure in `~/.openclaw/openclaw.json`: + | Key | Type | Default | Description | |-----|------|---------|-------------| | `apiKey` | `string` | — | Supermemory API key. | + | `baseUrl` | `string` | `https://api.supermemory.ai` | API endpoint (self-hosted / local). | | `containerTag` | `string` | `openclaw_{hostname}` | Root memory namespace. | | `autoRecall` | `boolean` | `true` | Inject relevant memories before every AI turn. | | `autoCapture` | `boolean` | `true` | Store conversation content after every turn. | @@ -158,12 +166,12 @@ openclaw supermemory wipe # Delete all memories (requires confirma openclaw supermemory setup ``` - 3. When prompted, paste your API key from [console.supermemory.ai](https://console.supermemory.ai). The key starts with `sm_`. + 3. When prompted, paste your API key from [app.supermemory.ai](https://app.supermemory.ai/?view=integrations). The key starts with `sm_`. 4. Restart OpenClaw to activate the plugin: ```bash - openclaw gateway --force + openclaw gateway restart ``` 5. Verify the connection: @@ -278,7 +286,7 @@ openclaw supermemory wipe # Delete all memories (requires confirma ## Next Steps - + Source code, issues, and detailed README. diff --git a/apps/docs/integrations/opencode.mdx b/apps/docs/integrations/opencode.mdx index bec9167b..3cce46d7 100644 --- a/apps/docs/integrations/opencode.mdx +++ b/apps/docs/integrations/opencode.mdx @@ -8,12 +8,36 @@ icon: "/images/opencode-logo.png" [OpenCode-Supermemory](https://github.com/supermemoryai/opencode-supermemory) is an OpenCode plugin that gives your AI persistent memory across sessions. Your agent remembers what you worked on — across sessions, across projects. -**Prefer to keep everything on your machine?** This plugin works with [self-hosted Supermemory](/self-hosting/overview) — run `npx supermemory local`, then `export SUPERMEMORY_API_URL="http://localhost:6767"` and use the API key printed on first boot. +**Prefer to keep everything on your machine?** This plugin works with [self-hosted Supermemory](/self-hosting/overview) — run `npx supermemory local`, then set `apiKey` / base URL in `~/.config/opencode/supermemory.jsonc` and use the API key printed on first boot. -## Get Your API Key +## Install the Plugin -Create a Supermemory API key from the [API Keys](https://console.supermemory.ai/keys) page, then add it to your shell profile so it persists across sessions: +```bash +bunx opencode-supermemory@latest install +``` + +For LLM agents (non-interactive): + +```bash +bunx opencode-supermemory@latest install --no-tui +``` + +## Authenticate + +Browser login (recommended): + +```bash +bunx opencode-supermemory@latest login +``` + +Check the connection any time: + +```bash +bunx opencode-supermemory@latest status +``` + +Or set an API key manually from [app.supermemory.ai](https://app.supermemory.ai/?view=integrations) / [API Keys](https://console.supermemory.ai/keys): @@ -36,18 +60,6 @@ Create a Supermemory API key from the [API Keys](https://console.supermemory.ai/ -## Install the Plugin - -```bash -bunx opencode-supermemory@latest install -``` - -For LLM agents (non-interactive): - -```bash -bunx opencode-supermemory@latest install --no-tui -``` - Ensure your `~/.config/opencode/opencode.jsonc` contains: ```json @@ -60,7 +72,7 @@ Ensure your `~/.config/opencode/opencode.jsonc` contains: Once installed, the plugin runs automatically: -- **Context Injection** — On session start, relevant memories are fetched and injected into the agent's context. This includes user preferences, project knowledge, and past interactions. +- **Context Injection** — On session start, relevant memories are fetched and injected into the agent's context (user profile, project knowledge, semantic matches). - **Keyword Detection** — Phrases like "remember" or "save this" trigger automatic storage. - **Smart Compaction** — At 80% context capacity, sessions are summarized and saved as memories. - **Privacy Protection** — Content within `` tags never persists. @@ -111,13 +123,16 @@ Create `~/.config/opencode/supermemory.jsonc`: ```jsonc { - "apiKey": "sm_...", // Or use SUPERMEMORY_API_KEY env var + "apiKey": "sm_...", // Or use SUPERMEMORY_API_KEY / browser login "similarityThreshold": 0.6, // Minimum match score (0-1) "maxMemories": 5, // Memories per injection "maxProjectMemories": 10, // Project memory listings "maxProfileItems": 5, // Profile facts injected "injectProfile": true, // Include user preferences in context "containerTagPrefix": "opencode", // Tag prefix for scoping + "userContainerTag": "my-user-tag", // Optional override + "projectContainerTag": "my-project-tag", // Optional override + "keywordPatterns": ["log\\s+this"], // Extra auto-save triggers "compactionThreshold": 0.80 // Context usage ratio for summarization } ``` @@ -133,7 +148,7 @@ tail -f ~/.opencode-supermemory.log ## Next Steps - + Source code, issues, and detailed README. diff --git a/apps/docs/integrations/pipecat.mdx b/apps/docs/integrations/pipecat.mdx index a5cae1e9..1637ce44 100644 --- a/apps/docs/integrations/pipecat.mdx +++ b/apps/docs/integrations/pipecat.mdx @@ -236,7 +236,7 @@ For a complete example using Gemini Live speech-to-speech with Supermemory, chec Full working example with Gemini Live, including frontend and backend code. diff --git a/apps/docs/integrations/supermemory-sdk.mdx b/apps/docs/integrations/supermemory-sdk.mdx index 474976d5..18f7944d 100644 --- a/apps/docs/integrations/supermemory-sdk.mdx +++ b/apps/docs/integrations/supermemory-sdk.mdx @@ -36,12 +36,13 @@ Both SDKs also work against [self-hosted Supermemory](/self-hosting/overview) }); // Add a memory - await client.add({ content: "Meeting notes from Q1 planning", containerTags: ["user_123"] }); + await client.add({ content: "Meeting notes from Q1 planning", containerTag: "user_123" }); // Search memories - const response = await client.search.documents({ + const response = await client.search({ q: "planning notes", - containerTags: ["user_123"] + searchMode: "documents", + containerTag: "user_123" }); console.log(response.results); @@ -57,14 +58,15 @@ Both SDKs also work against [self-hosted Supermemory](/self-hosting/overview) // Add with metadata await client.add({ content: "Technical design doc", - containerTags: ["user_123"], + containerTag: "user_123", metadata: { category: "engineering", priority: "high" } }); // Search with filters - const results = await client.search.documents({ + const results = await client.search({ q: "design document", - containerTags: ["user_123"], + searchMode: "documents", + containerTag: "user_123", filters: { AND: [ { key: "category", value: "engineering" } @@ -78,6 +80,23 @@ Both SDKs also work against [self-hosted Supermemory](/self-hosting/overview) // Delete a document await client.documents.delete({ docId: "doc_123" }); ``` + + ## Error Handling & Retries + + | Status | Error | + |--------|-------| + | 400 | `BadRequestError` | + | 401 | `AuthenticationError` | + | 403 | `PermissionDeniedError` | + | 404 | `NotFoundError` | + | 409 | `ConflictError` | + | 422 | `UnprocessableEntityError` | + | 429 | `RateLimitError` | + | >=500 | `InternalServerError` | + + Connection errors, 408, 409, 429, and >=500 responses are retried automatically (`maxRetries`, default 2, exponential backoff). Requests time out after 1 minute by default (`timeout` option). Set the `SUPERMEMORY_LOG` env var (or `logLevel` client option) to `debug`/`info`/`warn`/`error`/`off` — defaults to `warn`. + + Requires TypeScript >= 4.9, Node 20+, Deno 1.28+, or Bun 1.0+. @@ -98,12 +117,13 @@ Both SDKs also work against [self-hosted Supermemory](/self-hosting/overview) ) # Add a memory - client.add(content="Meeting notes from Q1 planning", container_tags=["user_123"]) + client.add(content="Meeting notes from Q1 planning", container_tag="user_123") # Search memories - response = client.search.documents( + response = client.search.memories( q="planning notes", - container_tags=["user_123"] + search_mode="documents", + container_tag="user_123" ) print(response.results) @@ -119,14 +139,15 @@ Both SDKs also work against [self-hosted Supermemory](/self-hosting/overview) # Add with metadata client.add( content="Technical design doc", - container_tags=["user_123"], + container_tag="user_123", metadata={"category": "engineering", "priority": "high"} ) # Search with filters - results = client.search.documents( + results = client.search.memories( q="design document", - container_tags=["user_123"], + search_mode="documents", + container_tag="user_123", filters={ "AND": [ {"key": "category", "value": "engineering"} @@ -140,5 +161,11 @@ Both SDKs also work against [self-hosted Supermemory](/self-hosting/overview) # Delete a document client.documents.delete(doc_id="doc_123") ``` + + ## Error Handling & Retries + + Same error classes as the TypeScript SDK (`BadRequestError`, `AuthenticationError`, `PermissionDeniedError`, `NotFoundError`, `ConflictError`, `UnprocessableEntityError`, `RateLimitError`, `InternalServerError`), all inheriting from `supermemory.APIError`. Connection errors, 408, 409, 429, and >=500 responses are retried automatically (`max_retries`, default 2). Requests time out after 1 minute by default (`timeout` option). Set `SUPERMEMORY_LOG=info` (or `debug`) to enable logging. + + Requires Python 3.9+. diff --git a/apps/docs/intro.mdx b/apps/docs/intro.mdx deleted file mode 100644 index 319a55ea..00000000 --- a/apps/docs/intro.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "Overview — What is Supermemory?" -sidebarTitle: "Overview" -icon: "book-open" ---- - -Supermemory is the long-term and short-term memory and context infrastructure for AI agents. It is the [state of the art](https://supermemory.ai/research) across multiple different benchmarks, like LongMemEval and LoCoMo. - -With supermemory, developers can provide perfect recall about their users to build AI agents that are more intelligent, more personalized, and more consistent. Additionally, *supermemory* has all the pieces of the context stack built in: -- [Agent memory](/concepts/graph-memory) -- [Content extraction](/concepts/content-types) -- [Connectors and syncing](/connectors/overview) -- [Managed RAG platform](/concepts/super-rag) - -All this, coming together, makes supermemory the best abstraction to provide to agents. - -## How does it work? (at a glance) - -![](/images/232.png) - -- You send Supermemory text, files, and chats. -- Supermemory [intelligently indexes them](/concepts/how-it-works) and builds a semantic understanding graph on top of an entity (e.g., a user, a document, a project, an organization). -- At query time, we fetch only the most relevant context and pass it to your models. - -## Supermemory is context engineering. - -#### Ingestion and Extraction - -Supermemory handles all the extraction, for [any data type that you have](/concepts/content-types). -- Text -- Conversations -- Files (PDF, Images, Docs) -- Even videos! - -... and then, - -We offer three ways to add context to your LLMs: - -#### Memory API — Learned user context - -![memory graph](/images/memory-graph.png) - -Supermemory learns and builds the memory for the user. These are extracted facts about the user, that: -- [Evolve on top of existing context about the user](/concepts/graph-memory), **in real time** -- Handle **knowledge updates, temporal changes, forgetfulness** -- Creates a **user profile** as the default context provider for the LLM. - -_This can then be provided to the LLM, to give more contextual, personalized responses._ - -#### User profiles - -Having the latest, evolving context about the user allows us to also create a [**User Profile**](/concepts/user-profiles). This is a combination of static and dynamic facts about the user, that the agent should **always know** -Developers can configure supermemory with what static and dynamic contents are, depending on their use case. - -- Static: Information that the agent should **always** know. -- Dynamic: **Episodic** information, about last few conversations etc. - -This leads to a much better retrieval system, and extremely personalized responses. - -#### RAG - Advanced semantic search - -Along with the user context, developers can also choose to do a search on the raw context. We provide full RAG-as-a-service, along with -- Full advanced metadata filtering -- Contextual chunking -- Works well with the memory engine - - - See the full API Reference tab for detailed endpoint documentation. - - - - -All three approaches share the **same context pool** when using the same user ID (`containerTag`). You can mix and match based on your needs. - - -## Next steps - - - - Make your first API call in minutes - - - Understand the knowledge graph architecture - - - Run Supermemory on your own machine — one binary, zero config, fully offline - - - diff --git a/apps/docs/introduction.mdx b/apps/docs/introduction.mdx deleted file mode 100644 index 89f2437d..00000000 --- a/apps/docs/introduction.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: "Introduction" -description: "supermemory is the Memory API for the AI era" -mode: "custom" ---- - -export const HeroCard = ({ imageUrl, title, description, href }) => { - return ( - -
- {title} -
-
-

{title}

-

{description}

-
-
- ) -} - -
- -
-

- supermemory [docs] -

- -

- Meet the memory API for the AI era — scalable, powerful, affordable, and production-ready. -

- -
- - - - - - - -
-
-
diff --git a/apps/docs/list-memories/examples/basic.mdx b/apps/docs/list-memories/examples/basic.mdx deleted file mode 100644 index e0fa40dc..00000000 --- a/apps/docs/list-memories/examples/basic.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: "Basic Listing" -description: "Simple memory retrieval across languages" ---- - -Simple memory retrieval examples for getting started with the list memories endpoint. - -## Basic Usage - - - - ```typescript - import Supermemory from 'supermemory'; - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }); - - const response = await client.documents.list({ limit: 10 }); - console.log(response); - ``` - - - ```python - from supermemory import Supermemory - import os - - client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - response = client.documents.list(limit=10) - print(response) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"limit": 10}' - ``` - - - -## With Custom Parameters - - - - ```typescript - const response = await client.documents.list({ - containerTags: ["user_123"], - limit: 20, - sort: "updatedAt", - order: "desc" - }); - - console.log(`Found ${response.memories.length} memories`); - ``` - - - ```python - response = client.documents.list( - container_tags=["user_123"], - limit=20, - sort="updatedAt", - order="desc" - ) - - print(f"Found {len(response.memories)} memories") - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "containerTags": ["user_123"], - "limit": 20, - "sort": "updatedAt", - "order": "desc" - }' - ``` - - - - - Start with small `limit` values (10-20) when testing to avoid overwhelming responses. - diff --git a/apps/docs/list-memories/examples/filtering.mdx b/apps/docs/list-memories/examples/filtering.mdx deleted file mode 100644 index d159fb55..00000000 --- a/apps/docs/list-memories/examples/filtering.mdx +++ /dev/null @@ -1,506 +0,0 @@ ---- -title: "Filtering Memories" -description: "Filter memories by container tags and metadata using SQL-based filtering" ---- - -Filter memories using container tags and metadata. The filtering system uses SQL query construction, so you need to structure your filters like database queries. - -## Filter by Container Tags - -Container tags use exact array matching - memories must have the exact same tags in the same order. - - - - ```typescript - // Single tag - matches memories with exactly ["user_123"] - const userMemories = await client.documents.list({ - containerTags: ["user_123"] - }); - - // Multiple tags - matches memories with exactly ["user_123", "project_ai"] - const projectMemories = await client.documents.list({ - containerTags: ["user_123", "project_ai"] - }); - ``` - - - ```python - # Single tag - user_memories = client.documents.list(container_tags=["user_123"]) - - # Multiple tags (exact match) - project_memories = client.documents.list( - container_tags=["user_123", "project_ai"] - ) - ``` - - - ```bash - # Single tag - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"containerTags": ["user_123"]}' - - # Multiple tags - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"containerTags": ["user_123", "project_ai"]}' - ``` - - - -## Metadata Filtering with SQL Logic - -The `filters` parameter allows filtering by metadata fields using SQL-like query structures. Since we use SQL query construction in the backend, you need to structure your filters like database queries with explicit AND/OR logic. - -### Why This Structure? - -In SQL databases, `AND` has higher precedence than `OR`. Without explicit grouping, a query like: -``` -category = 'programming' OR framework = 'react' AND difficulty = 'advanced' -``` - -Is interpreted as: -``` -category = 'programming' OR (framework = 'react' AND difficulty = 'advanced') -``` - -The JSON structure forces explicit grouping to prevent unexpected results. - - -**Filter Structure Rules:** -- Always wrap conditions in `AND` or `OR` arrays (even single conditions) -- Pass the filter as an object (TypeScript/Python) or JSON string (cURL) -- Each condition needs `key`, `value`, and `negate` properties -- `negate: false` for normal matching, `negate: true` for exclusion - - -### Simple Metadata Filter - - - - ```typescript - // Filter by single metadata field - const programmingMemories = await client.documents.list({ - filters: { - AND: [ - { key: "category", value: "programming", negate: false } - ] - } - }); - ``` - - - ```python - # Filter by single metadata field - programming_memories = client.documents.list( - filters={ - "AND": [ - {"key": "category", "value": "programming", "negate": False} - ] - } - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "filters": "{\"AND\":[{\"key\":\"category\",\"value\":\"programming\",\"negate\":false}]}" - }' - ``` - - - -### Multiple Conditions (AND Logic) - - - - ```typescript - // All conditions must match - const reactTutorials = await client.documents.list({ - filters: { - AND: [ - { key: "category", value: "tutorial", negate: false }, - { key: "framework", value: "react", negate: false }, - { key: "difficulty", value: "beginner", negate: false } - ] - } - }); - ``` - - - ```python - # All conditions must match - react_tutorials = client.documents.list( - filters={ - "AND": [ - {"key": "category", "value": "tutorial", "negate": False}, - {"key": "framework", "value": "react", "negate": False}, - {"key": "difficulty", "value": "beginner", "negate": False} - ] - } - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "filters": "{\"AND\":[{\"key\":\"category\",\"value\":\"tutorial\",\"negate\":false},{\"key\":\"framework\",\"value\":\"react\",\"negate\":false}]}" - }' - ``` - - - -### Alternative Conditions (OR Logic) - - - - ```typescript - // Any condition can match - const frontendMemories = await client.documents.list({ - filters: { - OR: [ - { key: "framework", value: "react", negate: false }, - { key: "framework", value: "vue", negate: false }, - { key: "framework", value: "angular", negate: false } - ] - } - }); - ``` - - - ```python - # Any condition can match - frontend_memories = client.documents.list( - filters={ - "OR": [ - {"key": "framework", "value": "react", "negate": False}, - {"key": "framework", "value": "vue", "negate": False}, - {"key": "framework", "value": "angular", "negate": False} - ] - } - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "filters": "{\"OR\":[{\"key\":\"framework\",\"value\":\"react\",\"negate\":false},{\"key\":\"framework\",\"value\":\"vue\",\"negate\":false}]}" - }' - ``` - - - -### Complex Nested Logic - - - - ```typescript - // Complex logic: programming AND (react OR advanced difficulty) - const advancedContent = await client.documents.list({ - filters: { - AND: [ - { key: "category", value: "programming", negate: false }, - { - OR: [ - { key: "framework", value: "react", negate: false }, - { key: "difficulty", value: "advanced", negate: false } - ] - } - ] - } - }); - ``` - - - ```python - # Complex logic: programming AND (react OR advanced difficulty) - advanced_content = client.documents.list( - filters={ - "AND": [ - {"key": "category", "value": "programming", "negate": False}, - { - "OR": [ - {"key": "framework", "value": "react", "negate": False}, - {"key": "difficulty", "value": "advanced", "negate": False} - ] - } - ] - } - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "filters": "{\"AND\":[{\"key\":\"category\",\"value\":\"programming\",\"negate\":false},{\"OR\":[{\"key\":\"framework\",\"value\":\"react\",\"negate\":false},{\"key\":\"difficulty\",\"value\":\"advanced\",\"negate\":false}]}]}" - }' - ``` - - - -## Array Contains Filtering - -Filter memories that contain specific values in array fields like participants, tags, or team members. - -### Basic Array Contains - - - - ```typescript - // Find memories where john.doe participated - const meetingMemories = await client.documents.list({ - filters: { - AND: [ - { - key: "participants", - value: "john.doe", - filterType: "array_contains", - negate: false - } - ] - } - }); - ``` - - - ```python - # Find memories where john.doe participated - meeting_memories = client.documents.list( - filters={ - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains", - "negate": False - } - ] - } - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "filters": "{\"AND\":[{\"key\":\"participants\",\"value\":\"john.doe\",\"filterType\":\"array_contains\",\"negate\":false}]}" - }' - ``` - - - -### Array Contains with Exclusion - - - - ```typescript - // Find memories that don't include a specific team member - const filteredMemories = await client.documents.list({ - filters: { - AND: [ - { - key: "reviewers", - value: "external.consultant", - filterType: "array_contains", - negate: true // Exclude memories with external consultants - }, - { - key: "project_tags", - value: "internal-only", - filterType: "array_contains", - negate: false - } - ] - } - }); - ``` - - - ```python - # Find memories that don't include a specific team member - filtered_memories = client.documents.list( - filters={ - "AND": [ - { - "key": "reviewers", - "value": "external.consultant", - "filterType": "array_contains", - "negate": True # Exclude memories with external consultants - }, - { - "key": "project_tags", - "value": "internal-only", - "filterType": "array_contains", - "negate": False - } - ] - } - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "filters": "{\"AND\":[{\"key\":\"reviewers\",\"value\":\"external.consultant\",\"filterType\":\"array_contains\",\"negate\":true},{\"key\":\"project_tags\",\"value\":\"internal-only\",\"filterType\":\"array_contains\",\"negate\":false}]}" - }' - ``` - - - -### Multiple Array Contains (OR Logic) - - - - ```typescript - // Find memories involving any of several team leads - const leadershipMemories = await client.documents.list({ - filters: { - OR: [ - { - key: "attendees", - value: "engineering.lead", - filterType: "array_contains" - }, - { - key: "attendees", - value: "product.lead", - filterType: "array_contains" - }, - { - key: "attendees", - value: "design.lead", - filterType: "array_contains" - } - ] - }, - sort: "updatedAt", - order: "desc" - }); - ``` - - - ```python - # Find memories involving any of several team leads - leadership_memories = client.documents.list( - filters={ - "OR": [ - { - "key": "attendees", - "value": "engineering.lead", - "filterType": "array_contains" - }, - { - "key": "attendees", - "value": "product.lead", - "filterType": "array_contains" - }, - { - "key": "attendees", - "value": "design.lead", - "filterType": "array_contains" - } - ] - }, - sort="updatedAt", - order="desc" - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "filters": "{\"OR\":[{\"key\":\"attendees\",\"value\":\"engineering.lead\",\"filterType\":\"array_contains\"},{\"key\":\"attendees\",\"value\":\"product.lead\",\"filterType\":\"array_contains\"},{\"key\":\"attendees\",\"value\":\"design.lead\",\"filterType\":\"array_contains\"}]}", - "sort": "updatedAt", - "order": "desc" - }' - ``` - - - -## Combined Container Tags + Metadata Filtering - - - - ```typescript - const filteredMemories = await client.documents.list({ - containerTags: ["user_123"], - filters: { - AND: [ - { key: "category", value: "tutorial", negate: false }, - { key: "framework", value: "react", negate: false } - ] - }, - sort: "updatedAt", - order: "desc", - limit: 50 - }); - ``` - - - ```python - filtered_memories = client.documents.list( - container_tags=["user_123"], - filters={ - "AND": [ - {"key": "category", "value": "tutorial", "negate": False}, - {"key": "framework", "value": "react", "negate": False} - ] - }, - sort="updatedAt", - order="desc", - limit=50 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "containerTags": ["user_123"], - "filters": "{\"AND\":[{\"key\":\"category\",\"value\":\"tutorial\",\"negate\":false},{\"key\":\"framework\",\"value\":\"react\",\"negate\":false}]}", - "sort": "updatedAt", - "order": "desc", - "limit": 50 - }' - ``` - - - - -**Common Mistakes:** -- Using bare condition objects: `{"key": "category", "value": "programming"}` without wrapping in `AND` or `OR` -- Missing negate property: always include `"negate": false` or `"negate": true` -- For cURL requests: forgetting to properly escape the JSON string - - - -**Container Tags vs Metadata Filtering:** -- Container tags: Exact array matching for organizational grouping -- Metadata filters: SQL-like queries on custom metadata fields with complex logic -- Both can be combined for powerful filtering capabilities - diff --git a/apps/docs/list-memories/examples/monitoring.mdx b/apps/docs/list-memories/examples/monitoring.mdx deleted file mode 100644 index 7c373d3c..00000000 --- a/apps/docs/list-memories/examples/monitoring.mdx +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: "Status Monitoring" -description: "Monitor memory processing status and completion rates" ---- - -Monitor memory processing status and track completion rates using the list endpoint. - -## Status Overview - - - - ```typescript - const response = await client.documents.list({ limit: 100 }); - - const statusCounts = response.memories.reduce((acc: any, memory) => { - acc[memory.status] = (acc[memory.status] || 0) + 1; - return acc; - }, {}); - - console.log('Status breakdown:', statusCounts); - ``` - - - ```python - response = client.documents.list(limit=100) - - status_counts = {} - for memory in response.memories: - status = memory.status - status_counts[status] = status_counts.get(status, 0) + 1 - - print("Status breakdown:", status_counts) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"limit": 100}' | \ - jq '.memories | group_by(.status) | map({status: .[0].status, count: length})' - ``` - - - -## Filter Processing Memories - - - - ```typescript - const response = await client.documents.list({ limit: 100 }); - - const processing = response.memories.filter(m => - ['queued', 'extracting', 'chunking', 'embedding', 'indexing'].includes(m.status) - ); - - console.log(`${processing.length} memories currently processing`); - ``` - - - ```python - response = client.documents.list(limit=100) - - processing_statuses = ['queued', 'extracting', 'chunking', 'embedding', 'indexing'] - processing = [m for m in response.memories if m.status in processing_statuses] - - print(f"{len(processing)} memories currently processing") - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"limit": 100}' | \ - jq '.memories[] | select(.status | IN("queued", "extracting", "chunking", "embedding", "indexing"))' - ``` - - - -## Failed Memories - - - - ```typescript - const response = await client.documents.list({ limit: 100 }); - - const failedMemories = response.memories.filter(m => m.status === 'failed'); - - failedMemories.forEach(memory => { - console.log(`Failed: ${memory.id} - ${memory.title || 'Untitled'}`); - }); - ``` - - - ```python - response = client.documents.list(limit=100) - - failed_memories = [m for m in response.memories if m.status == 'failed'] - - for memory in failed_memories: - title = memory.title or 'Untitled' - print(f"Failed: {memory.id} - {title}") - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"limit": 100}' | \ - jq '.memories[] | select(.status == "failed") | {id, title, status}' - ``` - - - - - For real-time monitoring of individual memories, use the [Track Processing Status](/memory-api/track-progress) guide. - diff --git a/apps/docs/list-memories/examples/pagination.mdx b/apps/docs/list-memories/examples/pagination.mdx deleted file mode 100644 index 9a975acc..00000000 --- a/apps/docs/list-memories/examples/pagination.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: "Pagination" -description: "Handle large memory collections with pagination" ---- - -Handle large memory collections efficiently using pagination to process data in manageable chunks. - -## Basic Pagination - - - - ```typescript - // Get first page - const page1 = await client.documents.list({ - limit: 20, - page: 1 - }); - - // Get next page - const page2 = await client.documents.list({ - limit: 20, - page: 2 - }); - - console.log(`Page 1: ${page1.memories.length} memories`); - console.log(`Page 2: ${page2.memories.length} memories`); - ``` - - - ```python - # Get first page - page1 = client.documents.list(limit=20, page=1) - - # Get next page - page2 = client.documents.list(limit=20, page=2) - - print(f"Page 1: {len(page1.memories)} memories") - print(f"Page 2: {len(page2.memories)} memories") - ``` - - - ```bash - # Get first page - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"limit": 20, "page": 1}' - - # Get next page - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"limit": 20, "page": 2}' - ``` - - - -## Loop Through Pages - - - - ```typescript - let currentPage = 1; - let hasMore = true; - - while (hasMore) { - const response = await client.documents.list({ - page: currentPage, - limit: 50 - }); - - console.log(`Page ${currentPage}: ${response.memories.length} memories`); - - hasMore = currentPage < response.pagination.totalPages; - currentPage++; - } - ``` - - - ```python - current_page = 1 - has_more = True - - while has_more: - response = client.documents.list(page=current_page, limit=50) - - print(f"Page {current_page}: {len(response.memories)} memories") - - has_more = current_page < response.pagination.total_pages - current_page += 1 - ``` - - - ```bash - # Manual pagination with bash loop - for page in {1..5}; do - echo "=== Page $page ===" - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d "{\"page\": $page, \"limit\": 20}" | \ - jq '.memories | length' - done - ``` - - - - - Use larger `limit` values (50-100) for pagination to reduce the number of API calls needed. - diff --git a/apps/docs/list-memories/overview.mdx b/apps/docs/list-memories/overview.mdx deleted file mode 100644 index 13976fe7..00000000 --- a/apps/docs/list-memories/overview.mdx +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: "List Memories" -description: "Retrieve paginated memories with filtering and sorting options" -sidebarTitle: "Overview" ---- - - -Retrieve paginated memories with filtering and sorting options from your Supermemory account. - -## Quick Start - - - - ```typescript - import Supermemory from 'supermemory'; - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }); - - const memories = await client.documents.list({ limit: 10 }); - console.log(memories); - ``` - - - ```python - from supermemory import Supermemory - import os - - client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - memories = client.documents.list(limit=10) - print(f"Found {len(memories.memories)} memories") - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/documents/list" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"limit": 10}' - ``` - - - -## Response Schema - -The endpoint returns a structured response containing your memories and pagination information: - -```json -{ - "memories": [ - { - "id": "abc123", - "connectionId": null, - "createdAt": "2024-01-15T10:30:00.000Z", - "updatedAt": "2024-01-15T10:35:00.000Z", - "customId": "ml-basics-001", - "title": "Introduction to Machine Learning", - "summary": "This document introduces machine learning as a subset of artificial intelligence...", - "status": "done", - "type": "text", - "metadata": { - "category": "education", - "priority": "high", - "source": "research-notes" - }, - "containerTags": ["user_123", "ai-research"] - } - ], - "pagination": { - "currentPage": 1, - "totalPages": 3, - "totalItems": 25, - "limit": 10 - } -} -``` - -### Memory Object Fields - - - -| Field | Type | Description | -|-------|------|-------------| -| `id` | string | Unique identifier for the memory | -| `status` | ProcessingStatus | Current processing status (`queued`, `extracting`, `chunking`, `embedding`, `indexing`, `done`, `failed`) | -| `type` | MemoryType | Content type (`text`, `pdf`, `webpage`, `video`, `image`, etc.) | -| `title` | string \| null | Auto-generated or custom title | -| `summary` | string \| null | AI-generated summary of content | -| `createdAt` | string | ISO 8601 creation timestamp | -| `updatedAt` | string | ISO 8601 last update timestamp | - - - - - -| Field | Type | Description | -|-------|------|-------------| -| `customId` | string \| null | Your custom identifier for the memory | -| `connectionId` | string \| null | ID of connector that created this memory | -| `metadata` | object \| null | Custom key-value metadata you provided | -| `containerTags` | string[] | Tags for organizing and filtering memories | - - - -## Key Parameters - -All parameters are optional and sent in the request body since this endpoint uses `POST`: - - - **Number of items per page.** Controls how many memories are returned in a single request. Maximum recommended: 200 for optimal performance. - - - - **Page number to fetch (1-indexed).** Use with `limit` to paginate through large result sets. - - - - **Filter by tags.** Memories must match ALL provided tags. Use for filtering by user ID, project, or custom organization tags. - - - - **Sort field.** Options: `"createdAt"` (when memory was added) or `"updatedAt"` (when memory was last modified). - - - - **Sort direction.** Use `"desc"` for newest first, `"asc"` for oldest first. - - - - **Advanced filtering.** Filter based on metadata with advanced SQL logic. - - -## Examples - - - - Simple memory retrieval with default settings - - - Filter by tags, status, and other criteria - - - Handle large datasets with pagination - - - Track processing status across memories - - - - - The `/v3/documents/list` endpoint uses **POST** method, not GET. This allows for complex filtering parameters in the request body. - diff --git a/apps/docs/memory-api/connectors/advanced/bring-your-own-key.mdx b/apps/docs/memory-api/connectors/advanced/bring-your-own-key.mdx deleted file mode 100644 index 3d63cb46..00000000 --- a/apps/docs/memory-api/connectors/advanced/bring-your-own-key.mdx +++ /dev/null @@ -1,138 +0,0 @@ ---- -title: 'Bring Your Own Key (BYOK)' -description: 'Configure your own OAuth application credentials for enhanced security and control' ---- - -By default, supermemory uses its own OAuth applications to connect to third-party providers. However, you can configure your own OAuth application credentials for enhanced security and control. This is particularly useful for enterprise customers who want to maintain control over their data access. - - - Some providers like Google Drive require extensive verification and approval before you can use custom keys. - - -### Setting up Custom Provider Keys - -To configure custom OAuth credentials for your organization, use the `PATCH /v3/settings` endpoint: - -1. Set up your OAuth application on the provider's developer console. - -Google: https://console.developers.google.com/apis/credentials/oauthclient \ -Notion: https://www.notion.so/my-integrations \ -OneDrive: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsMenu - -2. If using Google drive, - -- Select the application type as `Web application` -- **Enable the Google drive api in "APIs and Services" in the Cloud Console** - -3. Configure the redirect URL, set it to: - -``` -https://api.supermemory.ai/v3/connections/auth/callback/{provider} -``` - -For example, if you are using Google Drive, the redirect URL would be: - -``` -https://api.supermemory.ai/v3/connections/auth/callback/google-drive -``` - -4. Configure the client ID and client secret in the `PATCH /v3/settings` endpoint. - - -```typescript Typescript -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env['SUPERMEMORY_API_KEY'], -}); - -// Example: Configure Google Drive custom OAuth credentials -const settings = await client.settings.update({ - googleCustomKeyEnabled: true, - googleDriveClientId: "your-google-client-id", - googleDriveClientSecret: "your-google-client-secret" -}); - -// Example: Configure Notion custom OAuth credentials -const settings = await client.settings.update({ - notionCustomKeyEnabled: true, - notionClientId: "your-notion-client-id", - notionClientSecret: "your-notion-client-secret" -}); - -// Example: Configure OneDrive custom OAuth credentials -const settings = await client.settings.update({ - onedriveCustomKeyEnabled: true, - onedriveClientId: "your-onedrive-client-id", - onedriveClientSecret: "your-onedrive-client-secret" -}); -``` - -```python Python -from supermemory import supermemory - -client = supermemory( - api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted -) - -# Example: Configure Google Drive custom OAuth credentials -settings = client.settings.update( - google_custom_key_enabled=True, - google_client_id="your-google-client-id", - google_client_secret="your-google-client-secret" -) - -# Example: Configure Notion custom OAuth credentials -settings = client.settings.update( - notion_custom_key_enabled=True, - notion_client_id="your-notion-client-id", - notion_client_secret="your-notion-client-secret" -) - -# Example: Configure OneDrive custom OAuth credentials -settings = client.settings.update( - onedrive_custom_key_enabled=True, - onedrive_client_id="your-onedrive-client-id", - onedrive_client_secret="your-onedrive-client-secret" -) -``` - -```bash cURL -# Example: Configure Google Drive custom OAuth credentials -curl --request PATCH \ - --url https://api.supermemory.ai/v3/settings \ - --header 'Authorization: Bearer ' \ - --header 'Content-Type: application/json' \ - --data '{ - "googleDriveCustomKeyEnabled": true, - "googleDriveClientId": "your-google-client-id", - "googleDriveClientSecret": "your-google-client-secret" -}' - -# Example: Configure Notion custom OAuth credentials -curl --request PATCH \ - --url https://api.supermemory.ai/v3/settings \ - --header 'Authorization: Bearer ' \ - --header 'Content-Type: application/json' \ - --data '{ - "notionCustomKeyEnabled": true, - "notionClientId": "your-notion-client-id", - "notionClientSecret": "your-notion-client-secret" -}' - -# Example: Configure OneDrive custom OAuth credentials -curl --request PATCH \ - --url https://api.supermemory.ai/v3/settings \ - --header 'Authorization: Bearer ' \ - --header 'Content-Type: application/json' \ - --data '{ - "onedriveCustomKeyEnabled": true, - "onedriveClientId": "your-onedrive-client-id", - "onedriveClientSecret": "your-onedrive-client-secret" -}' -``` - - - - Once you enable custom keys for a provider, all new connections for that provider will use your custom OAuth application. Existing connections WILL need to be re-authorized. - \ No newline at end of file diff --git a/apps/docs/memory-api/connectors/creating-connection.mdx b/apps/docs/memory-api/connectors/creating-connection.mdx deleted file mode 100644 index debabe7b..00000000 --- a/apps/docs/memory-api/connectors/creating-connection.mdx +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: 'Creating connections' -description: 'Create a connection to sync your content with supermemory' ---- - -To create a connection, just make a `POST` request to `/v3/connections/{provider}` - - -```typescript Typescript -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env['SUPERMEMORY_API_KEY'], // This is the default and can be omitted -}); - -// For OAuth providers (notion, google-drive, onedrive) -const connection = await client.connections.create('notion'); -console.debug(connection.authLink); - -// For web-crawler (no OAuth required) -const webCrawlerConnection = await client.connections.create('web-crawler', { - metadata: { startUrl: 'https://docs.example.com' } -}); -console.debug(webCrawlerConnection.id); // authLink will be null -``` - -```python Python -import requests - -url = "https://api.supermemory.ai/v3/connections/{provider}" - -payload = { - "redirectUrl": "", - "containerTags": [""], - "metadata": {}, - "documentLimit": 5000 -} -headers = { - "Authorization": "Bearer ", - "Content-Type": "application/json" -} - -response = requests.request("POST", url, json=payload, headers=headers) - -print(response.text) -``` - -```bash cURL -curl --request POST \ - --url https://api.supermemory.ai/v3/connections/{provider} \ - --header 'Authorization: Bearer ' \ - --header 'Content-Type: application/json' \ - --data '{ - "redirectUrl": "", - "containerTags": [ - "" - ], - "metadata": {}, - "documentLimit": 5000 -}' -``` - - -### Parameters - -- `provider`: The provider to connect to. Currently supported providers are `notion`, `google-drive`, `onedrive`, `web-crawler` -- `redirectUrl`: The URL to redirect to after the connection is created (your app URL) - - Note: For `web-crawler`, this is optional as no OAuth flow is required -- `containerTags`: Optional. For partitioning users, organizations, etc. in your app. - - Example: `["user_123", "project_alpha"]` -- `metadata`: Optional. Any metadata you want to associate with the connection. - - This metadata is added to every document synced from this connection. - - For `web-crawler`, must include `startUrl` in metadata: `{"startUrl": "https://example.com"}` -- `documentLimit`: Optional. Caps how many provider items are fetched **per sync run** (allowed range **1–10,000** when set). Exact behavior is provider-specific. - - **Notion:** Pages come from the Notion Search API, **newest edited first**; once the limit is reached, remaining shareable pages are skipped until a later sync or a higher limit. See [Notion connector — Document limit](/connectors/notion#document-limit). - - Default when omitted depends on how the connection is created (often **10,000** for hosted flows). - - Use this to control scope and cost per sync. - - -## Response - -supermemory sends a response with the following schema: -```json -{ - "id": "", - "authLink": "", - "expiresIn": "", - "redirectsTo": "" -} -``` - -For most providers (notion, google-drive, onedrive), you can use the `authLink` to redirect the user to the provider's login page. - - -**Web Crawler Exception:** For `web-crawler` provider, `authLink` and `expiresIn` will be `null` since no OAuth flow is required. The connection is established immediately upon creation. - - -Next up, managing connections. diff --git a/apps/docs/memory-api/connectors/google-drive.mdx b/apps/docs/memory-api/connectors/google-drive.mdx deleted file mode 100644 index 8413fdd2..00000000 --- a/apps/docs/memory-api/connectors/google-drive.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: 'Google Drive' -description: 'Sync your Google Drive content with supermemory' ---- - -supermemory syncs Google Drive documents automatically and instantaneously. - -## Supported file types - -- Google Docs -- Google Slides -- Google Sheets - -## Conversions - -To import items, supermemory converts documents into markdown, and then ingests them into supermemory. -This conversion is lossy, and some formatting may be lost. - -## Sync frequency - -supermemory syncs documents: -- **A document is modified or created (Webhook recieved)** - - Note that not all providers are synced via webhook (Instant sync right now) - - `Google-Drive` and `Notion` documents are synced instantaneously -- Every **four hours** -- On **Manual Sync** (API call) - - You can call `/v3/connections/{provider}/sync` to sync documents manually diff --git a/apps/docs/memory-api/connectors/overview.mdx b/apps/docs/memory-api/connectors/overview.mdx deleted file mode 100644 index e7f9d479..00000000 --- a/apps/docs/memory-api/connectors/overview.mdx +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: 'Connectors Overview' -sidebarTitle: 'Overview' -description: 'Sync external connections like Google Drive, Notion, OneDrive, Web Crawler with supermemory' ---- - -supermemory can sync external connections like Google Drive, Notion, OneDrive, and Web Crawler. - -### The Flow - -For OAuth-based connectors (Notion, Google Drive, OneDrive): -1. Make a `POST` request to `/v3/connections/{provider}` -2. supermemory will return an `authLink` which you can redirect the user to -3. The user will be redirected to the provider's login page -4. User is redirected back to your app's `redirectUrl` - -For Web Crawler: -1. Make a `POST` request to `/v3/connections/web-crawler` with `startUrl` in metadata -2. Connection is established immediately (no OAuth required) -3. Crawling begins automatically - -![Connectors Flow](/images/connectors-flow.png) - -## Sync frequency - -supermemory syncs documents: -- **A document is modified or created (Webhook received)** - - Note that not all providers are synced via webhook (Instant sync right now) - - `Google-Drive` and `Notion` documents are synced instantaneously - - `Web-Crawler` uses scheduled recrawling instead of webhooks -- Every **four hours** (for OAuth-based connectors) -- **Scheduled recrawling** (for Web Crawler - sites recrawled if not synced in 7+ days) -- On **Manual Sync** (API call) - - You can call `/v3/connections/{provider}/sync` to sync documents manually diff --git a/apps/docs/memory-api/creation/adding-memories.mdx b/apps/docs/memory-api/creation/adding-memories.mdx deleted file mode 100644 index 4c6471e3..00000000 --- a/apps/docs/memory-api/creation/adding-memories.mdx +++ /dev/null @@ -1,374 +0,0 @@ ---- -title: "Adding Memories" -description: "Learn how to add content to supermemory" -icon: "plus" ---- - - -1. **Content Organization** - - **Use `containerTags` for grouping/partitioning** - - Optional tags (array of strings) to group memories. - - Can be a user ID, project ID, or any other identifier. - - Allows filtering for memories that share specific tags. - - Example: `["user_123", "project_alpha"]` - - Read more about [filtering](/memory-api/features/filtering) - -2. **Performance Tips** - - **Batch Operations** - - You can add multiple items in parallel - - Use different `containerTags` for different spaces - - Don't wait for processing to complete unless needed - - - **Search Optimization** - ```json - { - "q": "error logs", - "documentThreshold": 0.7, // Higher = more precise - "limit": 5, // Keep it small - "onlyMatchingChunks": true // Skip extra context if not needed - } - ``` - -3. **URL Content** - - Send clean URLs without tracking parameters - - Use article URLs, not homepage URLs - - Check URL accessibility before sending - - - -## Basic Usage - -To add a memory, send a POST request to `/add` with your content: - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --data '{ - "customId": "xyz-my-db-id", - "content": "This is the content of my memory", - "metadata": { - "category": "technology", - "tag_1": "ai", - "tag_2": "machine-learning", - }, - "containerTags": ["user_123", "project_xyz"] -}' -``` - -```typescript Typescript -await client.memory.create({ - customId: "xyz-mydb-id", - content: "This is the content of my memory", - metadata: { - category: "technology", - tag_1": "ai", - tag_2": "machine-learning", - }, - containerTags: ["user_123", "project_xyz"] -}) -``` - -```python Python -client.memory.create( - customId="xyz-mydb-id", - content="documents related to python", - metadata={ - "category": "datascience", - "tag_1": "ai", - "tag_2": "machine-learning", - }, - containerTags=["user_123", "project_xyz"] -) -``` - - - -The API will return a response with an ID and initial status: - -```json -{ - "id": "mem_abc123", - "status": "queued" -} -``` - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - -d '{ - "content": "https://example.com/article", - "metadata": { - "source": "web", # Just example metadata - "category": "technology" # NOT required - }, - "containerTags": ["user_456", "research_papers"] - }' -``` - -```typescript Typescript -await client.memory.create({ - content: "https://example.com/article", - userId: "user_456", - metadata: { - source: "web", // Just example metadata - category: "technology", // NOT required - }, - containerTags: ["user_456", "research_papers"], -}); -``` - -```python Python -client.memory.create( - content="https://example.com/article", - userId="user_456", - metadata={ - "source": "web", - "category": "technology" - }, - containerTags=["user_456", "research_papers"] -) -``` - - - - -## Metadata and Organization - -You can add rich metadata to organize your content: - -```json -{ - "metadata": { - "source": "string", // String - "priority": 1234, // Custom numeric field - "custom_field": "any" // Any custom field - } -} -``` - - -## Partitioning by user - -You can attribute and partition your data by providing a `userId`: - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - -d '{ - "content": "This is space-specific content", - "userId": "space_123", - "metadata": { - "category": "space-content" - } - }' -``` - -```typescript Typescript -await client.memory.create({ - content: "This is space-specific content", - userId: "space_123", - metadata: { - category: "space-content", - }, -}); -``` - -```python Python -client.memory.create( - content="This is space-specific content", - userId="space_123", - metadata={ - "category": "space-content" - } -) -``` - - - - - When searching, if you provide a `userId`, only memories from that space will - be returned. - - -## Grouping - -You can group memories by providing an array of `containerTags`: - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - -d '{ - "content": "This is space-specific content", - "containerTags": ["user_123", "project_xyz"] - }' -``` - -```typescript Typescript -await client.memory.create({ - content: "This is space-specific content", - containerTags: ["user_123", "project_xyz"], -}); -``` - -```python Python -client.memory.create( - content="This is space-specific content", - containerTags=["user_123", "project_xyz"] -) -``` - - - -## Checking Status - -Check status using the memory ID: - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents/mem_abc123 \ - --request GET \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' -``` - -```typescript Typescript -await client.memory.get("mem_abc123"); -``` - -```python Python -client.memory.get("mem_abc123") -``` - - - - - -Memories are deleted after 2 minutes if an irrecoverable error occurs. - - - -## File Uploads - -For file uploads, use the dedicated file upload endpoint. You can include `containerTags` directly in the form data: - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents/file \ - --request POST \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --form 'file=@/path/to/your/file.pdf' \ - --form 'containerTags=["user_123", "project_xyz"]' -``` - -```typescript Typescript -const formData = new FormData(); -formData.append("file", fileBlob); -formData.append("containerTags", JSON.stringify(["user_123", "project_xyz"])); - -const response = await fetch("https://api.supermemory.ai/v3/documents/file", { - method: "POST", - headers: { - Authorization: "Bearer SUPERMEMORY_API_KEY", - }, - body: formData, -}); -``` - -```python Python -import requests -import json - -with open('/path/to/your/file.pdf', 'rb') as f: - files = {'file': f} - data = {'containerTags': json.dumps(["user_123", "project_xyz"])} - response = requests.post( - 'https://api.supermemory.ai/v3/documents/file', - headers={'Authorization': 'Bearer SUPERMEMORY_API_KEY'}, - files=files, - data=data - ) -``` - - - -### Adding Additional Metadata to Files - -If you need to add additional metadata (like title or description) after upload, you can use the PATCH endpoint: - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents/MEMORY_ID \ - --request PATCH \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --data '{ - "metadata": { - "title": "My Document", - "description": "Important project document" - } - }' -``` - -```typescript Typescript -await fetch(`https://api.supermemory.ai/v3/documents/${memoryId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer SUPERMEMORY_API_KEY", - }, - body: JSON.stringify({ - metadata: { - title: "My Document", - description: "Important project document", - }, - }), -}); -``` - -```python Python -import requests - -requests.patch( - f'https://api.supermemory.ai/v3/documents/{memory_id}', - headers={ - 'Content-Type': 'application/json', - 'Authorization': 'Bearer SUPERMEMORY_API_KEY' - }, - json={ - 'metadata': { - 'title': 'My Document', - 'description': 'Important project document' - } - } -) -``` - - - - - Metadata-only PATCH updates the document in place—no reindexing. Use this when adding or changing metadata (e.g. `accepted`, `title`, `description`) without modifying the document content. - - -## Next Steps - -Explore more advanced features in our API Reference tab. diff --git a/apps/docs/memory-api/creation/status.mdx b/apps/docs/memory-api/creation/status.mdx deleted file mode 100644 index 44a53656..00000000 --- a/apps/docs/memory-api/creation/status.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Processing Status" -description: "Learn about the stages of content processing" ---- - -After adding content, you can check its processing status: - -1. `queued`: Content is queued for processing -2. `extracting`: Extracting content from source -3. `chunking`: Splitting content into semantic chunks -4. `embedding`: Generating vector embeddings -5. `indexing`: Adding to search index -6. `done`: Processing complete -7. `failed`: Processing failed \ No newline at end of file diff --git a/apps/docs/memory-api/features/auto-multi-modal.mdx b/apps/docs/memory-api/features/auto-multi-modal.mdx deleted file mode 100644 index df20c318..00000000 --- a/apps/docs/memory-api/features/auto-multi-modal.mdx +++ /dev/null @@ -1,181 +0,0 @@ ---- -title: "Auto Multi Modal" -description: "supermemory automatically detects the content type of the document you are adding." -icon: "sparkles" ---- - -supermemory is natively multi-modal, and can automatically detect the content type of the document you are adding. - -We use the best of breed tools to extract content from URLs, and process it for optimal memory storage. - -## Automatic Content Type Detection - -supermemory automatically detects the content type of the document you're adding. Simply pass your content to the API, and supermemory will handle the rest. - - - - The content detection system analyzes: - - URL patterns and domains - - File extensions and MIME types - - Content structure and metadata - - Headers and response types - - - - 1. **Type Selection** - - Use `note` for simple text - - Use `webpage` for online content - - Use native types when possible - - 2. **URL Content** - - Send clean URLs without tracking parameters - - Use article URLs, not homepage URLs - - Check URL accessibility before sending - - - - - -### Quick Implementation - -All you need to do is pass the content to the `/documents` endpoint: - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents \ - --request POST \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - -d '{"content": "https://example.com/article"}' -``` - -```typescript -await client.add.create({ - content: "https://example.com/article", -}); -``` - -```python -client.add.create( - content="https://example.com/article" -) -``` - - - - - supermemory uses [Markdowner](https://md.dhr.wtf) to extract content from - URLs. - - -## Supported Content Types - -supermemory supports a wide range of content formats to ensure versatility in memory creation: - - - - - `note`: Plain text notes and documents - - Directly processes raw text content - - Automatically chunks content for optimal retrieval - - Preserves formatting and structure - - - - - `webpage`: Web pages (just provide the URL) - - Intelligently extracts main content - - Preserves important metadata (title, description, images) - - Extracts OpenGraph metadata when available - - - `tweet`: Twitter content - - Captures tweet text, media, and metadata - - Preserves thread structure if applicable - - - - - - `pdf`: PDF files - - Extracts text content while maintaining structure - - Handles both searchable PDFs and scanned documents with OCR - - Preserves page breaks and formatting - - - `google_doc`: Google Documents - - Seamlessly integrates with Google Docs API - - Maintains document formatting and structure - - Auto-updates when source document changes - - - `notion_doc`: Notion pages - - Extracts content while preserving Notion's block structure - - Handles rich text formatting and embedded content - - - - - - `image`: Images with text content - - Advanced OCR for text extraction - - Visual content analysis and description - - - `video`: Video content - - Transcription and content extraction - - Key frame analysis - - - - -## Processing Pipeline - - - - supermemory automatically identifies the content type based on the input provided. - - - - Type-specific extractors process the content with: - Specialized parsing for - each format - Error handling with retries - Rate limit management - - - - ```typescript - interface ProcessedContent { - content: string; // Extracted text - summary?: string; // AI-generated summary - tags?: string[]; // Extracted tags - categories?: string[]; // Content categories - } - ``` - - - - - Sentence-level splitting - - 2-sentence overlap - - Context preservation - - Semantic coherence - - - -## Technical Specifications - -### Size Limits - -| Content Type | Max Size | -| ------------ | -------- | -| Text/Note | 1MB | -| PDF | 10MB | -| Image | 5MB | -| Video | 100MB | -| Web Page | N/A | -| Google Doc | N/A | -| Notion Page | N/A | -| Tweet | N/A | - -### Processing Time - -| Content Type | Processing Time | -| ------------ | --------------- | -| Text/Note | Almost instant | -| PDF | 1-5 seconds | -| Image | 2-10 seconds | -| Video | 10+ seconds | -| Web Page | 1-3 seconds | -| Google Doc | N/A | -| Notion Page | N/A | -| Tweet | N/A | diff --git a/apps/docs/memory-api/features/content-cleaner.mdx b/apps/docs/memory-api/features/content-cleaner.mdx deleted file mode 100644 index e586c3dc..00000000 --- a/apps/docs/memory-api/features/content-cleaner.mdx +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: "Cleaning and Categorizing" -description: "Document Cleaning Summaries in supermemory" -icon: "washing-machine" ---- - -supermemory provides advanced configuration options to customize your content processing pipeline. At its core is an AI-powered system that can automatically analyze, categorize, and filter your content based on your specific needs. - -## Configuration Schema - -```json -{ - "shouldLLMFilter": true, - "categories": ["feature-request", "bug-report", "positive", "negative"], - "filterPrompt": "Analyze feedback sentiment and identify feature requests", - "includeItems": ["critical", "high-priority"], - "excludeItems": ["spam", "irrelevant"] -} -``` - -## Core Settings - -### shouldLLMFilter -- **Type**: `boolean` -- **Required**: No (defaults to `false`) -- **Description**: Master switch for AI-powered content analysis. Must be enabled to use any of the advanced filtering features. - -### categories -- **Type**: `string[]` -- **Limits**: Each category must be 1-50 characters -- **Required**: No -- **Description**: Define custom categories for content classification. When specified, the AI will only use these categories. If not specified, it will generate 3-5 relevant categories automatically. - -### filterPrompt -- **Type**: `string` -- **Limits**: 1-750 characters -- **Required**: No -- **Description**: Custom instructions for the AI on how to analyze and categorize content. Use this to guide the categorization process based on your specific needs. - -### includeItems & excludeItems -- **Type**: `string[]` -- **Limits**: Each item must be 1-20 characters -- **Required**: No -- **Description**: Fine-tune content filtering by specifying items to explicitly include or exclude during processing. - -## Content Processing Pipeline - -When content is ingested with LLM filtering enabled: - -1. **Initial Processing** - - Content is extracted and normalized - - Basic metadata (title, description) is captured - -2. **AI Analysis** - - Content is analyzed based on your `filterPrompt` - - Categories are assigned (either from your predefined list or auto-generated) - - Tags are evaluated and scored - -3. **Chunking & Indexing** - - Content is split into semantic chunks - - Each chunk is embedded for efficient search - - Metadata and classifications are stored - -## Example Use Cases - -### 1. Customer Feedback System -```json -{ - "shouldLLMFilter": true, - "categories": ["positive", "negative", "neutral"], - "filterPrompt": "Analyze customer sentiment and identify key themes", -} -``` - -### 2. Content Moderation -```json -{ - "shouldLLMFilter": true, - "categories": ["safe", "needs-review", "flagged"], - "filterPrompt": "Identify potentially inappropriate or sensitive content", - "excludeItems": ["spam", "offensive"], - "includeItems": ["user-generated"] -} -``` - -> **Important**: All filtering features (`categories`, `filterPrompt`, `includeItems`, `excludeItems`) require `shouldLLMFilter` to be enabled. Attempting to use these features without enabling `shouldLLMFilter` will result in a 400 error. diff --git a/apps/docs/memory-api/features/filtering.mdx b/apps/docs/memory-api/features/filtering.mdx deleted file mode 100644 index e7e3a14d..00000000 --- a/apps/docs/memory-api/features/filtering.mdx +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: "Filtering" -description: "Learn how to filter content while searching from supermemory" -icon: "list-filter-plus" ---- - -## Container Tag - -Container tag is an identifier for your end users, to group memories together.. - -This can be: -- A user using your product -- An organization using a SaaS - -A project ID, or even a dynamic one like `user_project_etc` - -We recommend using single containerTag in all API requests. - -The graph is built on top of the Container Tags. For example, each user / tag in your supermemory account will have one single graph built for them. - - - -```bash cURL -curl https://api.supermemory.ai/v3/search \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --data '{ - "q": "machine learning", - "containerTags": ["user_123"] - }' -``` - -```typescript Typescript -await client.search.execute({ - q: "machine learning", - containerTags: ["user_123"], -}); -``` - -```python Python -client.search.execute( - q="machine learning", - containerTags=["user_123"] -) -``` - - - -## Metadata - -Sometimes, you might want to add metadata and do advanced filtering based on it. - -Using metadata filtering, you can search based on: - -- AND and OR conditions -- String matching -- Numeric matching -- Date matching -- Time range queries - -### Validation Rules & Limits - -To ensure optimal performance and security, the filtering system has the following limits: - -- **Metadata keys**: Must contain only alphanumeric characters, underscores, and hyphens (`/^[a-zA-Z0-9_-]+$/`) -- **Metadata key length**: Maximum of 64 characters -- **Maximum conditions**: Up to 200 conditions per query -- **Maximum nesting depth**: Up to 8 levels of nested AND/OR expressions -- **Valid operators**: `=`, `!=`, `<`, `<=`, `>`, `>=` for numeric filtering - - -These limits help prevent overly complex queries that could impact performance. If you need to filter on more conditions, consider breaking your query into multiple requests or using broader search terms with post-processing. - - - - -```bash cURL -curl https://api.supermemory.ai/v3/search \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --data '{ - "q": "machine learning", - "filters": { - "AND": [ - { - "key": "category", - "value": "technology", - "negate": false - }, - { - "filterType": "numeric", - "key": "readingTime", - "value": "5", - "negate": false, - "numericOperator": "<=" - } - ] - } -}' -``` - -```typescript Typescript -await client.search.execute({ - q: "machine learning", - filters: { - AND: [ - { - key: "category", - value: "technology", - negate: false, - }, - { - filterType: "numeric", - key: "readingTime", - value: "5", - negate: false, - numericOperator: "<=", - }, - ], - }, -}); -``` - -```python Python -client.search.execute( - q="machine learning", - filters={ - "AND": [ - { - "key": "category", - "value": "technology", - "negate": false - }, - { - "filterType": "numeric", - "key": "readingTime", - "value": "5", - "negate": false, - "numericOperator": "<=" - } - ] - } -) -``` - - - -## Array Contains Filtering - -You can filter memories by array values using the `array_contains` filter type. This is particularly useful for filtering by participants or other array-based metadata. - -First, create a memory with participants in the metadata: - - - -```bash cURL -curl --location 'https://api.supermemory.ai/v3/documents' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ ---data '{ - "content": "quarterly planning meeting discussion", - "metadata": { - "participants": ["john.doe", "sarah.smith", "mike.wilson"] - } - }' -``` - -```typescript Typescript -await client.documents.create({ - content: "quarterly planning meeting discussion", - metadata: { - participants: ["john.doe", "sarah.smith", "mike.wilson"] - } -}); -``` - -```python Python -client.documents.create( - content="quarterly planning meeting discussion", - metadata={ - "participants": ["john.doe", "sarah.smith", "mike.wilson"] - } -) -``` - - - -Then search using the `array_contains` filter: - - - -```bash cURL -curl --location 'https://api.supermemory.ai/v3/search' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ ---data '{ - "q": "meeting", - "filters": { - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains" - } - ] - }, - "limit": 5 - }' -``` - -```typescript Typescript -await client.search.execute({ - q: "meeting", - filters: { - AND: [ - { - key: "participants", - value: "john.doe", - filterType: "array_contains" - } - ] - }, - limit: 5 -}); -``` - -```python Python -client.search.execute( - q="meeting", - filters={ - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains" - } - ] - }, - limit=5 -) -``` - - - -## Migration Notes - - -**Breaking Changes**: Recent updates to the filtering system have introduced stricter validation rules. If you're experiencing filter validation errors, please check the following: - -1. **Metadata Key Format**: Ensure all metadata keys only contain alphanumeric characters, underscores, and hyphens. Keys with spaces, dots, or other special characters will now fail validation. - -2. **Key Length**: Metadata keys must be 64 characters or fewer. - -3. **Filter Complexity**: Queries with more than 200 conditions or more than 8 levels of nesting will be rejected. - -**Example of invalid keys that need updating**: -- `"user.email"` → `"user_email"` -- `"reading time"` → `"reading_time"` -- `"category-with-very-long-name-that-exceeds-the-limit"` → `"category_name"` - - -## Document - -You can also find chunks within a specific, large document. - -This can be particularly useful for extremely large documents like Books, Podcasts, etc. - - - -```bash cURL -curl https://api.supermemory.ai/v3/search \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --data '{ - "q": "machine learning", - "docId": "doc_123" - }' -``` - -```typescript Typescript -await client.search.execute({ - q: "machine learning", - docId: "doc_123", -}); -``` - -```python Python -client.search.execute( - q="machine learning", - docId="doc_123" -) -``` - - diff --git a/apps/docs/memory-api/features/query-rewriting.mdx b/apps/docs/memory-api/features/query-rewriting.mdx deleted file mode 100644 index 9508297a..00000000 --- a/apps/docs/memory-api/features/query-rewriting.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "Query Rewriting" -description: "Query Rewriting in supermemory" -icon: "blend" ---- - -Query Rewriting is a feature that allows you to rewrite queries to make them more accurate. - -![Query Rewriting](/images/query-rewriting.png) - -### Usage - -In supermemory, you can enable query rewriting by setting the `rewriteQuery` parameter to `true` in the search API. - - - -```bash cURL -curl https://api.supermemory.ai/v3/search \ - --request POST \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --header 'Content-Type: application/json' \ - -d '{ - "q": "What is the capital of France?", - "rewriteQuery": true - }' -``` - -```typescript -await client.search.create({ - q: "What is the capital of France?", - rewriteQuery: true, -}); -``` - -```python -client.search.create( - q="What is the capital of France?", - rewriteQuery=True -) -``` - - - -### Notes and limitations - -- supermemory generates multiple rewrites, and runs the search through all of them. -- The results are then merged and returned to you. -- There is no additional costs associated with query rewriting. -- While query rewriting makes the quality much better, it also **incurs additional latency**. -- All other features like filtering, hybrid search, recency bias, etc. work with rewritten results as well. diff --git a/apps/docs/memory-api/features/reranking.mdx b/apps/docs/memory-api/features/reranking.mdx deleted file mode 100644 index 1df8a9c5..00000000 --- a/apps/docs/memory-api/features/reranking.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: "Reranking" -description: "Reranked search results in supermemory" -icon: "chart-bar-increasing" ---- - -Reranking is a feature that allows you to rerank search results based on the query. - -![Reranking](/images/rerank.png) - -### Usage - -In supermemory, you can enable answer rewriting by setting the `rerank` parameter to `true` in the search API. - - - -```bash cURL -curl https://api.supermemory.ai/v3/search?q=What+is+the+capital+of+France?&rerank=true \ - --request GET \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' -``` - -```typescript -await client.search.create({ - q: "What is the capital of France?", - rerank: true, -}); -``` - -```python -client.search.create( - q="What is the capital of France?", - rerank=True -) -``` - - - -### Notes and limitations - -- We currently use `bge-reranker-base` model for reranking. -- There is no additional costs associated with reranking. -- While reranking makes the quality much better, it also **incurs additional latency**. -- All other features like filtering, hybrid search, recency bias, etc. work with reranked results as well. diff --git a/apps/docs/memory-api/ingesting.mdx b/apps/docs/memory-api/ingesting.mdx deleted file mode 100644 index fcf101a5..00000000 --- a/apps/docs/memory-api/ingesting.mdx +++ /dev/null @@ -1,860 +0,0 @@ ---- -title: "Ingest Documents and Data" -sidebarTitle: "Ingesting content guide" -description: "Complete guide to ingesting text, URLs, files, and various content types into Supermemory" ---- - -Supermemory provides a powerful and flexible ingestion system that can process virtually any type of content. Whether you're adding simple text notes, web pages, PDFs, images, or complex documents from various platforms, our API handles it all seamlessly. - -## Understanding the Mental Model - -Before diving into the API, it's important to understand how Supermemory processes your content: - -### Documents vs Memories - -- **Documents**: Anything you put into Supermemory (files, URLs, text) is considered a **document** -- **Memories**: Documents are automatically chunked into smaller, searchable pieces called **memories** - -When you use the "Add Memory" endpoint, you're actually adding a **document**. Supermemory's job is to intelligently break that document into optimal **memories** that can be searched and retrieved. - -``` -Your Content → Document → Processing → Multiple Memories - ↓ ↓ ↓ ↓ - PDF File → Stored Doc → Chunking → Searchable Memories -``` - -You can visualize this process in the [Supermemory Console](https://console.supermemory.ai) where you'll see a graph view showing how your documents are broken down into interconnected memories. - -### Content Sources - -Supermemory accepts content through three main methods: - -1. **Direct API**: Upload files or send content via API endpoints -2. **Connectors**: Automated integrations with platforms like Google Drive, Notion, and OneDrive ([learn more about connectors](/connectors)) -3. **URL Processing**: Automatic extraction from web pages, videos, and social media - -## Overview - -The ingestion system consists of several key components: - -- **Multiple Input Methods**: JSON content, file uploads, and URL processing -- **Asynchronous Processing**: Background workflows handle content extraction and chunking -- **Auto Content Detection**: Automatically identifies and processes different content types -- **Space Organization**: Container tags group related memories for better context inference -- **Status Tracking**: Real-time status updates throughout the processing pipeline - -### How It Works - - - - Send your content (text, file, or URL) to create a new document - - - API validates the request and checks rate limits/quotas - - - Your content is stored as a document and queued for processing - - - Specialized extractors process the document based on its type - - - Document is intelligently chunked into multiple searchable memories - - - Memories are converted to vector embeddings and made searchable - - - -## Ingestion Endpoints - -### Add Document - JSON Content - -The primary endpoint for adding content that will be processed into documents. - -**Endpoint:** `POST /v3/documents` - - -Despite the endpoint name, you're creating a **document** that Supermemory will automatically chunk into searchable **memories**. - - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "Machine learning is a subset of artificial intelligence that enables computers to learn and make decisions from data without explicit programming.", - "containerTags": ["ai-research", "user_123"], - "metadata": { - "source": "research-notes", - "category": "education", - "priority": "high" - }, - "customId": "ml-basics-001" - }' -``` - -```typescript TypeScript -import Supermemory from 'supermemory' - -const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY -}) - -async function addContent() { - const result = await client.add({ - content: "Machine learning is a subset of artificial intelligence...", - containerTags: ["ai-research"], - metadata: { - source: "research-notes", - category: "education", - priority: "high" - }, - customId: "ml-basics-001" - }) - - console.log(result) // { id: "abc123", status: "queued" } -} - - addContent() -``` - -```python Python -from supermemory import Supermemory -import os - -client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - -result = client.add( - content="Machine learning is a subset of artificial intelligence...", - container_tags=["ai-research"], - metadata={ - "source": "research-notes", - "category": "education", - "priority": "high" - }, - custom_id="ml-basics-001" -) - -print(result) # { "id": "abc123", "status": "queued" } -``` - - - -#### Request Parameters - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `content` | string | Yes | The content to process into a document. Can be text, URL, or other supported formats | -| `containerTag` | string | No | **Recommended**: Single tag to group related memories in a space. Defaults to `"sm_project_default"` | -| `containerTags` | string[] | No | Legacy array format. Use `containerTag` instead for better performance | -| `metadata` | object | No | Additional key-value metadata (strings, numbers, booleans only) | -| `customId` | string | No | Your own identifier for this document (max 255 characters) | -| `raw` | string | No | Raw content to store alongside processed content | - -#### Response - -When you successfully create a document, you'll get back a simple confirmation with the document ID and its initial processing status: - -```json -{ - "id": "D2Ar7Vo7ub83w3PRPZcaP1", - "status": "queued" -} -``` - -**What this means:** -- `id`: Your document's unique identifier - save this to track processing or reference later -- `status`: Current processing state. `"queued"` means it's waiting to be processed into memories - - -The document starts processing immediately in the background. Within seconds to minutes (depending on content size), it will be chunked into searchable memories. - - -### File Upload: Drop and Process - -Got a PDF, image, or video? Upload it directly and let Supermemory extract the valuable content automatically. - -**Endpoint:** `POST /v3/documents/file` - -**What makes this powerful:** Instead of manually copying text from PDFs or transcribing videos, just upload the file. Supermemory handles OCR for images, transcription for videos, and intelligent text extraction for documents. - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents/file \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -F "file=@document.pdf" \ - -F "containerTags=research_project" - -# Response: -# { -# "id": "Mx7fK9pL2qR5tE8yU4nC7", -# "status": "processing" -# } -``` - -```typescript TypeScript -import Supermemory from 'supermemory' -import fs from 'fs' - -const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY -}) - -// Method 1: Using SDK uploadFile method (RECOMMENDED) -const result = await client.documents.uploadFile({ - file: fs.createReadStream('/path/to/document.pdf'), - containerTags: 'research_project' // String, not array! -}) - -// Method 2: Using fetch with form data (for browser/manual implementation) -const formData = new FormData() -formData.append('file', fileInput.files[0]) -formData.append('containerTags', 'research_project') - -const response = await fetch('https://api.supermemory.ai/v3/documents/file', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}` - }, - body: formData -}) - -const result = await response.json() -console.log(result) -// Output: { id: "Mx7fK9pL2qR5tE8yU4nC7", status: "processing" } -``` - -```python Python -from supermemory import Supermemory - -client = Supermemory(api_key="your_api_key") - -# Method 1: Using SDK upload_file method (RECOMMENDED) -result = client.documents.upload_file( - file=open('document.pdf', 'rb'), - container_tags='research_project' # String parameter name -) - -# Method 2: Using requests with form data -import requests - -files = {'file': open('document.pdf', 'rb')} -data = {'containerTags': 'research_project'} - -response = requests.post( - 'https://api.supermemory.ai/v3/documents/file', - headers={'Authorization': f'Bearer {api_key}'}, - files=files, - data=data -) - -result = response.json() -print(result) -# Output: {'id': 'Mx7fK9pL2qR5tE8yU4nC7', 'status': 'processing'} -``` - - - -#### Supported File Types - - - - - **PDF**: Extracted with OCR support for scanned documents - - **Google Docs**: Via Google Drive API integration - - **Google Sheets**: Spreadsheet content extraction - - **Google Slides**: Presentation content extraction - - **Notion Pages**: Rich content with block structure preservation - - **OneDrive Documents**: Microsoft Office documents - - - - - **Images**: JPG, PNG, GIF, WebP with OCR text extraction - - **Videos**: MP4, WebM, AVI with transcription (YouTube, Vimeo) - - - - - **Web Pages**: Any public URL with intelligent content extraction - - **Twitter/X Posts**: Tweet content and metadata - - **YouTube Videos**: Automatic transcription and metadata - - - - - **Plain Text**: TXT, MD, CSV files - - - -## Content Types & Processing - -### Automatic Detection - -Supermemory automatically detects content types based on: - -- **URL patterns**: Domain and path analysis for special services -- **MIME types**: File type detection from headers/metadata -- **Content analysis**: Structure and format inspection -- **File extensions**: Fallback identification method - -```typescript - -type MemoryType = - | 'text' // Plain text content - | 'pdf' // PDF documents - | 'tweet' // Twitter/X posts - | 'google_doc' // Google Docs - | 'google_slide'// Google Slides - | 'google_sheet'// Google Sheets - | 'image' // Images with OCR - | 'video' // Videos with transcription - | 'notion_doc' // Notion pages - | 'webpage' // Web pages - | 'onedrive' // OneDrive documents - - - -// Examples of automatic detection -const examples = { - "https://twitter.com/user/status/123": "tweet", - "https://youtube.com/watch?v=abc": "video", - "https://docs.google.com/document/d/123": "google_doc", - "https://docs.google.com/spreadsheets/d/123": "google_sheet", - "https://docs.google.com/presentation/d/123": "google_slide", - "https://notion.so/page-123": "notion_doc", - "https://example.com": "webpage", - "Regular text content": "text", - // PDF files uploaded → "pdf" - // Image files uploaded → "image" - // OneDrive links → "onedrive" -} -``` - -### Processing Pipeline - -Each content type follows a specialized processing pipeline: - - -Content is cleaned, normalized, and chunked for optimal retrieval: - -1. **Queued**: Memory enters the processing queue -2. **Extracting**: Text normalization and cleaning -3. **Chunking**: Intelligent splitting based on content structure -4. **Embedding**: Convert to vector representations for search -5. **Indexing**: Add to searchable index -6. **Done:** Metadata extraction completed - - - -Web pages undergo sophisticated content extraction: - -1. **Queued:** URL queued for processing -2. **Extracting**: Fetch page content with proper headers, remove navigation and boilerplate, extract title, description, etc. -3. **Chunking:** Content split for optimal retrieval -4. **Embedding**: Vector representation generation -5. **Indexing**: Add to search index -6. **Done:** Processing complete with `type: 'webpage'` - - - -Files are processed through specialized extractors: - -1. **Queued**: File queued for processing -2. **Content Extraction**: Type detection and format-specific processing. -3. **OCR/Transcription**: For images and media files -4. **Chunking:** Content broken down into searchable segments -5. **Embedding:** Vector representation creation -6. **Indexing:** Add to search index -7. **Done:** Processing completed - - -## Error Handling - -### Common Errors - -Scroll right to see more. - - - - ```json - // AuthenticationError class - { - name: "AuthenticationError", - status: 401, - message: "401 Unauthorized", - error: { - message: "Invalid API key", - type: "authentication_error" - } - } - ``` - **Causes:** - - Missing or invalid API key - - Expired authentication token - - Incorrect authorization header format - - - - ```json - // BadRequestError class - { - name: "BadRequestError", - status: 400, - message: "400 Bad Request", - error: { - message: "Invalid request parameters", - details: { - content: "Content cannot be empty", - customId: "customId exceeds maximum length" - } - } - } - ``` - **Causes:** - - Missing required fields - - Invalid parameter types - - Content too large - - Custom ID too long - - Invalid metadata structure - - - - ```json - // RateLimitError class - { - name: "RateLimitError", - status: 429, // NOT 402! - message: "429 Too Many Requests", - error: { - message: "Rate limit exceeded", - retry_after: 60 - } - } - ``` - **Causes:** - - Monthly token quota exceeded - - Rate limits exceeded - - Subscription limits reached - - **Fix:** Implement exponential backoff and respect rate limits - - - ```json - // NotFoundError class - { - name: "NotFoundError", - status: 404, - message: "404 Not Found", - error: { - message: "Memory not found", - resource_id: "invalid_memory_id" - } - } - ``` - Causes: - - Memory ID doesn't exist - - Memory was deleted - - Invalid endpoint URL - - - - ```json - // PermissionDeniedError class - { - name: "PermissionDeniedError", - status: 403, - message: "403 Forbidden", - error: { - message: "Insufficient permissions", - required_permission: "memories:write" - } - } - ``` - - Causes: - - API key lacks required permissions - - Accessing restricted resources - - Account limitations - - - - ```json - // InternalServerError class - { - name: "InternalServerError", - status: 500, - message: "500 Internal Server Error", - error: { - message: "Processing failed", - details: "Content extraction service unavailable" - } - } - ``` - **Causes:** - - External service unavailable - - Content extraction failure - - - ```json - // APIConnectionError class - NEW - { - name: "APIConnectionError", - message: "Connection error.", - cause: Error // Original network error - } - - // APIConnectionTimeoutError class - NEW - { - name: "APIConnectionTimeoutError", - message: "Request timed out." - } - ``` - - Causes: - - Network connectivity issues - - DNS resolution failures - - Request timeouts - - Proxy/firewall blocking - - - - -## Best Practices - -### Container Tags: Optimize for Performance - -Use single container tags for better query performance. Multiple tags are supported but increase latency. - -```json -{ - "content": "Updated authentication flow to use JWT tokens", - "containerTags": "[project_alpha]", - "metadata": { - "type": "technical_change", - "author": "sarah_dev", - "impact": "breaking" - } -} -``` - -**Single vs Multiple Tags** - -```javascript -// ✅ Recommended: Single tag, faster queries -{ "containerTags": ["project_alpha"] } - -// ⚠️ Allowed but slower: Multiple tags increase latency -{ "containerTags": ["project_alpha", "auth", "backend"] } -``` - -**Why single tags perform better:** -- Memories in the same space can reference each other efficiently -- Search queries don't need to traverse multiple spaces -- Connection inference is faster within a single space - - -### Custom IDs: Deduplication and Updates - -Custom IDs prevent duplicates and enable document updates. Two update methods available. - -**Method 1: POST with customId (Upsert)** -```bash -# Create document -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "API uses REST endpoints", - "customId": "api_docs_v1", - "containerTags": ["project_alpha"] - }' -# Response: {"id": "abc123", "status": "queued"} - -# Update same document (same customId = upsert) -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "API migrated to GraphQL", - "customId": "api_docs_v1", - "containerTags": ["project_alpha"] - }' -``` - -**Method 2: PATCH by ID (Update)** -```bash -curl -X PATCH "https://api.supermemory.ai/v3/documents/abc123" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "API now uses GraphQL with caching", - "metadata": {"version": 3} - }' -``` - -**Custom ID Patterns** - -```javascript -// External system sync -"jira_PROJ_123" -"confluence_456789" -"github_issue_987" - -// Database entities -"user_profile_12345" -"order_67890" - -// Versioned content -"meeting_2024_01_15" -"api_docs_auth" -"requirements_v3" -``` - -**Update Behavior** -- **Content changes:** Old memories are deleted, new memories created from updated content. Same document ID maintained. -- **Metadata-only changes:** Document metadata is updated in place. No reindexing—works with both internal `id` and `customId`. - -### Rate Limits & Quotas - -**Token Usage** -```javascript -"Hello world" // ≈ 2 tokens -"10-page PDF" // ≈ 2,000-4,000 tokens -"YouTube video (10 min)" // ≈ 1,500-3,000 tokens -"Web article" // ≈ 500-2,000 tokens -``` - -**Current Limits** - -| Feature | Free | Starter | Growth | -|---------|------|-----|------------| -| Memory Tokens/month | 100,000 | 1,000,000 | 10,000,000 | -| Search Queries/month | 1,000 | 10,000 | 100,000 | - -**Limit Exceeded Response** -```bash -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer your_api_key" \ - -d '{"content": "Some content"}' -``` - -Response: -```json -{"error": "Memory token limit reached", "status": 402} -``` - -## Batch Upload of Documents - -Process large volumes efficiently with rate limiting and error recovery. - -### Implementation Strategy - - - - ```typescript - import Supermemory, { - BadRequestError, - RateLimitError, - AuthenticationError - } from 'supermemory'; - - interface Document { - id: string; - content: string; - title?: string; - createdAt?: string; - metadata?: Record; - } - - async function batchIngest(documents: Document[], options = {}) { - const { - batchSize = 5, - delayBetweenBatches = 2000, - maxRetries = 3 - } = options; - - const results = []; - - for (let i = 0; i < documents.length; i += batchSize) { - const batch = documents.slice(i, i + batchSize); - console.log(`Processing batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(documents.length/batchSize)}`); - - const batchResults = await Promise.allSettled( - batch.map(doc => ingestWithRetry(doc, maxRetries)) - ); - - results.push(...batchResults); - - // Rate limiting between batches - if (i + batchSize < documents.length) { - await new Promise(resolve => setTimeout(resolve, delayBetweenBatches)); - } - } - - return results; - } - - async function ingestWithRetry(doc: Document, maxRetries: number) { - for (let attempt = 1; attempt <= maxRetries; attempt++) { - try { - return await client.add({ - content: doc.content, - customId: doc.id, - containerTags: ["batch_import_user_123"], // CORRECTED: Array - metadata: { - source: "migration", - batch_id: generateBatchId(), - original_created: doc.createdAt || new Date().toISOString(), - title: doc.title || "", - ...doc.metadata - } - }); - } catch (error) { - // CORRECTED: Proper error handling - if (error instanceof AuthenticationError) { - console.error('Authentication failed - check API key'); - throw error; // Don't retry auth errors - } - - if (error instanceof BadRequestError) { - console.error('Invalid document format:', doc.id); - throw error; // Don't retry validation errors - } - - if (error instanceof RateLimitError) { - console.log(`Rate limited on attempt ${attempt}, waiting longer...`); - const delay = Math.pow(2, attempt) * 2000; // Longer delays for rate limits - await new Promise(resolve => setTimeout(resolve, delay)); - continue; - } - - if (attempt === maxRetries) throw error; - - // Exponential backoff for other errors - const delay = Math.pow(2, attempt) * 1000; - console.log(`Retry ${attempt}/${maxRetries} for ${doc.id} in ${delay}ms`); - await new Promise(resolve => setTimeout(resolve, delay)); - } - } - } - - function generateBatchId(): string { - return `batch_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; - } - ``` - - - - ```python - import asyncio - import time - import logging - from typing import List, Dict, Any, Optional - from supermemory import Supermemory, BadRequestError, RateLimitError - - async def batch_ingest( - documents: List[Dict[str, Any]], - options: Optional[Dict[str, Any]] = None - ): - options = options or {} - batch_size = options.get('batch_size', 5) # CORRECTED: Conservative size - delay_between_batches = options.get('delay_between_batches', 2.0) # CORRECTED: 2 seconds - max_retries = options.get('max_retries', 3) - - results = [] - - for i in range(0, len(documents), batch_size): - batch = documents[i:i + batch_size] - batch_num = i // batch_size + 1 - total_batches = (len(documents) + batch_size - 1) // batch_size - - print(f"Processing batch {batch_num}/{total_batches}") - - # Process batch with proper error handling - tasks = [ingest_with_retry(doc, max_retries) for doc in batch] - batch_results = await asyncio.gather(*tasks, return_exceptions=True) - - results.extend(batch_results) - - # Rate limiting between batches - if i + batch_size < len(documents): - await asyncio.sleep(delay_between_batches) - - return results - - async def ingest_with_retry(doc: Dict[str, Any], max_retries: int): - for attempt in range(1, max_retries + 1): - try: - return await client.add( - content=doc['content'], - custom_id=doc['id'], - container_tags=["batch_import_user_123"], # CORRECTED: List - metadata={ - "source": "migration", - "batch_id": generate_batch_id(), - "original_created": doc.get('created_at', ''), - "title": doc.get('title', ''), - **doc.get('metadata', {}) - } - ) - except BadRequestError as e: - logging.error(f"Invalid document {doc['id']}: {e}") - raise # Don't retry validation errors - - except RateLimitError as e: - logging.warning(f"Rate limited on attempt {attempt}") - delay = 2 ** attempt * 2 # Longer delays for rate limits - await asyncio.sleep(delay) - continue - - except Exception as error: - if attempt == max_retries: - raise error - - # Exponential backoff - delay = 2 ** attempt - logging.info(f"Retry {attempt}/{max_retries} for {doc['id']} in {delay}s") - await asyncio.sleep(delay) - - def generate_batch_id() -> str: - import random - import string - return f"batch_{int(time.time())}_{random.choices(string.ascii_lowercase, k=8)}" - ``` - - - -### Best Practices for Batch Operations - - -- **Batch Size**: 3-5 documents at once -- **Delays**: 2-3 seconds between batches prevents rate limiting -- **Promise.allSettled()**: Handles mixed success/failure results -- **Progress Tracking**: Monitor long-running operations - -**Sample Output** -``` -Processing batch 1/50 (documents 1-3) -Successfully processed: 2/3 documents -Failed: 1/3 documents (BadRequestError: Invalid content) -Progress: 3/150 (2.0%) - Next batch in 2s -``` - - - -- **Specific Error Types:** Handle `BadRequestError`, `RateLimitError`, `AuthenticationError` differently -- **No Retry Logic**: Don't retry validation or auth errors -- **Rate Limit Handling**: Longer backoff delays for rate limit errors -- **Logging**: Record failures for review/retry - - - -- **Streaming**: Process large files in chunks -- **Cleanup**: Clear processed batches from memory -- **Progress Persistence**: Resume interrupted migrations - - - -Ready to start ingesting? [Get an API key](https://console.supermemory.ai) now! - diff --git a/apps/docs/memory-api/introduction.mdx b/apps/docs/memory-api/introduction.mdx deleted file mode 100644 index 24a46f8b..00000000 --- a/apps/docs/memory-api/introduction.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Introduction - Memory endpoints" -sidebarTitle: "Introduction" -description: "Ingest content at scale, in any format." ---- - -**supermemory** automatically **ingests and processes your data**, and makes it searchable. - - - The Memory engine scales linearly - which means we're **incredibly fast and scalable**, while providing one of the more affordable - - -![supermemory](/images/processing.png) - -It also gives you features like: - -- [Connectors and Syncing](/memory-api/connectors/) -- [Multimodality](/memory-api/features/auto-multi-modal) -- [Advanced Filtering](/memory-api/features/filtering) -- [Reranking](/memory-api/features/reranking) -- [Extracting details from text](/memory-api/features/content-cleaner) -- [Query Rewriting](/memory-api/features/query-rewriting) - -... and lots more\! - - -Check out the following resources to get started: - - - - - Get started in 5 minutes - - - Learn more about the API - - - See what supermemory can do for you - - - Learn more about the SDKs - - \ No newline at end of file diff --git a/apps/docs/memory-api/overview.mdx b/apps/docs/memory-api/overview.mdx deleted file mode 100644 index 79ba8757..00000000 --- a/apps/docs/memory-api/overview.mdx +++ /dev/null @@ -1,162 +0,0 @@ ---- -title: "Quickstart - 5 mins" -description: "Learn how to integrate supermemory into your application" ---- - -## Authentication - -Head to [supermemory's Developer Platform](https://console.supermemory.ai) built to help you monitor and manage every aspect of the API. - -All API requests require authentication using an API key. Include your API key as follows: - - - -```bash cURL -Authorization: Bearer YOUR_API_KEY -``` - -```typescript Typescript -// npm install supermemory - -const client = new supermemory({ - apiKey: "YOUR_API_KEY", -}); -``` - -```python Python -# pip install supermemory - -client = supermemory( - api_key="YOUR_API_KEY", -) -``` - - - -## Installing the clients - -You can use supermemory through the APIs, or using our SDKs - - - -```bash cURL -https://api.supermemory.ai/v3 -``` - -```bash Typescript -npm i supermemory -``` - -```bash Python -pip install supermemory -``` - - - -## Add your first memory - - - -```bash cURL -curl https://api.supermemory.ai/v3/documents \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - -d '{"content": "This is the content of my first memory."}' -``` - -```typescript Typescript -await client.memory.add({ - content: "This is the content of my first memory.", -}); -``` - -```python Python -client.memory.add( - content="This is the content of my first memory.", -) -``` - - - -This will add a new memory to your supermemory account. - -Try it out in the API Reference tab. - -## Content Processing - - - When you add content to supermemory, it goes through several processing steps: - - 1. **Queued**: Initial state when content is submitted - 2. **Extracting**: Content is being extracted from the source - 3. **Chunking**: Content is being split into semantic chunks - 4. **Embedding**: Generating vector embeddings for search - 5. **Indexing**: Adding content to the search index - 6. **Done**: Processing complete - - - - The system uses advanced NLP techniques for optimal chunking: - - - Sentence-level splitting for natural boundaries - - Context preservation with overlapping chunks - - Smart handling of long content - - Semantic coherence optimization - - - -## Search your memories - - - -```bash cURL -curl https://api.supermemory.ai/v3/search \ - --request POST \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - -d '{"q": "This is the content of my first memory."}' -``` - -```typescript Typescript -await client.search.execute({ - q: "This is the content of my first memory.", -}); -``` - -```python Python -client.search.execute( - q="This is the content of my first memory.", -) -``` - - - -Try it out in the API Reference tab. - -You can do a lot more with supermemory, and we will walk through everything you need to. - -Next, explore the features available in supermemory - - - - Adding memories - - - Searching for items - - - Connecting external sources - - - Explore Features - - diff --git a/apps/docs/memory-api/sdks/anthropic-claude-memory.mdx b/apps/docs/memory-api/sdks/anthropic-claude-memory.mdx deleted file mode 100644 index 10bc195b..00000000 --- a/apps/docs/memory-api/sdks/anthropic-claude-memory.mdx +++ /dev/null @@ -1,375 +0,0 @@ ---- -title: "Claude Memory Tool" -description: "Enable Claude's persistent memory capabilities with Supermemory as the backend" ---- - -Enable Claude's native memory tool functionality with Supermemory as the persistent storage backend. Claude can automatically store and retrieve information across conversations using familiar filesystem operations. - - - Check out the NPM page for more details - - -## Installation - -```bash -npm install @supermemory/tools @anthropic-ai/sdk -``` - -## Quick Start - -```typescript -import Anthropic from "@anthropic-ai/sdk" -import { createClaudeMemoryTool } from "@supermemory/tools/claude-memory" - -const anthropic = new Anthropic({ - apiKey: process.env.ANTHROPIC_API_KEY!, -}) - -const memoryTool = createClaudeMemoryTool(process.env.SUPERMEMORY_API_KEY!, { - projectId: 'my-app', -}) - -async function chatWithMemory(userMessage: string) { - const response = await anthropic.beta.messages.create({ - model: 'claude-sonnet-4-5', - max_tokens: 8096, - tools: [{ type: 'memory_20250818', name: 'memory' }], - betas: ['context-management-2025-06-27'], - messages: [{ role: 'user', content: userMessage }], - }) - - // Handle memory tool calls - for (const block of response.content) { - if (block.type === 'tool_use' && block.name === 'memory') { - const result = await memoryTool.handleCommandForToolResult( - block.input as MemoryCommand, - block.id - ) - console.log('Memory operation result:', result) - } - } - - return response -} -``` - -## How It Works - -Claude's memory tool uses a filesystem metaphor to manage persistent information: - -- **Files**: Individual memory items stored as Supermemory documents -- **Directories**: Organized using path structure (e.g., `/memories/user-preferences`) -- **Operations**: View, create, edit, delete, and rename files -- **Path Normalization**: Paths like `/memories/preferences` are stored as `--memories--preferences` - -## Configuration - -### Basic Configuration - -```typescript -import { createClaudeMemoryTool } from "@supermemory/tools/claude-memory" - -const memoryTool = createClaudeMemoryTool( - process.env.SUPERMEMORY_API_KEY!, - { - projectId: 'my-app', // Project identifier - baseUrl: 'https://api.supermemory.ai', // Optional: custom API endpoint - } -) -``` - -### Using Container Tags - -```typescript -const memoryTool = createClaudeMemoryTool( - process.env.SUPERMEMORY_API_KEY!, - { - containerTags: ['user:alice', 'app:chat'], - } -) -``` - -## Memory Operations - -Claude automatically performs these operations when managing memory: - -### View Files - -List directory contents or read file contents: - -```typescript -// Claude will automatically check /memories/ directory -// This maps to searching Supermemory documents with path prefix -``` - -### Create Files - -Store new information: - -```typescript -// Claude creates: /memories/user-preferences.txt -// Stored as document with customId: "--memories--user-preferences.txt" -``` - -### Edit Files - -Update existing memories using string replacement: - -```typescript -// Claude performs str_replace on file contents -// Updates the corresponding Supermemory document -``` - -### Delete Files - -Remove information: - -```typescript -// Claude deletes: /memories/old-data.txt -// Removes document from Supermemory -``` - -### Rename Files - -Reorganize memory structure: - -```typescript -// Claude renames: /memories/temp.txt -> /memories/final.txt -// Updates document customId in Supermemory -``` - -## Complete Chat Example - -Here's a full example with conversation handling: - -```typescript -import Anthropic from "@anthropic-ai/sdk" -import { createClaudeMemoryTool, type MemoryCommand } from "@supermemory/tools/claude-memory" - -const anthropic = new Anthropic({ - apiKey: process.env.ANTHROPIC_API_KEY!, -}) - -const memoryTool = createClaudeMemoryTool(process.env.SUPERMEMORY_API_KEY!, { - projectId: 'chat-app', -}) - -async function chat() { - const messages: Anthropic.MessageParam[] = [] - - // First message: store information - messages.push({ - role: 'user', - content: 'Remember that I prefer dark mode and use TypeScript' - }) - - let response = await anthropic.beta.messages.create({ - model: 'claude-sonnet-4-5', - max_tokens: 8096, - tools: [{ type: 'memory_20250818', name: 'memory' }], - betas: ['context-management-2025-06-27'], - messages, - }) - - // Process tool calls - const toolResults: Anthropic.ToolResultBlockParam[] = [] - - for (const block of response.content) { - if (block.type === 'tool_use' && block.name === 'memory') { - const result = await memoryTool.handleCommandForToolResult( - block.input as MemoryCommand, - block.id - ) - toolResults.push(result) - } - } - - // Continue conversation with tool results - if (toolResults.length > 0) { - messages.push({ role: 'assistant', content: response.content }) - messages.push({ role: 'user', content: toolResults }) - - response = await anthropic.beta.messages.create({ - model: 'claude-sonnet-4-5', - max_tokens: 8096, - tools: [{ type: 'memory_20250818', name: 'memory' }], - betas: ['context-management-2025-06-27'], - messages, - }) - } - - console.log(response.content) -} - -chat() -``` - -## Advanced Usage - -### Custom Path Management - -Control where Claude stores information: - -```typescript -// Claude automatically organizes by path -// /memories/preferences/editor.txt -// /memories/projects/current.txt -// /memories/notes/meeting-2024.txt - -// Each path is normalized and stored with appropriate metadata -``` - -### Error Handling - -Handle operations gracefully: - -```typescript -const result = await memoryTool.handleCommandForToolResult(command, toolUseId) - -if (result.is_error) { - console.error('Memory operation failed:', result.content) - // Handle error appropriately -} else { - console.log('Success:', result.content) -} -``` - -### Monitoring Operations - -Track memory operations: - -```typescript -for (const block of response.content) { - if (block.type === 'tool_use' && block.name === 'memory') { - console.log('Operation:', block.input.command) - console.log('Path:', block.input.path) - - const result = await memoryTool.handleCommandForToolResult( - block.input as MemoryCommand, - block.id - ) - - console.log('Result:', result.is_error ? 'Failed' : 'Success') - } -} -``` - -## Memory Organization - -### Best Practices - -1. **Use Descriptive Paths**: `/memories/user-preferences/theme.txt` is better than `/mem1.txt` -2. **Organize by Category**: Group related information under directories -3. **Keep Files Focused**: Store specific information in separate files -4. **Use Clear Naming**: Make file names self-explanatory - -### Path Structure Examples - -``` -/memories/ - ├── user-profile/ - │ ├── name.txt - │ ├── preferences.txt - │ └── settings.txt - ├── projects/ - │ ├── current-task.txt - │ └── goals.txt - └── notes/ - ├── meeting-notes.txt - └── ideas.txt -``` - -## API Reference - -### `createClaudeMemoryTool(apiKey, config)` - -Creates a memory tool instance for Claude. - -**Parameters:** -- `apiKey` (string): Your Supermemory API key -- `config` (optional): - - `projectId` (string): Project identifier - - `containerTags` (string[]): Alternative to projectId - - `baseUrl` (string): Custom API endpoint - -**Returns:** `ClaudeMemoryTool` instance - -### `handleCommandForToolResult(command, toolUseId)` - -Processes a memory command and returns formatted result. - -**Parameters:** -- `command` (MemoryCommand): The memory operation from Claude -- `toolUseId` (string): Tool use ID from Claude's response - -**Returns:** `Promise` with: -- `type`: "tool_result" -- `tool_use_id`: The tool use ID -- `content`: Operation result or error message -- `is_error`: Boolean indicating success/failure - -## Memory Commands - -Claude uses these command types internally: - -| Command | Description | Example | -|---------|-------------|---------| -| `view` | List directory or read file | `/memories/` or `/memories/file.txt` | -| `create` | Create new file | Create `/memories/new.txt` with content | -| `str_replace` | Edit file contents | Replace "old text" with "new text" | -| `insert` | Add content at line | Insert at line 5 | -| `delete` | Remove file | Delete `/memories/old.txt` | -| `rename` | Rename/move file | Rename `old.txt` to `new.txt` | - -## Environment Variables - -```bash -ANTHROPIC_API_KEY=your_anthropic_key -SUPERMEMORY_API_KEY=your_supermemory_key -``` - -## When to Use - -The Claude Memory Tool is ideal for: - -- **Conversational AI**: Claude automatically remembers user preferences and context -- **Personal Assistants**: Store and retrieve user-specific information -- **Documentation Bots**: Maintain knowledge across conversations -- **Project Management**: Track tasks and project state -- **Note-Taking Apps**: Persistent memory for meeting notes and ideas - -## Comparison with Other Approaches - -| Feature | Claude Memory Tool | OpenAI SDK Tools | AI SDK Tools | -|---------|-------------------|------------------|--------------| -| Automatic Memory | ✅ Claude decides | ❌ Manual control | ❌ Manual control | -| Filesystem Metaphor | ✅ Files/directories | ❌ Flat storage | ❌ Flat storage | -| Path Organization | ✅ Hierarchical | ❌ Tags only | ❌ Tags only | -| Integration | Anthropic SDK only | OpenAI SDK only | Vercel AI SDK | - -## Limitations - -- Requires Anthropic SDK with beta features enabled -- Path separators (`/`) are normalized to `--` for storage -- Maximum 100 files per directory listing -- File operations are asynchronous - -## Next Steps - - - - Use memory tools with OpenAI function calling - - - - Integrate with Vercel AI SDK - - - - Direct API access for advanced control - - - - See real-world examples - - \ No newline at end of file diff --git a/apps/docs/memory-api/sdks/native.mdx b/apps/docs/memory-api/sdks/native.mdx deleted file mode 100644 index cfc0bd34..00000000 --- a/apps/docs/memory-api/sdks/native.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: 'Supermemory SDKs' -sidebarTitle: "Python and JavaScript SDKs" -description: 'Learn how to use supermemory with Python and JavaScript' ---- - -For more information, see the full updated references at - - - - - - - - - - -## Python SDK - -## Installation - -```sh -# install from PyPI -pip install --pre supermemory -``` - -## Usage - - -```python -import os -from supermemory import Supermemory - -client = Supermemory( - api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted -) - -response = client.search.documents( - q="documents related to python", -) -print(response.results) -``` - -## JavaScript SDK - -## Installation - -```sh -npm install supermemory -``` - -## Usage - -```js -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env['SUPERMEMORY_API_KEY'], // This is the default and can be omitted -}); - -async function main() { - const response = await client.search.documents({ q: 'documents related to python' }); - - console.debug(response.results); -} - -main(); -``` diff --git a/apps/docs/memory-api/sdks/openai-plugins.mdx b/apps/docs/memory-api/sdks/openai-plugins.mdx deleted file mode 100644 index d95dad47..00000000 --- a/apps/docs/memory-api/sdks/openai-plugins.mdx +++ /dev/null @@ -1,584 +0,0 @@ ---- -title: "OpenAI SDK Plugins" -description: "Memory tools for OpenAI function calling with Supermemory integration" ---- - -Add memory capabilities to the official OpenAI SDKs using Supermemory's function calling tools. These plugins provide seamless integration with OpenAI's chat completions and function calling features. - - - - Check out the NPM page for more details - - - Check out the PyPI page for more details - - - -## Installation - - - -```bash Python -# Using uv (recommended) -uv add supermemory-openai-sdk - -# Or with pip -pip install supermemory-openai-sdk -``` - -```bash JavaScript/TypeScript -npm install @supermemory/tools -``` - - - -## Quick Start - - - -```python Python SDK -import asyncio -import openai -from supermemory_openai import SupermemoryTools, execute_memory_tool_calls - -async def main(): - # Initialize OpenAI client - client = openai.AsyncOpenAI(api_key="your-openai-api-key") - - # Initialize Supermemory tools - tools = SupermemoryTools( - api_key="your-supermemory-api-key", - config={"project_id": "my-project"} - ) - - # Chat with memory tools - response = await client.chat.completions.create( - model="gpt-5", - messages=[ - { - "role": "system", - "content": "You are a helpful assistant with access to user memories." - }, - { - "role": "user", - "content": "Remember that I prefer tea over coffee" - } - ], - tools=tools.get_tool_definitions() - ) - - # Handle tool calls if present - if response.choices[0].message.tool_calls: - tool_results = await execute_memory_tool_calls( - api_key="your-supermemory-api-key", - tool_calls=response.choices[0].message.tool_calls, - config={"project_id": "my-project"} - ) - print("Tool results:", tool_results) - - print(response.choices[0].message.content) - -asyncio.run(main()) -``` - -```typescript JavaScript/TypeScript SDK -import { supermemoryTools, getToolDefinitions, createToolCallExecutor } from "@supermemory/tools/openai" -import OpenAI from "openai" - -const client = new OpenAI({ - apiKey: process.env.OPENAI_API_KEY!, -}) - -// Get tool definitions for OpenAI -const toolDefinitions = getToolDefinitions() - -// Create tool executor -const executeToolCall = createToolCallExecutor(process.env.SUPERMEMORY_API_KEY!, { - projectId: "your-project-id", -}) - -// Use with OpenAI Chat Completions -const completion = await client.chat.completions.create({ - model: "gpt-5", - messages: [ - { - role: "user", - content: "What do you remember about my preferences?", - }, - ], - tools: toolDefinitions, -}) - -// Execute tool calls if any -if (completion.choices[0]?.message.tool_calls) { - for (const toolCall of completion.choices[0].message.tool_calls) { - const result = await executeToolCall(toolCall) - console.log(result) - } -} -``` - - - -## Configuration - -### Memory Tools Configuration - - - -```python Python Configuration -from supermemory_openai import SupermemoryTools - -tools = SupermemoryTools( - api_key="your-supermemory-api-key", - config={ - "project_id": "my-project", # or use container_tags - "base_url": "https://custom-endpoint.com", # optional - } -) -``` - -```typescript JavaScript Configuration -import { supermemoryTools } from "@supermemory/tools/openai" - -const tools = supermemoryTools(process.env.SUPERMEMORY_API_KEY!, { - containerTags: ["your-user-id"], - baseUrl: "https://custom-endpoint.com", // optional -}) -``` - - - -## Available Tools - -### Search Memories - -Search through user memories using semantic search: - - - -```python Python -# Search memories -result = await tools.search_memories( - information_to_get="user preferences", - limit=10, - include_full_docs=True -) -print(f"Found {len(result.memories)} memories") -``` - -```typescript JavaScript -// Search memories -const searchResult = await tools.searchMemories({ - informationToGet: "user preferences", - limit: 10, -}) -console.log(`Found ${searchResult.memories.length} memories`) -``` - - - -### Add Memory - -Store new information in memory: - - - -```python Python -# Add memory -result = await tools.add_memory( - memory="User prefers tea over coffee" -) -print(f"Added memory with ID: {result.memory.id}") -``` - -```typescript JavaScript -// Add memory -const addResult = await tools.addMemory({ - memory: "User prefers dark roast coffee", -}) -console.log(`Added memory with ID: ${addResult.memory.id}`) -``` - - - -### Fetch Memory - -Retrieve specific memory by ID: - - - -```python Python -# Fetch specific memory -result = await tools.fetch_memory( - memory_id="memory-id-here" -) -print(f"Memory content: {result.memory.content}") -``` - -```typescript JavaScript -// Fetch specific memory -const fetchResult = await tools.fetchMemory({ - memoryId: "memory-id-here" -}) -console.log(`Memory content: ${fetchResult.memory.content}`) -``` - - - -## Individual Tools - -Use tools separately for more granular control: - - - -```python Python Individual Tools -from supermemory_openai import ( - create_search_memories_tool, - create_add_memory_tool, - create_fetch_memory_tool -) - -search_tool = create_search_memories_tool("your-api-key") -add_tool = create_add_memory_tool("your-api-key") -fetch_tool = create_fetch_memory_tool("your-api-key") - -# Use individual tools in OpenAI function calling -tools_list = [search_tool, add_tool, fetch_tool] -``` - -```typescript JavaScript Individual Tools -import { - createSearchMemoriesTool, - createAddMemoryTool, - createFetchMemoryTool -} from "@supermemory/tools/openai" - -const searchTool = createSearchMemoriesTool(process.env.SUPERMEMORY_API_KEY!) -const addTool = createAddMemoryTool(process.env.SUPERMEMORY_API_KEY!) -const fetchTool = createFetchMemoryTool(process.env.SUPERMEMORY_API_KEY!) - -// Use individual tools -const toolDefinitions = [searchTool, addTool, fetchTool] -``` - - - -## Complete Chat Example - -Here's a complete example showing a multi-turn conversation with memory: - - - -```python Complete Python Example -import asyncio -import openai -from supermemory_openai import SupermemoryTools, execute_memory_tool_calls - -async def chat_with_memory(): - client = openai.AsyncOpenAI() - tools = SupermemoryTools( - api_key="your-supermemory-api-key", - config={"project_id": "chat-example"} - ) - - messages = [ - { - "role": "system", - "content": """You are a helpful assistant with memory capabilities. - When users share personal information, remember it using addMemory. - When they ask questions, search your memories to provide personalized responses.""" - } - ] - - while True: - user_input = input("You: ") - if user_input.lower() == 'quit': - break - - messages.append({"role": "user", "content": user_input}) - - # Get AI response with tools - response = await client.chat.completions.create( - model="gpt-5", - messages=messages, - tools=tools.get_tool_definitions() - ) - - # Handle tool calls - if response.choices[0].message.tool_calls: - messages.append(response.choices[0].message) - - tool_results = await execute_memory_tool_calls( - api_key="your-supermemory-api-key", - tool_calls=response.choices[0].message.tool_calls, - config={"project_id": "chat-example"} - ) - - messages.extend(tool_results) - - # Get final response after tool execution - final_response = await client.chat.completions.create( - model="gpt-5", - messages=messages - ) - - assistant_message = final_response.choices[0].message.content - else: - assistant_message = response.choices[0].message.content - messages.append({"role": "assistant", "content": assistant_message}) - - print(f"Assistant: {assistant_message}") - -# Run the chat -asyncio.run(chat_with_memory()) -``` - -```typescript Complete JavaScript Example -import OpenAI from "openai" -import { getToolDefinitions, createToolCallExecutor } from "@supermemory/tools/openai" -import readline from 'readline' - -const client = new OpenAI() -const executeToolCall = createToolCallExecutor(process.env.SUPERMEMORY_API_KEY!, { - projectId: "chat-example", -}) - -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, -}) - -async function chatWithMemory() { - const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [ - { - role: "system", - content: `You are a helpful assistant with memory capabilities. - When users share personal information, remember it using addMemory. - When they ask questions, search your memories to provide personalized responses.` - } - ] - - const askQuestion = () => { - rl.question("You: ", async (userInput) => { - if (userInput.toLowerCase() === 'quit') { - rl.close() - return - } - - messages.push({ role: "user", content: userInput }) - - // Get AI response with tools - const response = await client.chat.completions.create({ - model: "gpt-5", - messages, - tools: getToolDefinitions(), - }) - - const choice = response.choices[0] - if (choice?.message.tool_calls) { - messages.push(choice.message) - - // Execute tool calls - for (const toolCall of choice.message.tool_calls) { - const result = await executeToolCall(toolCall) - messages.push({ - role: "tool", - tool_call_id: toolCall.id, - content: JSON.stringify(result), - }) - } - - // Get final response after tool execution - const finalResponse = await client.chat.completions.create({ - model: "gpt-5", - messages, - }) - - const assistantMessage = finalResponse.choices[0]?.message.content || "No response" - console.log(`Assistant: ${assistantMessage}`) - messages.push({ role: "assistant", content: assistantMessage }) - } else { - const assistantMessage = choice?.message.content || "No response" - console.log(`Assistant: ${assistantMessage}`) - messages.push({ role: "assistant", content: assistantMessage }) - } - - askQuestion() - }) - } - - console.log("Chat with memory started. Type 'quit' to exit.") - askQuestion() -} - -chatWithMemory() -``` - - - -## Error Handling - -Handle errors gracefully in your applications: - - - -```python Python Error Handling -from supermemory_openai import SupermemoryTools -import openai - -async def safe_chat(): - try: - client = openai.AsyncOpenAI() - tools = SupermemoryTools(api_key="your-api-key") - - response = await client.chat.completions.create( - model="gpt-5", - messages=[{"role": "user", "content": "Hello"}], - tools=tools.get_tool_definitions() - ) - - except openai.APIError as e: - print(f"OpenAI API error: {e}") - except Exception as e: - print(f"Unexpected error: {e}") -``` - -```typescript JavaScript Error Handling -import OpenAI from "openai" -import { getToolDefinitions } from "@supermemory/tools/openai" - -async function safeChat() { - try { - const client = new OpenAI() - - const response = await client.chat.completions.create({ - model: "gpt-5", - messages: [{ role: "user", content: "Hello" }], - tools: getToolDefinitions(), - }) - - } catch (error) { - if (error instanceof OpenAI.APIError) { - console.error("OpenAI API error:", error.message) - } else { - console.error("Unexpected error:", error) - } - } -} -``` - - - -## API Reference - -### Python SDK - -#### `SupermemoryTools` - -**Constructor** -```python -SupermemoryTools( - api_key: str, - config: Optional[SupermemoryToolsConfig] = None -) -``` - -**Methods** -- `get_tool_definitions()` - Get OpenAI function definitions -- `search_memories(information_to_get, limit, include_full_docs)` - Search user memories -- `add_memory(memory)` - Add new memory -- `fetch_memory(memory_id)` - Fetch specific memory by ID -- `execute_tool_call(tool_call)` - Execute individual tool call - -#### `execute_memory_tool_calls` - -```python -execute_memory_tool_calls( - api_key: str, - tool_calls: List[ToolCall], - config: Optional[SupermemoryToolsConfig] = None -) -> List[dict] -``` - -### JavaScript SDK - -#### `supermemoryTools` - -```typescript -supermemoryTools( - apiKey: string, - config?: { projectId?: string; baseUrl?: string } -) -``` - -#### `createToolCallExecutor` - -```typescript -createToolCallExecutor( - apiKey: string, - config?: { projectId?: string; baseUrl?: string } -) -> (toolCall: OpenAI.Chat.ChatCompletionMessageToolCall) => Promise -``` - -## Environment Variables - -Set these environment variables: - -```bash -SUPERMEMORY_API_KEY=your_supermemory_key -OPENAI_API_KEY=your_openai_key -SUPERMEMORY_BASE_URL=https://custom-endpoint.com # optional -``` - -## Development - -### Python Setup - -```bash -# Install uv -curl -LsSf https://astral.sh/uv/install.sh | sh - -# Setup project -git clone -cd packages/openai-sdk-python -uv sync --dev - -# Run tests -uv run pytest - -# Type checking -uv run mypy src/supermemory_openai - -# Formatting -uv run black src/ tests/ -uv run isort src/ tests/ -``` - -### JavaScript Setup - -```bash -# Install dependencies -npm install - -# Run tests -npm test - -# Type checking -npm run type-check - -# Linting -npm run lint -``` - -## Next Steps - - - - Use with Vercel AI SDK for streamlined development - - - - Direct API access for advanced memory management - - diff --git a/apps/docs/memory-api/sdks/overview.mdx b/apps/docs/memory-api/sdks/overview.mdx deleted file mode 100644 index 30ace8a2..00000000 --- a/apps/docs/memory-api/sdks/overview.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "Overview" ---- - - - -
- ```pip install supermemory``` - - ```npm install supermemory``` -
- - - Easy to use with Vercel AI SDK - - - - Use supermemory with the python and javascript OpenAI SDKs - - - - We will add support for your favorite SDKs asap. - -
diff --git a/apps/docs/memory-api/sdks/python.mdx b/apps/docs/memory-api/sdks/python.mdx deleted file mode 100644 index 0888f2b0..00000000 --- a/apps/docs/memory-api/sdks/python.mdx +++ /dev/null @@ -1,349 +0,0 @@ ---- -title: 'Python SDK' -sidebarTitle: "Python" -description: 'Learn how to use supermemory with Python' ---- - -## Installation - -```sh -# install from PyPI -pip install --pre supermemory -``` - -## Usage - - -```python -import os -from supermemory import Supermemory - -client = Supermemory( - api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted -) - -response = client.search.execute( - q="documents related to python", -) -print(response.results) -``` - -While you can provide an `api_key` keyword argument, -we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) -to add `SUPERMEMORY_API_KEY="My API Key"` to your `.env` file -so that your API Key is not stored in source control. - -## Async usage - -Simply import `AsyncSupermemory` instead of `Supermemory` and use `await` with each API call: - -```python -import os -import asyncio -from supermemory import AsyncSupermemory - -client = AsyncSupermemory( - api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted -) - - -async def main() -> None: - response = await client.search.execute( - q="documents related to python", - ) - print(response.results) - - -asyncio.run(main()) -``` - -Functionality between the synchronous and asynchronous clients is otherwise identical. - -## Using types - -Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: - -- Serializing back into JSON, `model.to_json()` -- Converting to a dictionary, `model.to_dict()` - -Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. - -## File uploads - -Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. - -```python -from pathlib import Path -from supermemory import Supermemory - -client = Supermemory() - -client.documents.upload_file( - file=Path("/path/to/file"), -) -``` - -The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically. - -## Handling errors - -When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `supermemory.APIConnectionError` is raised. - -When the API returns a non-success status code (that is, 4xx or 5xx -response), a subclass of `supermemory.APIStatusError` is raised, containing `status_code` and `response` properties. - -All errors inherit from `supermemory.APIError`. - -```python -import supermemory -from supermemory import Supermemory - -client = Supermemory() - -try: - client.add( - content="This is a detailed article about machine learning concepts...", - ) -except supermemory.APIConnectionError as e: - print("The server could not be reached") - print(e.__cause__) # an underlying Exception, likely raised within httpx. -except supermemory.RateLimitError as e: - print("A 429 status code was received; we should back off a bit.") -except supermemory.APIStatusError as e: - print("Another non-200-range status code was received") - print(e.status_code) - print(e.response) -``` - -Error codes are as follows: - -| Status Code | Error Type | -| ----------- | -------------------------- | -| 400 | `BadRequestError` | -| 401 | `AuthenticationError` | -| 403 | `PermissionDeniedError` | -| 404 | `NotFoundError` | -| 422 | `UnprocessableEntityError` | -| 429 | `RateLimitError` | -| >=500 | `InternalServerError` | -| N/A | `APIConnectionError` | - -### Retries - -Certain errors are automatically retried 2 times by default, with a short exponential backoff. -Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, -429 Rate Limit, and >=500 Internal errors are all retried by default. - -You can use the `max_retries` option to configure or disable retry settings: - -```python -from supermemory import Supermemory - -# Configure the default for all requests: -client = Supermemory( - # default is 2 - max_retries=0, -) - -# Or, configure per-request: -client.with_options(max_retries=5).documents.add( - content="This is a detailed article about machine learning concepts...", -) -``` - -### Timeouts - -By default requests time out after 1 minute. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object: - -```python -from supermemory import Supermemory - -# Configure the default for all requests: -client = Supermemory( - # 20 seconds (default is 1 minute) - timeout=20.0, -) - -# More granular control: -client = Supermemory( - timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), -) - -# Override per-request: -client.with_options(timeout=5.0).documents.add( - content="This is a detailed article about machine learning concepts...", -) -``` - -On timeout, an `APITimeoutError` is thrown. - -Note that requests that time out are [retried twice by default](#retries). - -## Advanced - -### Logging - -We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. - -You can enable logging by setting the environment variable `SUPERMEMORY_LOG` to `info`. - -```shell -$ export SUPERMEMORY_LOG=info -``` - -Or to `debug` for more verbose logging. - -### How to tell whether `None` means `null` or missing - -In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: - -```py -if response.my_field is None: - if 'my_field' not in response.model_fields_set: - print('Got json like {}, without a "my_field" key present at all.') - else: - print('Got json like {"my_field": null}.') -``` - -### Accessing raw response data (e.g. headers) - -The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g., - -```py -from supermemory import Supermemory - -client = Supermemory() -response = client.documents.with_raw_response.add( - content="This is a detailed article about machine learning concepts...", -) -print(response.headers.get('X-My-Header')) - -memory = response.parse() # get the object that `documents.add()` would have returned -print(memory.id) -``` - -These methods return an [`APIResponse`](https://github.com/supermemoryai/python-sdk/tree/main/src/supermemory/_response.py) object. - -The async client returns an [`AsyncAPIResponse`](https://github.com/supermemoryai/python-sdk/tree/main/src/supermemory/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. - -#### `.with_streaming_response` - -The above interface eagerly reads the full response body when you make the request, which may not always be what you want. - -To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. - -```python -with client.documents.with_streaming_response.add( - content="This is a detailed article about machine learning concepts...", -) as response: - print(response.headers.get("X-My-Header")) - - for line in response.iter_lines(): - print(line) -``` - -The context manager is required so that the response will reliably be closed. - -### Making custom/undocumented requests - -This library is typed for convenient access to the documented API. - -If you need to access undocumented endpoints, params, or response properties, the library can still be used. - -#### Undocumented endpoints - -To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other -http verbs. Options on the client will be respected (such as retries) when making this request. - -```py -import httpx - -response = client.post( - "/foo", - cast_to=httpx.Response, - body={"my_param": True}, -) - -print(response.headers.get("x-foo")) -``` - -#### Undocumented request params - -If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request -options. - -#### Undocumented response properties - -To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You -can also get all the extra fields on the Pydantic model as a dict with -[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra). - -### Configuring the HTTP client - -You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: - -- Support for [proxies](https://www.python-httpx.org/advanced/proxies/) -- Custom [transports](https://www.python-httpx.org/advanced/transports/) -- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality - -```python -import httpx -from supermemory import Supermemory, DefaultHttpxClient - -client = Supermemory( - # Or use the `SUPERMEMORY_BASE_URL` env var - base_url="http://my.test.server.example.com:8083", - http_client=DefaultHttpxClient( - proxy="http://my.test.proxy.example.com", - transport=httpx.HTTPTransport(local_address="0.0.0.0"), - ), -) -``` - -You can also customize the client on a per-request basis by using `with_options()`: - -```python -client.with_options(http_client=DefaultHttpxClient(...)) -``` - -### Managing HTTP resources - -By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. - -```py -from supermemory import Supermemory - -with Supermemory() as client: - # make requests here - ... - -# HTTP client is now closed -``` - -## Versioning - -This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: - -1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ -3. Changes that we do not expect to impact the vast majority of users in practice. - -We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. - -We are keen for your feedback; please open an [issue](https://www.github.com/supermemoryai/python-sdk/issues) with questions, bugs, or suggestions. - -### Determining the installed version - -If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. - -You can determine the version that is being used at runtime with: - -```py -import supermemory -print(supermemory.__version__) -``` - -## Requirements - -Python 3.8 or higher. diff --git a/apps/docs/memory-api/sdks/supermemory-npm.mdx b/apps/docs/memory-api/sdks/supermemory-npm.mdx deleted file mode 100644 index c872458a..00000000 --- a/apps/docs/memory-api/sdks/supermemory-npm.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "`supermemory` on npm" -url: "https://www.npmjs.com/package/supermemory" -icon: npm ---- diff --git a/apps/docs/memory-api/sdks/supermemory-pypi.mdx b/apps/docs/memory-api/sdks/supermemory-pypi.mdx deleted file mode 100644 index 1b831245..00000000 --- a/apps/docs/memory-api/sdks/supermemory-pypi.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "`supermemory` on pypi" -url: "https://pypi.org/project/supermemory/" -icon: python ---- diff --git a/apps/docs/memory-api/sdks/typescript.mdx b/apps/docs/memory-api/sdks/typescript.mdx deleted file mode 100644 index d6670b10..00000000 --- a/apps/docs/memory-api/sdks/typescript.mdx +++ /dev/null @@ -1,391 +0,0 @@ ---- -title: 'Typescript SDK' -sidebarTitle: "Typescript" -description: 'Learn how to use supermemory with Typescript' ---- - -## Installation - -```sh -npm install supermemory -``` - -## Usage - -```js -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env['SUPERMEMORY_API_KEY'], // This is the default and can be omitted -}); - -async function main() { - const response = await client.search.execute({ q: 'documents related to python' }); - - console.debug(response.results); -} - -main(); -``` - -### Request & Response types - -This library includes TypeScript definitions for all request params and response fields. You may import and use them like so: - - -```ts -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env['SUPERMEMORY_API_KEY'], // This is the default and can be omitted -}); - -async function main() { - const params: Supermemory.AddParams = { - content: 'This is a detailed article about machine learning concepts...', - }; - const response: Supermemory.AddResponse = await client.add(params); -} - -main(); -``` - -Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors. - -## File uploads - -Request parameters that correspond to file uploads can be passed in many different forms: - -- `File` (or an object with the same structure) -- a `fetch` `Response` (or an object with the same structure) -- an `fs.ReadStream` -- the return value of our `toFile` helper - -```ts -import fs from 'fs'; -import Supermemory, { toFile } from 'supermemory'; - -const client = new Supermemory(); - -// If you have access to Node `fs` we recommend using `fs.createReadStream()`: -await client.documents.uploadFile({ file: fs.createReadStream('/path/to/file') }); - -// Or if you have the web `File` API you can pass a `File` instance: -await client.documents.uploadFile({ file: new File(['my bytes'], 'file') }); - -// You can also pass a `fetch` `Response`: -await client.documents.uploadFile({ file: await fetch('https://somesite/file') }); - -// Finally, if none of the above are convenient, you can use our `toFile` helper: -await client.documents.uploadFile({ file: await toFile(Buffer.from('my bytes'), 'file') }); -await client.documents.uploadFile({ file: await toFile(new Uint8Array([0, 1, 2]), 'file') }); -``` - -## Handling errors - -When the library is unable to connect to the API, -or if the API returns a non-success status code (i.e., 4xx or 5xx response), -a subclass of `APIError` will be thrown: - - -```ts -async function main() { - const response = await client.documents - .add({ content: 'This is a detailed article about machine learning concepts...' }) - .catch(async (err) => { - if (err instanceof supermemory.APIError) { - console.debug(err.status); // 400 - console.debug(err.name); // BadRequestError - console.debug(err.headers); // {server: 'nginx', ...} - } else { - throw err; - } - }); -} - -main(); -``` - -Error codes are as follows: - -| Status Code | Error Type | -| ----------- | -------------------------- | -| 400 | `BadRequestError` | -| 401 | `AuthenticationError` | -| 403 | `PermissionDeniedError` | -| 404 | `NotFoundError` | -| 422 | `UnprocessableEntityError` | -| 429 | `RateLimitError` | -| >=500 | `InternalServerError` | -| N/A | `APIConnectionError` | - -### Retries - -Certain errors will be automatically retried 2 times by default, with a short exponential backoff. -Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, -429 Rate Limit, and >=500 Internal errors will all be retried by default. - -You can use the `maxRetries` option to configure or disable this: - - -```js -// Configure the default for all requests: -const client = new Supermemory({ - maxRetries: 0, // default is 2 -}); - -// Or, configure per-request: -await client.add({ content: 'This is a detailed article about machine learning concepts...' }, { - maxRetries: 5, -}); -``` - -### Timeouts - -Requests time out after 1 minute by default. You can configure this with a `timeout` option: - - -```ts -// Configure the default for all requests: -const client = new Supermemory({ - timeout: 20 * 1000, // 20 seconds (default is 1 minute) -}); - -// Override per-request: -await client.add({ content: 'This is a detailed article about machine learning concepts...' }, { - timeout: 5 * 1000, -}); -``` - -On timeout, an `APIConnectionTimeoutError` is thrown. - -Note that requests which time out will be [retried twice by default](#retries). - -## Advanced Usage - -### Accessing raw Response data (e.g., headers) - -The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return. -This method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic. - -You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data. -Unlike `.asResponse()` this method consumes the body, returning once it is parsed. - - -```ts -const client = new Supermemory(); - -const response = await client.documents - .add({ content: 'This is a detailed article about machine learning concepts...' }) - .asResponse(); -console.debug(response.headers.get('X-My-Header')); -console.debug(response.statusText); // access the underlying Response object - -const { data: response, response: raw } = await client.documents - .add({ content: 'This is a detailed article about machine learning concepts...' }) - .withResponse(); -console.debug(raw.headers.get('X-My-Header')); -console.debug(response.id); -``` - -### Logging - - -All log messages are intended for debugging only. The format and content of log messages may change between releases. - - -#### Log levels - -The log level can be configured in two ways: - -1. Via the `SUPERMEMORY_LOG` environment variable -2. Using the `logLevel` client option (overrides the environment variable if set) - -```ts -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - logLevel: 'debug', // Show all log messages -}); -``` - -Available log levels, from most to least verbose: - -- `'debug'` - Show debug messages, info, warnings, and errors -- `'info'` - Show info messages, warnings, and errors -- `'warn'` - Show warnings and errors (default) -- `'error'` - Show only errors -- `'off'` - Disable all logging - -At the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies. -Some authentication-related headers are redacted, but sensitive data in request and response bodies -may still be visible. - -#### Custom logger - -By default, this library logs to `globalThis.console`. You can also provide a custom logger. -Most logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue. - -When providing a custom logger, the `logLevel` option still controls which messages are emitted, messages -below the configured level will not be sent to your logger. - -```ts -import Supermemory from 'supermemory'; -import pino from 'pino'; - -const logger = pino(); - -const client = new Supermemory({ - logger: logger.child({ name: 'supermemory' }), - logLevel: 'debug', // Send all messages to pino, allowing it to filter -}); -``` - -### Making custom/undocumented requests - -This library is typed for convenient access to the documented API. If you need to access undocumented -endpoints, params, or response properties, the library can still be used. - -#### Undocumented endpoints - -To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs. -Options on the client, such as retries, will be respected when making these requests. - -```ts -await client.post('/some/path', { - body: { some_prop: 'foo' }, - query: { some_query_arg: 'bar' }, -}); -``` - -#### Undocumented request params - -To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented -parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you -send will be sent as-is. - -```ts -client.foo.create({ - foo: 'my_param', - bar: 12, - // @ts-expect-error baz is not yet public - baz: 'undocumented option', -}); -``` - -For requests with the `GET` verb, any extra params will be in the query, all other requests will send the -extra param in the body. - -If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request -options. - -#### Undocumented response properties - -To access undocumented response properties, you may access the response object with `// @ts-expect-error` on -the response object, or cast the response object to the requisite type. Like the request params, we do not -validate or strip extra properties from the response from the API. - -### Customizing the fetch client - -By default, this library expects a global `fetch` function is defined. - -If you want to use a different `fetch` function, you can either polyfill the global: - -```ts -import fetch from 'my-fetch'; - -globalThis.fetch = fetch; -``` - -Or pass it to the client: - -```ts -import Supermemory from 'supermemory'; -import fetch from 'my-fetch'; - -const client = new Supermemory({ fetch }); -``` - -### Fetch options - -If you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.) - -```ts -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - fetchOptions: { - // `RequestInit` options - }, -}); -``` - -#### Configuring proxies - -To modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy options to requests: - -```ts -import Supermemory from 'supermemory'; -import * as undici from 'undici'; - -const proxyAgent = new undici.ProxyAgent('http://localhost:8888'); -const client = new Supermemory({ - fetchOptions: { - dispatcher: proxyAgent, - }, -}); -``` - -```ts -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - fetchOptions: { - proxy: 'http://localhost:8888', - }, -}); -``` - -```ts -import Supermemory from 'npm:supermemory'; - -const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } }); -const client = new Supermemory({ - fetchOptions: { - client: httpClient, - }, -}); -``` - -## Frequently Asked Questions - -## Semantic versioning - -This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: - -1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ -3. Changes that we do not expect to impact the vast majority of users in practice. - -We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. - -We are keen for your feedback; please open an [issue](https://www.github.com/supermemoryai/sdk-ts/issues) with questions, bugs, or suggestions. - -## Requirements - -TypeScript >= 4.9 is supported. - -The following runtimes are supported: - -- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more) -- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. -- Deno v1.28.0 or higher. -- Bun 1.0 or later. -- Cloudflare Workers. -- Vercel Edge Runtime. -- Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). -- Nitro v2.6 or greater. - -Note that React Native is not supported at this time. - -If you are interested in other runtime environments, please open or upvote an issue on GitHub. diff --git a/apps/docs/memory-api/searching/searching-memories.mdx b/apps/docs/memory-api/searching/searching-memories.mdx deleted file mode 100644 index 6e5f3454..00000000 --- a/apps/docs/memory-api/searching/searching-memories.mdx +++ /dev/null @@ -1,181 +0,0 @@ ---- -title: "Searching Memories" -description: "Learn how to search for and retrieve content from supermemory" ---- - - -1. **Query Formulation**: - - Use natural language queries - - Include relevant keywords - - Be specific but not too verbose - -2. **Filtering**: - - Use metadata filters for precision - - Combine multiple filters when needed - - Use appropriate thresholds - -3. **Performance**: - - Set appropriate result limits - - Use specific document/chunk filters - - Consider response timing - - - -## Basic Search - -To search through your memories, send a POST request to `/search`: - - - -```bash cURL -curl https://api.supermemory.ai/v3/search?q=machine+learning+concepts&limit=10 \ - --request GET \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' -``` - -```typescript Typescript -await client.search.execute({ - q: "machine learning concepts", - limit: 10, -}); -``` - -```python Python -client.search.execute( - q="machine learning concepts", - limit=10 -) -``` - - - -The API will return relevant matches with their similarity scores: - -```json -{ - "results": [ - { - "documentId": "doc_xyz789", - "chunks": [ - { - "content": "Machine learning is a subset of artificial intelligence...", - "isRelevant": true, - "score": 0.85 - } - ], - "score": 0.95, - "metadata": { - "source": "web", - "category": "technology" - }, - "title": "Introduction to Machine Learning" - } - ], - "total": 1, - "timing": 123.45 -} -``` - -## Search Parameters - -```json -{ - "q": "search query", // Required: Search query string - "limit": 10, // Optional: Max results (default: 10) - "threshold": 0.6, // Optional: Min similarity score (0-1, default: 0.6) - "containerTag": "user_123", // Optional: Filter by container tag - "rerank": false, // Optional: Rerank results for better relevance - "rewriteQuery": false, // Optional: Rewrite query for better matching - "include": { - "documents": false, // Optional: Include document metadata - "summaries": false, // Optional: Include document summaries - "relatedMemories": false, // Optional: Include related memory context - "forgottenMemories": false // Optional: Include forgotten memories in results - }, - "filters": { - // Optional: Metadata filters - "AND": [ - { - "key": "category", - "value": "technology" - } - ] - } -} -``` - -## Search Response - -The search response includes: - -```json -{ - "results": [ - { - "documentId": "string", // Document ID - "chunks": [ - { - // Matching chunks - "content": "string", // Chunk content - "isRelevant": true, // Is directly relevant - "score": 0.95 // Similarity score - } - ], - "score": 0.95, // Document score - "metadata": {}, // Document metadata - "title": "string", // Document title - "createdAt": "string", // Creation date - "updatedAt": "string" // Last update date - } - ], - "total": 1, // Total results - "timing": 123.45 // Search time (ms) -} -``` - -## Including Forgotten Memories - -By default, the search API excludes memories that have been marked as forgotten or have passed their expiration date. To include these in your search results, set `include.forgottenMemories` to `true`: - - - -```bash cURL -curl https://api.supermemory.ai/v4/search \ - --request POST \ - --header 'Authorization: Bearer SUPERMEMORY_API_KEY' \ - --header 'Content-Type: application/json' \ - --data '{ - "q": "old project notes", - "include": { - "forgottenMemories": true - } - }' -``` - -```typescript Typescript -await client.search.memories({ - q: "old project notes", - include: { - forgottenMemories: true - } -}); -``` - -```python Python -await client.search.memories( - q="old project notes", - include={ - "forgottenMemories": True - } -) -``` - - - - -Forgotten memories are memories that have been explicitly forgotten using the forget API or have passed their automatic expiration date (`forgetAfter`). Including them in search results can help recover information that may still be relevant. - - -## Next Steps - -Explore more advanced features in our API Reference tab. diff --git a/apps/docs/memory-api/track-progress.mdx b/apps/docs/memory-api/track-progress.mdx deleted file mode 100644 index 65c0462f..00000000 --- a/apps/docs/memory-api/track-progress.mdx +++ /dev/null @@ -1,256 +0,0 @@ ---- -title: "Track Processing Status" -description: "Monitor document processing status in real-time" -icon: "activity" ---- - -Track your documents through the processing pipeline to provide better user experiences and handle edge cases. - -## Processing Pipeline - -![Process of converting documents to memories](/images/pipeline.png) - -Each stage serves a specific purpose: - -- **Queued**: Document is waiting in the processing queue -- **Extracting**: Content is being extracted (OCR for images, transcription for videos) -- **Chunking**: Content is broken into optimal, searchable pieces -- **Embedding**: Each chunk is converted to vector representations -- **Indexing**: Vectors are added to the search index -- **Done**: Document is fully processed and searchable - - -Processing time varies by content type. Plain text processes in seconds, while a 10-minute video might take 2-3 minutes. - - -## Processing Documents - -Monitor all documents currently being processed across your account. - -`GET /v3/documents/processing` - - - -```typescript Typescript - -// Direct API call (not in SDK) -const response = await fetch('https://api.supermemory.ai/v3/documents/processing', { - headers: { - 'Authorization': `Bearer ${SUPERMEMORY_API_KEY}` - } -}); - -const processing = await response.json(); -console.log(`${processing.documents.length} documents processing`); -``` - -```python Python -# Direct API call (not in SDK) -import requests - -response = requests.get( - 'https://api.supermemory.ai/v3/documents/processing', - headers={'Authorization': f'Bearer {SUPERMEMORY_API_KEY}'} -) - -processing = response.json() -print(f"{len(processing['documents'])} documents processing") -``` - -```bash cURL -curl -X GET "https://api.supermemory.ai/v3/documents/processing" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" -``` - - - -### Response Format - -```json -{ - "documents": [ - { - "id": "doc_abc123", - "status": "extracting", - "created_at": "2024-01-15T10:30:00Z", - "updated_at": "2024-01-15T10:30:15Z", - "container_tags": ["research"], - "metadata": { - "source": "upload", - "filename": "report.pdf" - } - }, - { - "id": "doc_def456", - "status": "chunking", - "created_at": "2024-01-15T10:29:00Z", - "updated_at": "2024-01-15T10:30:00Z", - "container_tags": ["articles"], - "metadata": { - "source": "url", - "url": "https://example.com/article" - } - } - ], - "total": 2 -} -``` - -## Individual Documents - -Track specific document processing status. - -`GET /v3/documents/{id}` - - - -```typescript Typescript -const memory = await client.documents.get("doc_abc123"); - -console.log(`Status: ${memory.status}`); - -// Poll for completion -while (memory.status !== 'done') { - await new Promise(r => setTimeout(r, 2000)); - memory = await client.documents.get("doc_abc123"); - console.log(`Status: ${memory.status}`); -} -``` - -```python Python -memory = client.documents.get("doc_abc123") - -print(f"Status: {memory['status']}") - -# Poll for completion -import time -while memory['status'] != 'done': - time.sleep(2) - memory = client.documents.get("doc_abc123") - print(f"Status: {memory['status']}") -``` - -```bash cURL -curl -X GET "https://api.supermemory.ai/v3/documents/doc_abc123" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" -``` - - - -### Response Format - -```json -{ - "id": "doc_abc123", - "status": "done", - "content": "The original content...", - "container_tags": ["research"], - "metadata": { - "source": "upload", - "filename": "report.pdf" - }, - "created_at": "2024-01-15T10:30:00Z", - "updated_at": "2024-01-15T10:31:00Z" -} -``` - -For more comprehensive information on the get documents by ID endpoint, refer to the API Reference tab. - -## Status Values - -| Status | Description | Typical Duration | -|--------|-------------|------------------| -| `queued` | Waiting to be processed | < 5 seconds | -| `extracting` | Extracting content from source | 5-30 seconds | -| `chunking` | Breaking into searchable pieces | 5-15 seconds | -| `embedding` | Creating vector representations | 10-30 seconds | -| `indexing` | Adding to search index | 5-10 seconds | -| `done` | Fully processed and searchable | - | -| `failed` | Processing failed | - | - -## Polling Best Practices - -When polling for status updates: - -```typescript -async function waitForProcessing(documentId: string, maxWaitMs = 300000) { - const startTime = Date.now(); - const pollInterval = 2000; // 2 seconds - - while (Date.now() - startTime < maxWaitMs) { - const doc = await client.documents.get(documentId); - - if (doc.status === 'done') { - return doc; - } - - if (doc.status === 'failed') { - throw new Error(`Processing failed for ${documentId}`); - } - - await new Promise(r => setTimeout(r, pollInterval)); - } - - throw new Error(`Timeout waiting for ${documentId}`); -} -``` - -## Batch Processing - -For multiple documents, track them efficiently: - -```typescript -async function trackBatch(documentIds: string[]) { - const statuses = new Map(); - - // Initial check - for (const id of documentIds) { - const doc = await client.documents.get(id); - statuses.set(id, doc.status); - } - - // Poll until all done - while ([...statuses.values()].some(s => s !== 'done' && s !== 'failed')) { - await new Promise(r => setTimeout(r, 5000)); // 5 second interval for batch - - for (const id of documentIds) { - if (statuses.get(id) !== 'done' && statuses.get(id) !== 'failed') { - const doc = await client.documents.get(id); - statuses.set(id, doc.status); - } - } - - // Log progress - const done = [...statuses.values()].filter(s => s === 'done').length; - console.log(`Progress: ${done}/${documentIds.length} complete`); - } - - return statuses; -} -``` - -## Error Handling - -Handle processing failures gracefully: - -```typescript -async function addWithRetry(content: string, maxRetries = 3) { - for (let attempt = 1; attempt <= maxRetries; attempt++) { - const { id } = await client.add({ content }); - - try { - const result = await waitForProcessing(id); - return result; - } catch (error) { - console.error(`Attempt ${attempt} failed:`, error); - - if (attempt === maxRetries) { - throw error; - } - - // Exponential backoff - await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt))); - } - } -} -``` diff --git a/apps/docs/memory-graph/api-reference.mdx b/apps/docs/memory-graph/api-reference.mdx deleted file mode 100644 index 92641a74..00000000 --- a/apps/docs/memory-graph/api-reference.mdx +++ /dev/null @@ -1,334 +0,0 @@ ---- -title: 'API Reference' -description: 'Complete reference for Memory Graph props and types' ---- - -## Component Props - -### MemoryGraph - -The main graph component. - -#### Core Props - - - Array of documents to display in the graph. Each document must include its memory entries. - - - - Shows a loading indicator when true. - - - - Error object to display. Shows an error message overlay when set. - - - - Visual variant: - - `console`: Full-featured dashboard view (0.8x zoom, space selector visible) - - `consumer`: Embedded widget view (0.5x zoom, space selector hidden) - - - - Content to render when no documents exist. Useful for empty states. - - -#### Pagination Props - - - Shows a subtle indicator when loading additional documents. - - - - Whether more documents are available to load. - - - - Total number of documents currently loaded. Shown in loading indicator. - - - - Callback to load more documents. Called automatically when viewport shows most documents. - - - - Automatically load more documents when 80% are visible in viewport. - - -#### Display Props - - - Show or hide the space filter dropdown. Defaults to `true` for console variant, `false` for consumer. - - - - Array of document IDs to highlight with a pulsing outline. Accepts both `customId` and internal `id`. - - - - Controls whether highlights are shown. Useful for toggling highlights without changing the array. - - - - Pixels occluded on the right side (e.g., by a sidebar). Graph auto-fits accounting for this space. - - - - Custom ID for the legend component. Useful for testing or styling. - - -#### Controlled State Props - - - Currently selected space. When provided, makes space selection controlled. Use `"all"` for all spaces. - - - - Callback when space selection changes. Required when using `selectedSpace`. - - - - Maximum memories to show per document when a specific space is selected. Only applies when `selectedSpace !== "all"`. - - - - Enable experimental features. Currently unused but reserved for future features. - - -## Data Types - -### DocumentWithMemories - -```typescript -interface DocumentWithMemories { - id: string; - customId?: string | null; - contentHash: string | null; - orgId: string; - userId: string; - connectionId?: string | null; - title?: string | null; - content?: string | null; - summary?: string | null; - url?: string | null; - source?: string | null; - type?: string | null; - status: 'pending' | 'processing' | 'done' | 'failed'; - metadata?: Record | null; - processingMetadata?: Record | null; - raw?: string | null; - tokenCount?: number | null; - wordCount?: number | null; - chunkCount?: number | null; - averageChunkSize?: number | null; - summaryEmbedding?: number[] | null; - summaryEmbeddingModel?: string | null; - createdAt: string | Date; - updatedAt: string | Date; - memoryEntries: MemoryEntry[]; -} -``` - -### MemoryEntry - -```typescript -interface MemoryEntry { - id: string; - customId?: string | null; - documentId: string; - content: string | null; - summary?: string | null; - title?: string | null; - url?: string | null; - type?: string | null; - metadata?: Record | null; - embedding?: number[] | null; - embeddingModel?: string | null; - tokenCount?: number | null; - createdAt: string | Date; - updatedAt: string | Date; - - // Fields from join relationship - sourceAddedAt?: Date | null; - sourceRelevanceScore?: number | null; - sourceMetadata?: Record | null; - spaceContainerTag?: string | null; - - // Version chain fields - updatesMemoryId?: string | null; - nextVersionId?: string | null; - relation?: 'updates' | 'extends' | 'derives' | null; - - // Memory status fields - isForgotten?: boolean; - forgetAfter?: Date | string | null; - isLatest?: boolean; - - // Space/container fields - spaceId?: string | null; - - // Legacy fields (for backwards compatibility) - memory?: string | null; - memoryRelations?: Array<{ - relationType: 'updates' | 'extends' | 'derives'; - targetMemoryId: string; - }> | null; - parentMemoryId?: string | null; -} -``` - -### GraphNode - -Internal type for rendered nodes: - -```typescript -interface GraphNode { - id: string; - type: 'document' | 'memory'; - x: number; - y: number; - data: DocumentWithMemories | MemoryEntry; - size: number; - color: string; - isHovered: boolean; - isDragging: boolean; -} -``` - -### GraphEdge - -Internal type for connections: - -```typescript -interface GraphEdge { - id: string; - source: string; - target: string; - similarity: number; - edgeType: 'doc-memory' | 'doc-doc' | 'version'; - relationType?: 'updates' | 'extends' | 'derives'; - color: string; - visualProps: { - opacity: number; - thickness: number; - glow: number; - pulseDuration: number; - }; -} -``` - -## Exported Components - -Besides `MemoryGraph`, the package exports individual components for advanced use cases: - -### GraphCanvas - -Low-level canvas renderer. Not recommended for direct use. - -```typescript -import { GraphCanvas } from '@supermemory/memory-graph'; -``` - -### Legend - -Graph legend showing node types and counts. - -```typescript -import { Legend } from '@supermemory/memory-graph'; -``` - -### LoadingIndicator - -Loading state indicator with progress counter. - -```typescript -import { LoadingIndicator } from '@supermemory/memory-graph'; -``` - -### NodeDetailPanel - -Side panel showing node details when clicked. - -```typescript -import { NodeDetailPanel } from '@supermemory/memory-graph'; -``` - -### SpacesDropdown - -Space filter dropdown. - -```typescript -import { SpacesDropdown } from '@supermemory/memory-graph'; -``` - -## Exported Hooks - -### useGraphData - -Processes documents into graph nodes and edges. - -```typescript -import { useGraphData } from '@supermemory/memory-graph'; - -const { nodes, edges } = useGraphData( - data, - selectedSpace, - nodePositions, - draggingNodeId, - memoryLimit -); -``` - -### useGraphInteractions - -Handles pan, zoom, and node interactions. - -```typescript -import { useGraphInteractions } from '@supermemory/memory-graph'; - -const { - panX, - panY, - zoom, - selectedNode, - handlePanStart, - handleWheel, - // ... more interaction handlers -} = useGraphInteractions('console'); -``` - -## Constants - -### colors - -Color palette used throughout the graph: - -```typescript -import { colors } from '@supermemory/memory-graph'; - -colors.document.primary; // Document fill color -colors.memory.primary; // Memory fill color -colors.connection.strong; // Strong edge color -``` - -### GRAPH_SETTINGS - -Initial zoom and pan settings for variants: - -```typescript -import { GRAPH_SETTINGS } from '@supermemory/memory-graph'; - -GRAPH_SETTINGS.console.initialZoom; // 0.8 -GRAPH_SETTINGS.consumer.initialZoom; // 0.5 -``` - -### LAYOUT_CONSTANTS - -Spatial layout configuration: - -```typescript -import { LAYOUT_CONSTANTS } from '@supermemory/memory-graph'; - -LAYOUT_CONSTANTS.clusterRadius; // Memory orbit radius -LAYOUT_CONSTANTS.documentSpacing; // Distance between documents -``` diff --git a/apps/docs/memory-graph/examples.mdx b/apps/docs/memory-graph/examples.mdx deleted file mode 100644 index 14d615d5..00000000 --- a/apps/docs/memory-graph/examples.mdx +++ /dev/null @@ -1,407 +0,0 @@ ---- -title: 'Examples' -description: 'Common use cases and implementation patterns' ---- - -## With Pagination - -Load documents in chunks for better performance with large datasets. - -```tsx -'use client'; - -import { MemoryGraph } from '@supermemory/memory-graph'; -import type { DocumentWithMemories } from '@supermemory/memory-graph'; -import { useCallback, useEffect, useState } from 'react'; - -export default function PaginatedGraph() { - const [documents, setDocuments] = useState([]); - const [page, setPage] = useState(1); - const [hasMore, setHasMore] = useState(true); - const [isLoading, setIsLoading] = useState(true); - const [isLoadingMore, setIsLoadingMore] = useState(false); - - // Initial load - useEffect(() => { - fetchPage(1, false); - }, []); - - const fetchPage = async (pageNum: number, append: boolean) => { - if (pageNum === 1) { - setIsLoading(true); - } else { - setIsLoadingMore(true); - } - - const res = await fetch(`/api/graph?page=${pageNum}&limit=100`); - const data = await res.json(); - - if (append) { - setDocuments(prev => [...prev, ...data.documents]); - } else { - setDocuments(data.documents); - } - - setHasMore(data.pagination.currentPage < data.pagination.totalPages); - setIsLoading(false); - setIsLoadingMore(false); - }; - - const loadMore = useCallback(async () => { - if (!isLoadingMore && hasMore) { - const nextPage = page + 1; - setPage(nextPage); - await fetchPage(nextPage, true); - } - }, [page, hasMore, isLoadingMore]); - - return ( -
- -
- ); -} -``` - -## Highlighting Search Results - -```tsx -'use client'; - -import { MemoryGraph } from '@supermemory/memory-graph'; -import { useState } from 'react'; - -export default function SearchableGraph() { - const [documents, setDocuments] = useState([]); - const [searchResults, setSearchResults] = useState([]); - const [searchQuery, setSearchQuery] = useState(''); - - const handleSearch = async (query: string) => { - setSearchQuery(query); - - if (!query) { - setSearchResults([]); - return; - } - - const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`); - const data = await res.json(); - - // Extract document IDs from search results - const docIds = data.results.map(r => r.documentId); - setSearchResults(docIds); - }; - - return ( -
-
- handleSearch(e.target.value)} - style={{ - padding: '8px 12px', - borderRadius: 8, - border: '1px solid #333', - background: '#1a1a1a', - color: 'white', - }} - /> -
- - 0} - /> -
- ); -} -``` - -## Controlled Space Selection - -Control space filtering from outside the component. - -```tsx -'use client'; - -import { MemoryGraph } from '@supermemory/memory-graph'; -import { useState } from 'react'; - -export default function ControlledSpaceGraph() { - const [documents, setDocuments] = useState([]); - const [selectedSpace, setSelectedSpace] = useState('all'); - - // Extract available spaces from documents - const spaces = Array.from( - new Set( - documents.flatMap(doc => - doc.memoryEntries.map(m => m.spaceId || 'default') - ) - ) - ); - - return ( -
-
-

Filters

- - - - -
- - -
- ); -} -``` - -## Embedded Widget - -Use the consumer variant for embedded views with custom styling. - -```tsx -'use client'; - -import { MemoryGraph } from '@supermemory/memory-graph'; - -export default function EmbeddedGraph({ documents }) { - return ( -
- -
-

No memories to display

-
-
-
- ); -} -``` - -## With Loading States - -```tsx -'use client'; - -import { MemoryGraph } from '@supermemory/memory-graph'; -import { useEffect, useState } from 'react'; - -export default function LoadingGraph() { - const [documents, setDocuments] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - fetch('/api/graph') - .then(res => { - if (!res.ok) throw new Error('Failed to load graph'); - return res.json(); - }) - .then(data => { - setDocuments(data.documents); - setIsLoading(false); - }) - .catch(err => { - setError(err); - setIsLoading(false); - }); - }, []); - - return ( -
- -
-
-

Welcome to your Memory Graph

-

Add some content to get started

- -
-
-
-
- ); -} -``` - -## React Server Component - -```tsx -// Next.js App Router with Server Component -import { MemoryGraphClient } from './memory-graph-client'; - -async function getGraphData() { - const res = await fetch('https://api.supermemory.ai/v3/documents/documents', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - page: 1, - limit: 500, - sort: 'createdAt', - order: 'desc', - }), - cache: 'no-store', // or use revalidation - }); - - return res.json(); -} - -export default async function GraphPage() { - const data = await getGraphData(); - - return ; -} -``` - -```tsx -// memory-graph-client.tsx -'use client'; - -import { MemoryGraph } from '@supermemory/memory-graph'; -import type { DocumentWithMemories } from '@supermemory/memory-graph'; - -interface Props { - initialDocuments: DocumentWithMemories[]; -} - -export function MemoryGraphClient({ initialDocuments }: Props) { - return ( -
- -
- ); -} -``` - -## Mobile-Responsive Layout - -```tsx -'use client'; - -import { MemoryGraph } from '@supermemory/memory-graph'; -import { useState, useEffect } from 'react'; - -export default function ResponsiveGraph({ documents }) { - const [isMobile, setIsMobile] = useState(false); - - useEffect(() => { - const checkMobile = () => { - setIsMobile(window.innerWidth < 768); - }; - - checkMobile(); - window.addEventListener('resize', checkMobile); - return () => window.removeEventListener('resize', checkMobile); - }, []); - - return ( -
- -
- ); -} -``` diff --git a/apps/docs/memory-graph/installation.mdx b/apps/docs/memory-graph/installation.mdx deleted file mode 100644 index e3a0b2d4..00000000 --- a/apps/docs/memory-graph/installation.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: 'Installation' -description: 'Install and set up the Memory Graph component' ---- - -## Installation - -Install the package using your preferred package manager: - -```bash npm -npm install @supermemory/memory-graph -``` - -## Requirements - -- **React**: 18.0.0 or higher -- **react-dom**: 18.0.0 or higher - -## Next Steps - - - - Get the graph running with real data - - - Explore all available props and types - - diff --git a/apps/docs/memory-graph/npm.mdx b/apps/docs/memory-graph/npm.mdx deleted file mode 100644 index 73185178..00000000 --- a/apps/docs/memory-graph/npm.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "NPM link" -url: "https://www.npmjs.com/package/@supermemory/memory-graph" -icon: npm ---- diff --git a/apps/docs/memory-graph/overview.mdx b/apps/docs/memory-graph/overview.mdx deleted file mode 100644 index c3260d21..00000000 --- a/apps/docs/memory-graph/overview.mdx +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: 'Overview' -description: 'Interactive visualization for documents, memories and connections' ---- - -## What is Memory Graph? - -Memory Graph is a React component that visualizes your Supermemory documents and memories as an interactive network. Documents appear as rectangular nodes, memories as hexagonal nodes, and connections between them show relationships and similarity. - -The graph renders using Canvas 2D, providing smooth interactions with hundreds of nodes through pan, zoom, and drag operations. - -## When to Use It - -Use Memory Graph when you need to: - -- **Visualize knowledge graphs** - Show how documents and memories connect -- **Navigate memory spaces** - Filter and browse by workspace or tag -- **Create memory browsers** - Give users a visual overview of their stored content - -## Performance - -The graph handles hundreds of nodes efficiently through: -- Canvas-based rendering (not DOM elements) -- Viewport culling (only draws visible nodes) -- Level-of-detail optimization (simplifies rendering when zoomed out) -- Change-based rendering (only redraws when state changes) -- Throttled viewport calculations - -For very large datasets (1000+ documents), use pagination to load data in chunks. - -## Browser Support - -Works in all modern browsers that support: -- Canvas 2D API -- ES2020 JavaScript -- CSS custom properties - -Tested on Chrome, Firefox, Safari, and Edge (latest versions). diff --git a/apps/docs/memory-graph/quickstart.mdx b/apps/docs/memory-graph/quickstart.mdx deleted file mode 100644 index 1b02fef6..00000000 --- a/apps/docs/memory-graph/quickstart.mdx +++ /dev/null @@ -1,207 +0,0 @@ ---- -title: 'Quick Start' -description: 'Get Memory Graph running in 2 minutes' ---- - -## Basic Setup - -Here's a minimal example to get the graph running: - -```tsx -'use client'; // For Next.js App Router - -import { MemoryGraph } from '@supermemory/memory-graph'; -import type { DocumentWithMemories } from '@supermemory/memory-graph'; -import { useEffect, useState } from 'react'; - -export default function GraphPage() { - const [documents, setDocuments] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - fetch('/api/graph') - .then(res => res.json()) - .then(data => { - setDocuments(data.documents); - setIsLoading(false); - }) - .catch(err => { - setError(err); - setIsLoading(false); - }); - }, []); - - return ( -
- -
- ); -} -``` - -## Backend API Route - -Create an API route to fetch documents from Supermemory: - - - -```typescript Next.js App Router -// app/api/graph/route.ts -import { NextResponse } from 'next/server'; - -export async function GET() { - const response = await fetch('https://api.supermemory.ai/v3/documents/documents', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - }, - body: JSON.stringify({ - page: 1, - limit: 500, - sort: 'createdAt', - order: 'desc', - }), - }); - - const data = await response.json(); - return NextResponse.json(data); -} -``` - -```typescript Next.js Pages Router -// pages/api/graph.ts -import type { NextApiRequest, NextApiResponse } from 'next'; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - const response = await fetch('https://api.supermemory.ai/v3/documents/documents', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - }, - body: JSON.stringify({ - page: 1, - limit: 500, - sort: 'createdAt', - order: 'desc', - }), - }); - - const data = await response.json(); - res.json(data); -} -``` - -```javascript Express -// routes/graph.js -app.get('/api/graph', async (req, res) => { - const response = await fetch('https://api.supermemory.ai/v3/documents/documents', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - }, - body: JSON.stringify({ - page: 1, - limit: 500, - sort: 'createdAt', - order: 'desc', - }), - }); - - const data = await response.json(); - res.json(data); -}); -``` - - - - - Never expose your Supermemory API key to the client. Always fetch data through your backend. - - -## Environment Variables - -Add your API key to `.env.local`: - -```bash -SUPERMEMORY_API_KEY=your_api_key_here -``` - -Get your API key from the [Supermemory dashboard](https://console.supermemory.ai). - -## Common Customizations - -### Embedded Mode - -For a widget-style view, use the consumer variant: - -```tsx - -``` - -### CSS Import - -The component includes bundled styles. You don't need to import CSS separately. Styles are automatically injected when the component mounts. - -If you want explicit control, you can import the stylesheet: - -```typescript -import '@supermemory/memory-graph/styles.css'; -``` - - - The automatic CSS injection works for most setups. Only use the explicit import if you need custom control over style loading order. - - - -### Custom Empty State - -Show custom content when no documents exist: - -```tsx - -
-

No memories yet

-

Add content to see your knowledge graph

-
-
-``` - -### Hide Space Selector - -```tsx - -``` - -## Next Steps - - - - See more usage examples - - - Full API documentation - - diff --git a/apps/docs/memory-router/overview.mdx b/apps/docs/memory-router/overview.mdx deleted file mode 100644 index 9ed0ba99..00000000 --- a/apps/docs/memory-router/overview.mdx +++ /dev/null @@ -1,158 +0,0 @@ ---- -title: "Overview" -description: "Transform any LLM into an intelligent agent with unlimited context and persistent memory" -sidebarTitle: "Overview" ---- - -The Memory Router is a transparent proxy that sits between your application and your LLM provider, automatically managing context and memories without requiring any code changes. - - -**Live Demo**: Try the Memory Router at [supermemory.chat](https://supermemory.chat) to see it in action. - - - -**Using Vercel AI SDK?** Check out our [AI SDK integration](/integrations/ai-sdk) for the cleanest implementation with `@supermemory/tools/ai-sdk` - it's our recommended approach for new projects. - - -## What is the Memory Router? - -The Memory Router gives your LLM applications: - -- **Unlimited Context**: No more token limits - conversations can extend indefinitely -- **Automatic Memory Management**: Intelligently chunks, stores, and retrieves relevant context -- **Zero Code Changes**: Works with your existing OpenAI-compatible clients -- **Cost Optimization**: Save up to 70% on token costs through intelligent context management - -## How It Works - - - - Your application sends requests to Supermemory instead of directly to your LLM provider - - - - Supermemory automatically: - - Removes unnecessary context from long conversations - - Searches relevant memories from previous interactions - - Appends the most relevant context to your prompt - - - - The optimized request is forwarded to your chosen LLM provider - - - - New memories are created asynchronously without blocking the response - - - -## Key Benefits - -### For Developers - -- **Drop-in Integration**: Just change your base URL - no other code changes needed -- **Provider Agnostic**: Works with OpenAI, Anthropic, Google, Groq, and more -- **Shared Memory Pool**: Memories created via API are available to the Router and vice versa -- **Automatic Fallback**: If Supermemory has issues, requests pass through directly - -### For Applications - -- **Better Long Conversations**: Maintains context even after thousands of messages -- **Consistent Responses**: Memories ensure consistent information across sessions -- **Smart Retrieval**: Only relevant context is included, improving response quality -- **Cost Savings**: Automatic chunking reduces token usage significantly - -## When to Use the Memory Router - -The Memory Router is ideal for: - - - - - **Chat Applications**: Customer support, AI assistants, chatbots - - **Long Conversations**: Sessions that exceed model context windows - - **Multi-Session Memory**: Users who return and continue conversations - - **Quick Prototypes**: Get memory capabilities without building infrastructure - - - - - **Custom Retrieval Logic**: Need specific control over what memories to fetch - - **Non-Conversational Use**: Document processing, analysis tools - - **Complex Filtering**: Need advanced metadata filtering - - **Batch Operations**: Processing multiple documents at once - - - -## Supported Providers - -The Memory Router works with any OpenAI-compatible endpoint: - -| Provider | Base URL | Status | -|----------|----------|---------| -| OpenAI | `api.openai.com/v1` | ✅ Fully Supported | -| Anthropic | `api.anthropic.com/v1` | ✅ Fully Supported | -| Google Gemini | `generativelanguage.googleapis.com/v1beta/openai` | ✅ Fully Supported | -| Groq | `api.groq.com/openai/v1` | ✅ Fully Supported | -| DeepInfra | `api.deepinfra.com/v1/openai` | ✅ Fully Supported | -| OpenRouter | `openrouter.ai/api/v1` | ✅ Fully Supported | -| Custom | Any OpenAI-compatible | ✅ Supported | - - -**Not Yet Supported**: -- OpenAI Assistants API (`/v1/assistants`) - - -## Authentication - -The Memory Router requires two API keys: - -1. **Supermemory API Key**: For memory management -2. **Provider API Key**: For your chosen LLM provider - -You can provide these via: -- Headers (recommended for production) -- URL parameters (useful for testing) -- Request body (for compatibility) - -## How Memories Work - -When using the Memory Router: - -1. **Automatic Extraction**: Important information from conversations is automatically extracted -2. **Intelligent Chunking**: Long messages are split into semantic chunks -3. **Relationship Building**: New memories connect to existing knowledge -4. **Smart Retrieval**: Only the most relevant memories are included in context - - -Memories are shared between the Memory Router and Memory API when using the same `user_id`, allowing you to use both together. - - -## Response Headers - -The Memory Router adds diagnostic headers to help you understand what's happening: - -| Header | Description | -|--------|-------------| -| `x-supermemory-conversation-id` | Unique conversation identifier | -| `x-supermemory-context-modified` | Whether context was modified (`true`/`false`) | -| `x-supermemory-tokens-processed` | Number of tokens processed | -| `x-supermemory-chunks-created` | New memory chunks created | -| `x-supermemory-chunks-retrieved` | Memory chunks added to context | - -## Error Handling - -The Memory Router is designed for reliability: - -- **Automatic Fallback**: If Supermemory encounters an error, your request passes through unmodified -- **Error Headers**: `x-supermemory-error` header provides error details -- **Zero Downtime**: Your application continues working even if memory features are unavailable - -## Rate Limits & Pricing - -### Rate Limits -- No Supermemory-specific rate limits -- Subject only to your LLM provider's limits - -### Pricing -- **Free Tier**: 100k tokens stored at no cost -- **Standard Plan**: $20/month after free tier -- **Usage-Based**: Each conversation includes 20k free tokens, then $1 per million tokens diff --git a/apps/docs/memory-router/usage.mdx b/apps/docs/memory-router/usage.mdx deleted file mode 100644 index 68dad6f6..00000000 --- a/apps/docs/memory-router/usage.mdx +++ /dev/null @@ -1,214 +0,0 @@ ---- -title: "Usage" -description: "How to implement the Memory Router in your application" -sidebarTitle: "Usage" ---- - -Add unlimited memory to your LLM applications with just a URL change. - -## Prerequisites - -You'll need: -1. A [Supermemory API key](https://console.supermemory.ai) -2. Your LLM provider's API key - -## Basic Setup - - - - **Supermemory API Key:** - 1. Sign up at [console.supermemory.ai](https://console.supermemory.ai) - 2. Navigate to **API Keys** → **Create API Key** - 3. Copy your key - - **Provider API Key:** - - [OpenAI](https://platform.openai.com/api-keys) - - [Anthropic](https://console.anthropic.com/settings/keys) - - [Google Gemini](https://aistudio.google.com/app/apikey) - - [Groq](https://console.groq.com/keys) - - - - Prepend `https://api.supermemory.ai/v3/` to your provider's URL: - - ``` - https://api.supermemory.ai/v3/[PROVIDER_URL] - ``` - - - - Include both API keys in your requests (see examples below) - - - -## Provider URLs - - - -```text OpenAI -https://api.supermemory.ai/v3/https://api.openai.com/v1/ -``` - -```text Anthropic -https://api.supermemory.ai/v3/https://api.anthropic.com/v1/ -``` - -```text Google Gemini -https://api.supermemory.ai/v3/https://generativelanguage.googleapis.com/v1beta/openai/ -``` - -```text Groq -https://api.supermemory.ai/v3/https://api.groq.com/openai/v1/ -``` - - - -## Implementation Examples - - - - ```python - from openai import OpenAI - - client = OpenAI( - api_key="YOUR_OPENAI_API_KEY", - base_url="https://api.supermemory.ai/v3/https://api.openai.com/v1/", - default_headers={ - "x-supermemory-api-key": "YOUR_SUPERMEMORY_API_KEY", - "x-sm-user-id": "user123" # Unique user identifier - } - ) - - # Use as normal - response = client.chat.completions.create( - model="gpt-5", - messages=[ - {"role": "user", "content": "Hello!"} - ] - ) - - print(response.choices[0].message.content) - ``` - - - - ```typescript - import OpenAI from 'openai'; - - const client = new OpenAI({ - apiKey: process.env.OPENAI_API_KEY, - baseURL: 'https://api.supermemory.ai/v3/https://api.openai.com/v1/', - defaultHeaders: { - 'x-supermemory-api-key': process.env.SUPERMEMORY_API_KEY, - 'x-sm-user-id': 'user123' // Unique user identifier - } - }); - - // Use as normal - const response = await client.chat.completions.create({ - model: 'gpt-5', - messages: [ - { role: 'user', content: 'Hello!' } - ] - }); - - console.log(response.choices[0].message.content); - ``` - - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/https://api.openai.com/v1/chat/completions" \ - -H "Authorization: Bearer YOUR_OPENAI_API_KEY" \ - -H "x-supermemory-api-key: YOUR_SUPERMEMORY_API_KEY" \ - -H "x-sm-user-id: user123" \ - -H "Content-Type: application/json" \ - -d '{ - "model": "gpt-5", - "messages": [{"role": "user", "content": "Hello!"}] - }' - ``` - - - -## Alternative: URL Parameters - -If you can't modify headers, pass authentication via URL parameters: - - - -```python Python -client = OpenAI( - api_key="YOUR_OPENAI_API_KEY", - base_url="https://api.supermemory.ai/v3/https://api.openai.com/v1/chat/completions?userId=user123" -) - -# Then set Supermemory API key as environment variable: -# export SUPERMEMORY_API_KEY="your_key_here" -``` - -```typescript TypeScript -const client = new OpenAI({ - apiKey: process.env.OPENAI_API_KEY, - baseURL: 'https://api.supermemory.ai/v3/https://api.openai.com/v1/chat/completions?userId=user123' -}); - -// Set Supermemory API key as environment variable: -// SUPERMEMORY_API_KEY="your_key_here" -``` - -```bash cURL -curl -X POST "https://api.supermemory.ai/v3/https://api.openai.com/v1/chat/completions?userId=user123" \ - -H "Authorization: Bearer YOUR_OPENAI_API_KEY" \ - -H "x-supermemory-api-key: YOUR_SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"model": "gpt-5", "messages": [{"role": "user", "content": "Hello!"}]}' -``` - - - -## Conversation Management - -### Managing Conversations - -Use `x-sm-conversation-id` to maintain conversation context across requests: - -```python -# Start a new conversation -response1 = client.chat.completions.create( - model="gpt-5", - messages=[{"role": "user", "content": "My name is Alice"}], - extra_headers={ - "x-sm-conversation-id": "conv_123" - } -) - -# Continue the same conversation later -response2 = client.chat.completions.create( - model="gpt-5", - messages=[{"role": "user", "content": "What's my name?"}], - extra_headers={ - "x-sm-conversation-id": "conv_123" - } -) -# Response will remember "Alice" -``` - -### User Identification - -Always provide a unique user ID to isolate memories between users: - -```python -# Different users have separate memory spaces -client_alice = OpenAI( - api_key="...", - base_url="...", - default_headers={"x-sm-user-id": "alice_123"} -) - -client_bob = OpenAI( - api_key="...", - base_url="...", - default_headers={"x-sm-user-id": "bob_456"} -) -``` diff --git a/apps/docs/memory-router/with-memory-api.mdx b/apps/docs/memory-router/with-memory-api.mdx deleted file mode 100644 index e93705ea..00000000 --- a/apps/docs/memory-router/with-memory-api.mdx +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: "Use with Memory API" -description: "Combine the Memory Router with Memory API for maximum control" -sidebarTitle: "Use with Memory API" ---- - -The Memory Router and Memory API share the same memory pool. When you use the same `user_id`, memories are automatically shared between both systems. - -## How They Work Together - - -**Key Insight**: Both the Router and API access the same memories when using identical `user_id` values. This enables powerful hybrid implementations. - - -### Shared Memory Pool - -```python -# Memory created via API -from supermemory import Client - -api_client = Client(api_key="YOUR_SUPERMEMORY_KEY") - -# Add memory via API -api_client.add({ - "content": "User prefers Python over JavaScript for backend development", - "user_id": "user123" -}) - -# Later, in your chat application using Router -from openai import OpenAI - -router_client = OpenAI( - api_key="YOUR_OPENAI_KEY", - base_url="https://api.supermemory.ai/v3/https://api.openai.com/v1/", - default_headers={ - "x-supermemory-api-key": "YOUR_SUPERMEMORY_KEY", - "x-sm-user-id": "user123" # Same user_id - } -) - -# Router automatically has access to the API-created memory -response = router_client.chat.completions.create( - model="gpt-5", - messages=[{"role": "user", "content": "What language should I use for my new backend?"}] -) -# Response will consider the Python preference -``` - -## Pre-load Context via API - -Use the API to add documents and context before conversations: - -```python -# Step 1: Load user's documents via API -api_client.add({ - "content": "https://company.com/product-docs.pdf", - "user_id": "support_agent_123", - "metadata": {"type": "product_documentation"} -}) - -# Step 2: Support agent uses chat with Router -router_client = OpenAI( - base_url="https://api.supermemory.ai/v3/https://api.openai.com/v1/", - default_headers={"x-sm-user-id": "support_agent_123"} -) - -# Agent has automatic access to product docs -response = router_client.chat.completions.create( - model="gpt-5", - messages=[{"role": "user", "content": "How does the enterprise pricing work?"}] -) -``` - - -## Best Practices - -### 1. Consistent User IDs - -Always use the same `user_id` format across both systems: - -```python -# ✅ Good - consistent user_id -api_client.add({"user_id": "user_123"}) -router_headers = {"x-sm-user-id": "user_123"} - -# ❌ Bad - inconsistent user_id -api_client.add({"user_id": "user-123"}) -router_headers = {"x-sm-user-id": "user_123"} # Different format! -``` - -### 2. Use Container Tags for Organization - -```python -# API: Add memories with tags -api_client.add({ - "content": "Q3 revenue report", - "user_id": "analyst_1", - "containerTag": "financial_reports" -}) - -# Router: Memories are automatically organized -# The Router will intelligently retrieve from the right containers -``` - -### 3. Leverage Each System's Strengths - -| Use Case | Best Choice | Why | -|----------|------------|-----| -| Chat conversations | Router | Automatic context management | -| Document upload | API | Batch processing, custom IDs | -| Search & filter | API | Advanced query capabilities | -| Quick prototypes | Router | Zero code changes | -| Memory management | API | Full CRUD operations | diff --git a/apps/docs/memorybench/architecture.mdx b/apps/docs/memorybench/architecture.mdx deleted file mode 100644 index 6a37df6a..00000000 --- a/apps/docs/memorybench/architecture.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: "Architecture" -description: "Understanding MemoryBench's design and implementation" -sidebarTitle: "Architecture" ---- - -## System Overview - -```mermaid -flowchart TB - B["Benchmarks
(LoCoMo, LongMemEval..)"] - P["Providers
(Supermemory, Mem0, Zep)"] - J["Judges
(GPT-4o, Claude..)"] - - B --> O[Orchestrator] - P --> O - J --> O - - O --> Pipeline - - subgraph Pipeline[" "] - direction LR - I[Ingest] --> IX[Indexing] --> S[Search] --> A[Answer] --> E[Evaluate] - end - - style B fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style P fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style J fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style O fill:#0369A1,stroke:#0369A1,color:#fff - style I fill:#F1F5F9,stroke:#64748B,color:#334155 - style IX fill:#F1F5F9,stroke:#64748B,color:#334155 - style S fill:#F1F5F9,stroke:#64748B,color:#334155 - style A fill:#F1F5F9,stroke:#64748B,color:#334155 - style E fill:#F1F5F9,stroke:#64748B,color:#334155 -``` - -## Core Components - -| Component | Role | -|-----------|------| -| **Benchmarks** | Load test data and provide questions with ground truth answers | -| **Providers** | Memory services being evaluated (handle ingestion and search) | -| **Judges** | LLM-based evaluators that score answers against ground truth | - -See [Integrations](/memorybench/integrations) for all supported benchmarks, providers, and models. - -## Pipeline - -```mermaid -flowchart LR - A[Ingest] --> B[Index] --> C[Search] --> D[Answer] --> E[Evaluate] --> F[Report] - - style A fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style B fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style C fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style D fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style E fill:#E0F2FE,stroke:#0369A1,color:#0C4A6E - style F fill:#DCFCE7,stroke:#16A34A,color:#166534 -``` - -| Phase | What Happens | -|-------|--------------| -| **Ingest** | Load benchmark sessions → Push to provider | -| **Index** | Wait for provider indexing | -| **Search** | Query provider → Retrieve context | -| **Answer** | Build prompt → Generate answer via LLM | -| **Evaluate** | Compare to ground truth → Score via judge | -| **Report** | Aggregate scores → Output accuracy, latency, token metrics, and [MemScore](/memorybench/memscore) | - -Each phase checkpoints independently. Failed runs resume from last successful point. - -## Advanced Checkpointing - -Runs persist to `data/runs/{runId}/`: - -``` -data/runs/my-run/ -├── checkpoint.json # Run state and progress -├── results/ # Search results per question -└── report.json # Final report -``` - -Re-running same ID resumes. Use `--force` to restart. - -## File Structure - -``` -src/ -├── cli/commands/ # run, compare, test, serve, status... -├── orchestrator/phases/ # ingest, search, answer, evaluate, report -├── benchmarks/ -│ └── /index.ts # e.g. locomo/, longmemeval/, convomem/ -├── providers/ -│ └── / -│ ├── index.ts # Provider implementation -│ └── prompts.ts # Custom prompts (optional) -├── judges/ # openai.ts, anthropic.ts, google.ts -└── types/ # provider.ts, benchmark.ts, unified.ts -``` diff --git a/apps/docs/memorybench/cli.mdx b/apps/docs/memorybench/cli.mdx deleted file mode 100644 index 3ab5c503..00000000 --- a/apps/docs/memorybench/cli.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: "CLI Reference" -description: "Command-line interface for running MemoryBench evaluations" -sidebarTitle: "CLI" ---- - -## Commands - -### run - -Execute the full benchmark pipeline. - -```bash -bun run src/index.ts run -p -b -j -r -``` - -| Option | Description | -|--------|-------------| -| `-p, --provider` | Memory provider (`supermemory`, `mem0`, `zep`) | -| `-b, --benchmark` | Benchmark (`locomo`, `longmemeval`, `convomem`) | -| `-j, --judge` | Judge model (default: `gpt-4o`) | -| `-r, --run-id` | Run identifier (auto-generated if omitted) | -| `-m, --answering-model` | Model for answer generation (default: `gpt-4o`) | -| `-l, --limit` | Limit number of questions | -| `-s, --sample` | Sample N questions per category | -| `--sample-type` | Sampling strategy: `consecutive` (default), `random` | -| `--force` | Clear checkpoint and restart | - -See [Supported Models](/memorybench/supported-models) for all available judge and answering models. - ---- - -### compare - -Run benchmark across multiple providers in parallel. - -```bash -bun run src/index.ts compare -p supermemory,mem0,zep -b locomo -j gpt-4o -``` - ---- - -### test - -Evaluate a single question for debugging. - -```bash -bun run src/index.ts test -r -q -``` - ---- - -### status - -Check progress of a run. - -```bash -bun run src/index.ts status -r -``` - ---- - -### show-failures - -Debug failed questions with full context. - -```bash -bun run src/index.ts show-failures -r -``` - ---- - -### list-questions - -Browse benchmark questions. - -```bash -bun run src/index.ts list-questions -b -``` - ---- - -### Random Sampling - -Sample N questions per category with optional randomization. - -```bash -bun run src/index.ts run -p supermemory -b longmemeval -s 3 --sample-type random -``` - ---- - -### serve - -Start the web UI. - -```bash -bun run src/index.ts serve -``` - -Opens at [http://localhost:3000](http://localhost:3000). - ---- - -### help - -Get help on providers, models, or benchmarks. - -```bash -bun run src/index.ts help providers -bun run src/index.ts help models -bun run src/index.ts help benchmarks -``` - -## Checkpointing - -Runs are saved to `data/runs/{runId}/` and automatically resume from the last successful phase. Use `--force` to restart. diff --git a/apps/docs/memorybench/contributing.mdx b/apps/docs/memorybench/contributing.mdx deleted file mode 100644 index 2f8e45e2..00000000 --- a/apps/docs/memorybench/contributing.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "Contributing" -description: "Guidelines for contributing to MemoryBench" -sidebarTitle: "Contributing" ---- - -## Getting Started - -1. Fork the repository -2. Clone your fork: - ```bash - git clone https://github.com/YOUR_USERNAME/memorybench - cd memorybench - bun install - ``` -3. Create a branch: - ```bash - git checkout -b feature/your-feature - ``` - -## Development Workflow - -### Running Tests - -```bash -bun test -``` - -### Running the CLI - -```bash -bun run src/index.ts -``` - -### Running the Web UI - -```bash -cd ui -bun run dev -``` - -## Code Structure - -| Directory | Purpose | -|-----------|---------| -| `src/cli/` | CLI commands | -| `src/orchestrator/` | Pipeline execution | -| `src/benchmarks/` | Benchmark adapters | -| `src/providers/` | Provider integrations | -| `src/judges/` | LLM judge implementations | -| `src/types/` | TypeScript interfaces | -| `ui/` | Next.js web interface | - -## Contribution Types - -### Adding a Provider - -See [Extending MemoryBench](/memorybench/extend-provider) for the full guide. - -1. Create `src/providers/yourprovider/index.ts` -2. Implement the `Provider` interface -3. Register in `src/providers/index.ts` -4. Add config in `src/utils/config.ts` -5. Submit PR with tests - -### Adding a Benchmark - -1. Create `src/benchmarks/yourbenchmark/index.ts` -2. Implement the `Benchmark` interface -3. Register in `src/benchmarks/index.ts` -4. Document question types -5. Submit PR with sample data - -### Bug Fixes - -1. Create an issue describing the bug -2. Reference the issue in your PR -3. Include test cases that reproduce the bug - -## Pull Request Guidelines - -- Keep PRs focused on a single change -- Update documentation if needed -- Ensure all tests pass -- Follow existing code style - -## Questions? - -Open an issue on [GitHub](https://github.com/supermemoryai/memorybench/issues). diff --git a/apps/docs/memorybench/extend-benchmark.mdx b/apps/docs/memorybench/extend-benchmark.mdx index c66cf4d9..231cbb9c 100644 --- a/apps/docs/memorybench/extend-benchmark.mdx +++ b/apps/docs/memorybench/extend-benchmark.mdx @@ -1,10 +1,27 @@ --- -title: "Extend Benchmark" -description: "Add a custom benchmark dataset to MemoryBench" -sidebarTitle: "Extend Benchmark" +title: "Building a Benchmark" +description: "Add a custom benchmark dataset when the built-in ones don't match your use case" +sidebarTitle: "Building a Benchmark" +icon: "flask-conical" --- -## Benchmark Interface +MemoryBench ships with three datasets — [LoCoMo](https://github.com/snap-research/locomo), [LongMemEval](https://huggingface.co/datasets/xiaowu0162/longmemeval-cleaned), and [ConvoMem](https://huggingface.co/datasets/Salesforce/ConvoMem) — but they won't cover every product. If your agent has a workflow the built-in benchmarks don't exercise (a specific domain, a scenario your users actually hit, a regression you want to guard against), you can add your own benchmark dataset and every provider — including Supermemory — runs against it the same way. + +## Choosing between the built-in datasets + +Before building your own, check whether one of the existing datasets already covers what you need: + +| Benchmark | Best for | Primary challenge | +|---|---|---| +| **LoCoMo** | Personal assistants, support bots — anything with recurring sessions over days/weeks | Temporal context, cross-session recall | +| **LongMemEval** | RAG / document search, knowledge bases | Information density, precise retrieval, synthesis | +| **ConvoMem** | Dialogue systems, interview bots, meeting assistants | Reference resolution within a single conversation | + +You can also run all three to get a full picture of where a memory system is strong or weak — a system that's great at LoCoMo but weak at LongMemEval is good at temporal recall but struggles with dense information retrieval, for example. + +## The Benchmark interface + +Every dataset — built-in or custom — implements the same interface (`src/types/benchmark.ts`): ```typescript interface Benchmark { @@ -17,59 +34,48 @@ interface Benchmark { } ``` +Sessions — the raw conversational data a provider ingests before being asked a question — are normalized to a single shape regardless of benchmark: + +```typescript +interface UnifiedSession { + sessionId: string + messages: Array<{ role: "user" | "assistant"; content: string }> + metadata?: { + date?: string // ISO format + formattedDate?: string // human readable + [key: string]: any + } +} +``` + +## Adding your own benchmark + +1. Create `src/benchmarks/mybenchmark/index.ts` implementing the `Benchmark` interface above +2. `load()` parses your dataset (JSON, CSV, whatever you have) into `UnifiedSession`s and questions +3. `getQuestions()` returns your question set, each with a ground-truth answer and a question type +4. Register it in `src/benchmarks/index.ts` and add the name to `BenchmarkName` in `src/types/benchmark.ts` +5. Run it exactly like a built-in benchmark: + +```bash +bun run src/index.ts run -p supermemory -b mybenchmark +bun run src/index.ts compare -p supermemory,mem0,zep -b mybenchmark +``` + +Question types are your own vocabulary — group questions however matters to your product (`billing_history`, `escalation_context`, `preference_drift`, etc.), and the final report breaks accuracy down per type so you can see exactly where a provider is strong or weak on *your* scenarios, not a generic academic one. + + +Full interface details and a working template: [`src/benchmarks/README.md`](https://github.com/supermemoryai/memorybench/blob/main/src/benchmarks/README.md) in the repo. + + --- -## Adding a Custom Benchmark +## Next -### 1. Create the Benchmark - -```typescript -// src/benchmarks/mybenchmark/index.ts -import type { Benchmark, UnifiedQuestion, UnifiedSession } from "../../types" - -export class MyBenchmark implements Benchmark { - name = "mybenchmark" - private questions: UnifiedQuestion[] = [] - private sessions: Map = new Map() - - async load() { - const data = await this.loadDataset() - this.processData(data) - } - - getQuestions(filter?: QuestionFilter) { - let result = [...this.questions] - if (filter?.limit) result = result.slice(0, filter.limit) - return result - } - - getHaystackSessions(questionId: string) { - return this.sessions.get(questionId) || [] - } - - getGroundTruth(questionId: string) { - return this.questions.find(q => q.questionId === questionId)?.groundTruth || "" - } - - getQuestionTypes() { - return { - "type1": { id: "type1", description: "Type 1 questions" }, - "type2": { id: "type2", description: "Type 2 questions" }, - } - } -} -``` - -### 2. Register the Benchmark - -```typescript -// src/benchmarks/index.ts -import { MyBenchmark } from "./mybenchmark" - -export const benchmarks = { - locomo: LoComoBenchmark, - longmemeval: LongMemEvalBenchmark, - convomem: ConvoMemBenchmark, - mybenchmark: MyBenchmark, // Add here -} -``` + + + Register a memory system to run against your new benchmark. + + + How accuracy, latency, and MemScore are computed. + + diff --git a/apps/docs/memorybench/extend-provider.mdx b/apps/docs/memorybench/extend-provider.mdx index f3fec92e..2e7f3a6f 100644 --- a/apps/docs/memorybench/extend-provider.mdx +++ b/apps/docs/memorybench/extend-provider.mdx @@ -1,10 +1,44 @@ --- -title: "Extend Provider" -description: "Add a custom memory provider to MemoryBench" -sidebarTitle: "Extend Provider" +title: "Adding a Provider" +description: "Register your own memory implementation so MemoryBench can score and compare it" +sidebarTitle: "Adding a Provider" +icon: "plug" --- -## Provider Interface +A "provider" in MemoryBench is any memory or RAG system that can ingest sessions and answer a search query — Supermemory, Mem0, and Zep ship as built-in providers, and **your own memory implementation is just another provider**. Once it's registered, it runs through the exact same pipeline and gets scored on the exact same footing as everything else. + +There are two ways to do this: let the skill generate the provider for you, or write it by hand. + +## The fast path: the MemoryBench skill + +MemoryBench ships a Claude Code skill (`benchmark-context`) that automates the whole flow — from reading your code to a finished comparison report — without you writing any MemoryBench-specific code yourself. + +```bash +# Run from your project root, not from inside memorybench +/memorybench +``` + +It walks through 7 phases: + +| Phase | What happens | +|---|---| +| **1. Setup** | Clones `memorybench` into `./memorybench` and installs dependencies | +| **2. Discovery** | An agent reads your memory code to find its init, ingest, and search methods | +| **3. Code generation** | Generates a provider adapter implementing the `Provider` interface, adapted to your code | +| **4. Registration** | Registers the provider in the framework's types and config | +| **5. Configuration** | Asks for your API keys (your provider, any comparison providers, and a judge model) and writes `.env.local` | +| **6. Validation** | Runs one question end-to-end to confirm ingest/search actually work before committing to a full run | +| **7. Benchmark execution** | Runs the full comparison and reports accuracy, latency, and context-token results side by side | + +Before it does anything, it asks 5 quick questions: your provider's name, where your memory code lives, which [benchmark](/memorybench/extend-benchmark) to run, which providers to compare against (Supermemory, Mem0, Zep, or the no-API-key `filesystem`/`rag` baselines), and how many questions to sample (5 for a quick check, 20 for a real signal, or the full set). + + +Run it from **your project's root**, not from inside `memorybench` — the skill clones the framework as a subdirectory and analyzes your code via relative paths. + + +## Doing it by hand + +If you'd rather write the adapter yourself, every provider implements the same interface (`src/types/provider.ts`): ```typescript interface Provider { @@ -18,101 +52,41 @@ interface Provider { } ``` ---- +| Method | Responsibility | +|---|---| +| `initialize()` | Set up your client with an API key / config | +| `ingest()` | Push benchmark sessions into your system, return the resulting document IDs | +| `awaitIndexing()` | Block until those documents are actually searchable — a no-op if your system indexes synchronously, a poll loop with backoff if it's async | +| `search()` | Run a query, return results in whatever shape your system returns them | +| `clear()` | Delete everything under a `containerTag`, so runs don't bleed into each other | -## Adding a Custom Provider +Steps: -### 1. Create the Provider +1. Create `src/providers/myprovider/index.ts` implementing `Provider` +2. Register it in `src/providers/index.ts` +3. Add the name to `ProviderName` in `src/types/provider.ts` +4. Add its config (API key, base URL, etc.) in `src/utils/config.ts` +5. Optionally override `prompts` (`ProviderPrompts`) if your search results need custom formatting before they're handed to the answering LLM or the judge -```typescript -// src/providers/myprovider/index.ts -import type { Provider, ProviderConfig, UnifiedSession } from "../../types" - -export class MyProvider implements Provider { - name = "myprovider" - private client: MyClient | null = null - - async initialize(config: ProviderConfig) { - this.client = new MyClient({ apiKey: config.apiKey }) - } - - async ingest(sessions: UnifiedSession[], options: IngestOptions) { - const documentIds: string[] = [] - for (const session of sessions) { - const response = await this.client.add({ - content: JSON.stringify(session.messages), - metadata: session.metadata - }) - documentIds.push(response.id) - } - return { documentIds } - } - - async awaitIndexing(result: IngestResult) { - // Poll until indexing complete - } - - async search(query: string, options: SearchOptions) { - return await this.client.search({ q: query, limit: 10 }) - } - - async clear(containerTag: string) { - await this.client.delete(containerTag) - } -} +```bash +bun run src/index.ts test -p myprovider -b locomo -q question_1 # one question, fast sanity check +bun run src/index.ts run -p myprovider -b locomo # full run +bun run src/index.ts compare -p myprovider,supermemory,mem0 -b locomo -l 20 ``` -### 2. Register the Provider - -```typescript -// src/providers/index.ts -import { MyProvider } from "./myprovider" - -export const providers = { - supermemory: SupermemoryProvider, - mem0: Mem0Provider, - zep: ZepProvider, - myprovider: MyProvider, // Add here -} -``` - -### 3. Add Configuration - -```typescript -// src/utils/config.ts -case "myprovider": - return { - apiKey: process.env.MYPROVIDER_API_KEY!, - } -``` + +Full interface, including async-indexing and custom-prompt examples: [`src/providers/README.md`](https://github.com/supermemoryai/memorybench/blob/main/src/providers/README.md) in the repo. + --- -## Custom Prompts +## Next -Providers can define custom answer and judge prompts for better results. - -```typescript -// src/providers/myprovider/prompts.ts -export const MY_PROMPTS: ProviderPrompts = { - answerPrompt: (question, context, questionDate) => { - return `Based on context:\n${context}\n\nAnswer: ${question}` - }, - - judgePrompt: (question, groundTruth, hypothesis) => ({ - default: "Compare answer to ground truth...", - temporal: "Allow off-by-one for dates...", - adversarial: "Check if model correctly abstained...", - }) -} -``` - -Then reference in your provider: - -```typescript -export class MyProvider implements Provider { - name = "myprovider" - prompts = MY_PROMPTS // Custom prompts - // ... -} -``` + + + Run your provider against a dataset built for your own use case. + + + What the report actually tells you. + + diff --git a/apps/docs/memorybench/github.mdx b/apps/docs/memorybench/github.mdx deleted file mode 100644 index 34468d21..00000000 --- a/apps/docs/memorybench/github.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "MemoryBench on GitHub" -url: "https://github.com/supermemoryai/memorybench" -icon: github ---- diff --git a/apps/docs/memorybench/installation.mdx b/apps/docs/memorybench/installation.mdx deleted file mode 100644 index ef21cac8..00000000 --- a/apps/docs/memorybench/installation.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: "Installation" -description: "Get MemoryBench up and running in your environment" -sidebarTitle: "Installation" ---- - -## Prerequisites - -- [Bun](https://bun.sh) runtime installed -- API keys for providers and LLM judges you want to use - -## Install MemoryBench - -```bash -git clone https://github.com/supermemoryai/memorybench -cd memorybench -bun install -``` - -## Configure API Keys - -Create a `.env.local` file in the root directory: - -```bash -# Memory Providers (add keys for providers you want to test) -SUPERMEMORY_API_KEY=your_key -MEM0_API_KEY=your_key -ZEP_API_KEY=your_key - -# LLM Judges (at least one required) -OPENAI_API_KEY=your_key -ANTHROPIC_API_KEY=your_key -GOOGLE_API_KEY=your_key -``` - - -You only need API keys for the providers and judges you plan to use. For example, to benchmark Supermemory with GPT-4o as judge, you only need `SUPERMEMORY_API_KEY` and `OPENAI_API_KEY`. - - -## Verify Installation - -```bash -bun run src/index.ts help -``` - -You should see the list of available commands. - -## Start the Web Interface - -```bash -bun run src/index.ts serve -``` - -Opens at [http://localhost:3000](http://localhost:3000). - -## Next Steps - -- [CLI Reference](/memorybench/cli) - Play around with MemoryBench -- [Architecture](/memorybench/architecture) - Understand how MemoryBench works -- [Extend MemoryBench](/memorybench/extend-provider) - Add custom providers, benchmarks, and prompts diff --git a/apps/docs/memorybench/integrations.mdx b/apps/docs/memorybench/integrations.mdx deleted file mode 100644 index e4532d50..00000000 --- a/apps/docs/memorybench/integrations.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "Integrations" -description: "Supported benchmarks and providers in MemoryBench" -sidebarTitle: "Integrations" ---- - -## Benchmarks - -| Benchmark | Description | Source | Categories | -|-----------|-------------|--------|------------| -| LoCoMo | Long context memory testing fact recall across extended conversations | [snap-research/locomo](https://github.com/snap-research/locomo) | `single-hop`, `multi-hop`, `temporal`, `world-knowledge`, `adversarial` | -| LongMemEval | Long-term memory evaluation across multiple sessions with knowledge updates | [xiaowu0162/longmemeval](https://huggingface.co/datasets/xiaowu0162/longmemeval-cleaned) | `single-session-user`, `single-session-assistant`, `multi-session`, `temporal-reasoning`, `knowledge-update` | -| ConvoMem | Conversational memory focused on personalization and preference learning | [Salesforce/ConvoMem](https://huggingface.co/datasets/Salesforce/ConvoMem) | `user_evidence`, `assistant_facts_evidence`, `preference_evidence`, `changing_evidence`, `abstention_evidence` | - - -We're actively adding support for more benchmarks. [Contribute your own](/memorybench/extend-benchmark) or [create a feature request](https://github.com/supermemoryai/memorybench/issues). - - ---- - -## Providers - - - - Chunk-based semantic search - - - - LLM-powered memory extraction - - - - Knowledge graph construction - - - - -We're actively adding support for more providers. [Contribute your own](/memorybench/extend-provider) or [create a feature request](https://github.com/supermemoryai/memorybench/issues). - diff --git a/apps/docs/memorybench/memscore.mdx b/apps/docs/memorybench/memscore.mdx index f94f2062..4335dc55 100644 --- a/apps/docs/memorybench/memscore.mdx +++ b/apps/docs/memorybench/memscore.mdx @@ -1,120 +1,91 @@ --- -title: "MemScore" -description: "A composite metric for comparing memory providers across quality, latency, and token efficiency" +title: "Measuring Results" +description: "How MemoryBench scores a run — qualitative judging and quantitative metrics" +sidebarTitle: "Measuring" +icon: "gauge" --- -## What is MemScore? +Every question goes through the same pipeline — **ingest → search → answer → evaluate → report** — and produces two different kinds of signal: a **qualitative** judgment on whether the answer was actually right, and **quantitative** measurements of how fast and how expensive getting there was. MemoryBench keeps both instead of collapsing everything into a single number. -MemScore is a composite metric that captures three dimensions of memory provider performance in a single line: +## Qualitative: was the answer right? -``` -accuracy% / latencyMs / contextTok +Correctness isn't decided by string matching — a **judge LLM** (GPT-4o, Claude Sonnet, or Gemini Flash, your choice) compares the provider's answer against ground truth and returns a verdict: + +```typescript +{ score: 0 | 1, label: "correct" | "incorrect", explanation: string } ``` -For example: - -``` -85% / 120ms / 1500tok -``` - -This tells you the provider achieved **85% accuracy**, with an average search latency of **120ms**, sending **1,500 tokens** of context to the answering model per question. - -## Components - -| Component | What it measures | Source | -|-----------|-----------------|--------| -| **Quality** | Answer accuracy as a percentage | `(correct / total) * 100` from judge evaluations | -| **Latency** | Average search response time in milliseconds | Mean of all search phase durations | -| **Tokens** | Average context tokens sent to the answering model | Client-side token count of retrieved context per question | - - -MemScore is not a single number — it's a triple. This is intentional. Collapsing quality, latency, and cost into one score hides important tradeoffs. A provider with 90% accuracy at 5,000 tokens is very different from one with 90% accuracy at 500 tokens. - - -## How token counting works - -MemoryBench counts tokens client-side using provider-specific tokenizers: - -| Model provider | Tokenizer | Method | -|----------------|-----------|--------| -| **OpenAI** | `js-tiktoken` | Exact count using `o200k_base` or `cl100k_base` encoding | -| **Anthropic** | `@anthropic-ai/tokenizer` | Exact count using Anthropic's tokenizer | -| **Google** | Approximation | `Math.ceil(text.length / 4)` | - -Three token values are tracked per question: - -- **`promptTokens`** — Total tokens in the full prompt (instructions + context + question) -- **`basePromptTokens`** — Tokens in the prompt without any retrieved context -- **`contextTokens`** — Tokens in just the retrieved context string - -The MemScore uses `contextTokens` because it isolates what the memory provider actually contributed. - -## Where MemScore appears - -### CLI output - -After a benchmark run completes, MemScore is printed in the summary: - -``` -SUMMARY: - Total Questions: 50 - Correct: 43 - Accuracy: 86.00% - - Quality: 86% - Latency: 145ms (avg) - Tokens: 1,823 (avg context sent to answering model) - - MemScore: 86% / 145ms / 1823tok -``` - -### Web UI - -The MemScore card appears at the top of the run overview page. Per-question token counts are shown next to each model answer in both the question list and detail views. - -### Report JSON - -The `report.json` file includes both a display string and structured components: - -```json -{ - "memscore": "86% / 145ms / 1823tok", - "memscoreComponents": { - "quality": 86, - "latencyMs": 145, - "contextTokens": 1823 - }, - "tokens": { - "totalTokens": 142500, - "basePromptTokens": 21000, - "contextTokens": 91150, - "avgTokensPerQuestion": 2850, - "avgBasePromptTokens": 420, - "avgContextTokens": 1823 - } -} -``` - -Use `memscoreComponents` for programmatic comparisons — it avoids parsing the display string. - -## Comparing providers - -MemScore is most useful when comparing providers on the same benchmark: +The judge is judge-agnostic on purpose — score the same run with two different judges if you want to sanity-check that a result isn't an artifact of one model's grading bias. The prompt the judge uses can also vary by question type (temporal questions get graded differently than abstention questions, for example), and providers can supply their own judge prompts if their answers need custom framing. ```bash -bun run src/index.ts compare -p supermemory,mem0,zep -b locomo -j gpt-4o +# Grade a run with a different judge +bun run src/index.ts run -p supermemory -b locomo -j sonnet-4 ``` -Each provider's report will include its own MemScore, making it easy to see tradeoffs at a glance: +## Quantitative: how fast, how much -| Provider | MemScore | -|----------|----------| -| Provider A | `88% / 145ms / 1200tok` | -| Provider B | `82% / 80ms / 2400tok` | -| Provider C | `85% / 110ms / 1800tok` | +Alongside the correctness verdict, every question also records hard numbers: -In this example, Provider A has the highest accuracy but the slowest search. Provider B is the fastest but sends the most context without achieving the best accuracy — suggesting its retrieval may be less precise. Provider C lands in the middle on all three axes. There's no single "winner" — the right choice depends on whether you prioritize quality, speed, or token efficiency. +| Metric | What it measures | +|---|---| +| **Accuracy** | Judge score (0–1) averaged across all questions, and broken down per question type | +| **Latency** | Search time and answer-generation time per question (p50 / p95 across a run) | +| **Context tokens** | How much context was sent to the answering model — a proxy for retrieval cost | +| **Success rate** | Percentage of questions that completed without erroring (failures are excluded from accuracy, not counted against it) | -## Backward compatibility +## MemScore -Runs from before MemScore was added will still work. If token data is not present in the checkpoint, the `memscore`, `memscoreComponents`, and `tokens` fields will be `undefined` in the report. The CLI and web UI gracefully skip the MemScore display when data is unavailable. +The report doesn't reduce these to one score. **MemScore** reports the three that matter for a production decision side by side: + +``` +MemScore: 86% / 145ms / 1823tok + ▲ ▲ ▲ + │ │ └─ context tokens sent to the answering model (cost) + │ └───────── search latency + └─────────────── answer accuracy vs. ground truth +``` + +A provider that's 2% more accurate but 5x slower and 3x more expensive in context tokens isn't unambiguously "better" — MemScore leaves that trade-off to you instead of picking weights for you. + +## Reading the numbers + +Rough bands, from running MemoryBench across the built-in benchmarks: + +| Accuracy | Read | +|---|---| +| 80%+ | Excellent, production-ready | +| 70–80% | Good, some room to improve | +| 60–70% | Adequate, likely needs tuning | +| `<60%` | Investigate — retrieval, prompts, or indexing likely need work | + +| Search latency | Read | +|---|---| +| `<100ms` | Excellent (vector-search level) | +| 100–300ms | Good, typical API latency | +| 300–500ms | Adequate for most use cases | +| `>500ms` | Slow — worth optimizing | + +Per-question-type breakdowns are usually more useful than the headline number: strong on LoCoMo but weak on LongMemEval means good temporal/cross-session recall but weak dense-retrieval; the reverse means the opposite. That's what tells you what to actually go fix. + +## Digging into a specific run + +```bash +bun run src/index.ts status -r my-run # progress / summary +bun run src/index.ts show-failures -r my-run # full context on what got graded wrong +bun run src/index.ts serve # web UI at localhost:3000 for visual inspection +``` + +Results and checkpoints for every run live at `data/runs/{runId}/report.json`, with per-question-type accuracy, latency percentiles, and per-question token counts. + +--- + +## Next + + + + Get your own system into a run that produces these numbers. + + + Measure against scenarios specific to your product. + + diff --git a/apps/docs/memorybench/overview.mdx b/apps/docs/memorybench/overview.mdx index 0e0bd11e..1de18701 100644 --- a/apps/docs/memorybench/overview.mdx +++ b/apps/docs/memorybench/overview.mdx @@ -1,57 +1,86 @@ --- title: "MemoryBench" -description: "Open-source framework for standardized, reproducible benchmarks of memory layer providers" +description: "Open-source framework for benchmarking memory providers — including your own" sidebarTitle: "Overview" icon: "flask-conical" --- -Our goal is to make evaluation more rigorous, accessible, and in line with industry standards. Design and run evaluations tailored to your specific needs, and run industry-standard benchmarks easily on any memory provider. With MemoryBench, you can trust in provider through transparent, reproducible, and domain-relevant evaluations. +Benchmarking memory systems is hard, and most comparisons you'll find aren't apples-to-apples — different datasets, different judges, different prompts, cherry-picked runs. **MemoryBench** ([`supermemoryai/memorybench`](https://github.com/supermemoryai/memorybench), MIT licensed) is the open-source framework we built to fix that: the same benchmark questions, the same pipeline, and the same judges run against every provider, so a comparison actually means something. - - -
- ```bun run src/index.ts serve``` -
+We open-sourced it so you don't have to take our word for anything — you can run it yourself, against your own memory implementation, on the datasets that match your use case. - - Get MemoryBench up and running in your environment - + + Clone it, run it against your own data, or read the source for exactly how each provider is scored. + - - Command-line interface for running evaluations - +--- - - Understanding MemoryBench's design and implementation - +## Benchmark your own memory system - - Composite metric for comparing quality, latency, and token efficiency - -
+MemoryBench ships a **Claude Code skill** that automates the entire process of benchmarking a custom memory implementation — yours — against Supermemory, Mem0, and Zep. Point it at your code and it handles discovery, integration, and the run: -## Works with any memory provider +1. Asks a few questions about your setup (provider name, where your memory code lives, which benchmark, which competitors, how many questions) +2. Analyzes your memory code to find its init, ingest, and search methods +3. Generates a provider adapter and registers it with the framework +4. Runs the full benchmark against your chosen competitors +5. Reports accuracy, latency, and context-token results side by side + +```bash +# From your project root +/memorybench +``` + +No manual TypeScript required to get a first result — see [Adding a Provider](/memorybench/extend-provider) for what the skill generates and how to do it by hand. + +--- + +## How it works + +Every run goes through the same checkpointed pipeline, regardless of provider or benchmark: + +``` +INGEST → SEARCH → ANSWER → EVALUATE → REPORT +``` + +Ingestion can take hours for large datasets, and API calls fail — so every phase checkpoints independently and a run resumes from the last completed step instead of starting over. - Cloud-based memory layer + Chunk-based semantic search - - Graph-based memory + LLM-powered memory extraction - - Long-term memory for AI + Knowledge graph construction - -We're actively adding support for more providers. [Contribute your own](/memorybench/extend-provider) or [create a feature request](https://github.com/supermemoryai/memorybench/issues). - +| Benchmark | Tests | Source | +|---|---|---| +| **LoCoMo** | Fact recall across extended, multi-session conversations — single-hop, multi-hop, temporal, adversarial | [snap-research/locomo](https://github.com/snap-research/locomo) | +| **LongMemEval** | Long-term memory across sessions, including knowledge that gets updated mid-conversation | [xiaowu0162/longmemeval](https://huggingface.co/datasets/xiaowu0162/longmemeval-cleaned) | +| **ConvoMem** | Personalization, preference learning, and reference resolution within a conversation | [Salesforce/ConvoMem](https://huggingface.co/datasets/Salesforce/ConvoMem) | -## Contribute +None of these fit your use case? [Build your own benchmark](/memorybench/extend-benchmark) — providers, benchmarks, and judges are all pluggable. - - Found a bug or have a feature request? Let us know. - +Judging is judge-agnostic too — score a run with GPT-4o, Claude, Gemini, or any model you configure, so results aren't an artifact of one evaluator's bias. + +--- + +## Read next + + + + Test on scenarios that actually match your product, not just the built-in datasets. + + + Register your own memory system so it can be scored and compared. + + + MemScore, judge scoring, and how to read a report. + + + Found a bug, or want a provider/benchmark we don't support yet? + + diff --git a/apps/docs/memorybench/quickstart.mdx b/apps/docs/memorybench/quickstart.mdx deleted file mode 100644 index 645117fd..00000000 --- a/apps/docs/memorybench/quickstart.mdx +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: "Quick Start" -description: "Run your first benchmark evaluation in 3 steps" -sidebarTitle: "Quick Start" ---- - -## 1. Run Your First Benchmark - -```bash -bun run src/index.ts run -p supermemory -b longmemeval -j gpt-4o -r my-first-run -``` - -## 2. View Results - -### Option A: Web UI - -```bash -bun run src/index.ts serve -``` - -Open [http://localhost:3000](http://localhost:3000) to see results visually. - -### Option B: CLI - -```bash -# Check run status -bun run src/index.ts status -r my-first-run - -# View failed questions for debugging -bun run src/index.ts show-failures -r my-first-run -``` - -## 3. Compare Providers - -Run the same benchmark across multiple providers: - -```bash -bun run src/index.ts compare -p supermemory,mem0,zep -b locomo -j gpt-4o -``` - -## Sample Output - -Each run produces a [MemScore](/memorybench/memscore) — a composite metric capturing quality, latency, and token efficiency: - -``` -SUMMARY: - Total Questions: 50 - Correct: 36 - Accuracy: 72.00% - - Quality: 72% - Latency: 1250ms (avg) - Tokens: 1,823 (avg context sent to answering model) - - MemScore: 72% / 1250ms / 1823tok -``` - -Full results are saved to `data/runs/{runId}/report.json` with detailed breakdowns by question type, latency percentiles, and per-question token counts. - -## What's Next - -- [MemScore](/memorybench/memscore) — understand the composite metric and how to compare providers -- [CLI Reference](/memorybench/cli) — all available commands -- [Architecture](/memorybench/architecture) — how MemoryBench works under the hood diff --git a/apps/docs/memorybench/supported-models.mdx b/apps/docs/memorybench/supported-models.mdx deleted file mode 100644 index fd374c64..00000000 --- a/apps/docs/memorybench/supported-models.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: "Supported Models" -description: "Available models for judges and answer generation" -sidebarTitle: "Supported Models" ---- - -Models available for evaluation judges and answer generation in MemoryBench. - -## OpenAI - -| Model Name | Slug | -|------------|------| -| GPT-4o | `gpt-4o` | -| GPT-4o Mini | `gpt-4o-mini` | -| GPT-4.1 | `gpt-4.1` | -| GPT-4.1 Mini | `gpt-4.1-mini` | -| GPT-4.1 Nano | `gpt-4.1-nano` | -| GPT-5 | `gpt-5` | -| GPT-5 Mini | `gpt-5-mini` | -| o1 | `o1` | -| o1 Pro | `o1-pro` | -| o3 | `o3` | -| o3 Mini | `o3-mini` | -| o3 Pro | `o3-pro` | -| o4 Mini | `o4-mini` | - -## Anthropic - -| Model Name | Slug | -|------------|------| -| Claude Opus 4.5 | `opus-4.5` | -| Claude Sonnet 4.5 | `sonnet-4.5` | -| Claude Haiku 4.5 | `haiku-4.5` | -| Claude Opus 4.1 | `opus-4.1` | -| Claude Sonnet 4 | `sonnet-4` | - -## Google - -| Model Name | Slug | -|------------|------| -| Gemini 2.5 Pro | `gemini-2.5-pro` | -| Gemini 2.5 Flash | `gemini-2.5-flash` | -| Gemini 2.5 Flash Lite | `gemini-2.5-flash-lite` | -| Gemini 2.0 Flash | `gemini-2.0-flash` | -| Gemini 3 Pro Preview | `gemini-3-pro-preview` | - - -Make sure you have the corresponding API key set in your `.env.local` for the model you want to use. - diff --git a/apps/docs/migration/from-mem0.mdx b/apps/docs/migration/from-mem0.mdx index 6903379e..206a886e 100644 --- a/apps/docs/migration/from-mem0.mdx +++ b/apps/docs/migration/from-mem0.mdx @@ -200,9 +200,9 @@ results = client.search( ``` ```python Supermemory -results = client.documents.search( - query="user preferences", - container_tags=["user_alice"] +results = client.search.memories( + q="user preferences", + container_tag="user_alice" ) ``` @@ -247,6 +247,6 @@ For enterprise migrations, [contact us](mailto:support@supermemory.ai) for assis ## Next Steps -1. [Explore](/how-it-works) how Supermemory works +1. [Explore](/concepts/how-it-works) how Supermemory works 2. Read the [quickstart](/quickstart) and add and retrieve your first memories 3. [Connect](/connectors/overview) to Google Drive, Notion, and OneDrive with automatic syncing diff --git a/apps/docs/migration/from-zep.mdx b/apps/docs/migration/from-zep.mdx index f6585605..c95fcd31 100644 --- a/apps/docs/migration/from-zep.mdx +++ b/apps/docs/migration/from-zep.mdx @@ -9,9 +9,9 @@ sidebarTitle: "From Zep" | Zep AI | Supermemory | |--------|-------------| | Sessions & Messages | Documents & Container Tags | -| `session.create()` | Use `containerTags` parameter | -| `memory.add(session_id, ...)` | `add({containerTag: [...]})` | -| `memory.search(session_id, {text: ...})` | `search.execute({q: ..., containerTags: [...]})` | +| `session.create()` | Use `containerTag` parameter | +| `memory.add(session_id, ...)` | `add({containerTag: "..."})` | +| `memory.search(session_id, {text: ...})` | `search.execute({q: ..., containerTag: "..."})` | ## Installation @@ -56,7 +56,7 @@ session = client.session.create( ```python Supermemory # No explicit session creation - use containerTag -containerTag = ["user_123"] +containerTag = "user_123" ``` @@ -75,7 +75,7 @@ client.memory.add( ```python Supermemory client.add({ "content": "User prefers dark mode", - "containerTag": ["user_123"] + "containerTag": "user_123" }) ``` @@ -95,7 +95,7 @@ results = client.memory.search( ```python Supermemory results = client.search.execute({ "q": "preferences", - "containerTag": ["user_123"], + "containerTag": "user_123", "limit": 5 }) ``` @@ -112,7 +112,7 @@ memories = client.memory.get(session_id="user_123") ```python Supermemory documents = client.documents.list({ - "containerTag": ["user_123"], + "containerTags": ["user_123"], "limit": 100 }) ``` @@ -122,7 +122,7 @@ documents = client.documents.list({ ## Migration Steps 1. **Replace client initialization** - Use Supermemory client instead of Zep -2. **Map sessions to container tags** - Replace `session_id="user_123"` with `containerTag: ["user_123"]` +2. **Map sessions to container tags** - Replace `session_id="user_123"` with `containerTag: "user_123"` 3. **Update method calls** - Use `add()` and `search.execute()` instead of `memory.add()` and `memory.search()` 4. **Change search parameter** - Use `q` instead of `text` 5. **Handle async processing** - Documents process asynchronously (status: `queued` → `done`) @@ -152,7 +152,7 @@ results = client.memory.search("user_123", { from supermemory import Supermemory client = Supermemory(api_key="...") -containerTag = ["user_123"] +containerTag = "user_123" client.add({ "content": "I love Python", @@ -203,7 +203,7 @@ for (const sessionId of sessionIds) { if (mem.content) { await supermemory.add({ content: mem.content, - containerTag: [`session_${sessionId}`, `user_${memory.user_id || "unknown"}`], + containerTag: `session:${sessionId}:user:${memory.user_id || "unknown"}`, metadata: { role: mem.role, type: "message", @@ -238,7 +238,7 @@ for session_id in session_ids: if mem.content: supermemory.add({ "content": mem.content, - "containerTag": [f"session_{session_id}", f"user_{memory.user_id or 'unknown'}"], + "containerTag": f"session:{session_id}:user:{memory.user_id or 'unknown'}", "metadata": { "role": mem.role, "type": "message", @@ -315,9 +315,9 @@ async function migrateFromZep( // Import to Supermemory let totalMemories = 0; for (const [sessionId, data] of Object.entries(exportedData) as any) { - const containerTag = ["imported_from_zep", `session_${sessionId}`]; + let containerTag = `imported_from_zep:session:${sessionId}`; if (data.session.user_id) { - containerTag.push(`user_${data.session.user_id}`); + containerTag += `:user:${data.session.user_id}`; } for (const memory of data.memories) { @@ -368,5 +368,5 @@ migrateFromZep( ## Resources - [Supermemory SDKs](/integrations/supermemory-sdk) -- [API Reference](/memory-api/overview) -- [Search Documentation](/search) +- [API Reference](/api-reference/overview) +- [Search Documentation](/recall/search) diff --git a/apps/docs/model-enhancement/context-extender.mdx b/apps/docs/model-enhancement/context-extender.mdx deleted file mode 100644 index a7d7897e..00000000 --- a/apps/docs/model-enhancement/context-extender.mdx +++ /dev/null @@ -1,233 +0,0 @@ ---- -title: "supermemory Infinite Chat" -description: "Build chat applications with unlimited context using supermemory's intelligent proxy" -tag: "BETA" ---- - -import GettingAPIKey from '/snippets/getting-api-key.mdx'; - -supermemory Infinite Chat is a powerful solution that gives your chat applications unlimited contextual memory. It works as a transparent proxy in front of your existing LLM provider, intelligently managing long conversations without requiring any changes to your application logic. - -Infinite Context Diagram - - - - - - No more token limits - conversations can extend indefinitely - - - Transparent proxying with negligible overhead - - - Save up to 70% on token costs for long conversations - - - Works with any OpenAI-compatible endpoint - - - - - -## Getting Started - -To use the Infinite Chat endpoint, you need to: - -### 1. Get a supermemory API key - - - -### 2. Add supermemory in front of any **OpenAI-Compatible** API URL - - - -```typescript Typescript -import OpenAI from "openai"; - -/** - * Initialize the OpenAI client with supermemory proxy - * @param {string} OPENAI_API_KEY - Your OpenAI API key - * @param {string} SUPERMEMORY_API_KEY - Your supermemory API key - * @returns {OpenAI} - Configured OpenAI client - */ -const client = new OpenAI({ - apiKey: process.env.OPENAI_API_KEY, - baseURL: "https://api.supermemory.ai/v3/https://api.openai.com/v1", - headers: { - "x-supermemory-api-key": process.env.SUPERMEMORY_API_KEY, - "x-sm-user-id": "Your_users_id" - }, -}); -``` - -```python Python -import openai -import os - -# Configure the OpenAI client with supermemory proxy -openai.api_base = "https://api.supermemory.ai/v3/https://api.openai.com/v1" -openai.api_key = os.environ.get("OPENAI_API_KEY") # Your regular OpenAI key -openai.default_headers = { - "x-supermemory--api-key": os.environ.get("SUPERMEMORY_API_KEY"), # Your supermemory key -} - -# Create a chat completion with unlimited context -response = openai.ChatCompletion.create( - model="gpt-5-nano", - messages=[{"role": "user", "content": "Your message here"}] -) -``` - - - -## How It Works - - - - All requests pass through supermemory to your chosen LLM provider with zero latency overhead. - - Transparent Proxy Diagram - - - Long conversations are automatically broken down into optimized segments using our proprietary chunking algorithm that preserves semantic coherence. - - - When conversations exceed token limits (20k+), supermemory intelligently retrieves the most relevant context from previous messages. - - - The system intelligently balances token usage, ensuring optimal performance while minimizing costs. - - - -## Performance Benefits - - - Save up to 70% on token costs for long conversations through intelligent context management and caching. - - - - No more 8k/32k/128k token limits - conversations can extend indefinitely with supermemory's advanced retrieval system. - - - - Better context retrieval means more coherent responses even in very long threads, reducing hallucinations and inconsistencies. - - - - The proxy adds negligible latency to your requests, ensuring fast response times for your users. - - -## Pricing - - - -
-
-
-

Free Tier

-

100k tokens stored at no cost

-
-
-

Standard Plan

-

$20/month fixed cost after exceeding free tier

-
-
-

Usage-Based

-

Each thread includes 20k free tokens, then $1 per million tokens thereafter

-
-
-
-
- -
- - - - - - - - - - - - - - - - - - - - -
- Feature - - Free - - Standard -
- Tokens Stored - - 100k - - Unlimited -
- Conversations - - 10 - - Unlimited -
-
-
-
- -## Error Handling - - - supermemory is designed with reliability as the top priority. If any issues occur within the supermemory processing pipeline, the system will automatically fall back to direct forwarding of your request to the LLM provider, ensuring zero downtime for your applications. - - -Each response includes diagnostic headers that provide information about the processing: - -| Header | Description | -| -------------------------------- | ---------------------------------------------------------------------- | -| `x-supermemory-conversation-id` | Unique identifier for the conversation thread | -| `x-supermemory-context-modified` | Indicates whether supermemory modified the context ("true" or "false") | -| `x-supermemory-tokens-processed` | Number of tokens processed in this request | -| `x-supermemory-chunks-created` | Number of new chunks created from this conversation | -| `x-supermemory-chunks-deleted` | Number of chunks removed (if any) | -| `x-supermemory-docs-deleted` | Number of documents removed (if any) | - -If an error occurs, an additional header `x-supermemory-error` will be included with details about what went wrong. Your request will still be processed by the underlying LLM provider even if supermemory encounters an error. - -## Rate Limiting - - - Currently, there are no rate limits specific to supermemory. Your requests are subject only to the rate limits of your underlying LLM provider. - - -## Supported Models - -supermemory works with any OpenAI-compatible API, including: - - - - GPT-3.5, GPT-4, GPT-4o - - - Claude 3 models - - - Any provider with an OpenAI-compatible endpoint - - diff --git a/apps/docs/model-enhancement/getting-started.mdx b/apps/docs/model-enhancement/getting-started.mdx deleted file mode 100644 index 7af3bfab..00000000 --- a/apps/docs/model-enhancement/getting-started.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: "Getting Started with Model Enhancement" -sidebarTitle: "Quickstart" -description: "Superpower your LLM in one line" ---- - -import GettingAPIKey from '/snippets/getting-api-key.mdx'; - -## Get your supermemory API key - - - -## Get your LLM provider's API key - -Head to your LLM provider's dashboard and get your API key. - -- [OpenAI](https://platform.openai.com/api-keys) -- [Gemini](https://aistudio.google.com/apikey) -- [Anthropic](https://console.anthropic.com/account/keys) -- [Groq](https://console.groq.com/keys) - -## Choose your endpoint - - - -```bash OpenAI -https://api.supermemory.ai/v3/https://api.openai.com/v1/chat/completions -``` - - -```bash Gemini -https://api.supermemory.ai/v3/https://generativelanguage.googleapis.com/v1beta/openai -``` - - -```bash Anthropic -https://api.supermemory.ai/v3/https://api.anthropic.com/v1 -``` - - -```bash Groq -https://api.supermemory.ai/v3/https://api.groq.com/openai/v1 -``` - - -```bash Other provider -https://api.supermemory.ai/v3/ -``` - - - -## Making your first request - - - -```bash cURL -curl https://api.supermemory.ai/v3/https://api.openai.com/v1/chat/completions \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $OPENAI_API_KEY" \ - -H "x-supermemory--api-key: $SUPERMEMORY_API_KEY" \ - -H 'x-sm-user-id: user_id' \ - -d '{ - "model": "gpt-5", - "messages": [ - {"role": "user", "content": "What is the capital of France?"} - ] - }' -``` - - -``` -``` - - -```typescript TypeScript -import OpenAI from 'openai'; - -const openai = new OpenAI({ - apiKey: process.env.OPENAI_API_KEY, - baseURL: 'https://api.supermemory.ai/v3/https://api.openai.com/v1', - defaultHeaders: { - 'x-supermemory-api-key': process.env.SUPERMEMORY_API_KEY, - 'x-sm-user-id': 'your-user-id' - } -}); - -const completion = await openai.chat.completions.create({ - model: "gpt-5", -/// you can also add user here - user: "user", - messages: [ - { role: "user", content: "What is the capital of France?" } - ] -}); - - console.debug(completion.choices[0].message); -``` - - diff --git a/apps/docs/model-enhancement/identifying-users.mdx b/apps/docs/model-enhancement/identifying-users.mdx deleted file mode 100644 index cdc1bbf2..00000000 --- a/apps/docs/model-enhancement/identifying-users.mdx +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: "Identifying Users" -description: "Identifying users in supermemory" ---- - -You can enable built-in cross-conversational memory by sending supermemory a `x-sm-user-id`. - -## How supermemory Identifies Users and conversations - -supermemory will find the user ID in the following places (in order of priority): - -### `x-sm-user-id` header - -You can add a default header of x-sm-user-id with any client and model - -### `user` in body - -For models that support the `user` parameter in the body, such as OpenAI, you can also attach it to the body. - -### `userId` in search params - -You can also add `?userId=xyz` in the URL search parameters, incase the models don't support it. - -## Conversation ID - -If a conversation identifier is provided, You do not need to send the entire array of messages to supermemory. - -```typescript -// if you provide conversation ID, You do not need to send all the messages every single time. supermemory automatically backfills it. -const client = new OpenAI({ - baseURL: -"https://api.supermemory.ai/v3/https://api.openai.com/v1", - defaultHeaders: { - "x-supermemory-api-key": - "SUPERMEMORY_API_KEY", - "x-sm-user-id": `dhravya`, - "x-sm-conversation-id": "conversation-id" - }, -}) - -const messages = [ -{"role" : "user", "text": "SOme long thing"}, -// .... 50 other messages -{"role" : "user", "text": "new message"}, -] - -const client.generateText(messages) - -// Next time, you dont need to send more. -const messages2 = [{"role" : "user", "text": "What did we talk about in this conversation, and the one we did last year?"}] - -const client.generateText(messages2) -``` - -## Implementation Examples - -### Google Gemini - -```typescript -const ai = new GoogleGenAI({ apiKey: "YOUR_API_KEY" }); - -async function main() { - const response = await ai.models.generateContent({ - model: "gemini-2.0-flash", - contents: "Explain how AI works in a few words", - config: { - httpOptions: { - headers: { - 'x-sm-user-id': "user_123" - } - } - }, - }); - console.debug(response.text); -} -``` - -### Anthropic - -```typescript -const anthropic = new Anthropic({ - apiKey: 'YOUR_API_KEY', // defaults to process.env["ANTHROPIC_API_KEY"] -}); - -async function main() { - const msg = await anthropic.messages.create({ - model: "claude-sonnet-4-20250514", - max_tokens: 1024, - messages: [{ role: "user", content: "Hello, Claude" }], - }, { - // Using headers - headers: { - 'x-sm-user-id': "user_123" - } - }); - - console.debug(msg); -} -``` - -### OpenAI - -```typescript -const openai = new OpenAI({ - apiKey: "YOUR_API_KEY" -}); - -async function main() { - const completion = await openai.chat.completions.create({ - messages: [ - { role: "user", content: "Hello, Assistant" } - ], - model: "gpt-5", - user: "user_123" - }); - - console.debug(completion.choices[0].message); -} -``` diff --git a/apps/docs/n8n.mdx b/apps/docs/n8n.mdx deleted file mode 100644 index f68b1f7f..00000000 --- a/apps/docs/n8n.mdx +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: "n8n Integration" -description: "Automate knowledge management with Supermemory in n8n workflows" -sidebarTitle: "n8n" ---- - -Connect Supermemory to your n8n workflows to build intelligent automation workflows and agents that leverage your full knowledge base. - -## Quick Start - -### Prerequisites - -- n8n instance (self-hosted or cloud) -- Supermemory API key ([get one here](https://console.supermemory.com/settings)) -- Basic understanding of n8n workflows - -### Setting Up the HTTP Request Node - -The Supermemory integration in n8n uses the HTTP Request node to interact with the Supermemory API. Here's how to configure it: - -1. Add an **HTTP Request** node to your workflow (Core > HTTP Request) -![](/images/core-http-req.png) -2. Set the **Method** to `POST` -3. Set the **URL** to the appropriate Supermemory API endpoint: - - Add memory: `https://api.supermemory.ai/v3/documents` - - Search memories: `https://api.supermemory.ai/v4/search` -4. For authentication, select **Generic Credential Type** and then **Bearer Auth** -5. Click on **Create New Credential** and paste the Supermemory API Key in the Bearer Token field. -![](/images/bearer-auth-add-n8n.png) -6. Check **Send Body** and select **JSON** as the Body Content Type. The fields depend on what API endpoint you're sending the request to. You can find detailed step-by-step examples below. - -## Step-by-Step Tutorial - -In this tutorial, we'll create a workflow that automatically adds every email from Gmail to your Supermemory knowledge base. We'll use the HTTP Request node to send email data to Supermemory's API, creating a searchable archive of all your communications. - -### Adding Gmail Emails to Supermemory - -Follow these steps to build a workflow that captures and stores your Gmail messages: - -#### Step 1: Set Up Gmail Trigger - -![](/images/gmail-trigger.png) - -1. **Add a Gmail Trigger node** to your workflow -2. Configure your Gmail credentials (OAuth2 recommended) -3. Set the trigger to **Message Received** -4. Optional: Add labels or filters to process specific emails only - -#### Step 2: Configure HTTP Request Node - -1. **Add an HTTP Request node** after the Gmail Trigger -2. **Method**: `POST` -3. **URL**: `https://api.supermemory.ai/v3/documents` -4. Select your auth credentials you created with the Supermemory API Key. - -#### Step 3: Format Email Data for Supermemory - -In the HTTP Request node's **Body**, select **JSON** and **Using Fields Below** - -And create 2 fields: - -1. name: `content`, value: `{{ $json.snippet }}` -2. name: `containerTag`, value: gmail - - -![](/images/gmail-content.png) - -#### Step 4: Handle Attachments (Optional) - -If you want to process attachments: - -1. **Add a Loop node** after the Gmail Trigger -2. Loop through `{{$json.attachments}}` -3. **Add a Gmail node** to download each attachment -4. **Add another HTTP Request node** to store attachment metadata - - -#### Step 5: Add Error Handling - -1. **Add an Error Trigger node** connected to your workflow -2. Configure it to catch errors from the HTTP Request node -3. **Add a notification node** (Email, Slack, etc.) to alert you of failures -4. Optional: Add a **Wait node** with retry logic - -#### Step 6: Test Your Workflow - -1. **Activate the workflow** in test mode -2. Send a test email to your Gmail account -3. Check the execution to ensure the email was captured -4. Verify in Supermemory that the email appears in search results - -Refer to the API Reference tab to learn more about other supermemory API endpoints. \ No newline at end of file diff --git a/apps/docs/openai-sdks/usage.mdx b/apps/docs/openai-sdks/usage.mdx deleted file mode 100644 index db2e52e3..00000000 --- a/apps/docs/openai-sdks/usage.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Usage with OpenAI SDKs" ---- - -To use supermemory with the OpenAI SDKs, - -``` -import { memoryToolSchemas } from "@supermemory/tools/openai" -``` diff --git a/apps/docs/analytics.mdx b/apps/docs/overview/analytics.mdx similarity index 100% rename from apps/docs/analytics.mdx rename to apps/docs/overview/analytics.mdx diff --git a/apps/docs/overview/billing.mdx b/apps/docs/overview/billing.mdx new file mode 100644 index 00000000..8b12af25 --- /dev/null +++ b/apps/docs/overview/billing.mdx @@ -0,0 +1,334 @@ +--- +title: "Billing & usage" +description: "Enterprise-grade reference for Supermemory metering — SM tokens, operations, search, SuperRAG, plans, diff billing, and programmatic usage APIs." +sidebarTitle: "Billing & usage" +icon: "credit-card" +--- + +Supermemory billing is **usage-based USD credits**. Plans include a monthly credit balance; metered product usage draws that balance down. You manage plan, invoices, top-ups, and auto top-up in the [Developer Console](https://console.supermemory.ai). + +List prices and the public rate card also live on [supermemory.ai/pricing](https://supermemory.ai/pricing). This page is the **contract-level model**: what we meter, when tokens are free (already seen), what an operation is, plan feature gates, and how to read usage programmatically. + + +Console charts are **estimates**. Invoice / customer-portal line items are authoritative. + + +## Mental model + +```text +PLAN (Free · Pro · Scale · Enterprise) + │ includes monthly USD credits + ▼ +USD CREDIT BALANCE ──draw──► METERS + ├── sm_tokens_text / sm_tokens_rich (Memory ingest) + ├── sm_superrag_text / sm_superrag_rich (SuperRAG task) + ├── sm_search_queries (Search / profile) + └── sm_operations (platform ops) +``` + +1. You hold a **USD credit balance** (`usd_credits`). +2. Product activity increments **meters** (tokens, queries, operations). +3. Each meter unit multiplies by a **USD-per-unit** rate and debits the balance. +4. **Re-ingesting the same document under the same `customId` only bills the net-new token delta** — already-seen content is effectively **fully discounted**. + +--- + +## Meters (what we count) + +| Feature ID | UI label | What counts | Unit | +|---|---|---|---| +| `sm_tokens_text` | Memory tokens (text) | Billable **new** tokens on Memory-path ingest for text-like content (`text`, `tweet`, `github_markdown`) | tokens | +| `sm_tokens_rich` | Memory tokens (rich) | Billable **new** tokens on Memory-path ingest for multimodal / extraction-heavy types (PDF, media, etc.) | tokens | +| `sm_superrag_text` | SuperRAG tokens (text) | Billable **new** tokens when the task type is SuperRAG (text) | tokens | +| `sm_superrag_rich` | SuperRAG tokens (rich) | Billable **new** tokens when the task type is SuperRAG (rich) | tokens | +| `sm_search_queries` | Search queries | Each search / profile call that runs retrieval (v3 search, v4 search, v4 profile with search) | queries | +| `sm_operations` | Operations | Counted platform operations not fully attributed to token meters (e.g. certain ingest modes such as **instant dreaming**, and other non-token platform actions) | operations | + +### List rates (USD) + +These match the console meter table (USD **per unit**; ×1000 ≈ price per 1K units): + +| Meter | USD per unit | Approx per 1K units | +|---|---|---| +| `sm_tokens_text` | 0.000005 | **0.005 USD** / 1K tokens | +| `sm_tokens_rich` | 0.00001 | **0.010 USD** / 1K tokens | +| `sm_superrag_text` | 0.000001 | **0.001 USD** / 1K tokens | +| `sm_superrag_rich` | 0.000002 | **0.002 USD** / 1K tokens | +| `sm_search_queries` | 0.000005 | **0.005 USD** / 1K queries | +| `sm_operations` | 0.0001 | **0.10 USD** / 1K operations | + +Rates can change; treat [pricing](https://supermemory.ai/pricing) + your invoice as source of truth. + +### Memory vs SuperRAG tokens + +Ingestion is attributed by **task type**: + +- **Memory** (`taskType: "memory"`) → `sm_tokens_text` / `sm_tokens_rich` +- **SuperRAG** (`taskType: "superrag"`) → `sm_superrag_text` / `sm_superrag_rich` + +Text-like document types bill on the **text** meters; everything else bills as **rich** (OCR, video/audio, heavy extractors). + +### What is an operation? + +**`sm_operations`** is the meter for discrete platform work that is not “how many tokens did we embed.” Examples include: + +- **`dreaming: "instant"`** — processes a document’s memory extraction immediately (does not wait for dynamic batch dreaming). Documented as **one extra operation per document** on top of normal token metering. See [Processing modes](/ingestion/add-memories#processing-modes). +- Other non-token platform actions the product attributes to the operations meter (console: “counted platform operations not attributed to token or search meters”). + +Search is primarily metered as **`sm_search_queries`** (one unit per gated search/profile request). Prefer thinking of operations as **extra platform work**, not as a synonym for “API call.” + +### Search and profile + +| Call | Typical meter | +|---|---| +| `POST /v3/search`, `POST /v4/search`, `client.search.*` | `sm_search_queries` (+1) | +| `POST /v4/profile` when it runs retrieval | `sm_search_queries` (+1) | + +If the org is out of balance, search/profile can return **402** (payment required) depending on gate configuration. + +--- + +## Full discount on already-seen tokens (diff billing) + +This is the most important cost control in production agents. + +### How it works + +When you re-add content under the **same `customId`** (same org / document identity), the pipeline: + +1. Loads the **previous extracted content** for that document +2. Computes **full** token count of the merged/updated document +3. Bills only: + +```text +billableTokens = max(0, fullTokenCount - previousTokenCount) +``` + +So **tokens Supermemory has already processed are not billed again**. Unchanged content is a **full discount** on the token meters. Only the **net-new delta** (and any new rich extraction on that delta) draws credits. + +This is why long-lived agent loops stay cheap: re-sync the same conversation `customId`, re-upload the same policy doc, or connector re-sync with stable IDs — you pay for **new** material, not the whole history every time. + +### Requirements + +| Requirement | Why | +|---|---| +| **Stable `customId`** | Identity for “this is the same document.” Max length 255. | +| **Same org / key** | Documents are org-scoped. | +| **Update path, not full replace** | Full replace clears previous content for billing purposes (`isFullReplace` treats previous tokens as 0). Prefer append/update with the same `customId` for chat. | + +### Practical patterns + +```typescript +// Session stays one document — only new turns bill tokens +await client.add({ + content: "user: " + msg + "\nassistant: " + reply, + containerTag: userId, + customId: "chat_" + sessionId, // stable for the session + dreaming: "instant", // optional: +1 operation, faster memory +}); +``` + +Connectors already use stable IDs (e.g. Drive file id, Gmail thread id, `s3://bucket/key`) so re-syncs diff-bill automatically. + +### What is not free + +- **First** ingest of content still bills full token count +- **Search / profile** still bill query meters every call +- **Instant dreaming** still bills the **operation** surcharge when used +- **Brand-new `customId`** = brand-new document = full tokens + +--- + +## Credits and balance behavior + +| Concept | Behavior | +|---|---| +| **Included plan credits** | Monthly USD allowance tied to the plan (resets each billing period; **no rollover**) | +| **Top-up credits** | Purchased USD credits (console presets e.g. 10 / 25 / 50 / 100 USD). Persist until used (do not expire with the calendar month the way subscription inclusion does) | +| **Spend order** | Plan inclusion is consumed before top-up balance (Autumn merges both into `usd_credits`) | +| **Auto top-up** | Configurable in console for paid plans — adds credits when balance is low | +| **Spend caps** | Scale+ supports hard caps so usage cannot run away | +| **Depleted balance** | Metered APIs may block (e.g. **402**) until top-up or period reset | + +### Plan credit inclusion (approximate) + +| Plan | Product ID | Included credits / month | +|---|---|---| +| Free | `api_free` | **5 USD** | +| Pro | `api_pro` | **20 USD** | +| Scale | `api_scale` | **600 USD** | +| Enterprise | `api_enterprise` | Custom / unlimited by contract | + +Legacy product IDs (`memory_free`, `memory_starter`, `memory_growth`, `memory_enterprise`) still resolve for existing customers. + +--- + +## Plans and feature access + +Usage meters are shared; **feature gates** differ by tier. + +### Plan summary + +| Plan | Price (list) | Included credits | Best for | +|---|---|---|---| +| **Free** | 0 USD | 5 USD | Evaluate API, prototypes | +| **Pro** | 19 USD/mo | 20 USD | Developers, plugins, core connectors | +| **Scale** | 399 USD/mo | 600 USD | Production, full connectors, teams | +| **Enterprise** | Custom | Contract | SSO, custom metering, FDE, air-gap | + +### Feature matrix (code gates) + +| Feature | Free | Pro | Scale | Enterprise | +|---|---|---|---|---| +| Memory API, search, profiles | Yes | Yes | Yes | Yes | +| Diff / delta token billing | Yes | Yes | Yes | Yes | +| Plugins (Claude Code, Cursor, Hermes, …) | — | Yes | Yes | Yes | +| Team management | — | Yes | Yes | Yes | +| Google Drive, OneDrive, Notion connectors | — | Yes | Yes | Yes | +| Gmail, GitHub, S3, Web Crawler connectors | — | — | Yes | Yes | +| User Insights | — | — | Yes | Yes | +| Org seat limit (members) | 1 | 3 | Unlimited | Unlimited | +| Auto top-up | Limited | Yes | Yes | Contract | +| Spend caps | — | — | Yes | Contract | +| Custom metering / SSO / dedicated deploy | — | — | — | Yes | + +Overrides can be applied per org in metadata (`featureOverrides`) for enterprise deals. + +### HTTP behavior when gated + +- **403** — plan too low for a **feature** (e.g. connector not on Free) +- **402** — **quota / credits** exhausted for a metered call (search, tokens, etc.) + +--- + +## Programmatic access + +All of the following require an **org-admin capable** credential. **Scoped API keys cannot read billing** (403). + +Base: `https://api.supermemory.ai` +Auth: `Authorization: Bearer YOUR_API_KEY` + +### Summary — plan + high-level usage + +`GET /v3/auth/billing` + +```bash +curl -s https://api.supermemory.ai/v3/auth/billing \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" +``` + +Typical fields: + +```json +{ + "plan": "pro", + "usage": { + "tokens": { "used": 120000, "limit": 0 }, + "queries": { "used": 4200, "limit": 0 } + }, + "credits": {}, + "resetDate": "2026-08-01T00:00:00.000Z", + "orgName": "Acme", + "billingEmail": "billing@acme.com" +} +``` + +CLI: + +```bash +npx supermemory billing show +npx supermemory billing usage +``` + +### Feature breakdown (Autumn features) + +`GET /v3/auth/billing/usage` + +Returns per-feature `used` / `limit` / `unit` for the org’s Autumn customer features (including `usd_credits`, token meters, search, operations), plus period bounds when available. + +```bash +curl -s https://api.supermemory.ai/v3/auth/billing/usage \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" +``` + +### Meter events (day × feature) + +`GET /v3/auth/billing/usage-events` + +Optional query: `?start=&end=` to override the billing period. + +```bash +curl -s "https://api.supermemory.ai/v3/auth/billing/usage-events" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" +``` + +Response includes `byFeature`, `byDay`, `memoryTotal`, `superragTotal`, period start/end. + +### Auto top-up config + +```http +GET /v3/auth/billing/auto-topups +PATCH /v3/auth/billing/auto-topups +``` + +### Invoices + +`GET /v3/auth/billing/invoices` + +### Product / request analytics (not the same as USD meters) + +For **request volume**, errors, and per-key traffic (ops monitoring, not USD ledger): + +`GET /v3/analytics/usage?period=24h|7d|30d` + +See [Analytics](/overview/analytics). + +### TypeScript sketch + +```typescript +const headers = { + Authorization: "Bearer " + process.env.SUPERMEMORY_API_KEY, +}; + +const billing = await fetch("https://api.supermemory.ai/v3/auth/billing", { + headers, +}).then((r) => r.json()); + +const usage = await fetch("https://api.supermemory.ai/v3/auth/billing/usage", { + headers, +}).then((r) => r.json()); + +const events = await fetch( + "https://api.supermemory.ai/v3/auth/billing/usage-events", + { headers }, +).then((r) => r.json()); + +console.log({ + plan: billing.plan, + resetDate: billing.resetDate, + usage, + events, +}); +``` + +--- + +## Cost control checklist (production) + +1. **Always set stable `customId`** on conversations and docs so re-sync is free on old tokens. +2. Prefer **session-level** conversation documents over one-line micro-adds (better memory **and** less wasted processing). +3. Use **`dreaming: "instant"`** only when you need immediate memory (extra operation); default `"dynamic"` batches extraction. +4. Cache **profiles** short-TTL in your app if you call them every turn. +5. Scope with **`containerTag`** so you can delete/export a tenant without scanning the org. +6. Enable **spend caps / auto top-up** on Scale for predictable production. +7. Pull **`/v3/auth/billing/usage-events`** into your own FinOps dashboard for per-day Memory vs SuperRAG spend. + +--- + +## Related + +- [Pricing page](https://supermemory.ai/pricing) — live plan marketing rates +- [Console billing](https://console.supermemory.ai) — plan, invoices, top-ups +- [Add context](/ingestion/add-memories) — `customId`, `dreaming` +- [Analytics](/overview/analytics) — request-level observability +- [Security & compliance](/overview/security) — trust posture for enterprise review diff --git a/apps/docs/overview/comparison.mdx b/apps/docs/overview/comparison.mdx new file mode 100644 index 00000000..342f11f0 --- /dev/null +++ b/apps/docs/overview/comparison.mdx @@ -0,0 +1,187 @@ +--- +title: "Comparison - Should I use supermemory?" +description: "When Supermemory is the right choice versus DIY vector stacks, thin memory layers, pure RAG, and building it yourself. The answer is: you should probably use supermemory" +sidebarTitle: "Comparison" +icon: "scale" +--- + + + +> "Comparison is the thief of joy," but the wrong abstraction costs more than a page like this. + +Non-detailed reasons to pick supermemory over the alternatives. If you're migrating from a specific tool, the [migration guides](/migration/from-mem0) name names and map APIs. + +## vs Rolling your own (vector DB + embeddings + glue) + +- **Skip the vendor pile-up.** No stitching together a vector DB, an embedding model, chunking scripts, and a fact-extraction prompt. One engine does it. +- **Get temporal truth for free.** "Loved Adidas, switched to Puma" resolves correctly instead of both facts looking equally relevant forever. +- **Ship identity, not just similar text.** Entities and profiles come built in, not bolted on later. +- **Stay portable.** Use our cloud, or [self-host](/self-hosting/overview) the same engine on your own infra. + +## vs "Memory layers" that are thin wrappers + +- **Facts actually update.** When a user changes their mind, the old fact doesn't sit next to the new one forever. +- **Real relationships, not blobs.** A graph connects people, projects, and events across sessions, not a pile of stored chat turns. +- **Profiles included.** No extra work to get a standing summary of who a user is. +- **Configurable where it matters.** Extractors, retrieval, and isolation are primitives you compose, not a black box. + +## vs Pure RAG / document search products + +- **Both layers, one engine.** SuperRAG for corpus grounding, memory and profiles for people, sharing the same container tags. +- **Personal state isn't just another document.** "What the policy says" and "what this customer decided last quarter" stay distinct but connected. +- **No second vendor for personalization.** You're not stitching a memory product onto your RAG stack. + +## vs Building a full context engine in-house + +- **Skip years of infra work.** Extraction models, temporal updates, conflict resolution, and connector maintenance, already built. +- **Compliance comes standard.** SOC 2, GDPR, and HIPAA paths, plus scoped keys, without a dedicated platform team. +- **Still yours if you want it.** [Self-host](/self-hosting/overview) the same binary when you need it on your own metal. + +Most AI apps are better off using supermemory than building this themselves. Run the [quickstart](/quickstart) and judge for yourself. + +## Supermemory is never overkill + +In most cases, supermemory is the *lighter* choice (not heavier), and cheaper too. It bundles all the blocks while staying fully composable, so it fits everything from side projects and internal tools to production infra millions of people rely on. Rolling your own means signing up for a dozen separate vendors for the database, hosting, embeddings, graph, vector store, and ingestion pipeline instead. + +Data ownership isn't a tradeoff either: [self-host](/self-hosting/overview) supermemory and nothing leaves your servers. And if you're worried about lock-in, you can always export your data, delete it, or run your own instance, **supermemory is an architecture** to build with, not an opinionated service. + + + + + +This page is intentionally **not** a vendor scorecard. We know things change and improve over time. Instead: the categories people actually evaluate, what each is good at, and when Supermemory is the better fit. + +If you are migrating from a specific tool, use the [migration guides](/migration/from-mem0), that is where we name names and map APIs. + +## vs Rolling your own (vector DB + embeddings + glue) + +**What this path is:** Pinecone/Weaviate/pgvector + an embedding model + chunking scripts + a prompt that says “here is relevant context.” and running it through a text model, extracting facts. + +**When it is enough** + +- Static knowledge base, low update rate +- You already run retrieval infra and only need nearest-neighbor chunks +- Latency, ops, and embedding quality are already solved problems for your team + +**Where it breaks for agent memory** + +- No temporal truth (“loved Adidas” then “switched to Puma”, both stay equally “relevant”) +- You have to use 6+ vendors for all the different stuff +- No entity identity or profile, just similar text +- Multimodal extraction, connectors, forgetting, and multi-tenant isolation become a second product +- You spend lots of time on just figuring out the right plumbing and combinations of vendors +- Not very scalable for memory. New facts need knowledge of all previous facts + +**Supermemory instead:** one engine that derives **memories** using our custom model, a **temporal vector-graph engine**, and **profiles**, with hybrid retrieval and isolation primitives built in. You keep the option to [self-host](/self-hosting/overview) when you want the stack on your metal. + +## vs “Memory layers” that are thin wrappers + +**What this path is:** an API that stores chat turns or summaries in a vector store, sometimes with a light extract-facts prompt. Marketed as memory; architected as RAG with better branding. + +**When it is enough** + +- Demo chatbots and hackathon agents +- You only need “remember the last few sessions” as blobs of text +- Quality bar is “sometimes recalls a preference” + +**Where it breaks in production** + +- Facts do not **update** cleanly when users change their mind +- Some of them have no real graph of people, projects, and relations across separately ingested events +- There's no concept of Profiles since they don't have the same underlying learning model and store engine +- You still have to build the entire thing around it, on their abstraction. Low configurability and doesn't support many use cases (Extractors, retrieval, etc.) + +**Supermemory instead:** memory is a first-class data model (documents → derived memories → graph → profiles), not a convenience wrapper. Same store from API, MCP, plugins, and Company Brain, all primitives built in for you to compose for your use case. See [How it works](/concepts/how-it-works) and [Graph memory](/concepts/graph-memory). + +## vs Pure RAG / document search products + +**What this path is:** excellent document ingestion and semantic search over a corpus, wikis, PDFs, tickets. No (or weak) per-user long-horizon memory. + +**When it is enough** + +- Internal knowledge base Q&A only, no change in text +- “Chat with these PDFs” with a fixed corpus +- Content is universal, not personal. The files are structured and short +- Content does not update enough over long horizons + +**Where it breaks** + +- Personalized agents that must know *this user* over months +- Mixing “what is in the policy doc” with “what did this customer decide last quarter” +- You still have to build in the contextualization and bear the cost of it. Also need to sign up for many vendors for the same. +- Treating user state as another document collection + +**Supermemory instead:** **both** layers in one engine, SuperRAG for corpus grounding, memory + profiles for people and entities. They share container tags so isolation stays coherent. Deep dive: [Memory vs RAG](/concepts/memory-vs-rag). + +## vs Building a full context engine in-house + +**What this path is:** custom extraction models, graph store, profile assembly, hybrid search, connector fleet, multi-tenant keys, compliance pack. + +**When it is justified** + +- Memory *is* the product and differentiation lives in proprietary models/data +- You have a dedicated platform team and years of runway +- Regulatory constraints force a greenfield design with no external dependency (even then, [self-host](/self-hosting/overview) is often enough) + +**What you are actually signing up for** + +- Extraction quality and eval harnesses +- Temporal updates, conflict resolution, forgetting +- Multimodal pipelines and connector maintenance +- Authz (scoped keys, container boundaries), billing metering, SOC 2 / GDPR / HIPAA paths +- Sub-300ms retrieval under agent-loop load, deployability, maintaining it forever as the industry changes + +**Supermemory instead:** that platform as a product, managed cloud or +self-hosted binary, so your team ships agents and apps, not a second infrastructure company. Benchmarks and research: [supermemory.ai/research](https://supermemory.ai/research). + +## Decision cheat sheet + +| If your job is… | Prefer | +|---|---| +| Q&A over a mostly static doc set | RAG product or SuperRAG-only usage | +| Remember users across sessions with updates over time | Supermemory memory + profiles | +| Both personalization *and* company docs | Supermemory (memory + SuperRAG, same containers) | +| Full control, data never leaves your network | Supermemory [self-host](/self-hosting/overview) / Enterprise | +| Maximum control of every model weight and storage engine | Build in-house (or fork open pieces and accept the ops) | + +## Prove it yourself + +We would rather you verify than trust a comparison page: + +1. Run the [quickstart](/quickstart), scatter facts across “sessions,” ask a question that requires linking them +2. Reproduce long-horizon results with [MemoryBench](https://supermemory.ai/research) / the MemoryBench docs when you care about evals +3. If you already store memories elsewhere, use a [migration guide](/migration/from-mem0) + +## Supermemory is never overkill + +In most cases, supermemory will be the _lighter_ choice (not heavier), and it is cheaper too! Because supermemory involves all the blocks while being fully composable, but we also build the infrastructure ourselves (a post-trained model, etc.), it's perfect for everything from internal tools, side projects, and hobby projects to production-grade infrastructure that millions of people rely on. + +Building your own, however, will mean that you have to sign up for 20 different vendors to do your database, hosting, embedding, graph, vector store, learning model, ingestion pipeline, etc. + +Why is it cheaper? Because we (the team) come from an infrastructure background, we built some of the best base for memory out there. Owning the database and the model layer gives us a lot of advantages! + +And if data ownership is a concern, it shouldn't be :) You can always [self-host](/self-hosting/overview) supermemory which ensures that nothing leaves your servers and you have full control and access. + +Concerned about lock-in? You can always export your data, delete it, or switch to running your own instance of supermemory. **Supermemory is an architecture** to build with, not an _opinionated service_. It comes with the right defaults and some easy ways to use it, but you can go as deep as you want to make it perfect for your case. +Finally, we truly believe every use case can make advantage of supermemory, or a base of it's components. + +Most AI applications should use supermemory. + + + +## Related + + + + Product overview and one-engine mental model. + + + Why nearest-neighbor text is not memory. + + + Usage model if cost is part of the evaluation. + + + Trust posture for production and enterprise buyers. + + diff --git a/apps/docs/overview/security.mdx b/apps/docs/overview/security.mdx new file mode 100644 index 00000000..f4a6801d --- /dev/null +++ b/apps/docs/overview/security.mdx @@ -0,0 +1,88 @@ +--- +title: "Security & compliance" +description: "How Supermemory protects data — encryption, isolation, SOC 2, GDPR, HIPAA BAA, and deletion." +sidebarTitle: "Security & compliance" +icon: "shield" +--- + +Supermemory stores long-horizon context about people and organizations. Security and compliance are part of the product surface, not a footer claim. + +This page is the product-level trust overview. For multi-tenant design details, see [Container tags](/concepts/container-tags) and authentication docs in the Developer Platform. + +## Compliance posture + +| Framework | Status | Notes | +|---|---|---| +| **SOC 2 Type II** | Certified | Independent audit of security controls. Available on production plans that advertise it (see [pricing](https://supermemory.ai/pricing); typically Scale and above for formal enterprise packaging). | +| **GDPR** | Compliant | EU personal data handled with care; support for access and erasure workflows. | +| **HIPAA** | BAA available | Business Associate Agreement available for eligible cloud plans (Scale / Enterprise). Cloud-only unless you self-host under your own controls. | + +Need a report, DPA, or BAA? Contact [support@supermemory.com](mailto:support@supermemory.com) or your enterprise contact. + +## Security controls + +### Encryption + +- **In transit:** TLS for API and console traffic +- **At rest:** Industry-standard encryption for stored data (AES-256 class controls in the managed cloud) + +### Isolation and access + +- **Container tags** enforce hard boundaries between users, tenants, or projects — the primary multi-tenancy primitive. +- **API keys** authenticate every request. Prefer **scoped keys** when a client or session must only touch one container. +- **Organizations** in the console manage members, keys, and billing separation. + +A malicious or buggy client with a correctly scoped key cannot read another container’s memories. + +### Data use + +Supermemory is infrastructure for *your* agents. Paid production usage is not treated as free training corpus for unrelated public models. For contractual wording (DPA, subprocessors, training policies), request the latest legal pack from support. + +### Data residency and deployment options + +- **Managed cloud** — default multi-tenant SaaS. +- **Self-hosted binary** — full engine on your machine or VPC; embeddings and storage stay where you run it. See [Self-hosting](/self-hosting/overview). +- **Enterprise / dedicated** — for stricter residency, air-gap, or custom deployment requirements. See [Local vs Enterprise](/self-hosting/local-vs-enterprise). + +## Privacy operations you should design for + +### Deleting a user (right to erasure) + +The practical GDPR-style path for app builders: + +1. Scope each end-user (or tenant) to a **container tag**. +2. When the user requests deletion, delete that container’s content via the API / console workflows for documents and memories under that tag. +3. Revoke any **scoped keys** issued for that user. + +Designing isolation up front makes erasure a single boundary operation instead of a forensic search. + +### Connectors and third-party sources + +OAuth connectors (Drive, Notion, Gmail, and others) pull content your users authorize. Disconnecting a connector stops future sync; you still control whether already-ingested documents remain in the memory store. Treat connector scope and retention as part of your product privacy policy. + +### Self-host when cloud is not enough + +If policy requires data never leave your network, run the [self-hosted engine](/self-hosting/overview). You bring the model endpoint (including fully offline OpenAI-compatible local models). Enterprise adds managed on-prem / dedicated options with organizational controls. + +## Reliability and support + +- Status and incidents are communicated through Supermemory’s status and support channels. +- Support depth scales with plan (community → email → priority → dedicated enterprise). +- Latency targets for retrieval are in the ~sub-300ms p50 range on the managed platform for typical search workloads; always validate on your traffic shape. + +## Related + + + + Which tiers include BAAs, seats, and self-host options. + + + How isolation works in the data model. + + + API keys and access for the Developer Platform. + + + Keep memory on your infrastructure. + + diff --git a/apps/docs/overview/use-cases.mdx b/apps/docs/overview/use-cases.mdx index a10f9aae..34090d04 100644 --- a/apps/docs/overview/use-cases.mdx +++ b/apps/docs/overview/use-cases.mdx @@ -1,110 +1,74 @@ --- -title: "Use Cases" -description: "What can you do with supermemory?" -mode: "wide" +title: "Use cases" +description: "What teams build with Supermemory — agents, knowledge, multi-tenant products, and tools." +sidebarTitle: "Use cases" +icon: "lightbulb" --- -Explore what you can build with supermemory: +Supermemory is one context engine. These are the shapes teams ship on top of it. - - - Quickly built apps to chat with: +## Agents that remember - • Your Twitter bookmarks \ - • Your PDF documents \ - • Your company documentation \ - ...and more\! + + + Preferences, people, projects, and decisions across sessions — without replaying the entire chat history into every prompt. - - Search everything with AI: - - • Product recommendations \ - • Document similarity matching \ - • Research paper analysis - - ...and more\! + + Account history, past tickets, and product facts at answer time. Isolate each customer with a container tag. - - Build agents with infinite context for: - - • Email management \ - • Meeting summarization \ - • Calendar organization \ - ...and more\! + + Remember the account, stakeholders, and last commitments. Profiles keep “always know” context warm. - - Build your own second brain: - - • Organize your notes, ideas, and resources - - • Connect concepts across documents - - • Never lose track of insights or inspiration - - ...and more\! + + Project conventions, past decisions, and repo context via API, MCP, or plugins (Claude Code, Codex, OpenClaw, and more). - - For agencies and creators: + - • Maintain consistent tone and style - • Analyze your brand’s unique voice - • Write with context-aware suggestions +## Knowledge and retrieval - ...and more\! + + + Drive, Notion, Gmail, OneDrive, S3, GitHub, web crawler — sync sources, then ask questions with managed SuperRAG. - - For clinics, hospitals, and researchers: - - • Securely summarize patient records - - • Extract key info from medical history - - • Support clinical decisions with AI - - ...and more\! + + Policies, wikis, and internal docs as shared memory for the team — API or Company Brain. - - For online communities and businesses: - - • Powered by your chat or forum history - - • Instant, accurate answers - - • Reduce support load - - ...and more\! + + Papers, notes, and long documents with multimodal ingestion (PDF, images, audio/video) and hybrid search. - - For students and educators: - - • Flashcards and quizzes from your notes - - • Search across textbooks and lectures - - • Personalized study assistants - - ...and more\! + + Contracts and policy corpora with strict isolation and audit-friendly deletion paths. See [Security](/overview/security). - - For law firms and compliance teams: + - • Search through contracts and case law +## Multi-tenant products - • Extract clauses, obligations, and risks +If you are building a SaaS that needs memory **per end user** (or per workspace): - • Keep up with regulatory changes +1. Map each user/workspace to a **container tag** +2. Ingest conversations and files into that tag +3. Search / load **profiles** only inside that tag +4. Issue **scoped keys** when the client must not cross tenants +5. On account deletion, erase that container’s data - ...and more\! +Deep dive lives in Developer Platform concepts ([container tags](/concepts/container-tags), [user profiles](/concepts/user-profiles)). + +## Surfaces (same engine) + +| If you want to… | Start here | +|---|---| +| Call the Memory API from your app | [Quickstart](/quickstart) | +| Use Claude / Cursor / coding agents | [Plugins & MCP](/supermemory-mcp/mcp) | +| Give the whole company a knowledge brain | Company Brain (from [docs home](/)) | +| Keep data on your machines | [Self-hosting](/self-hosting/overview) | + +## Related + + + + Product overview and mental model. - - For companies and teams: - - • Centralize all internal documentation - - • Search across wikis, policies, and emails - - • Onboard new hires faster - - ...and more\! + + Concepts, API guides, and integrations. - \ No newline at end of file + diff --git a/apps/docs/overview/what-is-supermemory.mdx b/apps/docs/overview/what-is-supermemory.mdx new file mode 100644 index 00000000..b394dcf5 --- /dev/null +++ b/apps/docs/overview/what-is-supermemory.mdx @@ -0,0 +1,145 @@ +--- +title: "What is Supermemory?" +description: "Supermemory is the long term and short term context and memory infrastructure for agents." +sidebarTitle: "What is Supermemory?" +icon: "book-open" +mode: "wide" +--- + +export const BuildingBlock = ({ icon, title, href }) => { + return ( + + + + {title} + + + ) +} + +Supermemory is **context infrastructure for AI agents**. We're one of the leading memory providers, with components to go beyond memory and configure it to be perfect for every usecase. + +It provides all the building blocks — Memory, Retrieval, Profiles, Connectors, Extractors, Evals, observability, and more. + +
+ + + + + + + + + +
+ +With supermemory, developers can provide perfect recall about their users to build AI agents that are more intelligent, more personalized, and more consistent. + +It is the [state of the art](https://supermemory.ai/research) across multiple different benchmarks, like LongMemEval and LoCoMo. It's also the best in a lot of independantly run benchmarks, like the [SWEContext](https://arxiv.org/pdf/2602.08316) bench. + +## How does it work? (at a glance) + +![](/images/232.png) + +- You send Supermemory raw data in any format - text, files, and chats, or connect it to the data sources +- Supermemory [intelligently indexes them](/concepts/how-it-works) using our user understanding model and builds a semantic understanding graph on top of an entity (e.g., a user, a document, a project, an organization). We call these entities `containerTag` +- This knowledge is now traversed by the agent, and an automatic profile is built for it. The agent may now use it for memory operations or for retrieval. + +## Why add memory to your agent? + +Without memory, every session starts from zero. The model cannot know what the user preferred last week, which project they are on, or that a fact has changed since yesterday. + +**Memory** gives an agent durable understanding of *people and entities over time* — preferences, decisions, relationships, corrections. **Retrieval (RAG)** grounds answers in *documents and knowledge bases*. You usually want both. + +By adding memory to your agent, you can: + +- **Personalize** — remember preferences, roles, and history across sessions without stuffing the full chat log into every prompt +- **Stay correct as facts change** — “I love Adidas” then “switching to Puma” should not leave both preferences equally true +- **Ground answers** — pull the right policy, ticket, or doc when the question needs source material +- **Ship multi-tenant products** — isolate each user or workspace so one customer’s memory never leaks into another’s + +You can think of memory as the always-on context a skilled teammate would carry — not a search box over raw logs. + +For the full category argument (vs DIY vectors, thin memory wrappers, pure RAG), see [Comparison](/overview/comparison) and [Memory vs RAG](/concepts/memory-vs-rag). + +## Why Supermemory? + +- **State of the art on long-horizon memory** — #1 on [LongMemEval](https://supermemory.ai/research), [LoCoMo](https://supermemory.ai/research), and [ConvoMem](https://supermemory.ai/research), plus independent benches like [SWEContext](https://arxiv.org/pdf/2602.08316) +- **Memory is a graph, not a blob store** — facts [update, connect, and forget](/concepts/graph-memory) in real time; not nearest-neighbor chunks alone +- **User profiles built in** — static + dynamic context the agent should [always know](/concepts/user-profiles), ~ready for the prompt +- **Memory + SuperRAG in one engine** — personalize *and* ground on the same `containerTag` / context pool +- **Every door, one store** — API, [MCP](/supermemory-mcp/mcp), plugins, [SMFS](/smfs/overview), connectors, and Company Brain share the same memories +- **Multimodal by default** — text, chats, PDFs, images, video, code via [extractors](/concepts/content-types) and [connectors](/connectors/overview) +- **Run it your way** — managed cloud or [self-host](/self-hosting/overview) as a single binary (including offline) + +![memory graph](/images/readme-memory-graph.png) + + +Memory, profiles, and SuperRAG share the **same context pool** when you use the same isolation (`containerTag`). Mix and match for your product! A container can be anything - a user, a project, team, organization, etc. + + +## Next steps + + + + Make your first API call in minutes + + + Understand the knowledge graph architecture + + + vs DIY vectors, thin memory layers, pure RAG + + + One binary, zero config, fully offline + + + Credits, SM tokens, and how usage works + + + SOC 2, GDPR, HIPAA BAA, encryption + + diff --git a/apps/docs/overview/why-supermemory.mdx b/apps/docs/overview/why-supermemory.mdx deleted file mode 100644 index c1d651a9..00000000 --- a/apps/docs/overview/why-supermemory.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: "Why supermemory?" -description: "Learn the problems and challenges of building a memory layer, and how supermemory solves them!" ---- - -### The problem - -...so you want to build your own memory layer. Let's go through your decision process: - - - - - - Oh no, it's way too expensive. Time to switch. - - Turns out it's painfully slow. Let's try another. - - Great, now it won't scale. Back to square one. - - The maintenance is a nightmare. Need something else. - - - - - - Which model fits your use case - - What are the performance tradeoffs - - How to keep up with new releases - - - - - - - Websites: How do you handle JavaScript? What about rate limits? - - PDFs: OCR keeps failing, text extraction is inconsistent - - Images: Need computer vision models now? - - Audio/Video: Transcription costs add up quickly - - - - - -And in the middle of all this, you're wondering... - -> "When will I actually ship my product?" - -### The solution - -If you're not a fan of reinventing the wheel, you can use supermemory. - - - - - Start for free, scale as you grow - - Simple API, deploy in minutes - - No complex setup or maintenance - - Clear, predictable pricing - - - - Notion, Google Drive, Slack - - Web scraping and PDF processing - - Email and calendar sync - - Custom connector SDK - - - - Enterprise-grade security - - Sub-200ms latency at scale - - Automatic failover and redundancy - - 99.9% uptime guarantee - - - -Stop reinventing the wheel. Focus on building your product while we handle the memory infrastructure. \ No newline at end of file diff --git a/apps/docs/quickstart.mdx b/apps/docs/quickstart.mdx index 8953c175..5aaa31cf 100644 --- a/apps/docs/quickstart.mdx +++ b/apps/docs/quickstart.mdx @@ -1,133 +1,624 @@ --- -title: Quickstart -description: Make your first API call to Supermemory - add and retrieve memories. +title: "Quickstart" +description: "Ingest a conversation and a document, then use document search, memory graph traversal, and profiles — and wire it into a chat harness." icon: "play" --- - -**Using Vercel AI SDK?** Check out the [AI SDK integration](/integrations/ai-sdk) for the cleanest implementation with `@supermemory/tools/ai-sdk`. - +By the end of this page you will: - -**Prefer to run it locally?** Supermemory is also a [self-hostable single binary](/self-hosting/overview) — `curl -fsSL https://supermemory.ai/install | bash` and you're running. - +1. **Ingest a conversation** (how personal memory actually arrives) +2. **Ingest a document** (how knowledge for RAG arrives) +3. **Retrieve three ways** — document search (RAG), memory graph traversal, and user profile +4. **Drop it into a chat harness** that remembers across restarts -## Memory API +Same `containerTag` for everything. One engine, three ways out. -**Step 1.** Sign up for [Supermemory's Developer Platform](http://console.supermemory.ai) to get the API key. Click on **API Keys -> Create API Key** to generate one. +## Get an API key -![create api key](./images/create-api.png) +Grab a key from the [developer console](https://console.supermemory.ai) — **API Keys → Create API Key**. -**Step 2.** Install the SDK and set your API key: +**console.supermemory.ai** is where keys and usage live. **app.supermemory.ai** is the consumer product on the same engine — not where you mint API keys. - - -```bash -pip install supermemory -export SUPERMEMORY_API_KEY="YOUR_API_KEY" -``` - - -```bash + +```bash TypeScript npm install supermemory -export SUPERMEMORY_API_KEY="YOUR_API_KEY" +export SUPERMEMORY_API_KEY="sm_..." ``` - - -**Step 3.** Here's everything you need to add memory to your LLM: +```bash Python +pip install supermemory +export SUPERMEMORY_API_KEY="sm_..." +``` - - -```python +```bash curl +export SUPERMEMORY_API_KEY="sm_..." +``` + + +## 1. Ingest a conversation + +Real apps do not push four isolated one-liners as separate “memories.” They send **conversation turns** — often the full session — under a stable `customId` so the pipeline can extract facts and link entities. + +We’ll use one user (`user_4f8a`) and one chat session. The turns never say “Sarah *is* my VP of Product” — that connection is what the graph should resolve later. + + +```typescript TypeScript +import Supermemory from "supermemory"; + +const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY }); +const user = "user_4f8a"; + +const conversation = ` +user: Just got back from Tokyo — the team offsite went great. +assistant: Glad it went well! Anything stand out? +user: Sarah presented the Q3 roadmap at the offsite. +assistant: Sounds like a big moment for her. +user: She's being promoted to VP of Product. +assistant: Congrats to Sarah — that's huge. +user: I need a gift idea for my VP of Product. +assistant: Happy to help brainstorm something personal. +`.trim(); + +const conv = await client.add({ + content: conversation, + containerTag: user, + customId: "chat_offsite_2026", // one session → one document + metadata: { type: "conversation" }, + dreaming: "instant", // process this document now — see note below +}); + +console.log(conv.id, conv.status); // e.g. "queued" +``` + +```python Python from supermemory import Supermemory client = Supermemory() -USER_ID = "dhravya" +user = "user_4f8a" -conversation = [ - {"role": "assistant", "content": "Hello, how are you doing?"}, - {"role": "user", "content": "Hello! I am Dhravya. I am 20 years old. I love to code!"}, - {"role": "user", "content": "Can I go to the club?"}, -] +conversation = """ +user: Just got back from Tokyo — the team offsite went great. +assistant: Glad it went well! Anything stand out? +user: Sarah presented the Q3 roadmap at the offsite. +assistant: Sounds like a big moment for her. +user: She's being promoted to VP of Product. +assistant: Congrats to Sarah — that's huge. +user: I need a gift idea for my VP of Product. +assistant: Happy to help brainstorm something personal. +""".strip() -# Get user profile + relevant memories for context -profile = client.profile(container_tag=USER_ID, q=conversation[-1]["content"]) - -static = "\n".join(profile.profile.static) -dynamic = "\n".join(profile.profile.dynamic) -memories = "\n".join(r.get("memory", "") for r in profile.search_results.results) - -context = f"""Static profile: -{static} - -Dynamic profile: -{dynamic} - -Relevant memories: -{memories}""" - -# Build messages with memory-enriched context -messages = [{"role": "system", "content": f"User context:\n{context}"}, *conversation] - -# response = llm.chat(messages=messages) - -# Store conversation for future context -client.add( - content="\n".join(f"{m['role']}: {m['content']}" for m in conversation), - container_tag=USER_ID, +conv = client.add( + content=conversation, + container_tag=user, + custom_id="chat_offsite_2026", + metadata={"type": "conversation"}, + dreaming="instant", # process this document now — see note below ) +print(conv.id, conv.status) ``` - - + +```bash curl +curl -X POST "https://api.supermemory.ai/v3/documents" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "content": "user: Just got back from Tokyo — the team offsite went great.\nassistant: Glad it went well! Anything stand out?\nuser: Sarah presented the Q3 roadmap at the offsite.\nassistant: Sounds like a big moment for her.\nuser: She is being promoted to VP of Product.\nassistant: Congrats to Sarah — that is huge.\nuser: I need a gift idea for my VP of Product.\nassistant: Happy to help brainstorm something personal.", + "containerTag": "user_4f8a", + "customId": "chat_offsite_2026", + "metadata": { "type": "conversation" }, + "dreaming": "instant" + }' +``` + + +`add` returns immediately with `status: "queued"`. Processing is still **async** — wait until `done` before searching. + + +**`dreaming: "instant"`** — By default, dreaming is `"dynamic"`: Supermemory may batch related documents so memories form from coherent units, which can lag after `status: "done"`. For this quickstart (and any path where you need memories/profiles right away), pass **`dreaming: "instant"`** so the document is processed on its own as soon as it finishes indexing. That bills one extra operation per document. See [Processing Modes](/ingestion/add-memories#processing-modes). + + +## 2. Ingest a document + +Now add **knowledge** the agent should ground on — a short internal note the conversation never fully spelled out. This is the SuperRAG / document path. + + +```typescript TypeScript +const handbook = ` +# Team notes — gifts & recognition + +When someone is promoted to VP or above, the company recommends a thoughtful gift +in the $75–$150 range. Experiences tied to recent team milestones land better +than generic swag. + +For product leadership, books on platform strategy or a dinner near the last +offsite city are common picks. Tokyo offsites often inspire travel-themed gifts. +`.trim(); + +const doc = await client.add({ + content: handbook, + containerTag: user, + customId: "doc_gift_policy", + metadata: { type: "document", source: "handbook" }, + taskType: "superrag" +}); + +console.log(doc.id, doc.status); +``` + +```python Python +handbook = """ +# Team notes — gifts & recognition + +When someone is promoted to VP or above, the company recommends a thoughtful gift +in the $75–$150 range. Experiences tied to recent team milestones land better +than generic swag. + +For product leadership, books on platform strategy or a dinner near the last +offsite city are common picks. Tokyo offsites often inspire travel-themed gifts. +""".strip() + +doc = client.add( + content=handbook, + container_tag=user, + custom_id="doc_gift_policy", + metadata={"type": "document", "source": "handbook"}, + task_type="superrag" +) +print(doc.id, doc.status) +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v3/documents" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "content": "# Team notes — gifts & recognition\n\nWhen someone is promoted to VP or above, the company recommends a thoughtful gift in the $75–$150 range. Experiences tied to recent team milestones land better than generic swag.\n\nFor product leadership, books on platform strategy or a dinner near the last offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.", + "containerTag": "user_4f8a", + "customId": "doc_gift_policy", + "metadata": { "type": "document", "source": "handbook" }, + "taskType": "superrag" + }' +``` + + +## 3. Wait until both are `done` + +Poll document status. With **`dreaming: "instant"`**, once status is `done` the document is indexed **and** memories for that document should be available for search and profiles (`queued → extracting → … → done`). + +> Note that the preferred way is to have `dreaming: dynamic`. supermemory charges one extra operation for instant dreaming. Instant is good for one off tests, setup, debugging and benchmarking. + + +```typescript TypeScript +async function waitUntilDone(id: string) { + for (;;) { + const d = await client.documents.get(id); + if (d.status === "done" || d.status === "failed") return d; + await new Promise((r) => setTimeout(r, 1500)); + } +} + +await waitUntilDone(conv.id); +await waitUntilDone(doc.id); +console.log("ready to search"); +``` + +```python Python +import time + +def wait_until_done(doc_id: str): + while True: + d = client.documents.get(doc_id) + if d.status in ("done", "failed"): + return d + time.sleep(1.5) + +wait_until_done(conv.id) +wait_until_done(doc.id) +print("ready to search") +``` + +```bash curl +# replace DOC_ID with each document id from the add responses +curl "https://api.supermemory.ai/v3/documents/DOC_ID" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" +# repeat until "status": "done" +``` + + +Short text with instant dreaming usually finishes in a few seconds. Larger PDFs take longer. If you omit `dreaming` (default `"dynamic"`), document RAG can work after `done` while memory extraction may still be batching — use `"instant"` when the next step is memory search or profiles. + +## 4. Three ways to get context back + +### A. Document search (RAG) + +Chunk-level retrieval over raw knowledge — use when you need **what the docs say**. + + +```typescript TypeScript +const rag = await client.search({ + q: "gift ideas for a VP promotion after a Tokyo offsite", + containerTag: user, + searchMode: "documents", + limit: 3, +}); + +for (const hit of rag.results) { + console.log(hit.title ?? hit.id); + for (const chunk of hit.chunks ?? []) { + console.log(" ", chunk.content?.slice(0, 160)); + } +} +``` + +```python Python +rag = client.search.memories( + q="gift ideas for a VP promotion after a Tokyo offsite", + container_tag=user, + search_mode="documents", + limit=3, +) + +for hit in rag.results: + print(getattr(hit, "title", None) or hit.id) + for chunk in hit.chunks or []: + print(" ", (chunk.content or "")[:160]) +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v3/search" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "q": "gift ideas for a VP promotion after a Tokyo offsite", + "containerTag": "user_4f8a", + "searchMode": "documents", + "limit": 3 + }' +``` + + +You should see chunks from the handbook (budget range, Tokyo offsite angle) — **document grounding**, not personal facts. + +Switch `searchMode` to `"hybrid"` to get extracted memories and document chunks together: + ```typescript -import Supermemory from "supermemory"; - -const client = new Supermemory(); -const USER_ID = "dhravya"; - -const conversation = [ - { role: "assistant", content: "Hello, how are you doing?" }, - { role: "user", content: "Hello! I am Dhravya. I am 20 years old. I love to code!" }, - { role: "user", content: "Can I go to the club?" }, -]; - -// Get user profile + relevant memories for context -const profile = await client.profile({ - containerTag: USER_ID, - q: conversation.at(-1)!.content, -}); - -const context = `Static profile: -${profile.profile.static.join("\n")} - -Dynamic profile: -${profile.profile.dynamic.join("\n")} - -Relevant memories: -${profile.searchResults.results.map((r) => r.memory).join("\n")}`; - -// Build messages with memory-enriched context -const messages = [{ role: "system", content: `User context:\n${context}` }, ...conversation]; - -// const response = await llm.chat({ messages }); - -// Store conversation for future context -await client.add({ - content: conversation.map((m) => `${m.role}: ${m.content}`).join("\n"), - containerTag: USER_ID, +await client.search({ + q: "gift ideas for a VP promotion after a Tokyo offsite", + containerTag: user, + searchMode: "hybrid", + limit: 5, }); ``` - - -That's it! Supermemory automatically: -- Extracts memories from conversations -- Builds and maintains user profiles (static facts + dynamic context) -- Returns relevant context for personalized LLM responses +### B. Memory graph traversal - -**Optional:** Use the `threshold` parameter to filter search results by relevance score. For example: `client.profile(container_tag=USER_ID, threshold=0.7, q=query)` will only include results with a score above 0.7. - +Search **extracted memories** with related edges. This is the entity-chain moment: gift → VP of Product → Sarah → Tokyo offsite. -Learn more about [User Profiles](/user-profiles) and [Search](/search). + +```typescript TypeScript +const memories = await client.search({ + q: "What gift should I get, and why?", + containerTag: user, + searchMode: "memories", + include: { relatedMemories: true }, + limit: 5, +}); + +console.log(JSON.stringify(memories, null, 2)); +``` + +```python Python +memories = client.search.memories( + q="What gift should I get, and why?", + container_tag=user, + search_mode="memories", + include={"relatedMemories": True}, + limit=5, +) +print(memories) +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v4/search" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "q": "What gift should I get, and why?", + "containerTag": "user_4f8a", + "searchMode": "memories", + "include": { "relatedMemories": true }, + "limit": 5 + }' +``` + + +Abbreviated shape: + +```json +{ + "results": [ + { + "memory": "Sarah is being promoted to VP of Product", + "similarity": 0.81, + "context": { + "parents": [ + { + "memory": "Sarah presented the Q3 roadmap at the Tokyo offsite", + "relation": "extends" + } + ], + "children": [ + { + "memory": "User needs a gift idea for their VP of Product, Sarah", + "relation": "derives" + } + ] + } + } + ], + "timing": 287 +} +``` + +You never wrote “Sarah is my VP of Product” as one sentence. The graph connected sessions of speech. Deep dive: [graph memory](/concepts/graph-memory). + +### C. User profile + +Profiles are the **always-on** summary (static + recent dynamic) of an entity (or a `containerTag`) - what you inject every turn without re-searching the world. + + +```typescript TypeScript +const { profile, searchResults } = await client.profile({ + containerTag: user, + q: "gift for the person being promoted", // optional: also run search +}); + +console.log("static:", profile.static); +console.log("dynamic:", profile.dynamic); +console.log("search hits:", searchResults?.results?.length ?? 0); +``` + +```python Python +result = client.profile( + container_tag=user, + q="gift for the person being promoted", +) + +print("static:", result.profile.static) +print("dynamic:", result.profile.dynamic) +print("search hits:", len(result.search_results.results) if result.search_results else 0) +``` + +```bash curl +curl -X POST "https://api.supermemory.ai/v4/profile" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "containerTag": "user_4f8a", + "q": "gift for the person being promoted" + }' +``` + + +> There is a lot more to profiles - with [Buckets](/user-profiles/buckets), for example, you can make supermemory learn and categorize incoming information for learning specific things. + + +| Path | Use when | +|---|---| +| **Document search** | Ground in policies, docs, handbooks | +| **Memory + related** | Personal facts, entity links, “what’s true about this user” | +| **Profile** | Cheap always-on context every LLM turn | + +Same `containerTag` → same context pool. See [Memory vs RAG](/concepts/memory-vs-rag). + +## 5. Put it in a harness + +There is no single required harness. The pattern is the same wherever you run the model: **read** context (profile / search / docs), generate, **write** the turn back under a stable `customId` so the session stays one document. + +Here are two example shapes — pick whatever matches your stack. + +### Example: explicit profile + search + add + + +```typescript TypeScript +// npm install supermemory openai +import Supermemory from "supermemory"; +import OpenAI from "openai"; +import * as readline from "node:readline/promises"; + +const memory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY }); +const llm = new OpenAI(); +const user = "user_4f8a"; +const sessionId = "chat_live_session"; +const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + +while (true) { + const question = await rl.question("you: "); + + const { profile, searchResults } = await memory.profile({ + containerTag: user, + q: question, + }); + + // optional: also pull document chunks for grounding + const rag = await memory.search({ + q: question, + containerTag: user, + searchMode: "documents", + limit: 3, + }); + const docBits = rag.results + .flatMap((r) => r.chunks ?? []) + .map((c) => c.content) + .filter(Boolean) + .slice(0, 3); + + const context = [ + "## Profile (static)", + ...profile.static, + "## Profile (dynamic)", + ...profile.dynamic, + "## Related memories", + ...(searchResults?.results?.map((m) => m.memory).filter(Boolean) ?? []), + "## Docs", + ...docBits, + ].join("\n"); + + const res = await llm.chat.completions.create({ + model: "gpt-4o", + messages: [ + { role: "system", content: `You help this user. Context:\n${context}` }, + { role: "user", content: question }, + ], + }); + const answer = res.choices[0].message.content ?? ""; + console.log(`assistant: ${answer}`); + + // append this turn into the same conversation document + await memory.add({ + content: `user: ${question}\nassistant: ${answer}`, + containerTag: user, + customId: sessionId, + }); +} +``` + +```python Python +# pip install supermemory openai +from supermemory import Supermemory +from openai import OpenAI + +memory = Supermemory() +llm = OpenAI() +user = "user_4f8a" +session_id = "chat_live_session" + +while True: + question = input("you: ") + + result = memory.profile(container_tag=user, q=question) + rag = memory.search.memories( + q=question, container_tag=user, search_mode="documents", limit=3 + ) + doc_bits = [] + for hit in rag.results: + for chunk in hit.chunks or []: + if chunk.content: + doc_bits.append(chunk.content[:300]) + if len(doc_bits) >= 3: + break + + memories = result.search_results.results if result.search_results else [] + context = "\n".join( + [ + "## Profile (static)", + *result.profile.static, + "## Profile (dynamic)", + *result.profile.dynamic, + "## Related memories", + *[m.memory for m in memories if m.memory], + "## Docs", + *doc_bits, + ] + ) + + res = llm.chat.completions.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": f"You help this user. Context:\n{context}"}, + {"role": "user", "content": question}, + ], + ) + answer = res.choices[0].message.content or "" + print(f"assistant: {answer}") + + memory.add( + content=f"user: {question}\nassistant: {answer}", + container_tag=user, + custom_id=session_id, + ) +``` + + +### Example: Vercel AI SDK + +Same pattern, wrapped: `withSupermemory` injects context and can save the conversation for you. Details: [AI SDK integration](/integrations/ai-sdk). + +```typescript +// npm install ai @ai-sdk/openai @supermemory/tools +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; +import { withSupermemory } from "@supermemory/tools/ai-sdk"; +import * as readline from "node:readline/promises"; + +const model = withSupermemory(openai("gpt-4o"), { + containerTag: "user_4f8a", + customId: "chat_live_session", // keep stable for the whole session + mode: "full", // profile + query search +}); + +const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + +while (true) { + const prompt = await rl.question("you: "); + const { text } = await generateText({ model, prompt }); + console.log(`assistant: ${text}`); +} +``` + +Try: + +``` +you: What gift should I get for the person being promoted? +assistant: You're looking for something for Sarah — she's being promoted to VP of +Product after presenting the Q3 roadmap in Tokyo. Your handbook suggests $75–$150 +and something tied to the offsite; a Tokyo-inspired experience or platform-strategy +book would fit… +``` + +### Kill it, restart it + +Ctrl+C the process, start again with the **same** `containerTag` (and optional same `customId` for the live session). Ask: + +``` +you: who's getting promoted? +assistant: Sarah — she's being promoted to VP of Product. +``` + +Nothing was reloaded from your process. Memory and docs live in supermemory. + +## Mental model + +``` + INGEST WAIT RETRIEVE + ────── ──── ──────── + Conversation (customId) → status === done → Memory graph (+ related) + Document (customId) → status === done → Document search (RAG) + → Profile (static + dynamic) + │ + ▼ + Chat harness +``` + +## Where next + + + + Conversations, files, URLs, customId updates, and status. + + + Hybrid vs memories, filters, thresholds, rerank. + + + How relations and entity chains are produced. + + + Static vs dynamic, and when to inject a profile every turn. + + + withSupermemory modes, customId, addMemory. + + + Isolation for multi-tenant products. + + diff --git a/apps/docs/memory-operations.mdx b/apps/docs/recall/memory-operations.mdx similarity index 95% rename from apps/docs/memory-operations.mdx rename to apps/docs/recall/memory-operations.mdx index f70a9b16..6126b1f9 100644 --- a/apps/docs/memory-operations.mdx +++ b/apps/docs/recall/memory-operations.mdx @@ -1,6 +1,6 @@ --- title: "Memory Operations" -sidebarTitle: "Memories" +sidebarTitle: "CRUD & Forgetting" description: "Advanced memory operations (v4 API)" icon: "database" --- @@ -8,8 +8,8 @@ icon: "database" These v4 endpoints operate on extracted memories (not raw documents). SDK support coming soon — use fetch or cURL for now. -For document management (list, get, update, delete), see [Document Operations](/document-operations). -For ingesting raw content (text, files, URLs) through the processing pipeline, see [Add Context](/add-memories). +For document management (list, get, update, delete), see [Document Operations](/ingestion/document-operations). +For ingesting raw content (text, files, URLs) through the processing pipeline, see [Add Context](/ingestion/add-memories). ## Create Memories @@ -112,7 +112,7 @@ This is useful for storing user preferences, traits, or any structured facts whe | `memories[].createdAt` | string | ISO 8601 timestamp | -**When to use this vs [Add Context](/add-memories)?** +**When to use this vs [Add Context](/ingestion/add-memories)?** Use **Create Memories** when you already know the exact facts to store (user preferences, traits, structured data). Use **Add Context** when you have raw content (conversations, documents, URLs) that Supermemory should process and extract memories from. @@ -336,7 +336,7 @@ Update a memory by creating a new version. The original is preserved with `isLat ## Next Steps -- [Review Inferred Memories](/memory-review) — Approve or decline low-confidence memories -- [Document Operations](/document-operations) — Manage documents (SDK supported) -- [Search](/search) — Query your memories -- [Ingesting Content](/add-memories) — Add new content +- [Review Inferred Memories](/recall/memory-review) — Approve or decline low-confidence memories +- [Document Operations](/ingestion/document-operations) — Manage documents (SDK supported) +- [Search](/recall/search) — Query your memories +- [Ingesting Content](/ingestion/add-memories) — Add new content diff --git a/apps/docs/memory-review.mdx b/apps/docs/recall/memory-review.mdx similarity index 98% rename from apps/docs/memory-review.mdx rename to apps/docs/recall/memory-review.mdx index 84fda2fa..8184bb96 100644 --- a/apps/docs/memory-review.mdx +++ b/apps/docs/recall/memory-review.mdx @@ -284,5 +284,5 @@ a request and the memory simply stays in the queue for a later session. ## Next Steps - [Graph Memory](/concepts/graph-memory) — How inferred (`derive`) memories are created -- [Memory Operations](/memory-operations) — Create, forget, and update memories -- [Search](/search) — How inferred memories are ranked in results +- [Memory Operations](/recall/memory-operations) — Create, forget, and update memories +- [Search](/recall/search) — How inferred memories are ranked in results diff --git a/apps/docs/search.mdx b/apps/docs/recall/search.mdx similarity index 74% rename from apps/docs/search.mdx rename to apps/docs/recall/search.mdx index 15f4861d..07f93515 100644 --- a/apps/docs/search.mdx +++ b/apps/docs/recall/search.mdx @@ -1,6 +1,6 @@ --- title: "Search" -sidebarTitle: "Search Memories and Docs" +sidebarTitle: "Search API" description: "Semantic search across your memories and documents" icon: "search" --- @@ -11,6 +11,10 @@ Search through your memories and documents with a single API call. **Use `searchMode: "hybrid"`** for best results. It searches both memories and document chunks, returning the most relevant content.
+ +**TypeScript SDK:** call `client.search({ q, searchMode })` directly — `searchMode` (`"memories"`, `"documents"`, or `"hybrid"`) picks what comes back. `client.search.memories()` and `client.search.documents()` still work but are deprecated; no migration is required, just use `client.search()` going forward. The Python SDK is unaffected — `client.search.memories()` remains the call there. + + ## Quick Start @@ -20,7 +24,7 @@ Search through your memories and documents with a single API call. const client = new Supermemory(); - const results = await client.search.memories({ + const results = await client.search({ q: "machine learning", containerTag: "user_123", searchMode: "hybrid", @@ -102,27 +106,30 @@ In hybrid mode, results contain either a `memory` field (extracted facts) or a ` |-----------|------|---------|-------------| | `q` | string | required | Search query | | `containerTag` | string | — | Filter by user/project | -| `searchMode` | string | `"hybrid"` | `"hybrid"` (recommended) or `"memories"` | +| `searchMode` | string | `"memories"` | `"memories"`, `"hybrid"` (recommended), or `"documents"` | | `limit` | number | 10 | Max results | | `threshold` | 0-1 | 0.5 | Similarity cutoff (higher = fewer, better results) | | `rerank` | boolean | false | Re-score for better relevance (+100ms) | +| `rewriteQuery` | boolean | false | Generate multiple rewrites, search all of them, and merge results. No extra cost, but adds latency. Composes with filtering, hybrid search, and recency bias | | `filters` | object | — | Metadata filters (`AND`/`OR` structure) | +| `include` | object | — | `{ documents, summaries, relatedMemories, forgottenMemories }` — opt in to extra context per result | ### Search Modes -- **`hybrid`** (recommended) — Searches both memories and document chunks, returns the most relevant +- **`hybrid`** (recommended) — Searches both memories and document chunks, and returns both in the response - **`memories`** — Only searches extracted memories +- **`documents`** — Only searches raw document/chunk content, skipping extracted memories ```typescript // Hybrid: memories + document chunks (recommended) -await client.search.memories({ +await client.search({ q: "quarterly goals", containerTag: "user_123", searchMode: "hybrid" }); // Memories only: just extracted facts -await client.search.memories({ +await client.search({ q: "user preferences", containerTag: "user_123", searchMode: "memories" @@ -136,7 +143,7 @@ await client.search.memories({ Filter by `containerTag` to scope results to a user or project: ```typescript -const results = await client.search.memories({ +const results = await client.search({ q: "project updates", containerTag: "user_123", searchMode: "hybrid" @@ -146,7 +153,7 @@ const results = await client.search.memories({ Use `filters` for metadata-based filtering: ```typescript -const results = await client.search.memories({ +const results = await client.search({ q: "meeting notes", containerTag: "user_123", filters: { @@ -177,7 +184,7 @@ const results = await client.search.memories({ Re-scores results for better relevance. Adds ~100ms latency. ```typescript -const results = await client.search.memories({ +const results = await client.search({ q: "complex technical question", containerTag: "user_123", rerank: true @@ -190,10 +197,21 @@ Control result quality vs quantity: ```typescript // Broad search — more results -await client.search.memories({ q: "...", threshold: 0.3 }); +await client.search({ q: "...", threshold: 0.3 }); // Precise search — fewer, better results -await client.search.memories({ q: "...", threshold: 0.8 }); +await client.search({ q: "...", threshold: 0.8 }); +``` + +### Including Forgotten Memories + +By default, search excludes memories that have been forgotten or have passed their `forgetAfter` expiration. Set `include.forgottenMemories` to `true` to recover them: + +```typescript +await client.search({ + q: "old project notes", + include: { forgottenMemories: true } +}); ``` --- @@ -204,7 +222,7 @@ Optimal configuration for conversational AI: ```typescript async function getContext(userId: string, message: string) { - const results = await client.search.memories({ + const results = await client.search({ q: message, containerTag: userId, searchMode: "hybrid", @@ -242,6 +260,6 @@ async function getContext(userId: string, message: string) { ## Next Steps -- [Ingesting Content](/add-memories) — Add content to search -- [User Profiles](/user-profiles) — Get user context with search +- [Ingesting Content](/ingestion/add-memories) — Add content to search +- [User Profiles](/recall/user-profiles) — Get user context with search - [Organizing & Filtering](/concepts/filtering) — Container tags and metadata diff --git a/apps/docs/user-profiles.mdx b/apps/docs/recall/user-profiles.mdx similarity index 63% rename from apps/docs/user-profiles.mdx rename to apps/docs/recall/user-profiles.mdx index cb5c7cd1..b2348093 100644 --- a/apps/docs/user-profiles.mdx +++ b/apps/docs/recall/user-profiles.mdx @@ -1,6 +1,6 @@ --- title: "User Profiles" -sidebarTitle: "User Profiles" +sidebarTitle: "Overview" description: "Fetch and use automatically maintained user context" icon: "user" --- @@ -14,7 +14,7 @@ This profile should be injected into the agent context for truly personalized ex Get a user's profile — their static facts and dynamic context — with a single API call. -Profiles are built automatically as you [ingest content](/add-memories). No setup required. +Profiles are built automatically as you [ingest content](/ingestion/add-memories). No setup required. ## Quick Start @@ -123,7 +123,59 @@ Get profile and search results in one call by adding the `q` parameter: | `threshold` | 0-1 | No | Filter search results by relevance score | | `filters` | object | No | Metadata filters applied to profile and search results | | `include` | string[] | No | Sections to return — any of `"static"`, `"dynamic"`, `"buckets"`. Omit to return all | -| `buckets` | string[] | No | Restrict the `buckets` section to specific keys. Omit for all configured buckets | +| `buckets` | string[] | No | Restrict the `buckets` section to specific keys. Omit for all configured buckets. See [Profile Buckets](/user-profiles/buckets) | + +--- + +## Filtering Profiles + +Profiles support the same [metadata filters](/concepts/filtering) as `/search` and `/documents/list` — `filters` narrows which memories are eligible to contribute to `static`, `dynamic`, and `buckets`, not just which search results come back. + + + + ```typescript + const { profile } = await client.profile({ + containerTag: "user_123", + filters: { + AND: [{ key: "source", value: "onboarding" }], + }, + }); + ``` + + + ```python + result = client.profile( + container_tag="user_123", + filters={"AND": [{"key": "source", "value": "onboarding"}]}, + ) + ``` + + + ```bash + curl -X POST "https://api.supermemory.ai/v4/profile" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "containerTag": "user_123", + "filters": { "AND": [{ "key": "source", "value": "onboarding" }] } + }' + ``` + + + +Combine `filters` with `q` to scope both the profile synthesis and the accompanying search results in one call: + +```typescript +const result = await client.profile({ + containerTag: "org_customer_442", + q: "billing issue", + filters: { + AND: [{ key: "channel", value: "support_ticket" }], + }, +}); +``` + +All filter types from [Organizing & Filtering](/concepts/filtering) are supported — string equality, `string_contains`, `numeric`, `array_contains`, nested `AND`/`OR`, and `negate`. --- @@ -186,136 +238,13 @@ ${result.searchResults?.results.map(m => m.memory).join('\n') || 'None'} ## Profile Buckets Buckets are **custom topical categories** for a profile — an axis that sits alongside -`static` and `dynamic`. Where static/dynamic split facts by how long-lived they are, -buckets group them by subject (e.g. `preferences`, `goals`, `work`). As content is -ingested, a classifier assigns each memory to the buckets it matches, so you can pull -just the slice of context a given surface needs. +`static` and `dynamic`, grouping facts by subject (e.g. `preferences`, `goals`, +`work`) instead of by how long-lived they are. -Every org starts with a built-in `preferences` bucket. You can define your own at the -organization or space level in your console settings; space-level buckets are -**add-only** — a container tag inherits all org buckets and may add more, but cannot -disable them. - -### Requesting buckets - -Pass `include: ["buckets"]` to return bucket-organized memories, and optionally -`buckets` to limit the response to specific keys. `include` also lets you skip -sections you don't need — `["buckets"]` alone omits `static` and `dynamic`. - - - - ```typescript - const res = await fetch("https://api.supermemory.ai/v4/profile", { - method: "POST", - headers: { - "Authorization": `Bearer ${API_KEY}`, - "Content-Type": "application/json" - }, - body: JSON.stringify({ - containerTag: "user_123", - include: ["buckets"], - buckets: ["preferences", "goals"] // optional — omit for all buckets - }) - }); - - const { profile } = await res.json(); - console.log(profile.buckets.preferences); - console.log(profile.buckets.goals); - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/profile" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "containerTag": "user_123", - "include": ["buckets"], - "buckets": ["preferences", "goals"] - }' - ``` - - - -**Response:** -```json -{ - "profile": { - "buckets": { - "preferences": [ - "[Summary] Prefers concise, technical answers and dark-mode tooling", - "[Recent] Switched their editor to Zed" - ], - "goals": [ - "[Recent] Wants to ship the billing revamp this quarter" - ] - } - } -} -``` - - -**`[Recent]` and `[Summary]` labels.** To keep profiles dense, an entity's older -memories are periodically aggregated into a short synthesis. Entries prefixed -`[Summary]` are that aggregated context; entries prefixed `[Recent]` were ingested -since the last aggregation and aren't summarized yet. The `dynamic` section uses the -same `[Recent]` prefix (plus a `[YYYY-MM-DD]` date). Strip the prefixes if you only -want raw text, or keep them to signal recency to your model. - - -### List bucket definitions - -To see which buckets are configured for a container tag (org buckets merged with any -space-level additions), call `/v4/profile/buckets`: - - - - ```typescript - const res = await fetch("https://api.supermemory.ai/v4/profile/buckets", { - method: "POST", - headers: { - "Authorization": `Bearer ${API_KEY}`, - "Content-Type": "application/json" - }, - body: JSON.stringify({ containerTag: "user_123" }) - }); - - const { buckets } = await res.json(); - // [{ key: "preferences", description: "..." }, ...] - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/profile/buckets" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"containerTag": "user_123"}' - ``` - - - -**Response:** -```json -{ - "buckets": [ - { - "key": "preferences", - "description": "Explicit first-person preferences the person directly stated." - } - ] -} -``` - -| Field | Type | Description | -|-------|------|-------------| -| `buckets[].key` | string | Stable slug, also stored on each memory. Lowercase alphanumeric with `-`/`_`, 1–64 chars | -| `buckets[].description` | string | What belongs in the bucket — guides the ingestion classifier | - - -Bucket descriptions steer classification. A precise description ("Explicit -first-person preferences only — exclude inferred traits") yields cleaner buckets than -a vague one. `static` and `dynamic` are reserved and can't be used as bucket keys. - + + Read and configure buckets — request bucketed profiles, create org/space buckets, + get AI-generated bucket suggestions, and see validation limits. + --- @@ -404,6 +333,7 @@ interface ProfileResponse { ## Next Steps +- [Profile Buckets](/user-profiles/buckets) — Custom topical categories for profiles - [User Profiles Concept](/concepts/user-profiles) — Understand static vs dynamic -- [Ingesting Content](/add-memories) — Build profiles by adding content +- [Ingesting Content](/ingestion/add-memories) — Build profiles by adding content - [AI SDK Integration](/integrations/ai-sdk) — Automatic profile injection diff --git a/apps/docs/search/examples/document-search.mdx b/apps/docs/search/examples/document-search.mdx deleted file mode 100644 index 4ef11070..00000000 --- a/apps/docs/search/examples/document-search.mdx +++ /dev/null @@ -1,588 +0,0 @@ ---- -title: "Documents Search (/v3/search)" -description: "Full-featured search with extensive control over ranking, filtering, and results" ---- - -Documents search (`POST /v3/search`) provides maximum control over search behavior with extensive parameters for fine-tuning results. - -## Basic Implementation - - - - ```typescript - import Supermemory from 'supermemory'; - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }); - - const results = await client.search.documents({ - q: "machine learning neural networks", - limit: 5 - }); - - console.log(`Found ${results.total} documents in ${results.timing}ms`); - - // Sample output structure - results.results.forEach((doc, i) => { - console.log(`${i + 1}. ${doc.title} (Score: ${doc.score})`); - console.log(` ${doc.chunks.length} chunks found`); - }); - ``` - - - ```python - from supermemory import Supermemory - import os - - client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - - results = client.search.documents( - q="machine learning neural networks", - limit=5 - ) - - print(f"Found {results.total} documents in {results.timing}ms") - - # Sample output structure - for i, doc in enumerate(results.results): - print(f"{i + 1}. {doc.title} (Score: {doc.score})") - print(f" {len(doc.chunks)} chunks found") - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning neural networks", - "limit": 5 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "documentId": "doc_ml_guide_2024", - "title": "Machine Learning with Neural Networks: A Comprehensive Guide", - "score": 0.89, - "chunks": [ - { - "content": "Neural networks are computational models inspired by biological neural networks. They consist of interconnected nodes (neurons) that process information through weighted connections...", - "score": 0.92, - "isRelevant": true - }, - { - "content": "Deep learning, a subset of machine learning, uses neural networks with multiple hidden layers to learn complex patterns in data...", - "score": 0.87, - "isRelevant": true - } - ], - "createdAt": "2024-01-15T10:30:00Z", - "metadata": { - "category": "ai", - "difficulty": "intermediate" - } - } - ], - "total": 12, - "timing": 156 -} -``` - -## Container Tags Filtering - -Container tags are the primary way to isolate search results by user, project, or organization. - -**Key behaviors:** -- **Array-based**: Unlike `/v4/search`, this endpoint accepts multiple container tags as an array -- **Exact array matching**: Documents must have the EXACT same container tags array to match - - - - ```typescript - const results = await client.search.documents({ - q: "quarterly reports", - containerTags: ["user_123"], - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="quarterly reports", - container_tags=["user_123"], - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "quarterly reports", - "containerTags": ["user_123"], - "limit": 10 - }' - ``` - - - -## Metadata Filtering - -Metadata filtering allows complex conditions on structured data attached to your documents. This uses SQL-like query construction in the backend, requiring explicit AND/OR structures. - -**Filter structure rules:** -- **Must wrap conditions** in AND or OR arrays, even for single conditions -- **Supports string matching** (exact), numeric operators, and array contains -- **Negate any condition** with `negate: true` -- **Combines with container tags** - both filters are applied - - - - ```typescript - const results = await client.search.documents({ - q: "machine learning", - filters: { - AND: [ - { - key: "category", - value: "technology", - negate: false - }, - { - filterType: "numeric", - key: "readingTime", - value: "5", - negate: false, - numericOperator: "<=" - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="machine learning", - filters={ - "AND": [ - { - "key": "category", - "value": "technology", - "negate": False - }, - { - "filterType": "numeric", - "key": "readingTime", - "value": "5", - "negate": False, - "numericOperator": "<=" - } - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning", - "filters": { - "AND": [ - { - "key": "category", - "value": "technology", - "negate": false - }, - { - "filterType": "numeric", - "key": "readingTime", - "value": "5", - "negate": false, - "numericOperator": "<=" - } - ] - }, - "limit": 10 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "documentId": "doc_tech_trends_2024", - "title": "Technology Trends in Machine Learning", - "score": 0.91, - "chunks": [ - { - "content": "Machine learning continues to evolve with new architectures and optimization techniques. Reading time for this comprehensive overview is approximately 8 minutes...", - "score": 0.88, - "isRelevant": true - } - ], - "metadata": { - "category": "technology", - "readingTime": 8, - "difficulty": "intermediate", - "published": true - } - } - ], - "total": 6, - "timing": 189 -} -``` - -## Array Contains Filtering - -When your metadata includes arrays (like participant lists, tags, or categories), use `array_contains` to check if the array includes a specific value. - - - - ```typescript - const results = await client.search.documents({ - q: "meeting discussion", - filters: { - AND: [ - { - key: "participants", - value: "john.doe", - filterType: "array_contains" - } - ] - }, - limit: 5 - }); - ``` - - - ```python - results = client.search.documents( - q="meeting discussion", - filters={ - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains" - } - ] - }, - limit=5 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "meeting discussion", - "filters": { - "AND": [ - { - "key": "participants", - "value": "john.doe", - "filterType": "array_contains" - } - ] - }, - "limit": 5 - }' - ``` - - - -## Threshold Control - -Control result quality with sensitivity thresholds: - - - - ```typescript - const results = await client.search.documents({ - q: "artificial intelligence", - documentThreshold: 0.7, // Higher = fewer, more relevant documents - chunkThreshold: 0.8, // Higher = fewer, more relevant chunks - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="artificial intelligence", - document_threshold=0.7, # Higher = fewer, more relevant documents - chunk_threshold=0.8, # Higher = fewer, more relevant chunks - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "artificial intelligence", - "documentThreshold": 0.7, - "chunkThreshold": 0.8, - "limit": 10 - }' - ``` - - - -## Query Rewriting - -Improve search accuracy with automatic query rewriting: - - - - ```typescript - const results = await client.search.documents({ - q: "What is the capital of France?", - rewriteQuery: true, // +400ms latency but better results - limit: 5 - }); - ``` - - - ```python - results = client.search.documents( - q="What is the capital of France?", - rewrite_query=True, # +400ms latency but better results - limit=5 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "What is the capital of France?", - "rewriteQuery": true, - "limit": 5 - }' - ``` - - - - -Query rewriting generates multiple query variations and searches through all of them, then merges results. No additional cost but adds ~400ms latency. - - -## Reranking - -Improve result quality with secondary ranking: - - - - ```typescript - const results = await client.search.documents({ - q: "machine learning applications", - rerank: true, // Apply secondary ranking algorithm - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="machine learning applications", - rerank=True, # Apply secondary ranking algorithm - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning applications", - "rerank": true, - "limit": 10 - }' - ``` - - - -## Document-Specific Search - -Search within a specific large document: - - - - ```typescript - const results = await client.search.documents({ - q: "neural networks", - docId: "doc_123", // Search only within this document - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="neural networks", - doc_id="doc_123", # Search only within this document - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "neural networks", - "docId": "doc_123", - "limit": 10 - }' - ``` - - - -## Full Context Options - -Include complete document content and summaries: - - - - ```typescript - const results = await client.search.documents({ - q: "research findings", - includeFullDocs: true, // Include complete document content - includeSummary: true, // Include document summaries - onlyMatchingChunks: false, // Include all chunks, not just matching ones - limit: 5 - }); - ``` - - - ```python - results = client.search.documents( - q="research findings", - include_full_docs=True, # Include complete document content - include_summary=True, # Include document summaries - only_matching_chunks=False, # Include all chunks, not just matching ones - limit=5 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "research findings", - "includeFullDocs": true, - "includeSummary": true, - "onlyMatchingChunks": false, - "limit": 5 - }' - ``` - - - -## Complete Advanced Example - -Combining all features for maximum control: - - - - ```typescript - const results = await client.search.documents({ - q: "machine learning performance metrics", - containerTags: ["research_project"], - filters: { - AND: [ - { key: "category", value: "ai", negate: false }, - { key: "status", value: "published", negate: false } - ] - }, - documentThreshold: 0.6, - chunkThreshold: 0.7, - rewriteQuery: true, - rerank: true, - includeFullDocs: false, - includeSummary: true, - onlyMatchingChunks: true, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="machine learning performance metrics", - container_tags=["research_project"], - filters={ - "AND": [ - {"key": "category", "value": "ai", "negate": False}, - {"key": "status", "value": "published", "negate": False} - ] - }, - document_threshold=0.6, - chunk_threshold=0.7, - rewrite_query=True, - rerank=True, - include_full_docs=False, - include_summary=True, - only_matching_chunks=True, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning performance metrics", - "containerTags": ["research_project"], - "filters": { - "AND": [ - {"key": "category", "value": "ai", "negate": false}, - {"key": "status", "value": "published", "negate": false} - ] - }, - "documentThreshold": 0.6, - "chunkThreshold": 0.7, - "rewriteQuery": true, - "rerank": true, - "includeFullDocs": false, - "includeSummary": true, - "onlyMatchingChunks": true, - "limit": 10 - }' - ``` - - diff --git a/apps/docs/search/examples/memory-search.mdx b/apps/docs/search/examples/memory-search.mdx deleted file mode 100644 index c6d18b6e..00000000 --- a/apps/docs/search/examples/memory-search.mdx +++ /dev/null @@ -1,695 +0,0 @@ ---- -title: "Memories Search (/v4/search)" -description: "Minimal-latency search optimized for chatbots and conversational AI" ---- - - -Memories search (`POST /v4/search`) provides minimal-latency search optimized for real-time interactions. This endpoint prioritizes speed over extensive control, making it perfect for chatbots, Q&A systems, and any application where users expect immediate responses. - -## Basic Search - - - - ```typescript - import Supermemory from 'supermemory'; - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }); - - const results = await client.search.memories({ - q: "machine learning applications", - limit: 5 - }); - - console.log(results) - ``` - - - ```python - from supermemory import Supermemory - import os - - client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - - results = client.search.memories( - q="machine learning applications", - limit=5 - ) - - console.log(results) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning applications", - "limit": 5 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "id": "mem_ml_apps_2024", - "memory": "Machine learning applications span numerous industries including healthcare (diagnostic imaging, drug discovery), finance (fraud detection, algorithmic trading), autonomous vehicles (computer vision, path planning), and natural language processing (chatbots, translation services).", - "similarity": 0.92, - "title": "Machine Learning Industry Applications", - "type": "text", - "metadata": { - "topic": "machine-learning", - "industry": "technology", - "created": "2024-01-10" - } - }, - { - "id": "mem_ml_healthcare", - "memory": "In healthcare, machine learning enables early disease detection through medical imaging analysis, personalized treatment recommendations, and drug discovery acceleration by predicting molecular behavior.", - "similarity": 0.89, - "title": "ML in Healthcare", - "type": "text" - } - ], - "total": 8, - "timing": 87 -} -``` - -## Container Tag Filtering - -Filter by user, project, or organization: - - - - ```typescript - const results = await client.search.memories({ - q: "project updates", - containerTag: "user_123", // Note: singular, not plural - limit: 10 - }); - ``` - - - ```python - results = client.search.memories( - q="project updates", - container_tag="user_123", # Note: singular, not plural - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "project updates", - "containerTag": "user_123", - "limit": 10 - }' - ``` - - - -## Threshold Control - -Control result quality with similarity threshold: - - - - ```typescript - const results = await client.search.memories({ - q: "artificial intelligence research", - threshold: 0.7, // Higher = fewer, more similar results - limit: 10 - }); - ``` - - - ```python - results = client.search.memories( - q="artificial intelligence research", - threshold=0.7, # Higher = fewer, more similar results - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "artificial intelligence research", - "threshold": 0.7, - "limit": 10 - }' - ``` - - - -## Reranking - -Improve result quality with secondary ranking: - - - - ```typescript - const results = await client.search.memories({ - q: "quantum computing breakthrough", - rerank: true, // Better relevance, slight latency increase - limit: 5 - }); - ``` - - - ```python - results = client.search.memories( - q="quantum computing breakthrough", - rerank=True, # Better relevance, slight latency increase - limit=5 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "quantum computing breakthrough", - "rerank": true, - "limit": 5 - }' - ``` - - - -## Query Rewriting - -Improve search accuracy with automatic query expansion: - - - - ```typescript - const results = await client.search.memories({ - q: "How do neural networks learn?", - rewriteQuery: true, // +400ms latency but better results - limit: 5 - }); - ``` - - - ```python - results = client.search.memories( - q="How do neural networks learn?", - rewrite_query=True, # +400ms latency but better results - limit=5 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "How do neural networks learn?", - "rewriteQuery": true, - "limit": 5 - }' - ``` - - - -## Include Related Content - -Include documents, related memories, and summaries: - - - - ```typescript - const results = await client.search.memories({ - q: "machine learning trends", - include: { - documents: true, // Include source documents - relatedMemories: true, // Include related memory entries - summaries: true // Include memory summaries - }, - limit: 5 - }); - ``` - - - ```python - results = client.search.memories( - q="machine learning trends", - include={ - "documents": True, # Include source documents - "relatedMemories": True, # Include related memory entries - "summaries": True # Include memory summaries - }, - limit=5 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning trends", - "include": { - "documents": true, - "relatedMemories": true, - "summaries": true - }, - "limit": 5 - }' - ``` - - - -## Metadata Filtering - -Simple metadata filtering for Memories search: - - - - ```typescript - const results = await client.search.memories({ - q: "research findings", - filters: { - AND: [ - { key: "category", value: "science", negate: false }, - { key: "status", value: "published", negate: false } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.memories( - q="research findings", - filters={ - "AND": [ - {"key": "category", "value": "science", "negate": False}, - {"key": "status", "value": "published", "negate": False} - ] - }, - limit=10 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "research findings", - "filters": { - "AND": [ - {"key": "category", "value": "science", "negate": false}, - {"key": "status", "value": "published", "negate": false} - ] - }, - "limit": 10 - }' - ``` - - - -## Chatbot Example - -Optimal configuration for conversational AI: - - - - ```typescript - // Optimized for chatbot responses - const results = await client.search.memories({ - q: userMessage, - containerTag: userId, - threshold: 0.6, // Balanced relevance - rerank: false, // Skip for speed - rewriteQuery: false, // Skip for speed - limit: 3 // Few, relevant results - }); - - // Quick response for chat - const context = results.results - .map(r => r.memory) - .join('\n\n'); - ``` - - - ```python - # Optimized for chatbot responses - results = client.search.memories( - q=user_message, - container_tag=user_id, - threshold=0.6, # Balanced relevance - rerank=False, # Skip for speed - rewrite_query=False, # Skip for speed - limit=3 # Few, relevant results - ) - - # Quick response for chat - context = '\n\n'.join([r.memory for r in results.results]) - ``` - - - ```bash - # Optimized for chatbot responses - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "user question here", - "containerTag": "user_123", - "threshold": 0.6, - "rerank": false, - "rewriteQuery": false, - "limit": 3 - }' - ``` - - - -## Complete Memories Search Example - -Combining features for comprehensive results: - - - - ```typescript - const results = await client.search.memories({ - q: "machine learning model performance", - containerTag: "research_team", - filters: { - AND: [ - { key: "topic", value: "ai", negate: false } - ] - }, - threshold: 0.7, - rerank: true, - rewriteQuery: false, // Skip for speed - include: { - documents: true, - relatedMemories: false, - summaries: true - }, - limit: 5 - }); - ``` - - - ```python - results = client.search.memories( - q="machine learning model performance", - container_tag="research_team", - filters={ - "AND": [ - {"key": "topic", "value": "ai", "negate": False} - ] - }, - threshold=0.7, - rerank=True, - rewrite_query=False, # Skip for speed - include={ - "documents": True, - "relatedMemories": False, - "summaries": True - }, - limit=5 - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning model performance", - "containerTag": "research_team", - "filters": { - "AND": [ - {"key": "topic", "value": "ai", "negate": false} - ] - }, - "threshold": 0.7, - "rerank": true, - "rewriteQuery": false, - "include": { - "documents": true, - "relatedMemories": false, - "summaries": true - }, - "limit": 5 - }' - ``` - - - -## Hybrid Search Mode - -Hybrid search mode allows you to search both memories and document chunks in a single request. When `searchMode="hybrid"`, results contain objects with either a `memory` key (for memory results) or a `chunk` key (for chunk results). - -### Basic Hybrid Search - - - - ```typescript - const results = await client.search.memories({ - q: "machine learning best practices", - searchMode: "hybrid", // Search memories + chunks - limit: 10 - }); - - // Handle mixed results - results.results.forEach(result => { - if ('memory' in result) { - console.log('Memory:', result.memory); - } else if ('chunk' in result) { - console.log('Chunk:', result.chunk); - console.log('From document:', result.documents?.[0]?.title); - } - }); - ``` - - - ```python - results = client.search.memories( - q="machine learning best practices", - search_mode="hybrid", # Search memories + chunks - limit=10 - ) - - # Handle mixed results - for result in results.results: - if 'memory' in result: - print('Memory:', result['memory']) - elif 'chunk' in result: - print('Chunk:', result['chunk']) - print('From document:', result.get('documents', [{}])[0].get('title')) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning best practices", - "searchMode": "hybrid", - "limit": 10 - }' - ``` - - - -### When to Use Hybrid Mode - -Use hybrid mode when: -- You want comprehensive search across both memories and documents -- Memories might not exist for certain queries but document content is available -- You need flexibility to get either memory or document chunk results -- You want a single search endpoint that covers all content types - -Use memories-only mode (`searchMode="memories"`) when: -- You only need user memories and preferences -- You want faster, more focused results -- You're building a personalized chatbot that relies on user context - -### Handling Mixed Results - -When using hybrid mode, you'll receive mixed results. Here's how to process them: - - - - ```typescript - const results = await client.search.memories({ - q: "quantum computing applications", - searchMode: "hybrid", - limit: 10 - }); - - // Separate memory and chunk results - const memoryResults = results.results.filter(r => 'memory' in r); - const chunkResults = results.results.filter(r => 'chunk' in r); - - console.log(`Found ${memoryResults.length} memories and ${chunkResults.length} chunks`); - - // Process memories - memoryResults.forEach(mem => { - console.log('Memory:', mem.memory); - console.log('Similarity:', mem.similarity); - }); - - // Process chunks - chunkResults.forEach(chunk => { - console.log('Chunk:', chunk.chunk); - console.log('Document:', chunk.documents?.[0]?.title); - console.log('Similarity:', chunk.similarity); - }); - ``` - - - ```python - results = client.search.memories( - q="quantum computing applications", - search_mode="hybrid", - limit=10 - ) - - # Separate memory and chunk results - memory_results = [r for r in results.results if 'memory' in r] - chunk_results = [r for r in results.results if 'chunk' in r] - - print(f"Found {len(memory_results)} memories and {len(chunk_results)} chunks") - - # Process memories - for mem in memory_results: - print('Memory:', mem['memory']) - print('Similarity:', mem['similarity']) - - # Process chunks - for chunk in chunk_results: - print('Chunk:', chunk['chunk']) - print('Document:', chunk.get('documents', [{}])[0].get('title')) - print('Similarity:', chunk['similarity']) - ``` - - - -### Hybrid Search with All Features - -Combining hybrid mode with other features: - - - - ```typescript - const results = await client.search.memories({ - q: "research findings on AI", - searchMode: "hybrid", - containerTag: "research_team", - threshold: 0.7, - rerank: true, - include: { - documents: true, - relatedMemories: true, - summaries: true - }, - limit: 10 - }); - - // Results are automatically sorted by similarity - // Memory results have 'memory' field, chunk results have 'chunk' field - results.results.forEach(result => { - if ('memory' in result) { - // Memory result - console.log('Memory:', result.memory); - console.log('Context:', result.context); - } else { - // Chunk result - console.log('Chunk:', result.chunk); - console.log('Document:', result.documents?.[0]); - } - }); - ``` - - - ```python - results = client.search.memories( - q="research findings on AI", - search_mode="hybrid", - container_tag="research_team", - threshold=0.7, - rerank=True, - include={ - "documents": True, - "relatedMemories": True, - "summaries": True - }, - limit=10 - ) - - # Results are automatically sorted by similarity - # Memory results have 'memory' field, chunk results have 'chunk' field - for result in results.results: - if 'memory' in result: - # Memory result - print('Memory:', result['memory']) - print('Context:', result.get('context')) - else: - # Chunk result - print('Chunk:', result['chunk']) - print('Document:', result.get('documents', [{}])[0]) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "research findings on AI", - "searchMode": "hybrid", - "containerTag": "research_team", - "threshold": 0.7, - "rerank": true, - "include": { - "documents": true, - "relatedMemories": true, - "summaries": true - }, - "limit": 10 - }' - ``` - - - - - **Important**: In hybrid mode, results are automatically merged and sorted by similarity score. Memory results and chunk results are deduplicated - if a chunk is already associated with a memory result, it won't appear as a separate chunk result. - - -## Common Use Cases - -- **Chatbots**: Basic search with container tag and low threshold -- **Q&A Systems**: Add reranking for better relevance -- **Knowledge Retrieval**: Include documents and summaries -- **Real-time Search**: Skip rewriting and reranking for maximum speed -- **Hybrid Search**: Use `searchMode="hybrid"` when you need comprehensive search across both memories and documents diff --git a/apps/docs/search/overview.mdx b/apps/docs/search/overview.mdx deleted file mode 100644 index 32c2d7da..00000000 --- a/apps/docs/search/overview.mdx +++ /dev/null @@ -1,493 +0,0 @@ ---- -title: "Search with Filters & Scoring" -description: "Semantic and hybrid search with metadata filters, scoring, and precise result control" -sidebarTitle : "Overview" ---- - -## Prerequisites - -Before searching memories, you need to set up the Supermemory client: - -- **Install the SDK** for your language -- **Get your API key** from [Supermemory Console](https://console.supermemory.ai) -- **Initialize the client** with your API key - - - -```bash npm -npm install supermemory -``` - -```bash pip -pip install supermemory -``` - - - - - -```typescript TypeScript -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! -}); -``` - -```python Python -from supermemory import Supermemory -import os - -client = Supermemory( - api_key=os.environ.get("SUPERMEMORY_API_KEY") -) -``` - - - -## Search Endpoints Overview - - - - **POST /v3/search** - - Full-featured search with extensive control over ranking, filtering, thresholds, and result structure. Searches through and returns relevant documents. More flexibility. - - - - **POST /v4/search** - - Minimal-latency search optimized for chatbots and conversational AI. Searches through and returns memories. Simple parameters, fast responses, easy to use. - - - -## Documents vs Memories Search: What's the Difference? - -The key difference between `/v3/search` and `/v4/search` is **documents vs memories**. `/v3/search` searches through the documents and returns matching chunks, whereas `/v4/search` searches through user's memories, preferences and history. - -- **Documents:** Refer to the data you ingest like text, pdfs, videos, images, etc. They are sources of ground truth. -- **Memories:** They are automatically extracted from your documents by Supermemory. Smaller information chunks inferred from documents and related to each other. - -Refer to the [ingestion guide](/memory-api/ingesting) to learn more about the difference between documents and memories. - -### Documents Search (`/v3/search`) -**High quality documents search** - extensive parameters for fine-tuning search behavior: - -- **Use cases**: Use this endpoint for use cases where "literal" document search is required. - - Looking through legal/finance documents - - Searching through items in google drive - - Chat with documentation -- With this endpoint, you get **Full Control** over - - Thresholds, - - Filtering - - Reranking - - Query rewriting - - - - ```typescript - // Documents search - const results = await client.search.documents({ - q: "machine learning accuracy", - limit: 10, - documentThreshold: 0.7, - chunkThreshold: 0.8, - rerank: true, - rewriteQuery: true, - includeFullDocs: true, - includeSummary: true, - onlyMatchingChunks: false, - containerTags: ["research"], - filters: { - AND: [{ key: "category", value: "ai", negate: false }] - } - }); - ``` - - - ```python - # Documents search - results = client.search.documents( - q="machine learning accuracy", - limit=10, - document_threshold=0.7, - chunk_threshold=0.8, - rerank=True, - rewrite_query=True, - include_full_docs=True, - include_summary=True, - only_matching_chunks=False, - container_tags=["research"], - filters={ - "AND": [{"key": "category", "value": "ai", "negate": False}] - } - ) - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning accuracy", - "limit": 10, - "documentThreshold": 0.7, - "chunkThreshold": 0.8, - "rerank": true, - "rewriteQuery": true, - "includeFullDocs": true, - "includeSummary": true, - "onlyMatchingChunks": false, - "containerTags": ["research"], - "filters": { - "AND": [{"key": "category", "value": "ai", "negate": false}] - } - }' - ``` - - - -```json Sample Response - -{ - "results": [ - { - "documentId": "doc_abc123", - "title": "Machine Learning Fundamentals", - "type": "pdf", - "score": 0.89, - "chunks": [ - { - "content": "Machine learning is a subset of artificial intelligence...", - "score": 0.95, - "isRelevant": true - } - ], - "metadata": { - "category": "education", - "author": "Dr. Smith", - "difficulty": "beginner" - }, - "createdAt": "2024-01-15T10:30:00Z", - "updatedAt": "2024-01-20T14:45:00Z" - } - ], - "timing": 187, - "total": 1 -} -``` - -The `/v3/search` endpoint returns the most relevant documents and chunks from those documents. Head over to the [response schema](/search/response-schema) page to understand more about the response structure. - -### Memories Search (`/v4/search`) -**Search through user memories**: - -- **Use cases**: Use this endpoint for use cases where understanding user context / preferences / memories is more important than literal document search. - - Personalized chatbots (AI Companions) - - Auto selecting based on what the user wants - - Setting the tone of the conversation - -Companies like Composio [Rube.app](https://rube.app) use memories search for letting the MCP automate better based on the user prompts before. - - - This endpoint works best for conversational AI use cases like chatbots. - - -**Hybrid Search Mode:** - -The `/v4/search` endpoint supports a `searchMode` parameter with two options: - -- **`"memories"`** (default): Searches only memory entries. Returns results with a `memory` key containing the memory content. -- **`"hybrid"`**: Searches memories first, then falls back to document chunks if needed. Returns mixed results where each result object has either a `memory` key (for memory results) or a `chunk` key (for chunk results from documents). - - - In hybrid mode, results are automatically merged by similarity score and deduplicated. Check for the presence of `memory` or `chunk` keys to distinguish result types. - - - - - ```typescript - // Memories search (default mode) - const results = await client.search.memories({ - q: "machine learning accuracy", - limit: 5, - containerTag: "research", - threshold: 0.7, - rerank: true, - searchMode: "memories" // Default: only search memories - }); - - // Hybrid search (memories + chunks) - const hybridResults = await client.search.memories({ - q: "machine learning accuracy", - limit: 5, - containerTag: "research", - threshold: 0.7, - searchMode: "hybrid" // Search memories + fallback to chunks - }); - ``` - - - ```python - # Memories search (default mode) - results = client.search.memories( - q="machine learning accuracy", - limit=5, - container_tag="research", - threshold=0.7, - rerank=True, - search_mode="memories" # Default: only search memories - ) - - # Hybrid search (memories + chunks) - hybrid_results = client.search.memories( - q="machine learning accuracy", - limit=5, - container_tag="research", - threshold=0.7, - search_mode="hybrid" # Search memories + fallback to chunks - ) - ``` - - - ```bash - # Memories search (default mode) - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning accuracy", - "limit": 5, - "containerTag": "research", - "threshold": 0.7, - "rerank": true, - }' - - # Hybrid search (memories + chunks) - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning accuracy", - "limit": 5, - "containerTag": "research", - "threshold": 0.7, - "rerank": true, - "searchMode": "hybrid" - }' - ``` - - - - -```json Sample Response -{ - "results": [ - { - "id": "mem_xyz789", - "memory": "Complete memory content about quantum computing applications...", - "similarity": 0.87, - "metadata": { - "category": "research", - "topic": "quantum-computing" - }, - "updatedAt": "2024-01-18T09:15:00Z", - "version": 3, - "context": { - "parents": [ - { - "memory": "Earlier discussion about quantum theory basics...", - "relation": "extends", - "version": 2, - "updatedAt": "2024-01-17T16:30:00Z" - } - ], - "children": [ - { - "memory": "Follow-up questions about quantum algorithms...", - "relation": "derives", - "version": 4, - "updatedAt": "2024-01-19T11:20:00Z" - } - ] - }, - "documents": [ - { - "id": "doc_quantum_paper", - "title": "Quantum Computing Applications", - "type": "pdf", - "createdAt": "2024-01-10T08:00:00Z" - } - ] - } - ], - "timing": 156, - "total": 1 -} - -``` - -The `/v4/search` endpoint searches through and returns memories. With `searchMode="hybrid"`, it can also return document chunks when memories aren't found, providing comprehensive search coverage. - -## Direct Document Retrieval - -If you don't need semantic search and just want to retrieve a specific document you've uploaded by its ID, use the GET document endpoint: - -`GET /v3/documents/{id}` - -This is useful when: -- You know the exact document ID -- You want to retrieve the full document content and metadata -- You need to check processing status or document details - - - -```typescript TypeScript -// Get a specific document by ID -const document = await client.documents.get("doc_abc123"); - -console.log(document.content); // Full document content -console.log(document.status); // Processing status -console.log(document.metadata); // Document metadata -console.log(document.summary); // AI-generated summary -``` - -```python Python -# Get a specific document by ID -document = client.documents.get("doc_abc123") - -print(document.content) # Full document content -print(document.status) # Processing status -``` - -```bash cURL -curl -X GET "https://api.supermemory.ai/v3/documents/{YOUR-DOCUMENT-ID}" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" -``` - - - - -This endpoint returns the complete document with all fields including content, metadata, containerTags, summary, and processing status. For more details, see the API Reference tab. - - -## Search Flow Architecture - -### Document Search (`/v3/search`) Flow - -```mermaid -graph TD - A[Query Input] --> B{Rewrite Query?} - B -->|Yes| C[Query Rewriting +400ms] - B -->|No| D[Generate Embeddings] - C --> E[Generate Rewritten Embeddings] - D --> F[Search Execution] - E --> F - F --> G[Apply Filtering
metadata, categories, containerTags] - G --> H{Rerank?} - H -->|Yes| I[Apply Reranking] - H -->|No| J[Build Results with Chunks] - I --> J - J --> K[Return Documents + Chunks + Scores] -``` - -### Memory Search (`/v4/search`) Flow - -```mermaid -graph TD - A[Query Input] --> B[Query Rewriting + Embedding] - B --> C[Parallel Search Execution] - C --> D[Apply Filtering] - D --> E[Merge Results] - E --> F[Deduplication] - F --> G{Rerank?} - G -->|Yes| H[Apply Reranking] - G -->|No| I[Return Memories + Similarity] - H --> I -``` - -## Key Concepts You Need to Understand - -### 1. Thresholds (Sensitivity Control) - -Thresholds control result quality vs quantity: - -- **0.0** = Least sensitive (more results, lower quality) -- **1.0** = Most sensitive (fewer results, higher quality) - -```typescript -// Different threshold strategies -const broadSearch = await client.search.documents({ - q: "machine learning", - chunkThreshold: 0.2, // Return more chunks - documentThreshold: 0.1 // From more documents -}); - -const preciseSearch = await client.search.documents({ - q: "machine learning", - chunkThreshold: 0.8, // Only highly relevant chunks - documentThreshold: 0.7 // From closely matching documents -}); -``` - -### 2. Chunk Context vs Exact Matching - -By default, Supermemory returns chunks **with context** (surrounding text): - -```typescript -// Default: includes surrounding chunks for context -const contextualResults = await client.search.documents({ - q: "neural networks", - onlyMatchingChunks: false // Default -}); - -// Precise: only the exact matching text -const exactResults = await client.search.documents({ - q: "neural networks", - onlyMatchingChunks: true -}); -``` - -### 3. Query Rewriting & Reranking - -**Query Rewriting** (+400ms latency): -- Expands your query to find more relevant results -- "ML" becomes "machine learning artificial intelligence" -- Useful for abbreviations and domain-specific terms - -**Reranking**: -- Re-scores results using a different algorithm -- More accurate but slower -- Recommended for critical searches - -### 4. Container Tags vs Metadata Filters - -Two different filtering mechanisms: - -When to use container tags: - - The user understanding graph is built on top of container tags. **The graph is formed on top of container tags.** - - Container tags are used for organizational grouping and exact matching. - - They are useful for categorizing content and ensuring precise results. -When to use metadata filters: - - When you need flexible conditions beyond exact matches. - - Useful for filtering by attributes like date, author, or category. - -```typescript -// Container tags: Organizational grouping (exact array matching) -const userContent = await client.search.documents({ - q: "python tutorial", - containerTag "user_123" // Must match exactly -}); - -// Metadata filters: SQL-based queries (flexible conditions) -const filteredContent = await client.search.documents({ - q: "python tutorial", - filters: JSON.stringify({ - AND: [ - { key: "language", value: "python", negate: false }, - { key: "difficulty", value: "beginner", negate: false } - ] - }) -}); -``` diff --git a/apps/docs/search/parameters.mdx b/apps/docs/search/parameters.mdx deleted file mode 100644 index f9df18da..00000000 --- a/apps/docs/search/parameters.mdx +++ /dev/null @@ -1,264 +0,0 @@ ---- -title: "Search Parameters" -description: "Complete reference for all search parameters and their effects" ---- - - -Complete parameter reference for all three search endpoints: document search, memory search, and execute search. - -## Common Parameters - -These parameters work across all search endpoints: - - - **Search query string** - - The text you want to search for. Can be natural language, keywords, or questions. - - ```typescript - q: "machine learning neural networks" - q: "What are the applications of quantum computing?" - q: "python tutorial beginner" - ``` - - - - **Maximum number of results to return** - - Controls how many results you get back. Higher limits increase response time and size. - - ```typescript - limit: 5 // Fast, focused results - limit: 20 // Comprehensive results - limit: 100 // Maximum recommended - ``` - - - - **Filter by container tags** - - Organizational tags for filtering results. Uses **exact array matching** - must match all tags in the same order. - - ```typescript - containerTags: ["user_123"] // Single tag - containerTags: ["user_123", "project_ai"] // Multiple tags (exact match) - ``` - - - - **Metadata filtering with SQL-like structure** - - JSON string containing AND/OR logic for filtering by metadata fields. Uses the same structure as memory listing filters. - - ```typescript - filters: JSON.stringify({ - AND: [ - { key: "category", value: "tutorial", negate: false }, - { key: "difficulty", value: "beginner", negate: false } - ] - }) - ``` - - - See [Metadata Filtering Guide](/concepts/filtering) for complete syntax and examples. - - - - - **Re-score results for better relevance** - - Applies a secondary ranking algorithm to improve result quality. Adds ~100-200ms latency but increases accuracy. - - ```typescript - rerank: true // Better accuracy, slower - rerank: false // Faster, standard accuracy - ``` - - - - **Expand and improve the query** - - Rewrites your query to find more relevant results. Particularly useful for abbreviations and domain-specific terms. **Adds ~400ms latency**. - - ```typescript - // Query rewriting examples: - "ML" → "machine learning artificial intelligence" - "JS" → "JavaScript programming language" - "API" → "application programming interface REST" - ``` - - - Query rewriting significantly increases latency. Only use when search quality is more important than speed. - - - -## Document Search Parameters (POST `/v3/search`) - -These parameters are specific to `client.search.documents()`: - - - **Sensitivity for chunk selection** - - Controls which text chunks are included in results: - - **0.0** = Least sensitive (more chunks, more results) - - **1.0** = Most sensitive (fewer chunks, higher quality) - - ```typescript - chunkThreshold: 0.2 // Broad search, many chunks - chunkThreshold: 0.8 // Precise search, only relevant chunks - ``` - - - - **Sensitivity for document selection** - - Controls which documents are considered for search: - - **0.0** = Search more documents (comprehensive) - - **1.0** = Search only highly relevant documents (focused) - - ```typescript - documentThreshold: 0.1 // Cast wide net - documentThreshold: 0.9 // Only very relevant documents - ``` - - - - **Search within a specific document** - - Limit search to chunks within a single document. Useful for finding content in large documents. - - ```typescript - docId: "doc_abc123" // Only search this document - ``` - - - - **Return only exact matching chunks** - - By default, Supermemory includes surrounding chunks for context. Set to `true` to get only the exact matching text. - - ```typescript - onlyMatchingChunks: false // Include context chunks (default) - onlyMatchingChunks: true // Only matching chunks - ``` - - - Context chunks help LLMs understand the full meaning. Only disable if you need precise text extraction. - - - - - **Include complete document content** - - Adds the full document text to each result. Useful for chatbots that need complete context. - - ```typescript - includeFullDocs: true // Full document in response - includeFullDocs: false // Only chunks and metadata - ``` - - - Including full documents can make responses very large. Use sparingly and with appropriate limits. - - - - - **Include document summaries** - - Adds AI-generated document summaries to results. Good middle-ground between chunks and full documents. - - ```typescript - includeSummary: true // Include document summaries - includeSummary: false // No summaries - ``` - - - - **Filter by metadata using SQL queries** - - ```typescript - - // Use this instead: - filters: JSON.stringify({ - OR: [ - { key: "category", value: "technology", negate: false }, - { key: "category", value: "science", negate: false } - ] - }) - ``` - - -## Memory Search Parameters (POST `/v4/search`) - -These parameters are specific to `client.search.memories()`: - - - **Sensitivity for memory selection** - - Controls which memories are returned based on similarity: - - **0.0** = Return more memories (broad search) - - **1.0** = Return only highly similar memories (precise search) - - ```typescript - threshold: 0.3 // Broader memory search - threshold: 0.8 // Only very similar memories - ``` - - - - **Search mode - memories only or hybrid search** - - Controls whether to search only memories or also include document chunks: - - **`"memories"`** (default): Searches only memory entries. Returns results with `memory` field. - - **`"hybrid"`**: Searches memories first, then falls back to document chunks if needed. Returns mixed results with either `memory` field (for memory results) or `chunk` field (for chunk results). - - - In hybrid mode, results are automatically merged and deduplicated. Results contain objects with either a `memory` key (for memory results) or a `chunk` key (for chunk results from document search). - - - ```typescript - searchMode: "memories" // Only search memories (default) - searchMode: "hybrid" // Search memories + fallback to chunks - ``` - - **When to use hybrid mode:** - - When you want comprehensive search across both memories and documents - - When memories might not exist for certain queries but document content is available - - When you need the flexibility to get either memory or document chunk results - - - - **Filter by single container tag** - - Note: Memory search uses `containerTag` (singular) while document search uses `containerTags` (plural array). - - ```typescript - containerTag: "user_123" // Single tag for memory search - ``` - - - - **Control what additional data to include** - - Object specifying what contextual information to include with memory results. - - - Include associated documents for each memory - - - - Include parent and child memories (contextual relationships) - - - - Include memory summaries - - - ```typescript - include: { - documents: true, // Show related documents - relatedMemories: true, // Show parent/child memories - summaries: true // Include summaries - } - ``` - diff --git a/apps/docs/search/query-rewriting.mdx b/apps/docs/search/query-rewriting.mdx deleted file mode 100644 index 114af692..00000000 --- a/apps/docs/search/query-rewriting.mdx +++ /dev/null @@ -1,440 +0,0 @@ ---- -title: "Query Rewriting" -description: "Improve search accuracy with automatic query expansion and rewriting" ---- - - -![query rewriting](/images/query-rewriting.png) - -Query rewriting automatically generates multiple variations of your search query to improve result coverage and accuracy. Supermemory creates several rewrites, searches through all of them, then merges and deduplicates the results. - -## How Query Rewriting Works - -When you enable `rewriteQuery: true`, Supermemory: - -1. **Analyzes your original query** for intent and key concepts -2. **Generates multiple rewrites** with different phrasings and synonyms -3. **Executes searches** for both original and rewritten queries in parallel -4. **Merges and deduplicates** results from all queries -5. **Returns unified results** ranked by relevance - -This process adds ~400ms latency but significantly improves result quality, especially for: -- **Natural language questions** ("How do neural networks learn?") -- **Ambiguous terms** that could have multiple meanings -- **Complex queries** with multiple concepts -- **Domain-specific terminology** that might have synonyms - -## Basic Query Rewriting - - - - ```typescript - import Supermemory from 'supermemory'; - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }); - - // Without query rewriting - const basicResults = await client.search.documents({ - q: "How do transformers work in AI?", - rewriteQuery: false, - limit: 5 - }); - - // With query rewriting - generates multiple query variations - const rewrittenResults = await client.search.documents({ - q: "How do transformers work in AI?", - rewriteQuery: true, - limit: 5 - }); - - console.log(`Basic search: ${basicResults.total} results`); - console.log(`Rewritten search: ${rewrittenResults.total} results`); - ``` - - - ```python - from supermemory import Supermemory - import os - - client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - - # Without query rewriting - basic_results = client.search.documents( - q="How do transformers work in AI?", - rewrite_query=False, - limit=5 - ) - - # With query rewriting - generates multiple query variations - rewritten_results = client.search.documents( - q="How do transformers work in AI?", - rewrite_query=True, - limit=5 - ) - - print(f"Basic search: {basic_results.total} results") - print(f"Rewritten search: {rewritten_results.total} results") - ``` - - - ```bash - # Without query rewriting - echo "Basic search:" - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "How do transformers work in AI?", - "rewriteQuery": false, - "limit": 5 - }' | jq '.total' - - # With query rewriting - echo "Rewritten search:" - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "How do transformers work in AI?", - "rewriteQuery": true, - "limit": 5 - }' | jq '.total' - ``` - - - -**Sample Output Comparison:** -```json -// Without rewriting: 3 results -{ - "results": [...], - "total": 3, - "timing": 120 -} - -// With rewriting: 8 results (found more relevant content) -{ - "results": [...], - "total": 8, - "timing": 520 // +400ms for query processing -} -``` - -## Natural Language Questions - -Query rewriting excels at converting conversational questions into effective search queries: - - - - ```typescript - // Natural language question - const results = await client.search.documents({ - q: "What are the best practices for training deep learning models?", - rewriteQuery: true, - limit: 10 - }); - - // The system might generate rewrites like: - // - "deep learning model training best practices" - // - "neural network training optimization techniques" - // - "machine learning model training guidelines" - // - "deep learning training methodology" - ``` - - - ```python - # Natural language question - results = client.search.documents( - q="What are the best practices for training deep learning models?", - rewrite_query=True, - limit=10 - ) - - # The system might generate rewrites like: - # - "deep learning model training best practices" - # - "neural network training optimization techniques" - # - "machine learning model training guidelines" - # - "deep learning training methodology" - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "What are the best practices for training deep learning models?", - "rewriteQuery": true, - "limit": 10 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "documentId": "doc_123", - "title": "Deep Learning Training Guide", - "score": 0.92, - "chunks": [ - { - "content": "Best practices for training deep neural networks include proper weight initialization, learning rate scheduling, and regularization techniques...", - "score": 0.89, - "isRelevant": true - } - ] - }, - { - "documentId": "doc_456", - "title": "Neural Network Optimization", - "score": 0.87, - "chunks": [ - { - "content": "Effective training methodologies involve batch normalization, dropout, and gradient clipping to prevent overfitting...", - "score": 0.85, - "isRelevant": true - } - ] - } - ], - "total": 12, - "timing": 445 -} -``` - -## Technical Term Expansion - -Query rewriting helps find content using different technical terminologies: - - - - ```typescript - // Original query with specific terminology - const results = await client.search.documents({ - q: "CNN architecture patterns", - rewriteQuery: true, - containerTags: ["research"], - limit: 8 - }); - - // System expands to include: - // - "convolutional neural network architecture" - // - "CNN design patterns" - // - "convolutional network structures" - // - "CNN architectural components" - ``` - - - ```python - # Original query with specific terminology - results = client.search.documents( - q="CNN architecture patterns", - rewrite_query=True, - container_tags=["research"], - limit=8 - ) - - # System expands to include: - # - "convolutional neural network architecture" - # - "CNN design patterns" - # - "convolutional network structures" - # - "CNN architectural components" - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "CNN architecture patterns", - "rewriteQuery": true, - "containerTags": ["research"], - "limit": 8 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "documentId": "doc_789", - "title": "Convolutional Neural Network Architectures", - "score": 0.94, - "chunks": [ - { - "content": "Modern CNN architectures like ResNet and DenseNet utilize skip connections to address the vanishing gradient problem...", - "score": 0.91, - "isRelevant": true - } - ] - }, - { - "documentId": "doc_101", - "title": "Deep Learning Design Patterns", - "score": 0.88, - "chunks": [ - { - "content": "Convolutional layers followed by pooling operations form the fundamental building blocks of CNN architectures...", - "score": 0.86, - "isRelevant": true - } - ] - } - ], - "total": 15, - "timing": 478 -} -``` - -## Memory Search with Query Rewriting - -Query rewriting works with both document and memory search: - - - - ```typescript - // Memory search with query rewriting - const memoryResults = await client.search.memories({ - q: "explain quantum entanglement simply", - rewriteQuery: true, - containerTag: "physics_notes", - limit: 5 - }); - - // Generates variations like: - // - "quantum entanglement explanation" - // - "what is quantum entanglement" - // - "quantum entanglement basics" - // - "simple quantum entanglement description" - ``` - - - ```python - # Memory search with query rewriting - memory_results = client.search.memories( - q="explain quantum entanglement simply", - rewrite_query=True, - container_tag="physics_notes", - limit=5 - ) - - # Generates variations like: - # - "quantum entanglement explanation" - # - "what is quantum entanglement" - # - "quantum entanglement basics" - # - "simple quantum entanglement description" - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "explain quantum entanglement simply", - "rewriteQuery": true, - "containerTag": "physics_notes", - "limit": 5 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "id": "mem_456", - "memory": "Quantum entanglement is a phenomenon where two particles become connected in such a way that measuring one instantly affects the other, regardless of distance. Think of it like having two magical coins that always land on opposite sides.", - "similarity": 0.91, - "title": "Simple Quantum Entanglement Explanation", - "metadata": { - "topic": "quantum-physics", - "difficulty": "beginner" - } - }, - { - "id": "mem_789", - "memory": "Einstein called quantum entanglement 'spooky action at a distance' because entangled particles seem to communicate instantaneously across vast distances, challenging our understanding of locality in physics.", - "similarity": 0.87, - "title": "Einstein's View on Entanglement" - } - ], - "total": 7, - "timing": 412 -} -``` - -## Complex Multi-Concept Queries - -Query rewriting excels at handling queries with multiple concepts: - - - - ```typescript - const results = await client.search.documents({ - q: "machine learning bias fairness algorithmic discrimination", - rewriteQuery: true, - filters: { - AND: [ - { key: "category", value: "ethics", negate: false } - ] - }, - limit: 10 - }); - - // Breaks down into focused rewrites: - // - "machine learning bias detection" - // - "algorithmic fairness in AI" - // - "discrimination in machine learning algorithms" - // - "bias mitigation techniques ML" - ``` - - - ```python - results = client.search.documents( - q="machine learning bias fairness algorithmic discrimination", - rewrite_query=True, - filters={ - "AND": [ - {"key": "category", "value": "ethics", "negate": False} - ] - }, - limit=10 - ) - - # Breaks down into focused rewrites: - # - "machine learning bias detection" - # - "algorithmic fairness in AI" - # - "discrimination in machine learning algorithms" - # - "bias mitigation techniques ML" - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning bias fairness algorithmic discrimination", - "rewriteQuery": true, - "filters": { - "AND": [ - {"key": "category", "value": "ethics", "negate": false} - ] - }, - "limit": 10 - }' - ``` - - diff --git a/apps/docs/search/reranking.mdx b/apps/docs/search/reranking.mdx deleted file mode 100644 index 7d2e017a..00000000 --- a/apps/docs/search/reranking.mdx +++ /dev/null @@ -1,387 +0,0 @@ ---- -title: "Reranking" -description: "Improve result relevance with secondary ranking algorithms" ---- - - -Reranking applies a secondary ranking algorithm to improve the relevance order of search results. After the initial search returns results, the reranker analyzes the relationship between your query and each result to provide better ordering. - -## How Reranking Works - -Supermemory's reranking process: - -1. **Initial search** returns results using standard semantic similarity -2. **Reranker model** analyzes query-result pairs -3. **Scores are recalculated** based on deeper semantic understanding -4. **Results are reordered** by the new relevance scores -5. **Final results** maintain the same structure but with improved ordering - -The reranker is particularly effective at: -- **Understanding context** and nuanced relationships -- **Handling ambiguous queries** with multiple possible meanings -- **Improving precision** for complex technical topics -- **Better ranking** when results have similar initial scores - -## Basic Reranking Comparison - - - - ```typescript - import Supermemory from 'supermemory'; - - const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! - }); - - // Search without reranking - const standardResults = await client.search.documents({ - q: "neural network optimization techniques", - rerank: false, - limit: 5 - }); - - // Search with reranking - const rerankedResults = await client.search.documents({ - q: "neural network optimization techniques", - rerank: true, - limit: 5 - }); - - console.log("Standard top result:", standardResults.results[0].score); - console.log("Reranked top result:", rerankedResults.results[0].score); - ``` - - - ```python - from supermemory import Supermemory - import os - - client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - - # Search without reranking - standard_results = client.search.documents( - q="neural network optimization techniques", - rerank=False, - limit=5 - ) - - # Search with reranking - reranked_results = client.search.documents( - q="neural network optimization techniques", - rerank=True, - limit=5 - ) - - print("Standard top result:", standard_results.results[0].score) - print("Reranked top result:", reranked_results.results[0].score) - ``` - - - ```bash - # Without reranking - echo "Standard ranking:" - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "neural network optimization techniques", - "rerank": false, - "limit": 3 - }' | jq '.results[0] | {title, score}' - - # With reranking - echo "Reranked results:" - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "neural network optimization techniques", - "rerank": true, - "limit": 3 - }' | jq '.results[0] | {title, score}' - ``` - - - -**Sample Output Comparison:** - -```json -// Without reranking - results ordered by semantic similarity -{ - "results": [ - { - "title": "Deep Learning Optimization Methods", - "score": 0.82, - "chunks": [ - { - "content": "Various optimization algorithms like Adam, RMSprop, and SGD are used in neural network training...", - "score": 0.79 - } - ] - }, - { - "title": "Neural Network Training Techniques", - "score": 0.81, - "chunks": [ - { - "content": "Batch normalization and dropout are common regularization techniques for neural networks...", - "score": 0.78 - } - ] - } - ], - "timing": 145 -} - -// With reranking - results reordered by contextual relevance -{ - "results": [ - { - "title": "Neural Network Training Techniques", - "score": 0.89, // Boosted by reranker - "chunks": [ - { - "content": "Batch normalization and dropout are common regularization techniques for neural networks...", - "score": 0.85 - } - ] - }, - { - "title": "Deep Learning Optimization Methods", - "score": 0.86, // Slightly adjusted - "chunks": [ - { - "content": "Various optimization algorithms like Adam, RMSprop, and SGD are used in neural network training...", - "score": 0.83 - } - ] - } - ], - "timing": 267 // Additional ~120ms for reranking -} -``` - -## Complex Query Reranking - -Reranking excels with complex, multi-faceted queries: - - - - ```typescript - const results = await client.search.documents({ - q: "sustainable machine learning carbon footprint energy efficiency", - rerank: true, - containerTags: ["research", "sustainability"], - limit: 8 - }); - - // Reranker understands the connection between: - // - Machine learning computational costs - // - Environmental impact of AI training - // - Energy-efficient model architectures - // - Green computing practices in ML - ``` - - - ```python - results = client.search.documents( - q="sustainable machine learning carbon footprint energy efficiency", - rerank=True, - container_tags=["research", "sustainability"], - limit=8 - ) - - # Reranker understands the connection between: - # - Machine learning computational costs - # - Environmental impact of AI training - # - Energy-efficient model architectures - # - Green computing practices in ML - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "sustainable machine learning carbon footprint energy efficiency", - "rerank": true, - "containerTags": ["research", "sustainability"], - "limit": 8 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "documentId": "doc_green_ai", - "title": "Green AI: Reducing the Carbon Footprint of Machine Learning", - "score": 0.94, // Highly relevant after reranking - "chunks": [ - { - "content": "Training large neural networks can consume as much energy as several cars over their lifetime. Sustainable ML practices focus on model efficiency, pruning, and quantization to reduce computational demands...", - "score": 0.92, - "isRelevant": true - } - ] - }, - { - "documentId": "doc_efficient_models", - "title": "Energy-Efficient Neural Network Architectures", - "score": 0.91, // Boosted for strong topical relevance - "chunks": [ - { - "content": "MobileNets and EfficientNets are designed specifically for energy-constrained environments, achieving high accuracy with minimal computational overhead...", - "score": 0.88, - "isRelevant": true - } - ] - } - ], - "total": 12, - "timing": 298 -} -``` - -## Memory Search Reranking - -Reranking also improves memory search results: - - - - ```typescript - const memoryResults = await client.search.memories({ - q: "explain transformer architecture attention mechanism", - rerank: true, - containerTag: "ai_notes", - threshold: 0.6, - limit: 5 - }); - - // Reranker identifies memories that best explain - // the relationship between transformers and attention - ``` - - - ```python - memory_results = client.search.memories( - q="explain transformer architecture attention mechanism", - rerank=True, - container_tag="ai_notes", - threshold=0.6, - limit=5 - ) - - # Reranker identifies memories that best explain - # the relationship between transformers and attention - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v4/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "explain transformer architecture attention mechanism", - "rerank": true, - "containerTag": "ai_notes", - "threshold": 0.6, - "limit": 5 - }' - ``` - - - -**Sample Output:** -```json -{ - "results": [ - { - "id": "mem_transformer_intro", - "memory": "The transformer architecture revolutionized NLP by replacing recurrent layers with self-attention mechanisms. The attention mechanism allows the model to focus on different parts of the input sequence when processing each token, enabling parallel processing and better long-range dependency modeling.", - "similarity": 0.93, // Reranked higher for comprehensive explanation - "title": "Transformer Architecture Overview", - "metadata": { - "topic": "deep-learning", - "subtopic": "transformers" - } - }, - { - "id": "mem_attention_detail", - "memory": "Self-attention computes attention weights by taking dot products between query, key, and value vectors derived from the input embeddings. This allows each position to attend to all positions in the previous layer, capturing complex relationships in the data.", - "similarity": 0.91, // Boosted for technical detail - "title": "Self-Attention Mechanism Details" - } - ], - "total": 8, - "timing": 198 -} -``` - -## Domain-Specific Reranking - -Reranking understands domain-specific relationships: - - - - ```typescript - // Medical domain query - const medicalResults = await client.search.documents({ - q: "diabetes treatment insulin resistance metformin", - rerank: true, - filters: { - AND: [ - { key: "domain", value: "medical", negate: false } - ] - }, - limit: 10 - }); - - // Reranker understands medical relationships: - // - Diabetes types and treatments - // - Insulin resistance mechanisms - // - Metformin's role in diabetes management - ``` - - - ```python - # Medical domain query - medical_results = client.search.documents( - q="diabetes treatment insulin resistance metformin", - rerank=True, - filters={ - "AND": [ - {"key": "domain", "value": "medical", "negate": False} - ] - }, - limit=10 - ) - - # Reranker understands medical relationships: - # - Diabetes types and treatments - # - Insulin resistance mechanisms - # - Metformin's role in diabetes management - ``` - - - ```bash - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "diabetes treatment insulin resistance metformin", - "rerank": true, - "filters": { - "AND": [ - {"key": "domain", "value": "medical", "negate": false} - ] - }, - "limit": 10 - }' - ``` - - diff --git a/apps/docs/search/response-schema.mdx b/apps/docs/search/response-schema.mdx deleted file mode 100644 index b4f43ff4..00000000 --- a/apps/docs/search/response-schema.mdx +++ /dev/null @@ -1,354 +0,0 @@ ---- -title: "Response Schema" -description: "Complete response structure for all search endpoints with scoring details" ---- - - -## Document Search Response (POST `/v3/search`) - -Response from `client.search.documents()` and `client.search.execute()`: - -```json -{ - "results": [ - { - "documentId": "doc_abc123", - "title": "Machine Learning Fundamentals", - "type": "pdf", - "score": 0.89, - "chunks": [ - { - "content": "Machine learning is a subset of artificial intelligence...", - "score": 0.95, - "isRelevant": true - } - ], - "metadata": { - "category": "education", - "author": "Dr. Smith", - "difficulty": "beginner" - }, - "createdAt": "2024-01-15T10:30:00Z", - "updatedAt": "2024-01-20T14:45:00Z" - } - ], - "timing": 187, - "total": 1 -} -``` - -### Document Result Fields - - - Unique identifier for the document containing the matching chunks. - - - - Document title if available. May be null for documents without titles. - - - - Document type (e.g., "pdf", "text", "webpage", "notion_doc"). May be null if not specified. - - - - **Overall document relevance score**. Combines semantic similarity, keyword matching, and metadata relevance. - - - **0.9-1.0**: Extremely relevant - - **0.7-0.9**: Highly relevant - - **0.5-0.7**: Moderately relevant - - **0.3-0.5**: Somewhat relevant - - **0.0-0.3**: Marginally relevant - - - - Array of matching text chunks from the document. Each chunk represents a portion of the document that matched your query. - - - The actual text content of the matching chunk. May include context from surrounding chunks unless `onlyMatchingChunks=true`. - - - - **Chunk-specific similarity score**. How well this specific chunk matches your query. - - - - Whether this chunk passed the `chunkThreshold`. `true` means the chunk is above the threshold, `false` means it's included for context only. - - - - - Document metadata as key-value pairs. Structure depends on what was stored with the document. - - ```json - { - "category": "tutorial", - "language": "python", - "difficulty": "intermediate", - "tags": "web-development,backend" - } - ``` - - - - ISO 8601 timestamp when the document was created. - - - - ISO 8601 timestamp when the document was last updated. - - - - **Full document content**. Only included when `includeFullDocs=true`. Can be very large. - - - Full document content can make responses extremely large. Use with appropriate limits and only when necessary. - - - - - **AI-generated document summary**. Only included when `includeSummary=true`. Provides a concise overview of the document. - - -## Memory Search Response - -Response from `client.search.memories()`: - -When `searchMode="memories"` (default), all results are memory entries: - -```json -{ - "results": [ - { - "id": "mem_xyz789", - "memory": "Complete memory content about quantum computing applications...", - "similarity": 0.87, - "metadata": { - "category": "research", - "topic": "quantum-computing" - }, - "updatedAt": "2024-01-18T09:15:00Z", - "version": 3, - "context": { - "parents": [ - { - "memory": "Earlier discussion about quantum theory basics...", - "relation": "extends", - "version": 2, - "updatedAt": "2024-01-17T16:30:00Z" - } - ], - "children": [ - { - "memory": "Follow-up questions about quantum algorithms...", - "relation": "derives", - "version": 4, - "updatedAt": "2024-01-19T11:20:00Z" - } - ] - }, - "documents": [ - { - "id": "doc_quantum_paper", - "title": "Quantum Computing Applications", - "type": "pdf", - "createdAt": "2024-01-10T08:00:00Z" - } - ] - } - ], - "timing": 156, - "total": 1 -} -``` - -When `searchMode="hybrid"`, results can contain both memory entries and document chunks. **Memory results have a `memory` key, chunk results have a `chunk` key:** - -```json -{ - "results": [ - { - "id": "mem_xyz789", - "memory": "Complete memory content about quantum computing applications...", - "similarity": 0.87, - "metadata": { - "category": "research", - "topic": "quantum-computing" - }, - "updatedAt": "2024-01-18T09:15:00Z", - "version": 3, - "context": { - "parents": [], - "children": [] - }, - "documents": [ - { - "id": "doc_quantum_paper", - "title": "Quantum Computing Applications", - "type": "pdf", - "createdAt": "2024-01-10T08:00:00Z", - "updatedAt": "2024-01-10T08:00:00Z" - } - ] - }, - { - "id": "chunk_abc123", - "chunk": "This is a chunk of content from a document about quantum computing...", - "similarity": 0.82, - "metadata": { - "category": "research", - "source": "document" - }, - "updatedAt": "2024-01-15T10:30:00Z", - "version": 1, - "context": { - "parents": [], - "children": [] - }, - "documents": [ - { - "id": "doc_quantum_research", - "title": "Quantum Computing Research Paper", - "type": "pdf", - "metadata": { - "author": "Dr. Smith" - }, - "createdAt": "2024-01-15T10:30:00Z", - "updatedAt": "2024-01-15T10:30:00Z" - } - ] - } - ], - "timing": 198, - "total": 2 -} -``` - - - **Distinguishing Memory vs Chunk Results:** - - In hybrid mode, check which key exists on the result object: - - **Memory results**: Have a `memory` key (no `chunk` key) - - **Chunk results**: Have a `chunk` key (no `memory` key) - - ```typescript - // TypeScript example - results.results.forEach(result => { - if ('memory' in result) { - // This is a memory result - console.log('Memory:', result.memory); - } else if ('chunk' in result) { - // This is a chunk result - console.log('Chunk:', result.chunk); - } - }); - ``` - - -### Memory Result Fields - - - Unique identifier for the memory entry or chunk ID. In hybrid mode, can be either a memory ID (e.g., `mem_xyz789`) or a chunk ID (e.g., `chunk_abc123`). - - - - **Complete memory content**. Only present for memory results (when `searchMode="memories"` or when a memory result is returned in hybrid mode). This field is not present for chunk results. - - - - **Chunk content from a document**. Only present for chunk results when `searchMode="hybrid"`. This field is not present for memory results. Contains the actual text content from the document chunk. - - - - **Similarity score** between your query and this memory. Higher scores indicate better matches. - - - **0.9-1.0**: Extremely similar - - **0.8-0.9**: Very similar - - **0.7-0.8**: Similar - - **0.6-0.7**: Somewhat similar - - **0.5-0.6**: Marginally similar - - - - Memory metadata as key-value pairs. Structure depends on what was stored with the memory. - - - - ISO 8601 timestamp when the memory was last updated. - - - - Version number of this memory entry. Used for tracking memory evolution and relationships. For chunk results, this is typically `1`. - - - - Root memory ID for memory entries. Only present for memory results. Always `null` for chunk results. - - - - **Contextual memory relationships**. Only included when `include.relatedMemories=true`. - - - Array of parent memories that this memory extends or derives from. - - - - Array of child memories that extend or derive from this memory. - - - ### Context Memory Structure - - - Content of the related memory. - - - - Relationship type: `"updates"`, `"extends"`, or `"derives"`. - - - **updates**: This memory updates/replaces the related memory - - **extends**: This memory builds upon the related memory - - **derives**: This memory is derived from the related memory - - - - Relative version distance: - - **Negative values** for parents (-1 = direct parent, -2 = grandparent) - - **Positive values** for children (+1 = direct child, +2 = grandchild) - - - - When the related memory was last updated. - - - - Metadata of the related memory. - - - - - **Associated documents**. Only included when `include.documents=true`. - - - Document identifier. - - - - Document title. - - - - Document type. - - - - Document metadata. - - - - Document creation timestamp. - - - - Document update timestamp. - - diff --git a/apps/docs/self-hosting/configuration.mdx b/apps/docs/self-hosting/configuration.mdx index 9714653f..09478722 100644 --- a/apps/docs/self-hosting/configuration.mdx +++ b/apps/docs/self-hosting/configuration.mdx @@ -76,7 +76,7 @@ Full provider table, multilingual guidance, remote examples (OpenAI / Gemini / O ### Embedding performance -Local embeddings are prewarmed at startup with conservative defaults — one worker, minimal CPU footprint. Turn these up if you're ingesting heavily and prefer throughput over headroom: +Local embeddings are prewarmed at startup with conservative defaults — one worker, minimal CPU footprint. Turn these up if you're ingesting heavily and prefer throughput over headroom (remote embedding providers ignore these — there's no local worker pool to tune): | Variable | Purpose | Default | |---|---|---| diff --git a/apps/docs/self-hosting/overview.mdx b/apps/docs/self-hosting/overview.mdx index c1ef34a1..8fc9fe23 100644 --- a/apps/docs/self-hosting/overview.mdx +++ b/apps/docs/self-hosting/overview.mdx @@ -1,5 +1,5 @@ --- -title: "Self-Hosting Supermemory" +title: "Supermemory local" sidebarTitle: "Overview" description: "State-of-the-art memory, running on your machine. One binary, zero config." icon: "server" diff --git a/apps/docs/self-hosting/providers.mdx b/apps/docs/self-hosting/providers.mdx new file mode 100644 index 00000000..84ec1c4e --- /dev/null +++ b/apps/docs/self-hosting/providers.mdx @@ -0,0 +1,62 @@ +--- +title: "Using supermemory local with different providers" +sidebarTitle: "Providers" +description: "Copy-paste .env setup for Ollama, OpenAI, Anthropic, Gemini, and OpenRouter" +icon: "route" +--- + +Supermemory local needs one model provider to power summaries, contextual chunking, and memory extraction. Pick the tab for whichever one you already have a key for. For the full variable reference (fast/text model overrides, offline setup, tuning), see [Configuration](/self-hosting/configuration). + + + +Fully offline — no API key leaves your machine. Any OpenAI-compatible local runner works the same way (LM Studio, vLLM, llama.cpp server); this is the Ollama version. + +```bash +ollama pull gpt-oss:20b +``` + +```bash .env +OPENAI_BASE_URL=http://localhost:11434/v1 +OPENAI_API_KEY=ollama # any non-empty string — Ollama doesn't check it +OPENAI_MODEL=gpt-oss:20b +``` + +`gpt-oss:20b` is a good default for a laptop-class GPU. Bigger models work if you have the VRAM — set `OPENAI_MODEL` to whatever you've pulled. + + + +```bash .env +OPENAI_API_KEY=sk-... +``` + +That's it — defaults to `gpt-5.1`. Override with `OPENAI_MODEL` if you want a different one. + + + +```bash .env +ANTHROPIC_API_KEY=sk-ant-... +``` + +Runs on `claude-haiku-4-5` — this one isn't currently configurable via env var. + + + +```bash .env +GEMINI_API_KEY=... +``` + +Runs on `gemini-3.1-flash-lite-preview` — also not currently overridable. This is the only key that also unlocks image, video, and high-fidelity PDF understanding (see the [full provider table](/self-hosting/configuration#llm-providers)). + + + +OpenRouter isn't a native provider — it's OpenAI-compatible, so it slots into the same `OPENAI_BASE_URL` path as Ollama: + +```bash .env +OPENAI_BASE_URL=https://openrouter.ai/api/v1 +OPENAI_API_KEY=sk-or-... +OPENAI_MODEL=openai/gpt-4o-mini +``` + +Set `OPENAI_MODEL` to any model slug from [OpenRouter's model list](https://openrouter.ai/models) — routing, fallback, and pricing all follow OpenRouter's own rules from there. + + diff --git a/apps/docs/self-hosting/quickstart.mdx b/apps/docs/self-hosting/quickstart.mdx index 2e4dfe60..cb86ee33 100644 --- a/apps/docs/self-hosting/quickstart.mdx +++ b/apps/docs/self-hosting/quickstart.mdx @@ -105,7 +105,7 @@ curl http://localhost:6767/v3/documents \ ```typescript -const results = await client.search.memories({ +const results = await client.search({ q: "what food should I avoid?", containerTag: "user_dhravya", }) @@ -113,7 +113,7 @@ const results = await client.search.memories({ ```python -results = client.search.memories( +results = client.search( q="what food should I avoid?", container_tag="user_dhravya", ) diff --git a/apps/docs/snippets/journey.mdx b/apps/docs/snippets/journey.mdx new file mode 100644 index 00000000..8a5d4cc1 --- /dev/null +++ b/apps/docs/snippets/journey.mdx @@ -0,0 +1,35 @@ +export const Journey = ({ children }) => ( +
+
+ {children} +
+); + +export const JourneyStep = ({ number, title, children }) => ( +
+
+ {number} +
+

+ {title} +

+
+ {children} +
+
+); + +export const JourneyItem = ({ icon, title, href }) => ( + + {icon && ( + + )} + {title} + +); diff --git a/apps/docs/snippets/slack-message.mdx b/apps/docs/snippets/slack-message.mdx new file mode 100644 index 00000000..b21910f4 --- /dev/null +++ b/apps/docs/snippets/slack-message.mdx @@ -0,0 +1,338 @@ +export const DHRAVYA = { + name: "Dhravya Shah", + avatar: "/images/company-brain/dhravya-slack-icon.jpg", +}; + +export const BOT_AVATAR = "/images/company-brain/supermemory-slack-icon.png"; + +export const Mention = ({ children, self = false }) => ( + + @{children} + +); + +export const ChannelRef = ({ children }) => ( + + #{children} + +); + +export const SlackButton = ({ children, variant = "default" }) => ( + + {children} + +); + +export const SlackUnfurl = ({ color = "#8a94a6", footer, children }) => ( +
+
+ {children} +
+ {footer ? ( +
{footer}
+ ) : null} +
+); + +export const SlackThread = ({ + type = "channel", + channel = "general", + private: isPrivate = false, + members, + dmWith, + maxHeight = "70vh", + children, +}) => { + const composerLabel = + type === "dm" + ? `Message ${dmWith?.name || "someone"}` + : type === "thread" + ? "Reply..." + : `Message ${isPrivate ? "" : "#"}${channel.replace(/^#/, "")}`; + + return ( +
+ {type === "thread" ? ( +
+ Thread +
+ + + +
+
+ ) : type === "dm" ? ( +
+
+ {dmWith?.name + +
+ + {dmWith?.name || "Direct message"} + +
+ ) : ( +
+
+ {isPrivate ? ( + + ) : ( + + )} + + {channel.replace(/^#/, "")} + +
+ {members ? ( +
+ + {members} +
+ ) : null} +
+ )} + +
+
{ + if (!el || !maxHeight) return; + const wrapper = el.parentElement; + const aboveHint = wrapper?.querySelector('[data-hint="above"]'); + const belowHint = wrapper?.querySelector('[data-hint="below"]'); + const update = () => { + const hasAbove = el.scrollTop > 4; + const hasBelow = el.scrollHeight - el.scrollTop - el.clientHeight > 4; + if (aboveHint) aboveHint.style.opacity = hasAbove ? "1" : "0"; + if (belowHint) belowHint.style.opacity = hasBelow ? "1" : "0"; + }; + update(); + el.addEventListener("scroll", update); + requestAnimationFrame(update); + }} + className="overflow-y-auto bg-white dark:bg-[#1A1D21]" + style={maxHeight ? { maxHeight } : undefined} + > + {children} +
+ {maxHeight ? ( +
+
+
+ + ↑ More messages above + +
+ ) : null} + {maxHeight ? ( +
+
+
+ + More messages below ↓ + +
+ ) : null} +
+ +
+
+ {composerLabel} +
+
+
+ ); +}; + +export const SlackReplyDivider = ({ count = 1 }) => ( +
+ + {count} {count === 1 ? "reply" : "replies"} + + +
+); + +export const SlackMessage = ({ + name, + self = false, + bot = false, + time, + color = "#611f69", + avatar, + badges, + reactions, + highlighted = false, + subtitle, + children, +}) => { + const SELF_NAME = "Dhravya Shah"; + const SELF_AVATAR = "/images/company-brain/dhravya-slack-icon.jpg"; + const BOT_AVATAR = "/images/company-brain/supermemory-slack-icon.png"; + + const resolvedName = bot ? "supermemory" : self ? SELF_NAME : name || SELF_NAME; + const resolvedAvatar = bot ? BOT_AVATAR : self ? SELF_AVATAR : avatar; + const resolvedBadges = badges || (bot ? ["AGENT"] : null); + + return ( +
+
+ {["✅", "👀", "🙌", "😊", "↩️", "⋯"].map((icon, i) => ( + + {icon} + + ))} +
+ {resolvedAvatar ? ( + {resolvedName} + ) : ( +
+ {(resolvedName || "?").slice(0, 1).toUpperCase()} +
+ )} +
+
+ + {resolvedName} + + {subtitle ? ( + + ({subtitle}) + + ) : null} + {resolvedBadges + ? resolvedBadges.map((b) => ( + + {b} + + )) + : null} + {time ? ( + {time} + ) : null} +
+
+ {children} +
+ {reactions ? ( +
+ {reactions.map((r, i) => ( + + {r.emoji} + {r.count} + + ))} +
+ ) : null} +
+
+ ); +}; + +export const FileAttachment = ({ name, size }) => ( +
+ +
+
{name}
+ {size ? ( +
{size}
+ ) : null} +
+
+); + +export const AgentLink = ({ href, children }) => ( + + {children} + +); diff --git a/apps/docs/supermemory-mcp/claude-desktop.mdx b/apps/docs/supermemory-mcp/claude-desktop.mdx index 837945a8..802fb43f 100644 --- a/apps/docs/supermemory-mcp/claude-desktop.mdx +++ b/apps/docs/supermemory-mcp/claude-desktop.mdx @@ -1,64 +1,46 @@ --- title: "Claude Desktop" -description: "Manual setup for supermemory MCP in Claude Desktop with step-by-step screenshots" +description: "Connect Supermemory MCP in Claude via Settings → Connectors" icon: "monitor" sidebarTitle: "Claude Desktop" --- -This guide walks through the **manual** install for [Claude Desktop](https://claude.ai/download): edit `claude_desktop_config.json`, add the supermemory server, then finish in **Connectors**. For a one-line CLI install instead, see [Setup and Usage](/supermemory-mcp/setup). +This guide walks through adding Supermemory as a **custom connector** in [Claude](https://claude.ai) (Desktop or web): open **Settings → Connectors**, add the MCP URL, connect, and authorize. For other clients and API-key auth, see [Setup and Usage](/supermemory-mcp/setup). - - Config file location: **macOS** `~/Library/Application Support/Claude/claude_desktop_config.json` · **Windows** `%APPDATA%\Claude\claude_desktop_config.json` - +## Step 1 — Open Connectors and add a custom connector -## Step 1 — Copy the configuration +In Claude, open **Settings → Connectors**. Click **Add**, then choose **Add custom connector**. -Copy the supermemory block below. You will paste it inside `mcpServers` in a later step. +![Claude settings Connectors page with Add custom connector highlighted](/images/supermemory-mcp/claude-desktop/step-1.jpg) -```json -{ - "mcpServers": { - "supermemory": { - "command": "npx", - "args": [ - "-y", - "mcp-remote@latest", - "https://mcp.supermemory.ai/mcp" - ] - } - } -} -``` +## Step 2 — Enter name and remote MCP URL -This is the same configuration shown in the supermemory dashboard when you choose **Claude Desktop** for MCP setup. +In the **Add custom connector** dialog: -## Step 2 — Open Developer settings and Edit Config +| Field | Value | +| --- | --- | +| **Name** | `Supermemory` (or any label you prefer) | +| **Remote MCP server URL** | `https://mcp.supermemory.ai/mcp` | -In Claude Desktop, open **Settings → Developer**, then click **Edit Config**. +Leave **OAuth Client ID** and **OAuth Client Secret** empty unless you have custom OAuth credentials. Click **Add**. -![Claude Desktop settings: Developer in the sidebar and Edit Config highlighted](/images/supermemory-mcp/claude-desktop/step-1.png) +![Add custom connector dialog with Supermemory name and mcp.supermemory.ai URL](/images/supermemory-mcp/claude-desktop/step-2.png) -## Step 3 — Open claude_desktop_config.json +## Step 3 — Connect -When `claude_desktop_config.json` opens in your editor, keep it ready for the next step. +Supermemory appears under your connectors. Click **Connect**. -![File list with claude_desktop_config.json selected](/images/supermemory-mcp/claude-desktop/step-2.png) +![Connectors list with supermemory and Connect button](/images/supermemory-mcp/claude-desktop/step-3.png) -## Step 4 — Paste under mcpServers and save +## Step 4 — Authorize -Paste what you copied under `mcpServers` (merge with existing servers if the file already has some), then save. +You’ll be redirected to Supermemory to sign in and choose access scopes (for example **Read + Write** or **Full access**). Select the scopes you want, then click **Authorize**. -![JSON editor showing supermemory mcpServers configuration](/images/supermemory-mcp/claude-desktop/step-3.png) +![Authorize MCP screen with scope options and Authorize button](/images/supermemory-mcp/claude-desktop/step-4.png) -## Step 5 — Restart and configure in Connectors +## Done -Restart Claude Desktop. Open **Settings → Connectors**, find **supermemory**, and click **Configure**. - -![Claude Desktop Connectors settings with supermemory and Configure highlighted](/images/supermemory-mcp/claude-desktop/step-4.png) - -## Step 6 — Done - -supermemory is installed in your Claude Desktop and ready to use. +Supermemory is connected and ready to use in Claude. You can change or revoke access later from **Settings → Connectors**. --- diff --git a/apps/docs/supermemory-mcp/introduction.mdx b/apps/docs/supermemory-mcp/introduction.mdx deleted file mode 100644 index 51f097ed..00000000 --- a/apps/docs/supermemory-mcp/introduction.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: 'About Supermemory MCP' -description: 'Give your AI assistants persistent memory with the Model Context Protocol' ---- - -Supermemory MCP Server 4.0 is a lightweight component that gives AI assistants persistent memory across conversations. It serves as a universal memory layer enabling Large Language Models (LLMs) to maintain context and memories across different applications and sessions, solving the fundamental limitation of AI assistants forgetting everything between conversations. - - - Jump to installation and setup - - -## What Supermemory MCP Does - -**Supermemory MCP** functions as a universal memory system that bridges AI applications through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io). It operates as an **MCP server** that communicates with MCP-compatible clients, storing and retrieving contextual information through the Supermemory API infrastructure. - -When users interact with any connected AI application, the system captures relevant information and makes it available across all other connected platforms through **semantic search and intelligent retrieval**. - -### Supported Platforms - -- **Claude Desktop** - Direct MCP protocol support -- **Cursor IDE** - Global MCP server configuration via `~/.cursor/mcp.json` -- **Windsurf** - Seamless integration for AI-powered development -- **VS Code** - Compatible with AI coding extensions -- **Cline/Roo-Cline** - Full MCP protocol support -- **Any MCP-compatible application** - Universal compatibility through standard protocol - -### Key Features - -- **OAuth Authentication** - Secure login through Supermemory accounts -- **API Key Support** - Alternative authentication for automation and CI/CD -- **Persistent Memory** - Save and recall information across sessions -- **User Profiles** - Auto-generated profiles from stored memories -- **Project Scoping** - Organize memories by project with `x-sm-project` header - -## Core Workflow - -1. User interacts with any MCP-compatible AI client -2. The client connects to `https://mcp.supermemory.ai/mcp` -3. OAuth flow authenticates the user (or API key validates directly) -4. During conversations, relevant information is stored using the `memory` tool -5. When context is needed, the `recall` tool retrieves relevant memories -6. The AI assistant accesses this persistent context regardless of which platform is being used - -## Security and Privacy - -### Authentication Model - -- **OAuth by default** - Secure authentication through Supermemory accounts -- **API key alternative** - Keys start with `sm_` for programmatic access -- **Session isolation** - Complete user data separation per account - -### Privacy Features - -- **Data isolation** - User memories completely separated by account -- **Secure infrastructure** - Built on Cloudflare's enterprise-grade platform -- **Open source** - Full transparency into how your data is handled - - - View the open-source implementation - diff --git a/apps/docs/supermemory-mcp/mcp.mdx b/apps/docs/supermemory-mcp/mcp.mdx index f317d920..c2a1d2d8 100644 --- a/apps/docs/supermemory-mcp/mcp.mdx +++ b/apps/docs/supermemory-mcp/mcp.mdx @@ -1,22 +1,55 @@ --- title: "Overview" -description: "Give your AI assistants persistent memory with the Model Context Protocol" +description: "Unified memory for Claude, Cursor, and every MCP client — one layer across all your tools" icon: "brain-circuit" --- -Supermemory MCP Server 4.0 gives AI assistants (Claude, Cursor, Windsurf, etc.) persistent memory across conversations. Built on Cloudflare Workers with Durable Objects for scalable, persistent connections. +Most AI tools forget you the moment the tab closes. You re-explain preferences, restate project context, and re-teach the same lessons in Claude, Cursor, ChatGPT, and everything else. -## Quick Install +**Supermemory MCP** is a single memory layer that plugs into any MCP-compatible client. Connect once, and the same long-term memory follows you across tools — coding agents, chat apps, IDEs, and whatever you add next. -```bash -npx -y install-mcp@latest https://mcp.supermemory.ai/mcp --client claude --oauth=yes +## What you get + +- **Unified memory across tools** — Facts you save in Claude are available in Cursor (and vice versa). One brain, many surfaces. +- **Memory that compounds** — Preferences, decisions, and project knowledge accumulate instead of resetting every session. +- **Profiles that stay current** — Supermemory builds a living user profile from what you share, so assistants start with who you are — not a blank slate. +- **Project-scoped context** — Keep work, personal, and client work separate with optional project tags. +- **Works where you already work** — Claude (Connectors), Cursor, Windsurf, VS Code, Cline, and any client that speaks MCP. + +### Why a small tool surface is intentional + +Supermemory MCP exposes a **minimal** set of tools on purpose. + +Assistants don’t need a kitchen-sink API to remember well. They need a few durable actions: save what matters, recall what’s relevant, and know who the user is. Fewer tools means less confusion for the model, clearer behavior, and more reliable use in production. + +| Surface | Role | +| --- | --- | +| **`memory`** | Save or forget something durable | +| **`recall`** | Search memories + optionally load the user profile | +| **`whoAmI`** | Confirm the authenticated user / session | +| **`context` prompt** | Inject a ready-to-use profile system message (`/context` in many clients) | +| **Profile / projects resources** | Raw profile and project list for clients that read MCP resources | + +That’s enough for agents to build real continuity — without tool sprawl. + +## How it fits together + +1. You connect your client to `https://mcp.supermemory.ai/mcp` (OAuth or API key). +2. During conversations, the model stores important facts with **`memory`**. +3. When context is needed, **`recall`** (and the profile) pull the right history back in. +4. Switch tools tomorrow — same account, same memory. + +Under the hood, the server runs on **Cloudflare Workers** with Durable Objects for scalable, sticky sessions. Your data is isolated per account; open-source implementation is on GitHub. + +## Connect + +Server URL: + +```text +https://mcp.supermemory.ai/mcp ``` -Replace `claude` with your MCP client: `cursor`, `windsurf`, `vscode`, etc. - -## Manual Configuration - -Add to your MCP client config: +Add it to your MCP client config: ```json { @@ -28,7 +61,9 @@ Add to your MCP client config: } ``` -The server uses **OAuth** by default. Your client will discover the authorization server via `/.well-known/oauth-protected-resource` and prompt you to authenticate. +The server uses **OAuth** by default. Your client discovers the authorization server via `/.well-known/oauth-protected-resource` and prompts you to sign in. + +For Claude (Settings → Connectors), see **[Claude Desktop](/supermemory-mcp/claude-desktop)**. For client-specific examples, see **[Setup and Usage](/supermemory-mcp/setup)**. ### API Key Authentication (Alternative) @@ -104,8 +139,10 @@ Get the current logged-in user's information. Returns `{ userId, email, name, cl ### `context` Inject user profile and preferences as system context for AI conversations. Returns a formatted message with the user's stable preferences and recent activity. -You can access this in Cursor and Claude Code by just doing /context, which will give the LLMs just enough context to use and query supermemory more. -**Purpose:** Unlike the `recall` tool (which searches for specific information) or the `profile` resource (which returns raw data), the `context` prompt provides a pre-formatted system message designed for context injection at the start of conversations. + +In Cursor and Claude Code you can often invoke this with **`/context`**, which gives the model enough profile context to use and query Supermemory effectively. + +**Purpose:** Unlike the `recall` tool (search for specific information) or the `profile` resource (raw data), the `context` prompt is a pre-formatted system message for conversation start. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| @@ -113,17 +150,21 @@ You can access this in Cursor and Claude Code by just doing /context, which will | `includeRecent` | boolean | No | Include recent activity in the profile. Default: `true` | **Output format:** -- Includes instructions to save new memories using the `memory` tool +- Instructions to save new memories using the `memory` tool - **Stable Preferences:** Long-term user facts and preferences - **Recent Activity:** Recent interactions and context (when `includeRecent` is `true`) - Fallback message when no profile exists yet **When to use:** -- Use `context` prompt for automatic system context injection at conversation start -- Use `recall` tool when you need to search for specific information -- Use `profile` resource when you need raw profile data for custom processing - - - View the open-source implementation - +- **`context` prompt** — automatic system context at conversation start +- **`recall` tool** — search for specific information +- **`profile` resource** — raw profile data for custom processing + + + Client configs, API keys, and project scoping. + + + Open-source implementation. + + diff --git a/apps/docs/supermemory-mcp/setup.mdx b/apps/docs/supermemory-mcp/setup.mdx index cf66e3a8..6865e502 100644 --- a/apps/docs/supermemory-mcp/setup.mdx +++ b/apps/docs/supermemory-mcp/setup.mdx @@ -4,17 +4,13 @@ description: 'How to set up and use Supermemory MCP Server 4.0' icon: 'settings' --- -## Quick Install (Recommended) +## Server URL -```bash -npx -y install-mcp@latest https://mcp.supermemory.ai/mcp --client claude --oauth=yes +```text +https://mcp.supermemory.ai/mcp ``` -Replace `claude` with your MCP client: `cursor`, `windsurf`, `vscode`, etc. - -## Manual Configuration - -Add this to your MCP client config (Claude Desktop, Cursor, Windsurf, etc.): +Add this to your MCP client config (Claude, Cursor, Windsurf, VS Code, etc.): ```json { @@ -70,7 +66,7 @@ This keeps memories organized by project, useful when working on multiple codeba ### Claude Desktop -For a screenshot-backed walkthrough (Developer → Edit Config, `claude_desktop_config.json`, Connectors), see **[Claude Desktop](/supermemory-mcp/claude-desktop)**. The recommended one-line install at the top of this page also supports Claude. +For a screenshot-backed walkthrough (Settings → Connectors → Add custom connector with the URL above), see **[Claude Desktop](/supermemory-mcp/claude-desktop)**. ### Cursor diff --git a/apps/docs/supermemory-mcp/technology.mdx b/apps/docs/supermemory-mcp/technology.mdx deleted file mode 100644 index 5f64e87d..00000000 --- a/apps/docs/supermemory-mcp/technology.mdx +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: 'Technical implementation details' -description: 'Technical implementation details of supermemory MCP' ---- - -The technical architecture prioritizes **simplicity and user experience** while maintaining robust functionality. Built as what the creators describe as "the simplest thing you'll see" - essentially a React Router application making fetch calls to the supermemory API - the entire system was developed and shipped in approximately 5 hours of actual work time. - -### Architecture components - -- **Backend API**: Built on top of the supermemory API (https://api.supermemory.ai/v3) -- **Transport Layer**: Uses Server-Sent Events (SSE) for real-time communication -- **Dynamic Server Generation**: Creates unique MCP server instances for each user via URL path parameters -- **Session Management**: Maintains complete user isolation through unique URLs -- **Infrastructure**: Hosted on Cloudflare using Durable Objects for persistent, long-running connections - -The system leverages **Cloudflare's infrastructure** with CPU-based billing, making it highly efficient since memory connections spend most time waiting between interactions rather than actively processing, resulting in minimal CPU usage despite potentially running for millions of milliseconds. - -## The two main components explained - -### addToSupermemory action - -This component **stores user information, preferences, and behavioral patterns** with sophisticated triggering mechanisms: - -**Trigger methods:** -- **Explicit commands**: Direct user instructions like "remember this" -- **Implicit detection**: Automatic identification of significant user traits, preferences, or patterns during conversations - -**Data types captured:** -- Technical preferences and details (e.g., "My primary programming language is Python") -- Project information and context (e.g., "I'm currently working on a project named 'Apollo'") -- User behaviors and emotional responses -- Personal facts, preferences, and decision-making patterns -- Rich context including technical details and examples - -### searchSupermemory action - -This component **retrieves relevant information** from stored memories using advanced search capabilities: - -**Activation triggers:** -- Explicit user requests for historical information -- Contextual situations where past user choices would be helpful for current decisions -- Automatic context enhancement based on conversation flow - -**Search capabilities:** -- **Semantic matching**: Finds relevant details across related experiences using vector search -- **Pattern recognition**: Identifies behavioral patterns and preferences -- **Cross-session retrieval**: Accesses memories from previous conversations and platforms -- **Intelligent filtering**: Returns most relevant context based on current conversation needs diff --git a/apps/docs/update-delete-memories/overview.mdx b/apps/docs/update-delete-memories/overview.mdx deleted file mode 100644 index 033f6c33..00000000 --- a/apps/docs/update-delete-memories/overview.mdx +++ /dev/null @@ -1,523 +0,0 @@ ---- -title: "Update & Delete Memories" -description: "Safely update and delete memories with upsert patterns and idempotency" -icon: "delete" ---- - -Choose from direct updates, idempotent upserts, single deletions, and powerful bulk operations. - -## Direct Updates - -Update existing memories by their ID when you know the specific memory you want to modify. - -- **Content changes** — Trigger full reprocessing (reindexing) through the pipeline. Response status is `"queued"`. -- **Metadata-only changes** — Update the document row only; no reindexing. Response status stays `"done"`. Use this when updating fields like `accepted`, `version`, or other filter metadata without changing the document content. - - - -```typescript Typescript -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! -}); - -// Update by memory ID -const updated = await client.documents.update('memory_id_123', { - content: 'Updated content here', - metadata: { version: 2, updated: true } -}); - -console.log(updated.status); // "queued" when content changed; "done" when metadata-only -console.log(updated.id); // "memory_id_123" -``` - -```python Python -from supermemory import Supermemory -import os - -client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - -# Update by memory ID -updated = client.documents.update( - 'memory_id_123', - content='Updated content here', - metadata={'version': 2, 'updated': True} -) - -print(f"Status: {updated.status}") # "queued" when content changed; "done" when metadata-only -print(f"ID: {updated.id}") # "memory_id_123" -``` - -```bash cURL -curl -X PATCH "https://api.supermemory.ai/v3/documents/memory_id_123" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "Updated content here", - "metadata": {"version": 2, "updated": true} - }' -``` - - - - -**Metadata-only updates:** If you omit `content` or send the same content and only change `metadata` (e.g. `accepted: false` → `accepted: true`), the document is updated in place with no reindexing. Works with both internal `id` and `customId`—no special setup required. - - -## Upserts Using customId - -Use `customId` for idempotent operations where the same `customId` with `add()` will update existing memory instead of creating duplicates. - - - -```typescript Typescript -import Supermemory from 'supermemory'; - -const client = new Supermemory({ - apiKey: process.env.SUPERMEMORY_API_KEY! -}); - -const customId = 'user-note-001'; - -// First call creates memory -const created = await client.add({ - content: 'Initial content', - customId: customId, - metadata: { version: 1 } -}); - -console.log('Created memory:', created.id); - -// Second call with same customId updates existing -const updated = await client.add({ - content: 'Updated content', - customId: customId, // Same customId = upsert - metadata: { version: 2 } -}); -``` - -```python Python -from supermemory import Supermemory -import os - -client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) - -custom_id = 'user-note-001' - -# First call creates memory -created = client.add( - content='Initial content', - custom_id=custom_id, - metadata={'version': 1} -) - -print(f'Created memory: {created.id}') - -# Second call with same customId updates existing -updated = client.add( - content='Updated content', - custom_id=custom_id, # Same customId = upsert - metadata={'version': 2} -) - -print(f'Updated memory: {updated.id}') -print(f'Same memory? {created.id == updated.id}') # True -``` - -```bash cURL -# First call - creates memory -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "Initial content", - "customId": "user-note-001", - "metadata": {"version": 1} - }' - -# Response: {"id": "mem_abc123", "status": "queued", "customId": "user-note-001"} - -# Second call - updates existing (same customId) -curl -X POST "https://api.supermemory.ai/v3/documents" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "content": "Updated content", - "customId": "user-note-001", - "metadata": {"version": 2} - }' - -# Response: {"id": "mem_abc123", "status": "queued", "customId": "user-note-001"} -# Note: Same ID returned - memory was updated, not created -``` - - - - -The `customId` enables idempotency across all endpoints. The `memoryId` doesn't support idempotency, only the `customId` does. - - - - -The `customId` can have a maximum length of 100 characters. - - - -## Single Delete - -Delete individual memories by their ID. This is a permanent hard delete with no recovery mechanism. - - - -```typescript Typescript -// Hard delete - permanently removes memory -await client.documents.delete('memory_id_123'); -console.log('Memory deleted successfully'); -``` - -```python Python -# Hard delete - permanently removes memory -client.documents.delete('memory_id_123') -print('Memory deleted successfully') - -# Error handling for single delete -try: - client.documents.delete('memory_id_123') - print('Delete successful') -except NotFoundError: - print('Memory not found or already deleted') -except AuthenticationError: - print('Authentication failed') -except Exception as e: - print(f'Delete failed: {e}') -``` - -```bash cURL -curl -X DELETE "https://api.supermemory.ai/v3/documents/memory_id_123" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" - -# Response: 204 No Content (success) -# Response: 404 Not Found (memory doesn't exist) -``` - - - -## Bulk Delete by IDs - -Delete multiple memories at once by providing an array of memory IDs. Maximum of 100 IDs per request. - - - -```typescript Typescript -// Bulk delete by memory IDs -const result = await client.documents.deleteBulk({ - ids: [ - 'memory_id_1', - 'memory_id_2', - 'memory_id_3', - 'non_existent_id' // This will be reported in errors - ] -}); - -console.log('Bulk delete result:', result); -// Output: { -// success: true, -// deletedCount: 3, -// errors: [ -// { id: "non_existent_id", error: "Memory not found" } -// ] -// } -``` - -```python Python -# Bulk delete by memory IDs -result = client.documents.delete_bulk( - ids=[ - 'memory_id_1', - 'memory_id_2', - 'memory_id_3', - 'non_existent_id' # This will be reported in errors - ] -) - -print(f'Bulk delete result: {result}') -# Output: { -# 'success': True, -# 'deletedCount': 3, -# 'errors': [ -# {'id': 'non_existent_id', 'error': 'Memory not found'} -# ] -# } -``` - -```bash cURL -curl -X DELETE "https://api.supermemory.ai/v3/documents/bulk" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "ids": [ - "memory_id_1", - "memory_id_2", - "memory_id_3", - "non_existent_id" - ] - }' - -# Response: { -# "success": true, -# "deletedCount": 3, -# "errors": [ -# {"id": "non_existent_id", "error": "Memory not found"} -# ] -# } -``` - - - -## Bulk Delete by Container Tags - -Delete all memories within specific container tags. This is useful for cleaning up entire projects or user data. - - - -```typescript Typescript -// Delete all memories in specific container tags -const result = await client.documents.deleteBulk({ - containerTags: ['user-123', 'project-old', 'archived-content'] -}); - -console.log('Bulk delete by tags result:', result); -// Output: { -// success: true, -// deletedCount: 45, -// containerTags: ["user-123", "project-old", "archived-content"] -// } -``` - -```python Python -# Delete all memories in specific container tags -result = client.documents.delete_bulk( - container_tags=['user-123', 'project-old', 'archived-content'] -) - -print(f'Bulk delete by tags result: {result}') -# Output: { -# 'success': True, -# 'deletedCount': 45, -# 'containerTags': ['user-123', 'project-old', 'archived-content'] -# } -``` - -```bash cURL -curl -X DELETE "https://api.supermemory.ai/v3/documents/bulk" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "containerTags": ["user-123", "project-old", "archived-content"] - }' - -# Response: { -# "success": true, -# "deletedCount": 45, -# "containerTags": ["user-123", "project-old", "archived-content"] -# } -``` - - - -## Advanced Patterns - -### Soft Delete Implementation - -For applications requiring audit trails or recovery mechanisms, implement soft delete patterns using metadata: - - - -```typescript Typescript -// Soft delete pattern using metadata -await client.documents.update('memory_id', { - metadata: { - deleted: true, - deletedAt: new Date().toISOString(), - deletedBy: 'user_123' - } -}); - -// Filter out deleted memories in searches -const activeMemories = await client.documents.list({ - filters: { - AND: [ - { key: "deleted", value: "true", negate: true } - ] - } -}); - -console.log('Active memories:', activeMemories.memories.length); -``` - -```python Python -from datetime import datetime - -# Soft delete pattern using metadata -client.documents.update( - 'memory_id', - metadata={ - 'deleted': True, - 'deletedAt': datetime.now().isoformat(), - 'deletedBy': 'user_123' - } -) - -# Filter out deleted memories -active_memories = client.documents.list( - filters={ - "AND": [ - {"key": "deleted", "value": "true", "negate": True} - ] - } -) - -print(f'Active memories: {len(active_memories.memories)}') -``` - -```bash cURL -# Soft delete using metadata -curl -X PATCH "https://api.supermemory.ai/v3/documents/memory_id" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "metadata": { - "deleted": true, - "deletedAt": "2024-01-15T10:30:00Z", - "deletedBy": "user_123" - } - }' - -# Response: {"id": "memory_id", "status": "queued"} -``` - - - -### Batch Processing for Large Operations - - - -```typescript Typescript -// Batch delete large numbers of memories safely -async function batchDeleteMemories(memoryIds: string[], batchSize = 100) { - const results = []; - - for (let i = 0; i < memoryIds.length; i += batchSize) { - const batch = memoryIds.slice(i, i + batchSize); - - console.log(`Processing batch ${Math.floor(i/batchSize) + 1} of ${Math.ceil(memoryIds.length/batchSize)}`); - - try { - const result = await client.documents.deleteBulk({ ids: batch }); - results.push(result); - - // Brief delay between batches to avoid rate limiting - if (i + batchSize < memoryIds.length) { - await new Promise(resolve => setTimeout(resolve, 1000)); - } - } catch (error) { - console.error(`Batch ${Math.floor(i/batchSize) + 1} failed:`, error); - results.push({ success: false, error: error.message, batch }); - } - } - - // Aggregate results - const totalDeleted = results - .filter(r => r.success) - .reduce((sum, r) => sum + (r.deletedCount || 0), 0); - - console.log(`Total deleted: ${totalDeleted} out of ${memoryIds.length}`); - return { totalDeleted, results }; -} -``` - -```python Python -import time -import math - -def batch_delete_memories(memory_ids, batch_size=100): - """Batch delete large numbers of memories safely""" - results = [] - - for i in range(0, len(memory_ids), batch_size): - batch = memory_ids[i:i + batch_size] - batch_num = i // batch_size + 1 - total_batches = math.ceil(len(memory_ids) / batch_size) - - print(f'Processing batch {batch_num} of {total_batches}') - - try: - result = client.documents.delete_bulk(ids=batch) - results.append(result) - - # Brief delay between batches to avoid rate limiting - if i + batch_size < len(memory_ids): - time.sleep(1) - except Exception as error: - print(f'Batch {batch_num} failed: {error}') - results.append({'success': False, 'error': str(error), 'batch': batch}) - - # Aggregate results - total_deleted = sum( - r.get('deletedCount', 0) for r in results if r.get('success') - ) - - print(f'Total deleted: {total_deleted} out of {len(memory_ids)}') - return {'totalDeleted': total_deleted, 'results': results} -``` - -```bash cURL -# Batch processing script example -#!/bin/bash - -MEMORY_IDS=("id1" "id2" "id3") # Your memory IDs array -BATCH_SIZE=100 -TOTAL_DELETED=0 - -# Process in batches -for ((i=0; i<${#MEMORY_IDS[@]}; i+=BATCH_SIZE)); do - batch=("${MEMORY_IDS[@]:i:BATCH_SIZE}") - batch_json=$(printf '%s\n' "${batch[@]}" | jq -R . | jq -s .) - - echo "Processing batch $((i/BATCH_SIZE + 1))" - - response=$(curl -s -X DELETE \ - "https://api.supermemory.ai/v3/documents/bulk" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d "{\"ids\": $batch_json}") - - deleted_count=$(echo "$response" | jq -r '.deletedCount // 0') - TOTAL_DELETED=$((TOTAL_DELETED + deleted_count)) - - echo "Batch deleted: $deleted_count memories" - sleep 1 # Rate limiting protection -done - -echo "Total deleted: $TOTAL_DELETED memories" -``` - - - -## Best Practices - -### Update Operations - -1. **Use customId for idempotent updates** - Prevents duplicate memories and enables safe retries -2. **Monitor processing status** - Content changes trigger full reprocessing; metadata-only updates do not reindex -3. **Handle metadata carefully** - Updates replace specified metadata keys -4. **Implement proper error handling** - Memory may be deleted between operations - -### Delete Operations - -1. **Hard delete is permanent** - No recovery mechanism exists -2. **Use bulk operations efficiently** - Maximum 100 IDs per bulk delete request -3. **Consider soft delete patterns** - Use metadata flags for recoverable deletion -4. **Batch large operations** - Avoid rate limits with proper batching -5. **Clean up application state** - Update your UI/cache after deletions diff --git a/apps/docs/user-profiles/api.mdx b/apps/docs/user-profiles/api.mdx deleted file mode 100644 index 7501e791..00000000 --- a/apps/docs/user-profiles/api.mdx +++ /dev/null @@ -1,226 +0,0 @@ ---- -title: "Profile API" -description: "Endpoint details and response structure for user profiles" -sidebarTitle: "API Reference" -icon: "code" ---- - -## Endpoint - -**`POST /v4/profile`** - -Retrieves a user's profile, optionally combined with search results. - -## Request - -### Headers - -| Header | Required | Description | -|--------|----------|-------------| -| `Authorization` | Yes | Bearer token with your API key | -| `Content-Type` | Yes | `application/json` | - -### Body Parameters - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `containerTag` | string | Yes | The container tag (usually user ID) to get profiles for | -| `threshold` | float | No | Threshold for filtering search results. Only results with a score above this threshold will be included. | -| `q` | string | No | Optional search query to include search results with the profile | - -## Response - -```json -{ - "profile": { - "static": [ - "User is a software engineer", - "User specializes in Python and React", - "User prefers dark mode interfaces" - ], - "dynamic": [ - "User is working on Project Alpha", - "User recently started learning Rust", - "User is debugging authentication issues" - ] - }, - "searchResults": { - "results": [...], // Only if 'q' parameter was provided - "total": 15, - "timing": 45.2 - } -} -``` - -### Response Fields - -| Field | Type | Description | -|-------|------|-------------| -| `profile.static` | string[] | Long-term, stable facts about the user | -| `profile.dynamic` | string[] | Recent context and temporary information | -| `searchResults` | object | Only present if `q` parameter was provided | -| `searchResults.results` | array | Matching memory results | -| `searchResults.total` | number | Total number of matches | -| `searchResults.timing` | number | Query execution time in milliseconds | - -## Basic Request - - - -```typescript TypeScript -const response = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - containerTag: 'user_123' - }) -}); - -const data = await response.json(); - -console.log("Static facts:", data.profile.static); -console.log("Dynamic context:", data.profile.dynamic); -``` - -```python Python -import requests -import os - -response = requests.post( - 'https://api.supermemory.ai/v4/profile', - headers={ - 'Authorization': f'Bearer {os.getenv("SUPERMEMORY_API_KEY")}', - 'Content-Type': 'application/json' - }, - json={ - 'containerTag': 'user_123' - } -) - -data = response.json() - -print("Static facts:", data['profile']['static']) -print("Dynamic context:", data['profile']['dynamic']) -``` - -```bash cURL -curl -X POST https://api.supermemory.ai/v4/profile \ - -H "Authorization: Bearer YOUR_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "containerTag": "user_123" - }' -``` - - - -## Profile with Search - -Include a search query to get both profile data and relevant memories in one call: - - - -```typescript TypeScript -const response = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - containerTag: 'user_123', - q: 'deployment errors yesterday' - }) -}); - -const data = await response.json(); - -// Profile data -const profile = data.profile; - -// Search results (only present because we passed 'q') -const searchResults = data.searchResults?.results || []; -``` - -```python Python -response = requests.post( - 'https://api.supermemory.ai/v4/profile', - headers={ - 'Authorization': f'Bearer {os.getenv("SUPERMEMORY_API_KEY")}', - 'Content-Type': 'application/json' - }, - json={ - 'containerTag': 'user_123', - 'q': 'deployment errors yesterday' - } -) - -data = response.json() - -profile = data['profile'] -search_results = data.get('searchResults', {}).get('results', []) -``` - - - -## Profile with Threshold - -Use the optional `threshold` parameter to filter search results by relevance score: - - - -```typescript TypeScript -const response = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - containerTag: 'user_123', - threshold: 0.7, // Only include results with score > 0.7 - q: 'deployment errors yesterday' - }) -}); - -const data = await response.json(); -``` - -```python Python -response = requests.post( - 'https://api.supermemory.ai/v4/profile', - headers={ - 'Authorization': f'Bearer {os.getenv("SUPERMEMORY_API_KEY")}', - 'Content-Type': 'application/json' - }, - json={ - 'containerTag': 'user_123', - 'threshold': 0.7, # Only include results with score > 0.7 - 'q': 'deployment errors yesterday' - } -) - -data = response.json() -``` - - - -## Error Responses - -| Status | Description | -|--------|-------------| -| `400` | Missing or invalid `containerTag` or `threshold` | -| `401` | Invalid or missing API key | -| `404` | Container not found | -| `500` | Internal server error | - -## Rate Limits - -Profile requests count toward your standard API rate limits. Since profiles are cached, repeated requests for the same user are efficient. - - - View complete integration examples for chat apps, support systems, and more - diff --git a/apps/docs/user-profiles/buckets.mdx b/apps/docs/user-profiles/buckets.mdx new file mode 100644 index 00000000..b44e686c --- /dev/null +++ b/apps/docs/user-profiles/buckets.mdx @@ -0,0 +1,372 @@ +--- +title: "Profile Buckets" +sidebarTitle: "Buckets" +description: "Custom topical categories for user profiles" +icon: "tags" +--- + +Buckets are **custom topical categories** for a profile — an axis that sits alongside `static` and `dynamic`. Where static/dynamic split facts by how long-lived they are, buckets group them by subject (e.g. `preferences`, `goals`, `work`). As content is ingested, a classifier assigns each memory to the buckets it matches, so you can pull just the slice of context a given surface needs. + + +New to buckets? Read the [conceptual overview](/concepts/user-profiles#buckets) first — this page is the API reference for reading, creating, and managing them. + + +Every org starts with a built-in `preferences` bucket. You can define your own at the organization level, add more at the space (container tag) level, or get AI-generated suggestions — all covered below. + +--- + +## Reading buckets + +### Requesting bucketed profiles + +Pass `include: ["buckets"]` to `/v4/profile` to return bucket-organized memories, and optionally `buckets` to limit the response to specific keys. `include` also lets you skip sections you don't need — `["buckets"]` alone omits `static` and `dynamic`. + + + + ```typescript + const res = await fetch("https://api.supermemory.ai/v4/profile", { + method: "POST", + headers: { + "Authorization": `Bearer ${API_KEY}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + containerTag: "user_123", + include: ["buckets"], + buckets: ["preferences", "goals"] // optional — omit for all buckets + }) + }); + + const { profile } = await res.json(); + console.log(profile.buckets.preferences); + console.log(profile.buckets.goals); + ``` + + + ```bash + curl -X POST "https://api.supermemory.ai/v4/profile" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "containerTag": "user_123", + "include": ["buckets"], + "buckets": ["preferences", "goals"] + }' + ``` + + + +**Response:** +```json +{ + "profile": { + "buckets": { + "preferences": [ + "[Summary] Prefers concise, technical answers and dark-mode tooling", + "[Recent] Switched their editor to Zed" + ], + "goals": [ + "[Recent] Wants to ship the billing revamp this quarter" + ] + } + } +} +``` + + +**`[Recent]` and `[Summary]` labels.** To keep profiles dense, an entity's older memories are periodically aggregated into a short synthesis. Entries prefixed `[Summary]` are that aggregated context; entries prefixed `[Recent]` were ingested since the last aggregation and aren't summarized yet. The `dynamic` section uses the same `[Recent]` prefix (plus a `[YYYY-MM-DD]` date). Strip the prefixes if you only want raw text, or keep them to signal recency to your model. + + +### List bucket definitions + +To see which buckets are configured for a container tag (org buckets merged with any space-level additions), call `/v4/profile/buckets`: + + + + ```typescript + const res = await fetch("https://api.supermemory.ai/v4/profile/buckets", { + method: "POST", + headers: { + "Authorization": `Bearer ${API_KEY}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ containerTag: "user_123" }) + }); + + const { buckets } = await res.json(); + // [{ key: "preferences", description: "..." }, ...] + ``` + + + ```bash + curl -X POST "https://api.supermemory.ai/v4/profile/buckets" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"containerTag": "user_123"}' + ``` + + + +**Response:** +```json +{ + "buckets": [ + { + "key": "preferences", + "description": "Explicit first-person preferences the person directly stated." + } + ] +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `buckets[].key` | string | Stable slug, also stored on each memory. Lowercase alphanumeric with `-`/`_`, 1–64 chars | +| `buckets[].description` | string | What belongs in the bucket — guides the ingestion classifier | + +This endpoint requires only that the caller belongs to the org — any role, and any API key (scoped keys included) can read bucket definitions. + +--- + +## Creating and configuring buckets + +Bucket definitions live at two levels: **organization** (the default set every container tag gets) and **space** (per-container-tag additions). Both are configured through the settings API — there's no console-only path; these are regular authenticated endpoints. + + +Writing buckets requires an **admin or owner** role in the org, and a **full-access API key** — project/container-tag-**scoped** keys cannot call these endpoints and will get a `403`. Reading buckets (the endpoints above) has no such restriction. + + +### Organization-level buckets + +`PATCH /v3/settings` sets the org's bucket list. The `profileBuckets` array **replaces the entire stored list** — it's not a merge, so always send the full set you want. + + + + ```typescript + const res = await fetch("https://api.supermemory.ai/v3/settings", { + method: "PATCH", + headers: { + "Authorization": `Bearer ${API_KEY}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + profileBuckets: [ + { key: "work", description: "Professional role, employer, projects, and work-related decisions." }, + { key: "health", description: "Physical and mental wellbeing, habits, and health-related goals." } + ] + }) + }); + + const { updated } = await res.json(); + ``` + + + ```bash + curl -X PATCH "https://api.supermemory.ai/v3/settings" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "profileBuckets": [ + { "key": "work", "description": "Professional role, employer, projects, and work-related decisions." }, + { "key": "health", "description": "Physical and mental wellbeing, habits, and health-related goals." } + ] + }' + ``` + + + +**Response:** +```json +{ + "orgId": "org_abc123xyz", + "orgSlug": "acme-inc", + "updated": { + "profileBuckets": [ + { "key": "work", "description": "Professional role, employer, projects, and work-related decisions." }, + { "key": "health", "description": "Physical and mental wellbeing, habits, and health-related goals." } + ] + // ...other org settings fields + } +} +``` + +`GET /v3/settings` returns the current org settings, including `profileBuckets`, without changing anything. + +### Space (container tag) buckets + +`PATCH /v3/container-tags/{containerTag}` sets a container tag's own bucket list. These are **add-only** on top of org buckets — a tag always keeps every org bucket, and if a space bucket's key collides with an org bucket, the org's definition wins in the merged, effective set used at ingestion and read time. + + + + ```typescript + const res = await fetch("https://api.supermemory.ai/v3/container-tags/user_alex", { + method: "PATCH", + headers: { + "Authorization": `Bearer ${API_KEY}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + profileBuckets: [ + { key: "trip_planning", description: "Upcoming trip details specific to this user." } + ] + }) + }); + ``` + + + ```bash + curl -X PATCH "https://api.supermemory.ai/v3/container-tags/user_alex" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "profileBuckets": [ + { "key": "trip_planning", "description": "Upcoming trip details specific to this user." } + ] + }' + ``` + + + +**Response:** +```json +{ + "containerTag": "user_alex", + "name": "user_alex", + "entityContext": null, + "memoryFilesystemPaths": null, + "profileBuckets": [ + { "key": "trip_planning", "description": "Upcoming trip details specific to this user." } + ], + "updatedAt": "2026-07-18T00:00:00.000Z" +} +``` + + +Like the org endpoint, this **replaces the tag's own bucket list**, not the merged/effective set — `profileBuckets` in the response is only what this space added, not the org buckets it inherits. Call `/v4/profile/buckets` to see the merged, effective list for a tag. + + +### AI-generated suggestions + +`POST /v3/settings/suggest-buckets` returns 3–6 bucket suggestions tailored to your org, generated from the `filterPrompt` already configured in your org settings. It doesn't save anything — pass the results into the `PATCH /v3/settings` call above to apply them. + + + + ```typescript + const res = await fetch("https://api.supermemory.ai/v3/settings/suggest-buckets", { + method: "POST", + headers: { "Authorization": `Bearer ${API_KEY}` } + }); + + const { suggestions } = await res.json(); + // [{ key: "customer_support", description: "..." }, ...] + ``` + + + ```bash + curl -X POST "https://api.supermemory.ai/v3/settings/suggest-buckets" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" + ``` + + + + +Requires a `filterPrompt` already set on your org (via `PATCH /v3/settings`) — without one, this returns `400 { "error": "No organization context configured..." }`, since suggestions are tailored from it. + + +### Starter presets + +If you'd rather start from a template than write descriptions from scratch, these are the same presets available in the console UI: + +| Key | Description | +|-----|-------------| +| `preferences` | Stated likes, dislikes, and personal settings choices — food, media, tools, aesthetics, and other expressed tastes. | +| `interests` | Topics, hobbies, and domains the person is curious about or actively follows, even if not yet a firm preference. | +| `goals` | Short- and long-term objectives, aspirations, and things the person wants to achieve or work toward. | +| `work` | Professional context: current role, employer, projects, colleagues, career trajectory, and work-related decisions. | +| `relationships` | People in the person's life — family, friends, colleagues, partners — and the nature of those connections. | +| `health` | Physical and mental wellbeing: conditions, habits, medications, fitness routines, and health-related goals. | +| `skills` | Competencies, expertise areas, tools mastered, and things the person is actively learning. | +| `finances` | Financial habits, spending patterns, savings goals, income context, and money-related decisions. | +| `education` | Academic background, current courses, learning goals, and educational achievements. | +| `travel` | Places visited, travel preferences, upcoming trips, and destinations the person wants to visit. | +| `values` | Core beliefs, ethical stances, principles, and things that matter most to the person. | +| `projects` | Personal and professional side projects, creative endeavors, and things being built outside of primary work. | + +### Default bucket + +If neither the org nor the space has configured any buckets, ingestion falls back to a single built-in `preferences` bucket, scoped tightly to explicit first-person statements ("prefers X over Y", "always uses W") — not inferred traits or general observations. Configuring your own buckets replaces this default. + +--- + +## Validation & limits + +| Rule | Detail | +|------|--------| +| Key format | Lowercase alphanumeric, starting with a letter/digit, may contain `-`/`_`. 1–64 chars | +| Reserved keys | `static` and `dynamic` can't be used as bucket keys | +| Max buckets | 50 per array — applies separately to an org's list and to each space's list | +| Duplicate keys | Rejected within a single request's array | +| Description | Optional, up to 2,000 chars. Defaults to empty if omitted | + + +Bucket descriptions steer classification. A precise description ("Explicit first-person preferences only — exclude inferred traits") yields cleaner buckets than a vague one. + + +--- + +## Configure + +### Instructions + +Bucket `description`s only steer classification *within* a bucket — they don't tell the model anything about the space itself. For that, set [`entityContext`](/concepts/customization#entity-context) on the container tag: a free-text field that's appended alongside `filterPrompt` into the same prompt the extraction/classification step uses, so it shapes bucket assignment too, not just fact extraction. + +`PATCH /v3/container-tags/{containerTag}`: + + + + ```typescript + await fetch("https://api.supermemory.ai/v3/container-tags/user_alex", { + method: "PATCH", + headers: { + "Authorization": `Bearer ${API_KEY}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + entityContext: "This tag belongs to a solo founder juggling sales, hiring, and product." + }) + }); + ``` + + + ```bash + curl -X PATCH "https://api.supermemory.ai/v3/container-tags/user_alex" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "entityContext": "This tag belongs to a solo founder juggling sales, hiring, and product." + }' + ``` + + + +| Field | Type | Limit | +|-------|------|-------| +| `entityContext` | string \| null | Up to 1,500 characters. Pass `null` to clear | + + +`entityContext` is per-container-tag, so use it for context specific to that user/space (who they are, what the space is for) — use org-level [`filterPrompt`](/concepts/customization) for guidance that should apply everywhere. Both are combined into the same prompt, so keep them complementary rather than redundant. + + +You can also set `entityContext` inline when adding content, via `entityContext` on [`POST /v4/memories`](/ingestion/add-memories) — useful if you don't want a separate settings call. + +### Model selection + +The model behind extraction and bucket classification isn't configurable through the API on supermemory Cloud — it's managed for you. If you're self-hosting, you choose the provider and model yourself via environment variables (`OPENAI_MODEL` and related) — see [Self-hosting Configuration](/self-hosting/configuration). + +--- + +## Next Steps + +- [User Profiles](/recall/user-profiles) — Fetch and use profiles via the API +- [User Profiles Concept](/concepts/user-profiles) — Static vs dynamic vs buckets +- [Container Tags](/concepts/container-tags) — How spaces and container tags work diff --git a/apps/docs/user-profiles/examples.mdx b/apps/docs/user-profiles/examples.mdx deleted file mode 100644 index bd64b9da..00000000 --- a/apps/docs/user-profiles/examples.mdx +++ /dev/null @@ -1,370 +0,0 @@ ---- -title: "Profile Examples" -description: "Complete code examples for integrating user profiles" -sidebarTitle: "Examples" -icon: "laptop-code" ---- - -## Building a Personalized Prompt - -The most common use case: inject profile data into your LLM's system prompt. - - - -```typescript TypeScript -async function handleChatMessage(userId: string, message: string) { - // Get user profile - const profileResponse = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ containerTag: userId }) - }); - - const { profile } = await profileResponse.json(); - - // Build personalized system prompt - const systemPrompt = `You are assisting a user with the following context: - -ABOUT THE USER: -${profile.static?.join('\n') || 'No profile information yet.'} - -CURRENT CONTEXT: -${profile.dynamic?.join('\n') || 'No recent activity.'} - -Provide responses personalized to their expertise level and preferences.`; - - // Send to your LLM - const response = await llm.chat({ - messages: [ - { role: "system", content: systemPrompt }, - { role: "user", content: message } - ] - }); - - return response; -} -``` - -```python Python -import requests -import os - -async def handle_chat_message(user_id: str, message: str): - # Get user profile - response = requests.post( - 'https://api.supermemory.ai/v4/profile', - headers={ - 'Authorization': f'Bearer {os.getenv("SUPERMEMORY_API_KEY")}', - 'Content-Type': 'application/json' - }, - json={'containerTag': user_id} - ) - - profile = response.json()['profile'] - - # Build personalized system prompt - static_facts = '\n'.join(profile.get('static', ['No profile information yet.'])) - dynamic_context = '\n'.join(profile.get('dynamic', ['No recent activity.'])) - - system_prompt = f"""You are assisting a user with the following context: - -ABOUT THE USER: -{static_facts} - -CURRENT CONTEXT: -{dynamic_context} - -Provide responses personalized to their expertise level and preferences.""" - - # Send to your LLM - llm_response = await llm.chat( - messages=[ - {"role": "system", "content": system_prompt}, - {"role": "user", "content": message} - ] - ) - - return llm_response -``` - - - -## Full Context Mode - -Combine profile data with query-specific search for comprehensive context: - - - -```typescript TypeScript -async function getFullContext(userId: string, userQuery: string) { - // Single call gets both profile and search results - const response = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - containerTag: userId, - q: userQuery // Include the user's query - }) - }); - - const data = await response.json(); - - return { - // Static background about the user - userBackground: data.profile.static, - // Current activities and context - currentContext: data.profile.dynamic, - // Query-specific memories - relevantMemories: data.searchResults?.results || [] - }; -} - -// Usage -const context = await getFullContext('user_123', 'deployment error last week'); - -const systemPrompt = ` -User Background: -${context.userBackground.join('\n')} - -Current Context: -${context.currentContext.join('\n')} - -Relevant Information: -${context.relevantMemories.map(m => m.content).join('\n')} -`; -``` - -```python Python -async def get_full_context(user_id: str, user_query: str): - # Single call gets both profile and search results - response = requests.post( - 'https://api.supermemory.ai/v4/profile', - headers={ - 'Authorization': f'Bearer {os.getenv("SUPERMEMORY_API_KEY")}', - 'Content-Type': 'application/json' - }, - json={ - 'containerTag': user_id, - 'q': user_query # Include the user's query - } - ) - - data = response.json() - - return { - 'user_background': data['profile'].get('static', []), - 'current_context': data['profile'].get('dynamic', []), - 'relevant_memories': data.get('searchResults', {}).get('results', []) - } - -# Usage -context = await get_full_context('user_123', 'deployment error last week') - -system_prompt = f""" -User Background: -{chr(10).join(context['user_background'])} - -Current Context: -{chr(10).join(context['current_context'])} - -Relevant Information: -{chr(10).join(m['content'] for m in context['relevant_memories'])} -""" -``` - - - -## Filtering with Threshold - -Use the optional `threshold` parameter to filter search results by relevance score: - - - -```typescript TypeScript -async function getHighQualityContext(userId: string, userQuery: string) { - const response = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - containerTag: userId, - threshold: 0.7, // Only include high-confidence results - q: userQuery - }) - }); - - const data = await response.json(); - - // Only highly relevant memories are included - return data; -} -``` - -```python Python -async def get_high_quality_context(user_id: str, user_query: str): - response = requests.post( - 'https://api.supermemory.ai/v4/profile', - headers={ - 'Authorization': f'Bearer {os.getenv("SUPERMEMORY_API_KEY")}', - 'Content-Type': 'application/json' - }, - json={ - 'containerTag': user_id, - 'threshold': 0.7, # Only include high-confidence results - 'q': user_query - } - ) - - data = response.json() - - # Only highly relevant memories are included - return data -``` - - - -## Separate Profile and Search - -For more control, you can call profile and search endpoints separately: - -```typescript TypeScript -async function advancedContext(userId: string, query: string) { - // Parallel requests for profile and search - const [profileRes, searchRes] = await Promise.all([ - fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ containerTag: userId }) - }), - fetch('https://api.supermemory.ai/v3/search', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - q: query, - containerTag: userId, - limit: 5 - }) - }) - ]); - - const profile = await profileRes.json(); - const search = await searchRes.json(); - - return { profile: profile.profile, searchResults: search.results }; -} -``` - -## Express.js Middleware - -Add profile context to all authenticated requests: - -```typescript TypeScript -import express from 'express'; - -// Middleware to fetch user profile -async function withUserProfile(req, res, next) { - if (!req.user?.id) { - return next(); - } - - try { - const response = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ containerTag: req.user.id }) - }); - - req.userProfile = await response.json(); - } catch (error) { - console.error('Failed to fetch profile:', error); - req.userProfile = null; - } - - next(); -} - -const app = express(); - -// Apply to all routes -app.use(withUserProfile); - -app.post('/chat', async (req, res) => { - const { message } = req.body; - - // Profile is automatically available - const profile = req.userProfile?.profile; - - // Use in your LLM call... -}); -``` - -## Next.js API Route - -```typescript TypeScript -// app/api/chat/route.ts -import { NextRequest, NextResponse } from 'next/server'; - -export async function POST(req: NextRequest) { - const { userId, message } = await req.json(); - - // Fetch profile - const profileRes = await fetch('https://api.supermemory.ai/v4/profile', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ containerTag: userId }) - }); - - const { profile } = await profileRes.json(); - - // Build context and call your LLM... - const response = await generateResponse(message, profile); - - return NextResponse.json({ response }); -} -``` - -## AI SDK Integration - -For the cleanest integration, use the Supermemory AI SDK middleware: - -```typescript TypeScript -import { generateText } from "ai" -import { withSupermemory } from "@supermemory/tools/ai-sdk" -import { openai } from "@ai-sdk/openai" - -// Simple setup - profiles automatically injected -const model = withSupermemory(openai("gpt-4"), { - containerTag: "user-123", - customId: "conv-1", -}) - -const result = await generateText({ - model, - messages: [{ role: "user", content: "Help me with my current project" }] -}) -// Model automatically has access to user's profile! -``` - - - Learn more about automatic profile injection with the AI SDK - diff --git a/apps/docs/user-profiles/overview.mdx b/apps/docs/user-profiles/overview.mdx deleted file mode 100644 index 160807fa..00000000 --- a/apps/docs/user-profiles/overview.mdx +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: "User Profiles" -description: "Automatically maintained user context that gives your LLMs instant, comprehensive knowledge about each user" -sidebarTitle: "Overview" -icon: "user" ---- - -User profiles are **automatically maintained collections of facts about your users** that Supermemory builds from all their interactions and content. Think of it as a persistent "about me" document that's always up-to-date and instantly accessible. - - - - No search queries needed - comprehensive user information is always ready - - - Profiles update automatically as users interact with your system - - - Static facts + dynamic context for perfect personalization - - - Just ingest content normally - profiles build themselves - - - -## Why Profiles? - -Traditional memory systems rely entirely on search, which has fundamental limitations: - -| Problem | With Search Only | With Profiles | -|---------|-----------------|---------------| -| **Context retrieval** | 3-5 search queries | 1 profile call | -| **Response time** | 200-500ms | 50-100ms | -| **Consistency** | Varies by search quality | Always comprehensive | -| **Basic user info** | Requires specific queries | Always available | - -**Search is too narrow**: When you search for "project updates", you miss that the user prefers bullet points, works in PST timezone, and uses specific terminology. - -**Profiles provide the foundation**: Instead of repeatedly searching for basic context, profiles give your LLM a complete picture of who the user is. - -## Static vs Dynamic - -Profiles intelligently separate two types of information: - -![](/images/static-dynamic-profile.png) - -### Static Profile - -Long-term, stable facts that rarely change: - -- "Sarah Chen is a senior software engineer at TechCorp" -- "Sarah specializes in distributed systems and Kubernetes" -- "Sarah has a PhD in Computer Science from MIT" -- "Sarah prefers technical documentation over video tutorials" - -### Dynamic Profile - -Recent context and temporary states: - -- "Sarah is currently migrating the payment service to microservices" -- "Sarah recently started learning Rust for a side project" -- "Sarah is preparing for a conference talk next month" -- "Sarah is debugging a memory leak in the authentication service" - -## How It Works - -Profiles are **automatically built and maintained** through Supermemory's ingestion pipeline: - - - - When users add documents, chat, or any content to Supermemory, it goes through the standard ingestion workflow. - - - - AI analyzes the content to extract not just memories, but also facts about the user themselves. - - - - The system generates profile operations (add, update, or remove facts) based on the new information. - - - - Profiles are updated in real-time, ensuring they always reflect the latest information. - - - - - You don't need to manually manage profiles - they build themselves as users interact with your system. - - -## Profiles + Search - -Profiles don't replace search - they complement it: - - - - The user's profile gives your LLM comprehensive background context about who they are, what they know, and what they're working on. - - - - When you need specific information (like "error in deployment yesterday"), search finds those exact memories. - - - - Your LLM gets both the broad understanding from profiles AND the specific details from search. - - - -### Example - -User asks: **"Can you help me debug this?"** - -**Without profiles**: The LLM has no context about the user's expertise level, current projects, or debugging preferences. - -**With profiles**: The LLM knows: -- The user is a senior engineer (adjust technical level) -- They're working on a payment service migration (likely context) -- They prefer command-line tools over GUIs (tool suggestions) -- They recently had issues with memory leaks (possible connection) - -## Next Steps - - - - Learn how to fetch and use profiles via the API - - - See complete integration examples - - - Use the AI SDK for automatic profile injection - - - Common patterns and applications - - diff --git a/apps/docs/user-profiles/use-cases.mdx b/apps/docs/user-profiles/use-cases.mdx deleted file mode 100644 index db383513..00000000 --- a/apps/docs/user-profiles/use-cases.mdx +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: "Profile Use Cases" -description: "Common patterns and applications for user profiles" -sidebarTitle: "Use Cases" -icon: "lightbulb" ---- - -## Personalized AI Assistants - -The most common use case: building AI assistants that truly know your users. - -**What profiles provide:** -- User's expertise level (adjust technical depth) -- Communication preferences (brief vs detailed, formal vs casual) -- Tools and technologies they use -- Current projects and priorities - -**Example prompt enhancement:** - -```typescript -const systemPrompt = `You are assisting ${userName}. - -Their background: -${profile.static.join('\n')} - -Current focus: -${profile.dynamic.join('\n')} - -Adjust your responses to match their expertise level and preferences.`; -``` - -**Result:** An assistant that explains React hooks differently to a junior developer vs a senior architect. - -## Customer Support Systems - -Give support agents (or AI) instant context about customers. - -**What profiles provide:** -- Customer's product usage history -- Previous issues and resolutions -- Preferred communication channels -- Technical proficiency level - -**Benefits:** -- No more "let me look up your account" -- Agents immediately understand customer context -- AI support can reference past interactions naturally - -```typescript -// Support agent dashboard -async function loadCustomerContext(customerId: string) { - const { profile } = await getProfile(customerId); - - return { - summary: profile.static, // Long-term customer info - recentIssues: profile.dynamic // Current tickets, recent problems - }; -} -``` - -## Educational Platforms - -Adapt learning content to each student's level and progress. - -**What profiles provide:** -- Learning style preferences -- Completed courses and topics -- Areas of strength and weakness -- Current learning goals - -**Example adaptation:** - -```typescript -// Profile might contain: -// static: ["Visual learner", "Strong in algebra, struggles with geometry"] -// dynamic: ["Currently studying calculus", "Preparing for AP exam"] - -const tutorPrompt = `You're helping a student with: -${profile.static.join('\n')} - -Current focus: ${profile.dynamic.join('\n')} - -Adapt explanations to their learning style and build on their strengths.`; -``` - -## Development Tools - -IDE assistants and coding tools that understand your codebase and habits. - -**What profiles provide:** -- Preferred languages and frameworks -- Coding style and conventions -- Current project context -- Frequently used patterns - -**Example:** - -```typescript -// Profile for a developer: -// static: ["Prefers TypeScript", "Uses functional patterns", "Senior engineer"] -// dynamic: ["Working on auth refactor", "Recently learning Rust"] - -// Code assistant knows to: -// - Suggest TypeScript solutions -// - Use functional patterns in examples -// - Provide senior-level explanations -// - Connect suggestions to the auth refactor when relevant -``` - -## Knowledge Base Assistants - -Internal tools that understand each employee's role and responsibilities. - -**What profiles provide:** -- Department and role -- Projects they're involved in -- Access level and permissions context -- Areas of expertise (for routing questions) - -**Example:** - -```typescript -// HR assistant that knows: -// - Employee's team and manager -// - Their location/timezone -// - Recent PTO requests -// - Benefits elections - -const response = await hrAssistant.answer( - "When is my next performance review?", - { profile: employeeProfile } -); -// Can answer with specific dates, manager name, etc. -``` - -## E-commerce Recommendations - -Personalized shopping experiences beyond basic recommendation engines. - -**What profiles provide:** -- Style preferences -- Size information -- Past purchases and returns -- Budget range -- Occasions they shop for - -**Example conversation:** - -``` -User: "I need something for a wedding next month" - -// Profile knows: prefers classic styles, size M, budget-conscious, -// previously bought navy suits \ No newline at end of file diff --git a/apps/docs/using-supermemory.mdx b/apps/docs/using-supermemory.mdx new file mode 100644 index 00000000..f65ed2e3 --- /dev/null +++ b/apps/docs/using-supermemory.mdx @@ -0,0 +1,64 @@ +--- +title: "Using Supermemory" +sidebarTitle: "Overview" +description: "The full loop: authenticate, put context in, get it back out, keep it correct." +icon: "compass" +--- + +import { Journey, JourneyStep, JourneyItem } from "/snippets/journey.mdx"; + +Everything in this section is one of four steps. Same loop whether you're building personal memory, RAG over docs, or both on the same `containerTag`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Raw input becomes **memories** (the knowledge graph) and/or indexed **document chunks** (for RAG) automatically — see [how it works](/concepts/how-it-works). You don't choose one or the other; both build from the same write. Retrieval gives you three ways to read that same pool back — see [Memory vs RAG](/concepts/memory-vs-rag) if you're not sure which one fits. + +## Where next + + + + Walk the whole loop end to end with one working example. + + + What happens between `add()` and a memory showing up in search. + + + The isolation boundary every ingest and retrieve call is scoped to. + + + When to reach for search, profiles, or both. + + + Run standardized, reproducible evals against Supermemory and other providers — including your own. + + diff --git a/apps/docs/vibe-coding.mdx b/apps/docs/vibe-coding.mdx deleted file mode 100644 index 6a5c3279..00000000 --- a/apps/docs/vibe-coding.mdx +++ /dev/null @@ -1,441 +0,0 @@ ---- -title: "Vibe Coding Setup" -description: "Automatic Supermemory integration using AI coding agents" -icon: "zap" -sidebarTitle: "Install with AI" ---- - -Get your AI coding agent to integrate Supermemory in minutes. Copy the prompt below, paste it into Claude/GPT/Cursor, and let it do the work. - -## Quick Setup - - - - Give your agent a way to reference and search through supermemory docs. - - - - Paste one prompt, answer questions, get working code - - - - Interactive guided setup - - - -## MCP Server - -Give your agent a way to reference and search through supermemory docs. - -### Quick Install - -```bash -npx -y install-mcp@latest https://supermemory.ai/docs/mcp --client claude-code --oauth=no -y -``` - -Replace `claude` with: `cursor`, `opencode`, or `vscode` - - ---- - -## The Prompt - - -**Copy everything in the code block below** and paste it into your AI coding agent. It will ask you questions and generate complete integration code. - - -After adding the MCP, paste this in your agent session: - - -```` -You are integrating Supermemory into my application. Supermemory provides user memory, semantic search, and automatic knowledge extraction for AI applications. - -Note: You can always reference the documentation by using the **SearchSupermemoryDocs MCP** or running a web search tool for content on **supermemory.ai/docs**. - -CANONICAL API SURFACE (use these, nothing else): - -- Auth header: `Authorization: Bearer $SUPERMEMORY_API_KEY` — the only supported auth header -- Write content: POST https://api.supermemory.ai/v3/documents -- Search: POST https://api.supermemory.ai/v4/search -- Profile + search: POST https://api.supermemory.ai/v4/profile -- Settings: PATCH https://api.supermemory.ai/v3/settings -- Scoping: `containerTag` (singular string) in the JSON body — never in a header -- SDK: `client.documents.add()`, `client.search.memories()`, `client.profile()` - -DO NOT USE — these are deprecated, undocumented, or fabricated by previous AI codegen: - -- Endpoints: /v1/anything, /v3/memories, /v3/search (use /v3/documents and /v4/search) -- Headers: x-supermemory-api-key, x-api-key, x-sm-user-id, x-sm-project, - x-project-id, X-Workspace-Id (always use Authorization: Bearer) -- Body keys: containerTags (plural array), userId, spaces, schema, container, - tags (top-level), filter (singular) (use containerTag + filters) -- SDK calls: client.search.execute, client.documents.add (use client.add), - client.documents.deleteBulk, client.documents.batch_add, - client.memories.updateMemory (the real method is client.memories.update) -- Kwargs: chunk_threshold (use `threshold`), sort, order, include_content, - include_full_docs, timeout (as an SDK kwarg) - -NOTE on memory mutation: `client.memories.update`, `client.memories.delete`, and -`client.memories.forget` ARE real and supported — but most apps don't need them. -Memories are auto-extracted from documents. Only reach for these if you're exposing -a "manage my memories" UI to end users or agents. -- Mixing: `rerank` and `rewriteQuery` are valid on /v4/search ONLY — never on /v3/search - -SCOPING IS LOAD-BEARING. Every write and every search MUST include `containerTag`. -If you omit it, every user's data collapses into the API key's default bucket — this -is the single most common bug in AI-generated Supermemory integrations. - -STEP 1: ASK ME THESE QUESTIONS - -1. What are you building? - - Personal chatbot/assistant - - Team knowledge base - - Customer support bot - - Document Q&A - - Other - -2. How do you want to integrate? - - Vercel AI SDK (@supermemory/tools) - - OpenAI plugins - - Direct SDK (supermemory npm/pip) - - Direct API calls - -3. Data model? - - Individual users only → containerTag: userId - - Organizations only → containerTag: orgId - - Both users AND orgs → ask for strategy - -4. Do you want USER PROFILES? - User profiles are automatically-maintained facts about users (what they like, what they're working on, preferences). - - Yes (RECOMMENDED) → Use client.profile() to get context - - No → Just use search - -5. How should I retrieve context? - - OPTION A: One call with search included → profile({ containerTag, q: userMessage }) - - OPTION B: Separate calls → profile() for facts, search() for memories - -STEP 2: INSTALL - -# Get API key: https://console.supermemory.ai -npm install supermemory # or: pip install supermemory -# For Vercel AI SDK: npm install @supermemory/tools -export SUPERMEMORY_API_KEY="sm_..." - - -STEP 3: CONFIGURE SETTINGS (DO THIS FIRST) - -```typescript -// PATCH https://api.supermemory.ai/v3/settings -fetch('https://api.supermemory.ai/v3/settings', { - method: 'PATCH', - headers: { - 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - shouldLLMFilter: true, - filterPrompt: `This is a [your app description]. containerTag is [userId/orgId]. We store [what data].` - }) -}) -``` - -STEP 4: CONTAINER TAG STRATEGY - -Based on their data model answer: - -USER-ONLY APP: -```typescript -containerTag: userId // Each user's memories are isolated -``` - -ORG-ONLY APP: -```typescript -containerTag: orgId // Org members share memories -``` - -BOTH (ask which): -- Option A: `containerTag: \`\${userId}-\${orgId}\`` -- Option B: `containerTag: orgId, metadata: { userId }` -- Option C: `containerTag: userId, metadata: { orgId }` - -STEP 5: INTEGRATION CODE - -Based on their integration choice: - ---- VERCEL AI SDK --- - -```typescript -import { streamText } from 'ai' -import { anthropic } from '@ai-sdk/anthropic' -import { supermemoryTools } from '@supermemory/tools/ai-sdk' - -// Option 1: Agent tools (recommended for agentic flows) -const result = await streamText({ - model: anthropic('claude-3-5-sonnet-20241022'), - prompt: userMessage, - tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY, { - containerTag: userId // singular string — never an array - }) -}) -// Agent gets searchMemories, addMemory, fetchMemory tools - -// Option 2: Profile middleware (automatic context injection) -import { withSupermemory } from '@supermemory/tools/ai-sdk' -const modelWithMemory = withSupermemory(anthropic('claude-3-5-sonnet-20241022'), { - containerTag: userId, - customId: 'conversation-1', -}) - -const result = await generateText({ - model: modelWithMemory, - messages: [{ role: 'user', content: userMessage }] -}) -// Profile is automatically injected into context -``` - - ---- DIRECT SDK (WITH PROFILES) --- - -```typescript -import Supermemory from 'supermemory' - -const client = new Supermemory() - -// Before each LLM call: -const { profile, searchResults } = await client.profile({ - containerTag: userId, - q: userMessage // Include this if they chose OPTION A (one call) - // Omit if they chose OPTION B (separate calls) -}) - -// Build context -const context = ` -Static facts: ${profile.static.join('\n')} -Recent context: ${profile.dynamic.join('\n')} -${searchResults ? `Memories: ${searchResults.results.map(r => r.memory).join('\n')}` : ''} -` - -// Send to LLM -const messages = [ - { role: 'system', content: `User context:\n${context}` }, - { role: 'user', content: userMessage } -] - -// After LLM responds: -await client.add({ - content: `user: ${userMessage}\nassistant: ${response}`, - containerTag: userId -}) -``` - ---- DIRECT SDK (NO PROFILES) --- - -```typescript -import Supermemory from 'supermemory' - -const client = new Supermemory() - -// Search for relevant memories -const results = await client.search({ - q: userMessage, - containerTag: userId, - searchMode: 'hybrid', // Searches memories + document chunks - limit: 5 -}) - -// Build context -const context = results.results.map(r => r.memory || r.chunk).join('\n') - -// Send to LLM with context -const messages = [ - { role: 'system', content: `Relevant context:\n${context}` }, - { role: 'user', content: userMessage } -] - -// Store the conversation -await client.add({ - content: `user: ${userMessage}\nassistant: ${response}`, - containerTag: userId -}) -``` - ---- PYTHON VERSION --- - -```python -from supermemory import Supermemory - -client = Supermemory() - -# With profiles (if they want it) -profile_data = client.profile( - container_tag=user_id, - q=user_message # Include if OPTION A, omit if OPTION B -) - -context = f""" -Static: {chr(10).join(profile_data.profile.static)} -Dynamic: {chr(10).join(profile_data.profile.dynamic)} -""" - -# Store conversation -client.add(content=f"user: {user_message}\\nassistant: {response}", container_tag=user_id) -``` - ---- DIRECT API --- - -```bash -# Add memory -curl -X POST https://api.supermemory.ai/v3/documents \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "conversation", "containerTag": "userId"}' - -# Get profile -curl -X POST https://api.supermemory.ai/v4/profile \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"containerTag": "userId", "q": "search query"}' - -# Search -curl -X POST https://api.supermemory.ai/v4/search \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"q": "query", "containerTag": "userId", "searchMode": "hybrid"}' -``` - -STEP 6: FILE UPLOADS (if they need it) - -```typescript -// Files are automatically extracted (PDFs, images with OCR, videos with transcription) -const formData = new FormData() -formData.append('file', fileBlob) -formData.append('containerTag', userId) - -await fetch('https://api.supermemory.ai/v3/documents/file', { - method: 'POST', - headers: { 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}` }, - body: formData -}) - -// Processing is async - check status before assuming searchable -// GET /v3/documents/{documentId} -``` - -STEP 7: SEARCH MODES - -```typescript -// HYBRID (recommended) - searches memories + document chunks -searchMode: 'hybrid' - -// MEMORIES ONLY - just extracted memories, no original text -searchMode: 'memories' -``` - -STEP 8: METADATA FILTERS (if they need secondary filtering) - -```typescript -// Always against /v4/search — rerank/rewriteQuery/filters are v4-only -await client.search.memories({ - q: query, - containerTag: userId, - filters: { - AND: [ - { key: 'type', value: 'conversation', type: 'string_equal' }, - { key: 'timestamp', value: '2024', type: 'string_contains' } - ] - } -}) -``` - -KEY POINTS: - -1. Configure settings FIRST with filterPrompt -2. User profiles = automatic facts about users (profile.static + profile.dynamic) -3. profile({ containerTag, q }) combines profile + search in ONE call -4. Search modes: 'hybrid' (recommended) or 'memories' -5. File extraction is automatic - no config needed -6. Store conversations after each interaction -7. containerTag should match what you put in filterPrompt - -TESTING: - -```bash -# 1. Configure settings -curl -X PATCH https://api.supermemory.ai/v3/settings \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"shouldLLMFilter": true, "filterPrompt": "..."}' - -# 2. Add test memory -curl -X POST https://api.supermemory.ai/v3/documents \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"content": "Test", "containerTag": "test_user"}' - -# 3. Get profile -curl -X POST https://api.supermemory.ai/v4/profile \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"containerTag": "test_user"}' -``` - - -NOW: -1. Ask me the 5 questions above -2. Generate complete working code based on my answers -3. Include installation, settings config, and full integration - -DOCS: https://supermemory.ai/docs -```` - - - - ---- - -## Claude Code Skill - -Interactive setup for Claude Code users. - -### Install - -```bash -# 1. Clone repo -git clone https://github.com/supermemoryai/supermemory.git - -# 2. Copy skill -mkdir -p ~/.claude/skills -cp supermemory/.claude/skills/supermemory-integrate.md ~/.claude/skills/ - -# 3. Restart Claude Code -``` - -### Use - -```bash -/supermemory-integrate -``` - -The skill asks questions interactively and generates code for your specific setup. - ---- - -## Next Steps - - - - Manual integration guide - - - - Deep dive into profiles - - - - Search modes and parameters - - - - Complete API docs - - diff --git a/apps/docs/zapier.mdx b/apps/docs/zapier.mdx deleted file mode 100644 index d7398ab4..00000000 --- a/apps/docs/zapier.mdx +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: "Integrate supermemory in your Zapier workflows" -sidebarTitle: "Zapier" -description: "Learn how to use the code block to integrate supermemory with Zapier and add memory to your automations." ---- - -With Supermemory you can now easily add memory to your Zapier workflow steps. Here's how: - -## Prerequisites -- A Supermemory API Key. Get yours [here](https://console.supermemory.ai) - -## Step-by-step tutorial - -For this tutorial, we're building a simple flow that adds incoming emails in Gmail to Supermemory. - - - - Open your Zapier account and click on 'Zap' to make a new automation. - ![make a zap - annotated](/images/make-zap.png) - - - Add a new Gmail node that gets triggered on every new email. Connect to your Google account. - ![add gmail](/images/add-gmail-node-zapier.png) - - - Now, add a new 'Code by Zapier' block. Set it up to run Python. - - In the **Input Data** section, map the content field to the Gmail raw snippet. - - ![](/images/map-content-to-gmail.png) - - - Since we're ingesting data here, we'll use the add documents endpoint. - - Add the following code block: - - ```python - import requests - - url = "https://api.supermemory.ai/v3/documents" - - payload = { "content": inputData['content'], "containerTag": "gmail" } - headers = { - "Authorization": "Bearer YOUR_SM_API_KEY", - "Content-Type": "application/json" - } - - response = requests.post(url, json=payload, headers=headers) - - print(response.json()) - ``` - - The `inputData['content']` field maps to the Gmail content fetched from Zapier. - - ![](/images/zapier-output.png) - - - - - Sometimes Zapier might show an error on the first test run. It usually works right after. Weird bug, we know. - - - -You can perform other operations like search, filtering, user profiles, etc., by using other Supermemory API endpoints which can be found in our API Reference tab. \ No newline at end of file diff --git a/apps/mcp/README.md b/apps/mcp/README.md index ad396af9..934ada87 100644 --- a/apps/mcp/README.md +++ b/apps/mcp/README.md @@ -12,17 +12,13 @@ A standalone MCP (Model Context Protocol) server for Supermemory that gives AI a ## Setup -### Quick Install (Recommended) +### Server URL -```bash -npx -y install-mcp@latest https://mcp.supermemory.ai/mcp --client claude --oauth=yes +```text +https://mcp.supermemory.ai/mcp ``` -Replace `claude` with your MCP client: `claude`, `cursor`, `windsurf`, etc. - -### Manual Configuration - -Add to your MCP client config (Claude Desktop, Cursor, Windsurf, etc.): +Add to your MCP client config (Claude, Cursor, Windsurf, VS Code, etc.): ```json { diff --git a/apps/web/components/connect-ai-modal.tsx b/apps/web/components/connect-ai-modal.tsx index f4da2de1..c4b85e7a 100644 --- a/apps/web/components/connect-ai-modal.tsx +++ b/apps/web/components/connect-ai-modal.tsx @@ -293,18 +293,34 @@ export function ConnectAIModal({ createMcpApiKeyMutation.mutate, ]) - function generateInstallCommand() { - if (!selectedClient || selectedClient === "chatgpt") return "" + function getMcpServerUrl() { + return "https://mcp.supermemory.ai/mcp" + } - let command = `npx -y install-mcp@latest https://mcp.supermemory.ai/mcp --client ${selectedClient} --oauth=yes` - - if (selectedProject && selectedProject !== "none") { - // Remove the "sm_project_" prefix from the containerTag - const projectIdForCommand = selectedProject.replace(/^sm_project_/, "") - command += ` --project ${projectIdForCommand}` + function getMcpConfigSnippet() { + const config: { + mcpServers: { + supermemory: { + url: string + headers?: { "x-sm-project": string } + } + } + } = { + mcpServers: { + supermemory: { + url: getMcpServerUrl(), + }, + }, } - - return command + if (selectedProject && selectedProject !== "none") { + const projectIdForCommand = selectedProject.replace(/^sm_project_/, "") + if (projectIdForCommand) { + config.mcpServers.supermemory.headers = { + "x-sm-project": projectIdForCommand, + } + } + } + return JSON.stringify(config, null, 2) } function getCursorDeeplink() { @@ -312,8 +328,13 @@ export function ConnectAIModal({ } const copyToClipboard = () => { - const command = generateInstallCommand() - navigator.clipboard.writeText(command) + navigator.clipboard.writeText(getMcpServerUrl()) + analytics.mcpInstallCmdCopied() + toast.success("Copied to clipboard!") + } + + const copyConfigSnippet = () => { + navigator.clipboard.writeText(getMcpConfigSnippet()) analytics.mcpInstallCmdCopied() toast.success("Copied to clipboard!") } @@ -553,8 +574,8 @@ export function ConnectAIModal({ selectedClient !== "mcp-url" && (

- Optional: scope installs to a project. Then copy and - run the command in your terminal. + Add this remote MCP server URL in your client. + Optional: scope to a project for the config snippet.