From ca89d161cc6c1953ac51a3dfe2365b962aa33c10 Mon Sep 17 00:00:00 2001 From: sohamd22 <85427822+sohamd22@users.noreply.github.com> Date: Thu, 15 Oct 2026 18:52:40 +0000 Subject: [PATCH] docs(api): move v5 search and ingest options into the request body (#1808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes v5 search and recall docs that didn't match the API. - **Options in the URL.** Search examples passed `searchMode`/`limit` as query params, and ingest examples passed `dreaming`/`taskType` the same way. v5 rejects every query param on these routes with `400`. They now go in the JSON body (quickstart, rules, super-rag, recall/search). - **`include`, not `attach`.** Renamed the search option. Its `forgotten` flag also admits forgotten memories into the main results, not just related context. - **Search response.** Added the required `isInference`. `metadata` is always an object, and `system.createdAt` is optional. - **Search add-ons are billed.** `rewriteQuery` and `rerank` each bill one extra operation; the docs said "no extra cost". - **Removed claims that don't match current behavior:** - inferred memories being down-weighted in search; - AST code chunking via `code-chunk` (super-rag now describes how chunking actually works); - a 64-character metadata key limit. - **Smaller fixes:** - The namespace is the SDK's first argument; the docs called it a top-level key. - "No v5 Python SDK" was stale. - Memory review: `total` semantics, the internal review stamp, and the missing 403. Checked against the current API and the published SDKs (TS 5.0.1, Python 5.0.0). Legacy v3/v4 docs are unchanged apart from factual fixes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- apps/docs/concepts/filtering.mdx | 5 ++--- apps/docs/concepts/rules.mdx | 13 ++++++------ apps/docs/concepts/super-rag.mdx | 22 +++++--------------- apps/docs/quickstart.mdx | 24 ++++++++++++++-------- apps/docs/recall/memory-review.mdx | 25 +++++++++++------------ apps/docs/recall/search.mdx | 29 +++++++++++++++------------ apps/docs/snippets/api-v5-filters.mdx | 2 +- 7 files changed, 59 insertions(+), 61 deletions(-) diff --git a/apps/docs/concepts/filtering.mdx b/apps/docs/concepts/filtering.mdx index da2b513c..6beaa1aa 100644 --- a/apps/docs/concepts/filtering.mdx +++ b/apps/docs/concepts/filtering.mdx @@ -22,7 +22,7 @@ Both can be used independently or together for precise filtering. ## Namespaces -Namespaces create isolated memory spaces. Use them to separate memories by user, project, or any logical boundary. The namespace is part of the URL (`/ns/{namespace}/...`), so every SDK call takes it as a top-level key. +Namespaces create isolated memory spaces. Use them to separate memories by user, project, or any logical boundary. The namespace is part of the URL (`/ns/{namespace}/...`), so namespace-scoped SDK calls take it as the first argument. ### Adding Memories to a Namespace @@ -42,7 +42,7 @@ const results = await supermemory.search("user_123", { ``` -Each search is scoped to a single namespace. Passing `namespace: "user_123"` restricts results to memories stored in that namespace. +Each search is scoped to a single namespace. Passing `"user_123"` as the namespace restricts results to memories stored in that namespace. ### Recommended patterns @@ -336,7 +336,6 @@ const results = await supermemory.search("user_123", { // Scopes results to this ### Metadata key rules - Allowed characters: `a-z`, `A-Z`, `0-9`, `_`, `-`, `.` -- Max length: 64 characters - No spaces or special characters - Keys are literal: `customer.plan` is one key named `customer.plan`, not a nested path diff --git a/apps/docs/concepts/rules.mdx b/apps/docs/concepts/rules.mdx index dab3452a..4a55e898 100644 --- a/apps/docs/concepts/rules.mdx +++ b/apps/docs/concepts/rules.mdx @@ -30,7 +30,7 @@ Agents benefit most from having a _general_ idea of the topic alongside tools to Two things about this table that trip people up. -**"Remember" and "look up" are both supermemory, but different reads.** You [ingest documents](/ingestion/add-memories); the pipeline derives memories from them and maintains a profile per [namespace](/concepts/container-tags). `supermemory.search({ searchMode: "memories" })` recalls the derived facts. `supermemory.search({ searchMode: "chunks" })` recalls the source material itself. A support agent usually needs both: memories for "this customer runs self-hosted and already tried reinstalling", documents for the actual troubleshooting guide. +**"Remember" and "look up" are both supermemory, but different reads.** You [ingest documents](/ingestion/add-memories); the pipeline derives memories from them and maintains a profile per [namespace](/concepts/container-tags). `supermemory.search(namespace, { query, searchMode: "memories" })` recalls the derived facts. `supermemory.search(namespace, { query, searchMode: "chunks" })` recalls the source material itself. A support agent usually needs both: memories for "this customer runs self-hosted and already tried reinstalling", documents for the actual troubleshooting guide. **Supermemory is not your system of record.** There's no SQL over memories, no joins, no aggregates, no querying by primary key. Keep transactional data in your database, and ingest the narrative *around* it ("the customer disputed invoice #4821 and churned over it") so your AI understands what the rows mean. @@ -56,10 +56,10 @@ client.add( ``` ```bash curl -curl -X POST "https://api.supermemory.ai/ns/test/document?taskType=superrag" \ +curl -X POST "https://api.supermemory.ai/ns/test/document" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{ "content": "testing" }' + -d '{ "content": "testing", "taskType": "superrag" }' ``` @@ -86,10 +86,10 @@ results = client.search( ``` ```bash curl -curl -X POST "https://api.supermemory.ai/ns/test/search?searchMode=hybrid" \ +curl -X POST "https://api.supermemory.ai/ns/test/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{ "query": "test" }' + -d '{ "query": "test", "searchMode": "hybrid" }' ``` @@ -252,11 +252,12 @@ results = client.search( ``` ```bash curl -curl -X POST "https://api.supermemory.ai/ns/org-supermemory/search?searchMode=chunks" \ +curl -X POST "https://api.supermemory.ai/ns/org-supermemory/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "preferred language", + "searchMode": "chunks", "filter": { "field": "team", "operator": "eq", "value": "Research" } }' ``` diff --git a/apps/docs/concepts/super-rag.mdx b/apps/docs/concepts/super-rag.mdx index 50c4568a..4e1d40e6 100644 --- a/apps/docs/concepts/super-rag.mdx +++ b/apps/docs/concepts/super-rag.mdx @@ -33,7 +33,7 @@ No chunking strategies to configure. No embedding models to choose. It just work By default, every `supermemory.add()` call runs on the **memory** path (`taskType: "memory"`): Supermemory chunks and embeds the content for retrieval, *and* runs it through the memory pipeline — extracting facts, updating the profile, and linking it into the knowledge graph. -If you're ingesting content that's purely reference material — documentation, a large PDF, a knowledge base article — and you don't need Supermemory to derive personal facts or update a profile from it, set `taskType: "superrag"` (a query parameter, so a top-level key in the SDK). It skips the memory pipeline entirely and only does the chunk → embed → index work needed to make the content searchable. +If you're ingesting content that's purely reference material — documentation, a large PDF, a knowledge base article — and you don't need Supermemory to derive personal facts or update a profile from it, set `taskType: "superrag"` in the request body. It skips the memory pipeline entirely and only does the chunk → embed → index work needed to make the content searchable. @@ -53,10 +53,10 @@ client.add( ``` ```bash cURL -curl -X POST "https://api.supermemory.ai/ns/docs_kb/document?taskType=superrag" \ +curl -X POST "https://api.supermemory.ai/ns/docs_kb/document" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{ "content": "..." }' + -d '{ "content": "...", "taskType": "superrag" }' ``` @@ -100,21 +100,9 @@ PDFs and documents are chunked by **semantic sections** — headers, paragraphs, ### Code -Code is chunked using [code-chunk](https://github.com/supermemoryai/code-chunk), our open-source library that understands AST (Abstract Syntax Tree) boundaries: +When content is recognized as Markdown, fenced code blocks are kept whole when they fit in a chunk. Larger blocks are split and re-wrapped in the original fence, including its language tag. Overlap can contain part of a previous line, so chunks are not guaranteed to be independently valid code. -- 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. +Raw source files and content not recognized as Markdown use plain-text chunking. A lone fenced block may not be enough for automatic Markdown detection. ### Web pages diff --git a/apps/docs/quickstart.mdx b/apps/docs/quickstart.mdx index 9d528c3a..d0b95173 100644 --- a/apps/docs/quickstart.mdx +++ b/apps/docs/quickstart.mdx @@ -97,13 +97,14 @@ print(conv.id, conv.status) # e.g. "queued" ``` ```bash curl -curl -X POST "https://api.supermemory.ai/ns/user_4f8a/document?dreaming=instant" \ +curl -X POST "https://api.supermemory.ai/ns/user_4f8a/document" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "user: Just got back from Tokyo — the team offsite went great.\nassistant: Glad it went well! Anything stand out?\nuser: Sarah presented the Q3 roadmap at the offsite.\nassistant: Sounds like a big moment for her.\nuser: She is being promoted to VP of Product.\nassistant: Congrats to Sarah — that is huge.\nuser: I need a gift idea for my VP of Product.\nassistant: Happy to help brainstorm something personal.", "id": "chat_offsite_2026", - "metadata": { "type": "conversation" } + "metadata": { "type": "conversation" }, + "dreaming": "instant" }' ``` @@ -164,13 +165,14 @@ print(doc.id, doc.status) ``` ```bash curl -curl -X POST "https://api.supermemory.ai/ns/user_4f8a/document?taskType=superrag" \ +curl -X POST "https://api.supermemory.ai/ns/user_4f8a/document" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "# Team notes — gifts & recognition\n\nWhen someone is promoted to VP or above, the company recommends a thoughtful gift in the $75–$150 range. Experiences tied to recent team milestones land better than generic swag.\n\nFor product leadership, books on platform strategy or a dinner near the last offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.", "id": "doc_gift_policy", - "metadata": { "type": "document", "source": "handbook" } + "metadata": { "type": "document", "source": "handbook" }, + "taskType": "superrag" }' ``` @@ -253,10 +255,14 @@ for hit in rag.results: ``` ```bash curl -curl -X POST "https://api.supermemory.ai/ns/user_4f8a/search?searchMode=chunks&limit=3" \ +curl -X POST "https://api.supermemory.ai/ns/user_4f8a/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{ "query": "gift ideas for a VP promotion after a Tokyo offsite" }' + -d '{ + "query": "gift ideas for a VP promotion after a Tokyo offsite", + "searchMode": "chunks", + "limit": 3 + }' ``` @@ -300,12 +306,14 @@ print(memories.to_json()) ``` ```bash curl -curl -X POST "https://api.supermemory.ai/ns/user_4f8a/search?searchMode=memories&limit=5" \ +curl -X POST "https://api.supermemory.ai/ns/user_4f8a/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "What gift should I get, and why?", - "include": { "related": true } + "searchMode": "memories", + "include": { "related": true }, + "limit": 5 }' ``` diff --git a/apps/docs/recall/memory-review.mdx b/apps/docs/recall/memory-review.mdx index 818cd066..d246e24a 100644 --- a/apps/docs/recall/memory-review.mdx +++ b/apps/docs/recall/memory-review.mdx @@ -7,8 +7,8 @@ icon: "/icons/hugeicons/check-list.svg" Supermemory's graph derives new facts from patterns across your existing memories (see [graph memory](/concepts/graph-memory)). Because nobody stated these facts -directly, they are flagged as inferred (`isInference: true`) and **down-weighted in -search until someone confirms them**. +directly, they are flagged as inferred (`isInference: true`) until someone confirms +them. These two endpoints let you build a review flow on top of that queue: list the inferred memories awaiting review, then approve, decline or undo a decision on each one. @@ -20,19 +20,17 @@ These endpoints are scoped to a single [namespace](/concepts/container-tags) path parameter. -## How review affects ranking +## What review changes -While a memory is unreviewed and inferred it is down-weighted in search, so the -engine's guesses rank below facts you stated explicitly. Reviewing it resolves that -either way: +Reviewing an inferred memory resolves it either way: | Action | Result | Effect on search | |--------|--------|------------------| -| **Approve** | `isInference` cleared | Ranks like a stated fact — no longer down-weighted | +| **Approve** | `isInference` cleared | Stays in search, no longer flagged as inferred | | **Decline** | `isForgotten` set | Removed from search entirely — a rejected guess is forgotten | -| **Undo** | back to unreviewed | Returns to the queue; inferred and down-weighted again | +| **Undo** | back to unreviewed | Returns to the queue, flagged as inferred again | -A reviewed memory is stamped with `reviewStatus` in its metadata so it drops out of the +A reviewed memory gets an internal review stamp in its metadata so it drops out of the review queue (declined memories also leave search, since they're forgotten). **Undo** clears that stamp — and un-forgets a declined memory — bringing it back. @@ -98,7 +96,7 @@ GET /v3/container-tags/{containerTag}/inferred | `memories[].createdAt` | string | ISO 8601 timestamp | | `memories[].updatedAt` | string | ISO 8601 timestamp | | `memories[].metadata` | object \| null | Arbitrary metadata stored on the memory | -| `total` | number | Count of unreviewed inferred memories returned | +| `total` | number | Total unreviewed inferred memories in the queue; can exceed the number returned in `memories` | The queue returns up to **50** memories, ordered by `parentCount` descending (most @@ -166,8 +164,8 @@ The reject action is named **`decline`**. There is no `reject` value. **Action semantics:** -- **`approve`** — Promote the memory: clears `isInference`, so it ranks like a stated - fact instead of a down-weighted guess. Stamps `reviewStatus: "approved"`. +- **`approve`** — Promote the memory: clears `isInference`, so it's treated as a + confirmed fact. Stamps `reviewStatus: "approved"`. - **`decline`** — Reject the suggestion: the memory is **forgotten** (`isForgotten: true`) and stamped `reviewStatus: "declined"`, so it leaves both search and the review queue. @@ -198,6 +196,7 @@ The reject action is named **`decline`**. There is no `reject` value. | Status | When | |--------|------| | `401` | Missing or invalid authentication | +| `403` | Your key can't access this namespace, or lacks write access to it | | `404` | The namespace or memory was not found in your organization | | `409` | The memory isn't reviewable for this action — it's not an inferred memory, or there's no prior review to undo | @@ -286,4 +285,4 @@ a request and the memory simply stays in the queue for a later session. - [Graph Memory](/concepts/graph-memory) — How inferred (`derive`) memories are created - [Memory Operations](/recall/memory-operations) — Forget memories -- [Search](/recall/search) — How inferred memories are ranked in results +- [Search](/recall/search) — Results flag inferred memories with `isInference` diff --git a/apps/docs/recall/search.mdx b/apps/docs/recall/search.mdx index 38d4d858..cc5817bc 100644 --- a/apps/docs/recall/search.mdx +++ b/apps/docs/recall/search.mdx @@ -12,7 +12,7 @@ Search through your memories and documents with a single API call. Each search r -**TypeScript SDK:** one call, `supermemory.search(namespace, { query, searchMode })`. `searchMode` (`"memories"`, `"chunks"`, or `"hybrid"`) picks what comes back. There is no v5 Python SDK yet; the Python tab shows the legacy client. +**SDKs:** one call, `supermemory.search(namespace, { query, searchMode })` in TypeScript or `client.search(namespace, query=..., search_mode=...)` in Python. `searchMode` (`"memories"`, `"chunks"`, or `"hybrid"`) picks what comes back. ## Quick start @@ -54,10 +54,10 @@ Search through your memories and documents with a single API call. Each search r ```bash - curl -X POST "https://api.supermemory.ai/ns/user_123/search?searchMode=hybrid&limit=5" \ + curl -X POST "https://api.supermemory.ai/ns/user_123/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ - -d '{ "query": "machine learning" }' + -d '{ "query": "machine learning", "searchMode": "hybrid", "limit": 5 }' ``` @@ -72,6 +72,7 @@ Search through your memories and documents with a single API call. Each search r "similarity": 0.91, "metadata": { "topic": "interests" }, "isLatest": true, + "isInference": false, "system": { "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T10:30:00.000Z" } }, { @@ -80,6 +81,7 @@ Search through your memories and documents with a single API call. Each search r "similarity": 0.87, "metadata": { "source": "onboarding_doc" }, "isLatest": true, + "isInference": false, "system": { "createdAt": "2024-01-14T09:15:00.000Z", "updatedAt": "2024-01-14T09:15:00.000Z" } } ], @@ -95,7 +97,7 @@ In hybrid mode, results contain either a `memory` field (extracted facts) or a ` ## Parameters -`namespace` is the URL path. Every other option goes in the JSON body (the second argument in the SDKs). +`namespace` is the URL path. Every other option goes in the JSON body: the second argument in TypeScript, or keyword arguments in Python. Search takes no query-string parameters; sending any returns `400`. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| @@ -104,10 +106,10 @@ In hybrid mode, results contain either a `memory` field (extracted facts) or a ` | `searchMode` | string | `"hybrid"` | `"hybrid"` (recommended), `"memories"`, or `"chunks"` | | `limit` | number | 10 | Max results (max 100) | | `threshold` | 0-1 | 0.3 | Similarity cutoff (higher = fewer, better results) | -| `rerank` | string | `"none"` | `"none"`, `"order"` (re-score for relevance, +100ms), or `"aggregate"` | -| `rewriteQuery` | boolean | false | Generate multiple rewrites, search all of them, and merge results. No extra cost, but adds latency | +| `rerank` | string | `"none"` | `"none"`, `"order"` (re-score for relevance, +100ms), or `"aggregate"`. Successful reranking or aggregation can bill one extra [operation](/overview/billing#what-is-an-operation); setting the option alone does not guarantee it runs | +| `rewriteQuery` | boolean | false | Generate multiple rewrites, search all of them, and merge results. Adds latency and can bill one extra [operation](/overview/billing#what-is-an-operation) when rewriting runs successfully | | `filter` | object | — | Metadata filter expression. See [Filtering](#filtering) | -| `include` | object | — | `{ documents, related, forgotten }` — opt in to extra context per result | +| `include` | object | all `false` | `{ documents, related, forgotten }` — opt in to extra context per result | Defaults changed from v4: `searchMode` was `memories` and is now `hybrid`; `threshold` was `0.6` and is now `0.3`. Set both explicitly if you are comparing against v4 results. @@ -196,9 +198,9 @@ await supermemory.search("user_123", { query: "...", threshold: 0.8 }); ### Attachments -- `attach.documents` adds the most relevant source document to each result. -- `attach.related` adds parent, child, and sibling memories (see [graph memory](/concepts/graph-memory)). -- `attach.forgotten` allows forgotten memories in related context. By default, search excludes memories that have been forgotten or have passed their `forgetAfter` expiration. +- `include.documents` adds the most recently updated source document to each result when one is available. +- `include.related` adds parent, child, and sibling memories (see [graph memory](/concepts/graph-memory)). +- `include.forgotten` lets forgotten and expired memories appear in results. By default, search excludes memories that have been forgotten or have passed their `forgetAfter` expiration. ```typescript await supermemory.search("user_123", { @@ -238,10 +240,11 @@ async function getContext(userId: string, message: string) { memory?: string; // Present for memory results chunk?: string; // Present for document chunk results similarity: number; // 0-1 - metadata: object | null; + metadata: Record; // {} when none isLatest: boolean; - system: { createdAt: string; updatedAt: string }; - included?: { // Only when you pass attach + isInference: boolean; // false for chunks + system: { createdAt?: string; updatedAt: string }; + included?: { // Only when you pass include document?: object; related?: { parents: object[]; children: object[]; siblings: object[] }; }; diff --git a/apps/docs/snippets/api-v5-filters.mdx b/apps/docs/snippets/api-v5-filters.mdx index 9e7e7ab3..2a96cbd8 100644 --- a/apps/docs/snippets/api-v5-filters.mdx +++ b/apps/docs/snippets/api-v5-filters.mdx @@ -83,7 +83,7 @@ await supermemory.search("user_1", { ``` -`filter` is a typed object under `body`, not a JSON string. The same shape works in `supermemory.list` and `supermemory.profile`. Keys are literal: `customer.plan` is one field name, not a nested path. +`filter` is a typed object in the request body (a field of the options object in the SDKs), not a JSON string. The same shape works in `supermemory.list` and `supermemory.profile`. Keys are literal: `customer.plan` is one field name, not a nested path. ### Deterministic conversion