mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-02 12:54:08 +00:00
624 lines
20 KiB
Text
624 lines
20 KiB
Text
---
|
||
title: "Quickstart"
|
||
description: "Ingest a conversation and a document, then use document search, memory graph traversal, and profiles — and wire it into a chat harness."
|
||
icon: "play"
|
||
---
|
||
|
||
By the end of this page you will:
|
||
|
||
1. **Ingest a conversation** (how personal memory actually arrives)
|
||
2. **Ingest a document** (how knowledge for RAG arrives)
|
||
3. **Retrieve three ways** — document search (RAG), memory graph traversal, and user profile
|
||
4. **Drop it into a chat harness** that remembers across restarts
|
||
|
||
Same `containerTag` for everything. One engine, three ways out.
|
||
|
||
## Get an API key
|
||
|
||
Grab a key from the [developer console](https://console.supermemory.ai) — **API Keys → Create API Key**.
|
||
|
||
**console.supermemory.ai** is where keys and usage live. **app.supermemory.ai** is the consumer product on the same engine — not where you mint API keys.
|
||
|
||
<CodeGroup>
|
||
```bash TypeScript
|
||
npm install supermemory
|
||
export SUPERMEMORY_API_KEY="sm_..."
|
||
```
|
||
|
||
```bash Python
|
||
pip install supermemory
|
||
export SUPERMEMORY_API_KEY="sm_..."
|
||
```
|
||
|
||
```bash curl
|
||
export SUPERMEMORY_API_KEY="sm_..."
|
||
```
|
||
</CodeGroup>
|
||
|
||
## 1. Ingest a conversation
|
||
|
||
Real apps do not push four isolated one-liners as separate “memories.” They send **conversation turns** — often the full session — under a stable `customId` so the pipeline can extract facts and link entities.
|
||
|
||
We’ll use one user (`user_4f8a`) and one chat session. The turns never say “Sarah *is* my VP of Product” — that connection is what the graph should resolve later.
|
||
|
||
<CodeGroup>
|
||
```typescript TypeScript
|
||
import Supermemory from "supermemory";
|
||
|
||
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
|
||
const user = "user_4f8a";
|
||
|
||
const conversation = `
|
||
user: Just got back from Tokyo — the team offsite went great.
|
||
assistant: Glad it went well! Anything stand out?
|
||
user: Sarah presented the Q3 roadmap at the offsite.
|
||
assistant: Sounds like a big moment for her.
|
||
user: She's being promoted to VP of Product.
|
||
assistant: Congrats to Sarah — that's huge.
|
||
user: I need a gift idea for my VP of Product.
|
||
assistant: Happy to help brainstorm something personal.
|
||
`.trim();
|
||
|
||
const conv = await client.add({
|
||
content: conversation,
|
||
containerTag: user,
|
||
customId: "chat_offsite_2026", // one session → one document
|
||
metadata: { type: "conversation" },
|
||
dreaming: "instant", // process this document now — see note below
|
||
});
|
||
|
||
console.log(conv.id, conv.status); // e.g. "queued"
|
||
```
|
||
|
||
```python Python
|
||
from supermemory import Supermemory
|
||
|
||
client = Supermemory()
|
||
user = "user_4f8a"
|
||
|
||
conversation = """
|
||
user: Just got back from Tokyo — the team offsite went great.
|
||
assistant: Glad it went well! Anything stand out?
|
||
user: Sarah presented the Q3 roadmap at the offsite.
|
||
assistant: Sounds like a big moment for her.
|
||
user: She's being promoted to VP of Product.
|
||
assistant: Congrats to Sarah — that's huge.
|
||
user: I need a gift idea for my VP of Product.
|
||
assistant: Happy to help brainstorm something personal.
|
||
""".strip()
|
||
|
||
conv = client.add(
|
||
content=conversation,
|
||
container_tag=user,
|
||
custom_id="chat_offsite_2026",
|
||
metadata={"type": "conversation"},
|
||
dreaming="instant", # process this document now — see note below
|
||
)
|
||
print(conv.id, conv.status)
|
||
```
|
||
|
||
```bash curl
|
||
curl -X POST "https://api.supermemory.ai/v3/documents" \
|
||
-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.",
|
||
"containerTag": "user_4f8a",
|
||
"customId": "chat_offsite_2026",
|
||
"metadata": { "type": "conversation" },
|
||
"dreaming": "instant"
|
||
}'
|
||
```
|
||
</CodeGroup>
|
||
|
||
`add` returns immediately with `status: "queued"`. Processing is still **async** — wait until `done` before searching.
|
||
|
||
<Note>
|
||
**`dreaming: "instant"`** — By default, dreaming is `"dynamic"`: Supermemory may batch related documents so memories form from coherent units, which can lag after `status: "done"`. For this quickstart (and any path where you need memories/profiles right away), pass **`dreaming: "instant"`** so the document is processed on its own as soon as it finishes indexing. That bills one extra operation per document. See [Processing Modes](/ingestion/add-memories#processing-modes).
|
||
</Note>
|
||
|
||
## 2. Ingest a document
|
||
|
||
Now add **knowledge** the agent should ground on — a short internal note the conversation never fully spelled out. This is the SuperRAG / document path.
|
||
|
||
<CodeGroup>
|
||
```typescript TypeScript
|
||
const handbook = `
|
||
# Team notes — gifts & recognition
|
||
|
||
When 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.
|
||
|
||
For product leadership, books on platform strategy or a dinner near the last
|
||
offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.
|
||
`.trim();
|
||
|
||
const doc = await client.add({
|
||
content: handbook,
|
||
containerTag: user,
|
||
customId: "doc_gift_policy",
|
||
metadata: { type: "document", source: "handbook" },
|
||
taskType: "superrag"
|
||
});
|
||
|
||
console.log(doc.id, doc.status);
|
||
```
|
||
|
||
```python Python
|
||
handbook = """
|
||
# Team notes — gifts & recognition
|
||
|
||
When 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.
|
||
|
||
For product leadership, books on platform strategy or a dinner near the last
|
||
offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.
|
||
""".strip()
|
||
|
||
doc = client.add(
|
||
content=handbook,
|
||
container_tag=user,
|
||
custom_id="doc_gift_policy",
|
||
metadata={"type": "document", "source": "handbook"},
|
||
task_type="superrag"
|
||
)
|
||
print(doc.id, doc.status)
|
||
```
|
||
|
||
```bash curl
|
||
curl -X POST "https://api.supermemory.ai/v3/documents" \
|
||
-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.",
|
||
"containerTag": "user_4f8a",
|
||
"customId": "doc_gift_policy",
|
||
"metadata": { "type": "document", "source": "handbook" },
|
||
"taskType": "superrag"
|
||
}'
|
||
```
|
||
</CodeGroup>
|
||
|
||
## 3. Wait until both are `done`
|
||
|
||
Poll document status. With **`dreaming: "instant"`**, once status is `done` the document is indexed **and** memories for that document should be available for search and profiles (`queued → extracting → … → done`).
|
||
|
||
> Note that the preferred way is to have `dreaming: dynamic`. supermemory charges one extra operation for instant dreaming. Instant is good for one off tests, setup, debugging and benchmarking.
|
||
|
||
<CodeGroup>
|
||
```typescript TypeScript
|
||
async function waitUntilDone(id: string) {
|
||
for (;;) {
|
||
const d = await client.documents.get(id);
|
||
if (d.status === "done" || d.status === "failed") return d;
|
||
await new Promise((r) => setTimeout(r, 1500));
|
||
}
|
||
}
|
||
|
||
await waitUntilDone(conv.id);
|
||
await waitUntilDone(doc.id);
|
||
console.log("ready to search");
|
||
```
|
||
|
||
```python Python
|
||
import time
|
||
|
||
def wait_until_done(doc_id: str):
|
||
while True:
|
||
d = client.documents.get(doc_id)
|
||
if d.status in ("done", "failed"):
|
||
return d
|
||
time.sleep(1.5)
|
||
|
||
wait_until_done(conv.id)
|
||
wait_until_done(doc.id)
|
||
print("ready to search")
|
||
```
|
||
|
||
```bash curl
|
||
# replace DOC_ID with each document id from the add responses
|
||
curl "https://api.supermemory.ai/v3/documents/DOC_ID" \
|
||
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
|
||
# repeat until "status": "done"
|
||
```
|
||
</CodeGroup>
|
||
|
||
Short text with instant dreaming usually finishes in a few seconds. Larger PDFs take longer. If you omit `dreaming` (default `"dynamic"`), document RAG can work after `done` while memory extraction may still be batching — use `"instant"` when the next step is memory search or profiles.
|
||
|
||
## 4. Three ways to get context back
|
||
|
||
### A. Document search (RAG)
|
||
|
||
Chunk-level retrieval over raw knowledge — use when you need **what the docs say**.
|
||
|
||
<CodeGroup>
|
||
```typescript TypeScript
|
||
const rag = await client.search({
|
||
q: "gift ideas for a VP promotion after a Tokyo offsite",
|
||
containerTag: user,
|
||
searchMode: "documents",
|
||
limit: 3,
|
||
});
|
||
|
||
for (const hit of rag.results) {
|
||
console.log(hit.title ?? hit.id);
|
||
for (const chunk of hit.chunks ?? []) {
|
||
console.log(" ", chunk.content?.slice(0, 160));
|
||
}
|
||
}
|
||
```
|
||
|
||
```python Python
|
||
rag = client.search.memories(
|
||
q="gift ideas for a VP promotion after a Tokyo offsite",
|
||
container_tag=user,
|
||
search_mode="documents",
|
||
limit=3,
|
||
)
|
||
|
||
for hit in rag.results:
|
||
print(getattr(hit, "title", None) or hit.id)
|
||
for chunk in hit.chunks or []:
|
||
print(" ", (chunk.content or "")[:160])
|
||
```
|
||
|
||
```bash curl
|
||
curl -X POST "https://api.supermemory.ai/v3/search" \
|
||
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"q": "gift ideas for a VP promotion after a Tokyo offsite",
|
||
"containerTag": "user_4f8a",
|
||
"searchMode": "documents",
|
||
"limit": 3
|
||
}'
|
||
```
|
||
</CodeGroup>
|
||
|
||
You should see chunks from the handbook (budget range, Tokyo offsite angle) — **document grounding**, not personal facts.
|
||
|
||
Switch `searchMode` to `"hybrid"` to get extracted memories and document chunks together:
|
||
|
||
```typescript
|
||
await client.search({
|
||
q: "gift ideas for a VP promotion after a Tokyo offsite",
|
||
containerTag: user,
|
||
searchMode: "hybrid",
|
||
limit: 5,
|
||
});
|
||
```
|
||
|
||
### B. Memory graph traversal
|
||
|
||
Search **extracted memories** with related edges. This is the entity-chain moment: gift → VP of Product → Sarah → Tokyo offsite.
|
||
|
||
<CodeGroup>
|
||
```typescript TypeScript
|
||
const memories = await client.search({
|
||
q: "What gift should I get, and why?",
|
||
containerTag: user,
|
||
searchMode: "memories",
|
||
include: { relatedMemories: true },
|
||
limit: 5,
|
||
});
|
||
|
||
console.log(JSON.stringify(memories, null, 2));
|
||
```
|
||
|
||
```python Python
|
||
memories = client.search.memories(
|
||
q="What gift should I get, and why?",
|
||
container_tag=user,
|
||
search_mode="memories",
|
||
include={"relatedMemories": True},
|
||
limit=5,
|
||
)
|
||
print(memories)
|
||
```
|
||
|
||
```bash curl
|
||
curl -X POST "https://api.supermemory.ai/v4/search" \
|
||
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"q": "What gift should I get, and why?",
|
||
"containerTag": "user_4f8a",
|
||
"searchMode": "memories",
|
||
"include": { "relatedMemories": true },
|
||
"limit": 5
|
||
}'
|
||
```
|
||
</CodeGroup>
|
||
|
||
Abbreviated shape:
|
||
|
||
```json
|
||
{
|
||
"results": [
|
||
{
|
||
"memory": "Sarah is being promoted to VP of Product",
|
||
"similarity": 0.81,
|
||
"context": {
|
||
"parents": [
|
||
{
|
||
"memory": "Sarah presented the Q3 roadmap at the Tokyo offsite",
|
||
"relation": "extends"
|
||
}
|
||
],
|
||
"children": [
|
||
{
|
||
"memory": "User needs a gift idea for their VP of Product, Sarah",
|
||
"relation": "derives"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"timing": 287
|
||
}
|
||
```
|
||
|
||
You never wrote “Sarah is my VP of Product” as one sentence. The graph connected sessions of speech. Deep dive: [graph memory](/concepts/graph-memory).
|
||
|
||
### C. User profile
|
||
|
||
Profiles are the **always-on** summary (static + recent dynamic) of an entity (or a `containerTag`) - what you inject every turn without re-searching the world.
|
||
|
||
<CodeGroup>
|
||
```typescript TypeScript
|
||
const { profile, searchResults } = await client.profile({
|
||
containerTag: user,
|
||
q: "gift for the person being promoted", // optional: also run search
|
||
});
|
||
|
||
console.log("static:", profile.static);
|
||
console.log("dynamic:", profile.dynamic);
|
||
console.log("search hits:", searchResults?.results?.length ?? 0);
|
||
```
|
||
|
||
```python Python
|
||
result = client.profile(
|
||
container_tag=user,
|
||
q="gift for the person being promoted",
|
||
)
|
||
|
||
print("static:", result.profile.static)
|
||
print("dynamic:", result.profile.dynamic)
|
||
print("search hits:", len(result.search_results.results) if result.search_results else 0)
|
||
```
|
||
|
||
```bash curl
|
||
curl -X POST "https://api.supermemory.ai/v4/profile" \
|
||
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"containerTag": "user_4f8a",
|
||
"q": "gift for the person being promoted"
|
||
}'
|
||
```
|
||
</CodeGroup>
|
||
|
||
> There is a lot more to profiles - with [Buckets](/user-profiles/buckets), for example, you can make supermemory learn and categorize incoming information for learning specific things.
|
||
|
||
|
||
| Path | Use when |
|
||
|---|---|
|
||
| **Document search** | Ground in policies, docs, handbooks |
|
||
| **Memory + related** | Personal facts, entity links, “what’s true about this user” |
|
||
| **Profile** | Cheap always-on context every LLM turn |
|
||
|
||
Same `containerTag` → same context pool. See [Memory vs RAG](/concepts/memory-vs-rag).
|
||
|
||
## 5. Put it in a harness
|
||
|
||
There is no single required harness. The pattern is the same wherever you run the model: **read** context (profile / search / docs), generate, **write** the turn back under a stable `customId` so the session stays one document.
|
||
|
||
Here are two example shapes — pick whatever matches your stack.
|
||
|
||
### Example: explicit profile + search + add
|
||
|
||
<CodeGroup>
|
||
```typescript TypeScript
|
||
// npm install supermemory openai
|
||
import Supermemory from "supermemory";
|
||
import OpenAI from "openai";
|
||
import * as readline from "node:readline/promises";
|
||
|
||
const memory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
|
||
const llm = new OpenAI();
|
||
const user = "user_4f8a";
|
||
const sessionId = "chat_live_session";
|
||
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||
|
||
while (true) {
|
||
const question = await rl.question("you: ");
|
||
|
||
const { profile, searchResults } = await memory.profile({
|
||
containerTag: user,
|
||
q: question,
|
||
});
|
||
|
||
// optional: also pull document chunks for grounding
|
||
const rag = await memory.search({
|
||
q: question,
|
||
containerTag: user,
|
||
searchMode: "documents",
|
||
limit: 3,
|
||
});
|
||
const docBits = rag.results
|
||
.flatMap((r) => r.chunks ?? [])
|
||
.map((c) => c.content)
|
||
.filter(Boolean)
|
||
.slice(0, 3);
|
||
|
||
const context = [
|
||
"## Profile (static)",
|
||
...profile.static,
|
||
"## Profile (dynamic)",
|
||
...profile.dynamic,
|
||
"## Related memories",
|
||
...(searchResults?.results?.map((m) => m.memory).filter(Boolean) ?? []),
|
||
"## Docs",
|
||
...docBits,
|
||
].join("\n");
|
||
|
||
const res = await llm.chat.completions.create({
|
||
model: "gpt-4o",
|
||
messages: [
|
||
{ role: "system", content: `You help this user. Context:\n${context}` },
|
||
{ role: "user", content: question },
|
||
],
|
||
});
|
||
const answer = res.choices[0].message.content ?? "";
|
||
console.log(`assistant: ${answer}`);
|
||
|
||
// append this turn into the same conversation document
|
||
await memory.add({
|
||
content: `user: ${question}\nassistant: ${answer}`,
|
||
containerTag: user,
|
||
customId: sessionId,
|
||
});
|
||
}
|
||
```
|
||
|
||
```python Python
|
||
# pip install supermemory openai
|
||
from supermemory import Supermemory
|
||
from openai import OpenAI
|
||
|
||
memory = Supermemory()
|
||
llm = OpenAI()
|
||
user = "user_4f8a"
|
||
session_id = "chat_live_session"
|
||
|
||
while True:
|
||
question = input("you: ")
|
||
|
||
result = memory.profile(container_tag=user, q=question)
|
||
rag = memory.search.memories(
|
||
q=question, container_tag=user, search_mode="documents", limit=3
|
||
)
|
||
doc_bits = []
|
||
for hit in rag.results:
|
||
for chunk in hit.chunks or []:
|
||
if chunk.content:
|
||
doc_bits.append(chunk.content[:300])
|
||
if len(doc_bits) >= 3:
|
||
break
|
||
|
||
memories = result.search_results.results if result.search_results else []
|
||
context = "\n".join(
|
||
[
|
||
"## Profile (static)",
|
||
*result.profile.static,
|
||
"## Profile (dynamic)",
|
||
*result.profile.dynamic,
|
||
"## Related memories",
|
||
*[m.memory for m in memories if m.memory],
|
||
"## Docs",
|
||
*doc_bits,
|
||
]
|
||
)
|
||
|
||
res = llm.chat.completions.create(
|
||
model="gpt-4o",
|
||
messages=[
|
||
{"role": "system", "content": f"You help this user. Context:\n{context}"},
|
||
{"role": "user", "content": question},
|
||
],
|
||
)
|
||
answer = res.choices[0].message.content or ""
|
||
print(f"assistant: {answer}")
|
||
|
||
memory.add(
|
||
content=f"user: {question}\nassistant: {answer}",
|
||
container_tag=user,
|
||
custom_id=session_id,
|
||
)
|
||
```
|
||
</CodeGroup>
|
||
|
||
### Example: Vercel AI SDK
|
||
|
||
Same pattern, wrapped: `withSupermemory` injects context and can save the conversation for you. Details: [AI SDK integration](/integrations/ai-sdk).
|
||
|
||
```typescript
|
||
// npm install ai @ai-sdk/openai @supermemory/tools
|
||
import { generateText } from "ai";
|
||
import { openai } from "@ai-sdk/openai";
|
||
import { withSupermemory } from "@supermemory/tools/ai-sdk";
|
||
import * as readline from "node:readline/promises";
|
||
|
||
const model = withSupermemory(openai("gpt-4o"), {
|
||
containerTag: "user_4f8a",
|
||
customId: "chat_live_session", // keep stable for the whole session
|
||
mode: "full", // profile + query search
|
||
});
|
||
|
||
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||
|
||
while (true) {
|
||
const prompt = await rl.question("you: ");
|
||
const { text } = await generateText({ model, prompt });
|
||
console.log(`assistant: ${text}`);
|
||
}
|
||
```
|
||
|
||
Try:
|
||
|
||
```
|
||
you: What gift should I get for the person being promoted?
|
||
assistant: You're looking for something for Sarah — she's being promoted to VP of
|
||
Product after presenting the Q3 roadmap in Tokyo. Your handbook suggests $75–$150
|
||
and something tied to the offsite; a Tokyo-inspired experience or platform-strategy
|
||
book would fit…
|
||
```
|
||
|
||
### Kill it, restart it
|
||
|
||
Ctrl+C the process, start again with the **same** `containerTag` (and optional same `customId` for the live session). Ask:
|
||
|
||
```
|
||
you: who's getting promoted?
|
||
assistant: Sarah — she's being promoted to VP of Product.
|
||
```
|
||
|
||
Nothing was reloaded from your process. Memory and docs live in supermemory.
|
||
|
||
## Mental model
|
||
|
||
```
|
||
INGEST WAIT RETRIEVE
|
||
────── ──── ────────
|
||
Conversation (customId) → status === done → Memory graph (+ related)
|
||
Document (customId) → status === done → Document search (RAG)
|
||
→ Profile (static + dynamic)
|
||
│
|
||
▼
|
||
Chat harness
|
||
```
|
||
|
||
## Where next
|
||
|
||
<CardGroup cols={2}>
|
||
<Card title="Add context" icon="plus" href="/ingestion/add-memories">
|
||
Conversations, files, URLs, customId updates, and status.
|
||
</Card>
|
||
<Card title="Search" icon="search" href="/recall/search">
|
||
Hybrid vs memories, filters, thresholds, rerank.
|
||
</Card>
|
||
<Card title="Graph memory" icon="waypoints" href="/concepts/graph-memory">
|
||
How relations and entity chains are produced.
|
||
</Card>
|
||
<Card title="User profiles" icon="user" href="/concepts/user-profiles">
|
||
Static vs dynamic, and when to inject a profile every turn.
|
||
</Card>
|
||
<Card title="AI SDK" icon="triangle" href="/integrations/ai-sdk">
|
||
withSupermemory modes, customId, addMemory.
|
||
</Card>
|
||
<Card title="Container tags" icon="lock" href="/concepts/container-tags">
|
||
Isolation for multi-tenant products.
|
||
</Card>
|
||
</CardGroup>
|