mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-26 06:04:08 +00:00
docs(api): move v5 search and ingest options into the request body (#1808)
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)
This commit is contained in:
parent
5323f427d0
commit
ca89d161cc
7 changed files with 59 additions and 61 deletions
|
|
@ -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", {
|
|||
```
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
### 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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" }'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
|
@ -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" }'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
|
@ -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" }
|
||||
}'
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
|
|
@ -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" }'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
|
@ -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"
|
||||
}'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
|
@ -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
|
||||
}'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
|
|
@ -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
|
||||
}'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
</Info>
|
||||
|
||||
## 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` |
|
||||
|
||||
<Note>
|
||||
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`
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ Search through your memories and documents with a single API call. Each search r
|
|||
</Tip>
|
||||
|
||||
<Note>
|
||||
**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.
|
||||
</Note>
|
||||
|
||||
## Quick start
|
||||
|
|
@ -54,10 +54,10 @@ Search through your memories and documents with a single API call. Each search r
|
|||
</Tab>
|
||||
<Tab title="cURL">
|
||||
```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 }'
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
|
@ -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 |
|
||||
|
||||
<Note>
|
||||
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<string, unknown>; // {} 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[] };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ await supermemory.search("user_1", {
|
|||
```
|
||||
</CodeGroup>
|
||||
|
||||
`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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue