Store memories
Engram supports three content types for storing memories. Each content type is a different entrypoint into the same pipeline.
All examples below use a connected client
See Connect to Engram for how to instantiate one.
import os
from engram import EngramClient
client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])
String content
Send raw text and let Engram extract structured memories from it.
run = client.memories.add(
"The user prefers dark mode and works primarily in Python. They are building a RAG application.",
user_id=test_user_id,
group="default",
)
print(run.run_id)
print(run.status)
The pipeline extracts individual facts from the text (e.g. "prefers dark mode", "works in Python") and stores them as separate memories.
Conversation content
Send multi-turn messages and let Engram extract memories from the dialogue. You can send new messages as they happen — there is no need to wait until a conversation is finished.
run = client.memories.add(
[
{"role": "user", "content": "I just moved to Berlin and I am looking for a good coffee shop."},
{"role": "assistant", "content": "Welcome to Berlin! Here are some popular coffee shops in the city..."},
{"role": "user", "content": "I prefer specialty coffee, not chains."},
],
user_id=test_user_id,
group="default",
)
print(run.run_id)
print(run.status)
The pipeline reads the messages and extracts relevant facts (e.g. "lives in Berlin", "prefers specialty coffee").
Pre-extracted content
If you've already extracted structured content, send it directly. This bypasses the LLM extraction step, but the content still passes through the transform and commit pipeline stages.
run = client.memories.add(
PreExtractedInput(items=[
PreExtractedItem(content="User prefers dark mode", topic="UserKnowledge"),
PreExtractedItem(content="User works in Python", topic="UserKnowledge"),
]),
user_id=test_user_id,
group="default",
)
print(run.run_id)
print(run.status)
Response
All three content types return the same response format:
{
"run_id": "run-uuid",
"status": "running"
}
A successful response means the pipeline has started, not that the memories have been committed. In most cases you don't need to do anything else, since memories become available once the pipeline finishes. If you have a specific reason to confirm completion, you can use the run_id to check the pipeline status.
Optional parameters
| Parameter | Type | Description |
|---|---|---|
user_id | string | Scope the memory to a specific user. Required if the target topic is user-scoped. |
properties | object<string, string> | Custom scope properties (e.g. {"conversation_id": "abc-123"}). Must include every key any target topic is scoped by. |
group | string | Memory group name (defaults to default) |
root | string | Pipeline root name (for advanced pipeline configurations) |
Which parameters are required depends on the topic's scoping configuration, not the content type. If a topic is user-scoped, you must include user_id. If a topic is scoped by a custom property (e.g. conversation_id), pass it in properties. These scoping parameters apply equally to all three content types.
Questions and feedback
If you have any questions or feedback, let us know in the user forum.
