diff --git a/apps/docs/add-memories.mdx b/apps/docs/add-memories.mdx new file mode 100644 index 00000000..f10f51a1 --- /dev/null +++ b/apps/docs/add-memories.mdx @@ -0,0 +1,373 @@ +--- +title: "Ingesting context to supermemory" +sidebarTitle: "Add context" +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. + + +## Quick Start + + + + ```typescript + import Supermemory from 'supermemory'; + + const client = new Supermemory(); + + // Add text content + await client.add({ + content: "Machine learning enables computers to learn from data", + containerTag: "user_123", + metadata: { category: "ai" } + }); + + // Add a URL (auto-extracted) + await client.add({ + content: "https://youtube.com/watch?v=dQw4w9WgXcQ", + containerTag: "user_123" + }); + ``` + + + ```python + from supermemory import Supermemory + + client = Supermemory() + + # Add text content + client.add( + content="Machine learning enables computers to learn from data", + container_tag="user_123", + metadata={"category": "ai"} + ) + + # Add a URL (auto-extracted) + client.add( + content="https://youtube.com/watch?v=dQw4w9WgXcQ", + container_tag="user_123" + ) + ``` + + + ```bash + 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": "user_123", + "metadata": {"category": "ai"} + }' + ``` + + + +**Response:** +```json +{ "id": "abc123", "status": "queued" } +``` + +--- + +## Updating Content + +Use `customId` to update existing documents or conversations. When you send content with the same `customId`, Supermemory intelligently processes only what's new. + +### Two ways to update: + +**Option 1: Send only the new content** +```typescript +// First request +await client.add({ + content: "user: Hi, I'm Sarah.\nassistant: Nice to meet you!", + customId: "conv_123", + containerTag: "user_sarah" +}); + +// Later: send only new messages +await client.add({ + content: "user: What's the weather?\nassistant: It's sunny today.", + customId: "conv_123", // Same ID — Supermemory links them + containerTag: "user_sarah" +}); +``` + +**Option 2: Send the full updated content** +```typescript +// Supermemory detects the diff and only processes new parts +await client.add({ + content: "user: Hi, I'm Sarah.\nassistant: Nice to meet you!\nuser: What's the weather?\nassistant: It's sunny today.", + customId: "conv_123", + containerTag: "user_sarah" +}); +``` + +Both work — choose what fits your architecture. + +### Replace entire document + +To completely replace a document's content (not append), use `memories.update()`: + +```typescript +// Replace the entire document content +await client.memories.update("doc_id_123", { + content: "Completely new content replacing everything", + metadata: { version: 2 } +}); +``` + +This triggers full reprocessing of the document. + +### Formatting conversations + +Format your conversations however you want. Supermemory handles any string format: + +```typescript +// Simple string +content: "user: Hello\nassistant: Hi there!" + +// JSON stringify +content: JSON.stringify(messages) + +// Template literal +content: messages.map(m => `${m.role}: ${m.content}`).join('\n') + +// Any format — just make it a string +content: formatConversation(messages) +``` + +--- + +## Upload Files + +Upload PDFs, images, and documents directly. + + + + ```typescript + import fs from 'fs'; + + await client.memories.uploadFile({ + file: fs.createReadStream('document.pdf'), + containerTags: 'user_123' + }); + ``` + + + ```python + with open('document.pdf', 'rb') as file: + client.memories.upload_file( + file=file, + container_tags='user_123' + ) + ``` + + + ```bash + curl -X POST "https://api.supermemory.ai/v3/documents/file" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -F "file=@document.pdf" \ + -F "containerTags=user_123" + ``` + + + +### Supported File Types + +| Type | Formats | Processing | +|------|---------|------------| +| Documents | PDF, DOC, DOCX, TXT, MD | Text extraction, OCR for scans | +| Images | JPG, PNG, GIF, WebP | OCR text extraction | +| Spreadsheets | CSV, Google Sheets | Structured data extraction | +| Videos | YouTube URLs, MP4 | Auto-transcription | + +**Limits:** 50MB max file size + +--- + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `content` | string | **Required.** Any raw content — text, conversations, URLs, HTML | +| `customId` | string | **Recommended.** Your ID for the content (conversation ID, doc ID). Enables updates and deduplication | +| `containerTag` | string | Group by user/project. Required for user profiles | +| `metadata` | object | Key-value pairs for filtering (strings, numbers, booleans) | + + + + **Content Types:** + ```typescript + // Any text — conversations, notes, documents + { content: "Meeting notes from today's standup" } + { content: JSON.stringify(messages) } + + // URLs (auto-detected and extracted) + { content: "https://example.com/article" } + { content: "https://youtube.com/watch?v=abc123" } + + // Markdown, HTML, or any format + { content: "# Project Docs\n\n## Features\n- Real-time sync" } + ``` + + **Container Tags:** + ```typescript + // By user + { containerTag: "user_123" } + + // By project + { containerTag: "project_alpha" } + + // Hierarchical + { containerTag: "org_456_team_backend" } + ``` + + **Custom IDs (Recommended):** + ```typescript + // Use IDs from your system + { customId: "conv_abc123" } // Conversation ID + { customId: "doc_456" } // Document ID + { customId: "thread_789" } // Thread ID + { customId: "meeting_2024_01_15" } // Meeting ID + + // Updates: same customId = same document + // Supermemory only processes new/changed content + await client.add({ + content: "Updated content...", + customId: "doc_456" // Links to existing document + }); + ``` + + **Metadata:** + ```typescript + { + metadata: { + source: "slack", + author: "john", + priority: 1, + reviewed: true + } + } + ``` + - No nested objects or arrays + - Values: string, number, or boolean only + + + +--- + +## Processing Pipeline + +When you add content, Supermemory: + +1. **Validates** your request +2. **Stores** the document and queues for processing +3. **Extracts** content (OCR, transcription, web scraping) +4. **Chunks** into searchable memories +5. **Embeds** for vector search +6. **Indexes** for retrieval + +Track progress with `GET /v3/documents/{id}`: +```typescript +const doc = await client.memories.get("abc123"); +console.log(doc.status); // "queued" | "processing" | "done" +``` + + + + Process multiple documents with rate limiting: + + ```typescript + async function batchUpload(documents: Array<{id: string, content: string}>) { + const results = []; + + for (const doc of documents) { + try { + const result = await client.add({ + content: doc.content, + customId: doc.id, + containerTag: "batch_import" + }); + results.push({ id: doc.id, success: true, docId: result.id }); + } catch (error) { + results.push({ id: doc.id, success: false, error }); + } + + // Rate limit: 1 second between requests + await new Promise(r => setTimeout(r, 1000)); + } + + return results; + } + ``` + + **Tips:** + - Batch size: 3-5 documents at once + - Delay: 1-2 seconds between requests + - Use `customId` to track and deduplicate + + + + | Status | Error | Cause | + |--------|-------|-------| + | 400 | BadRequestError | Missing required fields, invalid parameters | + | 401 | AuthenticationError | Invalid or missing API key | + | 403 | PermissionDeniedError | Insufficient permissions | + | 429 | RateLimitError | Too many requests or quota exceeded | + | 500 | InternalServerError | Processing failure | + + ```typescript + import { BadRequestError, RateLimitError } from 'supermemory'; + + try { + await client.add({ content: "..." }); + } catch (error) { + if (error instanceof RateLimitError) { + // Wait and retry + await new Promise(r => setTimeout(r, 60000)); + } else if (error instanceof BadRequestError) { + // Fix request parameters + console.error("Invalid request:", error.message); + } + } + ``` + + + + **Single delete:** + ```typescript + await client.memories.delete("doc_id_123"); + ``` + + **Bulk delete by IDs:** + ```typescript + await client.memories.bulkDelete({ + ids: ["doc_1", "doc_2", "doc_3"] + }); + ``` + + **Bulk delete by container tag:** + ```typescript + // Delete all content for a user + await client.memories.bulkDelete({ + containerTags: ["user_123"] + }); + ``` + + Deletes are permanent — no recovery. + + + +--- + +## Next Steps + +- [Search Memories](/search) — Query your content +- [User Profiles](/user-profiles) — Get user context +- [Organizing & Filtering](/concepts/filtering) — Container tags and metadata diff --git a/apps/docs/add-memories/examples/basic.mdx b/apps/docs/add-memories/examples/basic.mdx index e87893fc..02cac11e 100644 --- a/apps/docs/add-memories/examples/basic.mdx +++ b/apps/docs/add-memories/examples/basic.mdx @@ -12,7 +12,7 @@ The most basic operation - adding plain text content. ```typescript TypeScript -const response = await client.memories.add({ +const response = await client.add({ content: "Artificial intelligence is transforming how we work and live" }); @@ -21,7 +21,7 @@ console.log(response); ``` ```python Python -response = client.memories.add( +response = client.add( content="Artificial intelligence is transforming how we work and live" ) @@ -47,7 +47,7 @@ Group related content using container tags. ```typescript TypeScript -const response = await client.memories.add({ +const response = await client.add({ content: "Q4 2024 revenue exceeded projections by 15%", containerTag: "financial_reports" }); @@ -57,7 +57,7 @@ console.log(response.id); ``` ```python Python -response = client.memories.add( +response = client.add( content="Q4 2024 revenue exceeded projections by 15%", container_tag="financial_reports" ) @@ -87,7 +87,7 @@ Attach metadata for better search and filtering. ```typescript TypeScript -await client.memories.add({ +await client.add({ content: "New onboarding flow reduces drop-off by 30%", containerTag: "product_updates", metadata: { @@ -98,7 +98,7 @@ await client.memories.add({ ``` ```python Python -client.memories.add( +client.add( content="New onboarding flow reduces drop-off by 30%", container_tag="product_updates", metadata={ @@ -136,7 +136,7 @@ const notes = [ const results = await Promise.all( notes.map(note => - client.memories.add({ + client.add({ content: note, containerTag: "meeting_2024_01_15" }) @@ -152,7 +152,7 @@ notes = [ ] for note in notes: - client.memories.add( + client.add( content=note, container_tag="meeting_2024_01_15" ) @@ -176,19 +176,19 @@ Process web pages, YouTube videos, and other URLs automatically. ```typescript TypeScript // Web page -await client.memories.add({ +await client.add({ content: "https://example.com/article", containerTag: "articles" }); // YouTube video (auto-transcribed) -await client.memories.add({ +await client.add({ content: "https://youtube.com/watch?v=dQw4w9WgXcQ", containerTag: "videos" }); // Google Docs -await client.memories.add({ +await client.add({ content: "https://docs.google.com/document/d/abc123/edit", containerTag: "docs" }); @@ -196,19 +196,19 @@ await client.memories.add({ ```python Python # Web page -client.memories.add( +client.add( content="https://example.com/article", container_tag="articles" ) # YouTube video (auto-transcribed) -client.memories.add( +client.add( content="https://youtube.com/watch?v=dQw4w9WgXcQ", container_tag="videos" ) # Google Docs -client.memories.add( +client.add( content="https://docs.google.com/document/d/abc123/edit", container_tag="docs" ) @@ -246,7 +246,7 @@ const markdown = ` - **Enterprise security** `; -await client.memories.add({ +await client.add({ content: markdown, containerTag: "docs" }); @@ -262,7 +262,7 @@ markdown = """ - **Enterprise security** """ -client.memories.add( +client.add( content=markdown, container_tag="docs" ) diff --git a/apps/docs/add-memories/overview.mdx b/apps/docs/add-memories/overview.mdx index 28778b0e..95031f30 100644 --- a/apps/docs/add-memories/overview.mdx +++ b/apps/docs/add-memories/overview.mdx @@ -53,7 +53,7 @@ client = Supermemory( ```typescript TypeScript // Add text content -const result = await client.memories.add({ +const result = await client.add({ content: "Machine learning enables computers to learn from data", containerTag: "ai-research", metadata: { priority: "high" } @@ -65,7 +65,7 @@ console.log(result); ```python Python # Add text content -result = client.memories.add( +result = client.add( content="Machine learning enables computers to learn from data", container_tags=["ai-research"], metadata={"priority": "high"} @@ -125,14 +125,14 @@ Add text content, URLs, or any supported format. ```typescript TypeScript -await client.memories.add({ +await client.add({ content: "Your content here", containerTag: "project" }); ``` ```python Python -client.memories.add( +client.add( content="Your content here", container_tags=["project"] ) @@ -245,7 +245,5 @@ curl -X PATCH "https://api.supermemory.ai/v3/documents/doc_id" \ ## Next Steps -- [Track Processing Status](/memory-api/track-progress) - Monitor document processing -- [Search Memories](/search/overview) - Search your content -- [List Memories](/list-memories/overview) - Browse stored memories -- [Update & Delete](/update-delete-memories/overview) - Manage memories +- [Memory Operations](/memory-operations) - Track status, list, update, and delete memories +- [Search Memories](/search) - Search your content diff --git a/apps/docs/ai-sdk/examples.mdx b/apps/docs/ai-sdk/examples.mdx index 61ad8d50..9eabbae9 100644 --- a/apps/docs/ai-sdk/examples.mdx +++ b/apps/docs/ai-sdk/examples.mdx @@ -4,7 +4,7 @@ description: "Complete examples showing how to use Supermemory with Vercel AI SD sidebarTitle: "Examples" --- -This page provides comprehensive examples of using Supermemory with the Vercel AI SDK, covering both Memory Tools and Infinite Chat approaches. +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 @@ -114,62 +114,6 @@ export async function POST(request: Request) { } ``` -## Infinite Chat for Documentation - -Create a documentation assistant with unlimited context: - - - -```typescript Documentation Chat -import { streamText } from 'ai' - -const supermemoryInfiniteChat = 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' - } -}) - -export async function POST(request: Request) { - const { messages } = await request.json() - - const result = await streamText({ - model: supermemoryInfiniteChat('gpt-5'), - messages, - system: `You are a documentation assistant. You have access to all previous - conversations and can reference earlier discussions. Help users understand - the documentation by building on previous context.` - }) - - return result.toAIStreamResponse() -} -``` - -```typescript Upload Documentation -// Separate endpoint to upload documentation to memory -import { addMemory } from '@supermemory/tools' - -export async function POST(request: Request) { - const { content, title, url } = await request.json() - - const memory = await addMemory({ - apiKey: process.env.SUPERMEMORY_API_KEY!, - content, - title, - url, - headers: { - 'x-sm-conversation-id': 'documentation' - } - }) - - return Response.json({ success: true, memory }) -} -``` - - - ## Multi-User Learning Assistant Build an assistant that learns from multiple users but keeps data separate: @@ -394,12 +338,6 @@ ANTHROPIC_API_KEY=your_anthropic_key - Use project headers to separate different use cases - Implement error handling for tool failures -### Infinite Chat -- Use conversation IDs to maintain separate chat contexts -- Include user IDs for personalized experiences -- Test with different providers to find the best fit for your use case -- Monitor token usage for cost optimization - ### General Tips - Start with simple examples and gradually add complexity - Use the search functionality to avoid duplicate memories @@ -413,7 +351,7 @@ ANTHROPIC_API_KEY=your_anthropic_key Advanced memory management with full API control - - Drop-in proxy for existing LLM applications + + Automatic personalization with user profiles diff --git a/apps/docs/ai-sdk/infinite-chat.mdx b/apps/docs/ai-sdk/infinite-chat.mdx index c382bcbf..4d67a86d 100644 --- a/apps/docs/ai-sdk/infinite-chat.mdx +++ b/apps/docs/ai-sdk/infinite-chat.mdx @@ -206,7 +206,7 @@ const infiniteChat = createOpenAI({ ## Next Steps - + Explore explicit memory control diff --git a/apps/docs/ai-sdk/memory-tools.mdx b/apps/docs/ai-sdk/memory-tools.mdx index cc84097f..f48d04f7 100644 --- a/apps/docs/ai-sdk/memory-tools.mdx +++ b/apps/docs/ai-sdk/memory-tools.mdx @@ -137,8 +137,8 @@ Each tool returns a result object: ## Next Steps - - Try automatic memory management + + Automatic personalization with profiles diff --git a/apps/docs/ai-sdk/overview.mdx b/apps/docs/ai-sdk/overview.mdx index 07d70e29..0c9a48f4 100644 --- a/apps/docs/ai-sdk/overview.mdx +++ b/apps/docs/ai-sdk/overview.mdx @@ -4,7 +4,7 @@ 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 three approaches: **User Profiles** for automatic personalization, **Memory Tools** for agent-based interactions, and **Infinite Chat** for automatic context management. +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 @@ -68,50 +68,21 @@ const result = await streamText({ }) ``` -## Infinite Chat - -Automatic memory management for chat applications with unlimited context. - -```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: "What's my name?" } - ] -}) -``` - ## When to Use | Approach | Use Case | |----------|----------| | User Profiles | Personalized LLM responses with automatic user context | | Memory Tools | AI agents that need explicit memory control | -| Infinite Chat | Chat applications with automatic context | ## Next Steps - - + + Automatic personalization with profiles - + Agent-based memory management - - - Automatic context management - diff --git a/apps/docs/ai-sdk/user-profiles.mdx b/apps/docs/ai-sdk/user-profiles.mdx index fcfe4d7a..3afc41e0 100644 --- a/apps/docs/ai-sdk/user-profiles.mdx +++ b/apps/docs/ai-sdk/user-profiles.mdx @@ -289,7 +289,7 @@ The AI SDK middleware abstracts away the complexity of manual profile management Understand how profiles work conceptually - + Add explicit memory operations to your agents diff --git a/apps/docs/concepts/content-types.mdx b/apps/docs/concepts/content-types.mdx new file mode 100644 index 00000000..5776be5c --- /dev/null +++ b/apps/docs/concepts/content-types.mdx @@ -0,0 +1,214 @@ +--- +title: "Supported Content Types" +sidebarTitle: "Content Types" +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. + +## Text Content + +Raw text, conversations, notes, or any string content. + +```typescript +await client.add({ + content: "User prefers dark mode and uses vim keybindings", + containerTags: ["user_123"] +}); +``` + +**Best for:** Chat messages, user preferences, notes, logs, transcripts. + +--- + +## URLs & Web Pages + +Send a URL and Supermemory fetches, extracts, and indexes the content. + +```typescript +await client.add({ + content: "https://docs.example.com/api-reference", + containerTags: ["documentation"] +}); +``` + +**Extracts:** Article text, headings, metadata. Strips navigation, ads, boilerplate. + +--- + +## Documents + +### PDF + +```typescript +await client.add({ + content: pdfBase64, + contentType: "pdf", + title: "Q4 Financial Report" +}); +``` + +**Extracts:** Text, tables, headers. OCR for scanned documents. + +### Microsoft Office + +| Format | Extension | Content Type | +|--------|-----------|--------------| +| Word | `.docx` | `docx` | +| Excel | `.xlsx` | `xlsx` | +| PowerPoint | `.pptx` | `pptx` | + +```typescript +await client.add({ + content: docxBase64, + contentType: "docx", + title: "Product Roadmap" +}); +``` + +### Google Workspace + +Automatically handled via [Google Drive connector](/connectors/google-drive): +- Google Docs +- Google Sheets +- Google Slides + +--- + +## Code & Markdown + +```typescript +// Markdown +await client.add({ + content: markdownContent, + contentType: "md", + title: "README.md" +}); + +// Code files (auto-detected language) +await client.add({ + content: codeContent, + contentType: "code", + metadata: { language: "typescript" } +}); +``` + +**Extracts:** Structure, headings, code blocks with syntax awareness. + +Code is chunked using [code-chunk](https://github.com/supermemoryai/code-chunk), which understands AST boundaries to keep functions, classes, and logical blocks intact. See [Super RAG](/concepts/super-rag) for how Supermemory optimizes chunking for each content type. + +--- + +## Images + +```typescript +await client.add({ + content: imageBase64, + contentType: "image", + title: "Architecture Diagram" +}); +``` + +**Extracts:** OCR text, visual descriptions, diagram interpretations. + +**Supported:** PNG, JPG, JPEG, WebP, GIF + +--- + +## Audio & Video + +```typescript +// Audio +await client.add({ + content: audioBase64, + contentType: "audio", + title: "Customer Call Recording" +}); + +// Video +await client.add({ + content: videoBase64, + contentType: "video", + title: "Product Demo" +}); +``` + +**Extracts:** Transcription, speaker detection, topic segmentation. + +**Supported:** MP3, WAV, M4A, MP4, WebM + +--- + +## Structured Data + +### JSON + +```typescript +await client.add({ + content: JSON.stringify(userData), + contentType: "json", + title: "User Profile Data" +}); +``` + +### CSV + +```typescript +await client.add({ + content: csvContent, + contentType: "csv", + title: "Sales Data Q4" +}); +``` + +--- + +## File Upload + +For binary files, encode as base64: + +```typescript +import { readFileSync } from 'fs'; + +const file = readFileSync('./document.pdf'); +const base64 = file.toString('base64'); + +await client.add({ + content: base64, + contentType: "pdf", + title: "document.pdf" +}); +``` + +--- + +## Auto-Detection + +If you don't specify `contentType`, Supermemory auto-detects: + +```typescript +// URL detected automatically +await client.add({ content: "https://example.com/page" }); + +// Plain text detected automatically +await client.add({ content: "User said they prefer email contact" }); +``` + + +For binary content (files), always specify `contentType` for reliable processing. + + +--- + +## Content Limits + +| Type | Max Size | +|------|----------| +| Text | 1MB | +| Files | 50MB | +| URLs | Fetched content up to 10MB | + + +For large files, consider chunking or using [connectors](/connectors/overview) for automatic sync. + diff --git a/apps/docs/concepts/customization.mdx b/apps/docs/concepts/customization.mdx new file mode 100644 index 00000000..b84cae6b --- /dev/null +++ b/apps/docs/concepts/customization.mdx @@ -0,0 +1,159 @@ +--- +title: "Customizing for Your Use Case" +sidebarTitle: "Customization" +description: "Configure Supermemory's behavior for your specific application" +icon: "settings-2" +--- + +Configure how Supermemory processes and retrieves content for your specific use case. + +## Filter Prompts + +Tell Supermemory what content matters during ingestion. This helps filter and prioritize what gets indexed. + +```typescript +// Example: Brand guidelines assistant +await client.settings.update({ + shouldLLMFilter: true, + filterPrompt: `You are ingesting content for Brand.ai's brand guidelines system. + + Index: + - Official brand values and mission statements + - Approved tone of voice guidelines + - Logo usage and visual identity docs + - Approved messaging and taglines + + Skip: + - Draft documents and work-in-progress + - Outdated brand materials (pre-2024) + - Internal discussions about brand changes + - Competitor analysis docs` +}); +``` + + + + ```typescript + filterPrompt: `Personal AI assistant. Prioritize recent content, action items, + and personal context. Exclude spam and duplicates.` + ``` + + + ```typescript + filterPrompt: `Customer support agent. Prioritize verified solutions, official docs, + and resolved tickets. Exclude internal discussions and PII.` + ``` + + + ```typescript + filterPrompt: `Legal research assistant. Prioritize precedents, current regulations, + and approved contract language. Exclude privileged communications.` + ``` + + + ```typescript + filterPrompt: `Financial analysis assistant. Prioritize latest reports, verified data, + and regulatory filings. Exclude speculative data and MNPI.` + ``` + + + ```typescript + filterPrompt: `Healthcare information assistant. Prioritize evidence-based guidelines + and FDA-approved info. Exclude PHI and outdated recommendations.` + ``` + + + ```typescript + filterPrompt: `Developer documentation assistant. Prioritize current APIs, working + examples, and best practices. Exclude deprecated APIs and test fixtures.` + ``` + + + +--- + +## Chunk Size + +Control how documents are split into searchable pieces. Smaller chunks = more precise retrieval but less context per result. + +```typescript +await client.settings.update({ + chunkSize: 512 // -1 for default +}); +``` + +| Use Case | Chunk Size | Why | +|----------|------------|-----| +| Citations & references | `256-512` | Precise source attribution | +| Q&A / Support | `512-1024` | Balanced context | +| Long-form analysis | `1024-2048` | More context per chunk | +| Default | `-1` | Supermemory's optimized default | + + +Smaller chunks generate more memories per document. Larger chunks provide more context but may reduce precision. + + +--- + +## Connector Branding + +Show "Log in to **YourApp**" instead of "Log in to Supermemory" when users connect external services. + + + + 1. Create OAuth credentials in [Google Cloud Console](https://console.cloud.google.com/) + 2. Redirect URI: `https://api.supermemory.ai/v3/connections/google-drive/callback` + + ```typescript + await client.settings.update({ + googleDriveCustomKeyEnabled: true, + googleDriveClientId: "your-client-id.apps.googleusercontent.com", + googleDriveClientSecret: "your-client-secret" + }); + ``` + + + 1. Create integration at [Notion Developers](https://developers.notion.com/) + 2. Redirect URI: `https://api.supermemory.ai/v3/connections/notion/callback` + + ```typescript + await client.settings.update({ + notionCustomKeyEnabled: true, + notionClientId: "your-notion-client-id", + notionClientSecret: "your-notion-client-secret" + }); + ``` + + + 1. Register app in [Azure Portal](https://portal.azure.com/) + 2. Redirect URI: `https://api.supermemory.ai/v3/connections/onedrive/callback` + + ```typescript + await client.settings.update({ + onedriveCustomKeyEnabled: true, + onedriveClientId: "your-azure-app-id", + onedriveClientSecret: "your-azure-client-secret" + }); + ``` + + + +--- + +## API Reference + +```typescript +// Get current settings +const settings = await client.settings.get(); + +// Update settings +await client.settings.update({ + shouldLLMFilter: true, + filterPrompt: "...", + chunkSize: 512 +}); +``` + + +Settings are organization-wide. Changes apply to new content only—existing memories aren't reprocessed. + diff --git a/apps/docs/concepts/filtering.mdx b/apps/docs/concepts/filtering.mdx new file mode 100644 index 00000000..162f9b09 --- /dev/null +++ b/apps/docs/concepts/filtering.mdx @@ -0,0 +1,346 @@ +--- +title: "Organizing & Filtering Memories" +sidebarTitle: "Multi-Tenancy / Filtering" +description: "Use container tags and metadata to organize and retrieve memories" +icon: "users" +--- + +Supermemory provides two ways to organize your memories: + + + + **Organize memories** into isolated spaces by user, project, or workspace + + + **Query memories** by custom properties like category, status, or date + + + +Both can be used independently or together for precise filtering. + +--- + +## Container Tags + +Container tags create isolated memory spaces. Use them to separate memories by user, project, or any logical boundary. + +### Adding Memories with Tags + +```typescript +await client.add({ + content: "Meeting notes from Q1 planning", + containerTags: ["user_123"] +}); +``` + +### Searching with Tags + +```typescript +const results = await client.search.documents({ + q: "planning notes", + containerTags: ["user_123"] +}); +``` + + +Container tags use **exact array matching**. A memory tagged `["user_123", "project_a"]` won't match a search for just `["user_123"]`. + + +### Recommended Patterns + +| Pattern | Example | Use Case | +|---------|---------|----------| +| User isolation | `user_{userId}` | Per-user memories | +| Project grouping | `project_{projectId}` | Project-specific content | +| Hierarchical | `org_{orgId}_team_{teamId}` | Multi-level organization | + + + + ```typescript + // Multi-tenant SaaS - isolate by organization and user + await client.add({ + content: "Company policy document", + containerTags: ["org_acme_user_john"] + }); + + // Search only within that user's org context + const results = await client.search.documents({ + q: "vacation policy", + containerTags: ["org_acme_user_john"] + }); + + // Project-based isolation + await client.add({ + content: "Sprint 5 retrospective notes", + containerTags: ["project_mobile_app"] + }); + + // Time-based segmentation + await client.add({ + content: "Q1 2024 financial report", + containerTags: ["user_cfo_2024_q1"] + }); + ``` + + **API field differences:** + | Endpoint | Field | Type | + |----------|-------|------| + | `/v3/search` | `containerTags` | Array | + | `/v4/search` | `containerTag` | String | + | `/v3/documents/list` | `containerTags` | Array | + + + +--- + +## Metadata + +Metadata lets you attach custom properties to memories and filter by them later. + +### Adding Memories with Metadata + +```typescript +await client.add({ + content: "Technical design document for auth system", + containerTags: ["user_123"], + metadata: { + category: "engineering", + priority: "high", + year: 2024 + } +}); +``` + +### Searching with Metadata Filters + +Filters must be wrapped in `AND` or `OR` arrays: + +```typescript +const results = await client.search.documents({ + q: "design document", + containerTags: ["user_123"], + filters: { + AND: [ + { key: "category", value: "engineering" }, + { key: "priority", value: "high" } + ] + } +}); +``` + +### Filter Types + +| Type | Example | Description | +|------|---------|-------------| +| String equality | `{ key: "status", value: "published" }` | Exact match | +| String contains | `{ filterType: "string_contains", key: "title", value: "react" }` | Substring match | +| Numeric | `{ filterType: "numeric", key: "priority", value: "5", numericOperator: ">=" }` | Number comparison | +| Array contains | `{ filterType: "array_contains", key: "tags", value: "important" }` | Check array membership | + +### Combining Filters + +Use `AND` and `OR` for complex queries: + +```typescript +const results = await client.search.documents({ + q: "meeting notes", + filters: { + AND: [ + { key: "type", value: "meeting" }, + { + OR: [ + { key: "team", value: "engineering" }, + { key: "team", value: "product" } + ] + } + ] + } +}); +``` + +### Excluding Results + +Use `negate: true` to exclude matches: + +```typescript +const results = await client.search.documents({ + q: "documentation", + filters: { + AND: [ + { key: "status", value: "draft", negate: true } + ] + } +}); +``` + + + + **String contains (substring search):** + ```typescript + // Find documents with "machine learning" in the description + const results = await client.search.documents({ + q: "AI research", + filters: { + AND: [ + { + filterType: "string_contains", + key: "description", + value: "machine learning", + ignoreCase: true + } + ] + } + }); + ``` + + **Numeric comparisons:** + ```typescript + // Find high-priority items created after a specific date + const results = await client.search.documents({ + q: "tasks", + filters: { + AND: [ + { + filterType: "numeric", + key: "priority", + value: "7", + numericOperator: ">=" + }, + { + filterType: "numeric", + key: "created_timestamp", + value: "1704067200", // Unix timestamp + numericOperator: ">=" + } + ] + } + }); + ``` + + **Array contains (check array membership):** + ```typescript + // Find documents where a specific user is a participant + const results = await client.search.documents({ + q: "meeting notes", + filters: { + AND: [ + { + filterType: "array_contains", + key: "participants", + value: "alice@company.com" + } + ] + } + }); + ``` + + **Complex nested filters:** + ```typescript + // (category = "tech" OR category = "science") AND status != "archived" + const results = await client.search.documents({ + q: "research papers", + filters: { + AND: [ + { + OR: [ + { key: "category", value: "tech" }, + { key: "category", value: "science" } + ] + }, + { key: "status", value: "archived", negate: true } + ] + } + }); + ``` + + **Numeric operator negation mapping:** + When using `negate: true`, operators flip: + - `<` becomes `>=` + - `<=` becomes `>` + - `>` becomes `<=` + - `>=` becomes `<` + - `=` becomes `!=` + + + + **User's work documents from 2024:** + ```typescript + const results = await client.search.documents({ + q: "quarterly report", + containerTags: ["user_123"], + filters: { + AND: [ + { key: "category", value: "work" }, + { key: "type", value: "report" }, + { filterType: "numeric", key: "year", value: "2024", numericOperator: "=" } + ] + } + }); + ``` + + **Team meeting notes with specific participants:** + ```typescript + const results = await client.search.documents({ + q: "sprint planning", + containerTags: ["project_alpha"], + filters: { + AND: [ + { key: "type", value: "meeting" }, + { + OR: [ + { filterType: "array_contains", key: "participants", value: "alice" }, + { filterType: "array_contains", key: "participants", value: "bob" } + ] + } + ] + } + }); + ``` + + **Exclude drafts and deprecated content:** + ```typescript + const results = await client.search.documents({ + q: "documentation", + filters: { + AND: [ + { key: "status", value: "draft", negate: true }, + { filterType: "string_contains", key: "content", value: "deprecated", negate: true }, + { filterType: "array_contains", key: "tags", value: "archived", negate: true } + ] + } + }); + ``` + + + +--- + +## Quick Reference + +### When Adding Memories + +```typescript +await client.add({ + content: "Your content here", + containerTags: ["user_123"], // Isolation + metadata: { key: "value" } // Custom properties +}); +``` + +### When Searching + +```typescript +const results = await client.search.documents({ + q: "search query", + containerTags: ["user_123"], // Must match exactly + filters: { // Optional metadata filters + AND: [{ key: "status", value: "published" }] + } +}); +``` + +### Metadata Key Rules + +- Allowed characters: `a-z`, `A-Z`, `0-9`, `_`, `-`, `.` +- Max length: 64 characters +- No spaces or special characters diff --git a/apps/docs/concepts/graph-memory.mdx b/apps/docs/concepts/graph-memory.mdx new file mode 100644 index 00000000..6ac4940f --- /dev/null +++ b/apps/docs/concepts/graph-memory.mdx @@ -0,0 +1,140 @@ +--- +title: "How Graph Memory Works" +sidebarTitle: "Graph Memory" +description: "Automatic memory evolution, knowledge updates, and intelligent 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**. + +## Memory Relationships + +When you add content, Supermemory extracts facts and automatically connects them to existing memories through three relationship types: + +### Updates: Information Changes + +When new information contradicts existing knowledge: + +``` +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: + +```typescript +await client.add({ + content: "Alex mentioned he just started at Stripe" +}); + +const results = await client.search({ + query: "where does Alex work?" +}); +// → Stripe (latest), previously Google (historical) +``` + +--- + +## Learn More + + + + Deep dive into the architecture + + + Automatic summaries from the graph + + diff --git a/apps/docs/how-it-works.mdx b/apps/docs/concepts/how-it-works.mdx similarity index 96% rename from apps/docs/how-it-works.mdx rename to apps/docs/concepts/how-it-works.mdx index 318324b1..1830f7b0 100644 --- a/apps/docs/how-it-works.mdx +++ b/apps/docs/concepts/how-it-works.mdx @@ -1,7 +1,7 @@ --- title: "How Supermemory Works" description: "Understanding the knowledge graph architecture that powers intelligent memory" -icon: "brain" +icon: "cpu" --- @@ -142,11 +142,11 @@ Understanding the pipeline helps you optimize your usage: Now that you understand how Supermemory works: - + Start adding content to your knowledge graph - + Learn to query your knowledge effectively diff --git a/apps/docs/memory-vs-rag.mdx b/apps/docs/concepts/memory-vs-rag.mdx similarity index 99% rename from apps/docs/memory-vs-rag.mdx rename to apps/docs/concepts/memory-vs-rag.mdx index 699b906d..729355b6 100644 --- a/apps/docs/memory-vs-rag.mdx +++ b/apps/docs/concepts/memory-vs-rag.mdx @@ -2,6 +2,7 @@ title: "Memory vs RAG: Understanding the Difference" description: "Learn why agent memory and RAG are fundamentally different, and when to use each approach" sidebarTitle: "Memory vs RAG" +icon: "scale" --- Most developers confuse RAG (Retrieval-Augmented Generation) with agent memory. They're not the same thing, and using RAG for memory is why your agents keep forgetting important context. Let's understand the fundamental difference. @@ -193,7 +194,7 @@ Supermemory provides a unified platform that correctly handles both patterns: ### 1. Document Storage (RAG) ```python # Add a document for RAG-style retrieval -client.memories.add( +client.add( content="iPhone 15 has a 48MP camera and A17 Pro chip", # No user association - universal knowledge ) @@ -202,7 +203,7 @@ client.memories.add( ### 2. Memory Creation ```python # Add a user-specific memory -client.memories.add( +client.add( content="User prefers Android over iOS", container_tags=["user_123"], # User-specific metadata={ diff --git a/apps/docs/concepts/super-rag.mdx b/apps/docs/concepts/super-rag.mdx new file mode 100644 index 00000000..3e2aafc8 --- /dev/null +++ b/apps/docs/concepts/super-rag.mdx @@ -0,0 +1,171 @@ +--- +title: "SuperRAG (Managed RAG as a service)" +sidebarTitle: "SuperRAG" +description: "Supermemory provides a managed RAG solution - extraction, indexing, storing, and retrieval." +icon: "bolt" +--- + +Supermemory doesn't just store your content—it transforms it into optimized, searchable knowledge. Every upload goes through an intelligent pipeline that extracts, chunks, and indexes content in the ideal way for its type. + +## Automatic Content Intelligence + +When you add content, Supermemory: + +1. **Detects the content type** — PDF, code, markdown, images, video, etc. +2. **Extracts content optimally** — Uses type-specific extraction (OCR for images, transcription for audio) +3. **Chunks intelligently** — Applies the right chunking strategy for the content type +4. **Generates embeddings** — Creates vector representations for semantic search +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" +}); +``` + +No chunking strategies to configure. No embedding models to choose. It just works. + +--- + +## Smart Chunking by Content Type + +Different content types need different chunking strategies. Supermemory applies the optimal approach automatically: + +### Documents (PDF, DOCX) + +PDFs and documents are chunked by **semantic sections** — headers, paragraphs, and logical boundaries. This preserves context better than arbitrary character splits. + +``` +├── Executive Summary (chunk 1) +├── Introduction (chunk 2) +├── Section 1: Architecture +│ ├── Overview (chunk 3) +│ └── Components (chunk 4) +└── Conclusion (chunk 5) +``` + +### Code + +Code is chunked using [code-chunk](https://github.com/supermemoryai/code-chunk), our open-source library that understands AST (Abstract Syntax Tree) boundaries: + +- Functions and methods stay intact +- Classes are chunked by method +- Import statements grouped separately +- Comments attached to their code blocks + +```typescript +// A 500-line file becomes meaningful chunks: +// - Imports + type definitions +// - Each function as a separate chunk +// - Class methods individually indexed +``` + +This means searching for "authentication middleware" finds the actual function, not a random slice of code. + +### Web Pages + +URLs are fetched, cleaned of navigation/ads, and chunked by article structure — headings, paragraphs, lists. + +### Markdown + +Chunked by heading hierarchy, preserving the document structure. + +See [Content Types](/concepts/content-types) for the full list of supported formats. + +--- + +## Hybrid Memory + RAG + +Supermemory combines the best of both approaches in every search: + + + + - Finds similar document chunks + - Great for knowledge retrieval + - Stateless — same results for everyone + + + + - Extracts and tracks user facts + - Understands temporal context + - Personalizes results per user + + + +With `searchMode: "hybrid"` (the default), you get both: + +```typescript +const results = await client.search({ + q: "how do I deploy the app?", + containerTag: "user_123", + searchMode: "hybrid" +}); + +// Returns: +// - Deployment docs from your knowledge base (RAG) +// - User's previous deployment preferences (Memory) +// - Their specific environment configs (Memory) +``` + +--- + +## Search Optimization + +Two flags give you fine-grained control over result quality: + +### Reranking + +Re-scores results using a cross-encoder model for better relevance: + +```typescript +const results = await client.search({ + q: "complex technical question", + rerank: true // +~100ms, significantly better ranking +}); +``` + +**When to use:** Complex queries, technical documentation, when precision matters more than speed. + +### Query Rewriting + +Expands your query to capture more relevant results: + +```typescript +const results = await client.search({ + q: "how to auth", + rewriteQuery: true // Expands to "authentication login oauth jwt..." +}); +``` + +**When to use:** Short queries, user-facing search, when recall matters. + +--- + +## Why It's "Super" + +| Traditional RAG | SUPER RAG | +|-----------------|-----------| +| Manual chunking config | Automatic per content type | +| One-size-fits-all splits | AST-aware code chunking | +| Just document retrieval | Hybrid memory + documents | +| Static embeddings | Relationship-aware graph | +| Generic search | Rerank + query rewriting | + +You focus on building your product. Supermemory handles the RAG complexity. + +--- + +## Next Steps + + + + All supported formats and how they're processed + + + + Search parameters and optimization + + diff --git a/apps/docs/concepts/user-profiles.mdx b/apps/docs/concepts/user-profiles.mdx new file mode 100644 index 00000000..7b01b41e --- /dev/null +++ b/apps/docs/concepts/user-profiles.mdx @@ -0,0 +1,135 @@ +--- +title: "User Profiles" +sidebarTitle: "User 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. + + + + No search needed — comprehensive user info always ready + + + Profiles update as users interact with your system + + + +## Why Profiles? + +Traditional memory systems rely entirely on search: + +| Problem | Search Only | With Profiles | +|---------|------------|---------------| +| Context retrieval | 3-5 queries | 1 call | +| Response time | 200-500ms | 50-100ms | +| 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, and uses specific terminology. + +**Profiles provide the foundation**: Instead of searching for basic context, profiles give your LLM a complete picture of who the user is. + +--- + +## Static vs Dynamic + +Profiles separate two types of information: + +### Static Profile + +Long-term, stable facts: + +- "Sarah is a senior software engineer at TechCorp" +- "Sarah specializes in distributed systems" +- "Sarah prefers technical docs over video tutorials" + +### Dynamic Profile + +Recent context and temporary states: + +- "Sarah is migrating the payment service to microservices" +- "Sarah is preparing for a conference talk next month" +- "Sarah is debugging a memory leak in auth service" + +--- + +## How It Works + +Profiles are built automatically through ingestion: + +1. **Ingest content** — Users add documents, 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. + + +--- + +## Profiles + Search + +Profiles don't replace search — they complement it: + +- **Profile** = broad foundation (who the user is, preferences, background) +- **Search** = specific details (exact memories matching a query) + +### Example + +User asks: **"Can you help me debug this?"** + +**Without profiles**: LLM has no context about expertise, projects, or preferences. + +**With profiles**: LLM knows: +- Senior engineer (adjust technical level) +- Working on payment service (likely context) +- Prefers CLI tools (tool suggestions) +- Recent memory leak issues (possible connection) + +--- + +## Use Cases + +### Personalized AI Assistants + +Profiles provide: expertise level, communication preferences, tools used, current projects. + +```typescript +const systemPrompt = `You are assisting ${userName}. + +Background: ${profile.static.join('\n')} +Current focus: ${profile.dynamic.join('\n')} + +Adjust responses to their expertise and preferences.`; +``` + +### Customer Support + +Profiles provide: product usage, previous issues, tech proficiency. + +- No more "let me look up your account" +- Agents immediately understand context +- AI support references past interactions naturally + +### Educational Platforms + +Profiles provide: learning style, completed courses, strengths/weaknesses. + +### Development Tools + +Profiles provide: preferred languages, coding style, current project context. + +--- + +## Next Steps + + + + Learn how to fetch and use profiles + + + Automatic profile injection with AI SDK + + diff --git a/apps/docs/connectors/overview.mdx b/apps/docs/connectors/overview.mdx index 046cc305..f36c39ad 100644 --- a/apps/docs/connectors/overview.mdx +++ b/apps/docs/connectors/overview.mdx @@ -2,6 +2,7 @@ title: "Connectors Overview" description: "Integrate Google Drive, Notion, OneDrive, GitHub and Web Crawler to automatically sync documents into your knowledge base" sidebarTitle: "Overview" +icon: "layers" --- Connect external platforms to automatically sync documents into Supermemory. Supported connectors include Google Drive, Notion, OneDrive, GitHub and Web Crawler with real-time synchronization and intelligent content processing. diff --git a/apps/docs/connectors/troubleshooting.mdx b/apps/docs/connectors/troubleshooting.mdx index 847a7987..ec62fab7 100644 --- a/apps/docs/connectors/troubleshooting.mdx +++ b/apps/docs/connectors/troubleshooting.mdx @@ -1,6 +1,8 @@ --- title: "Connector Troubleshooting" +sidebarTitle: "Troubleshooting" description: "Diagnose and resolve common issues with Google Drive, Notion, and OneDrive connectors" +icon: "wrench" --- Quick guide to resolve common connector issues with authentication, syncing, and permissions. diff --git a/apps/docs/cookbook/ai-sdk-integration.mdx b/apps/docs/cookbook/ai-sdk-integration.mdx index 8bdafef7..d6853210 100644 --- a/apps/docs/cookbook/ai-sdk-integration.mdx +++ b/apps/docs/cookbook/ai-sdk-integration.mdx @@ -3,7 +3,7 @@ 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 both Memory Tools and Infinite Chat approaches. +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 @@ -113,62 +113,6 @@ export async function POST(request: Request) { } ``` -## Infinite Chat for Documentation - -Create a documentation assistant with unlimited context: - - - -```typescript Documentation Chat -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' - } -}) - -export async function POST(request: Request) { - const { messages } = await request.json() - - const result = await streamText({ - model: infiniteChat('gpt-5'), - messages, - system: `You are a documentation assistant. You have access to all previous - conversations and can reference earlier discussions. Help users understand - the documentation by building on previous context.` - }) - - return result.toAIStreamResponse() -} -``` - -```typescript Upload Documentation -// Separate endpoint to upload documentation to memory -import { addMemory } from '@supermemory/tools' - -export async function POST(request: Request) { - const { content, title, url } = await request.json() - - const memory = await addMemory({ - apiKey: process.env.SUPERMEMORY_API_KEY!, - content, - title, - url, - headers: { - 'x-sm-conversation-id': 'documentation' - } - }) - - return Response.json({ success: true, memory }) -} -``` - - - ## Multi-User Learning Assistant Build an assistant that learns from multiple users but keeps data separate: @@ -391,12 +335,6 @@ ANTHROPIC_API_KEY=your_anthropic_key - Use project headers to separate different use cases - Implement error handling for tool failures -### Infinite Chat -- Use conversation IDs to maintain separate chat contexts -- Include user IDs for personalized experiences -- Test with different providers to find the best fit for your use case -- Monitor token usage for cost optimization - ### General Tips - Start with simple examples and gradually add complexity - Use the search functionality to avoid duplicate memories @@ -410,7 +348,7 @@ ANTHROPIC_API_KEY=your_anthropic_key Advanced memory management with full API control - - Drop-in proxy for existing LLM applications + + Automatic personalization with user profiles diff --git a/apps/docs/cookbook/customer-support.mdx b/apps/docs/cookbook/customer-support.mdx index 32e0417e..b1643556 100644 --- a/apps/docs/cookbook/customer-support.mdx +++ b/apps/docs/cookbook/customer-support.mdx @@ -70,7 +70,7 @@ A customer support bot that: metadata?: Record }) { try { - const result = await client.memories.add({ + const result = await client.add({ content: `${interaction.type.toUpperCase()}: ${interaction.content}`, containerTag: this.getContainerTag(customerId), metadata: { @@ -146,7 +146,7 @@ A customer support bot that: try { const issueContent = `ISSUE: ${issue.subject}\n\nDescription: ${issue.description}\nCategory: ${issue.category}\nPriority: ${issue.priority}\nStatus: ${issue.status}` - const result = await client.memories.add({ + const result = await client.add({ content: issueContent, containerTag: this.getContainerTag(customerId), metadata: { @@ -232,7 +232,7 @@ A customer support bot that: try: content = f"{interaction['type'].upper()}: {interaction['content']}" - result = self.client.memories.add( + result = self.client.add( content=content, container_tag=self._get_container_tag(customer_id), metadata={ @@ -309,7 +309,7 @@ Category: {issue['category']} Priority: {issue['priority']} Status: {issue['status']}""" - result = self.client.memories.add( + result = self.client.add( content=issue_content, container_tag=self._get_container_tag(customer_id), metadata={ diff --git a/apps/docs/cookbook/document-qa.mdx b/apps/docs/cookbook/document-qa.mdx index d11e947b..e18b7c2f 100644 --- a/apps/docs/cookbook/document-qa.mdx +++ b/apps/docs/cookbook/document-qa.mdx @@ -71,7 +71,7 @@ A document Q&A system that: async uploadURL({ url, collection, metadata = {} }: { url: string, collection: string, metadata?: Record }) { try { - const result = await client.memories.add({ + const result = await client.add({ content: url, containerTag: collection, metadata: { @@ -216,7 +216,7 @@ A document Q&A system that: metadata = {} try: - result = self.client.memories.add( + result = self.client.add( content=url, container_tag=collection, metadata={ diff --git a/apps/docs/cookbook/overview.mdx b/apps/docs/cookbook/overview.mdx index 80ec57a1..a36dcfb6 100644 --- a/apps/docs/cookbook/overview.mdx +++ b/apps/docs/cookbook/overview.mdx @@ -53,7 +53,7 @@ We're working on more comprehensive recipes. Have a suggestion? [Let us know!](m Can't find what you're looking for? -- Browse [Search Examples](/search/examples/document-search) for specific feature usage +- 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 diff --git a/apps/docs/cookbook/personal-assistant.mdx b/apps/docs/cookbook/personal-assistant.mdx index 7d5f256b..d4522590 100644 --- a/apps/docs/cookbook/personal-assistant.mdx +++ b/apps/docs/cookbook/personal-assistant.mdx @@ -9,7 +9,7 @@ Build a personal AI assistant that learns and remembers everything about the use A personal AI assistant that: - **Remembers user preferences** (dietary restrictions, work schedule, communication style) -- **Maintains context** across multiple chat sessions +- **Maintains context** across multiple chat sessions - **Provides personalized recommendations** based on user history - **Handles multiple conversation topics** while maintaining context @@ -169,7 +169,7 @@ This searches the user's memory store for context relevant to their current mess ```python async def add_user_memory(content: str, container_tag: str, email: str = None): try: - supermemory_client.memories.add( + supermemory_client.add( content=content, container_tag=container_tag, metadata={"type": "personal_info", "email": normalize_email(email) if email else None} @@ -196,7 +196,7 @@ Stores new information about the user. 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: @@ -216,7 +216,7 @@ This endpoint receives the chat request. It expects: 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}" ``` @@ -229,7 +229,7 @@ The container tag (`user_abc123`) isolates this user's memories from everyone el ```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 @@ -308,7 +308,7 @@ After streaming completes, check if the user explicitly asked to remember someth ```python return StreamingResponse(generate(), media_type="text/plain") - + except Exception as e: raise HTTPException(status_code=500, detail=str(e)) ``` @@ -360,11 +360,11 @@ 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 @@ -388,12 +388,12 @@ 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( @@ -405,7 +405,7 @@ if st.session_state.user_name and st.session_state.email: stream=True, timeout=30 ) - + if response.status_code == 200: full_response = "" for line in response.iter_lines(): @@ -416,7 +416,7 @@ if st.session_state.user_name and st.session_state.email: full_response += data['content'] except: continue - + st.markdown(full_response) st.session_state.messages.append({"role": "assistant", "content": full_response}) else: @@ -544,7 +544,7 @@ Without email, we can't maintain personalization across sessions. const containerTag = `user_${email.toLowerCase().trim()}` ``` -Convert email to a container tag for memory isolation. +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: @@ -646,10 +646,10 @@ Catches any errors (API failures, tool errors, etc.) and returns a clean error r | **Streaming** | Manual SSE formatting | `toAIStreamResponse()` handles it | | **Error Handling** | Try/catch in each function | AI SDK handles tool errors | -**Python = Manual Control** +**Python = Manual Control** You explicitly search and add memories. More control, more code. -**TypeScript = AI-Driven** +**TypeScript = AI-Driven** The AI decides when to use tools. Less code, more "magic." ### Step 3: Chat UI @@ -668,12 +668,12 @@ export default function ChatPage() { 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 ( @@ -708,7 +708,7 @@ export default function ChatPage() { ) } - + return ( @@ -716,8 +716,8 @@ export default function ChatPage() { @@ -725,7 +725,7 @@ export default function ChatPage() { ))} - + - diff --git a/apps/docs/docs.json b/apps/docs/docs.json index 26aff108..0bad5cf7 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -42,7 +42,7 @@ "navbar": { "links": [ { - "href": "mailto:support@supermemory.ai", + "href": "mailto:support@supermemory.com", "label": "Support" } ], @@ -54,10 +54,6 @@ }, "navigation": { "tabs": [ - { - "pages": ["introduction"], - "tab": "Welcome" - }, { "icon": "code", "anchors": [ @@ -71,125 +67,98 @@ "pages": [ { "group": "Getting Started", - "pages": ["intro", "vibe-coding", "quickstart", "memory-vs-rag"] + "icon": "rocket", + "pages": ["intro", "quickstart", "vibe-coding"] }, { - "group": "Memory API", + "group": "Concepts", + "icon": "lightbulb", "pages": [ - "how-it-works", + "concepts/how-it-works", + "concepts/graph-memory", + "concepts/content-types", + "concepts/super-rag", + "concepts/memory-vs-rag", + "concepts/filtering", + "concepts/user-profiles", + "concepts/customization" + ] + }, + { + "group": "Using supermemory", + "icon": "brain", + "pages": [ + "add-memories", + "search", + "user-profiles", { - "group": "Add Memories", - "icon": "plus", - "pages": [ - "add-memories/overview", - "add-memories/parameters", - "memory-api/ingesting", - { - "group": "Examples", - "pages": [ - "add-memories/examples/basic", - "add-memories/examples/file-upload" - ] - } - ] + "group": "Manage Content", + "icon": "folder-cog", + "pages": ["document-operations", "memory-operations"] }, - { - "group": "Search Memories", - "icon": "search", - "pages": [ - "search/overview", - "search/parameters", - "search/response-schema", - "search/query-rewriting", - "search/reranking", - { - "group": "Examples", - "pages": [ - "search/examples/document-search", - "search/examples/memory-search" - ] - } - ] - }, - "search/filtering", - "memory-api/track-progress", - { - "group": "List Memories", - "icon": "list", - "pages": [ - "list-memories/overview", - { - "group": "Examples", - "pages": [ - "list-memories/examples/basic", - "list-memories/examples/filtering", - "list-memories/examples/pagination", - "list-memories/examples/monitoring" - ] - } - ] - }, - "update-delete-memories/overview", + "overview/use-cases" + ] + }, + { + "group": "Connectors and sync", + "icon": "plug", + "pages": [ + "connectors/overview", { "group": "Connectors", - "icon": "link", + "icon": "plug", "pages": [ - "connectors/overview", "connectors/notion", "connectors/google-drive", "connectors/onedrive", "connectors/s3", "connectors/github", - "connectors/web-crawler", - "connectors/troubleshooting", - "memory-api/connectors/managing-resources" + "connectors/web-crawler" ] }, - "/org-settings", - "/analytics", - "overview/use-cases" + "connectors/troubleshooting", + "memory-api/connectors/managing-resources" ] }, - { - "group": "User Profiles", - "icon": "user", - "pages": [ - "user-profiles/overview", - "user-profiles/api", - "user-profiles/examples", - "user-profiles/use-cases" - ] - }, - { - "group": "Memory Router", - "icon": "route", - "pages": [ - "memory-router/overview", - "memory-router/usage", - "memory-router/with-memory-api" - ] - }, - { - "group": "Integrations with no-code tools", - "pages": ["n8n", "zapier"] - }, - { - "group": "Supermemory MCP", - "pages": ["supermemory-mcp/mcp", "supermemory-mcp/setup"] - }, { "group": "Migration Guides", - "pages": ["migration/from-mem0", "migration/from-zep"] - }, - { - "group": "Deployment", - "pages": ["deployment/self-hosting"] + "icon": "arrow-right-left", + "pages": [ + { + "group": "From another provider", + "icon": "truck", + "pages": ["migration/from-mem0", "migration/from-zep"] + } + ] } ] + }, + { + "anchor": "Supermemory MCP", + "icon": "terminal", + "pages": ["supermemory-mcp/mcp", "supermemory-mcp/setup"] } ], "tab": "Developer Platform" }, + { + "icon": "plug", + "anchors": [ + { + "anchor": "Integrations", + "pages": [ + "integrations/supermemory-sdk", + "integrations/openai", + "integrations/ai-sdk", + "integrations/memory-graph", + "integrations/pipecat", + "integrations/n8n", + "integrations/zapier" + ] + } + ], + "tab": "Integrations" + }, { "icon": "book-open", "anchors": [ @@ -201,57 +170,7 @@ ], "tab": "API Reference" }, - { - "icon": "plug", - "anchors": [ - { - "anchor": "SDKs", - "pages": [ - "memory-api/sdks/overview", - { - "group": "Supermemory SDKs", - "pages": [ - "memory-api/sdks/native" - ] - }, - { - "group": "OpenAI SDK", - "icon": "sparkles", - "pages": ["memory-api/sdks/openai-plugins"] - }, - { - "group": "AI SDK", - "icon": "triangle", - "pages": [ - "ai-sdk/overview", - "ai-sdk/user-profiles", - "ai-sdk/memory-tools", - "ai-sdk/infinite-chat" - ] - }, - { - "group": "Memory Graph", - "icon": "network", - "pages": [ - "memory-graph/overview", - "memory-graph/installation", - "memory-graph/quickstart", - "memory-graph/api-reference", - "memory-graph/examples" - ] - }, - { - "group": "Voice & Realtime", - "icon": "mic", - "pages": [ - "voice-realtime/pipecat" - ] - } - ] - } - ], - "tab": "SDKs" - }, + { "icon": "flask-conical", "anchors": [ @@ -299,8 +218,7 @@ "cookbook/customer-support", "cookbook/ai-sdk-integration", "cookbook/perplexity-supermemory", - "cookbook/chat-with-gdrive", - "cookbook/inf-chat-blog" + "cookbook/chat-with-gdrive" ] } ] @@ -322,9 +240,224 @@ }, "redirects": [ { - "destination": "/introduction", + "destination": "/intro", "permanent": false, "source": "/" + }, + { + "destination": "/concepts/how-it-works", + "permanent": true, + "source": "/how-it-works" + }, + { + "destination": "/concepts/memory-vs-rag", + "permanent": true, + "source": "/memory-vs-rag" + }, + { + "destination": "/integrations/supermemory-sdk", + "permanent": true, + "source": "/memory-api/sdks/overview" + }, + { + "destination": "/integrations/supermemory-sdk", + "permanent": true, + "source": "/memory-api/sdks/native" + }, + { + "destination": "/integrations/openai", + "permanent": true, + "source": "/memory-api/sdks/openai-plugins" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/ai-sdk/overview" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/ai-sdk/user-profiles" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/ai-sdk/memory-tools" + }, + { + "destination": "/integrations/ai-sdk", + "permanent": true, + "source": "/ai-sdk/infinite-chat" + }, + { + "destination": "/integrations/memory-graph", + "permanent": true, + "source": "/memory-graph/overview" + }, + { + "destination": "/integrations/memory-graph", + "permanent": true, + "source": "/memory-graph/installation" + }, + { + "destination": "/integrations/memory-graph", + "permanent": true, + "source": "/memory-graph/quickstart" + }, + { + "destination": "/integrations/memory-graph", + "permanent": true, + "source": "/memory-graph/api-reference" + }, + { + "destination": "/integrations/memory-graph", + "permanent": true, + "source": "/memory-graph/examples" + }, + { + "destination": "/integrations/pipecat", + "permanent": true, + "source": "/voice-realtime/pipecat" + }, + { + "destination": "/integrations/n8n", + "permanent": true, + "source": "/n8n" + }, + { + "destination": "/integrations/zapier", + "permanent": true, + "source": "/zapier" + }, + { + "destination": "/concepts/filtering", + "permanent": true, + "source": "/search/filtering" + }, + { + "destination": "/add-memories", + "permanent": true, + "source": "/add-memories/overview" + }, + { + "destination": "/add-memories", + "permanent": true, + "source": "/add-memories/parameters" + }, + { + "destination": "/add-memories", + "permanent": true, + "source": "/memory-api/ingesting" + }, + { + "destination": "/add-memories", + "permanent": true, + "source": "/add-memories/examples/basic" + }, + { + "destination": "/add-memories", + "permanent": true, + "source": "/add-memories/examples/file-upload" + }, + { + "destination": "/search", + "permanent": true, + "source": "/search/overview" + }, + { + "destination": "/search", + "permanent": true, + "source": "/search/parameters" + }, + { + "destination": "/search", + "permanent": true, + "source": "/search/response-schema" + }, + { + "destination": "/search", + "permanent": true, + "source": "/search/query-rewriting" + }, + { + "destination": "/search", + "permanent": true, + "source": "/search/reranking" + }, + { + "destination": "/search", + "permanent": true, + "source": "/search/examples/document-search" + }, + { + "destination": "/search", + "permanent": true, + "source": "/search/examples/memory-search" + }, + { + "destination": "/concepts/user-profiles", + "permanent": true, + "source": "/user-profiles/overview" + }, + { + "destination": "/user-profiles", + "permanent": true, + "source": "/user-profiles/api" + }, + { + "destination": "/user-profiles", + "permanent": true, + "source": "/user-profiles/examples" + }, + { + "destination": "/concepts/user-profiles", + "permanent": true, + "source": "/user-profiles/use-cases" + }, + { + "destination": "/add-memories", + "permanent": true, + "source": "/update-delete-memories/overview" + }, + { + "destination": "/document-operations", + "permanent": true, + "source": "/memory-api/track-progress" + }, + { + "destination": "/document-operations", + "permanent": true, + "source": "/list-memories/overview" + }, + { + "destination": "/document-operations", + "permanent": true, + "source": "/list-memories/examples/basic" + }, + { + "destination": "/document-operations", + "permanent": true, + "source": "/list-memories/examples/filtering" + }, + { + "destination": "/document-operations", + "permanent": true, + "source": "/list-memories/examples/pagination" + }, + { + "destination": "/document-operations", + "permanent": true, + "source": "/list-memories/examples/monitoring" + }, + { + "destination": "/concepts/customization", + "permanent": true, + "source": "/org-settings" + }, + { + "destination": "/add-memories", + "permanent": true, + "source": "/memory-api/overview" } ], "styling": { "eyebrows": "breadcrumbs" }, diff --git a/apps/docs/document-operations.mdx b/apps/docs/document-operations.mdx new file mode 100644 index 00000000..d0b88551 --- /dev/null +++ b/apps/docs/document-operations.mdx @@ -0,0 +1,293 @@ +--- +title: "Document Operations" +sidebarTitle: "Documents" +description: "List, get, update, and delete your ingested documents" +icon: "files" +--- + +Manage documents after ingestion using the SDK. + +## List Documents + +Retrieve paginated documents with filtering. + + + + ```typescript + const documents = await client.documents.list({ + limit: 10, + containerTags: ["user_123"] + }); + + documents.forEach(d => { + console.log(d.id, d.title, d.status); + }); + ``` + + + ```python + documents = client.documents.list( + limit=10, + container_tags=["user_123"] + ) + + for doc in documents.memories: + print(doc.id, doc.title, doc.status) + ``` + + + ```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, "containerTags": ["user_123"]}' + ``` + + + +**Response:** +```json +{ + "memories": [ + { + "id": "doc_abc123", + "title": "Meeting notes", + "status": "done", + "type": "text", + "createdAt": "2024-01-15T10:30:00Z", + "containerTags": ["user_123"], + "metadata": { "source": "slack" } + } + ], + "pagination": { + "currentPage": 1, + "totalPages": 3, + "totalItems": 25 + } +} +``` + +### Parameters + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `limit` | number | 50 | Items per page (max 200) | +| `page` | number | 1 | Page number | +| `containerTags` | string[] | — | Filter by tags | +| `sort` | string | `createdAt` | Sort by `createdAt` or `updatedAt` | +| `order` | string | `desc` | `desc` (newest) or `asc` (oldest) | + + + ```typescript + async function getAllDocuments(containerTag: string) { + const all = []; + let page = 1; + + while (true) { + const { memories, pagination } = await client.documents.list({ + containerTags: [containerTag], + limit: 100, + page + }); + + all.push(...memories); + if (page >= pagination.totalPages) break; + page++; + } + + return all; + } + ``` + + + + ```typescript + const documents = await client.documents.list({ + containerTags: ["user_123"], + filters: JSON.stringify({ + AND: [ + { key: "status", value: "reviewed" }, + { key: "priority", value: "high" } + ] + }) + }); + ``` + + +--- + +## Get Document + +Get a specific document with its processing status. + + + + ```typescript + const doc = await client.documents.get("doc_abc123"); + + console.log(doc.status); // "queued" | "processing" | "done" | "failed" + console.log(doc.content); + ``` + + + ```python + doc = client.documents.get("doc_abc123") + + print(doc.status) + print(doc.content) + ``` + + + ```bash + curl "https://api.supermemory.ai/v3/documents/doc_abc123" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" + ``` + + + +### Processing Status + +| Status | Description | +|--------|-------------| +| `queued` | Waiting to process | +| `extracting` | Extracting content (OCR, transcription) | +| `chunking` | Breaking into searchable pieces | +| `embedding` | Creating vector representations | +| `done` | Ready for search | +| `failed` | Processing failed | + + + ```typescript + async function waitForProcessing(docId: string) { + while (true) { + const doc = await client.documents.get(docId); + + if (doc.status === "done") return doc; + if (doc.status === "failed") throw new Error("Processing failed"); + + await new Promise(r => setTimeout(r, 2000)); + } + } + ``` + + +--- + +## Update Document + +Update a document's content or metadata. Triggers reprocessing. + + + + ```typescript + await client.documents.update("doc_abc123", { + content: "Updated content here", + metadata: { version: 2, reviewed: true } + }); + ``` + + + ```python + client.documents.update( + "doc_abc123", + content="Updated content here", + metadata={"version": 2, "reviewed": True} + ) + ``` + + + ```bash + curl -X PUT "https://api.supermemory.ai/v3/documents/doc_abc123" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"content": "Updated content here", "metadata": {"version": 2}}' + ``` + + + +--- + +## Delete Documents + +Permanently remove documents. + + + + ```typescript + // Single delete + await client.documents.delete("doc_abc123"); + + // Bulk delete by IDs + await client.documents.bulkDelete({ + ids: ["doc_1", "doc_2", "doc_3"] + }); + + // Bulk delete by container tag (delete all for a user) + await client.documents.bulkDelete({ + containerTags: ["user_123"] + }); + ``` + + + ```python + # Single delete + client.documents.delete("doc_abc123") + + # Bulk delete by IDs + client.documents.bulk_delete(ids=["doc_1", "doc_2", "doc_3"]) + + # Bulk delete by container tag + client.documents.bulk_delete(container_tags=["user_123"]) + ``` + + + ```bash + # Single delete + curl -X DELETE "https://api.supermemory.ai/v3/documents/doc_abc123" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" + + # Bulk delete by IDs + curl -X POST "https://api.supermemory.ai/v3/documents/bulk-delete" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"ids": ["doc_1", "doc_2", "doc_3"]}' + ``` + + + + +Deletes are permanent — no recovery. + + +--- + +## Processing Queue + +Check documents currently being processed. + + + + ```typescript + const response = await fetch("https://api.supermemory.ai/v3/documents/processing", { + headers: { "Authorization": `Bearer ${API_KEY}` } + }); + + const { documents } = await response.json(); + console.log(`${documents.length} documents processing`); + ``` + + + ```bash + curl "https://api.supermemory.ai/v3/documents/processing" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" + ``` + + + +--- + +## Next Steps + +- [Memory Operations](/memory-operations) — Advanced v4 memory operations +- [Search](/search) — Query your memories +- [Ingesting Content](/add-memories) — Add new content diff --git a/apps/docs/images/openai.svg b/apps/docs/images/openai.svg new file mode 100644 index 00000000..cba1bd1c --- /dev/null +++ b/apps/docs/images/openai.svg @@ -0,0 +1 @@ +OpenAI diff --git a/apps/docs/images/pipecat.svg b/apps/docs/images/pipecat.svg new file mode 100644 index 00000000..4f7fd4f0 --- /dev/null +++ b/apps/docs/images/pipecat.svg @@ -0,0 +1 @@ + diff --git a/apps/docs/images/quickstart-icon.svg b/apps/docs/images/quickstart-icon.svg new file mode 100644 index 00000000..eac75e8b --- /dev/null +++ b/apps/docs/images/quickstart-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/docs/images/supermemory.svg b/apps/docs/images/supermemory.svg new file mode 100644 index 00000000..2086fcaf --- /dev/null +++ b/apps/docs/images/supermemory.svg @@ -0,0 +1 @@ + diff --git a/apps/docs/integrations/ai-sdk.mdx b/apps/docs/integrations/ai-sdk.mdx new file mode 100644 index 00000000..f67c8508 --- /dev/null +++ b/apps/docs/integrations/ai-sdk.mdx @@ -0,0 +1,196 @@ +--- +title: "Vercel AI SDK" +sidebarTitle: "Vercel AI SDK" +description: "Use Supermemory with Vercel AI SDK for seamless memory management" +icon: "triangle" +--- + +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 +``` + +## Quick Comparison + +| Approach | Use Case | Setup | +|----------|----------|-------| +| User Profiles | Personalized LLM responses with automatic user context | Simple middleware | +| Memory Tools | AI agents that need explicit memory control | Tool definitions | + +--- + +## User Profiles with Middleware + +Automatically inject user profiles into every LLM call for instant personalization. + +```typescript +import { generateText } from "ai" +import { withSupermemory } from "@supermemory/tools/ai-sdk" +import { openai } from "@ai-sdk/openai" + +const modelWithMemory = withSupermemory(openai("gpt-5"), "user-123") + +const result = await generateText({ + model: modelWithMemory, + messages: [{ role: "user", content: "What do you know about me?" }] +}) +``` + + + **Memory saving is disabled by default.** The middleware only retrieves existing memories. To automatically save new memories: + + ```typescript + const modelWithMemory = withSupermemory(openai("gpt-5"), "user-123", { + addMemory: "always" + }) + ``` + + +### Memory Search Modes + +**Profile Mode (Default)** - Retrieves the user's complete profile: + +```typescript +const model = withSupermemory(openai("gpt-4"), "user-123", { mode: "profile" }) +``` + +**Query Mode** - Searches memories based on the user's message: + +```typescript +const model = withSupermemory(openai("gpt-4"), "user-123", { mode: "query" }) +``` + +**Full Mode** - Combines profile AND query-based search: + +```typescript +const model = withSupermemory(openai("gpt-4"), "user-123", { mode: "full" }) +``` + +### Custom Prompt Templates + +Customize how memories are formatted: + +```typescript +import { withSupermemory, type MemoryPromptData } from "@supermemory/tools/ai-sdk" + +const claudePrompt = (data: MemoryPromptData) => ` + + + ${data.userMemories} + + + ${data.generalSearchMemories} + + +`.trim() + +const model = withSupermemory(anthropic("claude-3-sonnet"), "user-123", { + mode: "full", + promptTemplate: claudePrompt +}) +``` + +### Verbose Logging + +```typescript +const model = withSupermemory(openai("gpt-4"), "user-123", { + verbose: true +}) +// Console output shows memory retrieval details +``` + +--- + +## 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") +}) +``` + +### 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") +}) +// AI will call: searchMemories({ informationToGet: "dietary preferences" }) +``` + +**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") +}) +// AI will 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") +}) +``` + +### Using Individual Tools + +For more control, import tools separately: + +```typescript +import { + searchMemoriesTool, + addMemoryTool, + fetchMemoryTool +} from "@supermemory/tools/ai-sdk" + +const result = await streamText({ + model: openai("gpt-5"), + prompt: "What do you know about me?", + tools: { + searchMemories: searchMemoriesTool("API_KEY", { projectId: "personal" }), + createEvent: yourCustomTool, + } +}) +``` + +### Tool Results + +```typescript +// searchMemories result +{ success: true, results: [...], count: 5 } + +// addMemory result +{ success: true, memory: { id: "mem_123", ... } } + +// fetchMemory result +{ success: true, memory: { id: "mem_123", content: "...", ... } } +``` + diff --git a/apps/docs/integrations/memory-graph.mdx b/apps/docs/integrations/memory-graph.mdx new file mode 100644 index 00000000..decd5f52 --- /dev/null +++ b/apps/docs/integrations/memory-graph.mdx @@ -0,0 +1,363 @@ +--- +title: 'Memory Graph' +sidebarTitle: "Memory Graph" +description: 'Interactive visualization for documents, memories and connections' +icon: "network" +--- + +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. + + + Check out the NPM page for more details + + +## Installation + +```bash +npm install @supermemory/memory-graph +``` + +**Requirements:** React 18.0.0 or higher + +## Quick Start + +```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 +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. + + +--- + +## Variants + +**Console Variant** - Full-featured dashboard view (0.8x zoom, space selector visible): + +```tsx + +``` + +**Consumer Variant** - Embedded widget view (0.5x zoom, space selector hidden): + +```tsx + +``` + +--- + +## Examples + +### With Pagination + +```tsx +'use client'; + +import { MemoryGraph } 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); + + useEffect(() => { fetchPage(1, false); }, []); + + const fetchPage = async (pageNum, append) => { + pageNum === 1 ? setIsLoading(true) : setIsLoadingMore(true); + + const res = await fetch(`/api/graph?page=${pageNum}&limit=100`); + const data = await res.json(); + + append ? setDocuments(prev => [...prev, ...data.documents]) : 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 + 0} +/> +``` + +### Controlled Space Selection + +```tsx + +``` + +### Custom Empty State + +```tsx + + + No memories yet + Add content to see your knowledge graph + + +``` + +--- + +## Props Reference + +### Core Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `documents` | `DocumentWithMemories[]` | required | Array of documents to display | +| `isLoading` | `boolean` | `false` | Shows loading indicator | +| `error` | `Error \| null` | `null` | Error to display | +| `variant` | `"console" \| "consumer"` | `"console"` | Visual variant | +| `children` | `ReactNode` | - | Custom empty state content | + +### Pagination Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `isLoadingMore` | `boolean` | `false` | Shows indicator when loading more | +| `hasMore` | `boolean` | `false` | Whether more documents available | +| `totalLoaded` | `number` | - | Total documents currently loaded | +| `loadMoreDocuments` | `() => Promise` | - | Callback to load more | +| `autoLoadOnViewport` | `boolean` | `true` | Auto-load when 80% visible | + +### Display Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `showSpacesSelector` | `boolean` | variant-based | Show space filter dropdown | +| `highlightDocumentIds` | `string[]` | `[]` | Document IDs to highlight | +| `highlightsVisible` | `boolean` | `true` | Whether highlights shown | +| `occludedRightPx` | `number` | `0` | Pixels occluded on right | + +### Controlled State Props + +| Prop | Type | Description | +|------|------|-------------| +| `selectedSpace` | `string` | Currently selected space (use `"all"` for all) | +| `onSpaceChange` | `(spaceId: string) => void` | Callback when space changes | +| `memoryLimit` | `number` | Max memories per document when space selected | + +--- + +## Data Types + +### DocumentWithMemories + +```typescript +interface DocumentWithMemories { + id: string; + customId?: 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; + createdAt: string | Date; + updatedAt: string | Date; + memoryEntries: MemoryEntry[]; +} +``` + +### MemoryEntry + +```typescript +interface MemoryEntry { + id: string; + documentId: string; + content: string | null; + summary?: string | null; + title?: string | null; + type?: string | null; + metadata?: Record | null; + createdAt: string | Date; + updatedAt: string | Date; + spaceContainerTag?: string | null; + relation?: 'updates' | 'extends' | 'derives' | null; + isLatest?: boolean; + spaceId?: string | null; +} +``` + +--- + +## Exports + +### Components + +```typescript +import { + MemoryGraph, + GraphCanvas, + Legend, + LoadingIndicator, + NodeDetailPanel, + SpacesDropdown +} from '@supermemory/memory-graph'; +``` + +### Hooks + +```typescript +import { useGraphData, useGraphInteractions } from '@supermemory/memory-graph'; +``` + +### Constants + +```typescript +import { colors, GRAPH_SETTINGS, LAYOUT_CONSTANTS } from '@supermemory/memory-graph'; +``` + +--- + +## 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 when zoomed out) +- Change-based rendering (only redraws when state changes) + +For very large datasets (1000+ documents), use pagination to load data in chunks. + +## Browser Support + +Works in all modern browsers supporting Canvas 2D API, ES2020, and CSS custom properties. Tested on Chrome, Firefox, Safari, and Edge. diff --git a/apps/docs/integrations/n8n.mdx b/apps/docs/integrations/n8n.mdx new file mode 100644 index 00000000..9fbf88e3 --- /dev/null +++ b/apps/docs/integrations/n8n.mdx @@ -0,0 +1,93 @@ +--- +title: "n8n" +sidebarTitle: "n8n" +description: "Automate knowledge management with Supermemory in n8n workflows" +icon: "workflow" +--- + +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) + +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. + +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 + + + +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 + + + + +#### 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/integrations/openai.mdx b/apps/docs/integrations/openai.mdx new file mode 100644 index 00000000..b27f7fce --- /dev/null +++ b/apps/docs/integrations/openai.mdx @@ -0,0 +1,586 @@ +--- +title: "OpenAI SDK" +sidebarTitle: "OpenAI SDK" +description: "Memory tools for OpenAI function calling with Supermemory integration" +icon: "/images/openai.svg" +--- + +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/integrations/pipecat.mdx b/apps/docs/integrations/pipecat.mdx new file mode 100644 index 00000000..fbd9852c --- /dev/null +++ b/apps/docs/integrations/pipecat.mdx @@ -0,0 +1,203 @@ +--- +title: "Pipecat" +sidebarTitle: "Pipecat (Voice)" +description: "Integrate Supermemory with Pipecat for conversational memory in voice AI agents" +icon: "/images/pipecat.svg" +--- + +Supermemory integrates with [Pipecat](https://github.com/pipecat-ai/pipecat), providing long-term memory capabilities for voice AI agents. Your Pipecat applications will remember past conversations and provide personalized responses based on user history. + +## Installation + +To use Supermemory with Pipecat, install the required dependencies: + +```bash +pip install supermemory-pipecat +``` + +Set up your API key as an environment variable: + +```bash +export SUPERMEMORY_API_KEY=your_supermemory_api_key +``` + +You can obtain an API key from [console.supermemory.ai](https://console.supermemory.ai). + +## Configuration + +Supermemory integration is provided through the `SupermemoryPipecatService` class in Pipecat: + +```python +from supermemory_pipecat import SupermemoryPipecatService, InputParams + +memory = SupermemoryPipecatService( + api_key=os.getenv("SUPERMEMORY_API_KEY"), + user_id="unique_user_id", + session_id="session_123", + params=InputParams( + mode="full", # "profile" | "query" | "full" + search_limit=10, # Max memories to retrieve + search_threshold=0.1, # Relevance threshold (0.0-1.0) + system_prompt="Based on previous conversations:\n\n", + ), +) +``` + +## Pipeline Integration + +The `SupermemoryPipecatService` should be positioned between your context aggregator and LLM service in the Pipecat pipeline: + +```python +pipeline = Pipeline([ + transport.input(), + stt, # Speech-to-text + context_aggregator.user(), + memory, # <- Supermemory memory service + llm, + tts, # Text-to-speech + transport.output(), + context_aggregator.assistant(), +]) +``` + +## How It Works + +When integrated with Pipecat, Supermemory provides two key functionalities: + +### 1. Memory Retrieval + +When a user message is detected, Supermemory retrieves relevant memories: + +- **Static Profile**: Persistent facts about the user +- **Dynamic Profile**: Recent context and preferences +- **Search Results**: Semantically relevant past memories + +### 2. Context Enhancement + +Retrieved memories are formatted and injected into the LLM context before generation, giving the model awareness of past conversations. + +## Memory Modes + +| Mode | Static Profile | Dynamic Profile | Search Results | Use Case | +|------|----------------|-----------------|----------------|----------| +| `"profile"` | Yes | Yes | No | Personalization without search | +| `"query"` | No | No | Yes | Finding relevant past context | +| `"full"` | Yes | Yes | Yes | Complete memory (default) | + +## Configuration Options + +You can customize how memories are retrieved and used: + +### InputParams + +```python +InputParams( + mode="full", # Memory mode (default: "full") + search_limit=10, # Max memories to retrieve (default: 10) + search_threshold=0.1, # Similarity threshold 0.0-1.0 (default: 0.1) + system_prompt="Based on previous conversations:\n\n", +) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `search_limit` | int | 10 | Maximum number of memories to retrieve per query | +| `search_threshold` | float | 0.1 | Minimum similarity threshold for memory retrieval | +| `mode` | str | "full" | Memory retrieval mode: `"profile"`, `"query"`, or `"full"` | +| `system_prompt` | str | "Based on previous conversations:\n\n" | Prefix text for memory context | + +## Example: Voice Agent with Memory + +Here's a complete example of a Pipecat voice agent with Supermemory integration: + +```python +import os +from fastapi import FastAPI, WebSocket +from fastapi.middleware.cors import CORSMiddleware + +from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.frames.frames import LLMMessagesFrame +from pipecat.pipeline.pipeline import Pipeline +from pipecat.pipeline.runner import PipelineRunner +from pipecat.pipeline.task import PipelineParams, PipelineTask +from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.serializers.protobuf import ProtobufFrameSerializer +from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.tts import OpenAITTSService +from pipecat.services.openai.stt import OpenAISTTService +from pipecat.transports.websocket.fastapi import ( + FastAPIWebsocketParams, + FastAPIWebsocketTransport, +) + +from supermemory_pipecat import SupermemoryPipecatService, InputParams + +app = FastAPI() + +SYSTEM_PROMPT = """You are a helpful voice assistant with memory capabilities. +You remember information from past conversations and use it to provide personalized responses. +Keep responses brief and conversational.""" + + +async def run_bot(websocket_client, user_id: str, session_id: str): + transport = FastAPIWebsocketTransport( + websocket=websocket_client, + params=FastAPIWebsocketParams( + audio_in_enabled=True, + audio_out_enabled=True, + vad_enabled=True, + vad_analyzer=SileroVADAnalyzer(), + vad_audio_passthrough=True, + serializer=ProtobufFrameSerializer(), + ), + ) + + stt = OpenAISTTService(api_key=os.getenv("OPENAI_API_KEY")) + llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o-mini") + tts = OpenAITTSService(api_key=os.getenv("OPENAI_API_KEY"), voice="alloy") + + # Supermemory memory service + memory = SupermemoryPipecatService( + user_id=user_id, + session_id=session_id, + params=InputParams( + mode="full", + search_limit=10, + search_threshold=0.1, + ), + ) + + context = OpenAILLMContext([{"role": "system", "content": SYSTEM_PROMPT}]) + context_aggregator = llm.create_context_aggregator(context) + + pipeline = Pipeline([ + transport.input(), + stt, + context_aggregator.user(), + memory, + llm, + tts, + transport.output(), + context_aggregator.assistant(), + ]) + + task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True)) + + @transport.event_handler("on_client_disconnected") + async def on_client_disconnected(transport, client): + await task.cancel() + + runner = PipelineRunner(handle_sigint=False) + await runner.run(task) + + +@app.websocket("/ws") +async def websocket_endpoint(websocket: WebSocket): + await websocket.accept() + await run_bot(websocket, user_id="alice", session_id="session-123") + + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8000) +``` diff --git a/apps/docs/integrations/supermemory-sdk.mdx b/apps/docs/integrations/supermemory-sdk.mdx new file mode 100644 index 00000000..33c80517 --- /dev/null +++ b/apps/docs/integrations/supermemory-sdk.mdx @@ -0,0 +1,140 @@ +--- +title: 'Supermemory SDK' +sidebarTitle: "Supermemory SDK" +description: 'Official Python and JavaScript SDKs for Supermemory' +icon: "/images/supermemory.svg" +--- + + + + pip install supermemory + + + npm install supermemory + + + + + + ## Installation + + ```bash + npm install supermemory + ``` + + ## Quick Start + + ```typescript + import Supermemory from 'supermemory'; + + const client = new Supermemory({ + apiKey: process.env.SUPERMEMORY_API_KEY, // Default, can be omitted + }); + + // Add a memory + await client.add({ content: "Meeting notes from Q1 planning", containerTags: ["user_123"] }); + + // Search memories + const response = await client.search.documents({ + q: "planning notes", + containerTags: ["user_123"] + }); + console.log(response.results); + + // Get user profile + const profile = await client.profile({ containerTag: "user_123" }); + console.log(profile.profile.static); + console.log(profile.profile.dynamic); + ``` + + ## Common Operations + + ```typescript + // Add with metadata + await client.add({ + content: "Technical design doc", + containerTags: ["user_123"], + metadata: { category: "engineering", priority: "high" } + }); + + // Search with filters + const results = await client.search.documents({ + q: "design document", + containerTags: ["user_123"], + filters: { + AND: [ + { key: "category", value: "engineering" } + ] + } + }); + + // List documents + const docs = await client.documents.list({ containerTags: ["user_123"], limit: 10 }); + + // Delete a document + await client.documents.delete({ docId: "doc_123" }); + ``` + + + + ## Installation + + ```bash + pip install supermemory + ``` + + ## Quick Start + + ```python + import os + from supermemory import Supermemory + + client = Supermemory( + api_key=os.environ.get("SUPERMEMORY_API_KEY"), # Default, can be omitted + ) + + # Add a memory + client.add(content="Meeting notes from Q1 planning", container_tags=["user_123"]) + + # Search memories + response = client.search.documents( + q="planning notes", + container_tags=["user_123"] + ) + print(response.results) + + # Get user profile + profile = client.profile(container_tag="user_123") + print(profile.profile.static) + print(profile.profile.dynamic) + ``` + + ## Common Operations + + ```python + # Add with metadata + client.add( + content="Technical design doc", + container_tags=["user_123"], + metadata={"category": "engineering", "priority": "high"} + ) + + # Search with filters + results = client.search.documents( + q="design document", + container_tags=["user_123"], + filters={ + "AND": [ + {"key": "category", "value": "engineering"} + ] + } + ) + + # List documents + docs = client.documents.list(container_tags=["user_123"], limit=10) + + # Delete a document + client.documents.delete(doc_id="doc_123") + ``` + + diff --git a/apps/docs/integrations/zapier.mdx b/apps/docs/integrations/zapier.mdx new file mode 100644 index 00000000..f00cc6d5 --- /dev/null +++ b/apps/docs/integrations/zapier.mdx @@ -0,0 +1,65 @@ +--- +title: "Zapier" +sidebarTitle: "Zapier" +description: "Automate memory management with Supermemory in Zapier workflows" +icon: "bolt" +--- + +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. +  + + + Add a new Gmail node that gets triggered on every new email. Connect to your Google account. +  + + + 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. + +  + + + 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. + +  + + + + + 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/docs/intro.mdx b/apps/docs/intro.mdx index 3f6d64a9..e5cb52fc 100644 --- a/apps/docs/intro.mdx +++ b/apps/docs/intro.mdx @@ -1,25 +1,32 @@ --- title: "Overview — What is Supermemory?" sidebarTitle: "Overview" -description = "Add long-term memory to your LLMs with three integration paths: AI SDK, Memory API, or Memory Router." +icon: "book-open" --- -Supermemory gives your LLMs long-term memory. Instead of stateless text generation, they recall the right facts from your files, chats, and tools, so responses stay consistent, contextual, and personal. +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](/concepts/connectors-syncing) +- Managed RAG platform + +All this, coming together, makes supermemory the best abstraction to provide to agents. ## How does it work? (at a glance)  - You send Supermemory text, files, and chats. -- Supermemory [intelligently indexes them](/how-it-works) and builds a semantic understanding graph on top of an entity (e.g., a user, a document, a project, an organization). +- 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. +Supermemory handles all the extraction, for [any data type that you have](/concepts/content-types). - Text - Conversations - Files (PDF, Images, Docs) @@ -34,7 +41,7 @@ We offer three ways to add context to your LLMs:  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, **in real time** +- [Evolve on top of existing context about the user](/concepts/memory-graph), **in real time** - Handle **knowledge updates, temporal changes, forgetfulness** - Creates a **user profile** as the default context provider for the LLM. @@ -42,7 +49,7 @@ _This can then be provided to the LLM, to give more contextual, personalized res #### User profiles -Having the latest, evolving context about the user allows us to also create a **User Profile**. This is a combination of static and dynamic facts about the user, that the agent should **always know** +Having the latest, evolving context about the user allows us to also create a [**User Profile**](/concepts/user-profile). 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. @@ -68,4 +75,4 @@ All three approaches share the **same context pool** when using the same user ID ## Next steps -Head to the [**How it works**](/how-it-works) guide to understand the underlying way of how supermemory represents and learns in data. +Head to the [**How it works**](/concepts/how-it-works) guide to understand the underlying way of how supermemory represents and learns in data. diff --git a/apps/docs/introduction.mdx b/apps/docs/introduction.mdx index 197586d6..89f2437d 100644 --- a/apps/docs/introduction.mdx +++ b/apps/docs/introduction.mdx @@ -45,14 +45,14 @@ export const HeroCard = ({ imageUrl, title, description, href }) => { imageUrl="https://imagedelivery.net/_Zs8NCbSWCQ8-iurXrWjBg/9af9572c-9f8d-42d8-f7d0-503a5f87a300/public" title="User profiles" description="One line to add memory to your app. Supercharge your LLM with supermemory's intelligent context management." - href="/memory-router/overview" + href="/concepts/user-profiles" /> diff --git a/apps/docs/memory-api/ingesting.mdx b/apps/docs/memory-api/ingesting.mdx index 79468eaf..c2839252 100644 --- a/apps/docs/memory-api/ingesting.mdx +++ b/apps/docs/memory-api/ingesting.mdx @@ -104,7 +104,7 @@ const client = new Supermemory({ }) async function addContent() { - const result = await client.memories.add({ + const result = await client.add({ content: "Machine learning is a subset of artificial intelligence...", containerTags: ["ai-research"], metadata: { @@ -127,7 +127,7 @@ import os client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) -result = client.memories.add( +result = client.add( content="Machine learning is a subset of artificial intelligence...", container_tags=["ai-research"], metadata={ @@ -699,7 +699,7 @@ Process large volumes efficiently with rate limiting and error recovery. async function ingestWithRetry(doc: Document, maxRetries: number) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { - return await client.memories.add({ + return await client.add({ content: doc.content, customId: doc.id, containerTags: ["batch_import_user_123"], // CORRECTED: Array @@ -787,7 +787,7 @@ Process large volumes efficiently with rate limiting and error recovery. async def ingest_with_retry(doc: Dict[str, Any], max_retries: int): for attempt in range(1, max_retries + 1): try: - return await client.memories.add( + return await client.add( content=doc['content'], custom_id=doc['id'], container_tags=["batch_import_user_123"], # CORRECTED: List diff --git a/apps/docs/memory-api/introduction.mdx b/apps/docs/memory-api/introduction.mdx index ca4fa705..24a46f8b 100644 --- a/apps/docs/memory-api/introduction.mdx +++ b/apps/docs/memory-api/introduction.mdx @@ -37,7 +37,7 @@ Check out the following resources to get started: 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/sdks/anthropic-claude-memory.mdx b/apps/docs/memory-api/sdks/anthropic-claude-memory.mdx index 5e6c5866..10bc195b 100644 --- a/apps/docs/memory-api/sdks/anthropic-claude-memory.mdx +++ b/apps/docs/memory-api/sdks/anthropic-claude-memory.mdx @@ -357,11 +357,11 @@ The Claude Memory Tool is ideal for: ## Next Steps - + Use memory tools with OpenAI function calling - + Integrate with Vercel AI SDK diff --git a/apps/docs/memory-api/sdks/openai-plugins.mdx b/apps/docs/memory-api/sdks/openai-plugins.mdx index 635e0008..d95dad47 100644 --- a/apps/docs/memory-api/sdks/openai-plugins.mdx +++ b/apps/docs/memory-api/sdks/openai-plugins.mdx @@ -574,7 +574,7 @@ npm run lint ## Next Steps - + Use with Vercel AI SDK for streamlined development diff --git a/apps/docs/memory-api/sdks/overview.mdx b/apps/docs/memory-api/sdks/overview.mdx index 32ffdd32..30ace8a2 100644 --- a/apps/docs/memory-api/sdks/overview.mdx +++ b/apps/docs/memory-api/sdks/overview.mdx @@ -3,18 +3,18 @@ title: "Overview" --- - + ```pip install supermemory``` ```npm install supermemory``` - + Easy to use with Vercel AI SDK - + Use supermemory with the python and javascript OpenAI SDKs diff --git a/apps/docs/memory-api/sdks/python.mdx b/apps/docs/memory-api/sdks/python.mdx index 52b6b3af..33700552 100644 --- a/apps/docs/memory-api/sdks/python.mdx +++ b/apps/docs/memory-api/sdks/python.mdx @@ -101,7 +101,7 @@ from supermemory import Supermemory client = Supermemory() try: - client.memories.add( + client.add( content="This is a detailed article about machine learning concepts...", ) except supermemory.APIConnectionError as e: @@ -346,4 +346,4 @@ print(supermemory.__version__) ## Requirements -Python 3.8 or higher. \ No newline at end of file +Python 3.8 or higher. diff --git a/apps/docs/memory-api/sdks/typescript.mdx b/apps/docs/memory-api/sdks/typescript.mdx index dd656a25..bea67033 100644 --- a/apps/docs/memory-api/sdks/typescript.mdx +++ b/apps/docs/memory-api/sdks/typescript.mdx @@ -44,7 +44,7 @@ async function main() { const params: supermemory.MemoryAddParams = { content: 'This is a detailed article about machine learning concepts...', }; - const response: supermemory.MemoryAddResponse = await client.memories.add(params); + const response: supermemory.MemoryAddResponse = await client.add(params); } main(); @@ -135,7 +135,7 @@ const client = new Supermemory({ }); // Or, configure per-request: -await client.memories.add({ content: 'This is a detailed article about machine learning concepts...' }, { +await client.add({ content: 'This is a detailed article about machine learning concepts...' }, { maxRetries: 5, }); ``` @@ -152,7 +152,7 @@ const client = new Supermemory({ }); // Override per-request: -await client.memories.add({ content: 'This is a detailed article about machine learning concepts...' }, { +await client.add({ content: 'This is a detailed article about machine learning concepts...' }, { timeout: 5 * 1000, }); ``` @@ -388,4 +388,4 @@ The following runtimes are supported: 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. \ No newline at end of file +If you are interested in other runtime environments, please open or upvote an issue on GitHub. diff --git a/apps/docs/memory-api/track-progress.mdx b/apps/docs/memory-api/track-progress.mdx index e14d7739..164ce044 100644 --- a/apps/docs/memory-api/track-progress.mdx +++ b/apps/docs/memory-api/track-progress.mdx @@ -236,7 +236,7 @@ Handle processing failures gracefully: ```typescript async function addWithRetry(content: string, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { - const { id } = await client.memories.add({ content }); + const { id } = await client.add({ content }); try { const result = await waitForProcessing(id); @@ -253,4 +253,4 @@ async function addWithRetry(content: string, maxRetries = 3) { } } } -``` \ No newline at end of file +``` diff --git a/apps/docs/memory-graph/installation.mdx b/apps/docs/memory-graph/installation.mdx index 0051825f..e3a0b2d4 100644 --- a/apps/docs/memory-graph/installation.mdx +++ b/apps/docs/memory-graph/installation.mdx @@ -19,10 +19,10 @@ npm install @supermemory/memory-graph ## Next Steps - + Get the graph running with real data - + Explore all available props and types diff --git a/apps/docs/memory-graph/quickstart.mdx b/apps/docs/memory-graph/quickstart.mdx index d05a0925..1b02fef6 100644 --- a/apps/docs/memory-graph/quickstart.mdx +++ b/apps/docs/memory-graph/quickstart.mdx @@ -198,10 +198,10 @@ Show custom content when no documents exist: ## Next Steps - + See more usage examples - + Full API documentation diff --git a/apps/docs/memory-operations.mdx b/apps/docs/memory-operations.mdx new file mode 100644 index 00000000..6b141447 --- /dev/null +++ b/apps/docs/memory-operations.mdx @@ -0,0 +1,98 @@ +--- +title: "Memory Operations" +sidebarTitle: "Memories" +description: "Advanced memory operations (v4 API)" +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). + + +## Forget Memory + +Soft-delete a memory — excluded from search results but preserved in the system. Use this when you might want to restore later. + + + + ```typescript + await fetch("https://api.supermemory.ai/v4/memories/mem_abc123/forget", { + method: "POST", + headers: { + "Authorization": `Bearer ${API_KEY}` + } + }); + ``` + + + ```bash + curl -X POST "https://api.supermemory.ai/v4/memories/mem_abc123/forget" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" + ``` + + + +The memory will no longer appear in search results but remains in the database. + +--- + +## Update Memory (Versioned) + +Update a memory by creating a new version. The original is preserved with `isLatest=false`. + + + + ```typescript + await fetch("https://api.supermemory.ai/v4/memories", { + method: "PATCH", + headers: { + "Authorization": `Bearer ${API_KEY}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + // Identify by ID or content + id: "mem_abc123", + // content: "Original content to match", + + newContent: "Updated content goes here", + metadata: { + tags: ["updated"] + } + }) + }); + ``` + + + ```bash + curl -X PATCH "https://api.supermemory.ai/v4/memories" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "id": "mem_abc123", + "newContent": "Updated content goes here", + "metadata": {"tags": ["updated"]} + }' + ``` + + + +### Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `id` | string | * | Memory ID to update | +| `content` | string | * | Original content to match (alternative to ID) | +| `newContent` | string | yes | New content for the memory | +| `metadata` | object | no | Updated metadata | + +\* Either `id` or `content` must be provided. + +--- + +## Next Steps + +- [Document Operations](/document-operations) — Manage documents (SDK supported) +- [Search](/search) — Query your memories +- [Ingesting Content](/add-memories) — Add new content diff --git a/apps/docs/memory-router/overview.mdx b/apps/docs/memory-router/overview.mdx index 4c142e5e..9ed0ba99 100644 --- a/apps/docs/memory-router/overview.mdx +++ b/apps/docs/memory-router/overview.mdx @@ -11,7 +11,7 @@ The Memory Router is a transparent proxy that sits between your application and -**Using Vercel AI SDK?** Check out our [AI SDK integration](/ai-sdk/overview) for the cleanest implementation with `@supermemory/tools/ai-sdk` - it's our recommended approach for new projects. +**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? diff --git a/apps/docs/memory-router/with-memory-api.mdx b/apps/docs/memory-router/with-memory-api.mdx index ae4396c2..e93705ea 100644 --- a/apps/docs/memory-router/with-memory-api.mdx +++ b/apps/docs/memory-router/with-memory-api.mdx @@ -21,7 +21,7 @@ from supermemory import Client api_client = Client(api_key="YOUR_SUPERMEMORY_KEY") # Add memory via API -api_client.memories.add({ +api_client.add({ "content": "User prefers Python over JavaScript for backend development", "user_id": "user123" }) @@ -52,7 +52,7 @@ Use the API to add documents and context before conversations: ```python # Step 1: Load user's documents via API -api_client.memories.add({ +api_client.add({ "content": "https://company.com/product-docs.pdf", "user_id": "support_agent_123", "metadata": {"type": "product_documentation"} @@ -80,11 +80,11 @@ Always use the same `user_id` format across both systems: ```python # ✅ Good - consistent user_id -api_client.memories.add({"user_id": "user_123"}) +api_client.add({"user_id": "user_123"}) router_headers = {"x-sm-user-id": "user_123"} # ❌ Bad - inconsistent user_id -api_client.memories.add({"user_id": "user-123"}) +api_client.add({"user_id": "user-123"}) router_headers = {"x-sm-user-id": "user_123"} # Different format! ``` @@ -92,7 +92,7 @@ router_headers = {"x-sm-user-id": "user_123"} # Different format! ```python # API: Add memories with tags -api_client.memories.add({ +api_client.add({ "content": "Q3 revenue report", "user_id": "analyst_1", "containerTag": "financial_reports" diff --git a/apps/docs/migration/from-mem0.mdx b/apps/docs/migration/from-mem0.mdx index e218c592..c4ec85ff 100644 --- a/apps/docs/migration/from-mem0.mdx +++ b/apps/docs/migration/from-mem0.mdx @@ -1,19 +1,18 @@ --- -title: "Migrating from Mem0.ai to Supermemory" -description: "Complete guide to migrate your data and applications from Mem0.ai to Supermemory" +title: "Migrating from Mem0 to Supermemory" +description: "Complete guide to migrate your data and applications from Mem0 to Supermemory" sidebarTitle: "From Mem0" --- -Migrating from Mem0.ai to Supermemory is straightforward. This guide walks you through exporting your memories from Mem0 and importing them into Supermemory. +Migrating from Mem0 to Supermemory is straightforward. This guide walks you through exporting your memories from Mem0 and importing them into Supermemory. ## Why Migrate to Supermemory? -Supermemory offers enhanced capabilities over Mem0.ai: -- **Memory Router** for zero-code LLM integration +Supermemory offers enhanced capabilities over Mem0: - **Knowledge graph** architecture for better context relationships - **Multiple content types** (URLs, PDFs, images, videos) - **Generous free tier** (100k tokens) with affordable pricing -- **Multiple integration options** (API, Router, MCP, SDKs) +- **Multiple integration options** (API, MCP, SDKs) ## Quick Migration (All-in-One) @@ -49,7 +48,7 @@ print("Migration complete!") ## Step-by-Step Migration - + Mem0 provides two ways to export your memories: ### Option 1: Export via Dashboard (Recommended) @@ -141,7 +140,7 @@ print("Migration complete!") # Import to Supermemory try: - result = client.memories.add( + result = client.add( content=content, container_tags=["imported_from_mem0"], metadata={ @@ -161,13 +160,13 @@ print("Migration complete!") ## API Migration Reference -Here's how common Mem0.ai operations map to Supermemory: +Here's how common Mem0 operations map to Supermemory: ### Adding Memories -```python Mem0.ai +```python mem0 from mem0 import MemoryClient client = MemoryClient(api_key="...") @@ -181,7 +180,7 @@ client.add( from supermemory import Supermemory client = Supermemory(api_key="...") -client.memories.add( +client.add( content="User prefers dark mode", container_tags=["user_alice"] ) @@ -193,7 +192,7 @@ client.memories.add( -```python Mem0.ai +```python Mem0 results = client.search( query="user preferences", user_id="alice" @@ -213,7 +212,7 @@ results = client.memories.search( -```python Mem0.ai +```python Mem0 memories = client.get_all( user_id="alice" ) @@ -232,7 +231,7 @@ memories = client.memories.list( -```python Mem0.ai +```python Mem0 client.delete(memory_id="mem_123") ``` @@ -242,55 +241,6 @@ client.memories.delete("mem_123") -## Using Memory Router (Easiest Migration) - -For the simplest migration path, use Supermemory's Memory Router which requires minimal code changes: - - - -```python Before (Mem0 + OpenAI) -from openai import OpenAI -from mem0 import MemoryClient - -# Two separate clients needed -openai = OpenAI(api_key="sk-...") -memory = MemoryClient(api_key="mem0_key") - -# Manual memory management -context = memory.search("user preferences", user_id="alice") -messages = [ - {"role": "system", "content": f"Context: {context}"}, - {"role": "user", "content": "What are my preferences?"} -] - -response = openai.chat.completions.create( - model="gpt-5", - messages=messages -) -``` - -```python After (Supermemory Router) -from openai import OpenAI - -# Single client with automatic memory management -client = OpenAI( - api_key="sk-...", - base_url="https://api.supermemory.ai/v3/https://api.openai.com/v1", - default_headers={ - "x-supermemory-api-key": "your_supermemory_key", - "x-supermemory-user-id": "alice" - } -) - -# Memories handled automatically! -response = client.chat.completions.create( - model="gpt-5", - messages=[{"role": "user", "content": "What are my preferences?"}] -) -``` - - - For enterprise migrations, [contact us](mailto:support@supermemory.ai) for assistance. diff --git a/apps/docs/migration/from-zep.mdx b/apps/docs/migration/from-zep.mdx index a109a157..1da0980b 100644 --- a/apps/docs/migration/from-zep.mdx +++ b/apps/docs/migration/from-zep.mdx @@ -367,6 +367,6 @@ migrateFromZep( ## Resources -- [Supermemory SDKs](/memory-api/sdks/overview) +- [Supermemory SDKs](/integrations/supermemory-sdk) - [API Reference](/memory-api/overview) -- [Search Documentation](/search/overview) +- [Search Documentation](/search) diff --git a/apps/docs/migration/mem0-migration-script.py b/apps/docs/migration/mem0-migration-script.py index 7b05edf6..c83c208d 100644 --- a/apps/docs/migration/mem0-migration-script.py +++ b/apps/docs/migration/mem0-migration-script.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 """ -Mem0.ai to Supermemory Migration Script +Mem0 to Supermemory Migration Script ======================================== -Simple script to migrate memories from Mem0.ai to Supermemory. +Simple script to migrate memories from Mem0 to Supermemory. Prerequisites: 1. Install required packages: @@ -18,36 +18,34 @@ Usage: python mem0-migration-script.py """ -import os import json +import os import time from datetime import datetime -from typing import Dict, Any, Optional +from typing import Any, Dict, Optional + +from dotenv import load_dotenv from mem0 import MemoryClient from supermemory import Supermemory -from dotenv import load_dotenv # Load environment variables load_dotenv() + def export_from_mem0( api_key: str, org_id: Optional[str] = None, project_id: Optional[str] = None, - filters: Optional[Dict] = None + filters: Optional[Dict] = None, ) -> Dict[str, Any]: """ - Export memories from Mem0.ai using their export API + Export memories from mem0 using their export API """ - print("🔄 Starting Mem0.ai export...") - + print("🔄 Starting mem0 export...") + # Initialize Mem0 client - client = MemoryClient( - api_key=api_key, - org_id=org_id, - project_id=project_id - ) - + client = MemoryClient(api_key=api_key, org_id=org_id, project_id=project_id) + # Define export schema - this matches what Mem0 actually returns export_schema = { "type": "object", @@ -65,41 +63,40 @@ def export_from_mem0( "run_id": {"type": "string"}, "metadata": {"type": "object"}, "created_at": {"type": "string"}, - "updated_at": {"type": "string"} - } - } + "updated_at": {"type": "string"}, + }, + }, } - } + }, } - + try: # Step 1: Create export job print("📤 Creating export job...") export_response = client.create_memory_export( - schema=export_schema, - filters=filters if filters else {} + schema=export_schema, filters=filters if filters else {} ) - + export_id = export_response.get("id") print(f"✅ Export job created with ID: {export_id}") - + # Step 2: Wait for export to complete print("⏳ Waiting for export to complete...") time.sleep(5) # Usually takes a few seconds - + # Step 3: Retrieve the exported data using the correct method print("📥 Retrieving exported data...") export_data = client.get_memory_export(memory_export_id=export_id) - + # Step 4: Save backup backup_filename = f"mem0_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" with open(backup_filename, "w") as f: json.dump(export_data, f, indent=2) print(f"💾 Backup saved to: {backup_filename}") - + memory_count = len(export_data.get("memories", [])) - print(f"✅ Successfully exported {memory_count} memories from Mem0.ai") - + print(f"✅ Successfully exported {memory_count} memories from mem0") + # Show sample of exported data if memory_count > 0: print("\n📋 Sample exported memory:") @@ -107,36 +104,33 @@ def export_from_mem0( print(f" Content: {sample.get('content', 'N/A')[:50]}...") print(f" ID: {sample.get('id', 'None')}") print(f" User ID: {sample.get('user_id', 'None')}") - + return export_data - + except Exception as e: print(f"❌ Error exporting from Mem0: {str(e)}") raise + def import_to_supermemory(mem0_data: Dict[str, Any], api_key: str) -> Dict[str, int]: """ Import Mem0 memories into Supermemory """ print("\n🚀 Starting import to Supermemory...") - + # Initialize Supermemory client client = Supermemory(api_key=api_key) - + memories = mem0_data.get("memories", []) if not memories: print("⚠️ No memories found to import") return {"imported": 0, "failed": 0, "skipped": 0} - + # Statistics - stats = { - "imported": 0, - "failed": 0, - "skipped": 0 - } - + stats = {"imported": 0, "failed": 0, "skipped": 0} + print(f"📦 Processing {len(memories)} memories...") - + for i, memory in enumerate(memories, 1): try: # Check if content exists @@ -145,174 +139,178 @@ def import_to_supermemory(mem0_data: Dict[str, Any], api_key: str) -> Dict[str, print(f"⚠️ [{i}/{len(memories)}] Skipping: No content") stats["skipped"] += 1 continue - + # Build container tags container_tags = ["imported_from_mem0"] - + # Add user tag if present (handle None values) user_id = memory.get("user_id") if user_id and user_id != "None": container_tags.append(f"user_{user_id}") - + # Add agent tag if present agent_id = memory.get("agent_id") if agent_id and agent_id != "None": container_tags.append(f"agent_{agent_id}") - + # Add app tag if present app_id = memory.get("app_id") if app_id and app_id != "None": container_tags.append(f"app_{app_id}") - + # Add session tag if present session_id = memory.get("session_id") if session_id and session_id != "None": container_tags.append(f"session_{session_id}") - + # Generate a unique ID if Mem0 didn't provide one memory_id = memory.get("id") if not memory_id or memory_id == "None": # Use content hash for uniqueness import hashlib + memory_id = hashlib.md5(content.encode()).hexdigest()[:8] - + # Prepare metadata metadata = { "source": "mem0_migration", - "migration_date": datetime.now().isoformat() + "migration_date": datetime.now().isoformat(), } - + # Add original ID if it existed if memory.get("id") and memory["id"] != "None": metadata["original_id"] = memory["id"] - + # Add timestamps if available and not None created_at = memory.get("created_at") if created_at and created_at != "None": metadata["original_created_at"] = created_at - + updated_at = memory.get("updated_at") if updated_at and updated_at != "None": metadata["original_updated_at"] = updated_at - + # Add hash information if available hash_val = memory.get("hash") if hash_val and hash_val != "None": metadata["original_hash"] = hash_val - + prev_hash = memory.get("prev_hash") if prev_hash and prev_hash != "None": metadata["original_prev_hash"] = prev_hash - + # Merge with existing metadata if it's a valid dict if memory.get("metadata") and isinstance(memory["metadata"], dict): metadata.update(memory["metadata"]) - + # Import to Supermemory - result = client.memories.add( + result = client.add( content=content, container_tags=container_tags, custom_id=f"mem0_{memory_id}", - metadata=metadata + metadata=metadata, ) - + stats["imported"] += 1 print(f"✅ [{i}/{len(memories)}] Imported: {content[:50]}...") - + # Small delay to avoid rate limiting if i % 10 == 0: time.sleep(0.5) - + except Exception as e: stats["failed"] += 1 print(f"❌ [{i}/{len(memories)}] Failed: {str(e)}") - + return stats + def verify_migration(api_key: str, expected_count: int): """ Verify that memories were imported correctly """ print("\n🔍 Verifying migration...") - + client = Supermemory(api_key=api_key) - + try: # Check imported memories - result = client.memories.list( - container_tags=["imported_from_mem0"], - limit=100 - ) - - total_imported = result['pagination']['totalItems'] + result = client.memories.list(container_tags=["imported_from_mem0"], limit=100) + + total_imported = result["pagination"]["totalItems"] print(f"✅ Found {total_imported} imported memories in Supermemory") - + # Show sample memories - if result['memories']: + if result["memories"]: print("\n📋 Sample imported memories:") - for memory in result['memories'][:3]: - print(f" - {memory['id']}: {memory.get('summary', 'No summary')[:50]}...") - + for memory in result["memories"][:3]: + print( + f" - {memory['id']}: {memory.get('summary', 'No summary')[:50]}..." + ) + # Check success rate - success_rate = (total_imported / expected_count * 100) if expected_count > 0 else 0 + success_rate = ( + (total_imported / expected_count * 100) if expected_count > 0 else 0 + ) print(f"\n📊 Migration success rate: {success_rate:.1f}%") - + return total_imported - + except Exception as e: print(f"❌ Error during verification: {str(e)}") return 0 + def main(): """Main migration function""" print("=" * 60) - print("🎯 Mem0.ai to Supermemory Migration Tool") + print("🎯 mem0 to Supermemory Migration Tool") print("=" * 60) - + # Get credentials from environment mem0_api_key = os.getenv("MEM0_API_KEY") mem0_org_id = os.getenv("MEM0_ORG_ID") mem0_project_id = os.getenv("MEM0_PROJECT_ID") supermemory_api_key = os.getenv("SUPERMEMORY_API_KEY") - + # Validate credentials if not mem0_api_key: print("❌ Error: MEM0_API_KEY environment variable not set") return - + if not supermemory_api_key: print("❌ Error: SUPERMEMORY_API_KEY environment variable not set") return - + try: # Step 1: Export from Mem0 - print("\n📤 STEP 1: Export from Mem0.ai") + print("\n📤 STEP 1: Export from mem0") print("-" * 40) - + # You can add filters here if needed # Example: filters = {"AND": [{"user_id": "specific_user"}]} filters = None - + mem0_data = export_from_mem0( api_key=mem0_api_key, org_id=mem0_org_id, project_id=mem0_project_id, - filters=filters + filters=filters, ) - + # Step 2: Import to Supermemory print("\n📥 STEP 2: Import to Supermemory") print("-" * 40) - + stats = import_to_supermemory(mem0_data, supermemory_api_key) - + # Step 3: Verify migration print("\n✔️ STEP 3: Verification") print("-" * 40) - + expected_count = len(mem0_data.get("memories", [])) verify_migration(supermemory_api_key, expected_count) - + # Final summary print("\n" + "=" * 60) print("📊 MIGRATION SUMMARY") @@ -321,17 +319,18 @@ def main(): print(f"✅ Successfully imported: {stats['imported']}") print(f"⚠️ Skipped (no content): {stats['skipped']}") print(f"❌ Failed: {stats['failed']}") - - if stats['imported'] == expected_count - stats['skipped']: + + if stats["imported"] == expected_count - stats["skipped"]: print("\n🎉 Migration completed successfully!") - elif stats['imported'] > 0: + elif stats["imported"] > 0: print("\n⚠️ Migration completed with some issues. Check the logs above.") else: print("\n❌ Migration failed. Please check your credentials and try again.") - + except Exception as e: print(f"\n❌ Migration error: {str(e)}") print("Please check your credentials and network connection.") + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/apps/docs/org-settings.mdx b/apps/docs/org-settings.mdx deleted file mode 100644 index 0d954603..00000000 --- a/apps/docs/org-settings.mdx +++ /dev/null @@ -1,265 +0,0 @@ ---- -title: "Organization Settings" -description: "Configure organization-wide settings and content filtering for Supermemory" -icon: "settings" ---- - -Organization settings control how Supermemory processes content across your entire organization. These settings apply to all memories and connectors, helping you: - -- Filter content before indexing -- Configure custom OAuth applications for connectors -- Set organization-wide processing rules -- Control what gets indexed and what gets excluded - - -Settings are organization-wide and apply to all users and memories within your organization. - - -## Why Settings Matter - -The settings endpoint is crucial for teaching Supermemory about your specific use case. It helps Supermemory understand: - -- **What you are**: Your organization's specific use case and purpose -- **What to expect**: The types of content and information flowing through your system -- **How to interpret**: Context for understanding queries in your specific use case -- **What to prioritize**: Which content matters most for your users - -### Example: Brand Guidelines Use Case - -Without proper settings, when a user searches "what are our values?", Supermemory might return random documents mentioning "values". But with proper configuration: - -```typescript -await client.settings.update({ - shouldLLMFilter: true, - filterPrompt: `You are managing brand guidelines for Brand.ai. - You will receive all outbound content from our organization. - - When users search, they're looking for: - - "What are our values?" → Return official brand values document - - "What's our tone of voice?" → Return brand voice guidelines - - "How do we describe our mission?" → Return approved mission statements - - Focus on the latest approved brand materials, not drafts or outdated versions.` -}); -``` - -Now Supermemory understands that: -- Searches about "values" refer to brand values, not financial values -- "Tone" means brand voice, not audio settings -- Priority should be given to official, approved content - -This context dramatically improves search relevance and ensures users get the right information for their specific use case. - -## API Endpoints - -### Get Current Settings - -Retrieve your organization's current settings configuration. - - - -```typescript TypeScript -const settings = await client.settings.get(); -console.log('Current settings:', settings); -``` - -```python Python -settings = client.settings.get() -print(f'Current settings: {settings}') -``` - -```bash cURL -curl -X GET "https://api.supermemory.ai/v3/settings" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" -``` - - - -### Update Settings - -Update your organization's settings. You only need to include the fields you want to change. - - - -```typescript TypeScript -const updatedSettings = await client.settings.update({ - shouldLLMFilter: true, - filterPrompt: "Only index technical documentation and code", - includeItems: ["*.md", "*.ts", "*.py"], - excludeItems: ["node_modules", ".git", "*.test.*"] -}); - -console.log('Updated fields:', updatedSettings.updated); -``` - -```python Python -updated_settings = client.settings.update( - should_llm_filter=True, - filter_prompt="Only index technical documentation and code", - include_items=["*.md", "*.ts", "*.py"], - exclude_items=["node_modules", ".git", "*.test.*"] -) - -print(f'Updated fields: {updated_settings.updated}') -``` - -```bash cURL -curl -X PATCH "https://api.supermemory.ai/v3/settings" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "shouldLLMFilter": true, - "filterPrompt": "Only index technical documentation and code", - "includeItems": ["*.md", "*.ts", "*.py"], - "excludeItems": ["node_modules", ".git", "*.test.*"] - }' -``` - - - -## Content Filtering Settings - -Control what content gets indexed into Supermemory. - -### Basic Filtering - -Use include/exclude patterns to filter content: - -```typescript -await client.settings.update({ - includeItems: [ - "*.md", // All markdown files - "*.mdx", // MDX documentation - "docs/**", // Everything in docs folder - "src/**/*.ts" // TypeScript files in src - ], - excludeItems: [ - "node_modules", // Dependencies - ".git", // Version control - "*.test.*", // Test files - "build/**", // Build outputs - "*.tmp" // Temporary files - ] -}); -``` - -### Intelligent LLM Filtering - -Enable AI-powered content filtering for semantic understanding: - -```typescript -await client.settings.update({ - shouldLLMFilter: true, - filterPrompt: `You are filtering content for a technical documentation system. - - Include: - - API documentation - - Code examples and tutorials - - Technical guides and references - - Architecture documentation - - Exclude: - - Marketing materials - - Internal meeting notes - - Personal information - - Outdated or deprecated content - - Focus on content that helps developers understand and use our APIs.` -}); -``` - -## Connector OAuth Settings - -Configure custom OAuth applications for connector integrations. - -### Google Drive Custom OAuth - -```typescript -await client.settings.update({ - googleDriveCustomKeyEnabled: true, - googleDriveClientId: "your-client-id.apps.googleusercontent.com", - googleDriveClientSecret: "your-client-secret" -}); -``` - -### Notion Custom OAuth - -```typescript -await client.settings.update({ - notionCustomKeyEnabled: true, - notionClientId: "your-notion-oauth-client-id", - notionClientSecret: "your-notion-oauth-client-secret" -}); -``` - -### OneDrive Custom OAuth - -```typescript -await client.settings.update({ - onedriveCustomKeyEnabled: true, - onedriveClientId: "your-azure-app-id", - onedriveClientSecret: "your-azure-app-secret" -}); -``` - -## Best Practices - -### 1. Set Before Bulk Import -Configure settings before importing large amounts of content. Changes don't retroactively affect existing memories. - -### 2. Be Specific in Filter Prompts -Provide clear context about your organization and expected search patterns: - -```typescript -// Good - Specific and contextual -filterPrompt: `Technical documentation for developers. - Include: API references, code examples, error solutions. - Exclude: marketing content, personal data, test files. - Users search for: implementation details, troubleshooting, best practices.` - -// Bad - Too vague -filterPrompt: "Only important content" -``` - -### 3. Test OAuth Credentials -Always test custom OAuth credentials in development before production: - -```typescript -// Test connection after updating OAuth settings -const testConnection = await client.connections.create('google-drive', { - redirectUrl: 'https://yourapp.com/callback', - containerTags: ['test-connection'] -}); -``` - -### 4. Monitor Filter Effectiveness -Check what's being indexed to ensure filters work as expected: - -```typescript -const memories = await client.memories.list({ - containerTags: ['your-tags'], - limit: 10 -}); - -// Review what's actually being indexed -memories.memories.forEach(memory => { - console.log(`Indexed: ${memory.title} - ${memory.type}`); -}); -``` - -## Important Notes - - -**Settings Limitations:** -- Changes are organization-wide, not per-user -- Settings don't retroactively process existing memories -- OAuth credentials must be properly configured in respective platforms -- Filter patterns are applied during content ingestion - - -## Related Documentation - -- [Connectors Overview](/connectors/overview) - Setting up external integrations -- [Google Drive Setup](/connectors/google-drive) - Configure Google Drive OAuth -- [Notion Setup](/connectors/notion) - Configure Notion OAuth -- [OneDrive Setup](/connectors/onedrive) - Configure OneDrive OAuth \ No newline at end of file diff --git a/apps/docs/quickstart.mdx b/apps/docs/quickstart.mdx index 04418c4c..11c650ed 100644 --- a/apps/docs/quickstart.mdx +++ b/apps/docs/quickstart.mdx @@ -1,10 +1,11 @@ --- title: Quickstart description: Make your first API call to Supermemory - add and retrieve memories. +icon: "play" --- -**Using Vercel AI SDK?** Check out the [AI SDK integration](/ai-sdk/overview) for the cleanest implementation with `@supermemory/tools/ai-sdk`. +**Using Vercel AI SDK?** Check out the [AI SDK integration](/integrations/ai-sdk) for the cleanest implementation with `@supermemory/tools/ai-sdk`. ## Memory API @@ -104,7 +105,7 @@ const messages = [{ role: "system", content: `User context:\n${context}` }, ...c // const response = await llm.chat({ messages }); // Store conversation for future context -await client.memories.add({ +await client.add({ content: conversation.map((m) => `${m.role}: ${m.content}`).join("\n"), containerTag: USER_ID, }); @@ -121,4 +122,4 @@ That's it! Supermemory automatically: **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. -Learn more about [User Profiles](/user-profiles) and [Search](/search/overview). +Learn more about [User Profiles](/user-profiles) and [Search](/search). diff --git a/apps/docs/search.mdx b/apps/docs/search.mdx new file mode 100644 index 00000000..17df0ff2 --- /dev/null +++ b/apps/docs/search.mdx @@ -0,0 +1,237 @@ +--- +title: "Search" +sidebarTitle: "Search Memories and Docs" +description: "Semantic search across your memories and documents" +icon: "search" +--- + +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. + + +## Quick Start + + + + ```typescript + import Supermemory from 'supermemory'; + + const client = new Supermemory(); + + const results = await client.search({ + q: "machine learning", + containerTag: "user_123", + searchMode: "hybrid", + limit: 5 + }); + + results.results.forEach(result => { + console.log(result.content, result.similarity); + }); + ``` + + + ```python + from supermemory import Supermemory + + client = Supermemory() + + results = client.search( + q="machine learning", + container_tag="user_123", + search_mode="hybrid", + limit=5 + ) + + for result in results.results: + print(result.content, result.similarity) + ``` + + + ```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", + "containerTag": "user_123", + "searchMode": "hybrid", + "limit": 5 + }' + ``` + + + +**Response:** +```json +{ + "results": [ + { + "id": "mem_xyz", + "content": "User is interested in machine learning for product recommendations", + "similarity": 0.91, + "metadata": { "topic": "interests" } + }, + { + "id": "chunk_abc", + "content": "Machine learning enables personalized experiences at scale...", + "similarity": 0.87, + "metadata": { "source": "onboarding_doc" } + } + ], + "timing": 92, + "total": 5 +} +``` + +--- + +## Parameters + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `q` | string | required | Search query | +| `containerTag` | string | — | Filter by user/project | +| `searchMode` | string | `"hybrid"` | `"hybrid"` (recommended) or `"memories"` | +| `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) | +| `filters` | object | — | Metadata filters (`AND`/`OR` structure) | + +### Search Modes + +- **`hybrid`** (recommended) — Searches both memories and document chunks, returns the most relevant +- **`memories`** — Only searches extracted memories + +```typescript +// Hybrid: memories + document chunks (recommended) +await client.search({ + q: "quarterly goals", + containerTag: "user_123", + searchMode: "hybrid" +}); + +// Memories only: just extracted facts +await client.search({ + q: "user preferences", + containerTag: "user_123", + searchMode: "memories" +}); +``` + +--- + +## Filtering + +Filter by `containerTag` to scope results to a user or project: + +```typescript +const results = await client.search({ + q: "project updates", + containerTag: "user_123", + searchMode: "hybrid" +}); +``` + +Use `filters` for metadata-based filtering: + +```typescript +const results = await client.search({ + q: "meeting notes", + containerTag: "user_123", + filters: { + AND: [ + { key: "type", value: "meeting" }, + { key: "year", value: "2024" } + ] + } +}); +``` + + + - **String equality:** `{ key: "status", value: "active" }` + - **String contains:** `{ filterType: "string_contains", key: "title", value: "react" }` + - **Numeric:** `{ filterType: "numeric", key: "priority", value: "5", numericOperator: ">=" }` + - **Array contains:** `{ filterType: "array_contains", key: "tags", value: "important" }` + - **Negate:** `{ key: "status", value: "draft", negate: true }` + + See [Organizing & Filtering](/concepts/filtering) for full syntax. + + +--- + +## Query Optimization + +### Reranking + +Re-scores results for better relevance. Adds ~100ms latency. + +```typescript +const results = await client.search({ + q: "complex technical question", + containerTag: "user_123", + rerank: true +}); +``` + +### Threshold + +Control result quality vs quantity: + +```typescript +// Broad search — more results +await client.search({ q: "...", threshold: 0.3 }); + +// Precise search — fewer, better results +await client.search({ q: "...", threshold: 0.8 }); +``` + +--- + +## Chatbot Example + +Optimal configuration for conversational AI: + +```typescript +async function getContext(userId: string, message: string) { + const results = await client.search({ + q: message, + containerTag: userId, + searchMode: "hybrid", + threshold: 0.6, + limit: 5 + }); + + return results.results + .map(r => r.content) + .join('\n\n'); +} +``` + + + ```typescript + interface SearchResult { + id: string; + content: string; // Memory or chunk content + similarity: number; // 0-1 + metadata: object | null; + updatedAt: string; + } + + interface SearchResponse { + results: SearchResult[]; + timing: number; // ms + total: number; + } + ``` + + +--- + +## Next Steps + +- [Ingesting Content](/add-memories) — Add content to search +- [User Profiles](/user-profiles) — Get user context with search +- [Organizing & Filtering](/concepts/filtering) — Container tags and metadata diff --git a/apps/docs/search/filtering.mdx b/apps/docs/search/filtering.mdx deleted file mode 100644 index a9efecba..00000000 --- a/apps/docs/search/filtering.mdx +++ /dev/null @@ -1,902 +0,0 @@ ---- -title: "Filtering Memories" -description: "Filter and search memories using container tags and metadata" -icon: "filter" ---- - -Supermemory provides two complementary filtering mechanisms that work independently or together to help you find exactly what you need. - -## How Filtering Works - -Supermemory uses two types of filters for different purposes: - - - - **Organize memories** into isolated spaces by user, project, or workspace - - - **Query memories** by custom properties like category, status, or date - - - -Both filtering types can be used: -- **Independently** - Use container tags alone OR metadata filters alone -- **Together** - Combine both for precise filtering (most common) - -Think of it as: `[Container Tags] → [Your Memories] ← [Metadata Filters]` - -## Container Tags - -Container tags create isolated memory spaces. They're perfect for multi-tenant applications, user profiles, and project organization. - -### How Container Tags Work - -- **Exact matching**: Arrays must match exactly. A memory tagged with `["user_123", "project_ai"]` will NOT match a search for just `["user_123"]` -- **Isolation**: Each container tag combination creates a separate knowledge graph -- **Naming patterns**: Use consistent patterns like `user_{id}`, `project_{id}`, or `org_{id}_team_{id}` - -### Basic Usage - - - - ```typescript - // Search within a user's memories - const results = await client.search.documents({ - q: "machine learning notes", - containerTags: ["user_123"], - limit: 10 - }); - - // Search within a project - const projectResults = await client.search.documents({ - q: "requirements", - containerTags: ["project_ai"], - limit: 10 - }); - ``` - - - ```python - # Search within a user's memories - results = client.search.documents( - q="machine learning notes", - container_tags=["user_123"], - limit=10 - ) - - # Search within a project - project_results = client.search.documents( - q="requirements", - container_tags=["project_ai"], - limit=10 - ) - ``` - - - ```bash - # Search within a user's memories - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "machine learning notes", - "containerTags": ["user_123"], - "limit": 10 - }' - ``` - - - -### Container Tag Patterns - - -**Best Practice**: Use single container tags when possible. Multi-tag arrays require exact matching, which can be restrictive. - - -#### Recommended Patterns -- User isolation: `user_{userId}` -- Project grouping: `project_{projectId}` -- Workspace separation: `workspace_{workspaceId}` -- Hierarchical: `org_{orgId}_team_{teamId}` -- Temporal: `user_{userId}_2024_q1` - -#### API Differences - -| Endpoint | Field Name | Type | Example | -|----------|------------|------|---------| -| `/v3/search` | `containerTags` | Array | `["user_123"]` | -| `/v4/search` | `containerTag` | String | `"user_123"` | -| `/v3/documents/list` | `containerTags` | Array | `["user_123"]` | - -## Metadata Filtering - -Metadata filters let you query memories by any custom property. They use SQL-like AND/OR logic with explicit grouping. - -### Filter Structure - -All metadata filters must be wrapped in AND or OR arrays: - -```javascript -// ✅ Correct - wrapped in AND array -filters: { - AND: [ - { key: "category", value: "tech", negate: false } - ] -} - -// ❌ Wrong - not wrapped -filters: { - key: "category", value: "tech", negate: false -} -``` - -### Why Explicit Grouping? - -Without explicit grouping, this SQL query is ambiguous: -```sql -category = 'tech' OR status = 'published' AND priority = 'high' -``` - -Our structure forces clarity: -```javascript -// Clear: (category = 'tech') OR (status = 'published' AND priority = 'high') -{ - OR: [ - { key: "category", value: "tech" }, - { AND: [ - { key: "status", value: "published" }, - { key: "priority", value: "high" } - ]} - ] -} -``` - -### Basic Metadata Filtering - - - - ```typescript - // Single condition - const results = await client.search.documents({ - q: "neural networks", - filters: { - AND: [ - { key: "category", value: "ai", negate: false } - ] - }, - limit: 10 - }); - - // Multiple AND conditions - const filtered = await client.search.documents({ - q: "research", - filters: { - AND: [ - { key: "category", value: "science", negate: false }, - { key: "status", value: "published", negate: false }, - { key: "year", value: "2024", negate: false } - ] - }, - limit: 10 - }); - ``` - - - ```python - # Single condition - results = client.search.documents( - q="neural networks", - filters={ - "AND": [ - {"key": "category", "value": "ai", "negate": False} - ] - }, - limit=10 - ) - - # Multiple AND conditions - filtered = client.search.documents( - q="research", - filters={ - "AND": [ - {"key": "category", "value": "science", "negate": False}, - {"key": "status", "value": "published", "negate": False}, - {"key": "year", "value": "2024", "negate": False} - ] - }, - limit=10 - ) - ``` - - - ```bash - # Single condition - curl -X POST "https://api.supermemory.ai/v3/search" \ - -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "q": "neural networks", - "filters": { - "AND": [ - {"key": "category", "value": "ai", "negate": false} - ] - }, - "limit": 10 - }' - ``` - - - -## Filter Types in Detail - -Supermemory supports four filter types, each designed for specific use cases. - -### 1. String Equality (Default) - -Exact string matching with optional case-insensitive comparison. - - - - ```javascript - // Case-sensitive exact match (default) - { - key: "status", - value: "Published", - negate: false - } - ``` - - - ```javascript - // Matches "published", "Published", "PUBLISHED" - { - key: "status", - value: "PUBLISHED", - ignoreCase: true, - negate: false - } - ``` - - - ```javascript - // Exclude specific status - { - key: "status", - value: "draft", - negate: true - } - ``` - - - -### 2. String Contains - -Search for substrings within text fields. - - - - ```javascript - // Find all documents containing "machine learning" - { - filterType: "string_contains", - key: "description", - value: "machine learning", - negate: false - } - ``` - - - ```javascript - // Case-insensitive substring search - { - filterType: "string_contains", - key: "title", - value: "NEURAL", - ignoreCase: true, - negate: false - } - ``` - - - ```javascript - // Exclude documents containing "deprecated" - { - filterType: "string_contains", - key: "content", - value: "deprecated", - negate: true - } - ``` - - - -### 3. Numeric Comparisons - -Filter by numeric values with comparison operators. - - - - ```javascript - // Greater than or equal - { - filterType: "numeric", - key: "score", - value: "80", - numericOperator: ">=", - negate: false - } - - // Less than - { - filterType: "numeric", - key: "readingTime", - value: "10", - numericOperator: "<", - negate: false - } - ``` - - - ```javascript - // NOT equal to 5 (becomes !=) - { - filterType: "numeric", - key: "priority", - value: "5", - numericOperator: "=", - negate: true - } - - // NOT less than 80 (becomes >=) - { - filterType: "numeric", - key: "score", - value: "80", - numericOperator: "<", - negate: true - } - ``` - - - - -**Numeric Negation Mapping**: -When using `negate: true` with numeric filters, operators are reversed: -- `<` → `>=` -- `<=` → `>` -- `>` → `<=` -- `>=` → `<` -- `=` → `!=` - - -### 4. Array Contains - -Check if an array field contains a specific value. - - - - ```javascript - // Find documents with specific participant - { - filterType: "array_contains", - key: "participants", - value: "john.doe", - negate: false - } - ``` - - - ```javascript - // Exclude documents with specific tag - { - filterType: "array_contains", - key: "tags", - value: "archived", - negate: true - } - ``` - - - ```javascript - // Must have both participants (use AND) - { - AND: [ - { - filterType: "array_contains", - key: "participants", - value: "project.manager" - }, - { - filterType: "array_contains", - key: "participants", - value: "lead.developer" - } - ] - } - ``` - - - -## Common Patterns - -Ready-to-use filtering patterns for common scenarios. - -### User-Specific Content with Category - - - - ```typescript - const results = await client.search.documents({ - q: "project updates", - containerTags: ["user_123"], - filters: { - AND: [ - { key: "category", value: "work", negate: false }, - { key: "visibility", value: "private", negate: false } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="project updates", - container_tags=["user_123"], - filters={ - "AND": [ - {"key": "category", "value": "work", "negate": False}, - {"key": "visibility", "value": "private", "negate": False} - ] - }, - limit=10 - ) - ``` - - - -### Recent High-Priority Content - - - - ```typescript - const results = await client.search.documents({ - q: "important tasks", - filters: { - AND: [ - { - filterType: "numeric", - key: "priority", - value: "7", - numericOperator: ">=", - negate: false - }, - { - filterType: "numeric", - key: "created_timestamp", - value: "1704067200", // 2024-01-01 - numericOperator: ">=", - negate: false - } - ] - }, - limit: 20 - }); - ``` - - - ```python - results = client.search.documents( - q="important tasks", - filters={ - "AND": [ - { - "filterType": "numeric", - "key": "priority", - "value": "7", - "numericOperator": ">=", - "negate": False - }, - { - "filterType": "numeric", - "key": "created_timestamp", - "value": "1704067200", # 2024-01-01 - "numericOperator": ">=", - "negate": False - } - ] - }, - limit=20 - ) - ``` - - - -### Team Collaboration Filter - - - - ```typescript - const results = await client.search.documents({ - q: "meeting notes", - containerTags: ["project_alpha"], - filters: { - AND: [ - { - OR: [ - { - filterType: "array_contains", - key: "participants", - value: "alice" - }, - { - filterType: "array_contains", - key: "participants", - value: "bob" - } - ] - }, - { - key: "type", - value: "meeting", - negate: false - } - ] - }, - limit: 15 - }); - ``` - - - ```python - results = client.search.documents( - q="meeting notes", - container_tags=["project_alpha"], - filters={ - "AND": [ - { - "OR": [ - { - "filterType": "array_contains", - "key": "participants", - "value": "alice" - }, - { - "filterType": "array_contains", - "key": "participants", - "value": "bob" - } - ] - }, - { - "key": "type", - "value": "meeting", - "negate": False - } - ] - }, - limit=15 - ) - ``` - - - -### Exclude Drafts and Deprecated Content - - - - ```typescript - const results = await client.search.documents({ - q: "documentation", - filters: { - AND: [ - { - key: "status", - value: "draft", - negate: true // Exclude drafts - }, - { - filterType: "string_contains", - key: "content", - value: "deprecated", - negate: true // Exclude deprecated - }, - { - filterType: "array_contains", - key: "tags", - value: "archived", - negate: true // Exclude archived - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="documentation", - filters={ - "AND": [ - { - "key": "status", - "value": "draft", - "negate": True # Exclude drafts - }, - { - "filterType": "string_contains", - "key": "content", - "value": "deprecated", - "negate": True # Exclude deprecated - }, - { - "filterType": "array_contains", - "key": "tags", - "value": "archived", - "negate": True # Exclude archived - } - ] - }, - limit=10 - ) - ``` - - - -## API-Specific Notes - -Different endpoints have slightly different requirements: - -| Endpoint | Container Tag Field | Type | Filter Format | Notes | -|----------|---------------------|------|---------------|-------| -| `/v3/search` | `containerTags` | Array | JSON object | Document search | -| `/v4/search` | `containerTag` | String | JSON object | Memory search | -| `/v3/documents/list` | `containerTags` | Array | **JSON string** | Must use `JSON.stringify()` | - - -**List API Special Requirement**: The `/v3/documents/list` endpoint requires filters as a JSON string: - -```javascript -// ✅ Correct for List API -filters: JSON.stringify({ AND: [...] }) - -// ❌ Wrong for List API (but correct for Search API) -filters: { AND: [...] } -``` - - -## Combining Container Tags and Metadata - -Most real-world applications combine both filtering types for precise control. - -### Example: User's Work Documents from 2024 - - - - ```typescript - const results = await client.search.documents({ - q: "quarterly report", - containerTags: ["user_123"], // User isolation - filters: { - AND: [ - { key: "category", value: "work" }, - { key: "type", value: "report" }, - { - filterType: "numeric", - key: "year", - value: "2024", - numericOperator: "=" - } - ] - }, - limit: 10 - }); - ``` - - - ```python - results = client.search.documents( - q="quarterly report", - container_tags=["user_123"], # User isolation - filters={ - "AND": [ - {"key": "category", "value": "work"}, - {"key": "type", "value": "report"}, - { - "filterType": "numeric", - "key": "year", - "value": "2024", - "numericOperator": "=" - } - ] - }, - limit=10 - ) - ``` - - - -### Example: Project's Active High-Priority Tasks - - - - ```typescript - const results = await client.search.documents({ - q: "implementation", - containerTags: ["project_alpha"], // Project isolation - filters: { - AND: [ - { - key: "status", - value: "completed", - negate: true // Not completed - }, - { - filterType: "numeric", - key: "priority", - value: "7", - numericOperator: ">=", - negate: false - }, - { - filterType: "array_contains", - key: "assignees", - value: "current_user" - } - ] - }, - limit: 20 - }); - ``` - - - ```python - results = client.search.documents( - q="implementation", - container_tags=["project_alpha"], # Project isolation - filters={ - "AND": [ - { - "key": "status", - "value": "completed", - "negate": True # Not completed - }, - { - "filterType": "numeric", - "key": "priority", - "value": "7", - "numericOperator": ">=", - "negate": False - }, - { - "filterType": "array_contains", - "key": "assignees", - "value": "current_user" - } - ] - }, - limit=20 - ) - ``` - - - -## Document-Specific Search - -Search within a single large document using the `docId` parameter: - - - - ```typescript - // Search within a specific book or manual - const results = await client.search.documents({ - q: "neural architecture", - docId: "doc_textbook_ml_2024", - limit: 20 - }); - ``` - - - ```python - # Search within a specific book or manual - results = client.search.documents( - q="neural architecture", - doc_id="doc_textbook_ml_2024", - limit=20 - ) - ``` - - - -Use this for: -- Large textbooks or manuals -- Multi-chapter books -- Long podcast transcripts -- Course materials - -## Validation & Limits - -### Metadata Key Requirements -- **Pattern**: `/^[a-zA-Z0-9_.-]+$/` -- **Allowed**: Letters, numbers, underscore, hyphen, dot -- **Max length**: 64 characters -- **No spaces or special characters** - -### Valid vs Invalid Keys -```javascript -// ✅ Valid keys -"user_email" -"created-date" -"version.number" -"priority_level_2" - -// ❌ Invalid keys -"user email" // Spaces not allowed -"created@date" // @ not allowed -"priority!" // ! not allowed -"very_long_key_name_that_exceeds_64_characters_limit" // Too long -``` - -### Query Complexity Limits -- **Maximum conditions**: 200 per query -- **Maximum nesting depth**: 8 levels -- **Container tag arrays**: Must match exactly - -## Troubleshooting - -### No Results Returned - - - - **Problem**: Container tags must match exactly as arrays. - - **Solution**: Verify the exact array structure. `["user_123"]` ≠ `["user_123", "project_1"]` - - - **Problem**: Keys are case-sensitive by default. - - **Solution**: Check exact key spelling and casing, or use `ignoreCase: true` for values. - - - **Problem**: Using `negate: true` when you meant `false`. - - **Solution**: Review your negate values. `false` = include, `true` = exclude. - - - -### Validation Errors - - - - **Error**: "Invalid metadata key: contains unsafe characters" - - **Solution**: Remove spaces, special characters. Use only alphanumeric, underscore, hyphen, dot. - - - **Error**: "Invalid filter structure" - - **Solution**: Ensure all conditions are wrapped in AND or OR arrays. - - - **Error**: "Invalid filter format" - - **Solution**: For `/v3/documents/list`, use `JSON.stringify()` on the filter object. - - - -### Performance Issues - - - - **Problem**: Complex nested OR conditions with many branches. - - **Solution**: Simplify logic, reduce nesting, or split into multiple queries. - - - **Problem**: "Query exceeds maximum complexity" - - **Solution**: Reduce conditions (max 200) or nesting depth (max 8). - - \ No newline at end of file diff --git a/apps/docs/search/parameters.mdx b/apps/docs/search/parameters.mdx index f7c2b264..f9df18da 100644 --- a/apps/docs/search/parameters.mdx +++ b/apps/docs/search/parameters.mdx @@ -60,7 +60,7 @@ These parameters work across all search endpoints: ``` - See [Metadata Filtering Guide](/search/filtering) for complete syntax and examples. + See [Metadata Filtering Guide](/concepts/filtering) for complete syntax and examples. diff --git a/apps/docs/style.css b/apps/docs/style.css new file mode 100644 index 00000000..b1a5db87 --- /dev/null +++ b/apps/docs/style.css @@ -0,0 +1,5 @@ +.dark img[src*="openai.svg"], +.dark img[src*="pipecat.svg"], +.dark img[src*="supermemory.svg"] { + filter: invert(1); +} diff --git a/apps/docs/supermemory-mcp/mcp.mdx b/apps/docs/supermemory-mcp/mcp.mdx index acf20f93..f317d920 100644 --- a/apps/docs/supermemory-mcp/mcp.mdx +++ b/apps/docs/supermemory-mcp/mcp.mdx @@ -1,6 +1,7 @@ --- title: "Overview" description: "Give your AI assistants persistent memory with the Model Context Protocol" +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. diff --git a/apps/docs/supermemory-mcp/setup.mdx b/apps/docs/supermemory-mcp/setup.mdx index 647c07f5..92180467 100644 --- a/apps/docs/supermemory-mcp/setup.mdx +++ b/apps/docs/supermemory-mcp/setup.mdx @@ -1,6 +1,7 @@ --- title: 'Setup and Usage' description: 'How to set up and use Supermemory MCP Server 4.0' +icon: 'settings' --- ## Quick Install (Recommended) diff --git a/apps/docs/update-delete-memories/overview.mdx b/apps/docs/update-delete-memories/overview.mdx index 926e2971..f7e53973 100644 --- a/apps/docs/update-delete-memories/overview.mdx +++ b/apps/docs/update-delete-memories/overview.mdx @@ -74,7 +74,7 @@ const client = new Supermemory({ const customId = 'user-note-001'; // First call creates memory -const created = await client.memories.add({ +const created = await client.add({ content: 'Initial content', customId: customId, metadata: { version: 1 } @@ -83,7 +83,7 @@ const created = await client.memories.add({ console.log('Created memory:', created.id); // Second call with same customId updates existing -const updated = await client.memories.add({ +const updated = await client.add({ content: 'Updated content', customId: customId, // Same customId = upsert metadata: { version: 2 } @@ -99,7 +99,7 @@ client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY")) custom_id = 'user-note-001' # First call creates memory -created = client.memories.add( +created = client.add( content='Initial content', custom_id=custom_id, metadata={'version': 1} @@ -108,7 +108,7 @@ created = client.memories.add( print(f'Created memory: {created.id}') # Second call with same customId updates existing -updated = client.memories.add( +updated = client.add( content='Updated content', custom_id=custom_id, # Same customId = upsert metadata={'version': 2} @@ -151,7 +151,7 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \ 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. diff --git a/apps/docs/user-profiles.mdx b/apps/docs/user-profiles.mdx new file mode 100644 index 00000000..a8de0874 --- /dev/null +++ b/apps/docs/user-profiles.mdx @@ -0,0 +1,266 @@ +--- +title: "User Profiles" +sidebarTitle: "User Profiles" +description: "Fetch and use automatically maintained user context" +icon: "user" +--- + +User profiles are extremely short summaries of context about an entity (Usually a user, but can be anything) which includes both the *static* facts about them, as well as a few recent episodes. + +> You can think of these as a dynamic compaction that's done by supermemory in real-time. + +This profile should be injected into the agent context for truly personalized experiences. To read more, visit [User profiles - Concept](/concepts/user-profiles) + +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. + + +## Quick Start + + + + ```typescript + import Supermemory from 'supermemory'; + + const client = new Supermemory(); + + const { profile } = await client.profile({ + containerTag: "user_123" + }); + + console.log(profile.static); // Long-term facts + console.log(profile.dynamic); // Recent context + ``` + + + ```python + from supermemory import Supermemory + + client = Supermemory() + + result = client.profile(container_tag="user_123") + + print(result.profile.static) # Long-term facts + print(result.profile.dynamic) # Recent context + ``` + + + ```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"}' + ``` + + + +**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" + ] + } +} +``` + +--- + +## Profile + Search + +Get profile and search results in one call by adding the `q` parameter: + + + + ```typescript + const result = await client.profile({ + containerTag: "user_123", + q: "deployment errors" + }); + + // Profile data + const { static: facts, dynamic: context } = result.profile; + + // Search results (only if q was provided) + const memories = result.searchResults?.results || []; + ``` + + + ```python + result = client.profile( + container_tag="user_123", + q="deployment errors" + ) + + # Profile data + facts = result.profile.static + context = result.profile.dynamic + + # Search results + memories = result.search_results.results if result.search_results else [] + ``` + + + +--- + +## Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `containerTag` | string | Yes | User/project identifier | +| `q` | string | No | Search query (includes search results in response) | +| `threshold` | 0-1 | No | Filter search results by relevance score | + +--- + +## Building Prompts + +The most common pattern — inject profile into your LLM's system prompt: + +```typescript +async function chat(userId: string, message: string) { + const { profile } = await client.profile({ containerTag: userId }); + + const systemPrompt = `You are assisting a user. + +ABOUT THE USER: +${profile.static?.join('\n') || 'No profile yet.'} + +CURRENT CONTEXT: +${profile.dynamic?.join('\n') || 'No recent activity.'} + +Personalize responses to their expertise and preferences.`; + + return llm.chat({ + messages: [ + { role: "system", content: systemPrompt }, + { role: "user", content: message } + ] + }); +} +``` + +--- + +## Full Context Pattern + +Get profile + query-specific memories in one call: + +```typescript +async function getContext(userId: string, query: string) { + const result = await client.profile({ + containerTag: userId, + q: query, + threshold: 0.6 + }); + + return ` +User Background: +${result.profile.static.join('\n')} + +Current Context: +${result.profile.dynamic.join('\n')} + +Relevant Memories: +${result.searchResults?.results.map(m => m.content).join('\n') || 'None'} + `; +} +``` + +--- + +## Framework Examples + + + ```typescript + async function withProfile(req, res, next) { + if (!req.user?.id) return next(); + + try { + const { profile } = await client.profile({ + containerTag: req.user.id + }); + req.userProfile = profile; + } catch (e) { + req.userProfile = null; + } + next(); + } + + app.use(withProfile); + + app.post('/chat', (req, res) => { + // req.userProfile available in all routes + }); + ``` + + + + ```typescript + // app/api/chat/route.ts + export async function POST(req: NextRequest) { + const { userId, message } = await req.json(); + + const { profile } = await client.profile({ + containerTag: userId + }); + + const response = await generateResponse(message, profile); + return NextResponse.json({ response }); + } + ``` + + + + ```typescript + import { withSupermemory } from "@supermemory/tools/ai-sdk" + import { openai } from "@ai-sdk/openai" + + // Profiles automatically injected + const model = withSupermemory(openai("gpt-4"), "user-123") + + const result = await generateText({ + model, + messages: [{ role: "user", content: "Help with my project" }] + }); + ``` + + See [AI SDK Integration](/integrations/ai-sdk) for details. + + +--- + +## Response Schema + +```typescript +interface ProfileResponse { + profile: { + static: string[]; // Long-term facts + dynamic: string[]; // Recent context + }; + searchResults?: { // Only if q parameter provided + results: SearchResult[]; + total: number; + timing: number; + }; +} +``` + +--- + +## Next Steps + +- [User Profiles Concept](/concepts/user-profiles) — Understand static vs dynamic +- [Ingesting Content](/add-memories) — Build profiles by adding content +- [AI SDK Integration](/integrations/ai-sdk) — Automatic profile injection diff --git a/apps/docs/user-profiles/examples.mdx b/apps/docs/user-profiles/examples.mdx index 496f905f..aa3b796b 100644 --- a/apps/docs/user-profiles/examples.mdx +++ b/apps/docs/user-profiles/examples.mdx @@ -362,6 +362,6 @@ const result = await generateText({ // 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 index 80acd1c2..160807fa 100644 --- a/apps/docs/user-profiles/overview.mdx +++ b/apps/docs/user-profiles/overview.mdx @@ -126,7 +126,7 @@ User asks: **"Can you help me debug this?"** See complete integration examples - + Use the AI SDK for automatic profile injection diff --git a/apps/docs/vibe-coding.mdx b/apps/docs/vibe-coding.mdx index 54b00321..0e1f42cd 100644 --- a/apps/docs/vibe-coding.mdx +++ b/apps/docs/vibe-coding.mdx @@ -2,7 +2,7 @@ title: "Vibe Coding Setup" description: "Automatic Supermemory integration using AI coding agents" icon: "zap" -sidebarTitle: "Automatic setup" +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. @@ -180,7 +180,7 @@ const messages = [ ] // After LLM responds: -await client.memories.add({ +await client.add({ content: `user: ${userMessage}\nassistant: ${response}`, containerTag: userId }) @@ -211,7 +211,7 @@ const messages = [ ] // Store the conversation -await client.memories.add({ +await client.add({ content: `user: ${userMessage}\nassistant: ${response}`, containerTag: userId }) @@ -372,11 +372,11 @@ The skill asks questions interactively and generates code for your specific setu Manual integration guide - + Deep dive into profiles - + Search modes and parameters diff --git a/apps/mcp/src/client.ts b/apps/mcp/src/client.ts index 7112e451..cadfa734 100644 --- a/apps/mcp/src/client.ts +++ b/apps/mcp/src/client.ts @@ -76,7 +76,7 @@ export class SupermemoryClient { content: string, ): Promise<{ id: string; status: string; containerTag: string }> { try { - const result = await this.client.memories.add({ + const result = await this.client.add({ content, containerTag: this.containerTag, metadata: { diff --git a/packages/ai-sdk/package.json b/packages/ai-sdk/package.json index 5e59fa5e..deae39ad 100644 --- a/packages/ai-sdk/package.json +++ b/packages/ai-sdk/package.json @@ -25,7 +25,7 @@ }, "main": "./dist/index.js", "module": "./dist/index.js", - "types": "./dist/index-CITmF79o.d.ts", + "types": "./dist/index-h2cm3lSK.d.ts", "exports": { ".": "./dist/index.js", "./package.json": "./package.json" diff --git a/packages/ai-sdk/src/tools.ts b/packages/ai-sdk/src/tools.ts index f04df10b..f5126863 100644 --- a/packages/ai-sdk/src/tools.ts +++ b/packages/ai-sdk/src/tools.ts @@ -90,7 +90,7 @@ export function supermemoryTools( try { const metadata: Record = {} - const response = await client.memories.add({ + const response = await client.add({ content: memory, containerTags, ...(Object.keys(metadata).length > 0 && { metadata }), diff --git a/packages/openai-sdk-python/src/supermemory_openai/middleware.py b/packages/openai-sdk-python/src/supermemory_openai/middleware.py index e2399bb6..4f6dc8ec 100644 --- a/packages/openai-sdk-python/src/supermemory_openai/middleware.py +++ b/packages/openai-sdk-python/src/supermemory_openai/middleware.py @@ -1,31 +1,31 @@ """Supermemory middleware for OpenAI clients.""" -from dataclasses import dataclass -from typing import Optional, Union, Any, Literal, cast import asyncio import os +from dataclasses import dataclass +from typing import Any, Literal, Optional, Union, cast -from openai import OpenAI, AsyncOpenAI +import supermemory +from openai import AsyncOpenAI, OpenAI from openai.types.chat import ( ChatCompletionMessageParam, ChatCompletionSystemMessageParam, ) -import supermemory -from .utils import ( - Logger, - create_logger, - get_last_user_message, - get_conversation_content, - convert_profile_to_markdown, - deduplicate_memories, -) from .exceptions import ( - SupermemoryConfigurationError, SupermemoryAPIError, + SupermemoryConfigurationError, SupermemoryMemoryOperationError, SupermemoryNetworkError, ) +from .utils import ( + Logger, + convert_profile_to_markdown, + create_logger, + deduplicate_memories, + get_conversation_content, + get_last_user_message, +) @dataclass @@ -75,7 +75,7 @@ async def supermemory_profile_search( raise SupermemoryAPIError( "Supermemory profile search failed", status_code=response.status, - response_text=error_text + response_text=error_text, ) data = await response.json() @@ -98,7 +98,7 @@ async def supermemory_profile_search( raise SupermemoryAPIError( "Supermemory profile search failed", status_code=response.status_code, - response_text=response.text + response_text=response.text, ) return SupermemoryProfileSearch(response.json()) @@ -146,9 +146,18 @@ async def add_system_prompt( logger.debug( "Memory deduplication completed", { - "static": {"original": memory_count_static, "deduplicated": len(deduplicated.static)}, - "dynamic": {"original": memory_count_dynamic, "deduplicated": len(deduplicated.dynamic)}, - "search_results": {"original": memory_count_search, "deduplicated": len(deduplicated.search_results)}, + "static": { + "original": memory_count_static, + "deduplicated": len(deduplicated.static), + }, + "dynamic": { + "original": memory_count_dynamic, + "deduplicated": len(deduplicated.dynamic), + }, + "search_results": { + "original": memory_count_search, + "deduplicated": len(deduplicated.search_results), + }, }, ) @@ -217,10 +226,10 @@ async def add_memory_tool( # Handle both sync and async supermemory clients try: - response = await client.memories.add(**add_params) + response = await client.add(**add_params) except TypeError: # If it's not awaitable, call it synchronously - response = client.memories.add(**add_params) + response = client.add(**add_params) logger.info( "Memory saved successfully", @@ -237,18 +246,14 @@ async def add_memory_tool( {"error": str(network_error)}, ) raise SupermemoryNetworkError( - "Failed to save memory due to network error", - network_error + "Failed to save memory due to network error", network_error ) except Exception as error: logger.error( "Error saving memory", {"error": str(error)}, ) - raise SupermemoryMemoryOperationError( - "Failed to save memory", - error - ) + raise SupermemoryMemoryOperationError("Failed to save memory", error) class SupermemoryOpenAIWrapper: @@ -271,16 +276,17 @@ class SupermemoryOpenAIWrapper: if not hasattr(supermemory, "Supermemory"): raise SupermemoryConfigurationError( "supermemory package is required but not found", - ImportError("supermemory package not installed") + ImportError("supermemory package not installed"), ) api_key = self._get_api_key() try: - self._supermemory_client: supermemory.Supermemory = supermemory.Supermemory(api_key=api_key) + self._supermemory_client: supermemory.Supermemory = supermemory.Supermemory( + api_key=api_key + ) except Exception as e: raise SupermemoryConfigurationError( - f"Failed to initialize Supermemory client: {e}", - e + f"Failed to initialize Supermemory client: {e}", e ) # Wrap the chat completions create method @@ -359,15 +365,24 @@ class SupermemoryOpenAIWrapper: try: if task_obj.exception() is not None: exception = task_obj.exception() - if isinstance(exception, (SupermemoryNetworkError, SupermemoryAPIError)): + if isinstance( + exception, + (SupermemoryNetworkError, SupermemoryAPIError), + ): self._logger.warn( "Background memory storage failed", - {"error": str(exception), "type": type(exception).__name__} + { + "error": str(exception), + "type": type(exception).__name__, + }, ) else: self._logger.error( "Unexpected error in background memory storage", - {"error": str(exception), "type": type(exception).__name__} + { + "error": str(exception), + "type": type(exception).__name__, + }, ) except asyncio.CancelledError: self._logger.debug("Memory storage task was cancelled") @@ -440,7 +455,7 @@ class SupermemoryOpenAIWrapper: # We're in an async context, log warning and skip memory saving self._logger.warn( "Cannot save memory in sync client from async context", - {"error": str(e)} + {"error": str(e)}, ) else: raise @@ -454,7 +469,7 @@ class SupermemoryOpenAIWrapper: # Unexpected errors should be investigated self._logger.error( "Unexpected error saving memory", - {"error": str(e), "type": type(e).__name__} + {"error": str(e), "type": type(e).__name__}, ) # Handle memory search and injection @@ -464,11 +479,14 @@ class SupermemoryOpenAIWrapper: self._logger.debug("No user message found, skipping memory search") return original_create(**kwargs) - self._logger.info("Starting memory search", { - "container_tag": self._container_tag, - "conversation_id": self._options.conversation_id, - "mode": self._options.mode, - }) + self._logger.info( + "Starting memory search", + { + "container_tag": self._container_tag, + "conversation_id": self._options.conversation_id, + "mode": self._options.mode, + }, + ) # Use asyncio.run() for memory search and injection try: @@ -495,7 +513,7 @@ class SupermemoryOpenAIWrapper: self._logger, self._options.mode, self._get_api_key(), - ) + ), ) enhanced_messages = future.result() else: @@ -517,20 +535,24 @@ class SupermemoryOpenAIWrapper: if not self._background_tasks: return - self._logger.debug(f"Waiting for {len(self._background_tasks)} background tasks to complete") + self._logger.debug( + f"Waiting for {len(self._background_tasks)} background tasks to complete" + ) try: if timeout is not None: await asyncio.wait_for( asyncio.gather(*self._background_tasks, return_exceptions=True), - timeout=timeout + timeout=timeout, ) else: await asyncio.gather(*self._background_tasks, return_exceptions=True) self._logger.debug("All background tasks completed") except asyncio.TimeoutError: - self._logger.warn(f"Background tasks did not complete within {timeout}s timeout") + self._logger.warn( + f"Background tasks did not complete within {timeout}s timeout" + ) # Cancel remaining tasks for task in self._background_tasks: if not task.done(): @@ -580,7 +602,9 @@ class SupermemoryOpenAIWrapper: else: raise except asyncio.TimeoutError: - self._logger.warn("Some background memory tasks did not complete on exit") + self._logger.warn( + "Some background memory tasks did not complete on exit" + ) self.cancel_background_tasks() def __getattr__(self, name: str) -> Any: diff --git a/packages/openai-sdk-python/src/supermemory_openai/tools.py b/packages/openai-sdk-python/src/supermemory_openai/tools.py index 111253cd..87c19428 100644 --- a/packages/openai-sdk-python/src/supermemory_openai/tools.py +++ b/packages/openai-sdk-python/src/supermemory_openai/tools.py @@ -1,14 +1,14 @@ """Supermemory tools for OpenAI function calling.""" import json -from typing import Dict, List, Optional, Union, TypedDict +from typing import Dict, List, Optional, TypedDict, Union +import supermemory from openai.types.chat import ( + ChatCompletionFunctionToolParam, ChatCompletionMessageToolCall, ChatCompletionToolMessageParam, - ChatCompletionFunctionToolParam, ) -import supermemory from supermemory.types import ( MemoryAddResponse, MemoryGetResponse, @@ -230,7 +230,7 @@ class SupermemoryTools: if metadata: add_params["metadata"] = metadata - response: MemoryAddResponse = await self.client.memories.add(**add_params) + response: MemoryAddResponse = await self.client.add(**add_params) return MemoryAddResult( success=True, diff --git a/packages/pipecat-sdk-python/src/supermemory_pipecat/service.py b/packages/pipecat-sdk-python/src/supermemory_pipecat/service.py index ab07e672..01bc03df 100644 --- a/packages/pipecat-sdk-python/src/supermemory_pipecat/service.py +++ b/packages/pipecat-sdk-python/src/supermemory_pipecat/service.py @@ -11,12 +11,11 @@ import os from typing import Any, Dict, List, Literal, Optional from loguru import logger -from pydantic import BaseModel, Field - from pipecat.frames.frames import Frame, LLMContextFrame, LLMMessagesFrame from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContextFrame from pipecat.processors.frame_processor import FrameDirection, FrameProcessor +from pydantic import BaseModel, Field from .exceptions import ( ConfigurationError, @@ -73,7 +72,9 @@ class SupermemoryPipecatService(FrameProcessor): search_limit: int = Field(default=10, ge=1) search_threshold: float = Field(default=0.1, ge=0.0, le=1.0) - system_prompt: str = Field(default="Based on previous conversations, I recall:\n\n") + system_prompt: str = Field( + default="Based on previous conversations, I recall:\n\n" + ) mode: Literal["profile", "query", "full"] = Field(default="full") def __init__( @@ -202,7 +203,9 @@ class SupermemoryPipecatService(FrameProcessor): messages: List of message dicts with 'role' and 'content' keys. """ if self._supermemory_client is None: - logger.warning("Supermemory client not initialized, skipping memory storage") + logger.warning( + "Supermemory client not initialized, skipping memory storage" + ) return if not messages: @@ -223,7 +226,7 @@ class SupermemoryPipecatService(FrameProcessor): if self.session_id: add_params["custom_id"] = f"{self.session_id}" - await self._supermemory_client.memories.add(**add_params) + await self._supermemory_client.add(**add_params) logger.debug(f"Successfully stored {len(messages)} messages in Supermemory") except Exception as e: @@ -317,16 +320,22 @@ class SupermemoryPipecatService(FrameProcessor): if latest_user_message: # Retrieve memories from Supermemory try: - memories_data = await self._retrieve_memories(latest_user_message) + memories_data = await self._retrieve_memories( + latest_user_message + ) self._enhance_context_with_memories( context, latest_user_message, memories_data ) except MemoryRetrievalError as e: - logger.warning(f"Memory retrieval failed, continuing without memories: {e}") + logger.warning( + f"Memory retrieval failed, continuing without memories: {e}" + ) # Store unsent messages (user and assistant only, skip system) storable_messages = [ - msg for msg in context_messages if msg["role"] in ("user", "assistant") + msg + for msg in context_messages + if msg["role"] in ("user", "assistant") ] unsent_messages = storable_messages[self._messages_sent_count :] diff --git a/packages/tools/src/ai-sdk.ts b/packages/tools/src/ai-sdk.ts index 8b893cd0..0f2d5fe0 100644 --- a/packages/tools/src/ai-sdk.ts +++ b/packages/tools/src/ai-sdk.ts @@ -87,7 +87,7 @@ export const addMemoryTool = ( try { const metadata: Record = {} - const response = await client.memories.add({ + const response = await client.add({ content: memory, containerTags, ...(Object.keys(metadata).length > 0 && { metadata }), diff --git a/packages/tools/src/claude-memory.ts b/packages/tools/src/claude-memory.ts index 54da77a1..0a755913 100644 --- a/packages/tools/src/claude-memory.ts +++ b/packages/tools/src/claude-memory.ts @@ -329,7 +329,7 @@ export class ClaudeMemoryTool { try { const normalizedId = this.normalizePathToCustomId(filePath) - const response = await this.client.memories.add({ + const response = await this.client.add({ content: fileText, customId: normalizedId, containerTags: this.containerTags, @@ -388,7 +388,7 @@ export class ClaudeMemoryTool { // Update the document const normalizedId = this.normalizePathToCustomId(filePath) - const updateResponse = await this.client.memories.add({ + const updateResponse = await this.client.add({ content: newContent, customId: normalizedId, containerTags: this.containerTags, @@ -447,7 +447,7 @@ export class ClaudeMemoryTool { // Update the document const normalizedId = this.normalizePathToCustomId(filePath) - await this.client.memories.add({ + await this.client.add({ content: newContent, customId: normalizedId, containerTags: this.containerTags, @@ -530,7 +530,7 @@ export class ClaudeMemoryTool { const newNormalizedId = this.normalizePathToCustomId(newPath) // Create new document with new path - await this.client.memories.add({ + await this.client.add({ content: originalContent, customId: newNormalizedId, containerTags: this.containerTags, diff --git a/packages/tools/src/openai/middleware.ts b/packages/tools/src/openai/middleware.ts index 4d030d0e..d390d841 100644 --- a/packages/tools/src/openai/middleware.ts +++ b/packages/tools/src/openai/middleware.ts @@ -363,7 +363,7 @@ const addMemoryTool = async ( } // Fallback to old behavior for non-conversation memories - const response = await client.memories.add({ + const response = await client.add({ content, containerTags: [containerTag], customId, diff --git a/packages/tools/src/openai/tools.ts b/packages/tools/src/openai/tools.ts index 4078df09..c0a3e25d 100644 --- a/packages/tools/src/openai/tools.ts +++ b/packages/tools/src/openai/tools.ts @@ -141,7 +141,7 @@ export function createAddMemoryFunction( try { const metadata: Record = {} - const response = await client.memories.add({ + const response = await client.add({ content: memory, containerTags, ...(Object.keys(metadata).length > 0 && { metadata }), diff --git a/packages/tools/src/vercel/middleware.ts b/packages/tools/src/vercel/middleware.ts index 43306934..8336b397 100644 --- a/packages/tools/src/vercel/middleware.ts +++ b/packages/tools/src/vercel/middleware.ts @@ -137,7 +137,7 @@ export const saveMemoryAfterResponse = async ( ? `${getConversationContent(params)} \n\n Assistant: ${assistantResponseText}` : `User: ${userMessage} \n\n Assistant: ${assistantResponseText}` - const response = await client.memories.add({ + const response = await client.add({ content, containerTags: [containerTag], customId,
Add content to see your knowledge graph