---
title: Conversations (threads) | Letta Docs
description: Use conversations to manage parallel conversation threads with a single agent in the Letta API
---

Conversations are built into the [Letta Code](/letta-code/index.md) and [Letta Agent SDK](/letta-agent-sdk/quickstart/index.md). In Letta Code, launch with `letta --new` to start a new parallel conversation.

A conversation is a message thread within an agent. A single agent can have multiple conversations running in parallel, each with its own context window, but all sharing the same memory blocks and searchable message history.

This is useful when you want to run several sessions with the same agent simultaneously without them interfering with each other. For example, you might have one conversation where you’re refactoring an API while another is writing tests—both sessions share the agent’s learned context about your codebase.

## Creating a conversation

Create a conversation by specifying the agent ID:

- [TypeScript](#tab-panel-68)
- [Python](#tab-panel-69)

```
import Letta from "@letta-ai/letta-client";


const client = new Letta({ apiKey: process.env.LETTA_API_KEY });


const conversation = await client.conversations.create({
  agent_id: "agent-xxx",
});


console.log(`Created conversation: ${conversation.id}`);
```

```
from letta_client import Letta
import os


client = Letta(api_key=os.getenv("LETTA_API_KEY"))


conversation = client.conversations.create(agent_id="agent-xxx")


print(f"Created conversation: {conversation.id}")
```

## Sending messages

Send messages to a conversation. The response is always a stream:

- [TypeScript](#tab-panel-70)
- [Python](#tab-panel-71)

```
const stream = await client.conversations.messages.create(conversation.id, {
  messages: [{ role: "user", content: "Explain this codebase" }],
  stream_tokens: true,
});


for await (const chunk of stream) {
  if (chunk.message_type === "assistant_message") {
    process.stdout.write(chunk.content);
  }
}
```

```
stream = client.conversations.messages.create(
    conversation.id,
    messages=[{"role": "user", "content": "Explain this codebase"}],
    stream_tokens=True,
)


for chunk in stream:
    if chunk.message_type == "assistant_message":
        print(chunk.content, end="")
```

## Model overrides

You can set a different model for a conversation, or override the model on a single request. This is useful for routing cheaper conversations to a smaller model without creating a separate agent.

Model selection priority:

1. Per-request `override_model` parameter (highest)
2. Conversation-level `model` setting
3. Agent’s default model

- [TypeScript](#tab-panel-72)
- [Python](#tab-panel-73)

```
// Create a conversation with a specific model
const conversation = await client.conversations.create({
  agent_id: "agent-xxx",
  model: "openai/gpt-5-mini",
});


// Or override the model for a single request
const stream = await client.conversations.messages.create(conversation.id, {
  messages: [{ role: "user", content: "Hello" }],
  override_model: "anthropic/claude-haiku-4-5",
});
```

```
# Create a conversation with a specific model
conversation = client.conversations.create(
    agent_id="agent-xxx",
    model="openai/gpt-5-mini",
)


# Or override the model for a single request
stream = client.conversations.messages.create(
    conversation.id,
    messages=[{"role": "user", "content": "Hello"}],
    override_model="anthropic/claude-haiku-4-5",
)
```

## Listing conversations

List all conversations for an agent. Use `order_by` and `order` to control sort order:

- [TypeScript](#tab-panel-74)
- [Python](#tab-panel-75)

```
// Most recently active conversations
const conversations = await client.conversations.list({
  agent_id: "agent-xxx",
  order_by: "last_run_completion",
  order: "desc",
});


for (const conv of conversations) {
  console.log(conv.id);
}
```

```
# Most recently active conversations
conversations = client.conversations.list(
    agent_id="agent-xxx",
    order_by="last_run_completion",
    order="desc",
)


for conv in conversations:
    print(conv.id)
```

`order_by` accepts `"created_at"` or `"last_run_completion"`. `order` accepts `"asc"` or `"desc"`.

## Listing messages in a conversation

Retrieve the message history for a specific conversation:

- [TypeScript](#tab-panel-76)
- [Python](#tab-panel-77)

```
const messages = await client.conversations.messages.list(conversation.id);


for (const msg of messages) {
  console.log(`[${msg.message_type}] ${msg.content || msg.reasoning || ""}`);
}
```

```
messages = client.conversations.messages.list(conversation.id)


for msg in messages:
    print(f"[{msg.message_type}] {msg.content or msg.reasoning or ''}")
```

For the full REST API reference including all parameters and response schemas, see the [Conversations API](/api/resources/conversations/index.md).

## Forking a conversation

Fork a conversation when you want to branch from the same in-context history without changing the original thread. The fork belongs to the same agent, shares the selected source messages, and gets a freshly compiled system message from the agent’s current memory.

By default, a fork includes the source conversation’s in-context messages. Pass `message_id` to fork only through a specific message, including that message and excluding later messages.

- [TypeScript](#tab-panel-78)
- [Python](#tab-panel-79)

```
// Fork the full in-context conversation history.
const fork = await client.conversations.fork(conversation.id);


// Fork only through a specific source message.
const messages = await client.conversations.messages.list(conversation.id);
const targetMessage = messages[messages.length - 1];


const forkThroughMessage = await client.conversations.fork(conversation.id, {
  message_id: targetMessage.id,
});
```

```
# Fork the full in-context conversation history.
fork = client.conversations.fork(conversation.id)


# Fork only through a specific source message.
messages = client.conversations.messages.list(conversation.id)
target_message = messages[-1]


fork_through_message = client.conversations.fork(
    conversation.id,
    message_id=target_message.id,
)
```

The `message_id` must identify a message that is still in the source conversation’s in-context messages. If the message is not part of that context, the API returns a validation error.

In Letta Code, the `/fork` slash command creates a fork of the current conversation from the CLI or desktop app.

## Deleting a conversation

Delete a conversation when it’s no longer needed:

- [Python](#tab-panel-80)
- [TypeScript](#tab-panel-81)

```
client.conversations.delete(conversation.id)
```

```
// Not yet available in the TypeScript SDK.
// Use the REST API directly:
await fetch(`${baseUrl}/v1/conversations/${conversation.id}`, {
  method: "DELETE",
  headers: { Authorization: `Bearer ${apiKey}` },
});
```

Deleted conversations are removed from list results and can no longer be retrieved.

## How conversations share state

All conversations within an agent share:

- **Memory blocks**: The agent’s core memory (persona, human, project blocks, etc.) is shared across all conversations. When the agent updates a memory block in one conversation, that change is visible in all other conversations.

- **Searchable message history**: Messages from all conversations are pooled together in a searchable database. The agent can use `conversation_search` to recall context from any past conversation, not just the current one.

Each conversation has its own:

- **Context window**: The active messages being processed. Long conversations get compacted independently.

- **Message history**: The sequence of messages in that specific thread.

This design lets you run parallel sessions that build on shared knowledge while keeping their immediate context separate.

## When to use conversations

**Concurrency**: The `agents.messages.create` endpoint is not thread-safe—concurrent requests to the same agent can cause race conditions. If you need to send messages to an agent from multiple threads or processes simultaneously, use separate conversations. Each conversation has its own message stream that can be written to independently.

**Separating context**: When your application has clearly distinct interaction sessions (e.g., different user sessions, different tasks), conversations let you keep their context windows separate while still sharing the agent’s learned memory. This prevents unrelated messages from one session polluting another’s context.
