Observed since 21 Oct, 11:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
An experimental SDK for using Letta subagents for pluggable memory management
The AI Memory SDK is a lightweight wrapper around Letta's advanced memory management capabilities. Letta is a platform for building stateful AI agents that truly remember, learn, and evolve. The memory SDK exposes Letta's sophisticated memory architecture through a simplified interface for general-purpose use cases like user profiles, conversation summaries, and domain-specific knowledge bases.
Under the hood, the SDK creates a "subconscious agent"—a Letta agent configured to manage memory blocks. When you send messages, the agent asynchronously processes them and updates its memory blocks. This architecture leverages Letta's core strengths in persistent memory and stateful learning while providing a streamlined API for common memory patterns.
The SDK organizes memory around three concepts:
user_sarah, project_alpha, team_support). Each subject is backed by a Letta agent with its own memory state.human, summary, policies, history, preferences). These correspond to Letta's memory blocks—customizable, labeled sections that persist in the agent's core memory.This enables user profiles and conversation summaries, plus broader use cases like policy digests, running histories, study guides, or any domain‑specific memory you define.
See Letta's YouTube channel for more information on how to design memory architecture. This video provides a general overview.
Quick mental model—blocks live in the agent's context window (core memory), updated automatically as messages flow through:
+========================================+
| SYSTEM PROMPT |
+========================================+
| CORE MEMORY (BLOCKS) | <- Letta agent updates over time
| - <human> ... </human> |
| - <summary> ... </summary> |
| - <policies> ... </policies> |
| - <history> ... </history> |
+========================================+
| MESSAGES |
| * User -> Assistant |
| * User -> Assistant |
| * ... |
+========================================+
Messages can optionally be stored in archival memory (Letta's external long-term storage) by setting skip_vector_storage=False, enabling semantic search to retrieve relevant passages and inject them back into context.
In addition to the user-specific helpers, the SDK supports a generalized "subject" model:
user_sarah, team_alpha, or project_123.human, summary, preferences) attached to the subject's agent.You can bind a Memory instance to a subject at construction time, or pass a subject per call.
subconscious_agent_subject_<subject_id>). Ensure your subject_id uses only characters allowed by Letta agent names. Recommended: letters, numbers, underscores, and dashes. Avoid characters like : or other punctuation.Python (instance-scoped):
from ai_memory_sdk import Memory
memory = Memory(subject_id="user_sarah")
# Create a new block in this subject (no-op if it exists and reset=False)
memory.initialize_memory(
label="preferences",
description="Known user preferences.",
value="Likes cats",
)
# Add conversation messages to the bound subject (unified API)
memory.add_messages([
{"role": "user", "content": "I love cats"}
])
# Retrieve a block (raw or prompt formatted)
raw = memory.get_memory("preferences")
formatted = memory.get_memory("preferences", prompt_formatted=True)
Python (explicit subject):
from ai_memory_sdk import Memory
memory = Memory()
memory.initialize_subject("project_alpha", reset=True)
memory.initialize_memory("spec", "Project spec", value="v1", subject_id="project_alpha")
run = memory.add_messages_for_subject("project_alpha", [{"role": "user", "content": "Kickoff done"}])
memory.wait_for_run(run)
spec = memory.get_memory("spec", subject_id="project_alpha")
TypeScript (instance-scoped):
import { Memory } from '@letta-ai/memory-sdk'
const memory = new Memory({ subjectId: 'user_sarah' })
await memory.initializeMemory('preferences', 'Known user preferences.', 'Likes cats')
// unified API when instance is bound to a context
await memory.addMessages([{ role: 'user', content: 'I love cats' }])
const formatted = await memory.getMemory('preferences', true)
TypeScript (explicit subject):
const memory = new Memory()
await memory.initializeSubject('project_alpha', true)
await memory.initializeMemory('spec', 'Project spec', 'v1', 10000, false, 'project_alpha')
const run = await memory.addMessagesToSubject('project_alpha', [{ role: 'user', content: 'Kickoff done' }])
await memory.waitForRun(run)
pip install ai-memory-sdkLeverage Letta's memory block system to maintain persistent, evolving memory. Define blocks (human, summary, policies, history, study_guide, ...) with custom labels and descriptions. As you send messages, the Letta agent updates relevant blocks based on their descriptions. Retrieve blocks and inject them into your system prompts for context-aware interactions.
Example: Create a basic OpenAI gpt-4o-mini chat agent with subject‑scoped memory
from openai import OpenAI
from ai_memory_sdk import Memory
# Memory is a lightweight wrapper around Letta's memory management.
# It creates a Letta agent to handle persistent memory for your conversations.
#
# Assumes LETTA_API_KEY environment variable, or pass api_key="your_api_key"
memory = Memory()
# Set up your OpenAI client like you normally would.
# This example assumes that the OpenAI key is stored in the OPENAI_API_KEY
# environment variable.
openai_client = OpenAI()
def chat_with_memories(message: str, user_id: str = "default_user") -> str:
# Retrieve or initialize the subject (using user helpers for simplicity)
user_memory = memory.get_user_memory(user_id)
if not user_memory:
memory.initialize_user_memory(user_id, reset=True)
user_memory = memory.get_user_memory(user_id)
# the contents of the human block formatted as a prompt:
#
# <human description="Details about the human user you are speaking to.">
# Name: Sarah
# Interests: Likes cats (2025-09-04)
# </human>
user_memory_prompt= memory.get_user_memory(user_id, prompt_formatted=True)
print(user_memory_prompt)
# Generate the assistant response using the inference engine of your choice,
# OpenAI in this case.
system_prompt = f"<system>You are a helpful AI assistant</system>"
system_prompt += f"\n{user_memory_prompt}"
# Create the list of message
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": message}
]
# Send the messages to the OpenAI API
response = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
# Extract the assistant's message from the API response
assistant_response = response.choices[0].message.content
# Send the conversation to the Letta agent to update memory blocks
print("Updating memory...")
messages.append({"role": "assistant", "content": assistant_response})
memory.add_messages(user_id, messages)
return assistant_response
def main():
print("Chat with AI (type 'exit' to quit)")
while True:
user_input = input("You: ").strip()
if user_input.lower() == 'exit':
print("Goodbye!")
break
print(f"AI: {chat_with_memories(user_input)}")
if __name__ == "__main__":
main()
You can also search archival memory with memory.search(user_id, query) to retrieve relevant historical messages (requires skip_vector_storage=False when adding messages).
You can initialize the memory SDK with:
from ai_memory_sdk import Memory
memory = Memory(api_key="LETTA_API_KEY")
Send messages to the Letta agent to update memory blocks:
run = memory.add_messages("user_id", [{"role": "user", "content": "hi"}])
The Letta agent processes messages asynchronously and updates relevant blocks based on their descriptions. The run object tracks this processing.
[!WARNING] Each call to
add_messages(...)invokes the Letta agent. To reduce costs, send messages in batches (recommended 5-10) or only when messages are evicted from context.
Messages are processed asynchronously, so to ensure all memory updates are reflected you should wait for the Letta agent to complete processing.
memory.wait_for_run(run)
This blocks until the Letta agent finishes updating memory blocks.
Retrieve memory blocks (core memory) for the summary and/or user memory:
summary = memory.get_summary("user_id", prompt_formatted=True)
user_memory = memory.get_user_memory("user_id", prompt_formatted=True)
To get the raw block value instead of formatted XML, pass prompt_formatted=False.
You can work with arbitrary subjects (one subject = one Letta agent) and labeled blocks within them. You can bind a Memory instance to a subject or pass a subject per call.
Constructor (instance-scoped subject):
from ai_memory_sdk import Memory
memory = Memory(subject_id="user_sarah")
Subject methods (Python):
initialize_subject(subject_id: str, reset: bool = False) -> strlist_blocks(subject_id: Optional[str] = None) -> listinitialize_memory(label: str, description: str, value: str = "", char_limit: int = 10000, reset: bool = False, subject_id: Optional[str] = None) -> strget_memory(label: str, prompt_formatted: bool = False, subject_id: Optional[str] = None) -> Optional[str]delete_block(label: str, subject_id: Optional[str] = None) -> Noneadd_messages_for_subject(subject_id: str, messages: list, skip_vector_storage: bool = True) -> stradd_messages(messages: list, skip_vector_storage: bool = True) -> str (uses bound subject_id)Example:
memory = Memory(subject_id="user_sarah")
memory.initialize_memory("preferences", "Known user preferences.", "Likes cats")
run = memory.add_messages([{ "role": "user", "content": "I love cats" }])
memory.wait_for_run(run)
print(memory.get_memory("preferences", prompt_formatted=True))
Search archival memory (passages) with semantic search:
messages = memory.search("user_id", query="Favorite foods")
This searches Letta's archival memory (requires skip_vector_storage=False when adding messages). By default it filters to SDK-authored user messages (tags=["ai-memory-sdk", "user"]). To customize:
messages = memory.search("user_id", query="system prompts", tags=["assistant"]) # assistant passages
messages = memory.search("user_id", query="any", tags=[]) # no tag filter
Each subject is backed by a Letta agent (using the sleeptime architecture). Get the agent's ID with:
agent_id = memory.get_memory_agent_id("user_id")
View the agent at https://app.letta.com/agents/<AGENT_ID> to inspect its memory blocks and message history.
Delete the Letta agent and all associated data (blocks, passages) for a user:
memory.delete_user("user_id")
examples/chat.pyexamples/subject.pyexamples/archival_search.pyexamples/customer_support.pyexamples/subject.tsdocs/tutorial.mdexamples/README.mdai-memory-sdk for discoverability and ops. The default search uses this tag in addition to role tags.Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.2.0 | 4 Nov 2025 | 8 |
This describes our collected data; it is not a security assessment.
Observed since 21 Oct, 11:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:61dc2a056860aa269356f3845d3724d1c1be4790a4f0e9c6faa3fb6dc974c38d