From 4a86bf6e4c42add2c9f28363ce6ef8afc97c35ad Mon Sep 17 00:00:00 2001 From: Cameron Pfiffer Date: Tue, 14 Oct 2025 16:47:56 -0700 Subject: [PATCH] docs: Improve examples page (#5442) * Fix VoiceAgent to use run_manager instead of job_manager VoiceAgent.__init__() was incorrectly using job_manager parameter when ToolExecutionManager expects run_manager. This was causing the error: "VoiceAgent.__init__() got an unexpected keyword argument 'run_manager'". Changes: - Update VoiceAgent to accept and use run_manager instead of job_manager - Update VoiceSleeptimeAgent to accept run_manager parameter - Update imports to use RunManager instead of JobManager - Pass run_manager to ToolExecutionManager in VoiceAgent._execute_tool * docs: Add new examples to documentation - Introduced "Your First Agent" example to guide users in creating a Letta agent and understanding its memory capabilities. - Added "Attaching and Detaching Memory Blocks" example to demonstrate dynamic memory management for agents. - Updated navigation in docs.yml to include links to the new examples. These additions enhance the learning resources available for users working with Letta agents. --- fern/docs.yml | 4 + .../examples/attaching_detaching_blocks.mdx | 513 ++++++++++++++++++ fern/pages/examples/hello_world.mdx | 426 +++++++++++++++ letta/agents/voice_agent.py | 10 +- letta/agents/voice_sleeptime_agent.py | 6 +- tests/integration_test_voice_agent.py | 6 +- 6 files changed, 954 insertions(+), 11 deletions(-) create mode 100644 fern/pages/examples/attaching_detaching_blocks.mdx create mode 100644 fern/pages/examples/hello_world.mdx diff --git a/fern/docs.yml b/fern/docs.yml index 99d4a20e..2f0d4ac6 100644 --- a/fern/docs.yml +++ b/fern/docs.yml @@ -605,6 +605,10 @@ navigation: contents: - page: Overview path: pages/cookbooks_simple.mdx + - page: Your First Agent + path: pages/examples/hello_world.mdx + - page: Attaching and Detaching Memory Blocks + path: pages/examples/attaching_detaching_blocks.mdx - section: Multi-Agent contents: - page: Async Multi-Agent diff --git a/fern/pages/examples/attaching_detaching_blocks.mdx b/fern/pages/examples/attaching_detaching_blocks.mdx new file mode 100644 index 00000000..41c2e0f9 --- /dev/null +++ b/fern/pages/examples/attaching_detaching_blocks.mdx @@ -0,0 +1,513 @@ +--- +title: "Attaching and Detaching Memory Blocks" +subtitle: Dynamically control agent memory with attachable blocks +slug: examples/attaching-detaching-blocks +--- + +## Overview + +Memory blocks are structured sections of an agent's context window that persist across all interactions. They're always visible to the agent while they are attached. This makes them perfect for storing information that agents need constant access to, like organizational policies, user preferences, or working memory. + +One of the most powerful features of memory blocks is that they can be created independently and attached to or detached from agents at any time. + +This allows you to: + +- **Dynamically control** what information an agent has access to +- **Share memory** across multiple agents by attaching the same block to different agents +- **Temporarily grant access** to sensitive information, then revoke it when no longer needed +- **Switch contexts** by swapping out blocks as an agent moves between different tasks + +By the end of this guide, you'll understand how to create standalone memory blocks, attach them to agents, detach them to remove access, and re-attach them when needed. + + +For a comprehensive overview of memory blocks and their capabilities, see the [memory blocks guide](/guides/agents/memory-blocks). + + + +**This example uses Letta Cloud.** Generate an API key at [app.letta.com/api-keys](https://app.letta.com/api-keys) and set it as `LETTA_API_KEY` in your environment. Self-hosted servers only need an API key if authentication is enabled. You can learn more about self-hosting [here](/guides/selfhosting). + + +## What You'll Learn + +- Creating standalone memory blocks +- Attaching blocks to agents +- Testing agent access to attached blocks +- Detaching blocks to revoke access +- Re-attaching blocks to restore access + +## Prerequisites + +You will need to install `letta-client` to interface with a Letta server: + + +```bash TypeScript +npm install @letta-ai/letta-client +``` +```bash Python +pip install letta-client +``` + + +## Steps + +### Step 1: Initialize Client and Create Agent + + +```typescript TypeScript +import { LettaClient } from '@letta-ai/letta-client'; + +// Initialize the Letta client using LETTA_API_KEY environment variable +const client = new LettaClient({ token: process.env.LETTA_API_KEY }); + +// If self-hosting, specify the base URL: +// const client = new LettaClient({ baseUrl: "http://localhost:8283" }); + +// Create agent +// API Reference: https://docs.letta.com/api-reference/agents/create +const agent = await client.agents.create({ + name: "hello_world_assistant", + model: "openai/gpt-4o-mini", + // embedding: "openai/text-embedding-3-small", // Only set this if self-hosting +}); + +console.log(`Created agent: ${agent.id}\n`); +``` +```python Python +from letta_client import Letta +import os + +# Initialize the Letta client using LETTA_API_KEY environment variable +client = Letta(token=os.getenv("LETTA_API_KEY")) + +# If self-hosting, specify the base URL: +# client = Letta(base_url="http://localhost:8283") + +# Create agent +# API Reference: https://docs.letta.com/api-reference/agents/create +agent = client.agents.create( + name="hello_world_assistant", + model="openai/gpt-4o-mini", + # embedding="openai/text-embedding-3-small", # Only set this if self-hosting +) + +print(f"Created agent: {agent.id}\n") +``` + + + +``` +Created agent: agent-a1b2c3d4-e5f6-7890-abcd-ef1234567890 +``` + + +### Step 2: Create a Standalone Memory Block + +Memory blocks can be created independently of any agent. This allows you to share the same block across multiple agents or attach/detach blocks as needed. + +In this example, we'll create a standalone memory block storing information about Letta. We'll include a code that you can use to get the agent to respond to indicate that it has access to information in the block. + +When the block is attached, writing "The code is TimberTheDog1234!" will cause the agent to respond with "Access granted". If the block is not attached, the agent will not have access to any content in the block and will likely be confused by the code. + + +```typescript TypeScript +// Create memory block storing information about Letta +// API Reference: https://docs.letta.com/api-reference/blocks/create +const block = await client.blocks.create({ + label: "organization", + value: `Organization: Letta +Website: https://www.letta.com +Description: Letta is a platform for building and running stateful agents. +Code: TimberTheDog1234! + +When users provide a code, you should check if it matches the code you have +available. If it matches, you should respond with "Access granted".` +}); + +console.log(`Created block: ${block.id}\n`); +``` +```python Python +# Create memory block storing information about Letta +# API Reference: https://docs.letta.com/api-reference/blocks/create +block = client.blocks.create( + label="organization", + value="""Organization: Letta +Website: https://www.letta.com +Description: Letta is a platform for building and running stateful agents. +Code: TimberTheDog1234! + +When users provide a code, you should check if it matches the code you have +available. If it matches, you should respond with "Access granted".""", +) + +print(f"Created block: {block.id}\n") +``` + + + +``` +Created block: block-a1b2c3d4-e5f6-7890-abcd-ef1234567890 +``` + + +### Step 3: Attach Block to Agent + +Now let's attach the block to our agent. Attached blocks are injected into the agent's context window and are available to the agent to use in its responses. + + +```typescript TypeScript +// Attach memory block to agent +// API Reference: https://docs.letta.com/api-reference/agents/blocks/attach +await client.agents.blocks.attach(agent.id, { blockId: block.id }); + +console.log(`Attached block ${block.id} to agent ${agent.id}\n`); +``` +```python Python +# Attach memory block to agent +# API Reference: https://docs.letta.com/api-reference/agents/blocks/attach +agent = client.agents.blocks.attach( + agent_id=agent.id, + block_id=block.id, +) + +print(f"Attached block {block.id} to agent {agent.id}\n") +``` + + +### Step 4: Test Agent Access to Block + +The agent can now see what's in the block. Let's ask it about Letta to verify that it can see the general information in the block -- the description, website, and organization name. + + +```typescript TypeScript +// Send a message to test the agent's knowledge +// API Reference: https://docs.letta.com/api-reference/agents/messages/create +const response = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "What is Letta?" }] +}); + +for (const msg of response.messages) { + if (msg.messageType === "assistant_message") { + console.log(`Agent response: ${msg.content}\n`); + } +} +``` +```python Python +# Send a message to test the agent's knowledge +# API Reference: https://docs.letta.com/api-reference/agents/messages/create +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "What is Letta?"}], +) + +for msg in response.messages: + if msg.message_type == "assistant_message": + print(f"Agent response: {msg.content}\n") +``` + + +The agent will respond with general information about Letta: + +> **Agent response**: Letta is a platform designed for building and running stateful +> agents. You can find more information about it on their website: +> https://www.letta.com + +### Step 5: Detach Block from Agent + +Blocks can be detached from an agent, removing them from the agent's context window. Detached blocks are not deleted and can be re-attached to an agent later. + + +```typescript TypeScript +// Detach the block from the agent +// API Reference: https://docs.letta.com/api-reference/agents/blocks/detach +await client.agents.blocks.detach(agent.id, block.id); + +console.log(`Detached block ${block.id} from agent ${agent.id}\n`); +``` +```python Python +# Detach the block from the agent +# API Reference: https://docs.letta.com/api-reference/agents/blocks/detach +agent = client.agents.blocks.detach( + agent_id=agent.id, + block_id=block.id, +) + +print(f"Detached block {block.id} from agent {agent.id}\n") +``` + + +### Step 6: Verify Block is Detached + +Let's test the code that was in the block. The agent should no longer have access to it. + + +```typescript TypeScript +// Test that the agent no longer has access to the code +const response2 = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "The code is TimberTheDog1234!" }] +}); + +for (const msg of response2.messages) { + if (msg.messageType === "assistant_message") { + console.log(`Agent response: ${msg.content}\n`); + } +} +``` +```python Python +# Test that the agent no longer has access to the code +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "The code is TimberTheDog1234!"}], +) + +for msg in response.messages: + if msg.message_type == "assistant_message": + print(f"Agent response: {msg.content}\n") +``` + + + +``` +Agent response: It seems like you've provided a code or password. If this is +sensitive information, please ensure you only share it with trusted parties and +in secure environments. Let me know how I can assist you further! +``` + + + +The agent doesn't recognize the code because the block containing that information has been detached. + + +### Step 7: Re-attach Block and Test Again + +Let's re-attach the block to restore the agent's access to the information. + + +```typescript TypeScript +// Re-attach the block to the agent +await client.agents.blocks.attach(agent.id, { blockId: block.id }); + +console.log(`Re-attached block ${block.id} to agent ${agent.id}\n`); + +// Test the code again +const response3 = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "The code is TimberTheDog1234!" }] +}); + +for (const msg of response3.messages) { + if (msg.messageType === "assistant_message") { + console.log(`Agent response: ${msg.content}\n`); + } +} +``` +```python Python +# Re-attach the block to the agent +agent = client.agents.blocks.attach( + agent_id=agent.id, + block_id=block.id, +) + +print(f"Re-attached block {block.id} to agent {agent.id}\n") + +# Test the code again +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "The code is TimberTheDog1234!"}], +) + +for msg in response.messages: + if msg.message_type == "assistant_message": + print(f"Agent response: {msg.content}\n") +``` + + + +``` +Agent response: Access granted. How can I assist you further? +``` + + + +The agent now recognizes the code because we've re-attached the block containing that information. + + +## Complete Example + +Here's the full code in one place that you can run: + + +```typescript TypeScript +import { LettaClient } from '@letta-ai/letta-client'; + +// Initialize client +const client = new LettaClient({ token: process.env.LETTA_API_KEY }); + +// Create agent +const agent = await client.agents.create({ + name: "hello_world_assistant", + model: "openai/gpt-4o-mini", +}); + +console.log(`Created agent: ${agent.id}\n`); + +// Create standalone memory block +const block = await client.blocks.create({ + label: "organization", + value: `Organization: Letta +Website: https://www.letta.com +Description: Letta is a platform for building and running stateful agents. +Code: TimberTheDog1234! + +When users provide a code, you should check if it matches the code you have +available. If it matches, you should respond with "Access granted".` +}); + +console.log(`Created block: ${block.id}\n`); + +// Attach block to agent +await client.agents.blocks.attach(agent.id, { blockId: block.id }); +console.log(`Attached block to agent\n`); + +// Test agent with block attached +let response = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "What is Letta?" }] +}); +console.log(`Agent response: ${response.messages[0].content}\n`); + +// Detach block +await client.agents.blocks.detach(agent.id, block.id); +console.log(`Detached block from agent\n`); + +// Test agent without block +response = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "The code is TimberTheDog1234!" }] +}); +console.log(`Agent response: ${response.messages[0].content}\n`); + +// Re-attach block +await client.agents.blocks.attach(agent.id, { blockId: block.id }); +console.log(`Re-attached block to agent\n`); + +// Test agent with block re-attached +response = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "The code is TimberTheDog1234!" }] +}); +console.log(`Agent response: ${response.messages[0].content}\n`); +``` +```python Python +from letta_client import Letta +import os + +# Initialize client +client = Letta(token=os.getenv("LETTA_API_KEY")) + +# Create agent +agent = client.agents.create( + name="hello_world_assistant", + model="openai/gpt-4o-mini", +) + +print(f"Created agent: {agent.id}\n") + +# Create standalone memory block +block = client.blocks.create( + label="organization", + value="""Organization: Letta +Website: https://www.letta.com +Description: Letta is a platform for building and running stateful agents. +Code: TimberTheDog1234! + +When users provide a code, you should check if it matches the code you have +available. If it matches, you should respond with "Access granted".""", +) + +print(f"Created block: {block.id}\n") + +# Attach block to agent +agent = client.agents.blocks.attach( + agent_id=agent.id, + block_id=block.id, +) +print(f"Attached block to agent\n") + +# Test agent with block attached +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "What is Letta?"}], +) +print(f"Agent response: {response.messages[0].content}\n") + +# Detach block +agent = client.agents.blocks.detach( + agent_id=agent.id, + block_id=block.id, +) +print(f"Detached block from agent\n") + +# Test agent without block +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "The code is TimberTheDog1234!"}], +) +print(f"Agent response: {response.messages[0].content}\n") + +# Re-attach block +agent = client.agents.blocks.attach( + agent_id=agent.id, + block_id=block.id, +) +print(f"Re-attached block to agent\n") + +# Test agent with block re-attached +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "The code is TimberTheDog1234!"}], +) +print(f"Agent response: {response.messages[0].content}\n") +``` + + +## Key Concepts + + + +Memory blocks can be created independently and shared across multiple agents + + + +Attach and detach blocks to control what information an agent can access + + + +Detached blocks are not deleted and can be re-attached at any time + + + +The same block can be attached to multiple agents, enabling shared knowledge + + + +## Use Cases + + + +Attach a block with credentials or sensitive data only when needed, then detach it to prevent unauthorized access. + + + +Create a single block with organizational knowledge and attach it to multiple agents to ensure consistency. + + + +Detach blocks related to one task and attach blocks for another, allowing an agent to switch contexts efficiently. + + + +Give different agents access to different blocks based on their roles or permissions. + + + +## Next Steps + + +Learn more about memory blocks, including how to update them and manage their lifecycle + diff --git a/fern/pages/examples/hello_world.mdx b/fern/pages/examples/hello_world.mdx new file mode 100644 index 00000000..a589ba55 --- /dev/null +++ b/fern/pages/examples/hello_world.mdx @@ -0,0 +1,426 @@ +--- +title: "Your First Letta Agent" +subtitle: Create an agent, send messages, and understand basic memory +slug: examples/hello-world +--- + +This example walks you through creating your first Letta agent from scratch. Unlike traditional chatbots that forget everything between conversations, Letta agents are **stateful** - they maintain persistent memory and can learn about you over time. + +By the end of this guide, you'll understand how to create an agent, send it messages, and see how it automatically updates its memory based on your interactions. + + +**This example uses Letta Cloud.** Generate an API key at [app.letta.com/api-keys](https://app.letta.com/api-keys) and set it as `LETTA_API_KEY` in your environment. Self-hosted servers only need an API key if authentication is enabled. You can learn more about self-hosting [here](/guides/selfhosting). + + +## What You'll Learn + +- Initializing the Letta client +- Creating an agent with [memory blocks](/guides/agents/memory-blocks) +- Sending messages and receiving responses +- How agents update their own memory +- Inspecting memory tool calls and block contents + +## Prerequisites + +You will need to install `letta-client` to interface with a Letta server: + + +```bash TypeScript +npm install @letta-ai/letta-client +``` +```bash Python +pip install letta-client +``` + + +## Steps + +### Step 1: Initialize Client + +A __client__ is a connection to a Letta server. It's used to create and interact with agents, as well as any of Letta's other features. + + +```typescript TypeScript +import { LettaClient } from '@letta-ai/letta-client'; + +// Initialize the Letta client using LETTA_API_KEY environment variable +const client = new LettaClient({ token: process.env.LETTA_API_KEY }); + +// If self-hosting, specify the base URL: +// const client = new LettaClient({ baseUrl: "http://localhost:8283" }); +``` +```python Python +from letta_client import Letta +import os + +# Initialize the Letta client using LETTA_API_KEY environment variable +client = Letta(token=os.getenv("LETTA_API_KEY")) + +# If self-hosting, specify the base URL: +# client = Letta(base_url="http://localhost:8283") +``` + + +### Step 2: Create Agent + +Now that we have a client, let's create an agent with memory blocks that define what the agent knows about itself and you. Memory blocks can be used for any purpose, but we're building a simple chatbot that stores information about its personality (`persona`) and you (`human`). + + +```typescript TypeScript +// Create your first agent +// API Reference: https://docs.letta.com/api-reference/agents/create +const agent = await client.agents.create({ + name: "hello_world_assistant", + + // Memory blocks define what the agent knows about itself and you. + // Agents can modify these blocks during conversations using memory + // tools like memory_replace, memory_insert, memory_rethink, and memory. + memoryBlocks: [ + { + label: "persona", + value: "I am a friendly AI assistant here to help you learn about Letta." + }, + { + label: "human", + value: "Name: User\nFirst interaction: Learning about Letta" + } + ], + + // Model configuration + model: "openai/gpt-4o-mini", + // embedding: "openai/text-embedding-3-small", // Only set this if self-hosting +}); + +console.log(`Created agent: ${agent.id}`); +``` +```python Python +# Create your first agent +# API Reference: https://docs.letta.com/api-reference/agents/create +agent = client.agents.create( + name="hello_world_assistant", + + # Memory blocks define what the agent knows about itself and you + memory_blocks=[ + { + "label": "persona", + "value": "I am a friendly AI assistant here to help you learn about Letta." + }, + { + "label": "human", + "value": "Name: User\nFirst interaction: Learning about Letta" + } + ], + + # Model configuration + model="openai/gpt-4o-mini", + # embedding="openai/text-embedding-3-small", # Only set this if self-hosting +) + +print(f"Created agent: {agent.id}") +``` + + + +``` +Created agent: agent-a1b2c3d4-e5f6-7890-abcd-ef1234567890 +``` + + + +**Memory blocks** are the foundation of Letta agents. The `persona` block defines the agent's identity and behavior, while the `human` block stores information about the user. Learn more in the [Memory Blocks guide](/guides/agents/memory-blocks). + + +### Step 3: Send Your First Message + +Now let's send a message to the agent to see what it can do. + + +```typescript TypeScript +// Send a message to your agent +// API Reference: https://docs.letta.com/api-reference/agents/messages/create +const response = await client.agents.messages.create(agent.id, { + messages: [{ + role: "user", + content: "Hello! What's your purpose?" + }] +}); + +// Extract and print the assistant's response +for (const message of response.messages) { + if (message.messageType === "assistant_message") { + console.log(`Assistant: ${message.content}`); + } +} +``` +```python Python +# Send a message to your agent +# API Reference: https://docs.letta.com/api-reference/agents/messages/create +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{ + "role": "user", + "content": "Hello! What's your purpose?" + }] +) + +# Extract and print the assistant's response +for message in response.messages: + if message.message_type == "assistant_message": + print(f"Assistant: {message.content}") +``` + + + +``` +Assistant: Hello! I'm here to help you learn about Letta and answer any questions +you might have. Letta is a framework for building stateful AI agents with long-term +memory. I can explain concepts, provide examples, and guide you through using the +platform. What would you like to know? +``` + + +### Step 4: Provide Information for the Agent to Remember + +Now let's give the agent some information about yourself. If prompted correctly, the agent can add this information to a relevant memory block using one of its default memory tools. Unless tools are modified during creation, new agents usually have `memory_insert` and `memory_replace` tools. + + +```typescript TypeScript +// Send information about yourself +const response2 = await client.agents.messages.create(agent.id, { + messages: [{ + role: "user", + content: "My name is Cameron. Please store this information in your memory." + }] +}); + +// Print out tool calls and the assistant's response +for (const msg of response2.messages) { + if (msg.messageType === "assistant_message") { + console.log(`Assistant: ${msg.content}\n`); + } + if (msg.messageType === "tool_call_message") { + console.log(`Tool call: ${msg.toolCall.name}(${JSON.stringify(msg.toolCall.arguments)})`); + } +} +``` +```python Python +# Send information about yourself +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "My name is Cameron. Please store this information in your memory."}] +) + +# Print out tool calls and the assistant's response +for msg in response.messages: + if msg.message_type == "assistant_message": + print(f"Assistant: {msg.content}\n") + if msg.message_type == "tool_call_message": + print(f"Tool call: {msg.tool_call.name}({msg.tool_call.arguments})") +``` + + + +``` +Tool call: memory_replace({"block_label": "human", "old_content": "Name: User", "new_content": "Name: Cameron"}) +Assistant: Got it! I've updated my memory with your name, Cameron. How can I assist you today? +``` + + + +Notice the `tool_call_message` showing the agent using the `memory_replace` tool to update the `human` block. This is how Letta agents manage their own memory. + + +### Step 5: Inspect Agent Memory + +Let's see what the agent remembers. We'll print out both the summary and the full content of each memory block: + + +```typescript TypeScript +// Retrieve the agent's current memory blocks +// API Reference: https://docs.letta.com/api-reference/agents/blocks/list +const blocks = await client.agents.blocks.list(agent.id); + +console.log("Current Memory:"); +for (const block of blocks) { + console.log(` ${block.label}: ${block.value.length}/${block.limit} chars`); + console.log(` ${block.value}\n`); +} +``` +```python Python +# Retrieve the agent's current memory blocks +# API Reference: https://docs.letta.com/api-reference/agents/blocks/list +blocks = client.agents.blocks.list(agent_id=agent.id) + +print("Current Memory:") +for block in blocks: + print(f" {block.label}: {len(block.value)}/{block.limit} chars") + print(f" {block.value}\n") +``` + + +The `persona` block should have: + +> I am a friendly AI assistant here to help you learn about Letta. + +The `human` block should have something like: + +> Name: Cameron + + + +Notice how the `human` block now contains "Name: Cameron" instead of "Name: User". The agent used the `memory_replace` tool to update its memory based on the information you provided. + + +## Complete Example + +Here's the full code in one place that you can run: + + +```typescript TypeScript +import { LettaClient } from '@letta-ai/letta-client'; + +// Initialize client using LETTA_API_KEY environment variable +const client = new LettaClient({ token: process.env.LETTA_API_KEY }); + +// If self-hosting, specify the base URL: +// const client = new LettaClient({ baseUrl: "http://localhost:8283" }); + +// Create agent +const agent = await client.agents.create({ + name: "hello_world_assistant", + memoryBlocks: [ + { + label: "persona", + value: "I am a friendly AI assistant here to help you learn about Letta." + }, + { + label: "human", + value: "Name: User\nFirst interaction: Learning about Letta" + } + ], + model: "openai/gpt-4o-mini", + // embedding: "openai/text-embedding-3-small", // Only set this if self-hosting +}); + +console.log(`Created agent: ${agent.id}\n`); + +// Send first message +let response = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "Hello! What's your purpose?" }] +}); + +for (const msg of response.messages) { + if (msg.messageType === "assistant_message") { + console.log(`Assistant: ${msg.content}\n`); + } +} + +// Send information about yourself +response = await client.agents.messages.create(agent.id, { + messages: [{ role: "user", content: "My name is Cameron. Please store this information in your memory." }] +}); + +// Print out tool calls and the assistant's response +for (const msg of response.messages) { + if (msg.messageType === "assistant_message") { + console.log(`Assistant: ${msg.content}\n`); + } + if (msg.messageType === "tool_call_message") { + console.log(`Tool call: ${msg.toolCall.name}(${JSON.stringify(msg.toolCall.arguments)})`); + } +} + +// Inspect memory +const blocks = await client.agents.blocks.list(agent.id); +console.log("Current Memory:"); +for (const block of blocks) { + console.log(` ${block.label}: ${block.value.length}/${block.limit} chars`); + console.log(` ${block.value}\n`); +} +``` +```python Python +from letta_client import Letta +import os + +# Initialize client using LETTA_API_KEY environment variable +client = Letta(token=os.getenv("LETTA_API_KEY")) + +# If self-hosting, specify the base URL: +# client = Letta(base_url="http://localhost:8283") + +# Create agent +agent = client.agents.create( + name="hello_world_assistant", + memory_blocks=[ + { + "label": "persona", + "value": "I am a friendly AI assistant here to help you learn about Letta." + }, + { + "label": "human", + "value": "Name: User\nFirst interaction: Learning about Letta" + } + ], + model="openai/gpt-4o-mini", + # embedding="openai/text-embedding-3-small", # Only set this if self-hosting +) + +print(f"Created agent: {agent.id}\n") + +# Send first message +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "Hello! What's your purpose?"}] +) + +for msg in response.messages: + if msg.message_type == "assistant_message": + print(f"Assistant: {msg.content}\n") + +# Send information about yourself +response = client.agents.messages.create( + agent_id=agent.id, + messages=[{"role": "user", "content": "My name is Cameron. Please store this information in your memory."}] +) + +# Print out tool calls and the assistant's response +for msg in response.messages: + if msg.message_type == "assistant_message": + print(f"Assistant: {msg.content}\n") + if msg.message_type == "tool_call_message": + print(f"Tool call: {msg.tool_call.name}({msg.tool_call.arguments})") + +# Inspect memory +blocks = client.agents.blocks.list(agent_id=agent.id) +print("Current Memory:") +for block in blocks: + print(f" {block.label}: {len(block.value)}/{block.limit} chars") + print(f" {block.value}\n") +``` + + +## Key Concepts + + + +Letta agents maintain memory across conversations, unlike stateless chat APIs + + + +Modular memory components that agents can read and update during conversations + + + +Agents remember user preferences, conversation history, and learned information + + + +Agents intelligently update their memory as they learn more about you + + + +## Next Steps + + +Learn how to work with memory blocks, update them, and control agent knowledge + diff --git a/letta/agents/voice_agent.py b/letta/agents/voice_agent.py index 38d6c16a..2c7dc5f5 100644 --- a/letta/agents/voice_agent.py +++ b/letta/agents/voice_agent.py @@ -36,9 +36,9 @@ from letta.server.rest_api.utils import ( ) from letta.services.agent_manager import AgentManager from letta.services.block_manager import BlockManager -from letta.services.job_manager import JobManager from letta.services.message_manager import MessageManager from letta.services.passage_manager import PassageManager +from letta.services.run_manager import RunManager from letta.services.summarizer.enums import SummarizationMode from letta.services.summarizer.summarizer import Summarizer from letta.services.tool_executor.tool_execution_manager import ToolExecutionManager @@ -63,7 +63,7 @@ class VoiceAgent(BaseAgent): message_manager: MessageManager, agent_manager: AgentManager, block_manager: BlockManager, - job_manager: JobManager, + run_manager: RunManager, passage_manager: PassageManager, actor: User, ): @@ -73,7 +73,7 @@ class VoiceAgent(BaseAgent): # Summarizer settings self.block_manager = block_manager - self.job_manager = job_manager + self.run_manager = run_manager self.passage_manager = passage_manager # TODO: This is not guaranteed to exist! self.summary_block_label = "human" @@ -99,7 +99,7 @@ class VoiceAgent(BaseAgent): agent_manager=self.agent_manager, actor=self.actor, block_manager=self.block_manager, - job_manager=self.job_manager, + run_manager=self.run_manager, passage_manager=self.passage_manager, target_block_label=self.summary_block_label, ), @@ -444,7 +444,7 @@ class VoiceAgent(BaseAgent): message_manager=self.message_manager, agent_manager=self.agent_manager, block_manager=self.block_manager, - job_manager=self.job_manager, + run_manager=self.run_manager, passage_manager=self.passage_manager, sandbox_env_vars=sandbox_env_vars, actor=self.actor, diff --git a/letta/agents/voice_sleeptime_agent.py b/letta/agents/voice_sleeptime_agent.py index f2b3b426..fbd5d145 100644 --- a/letta/agents/voice_sleeptime_agent.py +++ b/letta/agents/voice_sleeptime_agent.py @@ -14,9 +14,9 @@ from letta.schemas.tool_rule import ChildToolRule, ContinueToolRule, InitToolRul from letta.schemas.user import User from letta.services.agent_manager import AgentManager from letta.services.block_manager import BlockManager -from letta.services.job_manager import JobManager from letta.services.message_manager import MessageManager from letta.services.passage_manager import PassageManager +from letta.services.run_manager import RunManager from letta.services.summarizer.enums import SummarizationMode from letta.services.summarizer.summarizer import Summarizer from letta.types import JsonDict @@ -34,7 +34,7 @@ class VoiceSleeptimeAgent(LettaAgent): message_manager: MessageManager, agent_manager: AgentManager, block_manager: BlockManager, - job_manager: JobManager, + run_manager: RunManager, passage_manager: PassageManager, target_block_label: str, actor: User, @@ -44,7 +44,7 @@ class VoiceSleeptimeAgent(LettaAgent): message_manager=message_manager, agent_manager=agent_manager, block_manager=block_manager, - job_manager=job_manager, + job_manager=run_manager, passage_manager=passage_manager, actor=actor, ) diff --git a/tests/integration_test_voice_agent.py b/tests/integration_test_voice_agent.py index 363c4a33..e3149966 100644 --- a/tests/integration_test_voice_agent.py +++ b/tests/integration_test_voice_agent.py @@ -25,9 +25,9 @@ from letta.schemas.usage import LettaUsageStatistics from letta.server.server import SyncServer from letta.services.agent_manager import AgentManager from letta.services.block_manager import BlockManager -from letta.services.job_manager import JobManager from letta.services.message_manager import MessageManager from letta.services.passage_manager import PassageManager +from letta.services.run_manager import RunManager from letta.services.summarizer.enums import SummarizationMode from letta.services.summarizer.summarizer import Summarizer from letta.services.tool_manager import ToolManager @@ -378,7 +378,7 @@ async def test_summarization(disable_e2b_api_key, voice_agent, server_url): agent_manager=agent_manager, actor=actor, block_manager=BlockManager(), - job_manager=JobManager(), + run_manager=RunManager(), passage_manager=PassageManager(), target_block_label="human", ) @@ -457,7 +457,7 @@ async def test_voice_sleeptime_agent(disable_e2b_api_key, voice_agent): agent_manager=agent_manager, actor=actor, block_manager=BlockManager(), - job_manager=JobManager(), + run_manager=RunManager(), passage_manager=PassageManager(), target_block_label="human", )