--- title: SDK v1.0 Migration Guide subtitle: Upgrading from v0.x to v1.0 slug: api-reference/sdk-migration-guide --- This guide covers migrating from Letta SDK v0.x (e.g., `1.0.0-alpha.2`) to v1.0 (e.g., `1.0.0-alpha.10`+). For agent architecture migrations, see the [Architecture Migration Guide](/guides/legacy/migration_guide). **Letta Cloud Only (for now)** This SDK v1.0 migration guide applies **only to Letta Cloud**. The current self-hosted Letta release (v0.13.x) does **not** support the v1.0 SDK. If you are self-hosting Letta, continue using SDK v0.x for now. **Coming soon:** We will be releasing a new open-source version of Letta that includes SDK v1.0 support for self-hosted deployments. To use the v1.0 SDK today, you must connect to Letta Cloud at `https://api.letta.com`. ## Overview SDK v1.0 introduces breaking changes to improve consistency and align with modern API design patterns: - **Naming convention**: All properties now use `snake_case` instead of `camelCase` - **Client initialization**: Simplified client constructor with renamed parameters - **Method names**: Several methods renamed for clarity - **Type imports**: Types moved to subpath exports for better organization - **Enums**: Replaced with string literal types - **Tool calls**: Changed from single object to array structure - **Pagination**: List methods now return page objects ## Quick Reference ### Package Update Update your package dependency: ```json package.json { "dependencies": { - "@letta-ai/letta-client": "1.0.0-alpha.2" + "@letta-ai/letta-client": "1.0.0-alpha.10" } } ``` ```toml pyproject.toml [tool.poetry.dependencies] -letta-client = "1.0.0a2" +letta-client = "1.0.0a10" ``` ### Import Changes ```typescript TypeScript // Old - import { LettaClient, Letta } from "@letta-ai/letta-client"; // New + import Letta from "@letta-ai/letta-client"; + import type { + Block, + CreateBlock, + AgentType + } from "@letta-ai/letta-client/resources/agents/agents"; + import type { + LettaMessageUnion, + ApprovalCreate + } from "@letta-ai/letta-client/resources/agents/messages"; + import type { + LlmConfig + } from "@letta-ai/letta-client/resources/models/models"; ``` ```python Python # Old - from letta_client import Letta, LettaClient # New + from letta import Letta + from letta.schemas.agent import Block, CreateBlock, AgentType + from letta.schemas.message import LettaMessageUnion, ApprovalCreate + from letta.schemas.llm_config import LlmConfig ``` ### Client Instantiation ```typescript TypeScript // Old - const client = new LettaClient({ - token: process.env.LETTA_API_KEY, - baseUrl: "https://api.letta.com" - }); // New + const client = new Letta({ + apiKey: process.env.LETTA_API_KEY, + baseURL: "https://api.letta.com" + }); ``` ```python Python # Old - client = LettaClient( - token=os.environ["LETTA_API_KEY"], - base_url="https://api.letta.com" - ) # New + client = Letta( + api_key=os.environ["LETTA_API_KEY"], + base_url="https://api.letta.com" + ) ``` ## Breaking Changes by Category ### 1. Pagination All list endpoints now use cursor-based pagination with consistent parameters: ```typescript TypeScript // Old - various pagination styles const messages = await client.agents.messages.list(agentId, { sort_by: "created_at", ascending: true }); // New - standardized cursor pagination const messagesPage = await client.agents.messages.list(agentId, { before: "msg_123", // cursor (message ID) after: "msg_456", // cursor (message ID) limit: 50, order: "asc" // or "desc" }); const messages = messagesPage.items; ``` ```python Python # Old messages = client.agents.messages.list( agent_id=agent_id, sort_by="created_at", ascending=True ) # New messages_page = client.agents.messages.list( agent_id=agent_id, before="msg_123", after="msg_456", limit=50, order="asc" ) messages = messages_page.items ``` **Affected endpoints:** - `agents.list()` - renamed `sort_by` → `order_by`, `ascending` → `order` - `agents.messages.list()` - `agents.tools.list()` - `agents.blocks.list()` - `agents.files.list()` - `agents.folders.list()` - `agents.groups.list()` - `blocks.list()` - `folders.list()` - `folders.files.list()` - `folders.passages.list()` - `folders.agents.list()` - `groups.list()` - `groups.messages.list()` - `identities.list()` - `providers.list()` - `runs.list()` - `runs.messages.list()` - `runs.steps.list()` - `jobs.list()` - `steps.list()` - `tags.list()` - `tools.list()` - `batches.list()` - `batches.messages.list()` ### 2. Method Renames and Endpoint Restructuring Many methods were reorganized for better SDK structure: ```typescript TypeScript // Agent updates - await client.agents.modify(agentId, updates) + await client.agents.update(agentId, updates) // Message operations - await client.agents.summarize_agent_conversation(agentId) + await client.agents.messages.compact(agentId) - await client.agents.cancel_agent_run(agentId) + await client.agents.messages.cancel(agentId) - await client.agents.messages.preview_raw_payload(agentId, messages) + await client.agents.messages.preview(agentId, messages) // Agent file operations - await client.agents.list_agent_files(agentId) + await client.agents.files.list(agentId) // Export/Import - await client.agents.export_agent_serialized(agentId) + await client.agents.exportFile(agentId) - await client.agents.import_agent_serialized(file) + await client.agents.importFile(file) // Folder operations - await client.folders.get_agents_for_folder(folderId) + await client.folders.agents.list(folderId) - await client.folders.retrieve_folder_metadata(folderId) + await client.folders.retrieve_metadata(folderId) // Provider operations - await client.providers.check_provider(providerId) + await client.providers.check(providerId) // Telemetry - await client.telemetry.retrieve_provider_trace(stepId) + await client.steps.trace(stepId) // Step metrics - await client.steps.retrieve_step_metrics(stepId) + await client.steps.metrics.retrieve(stepId) // Batch messages - await client.messages.list_batch_messages(batchId) + await client.batches.messages.list(batchId) // Multi-agent groups - agent.multi_agent_group + agent.managed_group ``` ```python Python # Agent updates - client.agents.modify(agent_id, **updates) + client.agents.update(agent_id, **updates) // Message operations - client.agents.summarize_agent_conversation(agent_id) + client.agents.messages.compact(agent_id) - client.agents.cancel_agent_run(agent_id) + client.agents.messages.cancel(agent_id) // Export/Import - client.agents.export_agent_serialized(agent_id) + client.agents.export_file(agent_id) - client.agents.import_agent_serialized(file) + client.agents.import_file(file) // Folder operations - client.folders.get_agents_for_folder(folder_id) + client.folders.agents.list(folder_id) // Provider operations - client.providers.check_provider(provider_id) + client.providers.check(provider_id) ``` ### 3. Deprecations Several endpoints and fields are now deprecated: **Deprecated endpoints:** - `client.agents.search()` - use `client.agents.list()` with filters - `client.messages.search()` - use `client.agents.messages.list()` with filters - `client.runs.list_active()` - use `client.runs.list(active=True)` - `client.jobs.list_active()` - use `client.jobs.list(active=True)` - `client.folders.get_by_name()` - use `client.folders.list(name="...")` - **MCP routes under `/tools/mcp/servers`** - replaced with new `/mcp-servers` endpoints - All old MCP methods moved from `client.tools.mcp.servers` to `client.mcp_servers` - Now use server IDs and tool IDs instead of names - Sources-related routes - replaced with folders - Passages routes - replaced with archives - Legacy agent architecture routes - All `/count` endpoints **Deprecated fields:** - `agent.memory` - use `agent.blocks` - `step.messages` - use `client.steps.messages.list(step_id)` - `agent.identity_ids` - replaced with `agent.identities` (full objects) - `agent.multi_agent_group` - renamed to `agent.managed_group` - `use_assistant_message` parameter - no longer needed - `tool_exec_environment_variables` - renamed to `secrets` **Deprecated on agent/block objects:** - Template-related fields: `is_template`, `base_template_id`, `deployment_id` - `entity_id`, `preserve_on_migration`, `hidden` - `name` on blocks (use `label`) ### 4. Property Names (camelCase → snake_case) All API properties now use `snake_case`: ```typescript TypeScript // Agent properties - agent.llmConfig + agent.llm_config - agent.contextWindowLimit + agent.context_window_limit - agent.blockIds + agent.block_ids - agent.includeBaseTools + agent.include_base_tools - agent.includeBaseToolRules + agent.include_base_tool_rules - agent.initialMessageSequence + agent.initial_message_sequence // Message properties - message.messageType + message.message_type - message.toolCallId + message.tool_call_id - message.toolReturn + message.tool_return - message.toolCall + message.tool_calls // Also changed to array! // API parameters - streamTokens: true + stream_tokens: true - approvalRequestId: id + approval_request_id: id ``` ```python Python # Agent properties - agent.llm_config # Already snake_case + agent.llm_config # No change needed - agent.context_window_limit + agent.context_window_limit # No change needed # Python SDK was already using snake_case # Most changes affect TypeScript/JavaScript only ``` ### 2. Agent Type Specification ```typescript TypeScript // Old - agentType: Letta.AgentType.LettaV1Agent // New + agent_type: "letta_v1_agent" as AgentType ``` ```python Python # Old - agent_type=AgentType.LETTA_V1_AGENT # New + agent_type="letta_v1_agent" ``` ### 3. Method Renames ```typescript TypeScript // Agent updates - await client.agents.modify(agentId, { model, llmConfig }) + await client.agents.update(agentId, { model, llm_config }) // Message streaming - client.agents.messages.createStream(agentId, { messages, streamTokens }) + client.agents.messages.stream(agentId, { messages, stream_tokens }) ``` ```python Python # Agent updates - client.agents.modify(agent_id, model=model, llm_config=config) + client.agents.update(agent_id, model=model, llm_config=config) # Message streaming - client.agents.messages.create_stream(agent_id, messages=messages) + client.agents.messages.stream(agent_id, messages=messages) ``` ### 4. Message Roles and Stop Reasons Enums replaced with string literals: ```typescript TypeScript // Message roles - role: Letta.MessageCreateRole.User + role: "user" // Stop reasons - if (stopReason === Letta.StopReasonType.EndTurn) + if (stopReason === "end_turn") - if (stopReason === Letta.StopReasonType.RequiresApproval) + if (stopReason === "requires_approval") ``` ```python Python # Message roles - role=MessageRole.USER + role="user" # Stop reasons - if stop_reason == StopReasonType.END_TURN: + if stop_reason == "end_turn": - if stop_reason == StopReasonType.REQUIRES_APPROVAL: + if stop_reason == "requires_approval": ``` ### 5. Tool Calls Structure Tool calls changed from single object to array: ```typescript TypeScript // Old - single tool_call - if (message.messageType === "approval_request_message") { - const toolCall = message.toolCall; - const id = toolCall.toolCallId; - const name = toolCall.name; - } // New - tool_calls array + if (message.message_type === "approval_request_message") { + const toolCalls = message.tool_calls || []; + if (toolCalls.length > 0) { + const toolCall = toolCalls[0]; + const id = toolCall.tool_call_id; + const name = toolCall.name; + } + } ``` ```python Python # Old - single tool_call - if message.message_type == "approval_request_message": - tool_call = message.tool_call - id = tool_call.tool_call_id - name = tool_call.name # New - tool_calls array + if message.message_type == "approval_request_message": + tool_calls = message.tool_calls or [] + if len(tool_calls) > 0: + tool_call = tool_calls[0] + id = tool_call.tool_call_id + name = tool_call.name ``` ### 6. Pagination List methods now return page objects: ```typescript TypeScript // Old - const messages = await client.agents.messages.list(agentId); // New + const messagesPage = await client.agents.messages.list(agentId); + const messages = messagesPage.items; ``` ```python Python # Old - messages = client.agents.messages.list(agent_id=agent_id) # New + messages_page = client.agents.messages.list(agent_id=agent_id) + messages = messages_page.items ``` ### 7. Date Handling ```typescript TypeScript // Old - date: new Date() // New + date: new Date().toISOString() ``` ```python Python # Python handles this automatically from datetime import datetime date = datetime.now() # Works in both versions ``` ### 8. Archive Management (New APIs) New endpoints for managing archival memory: ```typescript TypeScript // Create archive const archive = await client.archives.create({ name: "my-archive", description: "Project knowledge base" }); // List archives const archives = await client.archives.list(); // Get archive by ID const archive = await client.archives.retrieve(archiveId); // Update archive await client.archives.update(archiveId, { name: "updated-name" }); // Delete archive await client.archives.delete(archiveId); // Attach archive to agent await client.agents.archives.attach(agentId, archiveId); // Detach archive from agent await client.agents.archives.detach(agentId, archiveId); // List agents using an archive const agents = await client.archives.agents.list(archiveId); // Manage memories in archive await client.archives.memories.create(archiveId, { text: "Important fact" }); await client.archives.memories.update(archiveId, memoryId, { text: "Updated fact" }); await client.archives.memories.delete(archiveId, memoryId); ``` ```python Python # Create archive archive = client.archives.create( name="my-archive", description="Project knowledge base" ) # Attach/detach client.agents.archives.attach(agent_id, archive_id) client.agents.archives.detach(agent_id, archive_id) # Manage memories client.archives.memories.create(archive_id, text="Important fact") ``` ### 9. Identity and Block Management New attach/detach patterns for identities and blocks: ```typescript TypeScript // Attach identity to agent await client.agents.identities.attach(agentId, identityId); // Detach identity from agent await client.agents.identities.detach(agentId, identityId); // Attach identity to block await client.blocks.identities.attach(blockId, identityId); // Detach identity from block await client.blocks.identities.detach(blockId, identityId); // Agent now returns full identity objects const agent = await client.agents.retrieve(agentId); // Old: agent.identity_ids = ["id1", "id2"] // New: agent.identities = [{ id: "id1", name: "Alice", ... }, ...] ``` ```python Python # Attach/detach identities client.agents.identities.attach(agent_id, identity_id) client.agents.identities.detach(agent_id, identity_id) # Full identity objects agent = client.agents.retrieve(agent_id) for identity in agent.identities: print(identity.name) ``` ### 10. Agent Configuration Updates New parameters available for agent creation and updates: ```typescript TypeScript // Temperature, top_p, reasoning_effort now available at top level const agent = await client.agents.create({ model: "openai/gpt-4", temperature: 0.7, top_p: 0.9, reasoning_effort: "medium", max_tokens: 4096, context_window_limit: 128000 }); // Update agent configuration await client.agents.update(agentId, { temperature: 0.5, context_window_limit: 64000 }); ``` ```python Python # Create with configuration agent = client.agents.create( model="openai/gpt-4", temperature=0.7, top_p=0.9, reasoning_effort="medium", max_tokens=4096, context_window_limit=128000 ) # Update configuration client.agents.update( agent_id, temperature=0.5 ) ``` ### 11. Message Input Shorthand Simplified syntax for sending simple user messages: ```typescript TypeScript // Old - verbose const response = await client.agents.messages.create(agentId, { messages: [{ role: "user", content: "Hello!" }] }); // New - shorthand available const response = await client.agents.messages.create(agentId, { input: "Hello!" // Automatically creates user message }); // Both forms still supported ``` ```python Python # Old response = client.agents.messages.create( agent_id, messages=[{"role": "user", "content": "Hello!"}] ) # New shorthand response = client.agents.messages.create( agent_id, input="Hello!" ) ``` ### 12. Attach/Detach Return Values All attach/detach endpoints now return `None` instead of agent/object state: ```typescript TypeScript // Old - returned updated agent const updatedAgent = await client.agents.tools.attach(agentId, toolId); // New - returns void/None await client.agents.tools.attach(agentId, toolId); // Fetch agent separately if needed const agent = await client.agents.retrieve(agentId); ``` ```python Python # Old updated_agent = client.agents.tools.attach(agent_id, tool_id) # New client.agents.tools.attach(agent_id, tool_id) agent = client.agents.retrieve(agent_id) ``` **Affected methods:** - `agents.tools.attach/detach` - `agents.blocks.attach/detach` - `agents.folders.attach/detach` - `agents.archives.attach/detach` - `agents.identities.attach/detach` - `blocks.identities.attach/detach` ### 13. Agent Import/Export Changes Import endpoint now supports name overriding: ```typescript TypeScript // Old - append_copy_suffix parameter const agent = await client.agents.import(file, { append_copy_suffix: true // Deprecated }); // New - override_name parameter const agent = await client.agents.importFile(file, { override_name: "my-imported-agent" // Optional, exact name to use }); ``` ```python Python # Old agent = client.agents.import_agent( file, append_copy_suffix=True ) # New agent = client.agents.import_file( file, override_name="my-imported-agent" ) ``` ### 14. Query Parameter to Request Body Changes Several endpoints moved from query parameters to request body: ```typescript TypeScript // Tool approval settings (was query params, now request body) await client.agents.tools.update_approval(agentId, toolName, { require_approval: true }); // Reset messages (was query param, now request body) await client.agents.messages.reset(agentId, { add_default_initial_messages: false }); // Steps feedback (was query params, now request body) await client.steps.feedback.create(stepId, { rating: "positive", tags: ["helpful", "accurate"] }); ``` ```python Python # Tool approval client.agents.tools.update_approval( agent_id, tool_name, require_approval=True ) # Reset messages client.agents.messages.reset( agent_id, add_default_initial_messages=False ) ``` ### 15. Tags Endpoint Tags list endpoint now uses `name` parameter instead of `query_text`: ```typescript TypeScript // Old const tags = await client.tags.list({ query_text: "important" }); // New const tags = await client.tags.list({ name: "important" }); ``` ```python Python # Old tags = client.tags.list(query_text="important") # New tags = client.tags.list(name="important") ``` ### 16. Project ID Handling Project ID is now passed in the client constructor or headers: ```typescript TypeScript // Pass in constructor const client = new Letta({ apiKey: process.env.LETTA_API_KEY, projectId: "proj_123" }); // No longer in URL paths - await client.templates.agents.create("proj_123", templateVersion, data) + await client.templates.agents.create(templateVersion, data) ``` ```python Python # Pass in constructor client = Letta( api_key=os.environ["LETTA_API_KEY"], project_id="proj_123" ) ``` ### 17. MCP (Model Context Protocol) Server Management MCP routes have been completely restructured with new endpoints under `/mcp-servers`: ```typescript TypeScript // OLD ROUTES (under /tools/mcp/servers - DEPRECATED) // Using server names and tool names // List MCP servers - const servers = await client.tools.mcp.servers.list(); // Add MCP server - await client.tools.mcp.servers.create(serverConfig); // Update MCP server by name - await client.tools.mcp.servers.update(serverName, updateConfig); // Delete MCP server by name - await client.tools.mcp.servers.delete(serverName); // List tools from a server by name - const tools = await client.tools.mcp.servers.tools.list(serverName); // Add individual tool by name - await client.tools.mcp.servers.tools.add(serverName, toolName); // Resync tools - await client.tools.mcp.servers.resync(serverName); // Execute tool by names - await client.tools.mcp.servers.tools.execute(serverName, toolName, { args }); // Connect to server (for OAuth) - await client.tools.mcp.servers.connect(serverConfig); // NEW ROUTES (under /mcp-servers) // Using server IDs and tool IDs // List MCP servers (returns array of server objects with IDs) + const servers = await client.mcp_servers.list(); // Create MCP server (automatically syncs tools) + const server = await client.mcp_servers.create(serverConfig); + // Returns: { id: "mcp_server_123", name: "...", ... } // Get MCP server by ID + const server = await client.mcp_servers.retrieve(serverId); // Update MCP server by ID + await client.mcp_servers.update(serverId, updateConfig); // Delete MCP server by ID + await client.mcp_servers.delete(serverId); // List tools from a server by ID + const tools = await client.mcp_servers.tools.list(serverId); // Get specific tool by ID + const tool = await client.mcp_servers.tools.retrieve(serverId, toolId); // Run/execute tool by ID + const result = await client.mcp_servers.tools.run(serverId, toolId, { + args: { key: "value" } + }); // Refresh tools (replaces resync) + await client.mcp_servers.refresh(serverId); // Connect to server (for OAuth) - now uses server ID + await client.mcp_servers.connect(serverId); ``` ```python Python # OLD ROUTES (DEPRECATED) - servers = client.tools.mcp.servers.list() - client.tools.mcp.servers.create(server_config) - client.tools.mcp.servers.update(server_name, update_config) - client.tools.mcp.servers.delete(server_name) - tools = client.tools.mcp.servers.tools.list(server_name) - client.tools.mcp.servers.tools.add(server_name, tool_name) - client.tools.mcp.servers.resync(server_name) - client.tools.mcp.servers.tools.execute(server_name, tool_name, args=args) # NEW ROUTES + servers = client.mcp_servers.list() + server = client.mcp_servers.create(server_config) + server = client.mcp_servers.retrieve(server_id) + client.mcp_servers.update(server_id, update_config) + client.mcp_servers.delete(server_id) + tools = client.mcp_servers.tools.list(server_id) + tool = client.mcp_servers.tools.retrieve(server_id, tool_id) + result = client.mcp_servers.tools.run(server_id, tool_id, args={"key": "value"}) + client.mcp_servers.refresh(server_id) + client.mcp_servers.connect(server_id) ``` **Key Changes:** - **Namespace**: Moved from `client.tools.mcp.servers` to `client.mcp_servers` - **Identification**: Use server IDs and tool IDs instead of names - Old: `serverName` (string) → New: `serverId` (ID string like `"mcp_server_123"`) - Old: `toolName` (string) → New: `toolId` (ID string like `"tool_456"`) - **Tool Management**: Tools are now automatically synced when creating a server - No longer need to manually "add" individual tools - Use `refresh()` to resync tools (replaces `resync()`) - **Tool Execution**: Method renamed from `execute()` to `run()` - **Server Retrieval**: New `retrieve()` method to get individual server by ID - **Tool Retrieval**: New `retrieve()` method to get individual tool by ID **Migration Example:** ```typescript TypeScript // Before: Using names const servers = await client.tools.mcp.servers.list(); const myServer = servers.find(s => s.name === "my-server"); const tools = await client.tools.mcp.servers.tools.list("my-server"); const myTool = tools.find(t => t.name === "my-tool"); await client.tools.mcp.servers.tools.execute("my-server", "my-tool", { args: { query: "hello" } }); // After: Using IDs const servers = await client.mcp_servers.list(); const myServer = servers.find(s => s.name === "my-server"); const serverId = myServer.id; // Get ID from server object const tools = await client.mcp_servers.tools.list(serverId); const myTool = tools.find(t => t.name === "my-tool"); const toolId = myTool.id; // Get ID from tool object await client.mcp_servers.tools.run(serverId, toolId, { args: { query: "hello" } }); ``` ```python Python # Before servers = client.tools.mcp.servers.list() my_server = next(s for s in servers if s.name == "my-server") tools = client.tools.mcp.servers.tools.list("my-server") my_tool = next(t for t in tools if t.name == "my-tool") client.tools.mcp.servers.tools.execute( "my-server", "my-tool", args={"query": "hello"} ) # After servers = client.mcp_servers.list() my_server = next(s for s in servers if s.name == "my-server") server_id = my_server.id tools = client.mcp_servers.tools.list(server_id) my_tool = next(t for t in tools if t.name == "my-tool") tool_id = my_tool.id client.mcp_servers.tools.run( server_id, tool_id, args={"query": "hello"} ) ``` **Notes:** - MCP servers and tools now have persistent IDs in the database - Server names are no longer unique identifiers - use IDs instead - Tool schemas are automatically kept in sync via the `refresh()` endpoint - The old routes under `/tools/mcp/servers` are deprecated and will be removed ## Migration Examples ### Complete Agent Creation ```typescript TypeScript // Before const agent = await client.agents.create({ agentType: Letta.AgentType.LettaV1Agent, model: "openai/gpt-4", contextWindowLimit: 200_000, blockIds: ["block-1", "block-2"], includeBaseTools: false, includeBaseToolRules: false, initialMessageSequence: [], }); // After const agent = await client.agents.create({ agent_type: "letta_v1_agent" as AgentType, model: "openai/gpt-4", context_window_limit: 200_000, block_ids: ["block-1", "block-2"], include_base_tools: false, include_base_tool_rules: false, initial_message_sequence: [], }); ``` ```python Python # Before agent = client.agents.create( agent_type=AgentType.LETTA_V1_AGENT, model="openai/gpt-4", context_window_limit=200_000, block_ids=["block-1", "block-2"], include_base_tools=False, include_base_tool_rules=False, initial_message_sequence=[], ) # After agent = client.agents.create( agent_type="letta_v1_agent", model="openai/gpt-4", context_window_limit=200_000, block_ids=["block-1", "block-2"], include_base_tools=False, include_base_tool_rules=False, initial_message_sequence=[], ) ``` ### Streaming Messages ```typescript TypeScript // Before const stream = await client.agents.messages.createStream(agentId, { messages: [{ role: Letta.MessageCreateRole.User, content: "Hello" }], streamTokens: true, }); // After const stream = await client.agents.messages.stream(agentId, { messages: [{ role: "user", content: "Hello" }], stream_tokens: true, }); ``` ```python Python # Before stream = client.agents.messages.create_stream( agent_id=agent_id, messages=[{"role": "user", "content": "Hello"}], stream_tokens=True, ) # After stream = client.agents.messages.stream( agent_id=agent_id, messages=[{"role": "user", "content": "Hello"}], stream_tokens=True, ) ``` ### Handling Approvals ```typescript TypeScript // Before if (message.messageType === "approval_request_message") { const toolCall = message.toolCall; await client.agents.messages.create(agentId, { messages: [{ type: "approval", approvalRequestId: toolCall.toolCallId, approve: true, }], }); } // After if (message.message_type === "approval_request_message") { const toolCalls = message.tool_calls || []; if (toolCalls.length > 0) { const toolCall = toolCalls[0]; await client.agents.messages.create(agentId, { messages: [{ type: "approval", approval_request_id: toolCall.tool_call_id, approve: true, }], }); } } ``` ```python Python # Before if message.message_type == "approval_request_message": tool_call = message.tool_call client.agents.messages.create( agent_id=agent_id, messages=[{ "type": "approval", "approval_request_id": tool_call.tool_call_id, "approve": True, }], ) # After if message.message_type == "approval_request_message": tool_calls = message.tool_calls or [] if len(tool_calls) > 0: tool_call = tool_calls[0] client.agents.messages.create( agent_id=agent_id, messages=[{ "type": "approval", "approval_request_id": tool_call.tool_call_id, "approve": True, }], ) ``` ### Updating Agent Configuration ```typescript TypeScript // Before await client.agents.modify(agentId, { model: "openai/gpt-4", llmConfig: { temperature: 0.7 } }); const agent = await client.agents.retrieve(agentId); const config = agent.llmConfig; // After await client.agents.update(agentId, { model: "openai/gpt-4", llm_config: { temperature: 0.7 } }); const agent = await client.agents.retrieve(agentId); const config = agent.llm_config; ``` ```python Python # Before client.agents.modify( agent_id=agent_id, model="openai/gpt-4", llm_config={"temperature": 0.7} ) agent = client.agents.retrieve(agent_id=agent_id) config = agent.llm_config # After client.agents.update( agent_id=agent_id, model="openai/gpt-4", llm_config={"temperature": 0.7} ) agent = client.agents.retrieve(agent_id=agent_id) config = agent.llm_config ``` ## Migration Checklist Use this checklist to ensure a complete migration: **Core SDK Changes:** - [ ] Update package version to `1.0.0-alpha.10` or later - [ ] Update all imports (client and types) - [ ] Replace `LettaClient` with `Letta` - [ ] Update client constructor params: `token` → `apiKey`, `baseUrl` → `baseURL` - [ ] Add `projectId` to client constructor if using multi-project setup - [ ] Convert all property names from `camelCase` to `snake_case` - [ ] Replace enum references with string literals - [ ] Convert `Date` objects to ISO strings where required - [ ] Update type annotations to use new import paths **Method Renames:** - [ ] Update `modify()` calls to `update()` - [ ] Update `createStream()` calls to `stream()` - [ ] Rename `summarize_agent_conversation()` → `messages.compact()` - [ ] Rename `cancel_agent_run()` → `messages.cancel()` - [ ] Rename `preview_raw_payload()` → `messages.preview()` - [ ] Rename `list_agent_files()` → `files.list()` - [ ] Rename `export_agent_serialized()` → `export_file()` - [ ] Rename `import_agent_serialized()` → `import_file()` - [ ] Rename folder/provider method names (see section 2) - [ ] Update telemetry routes to use `steps.trace()` **Pagination:** - [ ] Update all list methods to access `.items` property - [ ] Replace `sort_by` with `order_by` in `agents.list()` - [ ] Replace `ascending` with `order` parameter - [ ] Update pagination parameters: `before`, `after`, `limit`, `order` - [ ] Handle cursor-based pagination for all list endpoints **Message Handling:** - [ ] Handle `tool_calls` as an array instead of single object - [ ] Update `identity_ids` references to use `identities` (full objects) - [ ] Replace `agent.memory` with `agent.blocks` - [ ] Update `step.messages` to use `steps.messages.list()` - [ ] Consider using new `input` shorthand for simple messages **Deprecations:** - [ ] Remove usage of deprecated search endpoints - [ ] Replace `list_active()` with `list(active=True)` - [ ] Remove `use_assistant_message` parameter - [ ] Replace `tool_exec_environment_variables` with `secrets` - [ ] Remove template-related fields from agent/block objects - [ ] Replace sources endpoints with folders - [ ] Replace passages endpoints with archives **New Features:** - [ ] Update attach/detach methods (now return `None`) - [ ] Use new archive management APIs if needed - [ ] Update agent import to use `override_name` instead of `append_copy_suffix` - [ ] Move query parameters to request body for affected endpoints - [ ] Use new agent configuration parameters (`temperature`, `top_p`, etc.) **MCP (Model Context Protocol) Changes:** - [ ] Migrate from `client.tools.mcp.servers` to `client.mcp_servers` - [ ] Update MCP server references to use IDs instead of names - [ ] Update MCP tool references to use IDs instead of names - [ ] Remove manual tool "add" operations (tools auto-sync on server create) - [ ] Replace `resync()` calls with `refresh()` - [ ] Replace `execute()` calls with `run()` - [ ] Add server/tool ID lookup logic if using names - [ ] Update OAuth connection flow to use server IDs **Testing:** - [ ] Test all agent operations (create, update, message) - [ ] Test streaming and approval flows - [ ] Verify memory block operations still work - [ ] Test pagination on list endpoints - [ ] Test archive management if used - [ ] Verify identity/block attach/detach operations - [ ] Test agent import/export ## Automated Migration Tools ### Find and Replace Script Use this script to help automate common replacements: ```bash Shell (TypeScript projects) # Install dependencies npm install -g jscodeshift # Run find-and-replace (adjust paths as needed) find src -name "*.ts" -o -name "*.tsx" | xargs sed -i '' \ -e 's/LettaClient/Letta/g' \ -e 's/\.modify(/.update(/g' \ -e 's/\.createStream(/.stream(/g' \ -e 's/\.messageType/.message_type/g' \ -e 's/\.toolCall/.tool_calls/g' \ -e 's/\.toolCallId/.tool_call_id/g' \ -e 's/\.toolReturn/.tool_return/g' \ -e 's/llmConfig/llm_config/g' \ -e 's/streamTokens/stream_tokens/g' \ -e 's/\.tools\.mcp\.servers/\.mcp_servers/g' \ -e 's/\.resync(/\.refresh(/g' # Note: MCP server/tool name -> ID migration requires manual intervention # as you need to fetch IDs from the API ``` ```python Python (migration helper) import re from pathlib import Path def migrate_file(filepath: Path): """Apply SDK v1.0 migration patterns to a Python file""" content = filepath.read_text() # Import updates content = re.sub( r'from letta_client import (\w+)', r'from letta import \1', content ) # Method renames content = content.replace('.modify(', '.update(') content = content.replace('.create_stream(', '.stream(') # MCP namespace changes content = content.replace('.tools.mcp.servers', '.mcp_servers') content = content.replace('.resync(', '.refresh(') # Already using snake_case in Python, but fix any camelCase content = re.sub(r'messageType', 'message_type', content) content = re.sub(r'toolCall([^_])', r'tool_calls\1', content) filepath.write_text(content) print(f"✓ Migrated {filepath}") # Usage for py_file in Path('src').rglob('*.py'): migrate_file(py_file) ``` **Always review automated changes!** These scripts help with common patterns but cannot handle all edge cases. Test thoroughly after migration. ## Troubleshooting ### "Property 'llmConfig' does not exist" (TypeScript) **Cause:** Property renamed to `llm_config` **Fix:** Update all references to use snake_case ```typescript - agent.llmConfig + agent.llm_config ``` ### "Cannot read property 'toolCallId' of undefined" **Cause:** `tool_call` changed to `tool_calls` (array) **Fix:** Access the first element of the array ```typescript - const id = message.toolCall.toolCallId; + const toolCalls = message.tool_calls || []; + const id = toolCalls[0]?.tool_call_id; ``` ### "items is not iterable" **Cause:** Trying to iterate over page object instead of items array **Fix:** Access the `.items` property first ```typescript - for (const message of messages) { + const messagesPage = await client.agents.messages.list(agentId); + for (const message of messagesPage.items) { ``` ### "Cannot find module '@letta-ai/letta-client/resources/...'" **Cause:** Types moved to subpath exports **Fix:** Update imports to use new subpaths ```typescript - import { Letta } from "@letta-ai/letta-client"; + import type { Block } from "@letta-ai/letta-client/resources/agents/agents"; ``` ### "Method 'modify' does not exist" **Cause:** Method renamed to `update` **Fix:** Update all modify calls ```typescript - await client.agents.modify(agentId, updates) + await client.agents.update(agentId, updates) ``` ### "Cannot access property 'identity_ids'" **Cause:** Field renamed to `identities` and now returns full objects **Fix:** Access the `identities` array and extract IDs if needed ```typescript - const ids = agent.identity_ids; + const identities = agent.identities; + const ids = identities.map(i => i.id); ``` ### "Pagination parameters 'sort_by' or 'ascending' not recognized" **Cause:** Pagination parameters standardized to `order_by` and `order` **Fix:** Update parameter names ```typescript - await client.agents.list({ sort_by: "created_at", ascending: true }) + await client.agents.list({ order_by: "created_at", order: "asc" }) ``` ### "Attach/detach methods return undefined" **Cause:** These methods now return `None`/`void` instead of updated state **Fix:** Fetch the object separately if you need the updated state ```typescript await client.agents.tools.attach(agentId, toolId); const agent = await client.agents.retrieve(agentId); // Get updated state ``` ### "Cannot find method 'summarize_agent_conversation'" **Cause:** Method moved to messages subresource **Fix:** Use the new path ```typescript - await client.agents.summarize_agent_conversation(agentId) + await client.agents.messages.compact(agentId) ``` ### "Query parameter 'add_default_initial_messages' not working" **Cause:** Parameter moved from query to request body **Fix:** Pass as request body parameter ```typescript - await client.agents.messages.reset(agentId, { params: { add_default_initial_messages: false } }) + await client.agents.messages.reset(agentId, { add_default_initial_messages: false }) ``` ### "Cannot find 'client.tools.mcp.servers'" **Cause:** MCP routes moved to new namespace **Fix:** Use new MCP server methods ```typescript - await client.tools.mcp.servers.list() + await client.mcp_servers.list() ``` ### "MCP server not found by name" **Cause:** MCP methods now use server IDs instead of names **Fix:** Lookup server ID from name first ```typescript // Get server ID from name const servers = await client.mcp_servers.list(); const myServer = servers.find(s => s.name === "my-server"); const serverId = myServer.id; // Use ID for subsequent operations await client.mcp_servers.tools.list(serverId); ``` ### "MCP tool 'toolName' not found" **Cause:** MCP tool execution now uses tool IDs instead of names **Fix:** Lookup tool ID from name first ```typescript const tools = await client.mcp_servers.tools.list(serverId); const myTool = tools.find(t => t.name === "my-tool"); const toolId = myTool.id; await client.mcp_servers.tools.run(serverId, toolId, { args }); ``` ### "Method 'execute' not found on mcp_servers.tools" **Cause:** Method renamed from `execute()` to `run()` **Fix:** Use the new method name ```typescript - await client.mcp_servers.tools.execute(serverId, toolId, { args }) + await client.mcp_servers.tools.run(serverId, toolId, { args }) ``` ## Additional Resources - [Architecture Migration Guide](/guides/legacy/migration_guide) - For migrating agent architectures - [API Reference](/api-reference) - Complete SDK documentation - [Changelog](/api-reference/changelog) - All SDK changes - [GitHub](https://github.com/letta-ai/letta) - Source code and issues - [Discord](https://discord.gg/letta) - Get help from the community ## Getting Help If you encounter issues during migration: 1. **Check the [Changelog](/api-reference/changelog)** for detailed release notes 2. **Search [GitHub Issues](https://github.com/letta-ai/letta/issues)** for known problems 3. **Ask in [Discord #dev-help](https://discord.gg/letta)** for community support 4. **Contact support@letta.com** for enterprise support