---
title: SDK v1.0 Migration Guide
subtitle: Upgrading from v0.x to v1.0
slug: api-reference/sdk-migration-guide
---

<Info>
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).
</Info>

<Warning>
**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`.
</Warning>

## 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:

<CodeGroup>
```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"
```
</CodeGroup>

### Import Changes

<CodeGroup>
```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
```
</CodeGroup>

### Client Instantiation

<CodeGroup>
```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"
+ )
```
</CodeGroup>

## Breaking Changes by Category

### 1. Pagination

All list endpoints now use cursor-based pagination with consistent parameters:

<CodeGroup>
```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
```
</CodeGroup>

**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:

<CodeGroup>
```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)
```
</CodeGroup>

### 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`:

<CodeGroup>
```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
```
</CodeGroup>

### 2. Agent Type Specification

<CodeGroup>
```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"
```
</CodeGroup>

### 3. Method Renames

<CodeGroup>
```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)
```
</CodeGroup>

### 4. Message Roles and Stop Reasons

Enums replaced with string literals:

<CodeGroup>
```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":
```
</CodeGroup>

### 5. Tool Calls Structure

Tool calls changed from single object to array:

<CodeGroup>
```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
```
</CodeGroup>

### 6. Pagination

List methods now return page objects:

<CodeGroup>
```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
```
</CodeGroup>

### 7. Date Handling

<CodeGroup>
```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
```
</CodeGroup>

### 8. Archive Management (New APIs)

New endpoints for managing archival memory:

<CodeGroup>
```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")
```
</CodeGroup>

### 9. Identity and Block Management

New attach/detach patterns for identities and blocks:

<CodeGroup>
```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)
```
</CodeGroup>

### 10. Agent Configuration Updates

New parameters available for agent creation and updates:

<CodeGroup>
```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
)
```
</CodeGroup>

### 11. Message Input Shorthand

Simplified syntax for sending simple user messages:

<CodeGroup>
```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!"
)
```
</CodeGroup>

### 12. Attach/Detach Return Values

All attach/detach endpoints now return `None` instead of agent/object state:

<CodeGroup>
```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)
```
</CodeGroup>

**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:

<CodeGroup>
```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"
)
```
</CodeGroup>

### 14. Query Parameter to Request Body Changes

Several endpoints moved from query parameters to request body:

<CodeGroup>
```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
)
```
</CodeGroup>

### 15. Tags Endpoint

Tags list endpoint now uses `name` parameter instead of `query_text`:

<CodeGroup>
```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")
```
</CodeGroup>

### 16. Project ID Handling

Project ID is now passed in the client constructor or headers:

<CodeGroup>
```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"
)
```
</CodeGroup>

### 17. MCP (Model Context Protocol) Server Management

MCP routes have been completely restructured with new endpoints under `/mcp-servers`:

<CodeGroup>
```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)
```
</CodeGroup>

**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:**

<CodeGroup>
```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"}
)
```
</CodeGroup>

**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

<CodeGroup>
```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=[],
)
```
</CodeGroup>

### Streaming Messages

<CodeGroup>
```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,
)
```
</CodeGroup>

### Handling Approvals

<CodeGroup>
```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,
            }],
        )
```
</CodeGroup>

### Updating Agent Configuration

<CodeGroup>
```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
```
</CodeGroup>

## 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:

<CodeGroup>
```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)
```
</CodeGroup>

<Warning>
**Always review automated changes!** These scripts help with common patterns but cannot handle all edge cases. Test thoroughly after migration.
</Warning>

## 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
