mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-01 02:01:40 +00:00
Merge c6fd728981 into cfa6c7cb17
This commit is contained in:
commit
df308e16c6
24 changed files with 1234 additions and 0 deletions
|
|
@ -218,6 +218,23 @@
|
|||
{
|
||||
"group": "Migration Guides",
|
||||
"pages": [
|
||||
{
|
||||
"group": "V3/V4 to V5",
|
||||
"icon": "arrow-up-right",
|
||||
"pages": [
|
||||
"migration/api-v5",
|
||||
"migration/api-v5-document-writes",
|
||||
"migration/api-v5-document-updates",
|
||||
"migration/api-v5-document-reads",
|
||||
"migration/api-v5-recall",
|
||||
"migration/api-v5-profiles",
|
||||
"migration/api-v5-memory-forgetting",
|
||||
"migration/api-v5-settings",
|
||||
"migration/api-v5-organization",
|
||||
"migration/api-v5-filters",
|
||||
"migration/api-v5-rollout"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "From another provider",
|
||||
"icon": "truck",
|
||||
|
|
|
|||
11
apps/docs/migration/api-v5-document-reads.mdx
Normal file
11
apps/docs/migration/api-v5-document-reads.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Reading and deleting content on V5"
|
||||
description: "Fetching documents, listing resources, and deleting documents or memories"
|
||||
sidebarTitle: "Reading content"
|
||||
---
|
||||
|
||||
import ContentManagement from "/snippets/api-v5-content-management.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<ContentManagement />
|
||||
11
apps/docs/migration/api-v5-document-updates.mdx
Normal file
11
apps/docs/migration/api-v5-document-updates.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Updating documents and files on V5"
|
||||
description: "Pick deliberately between appending, replacing, and touching only metadata"
|
||||
sidebarTitle: "Updating documents"
|
||||
---
|
||||
|
||||
import DocumentUpdates from "/snippets/api-v5-document-updates.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<DocumentUpdates />
|
||||
11
apps/docs/migration/api-v5-document-writes.mdx
Normal file
11
apps/docs/migration/api-v5-document-writes.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Writing documents on V5"
|
||||
description: "Single, batch, and file ingestion that keeps legacy append semantics"
|
||||
sidebarTitle: "Ingesting documents"
|
||||
---
|
||||
|
||||
import DocumentIngestion from "/snippets/api-v5-document-ingestion.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<DocumentIngestion />
|
||||
11
apps/docs/migration/api-v5-filters.mdx
Normal file
11
apps/docs/migration/api-v5-filters.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Metadata filters on V5"
|
||||
description: "Turning loose legacy filter objects into expressions the server validates"
|
||||
sidebarTitle: "Filter expressions"
|
||||
---
|
||||
|
||||
import Filters from "/snippets/api-v5-filters.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<Filters />
|
||||
11
apps/docs/migration/api-v5-memory-forgetting.mdx
Normal file
11
apps/docs/migration/api-v5-memory-forgetting.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Forgetting memories on V5"
|
||||
description: "Exact and semantic deletion now share a single response contract"
|
||||
sidebarTitle: "Forgetting memories"
|
||||
---
|
||||
|
||||
import MemoryForgetting from "/snippets/api-v5-memory-forgetting.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<MemoryForgetting />
|
||||
11
apps/docs/migration/api-v5-organization.mdx
Normal file
11
apps/docs/migration/api-v5-organization.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Organization settings on V5"
|
||||
description: "What remains is the shared context string and a read-only namespace count"
|
||||
sidebarTitle: "Organization context"
|
||||
---
|
||||
|
||||
import Organization from "/snippets/api-v5-organization.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<Organization />
|
||||
11
apps/docs/migration/api-v5-profiles.mdx
Normal file
11
apps/docs/migration/api-v5-profiles.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Profiles and buckets on V5"
|
||||
description: "Profiles no longer take search parameters; buckets get their own resource"
|
||||
sidebarTitle: "Profiles & buckets"
|
||||
---
|
||||
|
||||
import Profiles from "/snippets/api-v5-profiles.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<Profiles />
|
||||
11
apps/docs/migration/api-v5-recall.mdx
Normal file
11
apps/docs/migration/api-v5-recall.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Searching on V5"
|
||||
description: "Modes, filters, attachments, changed defaults, and response readers"
|
||||
sidebarTitle: "Searching"
|
||||
---
|
||||
|
||||
import Search from "/snippets/api-v5-search.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<Search />
|
||||
11
apps/docs/migration/api-v5-rollout.mdx
Normal file
11
apps/docs/migration/api-v5-rollout.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Checking parity, then rolling out V5"
|
||||
description: "Establish behavioral parity, account for intended differences, and cut over safely"
|
||||
sidebarTitle: "Parity and rollout"
|
||||
---
|
||||
|
||||
import Rollout from "/snippets/api-v5-rollout.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<Rollout />
|
||||
11
apps/docs/migration/api-v5-settings.mdx
Normal file
11
apps/docs/migration/api-v5-settings.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: "Container tags become namespaces"
|
||||
description: "Listing namespaces, editing their settings, deleting them, and moving their content"
|
||||
sidebarTitle: "Namespace lifecycle"
|
||||
---
|
||||
|
||||
import Namespaces from "/snippets/api-v5-namespaces.mdx";
|
||||
|
||||
## Migration details
|
||||
|
||||
<Namespaces />
|
||||
63
apps/docs/migration/api-v5.mdx
Normal file
63
apps/docs/migration/api-v5.mdx
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
title: "Moving a V3/V4 integration onto V5"
|
||||
description: "Move existing API integrations onto the namespace-scoped V5 surface"
|
||||
sidebarTitle: "V3/V4 to V5"
|
||||
icon: "arrow-up-right"
|
||||
---
|
||||
|
||||
import Overview from "/snippets/api-v5-overview.mdx";
|
||||
import DocumentIngestion from "/snippets/api-v5-document-ingestion.mdx";
|
||||
import DocumentUpdates from "/snippets/api-v5-document-updates.mdx";
|
||||
import ContentManagement from "/snippets/api-v5-content-management.mdx";
|
||||
import Search from "/snippets/api-v5-search.mdx";
|
||||
import Profiles from "/snippets/api-v5-profiles.mdx";
|
||||
import MemoryForgetting from "/snippets/api-v5-memory-forgetting.mdx";
|
||||
import Namespaces from "/snippets/api-v5-namespaces.mdx";
|
||||
import Organization from "/snippets/api-v5-organization.mdx";
|
||||
import Filters from "/snippets/api-v5-filters.mdx";
|
||||
import Rollout from "/snippets/api-v5-rollout.mdx";
|
||||
import Completion from "/snippets/api-v5-completion.mdx";
|
||||
|
||||
<Overview />
|
||||
|
||||
## Document ingestion
|
||||
|
||||
<DocumentIngestion />
|
||||
|
||||
## Document updates
|
||||
|
||||
<DocumentUpdates />
|
||||
|
||||
## Content management
|
||||
|
||||
<ContentManagement />
|
||||
|
||||
## Search
|
||||
|
||||
<Search />
|
||||
|
||||
## Profiles and buckets
|
||||
|
||||
<Profiles />
|
||||
|
||||
## Memory forgetting
|
||||
|
||||
<MemoryForgetting />
|
||||
|
||||
## Namespaces
|
||||
|
||||
<Namespaces />
|
||||
|
||||
## Organization settings
|
||||
|
||||
<Organization />
|
||||
|
||||
## Typed filters
|
||||
|
||||
<Filters />
|
||||
|
||||
## Verification and rollout
|
||||
|
||||
<Rollout />
|
||||
|
||||
<Completion />
|
||||
29
apps/docs/snippets/api-v5-completion.mdx
Normal file
29
apps/docs/snippets/api-v5-completion.mdx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
## Agent migration prompt
|
||||
|
||||
```text
|
||||
Move this repository off the legacy Supermemory V3/V4 API and onto V5. Begin by
|
||||
taking inventory: list every call site still targeting a legacy route. Then work
|
||||
through the per-domain guides linked from this page. Address exactly one
|
||||
namespace in each request. Where a default differs between the two versions,
|
||||
state it in the request rather than relying on whatever the server supplies.
|
||||
Bring response readers up to date as well. Back the change with contract tests
|
||||
that exercise old and new side by side. Leave application routes unprefixed, and
|
||||
leave connector routes alone. When an operation has been dropped, name it as
|
||||
dropped rather than manufacturing a stand-in.
|
||||
```
|
||||
|
||||
## Operations without a direct replacement
|
||||
|
||||
- **Direct memory creation and version updates** (`POST /v4/memories`,
|
||||
`PATCH /v4/memories`): ingest or replace a source document instead.
|
||||
- **Organization bucket suggestion** (`POST /v3/settings/suggest-buckets`) and
|
||||
**organization reset** (`POST /v3/settings/reset`): not part of the V5 public
|
||||
surface.
|
||||
- **Connector routes** that still use `/v3`: unchanged; do not rewrite them.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Authentication](/authentication) — unchanged bearer keys
|
||||
- [Search guide](/recall/search)
|
||||
- [Memory operations](/recall/memory-operations)
|
||||
- [API reference](/api-reference/overview) — legacy V3/V4 reference
|
||||
105
apps/docs/snippets/api-v5-content-management.mdx
Normal file
105
apps/docs/snippets/api-v5-content-management.mdx
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
In V5, retrieving, listing, and deleting all happen inside one namespace you name
|
||||
explicitly.
|
||||
|
||||
### Retrieve a document and its derived context
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
GET /v3/documents/{id}
|
||||
GET /v3/documents/{id}/chunks
|
||||
```
|
||||
|
||||
```bash V5
|
||||
GET /ns/{namespace}/document/{id}?attach=chunks&attach=memories
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Supply `attach` more than once to pull in chunks, memories, or both. An
|
||||
attachment you never asked for is simply **missing** from the payload, whereas one
|
||||
you did ask for that found nothing comes back as an **empty array**. The
|
||||
difference is real: `result.chunks === undefined` and `result.chunks.length === 0`
|
||||
do not mean the same thing.
|
||||
|
||||
The lifecycle fields have moved beneath `system`:
|
||||
|
||||
```json
|
||||
{"system":{"status":"done","createdAt":"...","updatedAt":"..."}}
|
||||
```
|
||||
|
||||
Legacy `GET /v3/documents/{id}` returned `status`, `createdAt`, and `updatedAt`
|
||||
as top-level fields, and needed a separate `GET /v3/documents/{id}/chunks` call
|
||||
for chunk data. V5 folds both into one request.
|
||||
|
||||
### List documents, chunks, or memories
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
POST /v3/documents/list
|
||||
POST /v4/memories/list
|
||||
```
|
||||
|
||||
```bash V5
|
||||
POST /ns/{namespace}/list/{type}?page=1&limit=100&sort=createdAt&order=desc
|
||||
{}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Give `type` one of `documents`, `chunks`, or `memories`. Paging and ordering move
|
||||
into the **query string**; the body carries nothing beyond an optional `filter`.
|
||||
|
||||
Whichever type you ask for, the response carries `documents`, `chunks`,
|
||||
`memories`, and `pagination` — but only the array you selected has entries in it.
|
||||
Code that used to pull `memories` out of a document list has to read `documents`
|
||||
now.
|
||||
|
||||
<Note>
|
||||
This is the one place where the legacy and V5 shapes diverge most sharply.
|
||||
`ListMemoriesQuerySchema` in this repository takes `page`, `limit`, `sort`,
|
||||
`order`, and a **stringified** `filters` value in the query string; V5 keeps
|
||||
the paging controls in the query string but moves filtering into a typed body
|
||||
field.
|
||||
</Note>
|
||||
|
||||
### Delete documents
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
DELETE /v3/documents/{id}
|
||||
DELETE /v3/documents/bulk
|
||||
```
|
||||
|
||||
```bash V5
|
||||
DELETE /ns/{namespace}/document
|
||||
{"ids":["doc_1","external_id_2"]}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
The V5 array accepts **1–100** Supermemory or caller-defined IDs. Inspect both
|
||||
`deletedCount` **and** per-ID `errors`: HTTP success can still include partial
|
||||
failures. The legacy bulk schema capped `ids` at 100 as well, so the limit is
|
||||
unchanged — but the legacy single-delete route is gone, and one call now covers
|
||||
both cases.
|
||||
|
||||
### Forget memories
|
||||
|
||||
| Legacy intent | V5 operation |
|
||||
| --- | --- |
|
||||
| Forget exact IDs | `DELETE /ns/{namespace}/memories` with `{"ids":[...]}` |
|
||||
| Find memories by meaning | `DELETE /ns/{namespace}/memories/semantic` with `{"query":"...","dryRun":true}` |
|
||||
|
||||
Both answer with `{ count, matches, errors }`. To delete semantically without
|
||||
drift, preview under `dryRun: true`, inspect the returned IDs, and send that exact
|
||||
list to the exact-ID endpoint.
|
||||
|
||||
The full dry-run, approval, response, and audit flow lives in
|
||||
[memory forgetting](./api-v5-memory-forgetting).
|
||||
|
||||
### Verification
|
||||
|
||||
- Assert that requested-but-empty attachments are `[]` while omitted attachments
|
||||
are absent.
|
||||
- Paginate each resource type until `currentPage >= totalPages`; confirm
|
||||
unselected arrays stay empty.
|
||||
- Verify chunk rows carry their parent `documentId`.
|
||||
- Try a document delete that only partly succeeds, and a semantic dry run.
|
||||
- Verify an ID cannot read, list, or delete content outside its namespace.
|
||||
91
apps/docs/snippets/api-v5-document-ingestion.mdx
Normal file
91
apps/docs/snippets/api-v5-document-ingestion.mdx
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
V5 moves document scope into the URL and keeps a repeated caller-supplied ID attached to one evolving document instead of creating a new one each time.
|
||||
|
||||
### Rename common fields
|
||||
|
||||
| Legacy | V5 | Location |
|
||||
| --- | --- | --- |
|
||||
| `containerTag` | `{namespace}` | Path |
|
||||
| `customId` | `id` | JSON body |
|
||||
| `entityContext` | `supportingContext` | JSON / form body |
|
||||
| `filterByMetadata` | `group` | JSON / form body |
|
||||
| `documentDate` | `date` | JSON / form body |
|
||||
| `taskType`, `dreaming` | unchanged | Query string |
|
||||
|
||||
In the legacy schema these live in `MemoryUpdateSchema` (`customId`,
|
||||
`entityContext`, `metadata`, `containerTags`) and are sent in the request body.
|
||||
In V5 the scope leaves the body entirely and becomes a path segment, so a single
|
||||
request can only ever address one namespace.
|
||||
|
||||
### Add or append one document
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
POST /v3/documents
|
||||
{"content":"new turn","customId":"conv_1","containerTag":"user_1"}
|
||||
```
|
||||
|
||||
```bash V5
|
||||
POST /ns/user_1/document?dreaming=dynamic
|
||||
{"content":"new turn","id":"conv_1"}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
The response is still an acceptance result carrying `id` and `status`. Repeating
|
||||
the V5 request with the same `id: "conv_1"` adds or diffs the new content into
|
||||
that document — it does **not** silently replace the canonical source.
|
||||
|
||||
### Batch ingestion
|
||||
|
||||
<CodeGroup>
|
||||
```json Legacy
|
||||
{"documents":["first","second"],"containerTag":"user_1"}
|
||||
```
|
||||
|
||||
```json V5
|
||||
{"documents":[{"content":"first","id":"doc_1"},{"content":"second","id":"doc_2"}]}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Post that V5 body to `POST /ns/user_1/document/batch`. The array holds anything
|
||||
from **1** to **600** document objects. Namespace, `taskType`, and processing mode
|
||||
apply once for the whole request, while content, ID, context, metadata, grouping,
|
||||
and date are set per item.
|
||||
|
||||
Results come back in submission order. Read `success`, `failed`, and every entry
|
||||
of `results` — a single batch may mix accepted and rejected documents, so a `200`
|
||||
on its own proves nothing.
|
||||
|
||||
### File ingestion
|
||||
|
||||
`POST /v3/documents/file` becomes `POST /ns/{namespace}/document/file`. Keep
|
||||
sending `multipart/form-data`:
|
||||
|
||||
| Part | Encoding |
|
||||
| --- | --- |
|
||||
| `file` | Binary file |
|
||||
| `supportingContext`, `date` | Plain strings |
|
||||
| `metadata`, `group` | JSON-encoded strings |
|
||||
| `fileType`, `mimeType` | Query parameters, when inference is not enough |
|
||||
|
||||
The API acknowledges the file once it is durably accepted. Extraction, indexing,
|
||||
and memory formation continue asynchronously — poll the document rather than
|
||||
assuming the first response means processing is complete.
|
||||
|
||||
### Processing choices
|
||||
|
||||
- `taskType=memory` extracts long-term memories; `taskType=superrag` indexes
|
||||
source context without generating memories.
|
||||
- `dreaming=dynamic` (the default) groups related documents so memories form
|
||||
from coherent units rather than one isolated entry at a time.
|
||||
- `dreaming=instant` handles documents one at a time and adds one billable
|
||||
operation for each of them.
|
||||
|
||||
### Verification
|
||||
|
||||
- Ingest text, a public URL, and a file, then wait for each document to reach a
|
||||
terminal processing state.
|
||||
- Repeat a caller-defined ID and confirm append/diff behavior rather than
|
||||
replacement.
|
||||
- Post a batch in which some documents succeed and some fail; check that the
|
||||
result order holds and that per-item errors are reported.
|
||||
- Confirm metadata and grouping are still filterable after processing completes.
|
||||
95
apps/docs/snippets/api-v5-document-updates.mdx
Normal file
95
apps/docs/snippets/api-v5-document-updates.mdx
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
V5 makes the difference between *adding* new information and *replacing* the canonical source explicit. Legacy `PATCH /v3/documents/{id}` overloaded both meanings, so pick the write deliberately.
|
||||
|
||||
### Choose the correct write
|
||||
|
||||
| Intent | Operation | Content behavior |
|
||||
| --- | --- | --- |
|
||||
| Add information to a stable caller ID | `POST /ns/{namespace}/document` | Append / diff |
|
||||
| Replace text or URL content | `PATCH /ns/{namespace}/document/{id}` | Replace and reprocess |
|
||||
| Update only supporting fields | Same `PATCH`, without `content` | Canonical content unchanged |
|
||||
| Replace a source file and its user metadata | `POST /ns/{namespace}/document/file/{id}` | Full replacement and reprocess |
|
||||
| Partially update a file or its supporting fields | `PATCH /ns/{namespace}/document/file/{id}` | Omitted fields unchanged |
|
||||
|
||||
### Update text or URL content
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
PATCH /v3/documents/doc_1
|
||||
{"content":"corrected source","metadata":{"revision":2}}
|
||||
```
|
||||
|
||||
```bash V5
|
||||
PATCH /ns/user_1/document/doc_1?dreaming=dynamic
|
||||
{"content":"corrected source","metadata":{"revision":2}}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You may send any non-empty selection from `content`, `supportingContext`,
|
||||
`metadata`, `group`, and `date`. Once `content` is present it becomes the new
|
||||
canonical source — which means facts that only the previous source supported can
|
||||
vanish when the document is reprocessed.
|
||||
|
||||
<Warning>
|
||||
Replacing `content` is not a metadata edit. If you only want to re-label a
|
||||
document, send `metadata` / `group` / `date` and omit `content` entirely.
|
||||
</Warning>
|
||||
|
||||
### Replace a file-backed document
|
||||
|
||||
```bash
|
||||
POST /ns/user_1/document/file/doc_1?dreaming=dynamic
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
file=@corrected.pdf
|
||||
metadata={"revision":2}
|
||||
```
|
||||
|
||||
`file` is mandatory on `POST`, and the call swaps out the canonical source along
|
||||
with the user-controlled metadata, grouping, context, and date. Any supporting
|
||||
field you leave out is **cleared**. Reach for this when the request you are
|
||||
sending is the whole new state of the file-backed document.
|
||||
|
||||
### Partially update a file-backed document
|
||||
|
||||
```bash
|
||||
PATCH /ns/user_1/document/file/doc_1?dreaming=dynamic
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
metadata={"reviewed":true}
|
||||
```
|
||||
|
||||
`PATCH` touches nothing beyond the fields you actually send. Send `file` to swap
|
||||
the source while the supporting fields you omit survive, or drop `file` entirely
|
||||
for a change confined to metadata, group, context, or date. Note the encoding
|
||||
split: `metadata` and `group` travel as JSON-encoded strings, whereas
|
||||
`supportingContext` and `date` are plain strings.
|
||||
|
||||
<Warning>
|
||||
V5 exposes no public `PUT /ns/{namespace}/document/file/{id}`. For a full
|
||||
replacement use `POST`; for a partial one use `PATCH`.
|
||||
</Warning>
|
||||
|
||||
### IDs and scope
|
||||
|
||||
The path `id` may be the Supermemory document ID **or** your caller-defined ID.
|
||||
It is resolved only inside `{namespace}`. An ID from another namespace is not a
|
||||
cross-namespace update mechanism — the request is rejected or not found rather
|
||||
than reaching across the boundary.
|
||||
|
||||
### Processing and conflicts
|
||||
|
||||
Content or file replacement is accepted before downstream processing finishes. A
|
||||
document that is still processing, a namespace conflict, or a conflicting
|
||||
internal file path can return `409`. Retry only after the conflicting operation
|
||||
reaches a terminal state.
|
||||
|
||||
### Verification
|
||||
|
||||
- Patch metadata alone and confirm the document content and its derived facts are
|
||||
unchanged.
|
||||
- Patch content, then check that the replacement source is canonical once
|
||||
processing finishes.
|
||||
- Replace a file with `POST` and confirm omitted user metadata is cleared.
|
||||
- Patch a file-backed document and confirm omitted fields survive.
|
||||
- Try the same ID against a different namespace; the update should be rejected or
|
||||
come back not found.
|
||||
109
apps/docs/snippets/api-v5-filters.mdx
Normal file
109
apps/docs/snippets/api-v5-filters.mdx
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
V5 uses one optional **singular** `filter` field for search, profiles, and list
|
||||
operations, replacing the loosely-typed `filters` object.
|
||||
|
||||
### Why the legacy shape was hard to migrate
|
||||
|
||||
In this repository the legacy filter type is deliberately permissive:
|
||||
|
||||
```ts
|
||||
export const SearchFiltersSchema = z
|
||||
.object({
|
||||
AND: z.array(z.unknown()).optional(),
|
||||
OR: z.array(z.unknown()).optional(),
|
||||
})
|
||||
.or(z.record(z.unknown()))
|
||||
```
|
||||
|
||||
`z.array(z.unknown())` means the individual conditions are **unvalidated**. The
|
||||
only place their intended shape is written down is an OpenAPI example and a
|
||||
`// TODO: Improve filter schema` comment above `ListMemoriesQuerySchema`. Any
|
||||
condition that "looked right" was accepted at the edge and interpreted
|
||||
downstream. V5 replaces that with a discriminated union the server can reject.
|
||||
|
||||
### Shape
|
||||
|
||||
```ts
|
||||
type Filter =
|
||||
| { field: string; operator: "eq" | "neq"; value: string; caseSensitive?: boolean }
|
||||
| { field: string; operator: "eq" | "neq"; value: number | boolean }
|
||||
| { field: string; operator: "gt" | "gte" | "lt" | "lte"; value: number }
|
||||
| { field: string; operator: "contains" | "notContains"; value: string; caseSensitive?: boolean }
|
||||
| { field: string; operator: "arrayContains" | "arrayNotContains"; value: string }
|
||||
| { operator: "and" | "or"; operands: Filter[] };
|
||||
```
|
||||
|
||||
A field name may be built from letters, numbers, `_`, `.`, and `-`. An expression
|
||||
may nest at most **five levels** deep and carry at most **200 operands** in a
|
||||
single logical group.
|
||||
|
||||
### Operator mapping
|
||||
|
||||
| Legacy condition | V5 predicate |
|
||||
| --- | --- |
|
||||
| `{ key, value }` | `{ field: key, operator: "eq", value }` |
|
||||
| `negate: true` equality | `operator: "neq"` |
|
||||
| `filterType: "string_contains"` | `operator: "contains"` |
|
||||
| contains + `negate: true` | `operator: "notContains"` |
|
||||
| `filterType: "array_contains"` | `operator: "arrayContains"` |
|
||||
| array contains + `negate: true` | `operator: "arrayNotContains"` |
|
||||
| numeric `=` / numeric `=` + `negate: true` | `eq` / `neq` with a JSON number |
|
||||
| numeric `>`, `>=`, `<`, `<=` | `gt`, `gte`, `lt`, `lte` |
|
||||
| `AND` / `OR` arrays | lowercase `and` / `or` with `operands` |
|
||||
| `ignoreCase: true` | `caseSensitive: false` |
|
||||
|
||||
### Before and after
|
||||
|
||||
<CodeGroup>
|
||||
```json Legacy
|
||||
{
|
||||
"AND": [
|
||||
{ "key": "category", "value": "research" },
|
||||
{ "key": "score", "value": 0.8, "filterType": "numeric", "numericOperator": ">=" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json V5
|
||||
{
|
||||
"operator": "and",
|
||||
"operands": [
|
||||
{ "field": "category", "operator": "eq", "value": "research" },
|
||||
{ "field": "score", "operator": "gte", "value": 0.8 }
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Deterministic conversion
|
||||
|
||||
Apply these steps in order. They are mechanical on purpose — a codemod should be
|
||||
able to do them without judgement calls.
|
||||
|
||||
1. Rename the outer `filters` field to `filter`.
|
||||
2. Recursively replace `AND` / `OR` objects with `{ operator, operands }`.
|
||||
3. The legacy `key` becomes `field`.
|
||||
4. Convert legacy flags (`negate`, `numericOperator`, `filterType`) into one
|
||||
explicit operator.
|
||||
5. Keep numeric values as JSON **numbers**, not numeric strings.
|
||||
6. Delete the legacy `filterType`, `negate`, `numericOperator`, and `ignoreCase`
|
||||
keys.
|
||||
|
||||
<Warning>
|
||||
Step 5 is the step most likely to be missed. Three schemas in this repository
|
||||
carry the same trap — `ListMemoriesQuerySchema`, `SearchRequestSchema`
|
||||
(`packages/validation/api.ts:414`), and `Searchv4RequestSchema`
|
||||
(`packages/validation/api.ts:508`) each ship an example that passes
|
||||
`"value": "1742745777"`, a numeric comparison written as a **string**. Every
|
||||
`gt`/`gte`/`lt`/`lte` operator in V5's union demands a JSON number, so a
|
||||
straight rename will fail validation.
|
||||
</Warning>
|
||||
|
||||
### Verification
|
||||
|
||||
- Compare result IDs for equality, inequality, contains, numeric, array, nested
|
||||
`AND`, and nested `OR` fixtures.
|
||||
- Add negative tests: legacy shapes, empty `operands`, incompatible value types,
|
||||
and unknown keys must all return `400`.
|
||||
- Confirm an omitted `filter` preserves unfiltered behavior.
|
||||
- Test one fixture at the nesting limit and one beyond it, to pin the five-level
|
||||
bound.
|
||||
93
apps/docs/snippets/api-v5-memory-forgetting.mdx
Normal file
93
apps/docs/snippets/api-v5-memory-forgetting.mdx
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
Forgetting in V5 acts on a single namespace, and an exact-ID request and a
|
||||
semantic request come back in the same result envelope.
|
||||
|
||||
### Choose exact or semantic forgetting
|
||||
|
||||
| Intent | V5 operation |
|
||||
| --- | --- |
|
||||
| Forget reviewed memory IDs | `DELETE /ns/{namespace}/memories` |
|
||||
| Find memories by meaning | `DELETE /ns/{namespace}/memories/semantic` |
|
||||
|
||||
The legacy API split these across two differently shaped endpoints:
|
||||
`DELETE /v4/memories` (identify by `id` **or** exact `content`, plus a `reason`)
|
||||
and `POST /v4/memories/forget-matching` (semantic `query` or explicit `ids`, with
|
||||
`dryRun`, `threshold`, and `maxForget`). V5 normalizes both onto one response
|
||||
contract.
|
||||
|
||||
### Forget exact IDs
|
||||
|
||||
```bash
|
||||
DELETE /ns/user_1/memories
|
||||
Content-Type: application/json
|
||||
|
||||
{"ids":["mem_1","mem_2"]}
|
||||
```
|
||||
|
||||
The count runs from **1** to **500** IDs. Your successes arrive under `matches`;
|
||||
anything missing or ineligible lands in `errors`. A 2xx status therefore does not
|
||||
prove that every ID you named was actually forgotten.
|
||||
|
||||
### Preview a semantic request
|
||||
|
||||
```bash
|
||||
DELETE /ns/user_1/memories/semantic
|
||||
Content-Type: application/json
|
||||
|
||||
{"query":"outdated home address","dryRun":true}
|
||||
```
|
||||
|
||||
With `dryRun: true` the request only selects — memory state is left **untouched**.
|
||||
With `dryRun: false` it removes whatever the selection resolves to at the moment
|
||||
the request runs.
|
||||
|
||||
### Avoid selection drift
|
||||
|
||||
```text
|
||||
semantic request with dryRun: true
|
||||
|
|
||||
v
|
||||
review matches[].id
|
||||
|
|
||||
v
|
||||
exact DELETE with reviewed IDs
|
||||
```
|
||||
|
||||
Use this workflow whenever a human or a policy must approve the exact set.
|
||||
Re-running the semantic request with `dryRun: false` can select a **different**
|
||||
set if memories changed after the preview.
|
||||
|
||||
<Warning>
|
||||
Do not assume the semantic endpoint is idempotent with respect to your earlier
|
||||
preview. The legacy `forget-matching` route had the same property, but the
|
||||
legacy docs described the two-step preview flow as optional; in V5 it is the
|
||||
recommended path for any deletion a reviewer has to sign off on.
|
||||
</Warning>
|
||||
|
||||
### Read the normalized response
|
||||
|
||||
```json
|
||||
{
|
||||
"count": 1,
|
||||
"matches": [{ "id": "mem_1", "memory": "Old address" }],
|
||||
"errors": [{ "id": "mem_2", "error": "Memory not found" }]
|
||||
}
|
||||
```
|
||||
|
||||
The value of `count` is by definition the length of `matches`. Dry-run and
|
||||
applied semantic requests share this shape, so the response body on its own will
|
||||
not reveal which mode produced it — record the mode next to your audit entry.
|
||||
|
||||
### Removed memory-write routes
|
||||
|
||||
V5 offers nothing in place of direct V4 memory creation or version updates. Feed
|
||||
source material in through the document routes and rewrite the canonical document
|
||||
whenever the underlying facts change.
|
||||
|
||||
### Verification
|
||||
|
||||
- Try ID sets that are all-success, partially successful, duplicated, unknown,
|
||||
and drawn from across namespaces.
|
||||
- A dry run should leave every matched memory recallable.
|
||||
- Forget the reviewed IDs exactly, then check that ordinary recall no longer
|
||||
surfaces them.
|
||||
- Log the request mode alongside the audit trail for semantic operations.
|
||||
86
apps/docs/snippets/api-v5-namespaces.mdx
Normal file
86
apps/docs/snippets/api-v5-namespaces.mdx
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
V5 renames the public isolation boundary from *container tag* to *namespace*.
|
||||
Existing values remain valid identifiers — no stored data rename is required.
|
||||
|
||||
### Endpoint mapping
|
||||
|
||||
| Legacy | V5 |
|
||||
| --- | --- |
|
||||
| `GET /v3/container-tags/list` | `GET /namespaces` |
|
||||
| `GET /v3/container-tags/{tag}` | `GET /ns/{namespace}` |
|
||||
| `PATCH /v3/container-tags/{tag}` | `PATCH /ns/{namespace}` |
|
||||
| `DELETE /v3/container-tags/{tag}` | `DELETE /ns/{namespace}` |
|
||||
| Merge container tags | `DELETE /ns/{source}` with `{"moveTo":"target"}` |
|
||||
|
||||
`GET /ns` also works and answers the same way as `GET /namespaces`; new code
|
||||
should standardize on the longer form.
|
||||
|
||||
### List namespaces
|
||||
|
||||
Each entry now exposes `id`, `namespace`, `documentCount`, `memoryCount`,
|
||||
nullable `description`, and `system.createdAt` / `system.updatedAt`. If a reader
|
||||
of yours still looks for `containerTag`, top-level timestamps, or the internal
|
||||
settings blobs, it needs to change.
|
||||
|
||||
<Note>
|
||||
The legacy list response in this repository is a flat array whose entries carry
|
||||
`id`, `name`, `containerTag`, `createdAt`, `updatedAt`, `isExperimental`,
|
||||
`emoji`, `isNova`, and `visibility`. V5 replaces `containerTag` with
|
||||
`namespace`, nests the timestamps under `system`, and drops the
|
||||
project/consumer distinction fields from the public shape.
|
||||
</Note>
|
||||
|
||||
### Read and update settings
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
PATCH /v3/container-tags/project_alpha
|
||||
{"entityContext":"Research project for distributed systems"}
|
||||
```
|
||||
|
||||
```bash V5
|
||||
PATCH /ns/project_alpha
|
||||
{"supportingContext":"Research project for distributed systems"}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
The public `GET` and `PATCH` shapes contain only `namespace`, `supportingContext`,
|
||||
and lifecycle timestamps. Profile buckets have their own `/profile/buckets`
|
||||
resource and are **not** namespace settings.
|
||||
|
||||
Passing `supportingContext: null` wipes whatever context is stored. You cannot
|
||||
simply leave the field out — `PATCH` demands at least one supported setting.
|
||||
|
||||
### Permanently delete a namespace
|
||||
|
||||
```bash
|
||||
DELETE /ns/project_alpha
|
||||
{}
|
||||
```
|
||||
|
||||
Omit `moveTo` and the delete runs synchronously: you get `200` back along with
|
||||
`deletedDocumentsCount` and `deletedMemoriesCount`. Namespace and content are
|
||||
both gone.
|
||||
|
||||
### Move then remove a namespace
|
||||
|
||||
```bash
|
||||
DELETE /ns/project_alpha
|
||||
{"moveTo":"project_archive"}
|
||||
```
|
||||
|
||||
You get `202` back with `status: "queued"` and an `operationId`. Source and
|
||||
destination must not be the same namespace. A `202` here means the move was
|
||||
queued, not that it finished.
|
||||
|
||||
Where legacy merge took several sources at once, V5 takes **one source per
|
||||
request**. Chain the moves and log each one separately.
|
||||
|
||||
### Verification
|
||||
|
||||
- Check that existing container-tag values still resolve when used as namespace
|
||||
paths.
|
||||
- Compare namespace counts against namespace-scoped document and memory lists.
|
||||
- A permanent delete should return final counts; a move should return `202`.
|
||||
- Confirm a restricted caller can neither read nor change namespaces beyond its
|
||||
own scope.
|
||||
- Confirm only organization-authorized callers can change settings or lifecycle.
|
||||
76
apps/docs/snippets/api-v5-organization.mdx
Normal file
76
apps/docs/snippets/api-v5-organization.mdx
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
What survives into V5 is the single organization-wide context string that steers
|
||||
memory formation. The administrative knobs and the profile-bucket mutation
|
||||
endpoints are gone from this resource.
|
||||
|
||||
### Endpoint mapping
|
||||
|
||||
| Legacy | V5 |
|
||||
| --- | --- |
|
||||
| `GET /v3/settings` | `GET /organization` |
|
||||
| `PATCH /v3/settings` | `PATCH /organization` |
|
||||
| `filterPrompt` | `organizationalContext` |
|
||||
|
||||
### Read organization settings
|
||||
|
||||
```bash
|
||||
GET /organization
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"organizationalContext": "Acme builds security tools for enterprises",
|
||||
"namespaceCount": 42
|
||||
}
|
||||
```
|
||||
|
||||
Any reader you have for a legacy setting that is absent from this allowlisted
|
||||
payload should be deleted. `namespaceCount` is read-only information; `PATCH`
|
||||
will not move it.
|
||||
|
||||
### Update organization context
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
PATCH /v3/settings
|
||||
{"filterPrompt":"Acme builds security tools for enterprises"}
|
||||
```
|
||||
|
||||
```bash V5
|
||||
PATCH /organization
|
||||
{"organizationalContext":"Acme builds security tools for enterprises"}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
The write is exhaustive — whatever you supply becomes the context, fully
|
||||
**replacing** what was there. Passing `null` clears it; an empty string is
|
||||
refused.
|
||||
|
||||
An organization administrator is required for these writes. A `403` means the
|
||||
caller is not one — it is not an invitation to fall back to namespace context
|
||||
quietly.
|
||||
|
||||
### Removed public operations
|
||||
|
||||
- There is no organization-settings route for profile-bucket mutation.
|
||||
- Bucket suggestion (`POST /v3/settings/suggest-buckets`) is not part of V5.
|
||||
- Organization data reset (`POST /v3/settings/reset`) is not part of V5.
|
||||
- Buckets belonging to a namespace live under
|
||||
`/ns/{namespace}/profile/buckets`.
|
||||
|
||||
<Warning>
|
||||
The legacy `OrganizationSettingsSchema` in this repository carries connection
|
||||
credentials (`googleDriveClientId`, `notionClientId`, `onedriveClientId`, and
|
||||
their secrets and enablement flags) alongside the filtering fields. Those are
|
||||
**not** part of the public V5 `/organization` response. If your code read them
|
||||
from `GET /v3/settings`, move that configuration to your own secret store or to
|
||||
the connector setup flow.
|
||||
</Warning>
|
||||
|
||||
### Verification
|
||||
|
||||
- Diff the V5 context against the legacy `filterPrompt` before you cut over.
|
||||
- Write the context, rewrite it, then clear it.
|
||||
- Check that `namespaceCount` matches what `GET /namespaces` reports for the same
|
||||
credentials.
|
||||
- Verify non-admin callers receive `403` on `PATCH`.
|
||||
- Check that nothing downstream still depends on the fields V5 dropped.
|
||||
90
apps/docs/snippets/api-v5-overview.mdx
Normal file
90
apps/docs/snippets/api-v5-overview.mdx
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
V5 keeps the same ingestion and recall workflows as V3/V4, but makes scope explicit in the URL, consolidates routes that used to overlap, and tightens request and response types.
|
||||
|
||||
<Warning>
|
||||
This is a **breaking API migration**. Changing only the URL is not enough: fields moved between path, query, and body, search defaults changed, response envelopes changed, and a few legacy operations have no V5 replacement at all.
|
||||
</Warning>
|
||||
|
||||
The API base URL and your bearer keys do not change. V5 application routes are **unversioned** — `/v5/reference` identifies the documentation version, not an API path prefix. Do not put `/v5` in application request paths.
|
||||
|
||||
## Recommended migration process
|
||||
|
||||
<Steps>
|
||||
<Step title="Inventory every legacy call site">
|
||||
Grep your integration for `/v3/`, `/v4/`, `containerTag`, `containerTags`,
|
||||
`customId`, `entityContext`, `filterByMetadata`, `filters`, and any legacy
|
||||
SDK method wrappers. Record each one with its caller and its purpose.
|
||||
</Step>
|
||||
<Step title="Resolve exactly one namespace per request">
|
||||
Move the legacy `containerTag` value into the `/ns/{namespace}` path
|
||||
segment. Never infer scope from a document or memory ID, and never send
|
||||
more than one namespace in a single V5 request.
|
||||
</Step>
|
||||
<Step title="Translate requests one domain at a time">
|
||||
Apply [document writes](./api-v5-document-writes),
|
||||
[document updates](./api-v5-document-updates),
|
||||
[content management](./api-v5-document-reads),
|
||||
[recall/search](./api-v5-recall),
|
||||
[profiles](./api-v5-profiles),
|
||||
[forgetting](./api-v5-memory-forgetting),
|
||||
[namespaces](./api-v5-settings),
|
||||
[organization](./api-v5-organization), and
|
||||
[typed filters](./api-v5-filters) independently.
|
||||
</Step>
|
||||
<Step title="Update response readers before switching traffic">
|
||||
Migrate envelopes, attachments, pagination, profile buckets, `system`
|
||||
lifecycle fields, and partial-error handling. A translated request with an
|
||||
untranslated reader still fails.
|
||||
</Step>
|
||||
<Step title="Verify legacy and V5 side by side">
|
||||
Work through the [verification and rollout guide](./api-v5-rollout). Check
|
||||
identity and behavior — never raw JSON ordering — and pass changed defaults
|
||||
explicitly so a default change cannot masquerade as a bug.
|
||||
</Step>
|
||||
<Step title="Cut over one domain at a time">
|
||||
Switch traffic, monitor failures and semantic drift, then delete that
|
||||
domain's legacy compatibility code only after it passes verification.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Endpoint map
|
||||
|
||||
| Legacy | V5 |
|
||||
| --- | --- |
|
||||
| `POST /v3/documents` | `POST /ns/{namespace}/document` |
|
||||
| `POST /v3/documents/batch` | `POST /ns/{namespace}/document/batch` |
|
||||
| `POST /v3/documents/file` | `POST /ns/{namespace}/document/file` |
|
||||
| `GET/PATCH /v3/documents/{id}` | `GET/PATCH /ns/{namespace}/document/{id}` |
|
||||
| `DELETE /v3/documents/{id}`, `DELETE /v3/documents/bulk` | `DELETE /ns/{namespace}/document` |
|
||||
| `POST /v3/documents/list`, `POST /v4/memories/list` | `POST /ns/{namespace}/list/{type}` |
|
||||
| `POST /v3/search`, `POST /v4/search` | `POST /ns/{namespace}/search` |
|
||||
| `POST /v4/profile` | `POST /ns/{namespace}/profile` |
|
||||
| `POST /v4/profile/buckets` | `GET/PUT/DELETE /ns/{namespace}/profile/buckets` |
|
||||
| `DELETE /v4/memories`, `POST /v4/memories/forget-matching` | `DELETE /ns/{namespace}/memories`, `DELETE /ns/{namespace}/memories/semantic` |
|
||||
| `GET/PATCH/DELETE /v3/container-tags/{tag}`, `POST /v3/container-tags/merge` | `GET /namespaces`, `GET/PATCH/DELETE /ns/{namespace}` |
|
||||
| `GET/PATCH /v3/settings` | `GET/PATCH /organization` |
|
||||
|
||||
## What has no V5 replacement
|
||||
|
||||
These legacy operations were deliberately dropped. Do not invent a substitute —
|
||||
rework the caller instead.
|
||||
|
||||
- **Direct memory creation and version updates.** `POST /v4/memories` and
|
||||
`PATCH /v4/memories` have no V5 equivalent. Ingest or replace a source
|
||||
document and let memories form from it.
|
||||
- **Organization bucket suggestion.** `POST /v3/settings/suggest-buckets` is not
|
||||
part of the V5 public surface.
|
||||
- **Organization data reset.** `POST /v3/settings/reset` is not part of the V5
|
||||
public surface.
|
||||
- **Connector routes.** Connections still use their existing `/v3/connections/*`
|
||||
paths and are **unchanged** by this migration. Do not rewrite them.
|
||||
|
||||
## Grounding note
|
||||
|
||||
This guide tracks the contract described by the V5 OpenAPI document that
|
||||
accompanies the V5 deployment. (For the legacy surfaces, the live
|
||||
`/v4/openapi` and `/v3/openapi` documents remain the references.) The legacy
|
||||
field names and defaults contrasted here are the ones still present in this
|
||||
repository's shared validation package — notably `SearchRequestSchema`,
|
||||
`Searchv4RequestSchema`, `ListMemoriesQuerySchema`, `MemoryUpdateSchema`, and the
|
||||
`SearchFiltersSchema` union. Where a behavior is not described by either source,
|
||||
this guide says so rather than guessing.
|
||||
95
apps/docs/snippets/api-v5-profiles.mdx
Normal file
95
apps/docs/snippets/api-v5-profiles.mdx
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
V5 returns a maintained profile directly, and gives profile bucket definitions
|
||||
their own namespace-scoped resource.
|
||||
|
||||
### Remove search behavior from profile calls
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
POST /v4/profile
|
||||
{"containerTag":"user_1","q":"work preferences","threshold":0.6,"include":{}}
|
||||
```
|
||||
|
||||
```bash V5
|
||||
POST /ns/user_1/profile
|
||||
{"filter":{"field":"region","operator":"eq","value":"us-west"},"buckets":["work"]}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Remove the legacy `q`, `threshold`, and `include`. If the caller needs
|
||||
query-ranked results, issue a **separate** V5 search request. Move `containerTag`
|
||||
to the path and rename `filters` to the singular `filter`.
|
||||
|
||||
<Note>
|
||||
The legacy shape is visible in this repository: `POST /v4/profile` is called
|
||||
with a body of `{ q, containerTag, include: ["static","dynamic"] }` and the
|
||||
response is read as `profile.static`, `profile.dynamic`, and
|
||||
`profile.buckets`. V5 keeps the `profile.static` / `profile.dynamic` /
|
||||
`profile.buckets` reader intact — what changes is that query parameters no
|
||||
longer belong on the profile call.
|
||||
</Note>
|
||||
|
||||
### Read the V5 profile shape
|
||||
|
||||
```json
|
||||
{
|
||||
"profile": {
|
||||
"static": ["The user works in design"],
|
||||
"dynamic": ["The user is preparing a launch"],
|
||||
"buckets": { "work": ["Prefers concise project updates"] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There is no way to switch off `static` or `dynamic`; both come back on every
|
||||
call. Leave `buckets` out of the request and you receive every effective custom
|
||||
bucket — or name up to 50 of them to restrict just that section.
|
||||
|
||||
### Read bucket definitions
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
POST /v4/profile/buckets
|
||||
{"containerTag":"user_1"}
|
||||
```
|
||||
|
||||
```bash V5
|
||||
GET /ns/user_1/profile/buckets
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
The response changes from key/description objects to a plain map:
|
||||
|
||||
```json
|
||||
{"buckets":{"work":"Professional preferences and ongoing work"}}
|
||||
```
|
||||
|
||||
### Add or edit namespace buckets
|
||||
|
||||
```bash
|
||||
PUT /ns/user_1/profile/buckets
|
||||
{"buckets":{"work":"Professional preferences and ongoing work"}}
|
||||
```
|
||||
|
||||
Supply anywhere between one and 50 name-to-description entries. Names already in
|
||||
the namespace get rewritten, new ones get created, and any namespace bucket you
|
||||
leave out stays exactly as it was.
|
||||
|
||||
### Delete namespace buckets
|
||||
|
||||
```bash
|
||||
DELETE /ns/user_1/profile/buckets
|
||||
{"buckets":["work"]}
|
||||
```
|
||||
|
||||
Every name has to be distinct. Buckets owned by the organization may show up in
|
||||
the effective `GET` response, but a namespace-level `PUT` or `DELETE` will not
|
||||
alter or drop them.
|
||||
|
||||
### Verification
|
||||
|
||||
- Check that `static`, `dynamic`, and `buckets` are present in every profile
|
||||
response.
|
||||
- Compare an omitted `buckets` request against one-name and multi-name narrowing.
|
||||
- Add, edit, and delete a namespace bucket without disturbing omitted buckets.
|
||||
- Attempt to mutate an inherited organization bucket and expect the documented
|
||||
error rather than a silent no-op.
|
||||
77
apps/docs/snippets/api-v5-rollout.mdx
Normal file
77
apps/docs/snippets/api-v5-rollout.mdx
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
Treat migration as a **behavioral comparison**, not a raw response-snapshot
|
||||
update. A diff of two JSON blobs will be dominated by generated IDs and
|
||||
timestamps and will tell you nothing about whether recall still works.
|
||||
|
||||
### Build deterministic fixtures
|
||||
|
||||
Use an isolated namespace, give every fixture a stable ID, and hold the source
|
||||
content fixed. The fixture set should span plaintext, URL, file, and batch
|
||||
ingestion, plus metadata, grouping, profile facts, related memories, forgotten
|
||||
memories, and the case where nothing matches.
|
||||
|
||||
For each case, write down the legacy request, the V5 request, the semantic
|
||||
outcome you expect, and any delta you are knowingly accepting. Whatever you do,
|
||||
keep generated IDs, signed URLs, timings, and JSON key ordering out of the
|
||||
comparison unless the contract actually promises them.
|
||||
|
||||
### Compare writes
|
||||
|
||||
- Repeated `POST` appends or diffs; `PATCH` replaces canonical content.
|
||||
- A batch keeps its results in the order you submitted them, and reports
|
||||
per-item failures rather than hiding them.
|
||||
- Touching only metadata leaves the source content as it was.
|
||||
- An accepted write is not a finished one: poll until processing settles into a
|
||||
terminal state.
|
||||
|
||||
### Compare reads and recall
|
||||
|
||||
- Attachments you did not request are missing from the payload; attachments you
|
||||
did request but that matched nothing come back as empty arrays.
|
||||
- A list call fills in the array for the resource type you asked for and leaves
|
||||
the others untouched.
|
||||
- Before trying V5's own search defaults, establish parity with the V4 mode and
|
||||
threshold stated explicitly.
|
||||
- Profiles always contain `static`, `dynamic`, and `buckets`.
|
||||
|
||||
### Exercise boundaries
|
||||
|
||||
| Boundary | Cases |
|
||||
| --- | --- |
|
||||
| Namespace | Correct, missing, unauthorized, cross-namespace ID |
|
||||
| Pagination | First, middle, final, empty, maximum limit |
|
||||
| Filters | Every operator, nested AND/OR, invalid type, excessive depth |
|
||||
| Deletion | All success, partial success, unknown IDs, semantic dry run |
|
||||
| Settings | Admin, non-admin, null removal, invalid empty value |
|
||||
|
||||
### Classify differences
|
||||
|
||||
```text
|
||||
same request intent
|
||||
|
|
||||
+-- same semantic result ------> parity
|
||||
+-- documented V5 difference --> update assertion
|
||||
+-- undocumented difference ----> block cutover
|
||||
```
|
||||
|
||||
An undocumented difference is a finding, not noise to be smoothed over. Save the
|
||||
request pair, the namespace, the IDs, the response status, and the smallest slice
|
||||
of the response that reproduces it.
|
||||
|
||||
### Cut over by domain
|
||||
|
||||
1. Build V5 requests behind a switch you can flip per domain.
|
||||
2. Where side effects permit, read both paths or shadow-call the new one.
|
||||
3. Cut over ingestion, content management, search, profiles, and settings one at
|
||||
a time, in that order.
|
||||
4. Watch for validation and authorization failures, latency shifts, a changing
|
||||
empty-result rate, and processing errors.
|
||||
5. Keep the legacy path in place until the observation window closes.
|
||||
|
||||
### Completion checklist
|
||||
|
||||
- No application call ends up pointing at a `/v5` prefix by mistake.
|
||||
- Connector routes, which this migration leaves alone, still carry their
|
||||
documented `/v3` paths.
|
||||
- Nothing still reads a legacy field name or legacy response shape.
|
||||
- Every default that changed is either deliberately accepted or sent explicitly.
|
||||
- Rolling back returns the previous caller to service without a data repair.
|
||||
98
apps/docs/snippets/api-v5-search.mdx
Normal file
98
apps/docs/snippets/api-v5-search.mdx
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
A V5 search runs against a single namespace, falls back to hybrid recall when you
|
||||
say nothing, and takes its ranking controls from a typed request body.
|
||||
|
||||
### Request mapping
|
||||
|
||||
| Legacy | V5 |
|
||||
| --- | --- |
|
||||
| `containerTag` | `/ns/{namespace}` |
|
||||
| body `q` | body `query` |
|
||||
| body `limit` | query `limit` |
|
||||
| `searchMode: "documents"` | `searchMode=chunks` |
|
||||
| omitted search mode | `searchMode=hybrid` |
|
||||
| `filters` | singular `filter` |
|
||||
| `include.documents` or `include.summaries` | `attach.documents` |
|
||||
| `include.relatedMemories` | `attach.related` |
|
||||
| `include.forgottenMemories` | `attach.forgotten` |
|
||||
| `rerank: true` / `aggregate: true` | `rerank: "order"` / `"aggregate"` |
|
||||
|
||||
<CodeGroup>
|
||||
```bash Legacy
|
||||
POST /v4/search
|
||||
{"q":"What did the user decide?","containerTag":"user_1","limit":10,"searchMode":"memories"}
|
||||
```
|
||||
|
||||
```bash V5
|
||||
POST /ns/user_1/search?limit=10&searchMode=memories
|
||||
{"query":"What did the user decide?","threshold":0.6,"rewriteQuery":false}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Changed defaults
|
||||
|
||||
| Setting | V4 | V5 |
|
||||
| --- | --- | --- |
|
||||
| Search mode | `memories` | `hybrid` |
|
||||
| Similarity threshold | `0.6` | `0.3` |
|
||||
| Reranking | Disabled | `rerank: "none"` |
|
||||
| Query rewriting | Disabled | `false` |
|
||||
|
||||
These are the values actually declared in `Searchv4RequestSchema` in this
|
||||
repository: `threshold` defaults to `0.6`, `limit` to `10`, and `rerank` and
|
||||
`rewriteQuery` both default to `false`. V5 widens recall by default, so set mode
|
||||
and threshold **explicitly** while you compare versions. Once parity testing
|
||||
passes, drop them only if you actually want the broader V5 hybrid defaults.
|
||||
|
||||
<Warning>
|
||||
A silently widened threshold is the single most common false "regression"
|
||||
during this migration. It returns *more* results, not wrong ones — pin
|
||||
`threshold` and `searchMode` until your comparison is green.
|
||||
</Warning>
|
||||
|
||||
### Search modes
|
||||
|
||||
| Mode | Returns |
|
||||
| --- | --- |
|
||||
| `memories` | Formed memories only |
|
||||
| `chunks` | Source chunks only |
|
||||
| `hybrid` | Both result types in one ranked list |
|
||||
|
||||
Nothing in V5 corresponds to the legacy `include.chunks` flag. Pick `chunks` or
|
||||
`hybrid` instead.
|
||||
|
||||
### Attachments and ranking
|
||||
|
||||
- Asking for `attach.documents` pulls the single most relevant source document
|
||||
into each result.
|
||||
- `attach.related` brings in parent, child, and sibling memories. The legacy
|
||||
`Searchv4RequestSchema` exposed this as `include.relatedMemories`, and memory
|
||||
results still carry a `context` object with `parents` and `children` arrays
|
||||
whose entries use the `updates` / `extends` / `derives` relation enum.
|
||||
- `attach.forgotten` lets forgotten memories appear in related context; it does
|
||||
not promote them to primary results.
|
||||
- The `rerank` setting takes `none`, `order`, or `aggregate`, while
|
||||
`rewriteQuery` governs query rewriting aimed at retrieval.
|
||||
|
||||
### Response mapping
|
||||
|
||||
| Legacy reader | V5 reader |
|
||||
| --- | --- |
|
||||
| Result array | `results` |
|
||||
| Timing | `searchTime` |
|
||||
| Source expansion | `result.included.document` |
|
||||
| Related context | `result.included.related.{parents,children,siblings}` |
|
||||
| Lifecycle fields | `result.system` |
|
||||
|
||||
Each primary result contains either `memory`, `chunk`, or both only where the
|
||||
contract allows it. Branch on field presence rather than assuming one result
|
||||
shape — in hybrid mode a single result array mixes both kinds.
|
||||
|
||||
### Verification
|
||||
|
||||
- Pin the V4 defaults explicitly and check result IDs against them first; treat
|
||||
V5 hybrid behavior as a separate test.
|
||||
- Cover all three modes, thresholds at `0` and `1`, each rerank option, and query
|
||||
rewriting on and off.
|
||||
- Try each attachment on its own and in combination, including the empty case.
|
||||
- Verify filters, namespace isolation, result limits, and rejection of body
|
||||
parameters placed in the query string (or vice versa).
|
||||
Loading…
Add table
Reference in a new issue