diff options
| author | Mahesh Sanikommu <[email protected]> | 2025-12-18 17:52:20 -0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-18 17:52:20 -0800 |
| commit | 1dd602c52b95fa4fdd6d6226f93ad0dc50f4538d (patch) | |
| tree | 615a4dbae523a37f3b8c778ca297c4a10f1e5f61 | |
| parent | fix: change support email to the one on slack (diff) | |
| download | supermemory-1dd602c52b95fa4fdd6d6226f93ad0dc50f4538d.tar.xz supermemory-1dd602c52b95fa4fdd6d6226f93ad0dc50f4538d.zip | |
feat(docs): v4 hybrid search parameter and examples (#621)
| -rw-r--r-- | apps/docs/search/examples/memory-search.mdx | 225 | ||||
| -rw-r--r-- | apps/docs/search/overview.mdx | 57 | ||||
| -rw-r--r-- | apps/docs/search/parameters.mdx | 22 | ||||
| -rw-r--r-- | apps/docs/search/response-schema.mdx | 101 |
4 files changed, 394 insertions, 11 deletions
diff --git a/apps/docs/search/examples/memory-search.mdx b/apps/docs/search/examples/memory-search.mdx index e3cfe7d6..c6d18b6e 100644 --- a/apps/docs/search/examples/memory-search.mdx +++ b/apps/docs/search/examples/memory-search.mdx @@ -464,9 +464,232 @@ Combining features for comprehensive results: </Tab> </Tabs> -## Comon Use Cases +## Hybrid Search Mode + +Hybrid search mode allows you to search both memories and document chunks in a single request. When `searchMode="hybrid"`, results contain objects with either a `memory` key (for memory results) or a `chunk` key (for chunk results). + +### Basic Hybrid Search + +<Tabs> + <Tab title="TypeScript"> + ```typescript + const results = await client.search.memories({ + q: "machine learning best practices", + searchMode: "hybrid", // Search memories + chunks + limit: 10 + }); + + // Handle mixed results + results.results.forEach(result => { + if ('memory' in result) { + console.log('Memory:', result.memory); + } else if ('chunk' in result) { + console.log('Chunk:', result.chunk); + console.log('From document:', result.documents?.[0]?.title); + } + }); + ``` + </Tab> + <Tab title="Python"> + ```python + results = client.search.memories( + q="machine learning best practices", + search_mode="hybrid", # Search memories + chunks + limit=10 + ) + + # Handle mixed results + for result in results.results: + if 'memory' in result: + print('Memory:', result['memory']) + elif 'chunk' in result: + print('Chunk:', result['chunk']) + print('From document:', result.get('documents', [{}])[0].get('title')) + ``` + </Tab> + <Tab title="cURL"> + ```bash + curl -X POST "https://api.supermemory.ai/v4/search" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "q": "machine learning best practices", + "searchMode": "hybrid", + "limit": 10 + }' + ``` + </Tab> +</Tabs> + +### When to Use Hybrid Mode + +Use hybrid mode when: +- You want comprehensive search across both memories and documents +- Memories might not exist for certain queries but document content is available +- You need flexibility to get either memory or document chunk results +- You want a single search endpoint that covers all content types + +Use memories-only mode (`searchMode="memories"`) when: +- You only need user memories and preferences +- You want faster, more focused results +- You're building a personalized chatbot that relies on user context + +### Handling Mixed Results + +When using hybrid mode, you'll receive mixed results. Here's how to process them: + +<Tabs> + <Tab title="TypeScript"> + ```typescript + const results = await client.search.memories({ + q: "quantum computing applications", + searchMode: "hybrid", + limit: 10 + }); + + // Separate memory and chunk results + const memoryResults = results.results.filter(r => 'memory' in r); + const chunkResults = results.results.filter(r => 'chunk' in r); + + console.log(`Found ${memoryResults.length} memories and ${chunkResults.length} chunks`); + + // Process memories + memoryResults.forEach(mem => { + console.log('Memory:', mem.memory); + console.log('Similarity:', mem.similarity); + }); + + // Process chunks + chunkResults.forEach(chunk => { + console.log('Chunk:', chunk.chunk); + console.log('Document:', chunk.documents?.[0]?.title); + console.log('Similarity:', chunk.similarity); + }); + ``` + </Tab> + <Tab title="Python"> + ```python + results = client.search.memories( + q="quantum computing applications", + search_mode="hybrid", + limit=10 + ) + + # Separate memory and chunk results + memory_results = [r for r in results.results if 'memory' in r] + chunk_results = [r for r in results.results if 'chunk' in r] + + print(f"Found {len(memory_results)} memories and {len(chunk_results)} chunks") + + # Process memories + for mem in memory_results: + print('Memory:', mem['memory']) + print('Similarity:', mem['similarity']) + + # Process chunks + for chunk in chunk_results: + print('Chunk:', chunk['chunk']) + print('Document:', chunk.get('documents', [{}])[0].get('title')) + print('Similarity:', chunk['similarity']) + ``` + </Tab> +</Tabs> + +### Hybrid Search with All Features + +Combining hybrid mode with other features: + +<Tabs> + <Tab title="TypeScript"> + ```typescript + const results = await client.search.memories({ + q: "research findings on AI", + searchMode: "hybrid", + containerTag: "research_team", + threshold: 0.7, + rerank: true, + include: { + documents: true, + relatedMemories: true, + summaries: true + }, + limit: 10 + }); + + // Results are automatically sorted by similarity + // Memory results have 'memory' field, chunk results have 'chunk' field + results.results.forEach(result => { + if ('memory' in result) { + // Memory result + console.log('Memory:', result.memory); + console.log('Context:', result.context); + } else { + // Chunk result + console.log('Chunk:', result.chunk); + console.log('Document:', result.documents?.[0]); + } + }); + ``` + </Tab> + <Tab title="Python"> + ```python + results = client.search.memories( + q="research findings on AI", + search_mode="hybrid", + container_tag="research_team", + threshold=0.7, + rerank=True, + include={ + "documents": True, + "relatedMemories": True, + "summaries": True + }, + limit=10 + ) + + # Results are automatically sorted by similarity + # Memory results have 'memory' field, chunk results have 'chunk' field + for result in results.results: + if 'memory' in result: + # Memory result + print('Memory:', result['memory']) + print('Context:', result.get('context')) + else: + # Chunk result + print('Chunk:', result['chunk']) + print('Document:', result.get('documents', [{}])[0]) + ``` + </Tab> + <Tab title="cURL"> + ```bash + curl -X POST "https://api.supermemory.ai/v4/search" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "q": "research findings on AI", + "searchMode": "hybrid", + "containerTag": "research_team", + "threshold": 0.7, + "rerank": true, + "include": { + "documents": true, + "relatedMemories": true, + "summaries": true + }, + "limit": 10 + }' + ``` + </Tab> +</Tabs> + +<Note> + **Important**: In hybrid mode, results are automatically merged and sorted by similarity score. Memory results and chunk results are deduplicated - if a chunk is already associated with a memory result, it won't appear as a separate chunk result. +</Note> + +## Common Use Cases - **Chatbots**: Basic search with container tag and low threshold - **Q&A Systems**: Add reranking for better relevance - **Knowledge Retrieval**: Include documents and summaries - **Real-time Search**: Skip rewriting and reranking for maximum speed +- **Hybrid Search**: Use `searchMode="hybrid"` when you need comprehensive search across both memories and documents diff --git a/apps/docs/search/overview.mdx b/apps/docs/search/overview.mdx index b6356202..575d87b5 100644 --- a/apps/docs/search/overview.mdx +++ b/apps/docs/search/overview.mdx @@ -194,33 +194,77 @@ Companies like Composio [Rube.app](https://rube.app) use memories search for let This endpoint works best for conversational AI use cases like chatbots. </Info> +**Hybrid Search Mode:** + +The `/v4/search` endpoint supports a `searchMode` parameter with two options: + +- **`"memories"`** (default): Searches only memory entries. Returns results with a `memory` key containing the memory content. +- **`"hybrid"`**: Searches memories first, then falls back to document chunks if needed. Returns mixed results where each result object has either a `memory` key (for memory results) or a `chunk` key (for chunk results from documents). + +<Note> + In hybrid mode, results are automatically merged by similarity score and deduplicated. Check for the presence of `memory` or `chunk` keys to distinguish result types. +</Note> + <Tabs> <Tab title="TypeScript"> ```typescript - // Memories search + // Memories search (default mode) const results = await client.search.memories({ q: "machine learning accuracy", limit: 5, containerTag: "research", threshold: 0.7, - rerank: true + rerank: true, + searchMode: "memories" // Default: only search memories + }); + + // Hybrid search (memories + chunks) + const hybridResults = await client.search.memories({ + q: "machine learning accuracy", + limit: 5, + containerTag: "research", + threshold: 0.7, + searchMode: "hybrid" // Search memories + fallback to chunks }); ``` </Tab> <Tab title="Python"> ```python - # Memories search + # Memories search (default mode) results = client.search.memories( q="machine learning accuracy", limit=5, container_tag="research", threshold=0.7, - rerank=True + rerank=True, + search_mode="memories" # Default: only search memories + ) + + # Hybrid search (memories + chunks) + hybrid_results = client.search.memories( + q="machine learning accuracy", + limit=5, + container_tag="research", + threshold=0.7, + search_mode="hybrid" # Search memories + fallback to chunks ) ``` </Tab> <Tab title="cURL"> ```bash + # Memories search (default mode) + curl -X POST "https://api.supermemory.ai/v4/search" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "q": "machine learning accuracy", + "limit": 5, + "containerTag": "research", + "threshold": 0.7, + "rerank": true, + }' + + # Hybrid search (memories + chunks) curl -X POST "https://api.supermemory.ai/v4/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ @@ -229,7 +273,8 @@ Companies like Composio [Rube.app](https://rube.app) use memories search for let "limit": 5, "containerTag": "research", "threshold": 0.7, - "rerank": true + "rerank": true, + "searchMode": "hybrid" }' ``` </Tab> @@ -283,7 +328,7 @@ Companies like Composio [Rube.app](https://rube.app) use memories search for let ``` -The `/v4/search` endpoint searches through and returns memories. +The `/v4/search` endpoint searches through and returns memories. With `searchMode="hybrid"`, it can also return document chunks when memories aren't found, providing comprehensive search coverage. ## Direct Document Retrieval diff --git a/apps/docs/search/parameters.mdx b/apps/docs/search/parameters.mdx index cd1030ae..f7c2b264 100644 --- a/apps/docs/search/parameters.mdx +++ b/apps/docs/search/parameters.mdx @@ -205,6 +205,28 @@ These parameters are specific to `client.search.memories()`: ``` </ParamField> +<ParamField query="searchMode" type="string" default="memories"> + **Search mode - memories only or hybrid search** + + Controls whether to search only memories or also include document chunks: + - **`"memories"`** (default): Searches only memory entries. Returns results with `memory` field. + - **`"hybrid"`**: Searches memories first, then falls back to document chunks if needed. Returns mixed results with either `memory` field (for memory results) or `chunk` field (for chunk results). + + <Note> + In hybrid mode, results are automatically merged and deduplicated. Results contain objects with either a `memory` key (for memory results) or a `chunk` key (for chunk results from document search). + </Note> + + ```typescript + searchMode: "memories" // Only search memories (default) + searchMode: "hybrid" // Search memories + fallback to chunks + ``` + + **When to use hybrid mode:** + - When you want comprehensive search across both memories and documents + - When memories might not exist for certain queries but document content is available + - When you need the flexibility to get either memory or document chunk results +</ParamField> + <ParamField query="containerTag" type="string"> **Filter by single container tag** diff --git a/apps/docs/search/response-schema.mdx b/apps/docs/search/response-schema.mdx index f9234787..b4f43ff4 100644 --- a/apps/docs/search/response-schema.mdx +++ b/apps/docs/search/response-schema.mdx @@ -114,6 +114,8 @@ Response from `client.search.documents()` and `client.search.execute()`: Response from `client.search.memories()`: +When `searchMode="memories"` (default), all results are memory entries: + ```json { "results": [ @@ -160,14 +162,101 @@ Response from `client.search.memories()`: } ``` +When `searchMode="hybrid"`, results can contain both memory entries and document chunks. **Memory results have a `memory` key, chunk results have a `chunk` key:** + +```json +{ + "results": [ + { + "id": "mem_xyz789", + "memory": "Complete memory content about quantum computing applications...", + "similarity": 0.87, + "metadata": { + "category": "research", + "topic": "quantum-computing" + }, + "updatedAt": "2024-01-18T09:15:00Z", + "version": 3, + "context": { + "parents": [], + "children": [] + }, + "documents": [ + { + "id": "doc_quantum_paper", + "title": "Quantum Computing Applications", + "type": "pdf", + "createdAt": "2024-01-10T08:00:00Z", + "updatedAt": "2024-01-10T08:00:00Z" + } + ] + }, + { + "id": "chunk_abc123", + "chunk": "This is a chunk of content from a document about quantum computing...", + "similarity": 0.82, + "metadata": { + "category": "research", + "source": "document" + }, + "updatedAt": "2024-01-15T10:30:00Z", + "version": 1, + "context": { + "parents": [], + "children": [] + }, + "documents": [ + { + "id": "doc_quantum_research", + "title": "Quantum Computing Research Paper", + "type": "pdf", + "metadata": { + "author": "Dr. Smith" + }, + "createdAt": "2024-01-15T10:30:00Z", + "updatedAt": "2024-01-15T10:30:00Z" + } + ] + } + ], + "timing": 198, + "total": 2 +} +``` + +<Note> + **Distinguishing Memory vs Chunk Results:** + + In hybrid mode, check which key exists on the result object: + - **Memory results**: Have a `memory` key (no `chunk` key) + - **Chunk results**: Have a `chunk` key (no `memory` key) + + ```typescript + // TypeScript example + results.results.forEach(result => { + if ('memory' in result) { + // This is a memory result + console.log('Memory:', result.memory); + } else if ('chunk' in result) { + // This is a chunk result + console.log('Chunk:', result.chunk); + } + }); + ``` +</Note> + ### Memory Result Fields <ResponseField name="id" type="string"> - Unique identifier for the memory entry. + Unique identifier for the memory entry or chunk ID. In hybrid mode, can be either a memory ID (e.g., `mem_xyz789`) or a chunk ID (e.g., `chunk_abc123`). +</ResponseField> + +<ResponseField name="memory" type="string" optional> + **Complete memory content**. Only present for memory results (when `searchMode="memories"` or when a memory result is returned in hybrid mode). This field is not present for chunk results. </ResponseField> -<ResponseField name="memory" type="string"> - **Complete memory content**. Unlike document search which returns chunks, memory search returns the full memory text. +<ResponseField name="chunk" type="string" optional> + **Chunk content from a document**. Only present for chunk results when `searchMode="hybrid"`. This field is not present for memory results. Contains the actual text content from the document chunk. </ResponseField> <ResponseField name="similarity" type="number" range="0-1"> @@ -189,7 +278,11 @@ Response from `client.search.memories()`: </ResponseField> <ResponseField name="version" type="number | null" optional> - Version number of this memory entry. Used for tracking memory evolution and relationships. + Version number of this memory entry. Used for tracking memory evolution and relationships. For chunk results, this is typically `1`. +</ResponseField> + +<ResponseField name="rootMemoryId" type="string | null" optional> + Root memory ID for memory entries. Only present for memory results. Always `null` for chunk results. </ResponseField> <ResponseField name="context" type="object" optional> |