Create an agent once. Resume it from anywhere.
The TypeScript SDK for stateful agents. Identity and memory stay with the agent — not the process, the model, or the machine.
npm install @letta-ai/letta-agent-sdk import { LettaAgentClient }
from "@letta-ai/letta-agent-sdk";
const client = new LettaAgentClient({
backend: "cloud",
});
// Create the agent once...
const agentId = await client.createAgent({
persona: "You are Nora, an analyst.",
});
// → "agent-3f97f111-…"// ...then resume it, from anywhere.
await using session =
client.resumeSession(agentId);
await session.send(
"What changed since last week?");
for await (const msg of session.stream()) {
if (msg.type === "assistant")
process.stdout.write(msg.content);
}
// → streams Nora's Thursday briefSame agent, different process. Nora already knows who she is, what changed since last week, and how you like your briefs.
Built by the team behind MemGPT, the paper that introduced memory management for LLM agents. Open source on GitHub.
Memory is part of the agent, not the app
Memory is a git repository the agent owns. It follows the agent everywhere it works, and the agent edits it as it learns.
const agentId = await client.createAgent({
model: "anthropic/claude-opus-4-8",
memory: [{
label: "persona",
value: "You are Quinn, an analyst.",
}, {
label: "team-context",
value: "The team ships on Thursdays.",
}],
});This repository follows the agent, not your repo.
system/memory you set at creation is in the system prompt every turn; everything else stays out of context until the agent reads it.dreamingbackground subagents consolidate lessons into memory without interrupting active work.trigger: "step-count" | "compaction-event" | "off",behavior: "reminder" | "auto-launch".skillsinstall packaged instructions into the agent's own memory, versioned with the agent:letta skills install anthropics/skills/pdf.stateless: truerun a one-off session that does not load or change the agent's memory.
One interface. Three backends.
One client, three backends. Swap one string — nothing else changes.
// Managed everything. State lives
// in Letta Cloud; tools in a sandbox.
const client = new LettaAgentClient({
backend: "cloud",
apiKey: process.env.LETTA_API_KEY,
});// No account, no server to start —
// the SDK owns a local App Server.
// State stays on this machine.
const client = new LettaAgentClient({
backend: "local",
});// letta server --backend local
// --listen ws://127.0.0.1:4500
const client = new LettaAgentClient({
backend: "remote",
url: "http://127.0.0.1:4500",
authToken:
process.env.LETTA_APP_SERVER_TOKEN,
});"cloud" | "local" | "remote" | |
|---|---|---|---|
| Agent state lives | Letta Cloud | Current machine | Determined by the App Server backend |
| Tools execute | Managed sandbox, or a computer you connect | Current machine | App Server machine |
| Account required | Letta API key | None | Your own auth token |
| Runtime you run | None | SDK-owned subprocess (Node 22.19+) | App Server you operate (Node 22.19+) |
| Best for | Managed everything | Fully local state and execution | A runtime under your control |
No account required for the local backend. Your code doesn't change when you swap the backend string.
TypeScript and JavaScript today; Python applications use the App Server WebSocket protocol directly.
Deployment guide→Pick the computer. Keep the agent.
A computer is where the agent works — separate from who the agent is. Managed sandbox by default, or connect your own machine.
// Managed sandbox by default,
// kept warm across reconnects —
// or bring your own machine:
await using session =
client.resumeSession(agentId, {
computer: { name: "work-laptop" },
cwd: "/workspace/project",
});One agent, three places it can work today.
Typed events in, render-ready rows out
Streaming, queueing, and optimistic updates — in the same client the browser uses. The accumulator turns the event stream into rows your UI renders.
import { createTranscriptAccumulator }
from "@letta-ai/letta-agent-sdk";
const transcript =
createTranscriptAccumulator();
await session.send(
"Summarize yesterday's deploys.");
for await (const msg of session.stream()) {
const rows = transcript.apply(msg);
render(rows);
}queuemessages sent mid-turn are queued by the runtime, not dropped.resumea dropped connection ends the session, not the agent:resumeSession(conversationId), then reconcile withlistMessages()orbootstrapState().otidpass your ownotidonsend(text, { otid })and the persisted message carries it back, so optimistic rows reconcile instead of re-rendering.recoverPendingApprovals()approvals left pending on the runtime re-arrive in your new session's callback.
Human approvals are part of the turn
Gate any tool call on your own UI. The turn waits for the human's Allow or Deny — and approvals left pending survive a dropped connection.
// inside createSession(agentId, { … }):
canUseTool: async (tool, args, ctx) => {
// your approval UI:
const ok = await askUser(tool, ctx);
return ok
? { behavior: "allow" }
: { behavior: "deny", interrupt: true };
},Your UI shows the tool call and its diff; the turn waits for the human's Allow or Deny.
Start from a running app
Every example is a complete application in the SDK repository. Clone it, install, run.
web-chat→
A web UI for chatting with an agent — streaming to the browser.
bug-fixer→
A stateful agent that finds and fixes bugs, remembering the codebase and past fixes across sessions.
research-team→
A multi-agent research system — shared memory and collaborative agents that improve over time.
release-notes→
Release notes from git commits, learning your formatting preferences over time.
custom-tools→
Client tools that execute locally in your process while the agent runs in a cloud sandbox.
dungeon-master→
A stateful DM that creates its own game system and keeps campaigns in MemFS.
git clone \
https://github.com/letta-ai/letta-agent-sdk
cd letta-agent-sdk/examples/web-chat
npm installYour first stateful agent is one npm install away
npm install @letta-ai/letta-agent-sdk No account needed for the local backend. Cloud needs an API key. Node.js 22.19+ only if you run the runtime yourself.
