Announcement: Letta v1 SDK

Announcing the Letta 1.0 SDK

We’ve made significant revisions to the Letta Agents SDK for a 1.0 stable release. To try to the 1.0 pre-release you can install:

Python: pip install letta-client --pre
TS: npm i @letta-ai/letta-client@alpha

You can also see the documentation for the 1.0 SDK here (in alpha).

If you are just starting with Letta, we recommend starting with the 1.0 SDK. If you are already using the existing SDK, you can see the migration guide for instructions on migrating.

In addition to unifying and cleaning up SDK patterns, the 1.0 SDK also has improved support for:

  • Provider-specific model configuration
  • Parallel tool calling
  • HITL & Approvals
  • MCP configuration

We are continuing to support deprecated routes and parameters to avoid breaking SDK releases before 1.0 — however we will likely sunset deprecated routes by the end of the 2025.

Please let us know if you have any feedback! We appreciate our community’s feedback so far on helping us design a new SDK experience :heart:

2 Likes

Great to see the 1.0 SDK release! This addresses several pain points I’ve been seeing in the community.

Key Improvements I’m Excited About

Parallel tool calling - This has been a common request, especially for agents that need to query multiple data sources simultaneously.

HITL & Approvals - The improved support here is huge. Many users are building customer-facing agents where message approval workflows are critical.

Provider-specific model configuration - This should help with the confusion around provider-specific parameters and make it easier to use advanced features like reasoning tokens or streaming configurations.

MCP configuration - With MCP adoption growing, better SDK support will make integrations much smoother.

For Users Migrating

A few things to note based on Discord conversations:

  1. New users: Start with 1.0 (pip install letta-client --pre). No need to learn deprecated patterns.

  2. Existing users: Current SDK continues to work until end of 2025. You have time to migrate gradually.

  3. Migration guide: The post mentions a migration guide - is this available at docs-v1.letta.com or will it be published separately?

Questions for Clarity

  • Are the deprecated routes clearly marked in the v1 docs?
  • Will there be a compatibility layer to help with the transition, or is this a hard migration?
  • Does the 1.0 SDK work with both current OSS (v0.5.2) and Letta Cloud, or only Cloud?

Thanks for the continued improvements to the developer experience!

sounds great! where can I find docs on migration: I can see straight off that MessageCreate has been removed.

The migration guide is here: SDK v1.0 Migration Guide | Letta

This covers all the breaking changes between SDK v0.x and v1.0, including method renames, property changes (camelCase → snake_case), pagination updates, and deprecated endpoints.

About MessageCreate:

I don’t see MessageCreate specifically mentioned in the migration guide. Can you share more context about how you were using it? For example:

  • Was it a type/interface for creating messages?
  • Was it a method for sending messages to agents?
  • What SDK are you using (Python or TypeScript)?

The main message-related changes in v1.0 are:

  1. Sending messages: Use client.agents.messages.create(agent_id, ...) (or the shorthand input="text" for simple user messages)
  2. Streaming messages: Method renamed from createStream() to stream()
  3. Message structure: Tool calls changed from single object to array (tool_calltool_calls)

If you can provide the code snippet where you were using MessageCreate, I can help you find the equivalent in v1.0!

I had to make these changes to fix the import error

-from letta_client import Letta, MessageCreate

+from letta_client import Letta

from typing import Optional, List, Type

from pydantic import BaseModel, Field

@@ -459,7 +459,7 @@ message_text = (

)

try:

response = client.agents.messages.create(

- agent_id=agent.id, messages=[MessageCreate(role=“user”, content=message_text)]

+ agent_id=agent.id, role=“user”, input=message_text

)

import logging

Perfect! That’s exactly the right migration pattern.

What changed:

In SDK v0.x, you had to construct message objects explicitly:

messages=[MessageCreate(role="user", content=message_text)]

In SDK v1.0, there’s a simpler shorthand syntax for basic user messages:

role="user", input=message_text

This is documented in the migration guide under “Message Input Shorthand”.

If you need more control (like sending multiple messages at once, or messages with different roles), you can still use the verbose syntax:

client.agents.messages.create(
    agent_id=agent.id,
    messages=[
        {"role": "user", "content": "First message"},
        {"role": "system", "content": "System instruction"}
    ]
)

But for simple cases like yours, the shorthand role="user", input=text is the recommended approach.

Thanks for sharing the code snippet - this will help other users migrating!

Also, it looks like tool registration no longer works for self-hosted

ERROR:main:Tool registration attempt 1 failed: “Could not resolve authentication method. Expected the api_key to be set. Or for the Authorization headers to be explicitly omitted”
ERROR:main:Tool registration attempt 2 failed: “Could not resolve authentication method. Expected the api_key to be set. Or for the Authorization headers to be explicitly omitted”
ERROR:main:Tool registration attempt 3 failed: “Could not resolve authentication method. Expected the api_key to be set. Or for the Authorization headers to be explicitly omitted”
ERROR:main:Failed to register tools: “Could not resolve authentication method. Expected the api_key to be set. Or for the Authorization headers to be explicitly omitted”

here is my tool registration snippet


def register_tool(
func, args_schema: Optional\[Type\[BaseModel\]\] = None, max_retries: int = 3

):

“”"

Register a Letta tool with retry logic and optional Pydantic schema.



Args:

    func: The tool function.

    args_schema: Optional Pydantic BaseModel for args validation/schema.

    max_retries: Retry attempts on failure.



Returns:

    Registered tool object or None.

"""

logging.basicConfig(level=logging.INFO)

logger = logging.getLogger(\__name_\_)

for attempt in range(max_retries):

try:

if args_schema:

            tool_obj = client.tools.upsert_from_function(

func=func, args_schema=args_schema

            )

else:

            tool_obj = client.tools.upsert_from_function(func=func)



        logger.info(f"Registered tool: {tool_obj.name} (ID: {tool_obj.id})")

return tool_obj

except Exception as e:

        logger.error(f"Tool registration attempt {attempt + 1} failed: {str(e)}")

if attempt < max_retries - 1:

            sleep(2)

else:

raise

return None
```

This is a known issue with SDK v1.0 for self-hosted servers without authentication.

The problem: The new SDK requires an api_key parameter even when connecting to self-hosted servers that don’t have authentication enabled.

Workaround: Pass a dummy API key when initializing your client:

from letta_client import Letta

# For self-hosted without authentication
client = Letta(
    base_url="http://localhost:8283",
    api_key="dummy"  # Required even though server doesn't use it
)

Why this happens:

The v1.0 SDK has stricter authentication validation. There was a fix attempt in alpha.v19, but it actually made things worse - now you need to pass "dummy" instead of being able to pass an empty string.

If you’re using environment variables:

import os
os.environ["LETTA_API_KEY"] = "dummy"

client = Letta(base_url="http://localhost:8283")

Expected behavior: Eventually, the SDK should allow connecting to self-hosted servers without requiring any API key. The team is aware of this issue.

Does adding api_key="dummy" to your client initialization fix your tool registration issue?

that seemed to work. But now I am unable to create a message

ERROR:main:Message creation failed: ‘MessagesResource’ object has no attribute ‘create’
Traceback (most recent call last):
response = client.agents.messages.create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: ‘MessagesResource’ object has no attribute ‘create’

That’s odd - client.agents.messages.create() is definitely the correct method in SDK v1.0. This suggests a version mismatch.

Can you verify your SDK version?

pip show letta-client

You should see something like Version: 1.0.0.alpha.19 (or higher).

If you’re not on the latest alpha:

pip install letta-client --pre --upgrade

Possible causes:

  1. Old cached imports - If you upgraded but Python is still loading the old version:

    # Clear Python cache and reinstall
    pip uninstall letta-client
    pip cache purge
    pip install letta-client --pre
    
  2. Multiple installations - Check if you have both old and new SDKs:

    pip list | grep letta
    

    You should only see letta-client, not letta or other variants.

  3. Virtual environment - Make sure you’re in the correct venv where you installed the new SDK.

After upgrading, restart your Python process/notebook to ensure the new version is loaded.

Can you share the output of pip show letta-client? That will help confirm what’s happening.

I am definitely using 1.0

pip show letta-client
Name: letta-client
Version: 1.0.0a19
Summary: The official Python library for the letta API
Home-page: GitHub - letta-ai/letta-python: A Python SDK for accessing the Letta API
Author: Letta
Author-email:
License: Apache-2.0

You’re definitely on the right version (1.0.0a19). The issue is likely cached imports from a previous version.

Try this diagnostic:

# Fresh Python session - restart your interpreter/notebook first!
from letta_client import Letta

client = Letta(base_url="http://localhost:8283", api_key="dummy")

# Check what methods are available
print(dir(client.agents.messages))

If you see 'create' in that list, the method exists but Python was loading a cached version.

To fix:

  1. Restart your Python process completely (close and reopen your script/notebook/terminal)
  2. If using Jupyter: Kernel → Restart Kernel
  3. If using a long-running Python process: stop and restart it

If that doesn’t work:

Try a clean reinstall:

pip uninstall letta-client -y
pip cache purge
pip install letta-client==1.0.0a19

Then restart Python again.

Verify after restart:

from letta_client import Letta
client = Letta(base_url="http://localhost:8283", api_key="dummy")

# This should work now
response = client.agents.messages.create(
    agent_id="your-agent-id",
    role="user", 
    input="test message"
)

Let me know if restarting your Python process fixes it!

indeed, there is no create method

[‘annotations’, ‘class’, ‘delattr’, ‘dict’, ‘dir’, ‘doc’, ‘eq’, ‘firstlineno’, ‘format’, ‘ge’, ‘getattribute’, ‘getstate’, ‘gt’, ‘hash’, ‘init’, ‘init_subclass’, ‘le’, ‘lt’, ‘module’, ‘ne’, ‘new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘setattr’, ‘sizeof’, ‘static_attributes’, ‘str’, ‘subclasshook’, ‘weakref’, ‘_client’, ‘_delete’, ‘_get’, ‘_get_api_list’, ‘_patch’, ‘_post’, ‘_put’, ‘_sleep’, ‘cancel’, ‘list’, ‘modify’, ‘reset’, ‘send’, ‘send_async’, ‘stream’, ‘summarize’, ‘with_raw_response’, ‘with_streaming_response’]

Ah! I see the issue now. In your version (1.0.0a19), the method is called send(), not create().

The available message methods are:

  • send - Send a message (synchronous)
  • send_async - Send a message (asynchronous)
  • stream - Stream a message response
  • list - List messages
  • cancel - Cancel a running message
  • summarize - Summarize conversation history
  • reset - Reset message history

Your working code should be:

response = client.agents.messages.send(
    agent_id=agent.id,
    role="user", 
    input=message_text
)

Or use the shorthand:

response = client.agents.messages.send(
    agent_id=agent.id,
    input=message_text  # role="user" is default
)

For streaming:

for chunk in client.agents.messages.stream(
    agent_id=agent.id,
    input=message_text
):
    print(chunk)

Sorry for the confusion - it looks like the method naming changed between alpha versions. The migration guide I referenced may be for a newer alpha than what you have installed.

This hole keeps getting bigger

ERROR:main:Message creation failed: Error code: 422 - {‘trace_id’: ‘’, ‘detail’: ‘[{‘type’: ‘missing’, ‘loc’: (‘body’, ‘messages’), ‘msg’: ‘Field required’, ‘input’: {‘input’: “Analyze this point’s coordinates: [-122.4194, 37.7749] (EPSG:4326). Is it in a known city? First, call download_data to fetch the dataset from https://naturalearth.s3.amazonaws.com/110m_cultural/ne_110m_populated_places.zip to natural_earth. Then, call geopandas_api with function_name=‘proximity_analysis’, point_coords=[-122.4194, 37.7749], distance_m=5000, dataset_path=‘natural_earth/ne_110m_populated_places.shp’.”}}]’}
Traceback (most recent call last):
File “gis-agent.py”, line 464, in
response = client.agents.messages.send(
agent_id=agent.id, input=message_text
)
File “/lib/python3.13/site-packages/letta_client/resources/agents/messages.py”, line 716, in send
return self._post(
~~~~~~~~~~^
f"/v1/agents/{agent_id}/messages",
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
…<24 lines>…
stream_cls=Stream[LettaStreamingResponse],
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File “/lib/python3.13/site-packages/letta_client/_base_client.py”, line 1242, in post
return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/lib/python3.13/site-packages/letta_client/_base_client.py”, line 1044, in request
raise self._make_status_error_from_response(err.response) from None
letta_client.UnprocessableEntityError: Error code: 422 - {‘trace_id’: ‘’, ‘detail’: ‘[{‘type’: ‘missing’, ‘loc’: (‘body’, ‘messages’), ‘msg’: ‘Field required’, ‘input’: {‘input’: “Analyze this point’s coordinates: [-122.4194, 37.7749] (EPSG:4326). Is it in a known city? First, call download_data to fetch the dataset from https://naturalearth.s3.amazonaws.com/110m_cultural/ne_110m_populated_places.zip to natural_earth. Then, call geopandas_api with function_name=‘proximity_analysis’, point_coords=[-122.4194, 37.7749], distance_m=5000, dataset_path=‘natural_earth/ne_110m_populated_places.shp’.”}}]’}

This is a server version mismatch. Your SDK (1.0.0a19) is sending the new input shorthand, but your self-hosted server doesn’t understand it yet.

The issue:

  • SDK v1.0 expects a newer server version that supports the input parameter
  • Your self-hosted server (likely 0.12.x or 0.13.x) expects the older messages format

Workaround - use the verbose message format:

response = client.agents.messages.send(
    agent_id=agent.id,
    messages=[{"role": "user", "content": message_text}]
)

This should work with your current server version.

Long-term solution:

You have two options:

  1. Upgrade your self-hosted server to match SDK v1.0 (would need to use latest Docker image)
  2. Downgrade your SDK to match your server version:
    pip uninstall letta-client
    pip install letta  # Old SDK for 0.12.x/0.13.x servers
    

If you want to stay on SDK v1.0, you’ll need to upgrade your Docker container to the latest version. But given your earlier concern about stability, you might prefer option 2 (downgrade SDK to match your pinned server).

What’s your Docker image version? That will help determine the best path forward.

I am using letta:latest in my Docker, but I am guessing this is NOT the alpha version of the server. Can you verify please

You’re correct - letta:latest is NOT the alpha server version compatible with SDK v1.0.

What letta:latest contains:

  • Latest stable release (likely 0.13.x or similar)
  • Does NOT support SDK v1.0 alpha features (like the input shorthand)

To use SDK v1.0, you need:

  • A development/alpha version of the server that matches SDK v1.0
  • Unfortunately, there’s no official Docker tag for this yet (like letta:alpha or letta:v1.0-alpha)

Your options:

  1. Downgrade SDK to match your server (recommended for stability):

    pip uninstall letta-client
    pip install letta  # Old stable SDK for letta:latest
    
  2. Use the verbose message format (workaround to keep SDK v1.0):

    response = client.agents.messages.send(
        agent_id=agent.id,
        messages=[{"role": "user", "content": message_text}]
    )
    

    This bypasses the input shorthand that your server doesn’t understand.

  3. Wait for stable v1.0 release - When SDK v1.0 exits alpha, there will be a corresponding stable Docker image.

Cameron/team: Is there an alpha Docker image tag users can use to test SDK v1.0? Or is the expectation that people use Letta Cloud during the alpha period?

Great, that works. Migration docs should have a note about this for self hosters.

Self hosting is going to be delayed a bit because you need an updated server version, but we should clarify this in the guide.

1 Like