API Changelog


Query tools by name

The List Tools API now supports querying by tool name.

1send_message_tool_id = client.agents.tools.list(tool_name="secret_message")[0].id

Authorization header now supports password

For self-deployed instances of Letta that are password-protected, the Authorization header now supports parsing passwords in addition to API keys. X-BARE-PASSWORD will still be supported as legacy, but will be deprecated in a future release.

Before:

1curl --request POST \
2 --url https://MYSERVER.up.railway.app/v1/agents/ \
3 --header 'X-BARE-PASSWORD: password banana' \
4 --header 'Content-Type: application/json' \
5 --data '{
6 ...
7 }'

After:

1curl --request POST \
2 --url https://MYSERVER.up.railway.app/v1/agents/ \
3 --header 'AUTHORIZATION: Bearer banana' \
4 --header 'Content-Type: application/json' \
5 --data '{
6 ...
7 }'

Password can now be passed via the token field when initializing the Letta client:

1client = LettaClient(
2 base_url="https://MYSERVER.up.railway.app",
3 token="banana",
4)

Tool rules improvements

ToolRule objects no longer should specify a type at instantiation, as this field is now immutable.

Before:

1 rule = InitToolRule(
2 tool_name="secret_message",
3 type="run_first"
4)

After:

1 rule = InitToolRule(tool_name="secret_message")

Letta also now supports smarter retry behavior for tool rules in the case of unrecoverable failures.

New API routes to query agent steps

The List Steps and Retrieve Step routes have been added to enable querying for additional metadata around agent execution.


Consistency Across Messages APIs

These are the final changes from our API overhaul, which means they are not backwards compatible to prior versions of our APIs and SDKs. Upgrading may require changes to your code.

Flattened UserMessage content

The content field on UserMessage objects returned by our Messages endpoints have been simplified to flat strings containing raw message text, rather than JSON strings with message text nested inside.

Before:

1 {
2 "id": "message-dea2ceab-0863-44ea-86dc-70cf02c05946",
3 "date": "2025-01-28T01:18:18+00:00",
4 "message_type": "user_message",
5 "content": "{\n \"type\": \"user_message\",\n \"message\": \"Hello, how are you?\",\n \"time\": \"2025-01-28 01:18:18 AM UTC+0000\"\n}"
6 }

After:

1 {
2 "id": "message-dea2ceab-0863-44ea-86dc-70cf02c05946",
3 "date": "2025-01-28T01:18:18+00:00",
4 "message_type": "user_message",
5 "content": "Hello, how are you?"
6 }

Top-level use_assistant_message parameter defaults to True

All message related APIs now include a top-level use_assistant_message parameter, which defaults to True if not specified. This parameter controls whether the endpoint should parse specific tool call arguments (default send_message) as AssistantMessage objects rather than ToolCallMessage objects.

Before:

1response = client.agents.messages.create(
2 agent_id=agent.id,
3 messages=[
4 MessageCreate(
5 role="user",
6 content="call the big_return function",
7 ),
8 ],
9 config=LettaRequestConfig(use_assistant_message=False),
10)

After:

1response = client.agents.messages.create(
2 agent_id=agent.id,
3 messages=[
4 MessageCreate(
5 role="user",
6 content="call the big_return function",
7 ),
8 ],
9 use_assistant_message=False,
10)

Previously, the List Messages endpoint defaulted to False internally, so this change may cause unexpected behavior in your code. To fix this, you can set the use_assistant_message parameter to False in your request.

1messages = client.agents.messages.list(
2 limit=10,
3 use_assistant_message=False,
4)

Consistent message return type

All message related APIs return LettaMessage objects now, which are simplified versions of Message objects stored in the database backend. Previously, our List Messages endpoint returned Message objects by default, which is no longer an option.

Built with