letta-nightly 0.6.39.dev20250314104053__py3-none-any.whl → 0.6.40.dev20250314173529__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of letta-nightly might be problematic. Click here for more details.

Files changed (59) hide show
  1. letta/agent.py +13 -3
  2. letta/agents/ephemeral_agent.py +2 -1
  3. letta/agents/low_latency_agent.py +8 -0
  4. letta/dynamic_multi_agent.py +274 -0
  5. letta/functions/function_sets/base.py +1 -0
  6. letta/functions/function_sets/extras.py +2 -1
  7. letta/functions/function_sets/multi_agent.py +17 -0
  8. letta/functions/helpers.py +41 -0
  9. letta/helpers/converters.py +67 -0
  10. letta/helpers/mcp_helpers.py +26 -5
  11. letta/llm_api/openai.py +1 -1
  12. letta/memory.py +2 -1
  13. letta/orm/__init__.py +2 -0
  14. letta/orm/agent.py +69 -20
  15. letta/orm/custom_columns.py +15 -0
  16. letta/orm/group.py +33 -0
  17. letta/orm/groups_agents.py +13 -0
  18. letta/orm/message.py +7 -4
  19. letta/orm/organization.py +1 -0
  20. letta/orm/sqlalchemy_base.py +3 -3
  21. letta/round_robin_multi_agent.py +152 -0
  22. letta/schemas/agent.py +3 -0
  23. letta/schemas/enums.py +0 -4
  24. letta/schemas/group.py +65 -0
  25. letta/schemas/letta_message.py +167 -106
  26. letta/schemas/letta_message_content.py +192 -0
  27. letta/schemas/message.py +28 -36
  28. letta/serialize_schemas/__init__.py +1 -1
  29. letta/serialize_schemas/marshmallow_agent.py +108 -0
  30. letta/serialize_schemas/{agent_environment_variable.py → marshmallow_agent_environment_variable.py} +1 -1
  31. letta/serialize_schemas/marshmallow_base.py +52 -0
  32. letta/serialize_schemas/{block.py → marshmallow_block.py} +1 -1
  33. letta/serialize_schemas/{custom_fields.py → marshmallow_custom_fields.py} +12 -0
  34. letta/serialize_schemas/marshmallow_message.py +42 -0
  35. letta/serialize_schemas/{tag.py → marshmallow_tag.py} +12 -2
  36. letta/serialize_schemas/{tool.py → marshmallow_tool.py} +1 -1
  37. letta/serialize_schemas/pydantic_agent_schema.py +111 -0
  38. letta/server/rest_api/app.py +15 -0
  39. letta/server/rest_api/routers/v1/__init__.py +2 -0
  40. letta/server/rest_api/routers/v1/agents.py +46 -40
  41. letta/server/rest_api/routers/v1/groups.py +233 -0
  42. letta/server/rest_api/routers/v1/tools.py +31 -3
  43. letta/server/rest_api/utils.py +1 -1
  44. letta/server/server.py +267 -12
  45. letta/services/agent_manager.py +65 -28
  46. letta/services/group_manager.py +147 -0
  47. letta/services/helpers/agent_manager_helper.py +151 -1
  48. letta/services/message_manager.py +11 -3
  49. letta/services/passage_manager.py +15 -0
  50. letta/settings.py +5 -0
  51. letta/supervisor_multi_agent.py +103 -0
  52. {letta_nightly-0.6.39.dev20250314104053.dist-info → letta_nightly-0.6.40.dev20250314173529.dist-info}/METADATA +1 -2
  53. {letta_nightly-0.6.39.dev20250314104053.dist-info → letta_nightly-0.6.40.dev20250314173529.dist-info}/RECORD +56 -46
  54. letta/serialize_schemas/agent.py +0 -80
  55. letta/serialize_schemas/base.py +0 -64
  56. letta/serialize_schemas/message.py +0 -29
  57. {letta_nightly-0.6.39.dev20250314104053.dist-info → letta_nightly-0.6.40.dev20250314173529.dist-info}/LICENSE +0 -0
  58. {letta_nightly-0.6.39.dev20250314104053.dist-info → letta_nightly-0.6.40.dev20250314173529.dist-info}/WHEEL +0 -0
  59. {letta_nightly-0.6.39.dev20250314104053.dist-info → letta_nightly-0.6.40.dev20250314173529.dist-info}/entry_points.txt +0 -0
@@ -4,109 +4,132 @@ from typing import Annotated, List, Literal, Optional, Union
4
4
 
5
5
  from pydantic import BaseModel, Field, field_serializer, field_validator
6
6
 
7
- from letta.schemas.enums import MessageContentType
7
+ from letta.schemas.letta_message_content import (
8
+ LettaAssistantMessageContentUnion,
9
+ LettaUserMessageContentUnion,
10
+ get_letta_assistant_message_content_union_str_json_schema,
11
+ get_letta_user_message_content_union_str_json_schema,
12
+ )
8
13
 
9
- # Letta API style responses (intended to be easier to use vs getting true Message types)
14
+ # ---------------------------
15
+ # Letta API Messaging Schemas
16
+ # ---------------------------
10
17
 
11
18
 
12
19
  class LettaMessage(BaseModel):
13
20
  """
14
- Base class for simplified Letta message response type. This is intended to be used for developers who want the internal monologue, tool calls, and tool returns in a simplified format that does not include additional information other than the content and timestamp.
21
+ Base class for simplified Letta message response type. This is intended to be used for developers
22
+ who want the internal monologue, tool calls, and tool returns in a simplified format that does not
23
+ include additional information other than the content and timestamp.
15
24
 
16
- Attributes:
25
+ Args:
17
26
  id (str): The ID of the message
18
27
  date (datetime): The date the message was created in ISO format
19
-
28
+ name (Optional[str]): The name of the sender of the message
20
29
  """
21
30
 
22
- # NOTE: use Pydantic's discriminated unions feature: https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions
23
- # see `message_type` attribute
24
-
25
31
  id: str
26
32
  date: datetime
33
+ name: Optional[str] = None
27
34
 
28
35
  @field_serializer("date")
29
36
  def serialize_datetime(self, dt: datetime, _info):
37
+ """
38
+ Remove microseconds since it seems like we're inconsistent with getting them
39
+ TODO: figure out why we don't always get microseconds (get_utc_time() does)
40
+ """
30
41
  if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None:
31
42
  dt = dt.replace(tzinfo=timezone.utc)
32
- # Remove microseconds since it seems like we're inconsistent with getting them
33
- # TODO figure out why we don't always get microseconds (get_utc_time() does)
34
43
  return dt.isoformat(timespec="seconds")
35
44
 
36
45
 
37
- class MessageContent(BaseModel):
38
- type: MessageContentType = Field(..., description="The type of the message.")
39
-
40
-
41
- class TextContent(MessageContent):
42
- type: Literal[MessageContentType.text] = Field(MessageContentType.text, description="The type of the message.")
43
- text: str = Field(..., description="The text content of the message.")
44
-
45
-
46
- MessageContentUnion = Annotated[
47
- Union[TextContent],
48
- Field(discriminator="type"),
49
- ]
50
-
51
-
52
46
  class SystemMessage(LettaMessage):
53
47
  """
54
48
  A message generated by the system. Never streamed back on a response, only used for cursor pagination.
55
49
 
56
- Attributes:
57
- content (Union[str, List[MessageContentUnion]]): The message content sent by the user (can be a string or an array of content parts)
50
+ Args:
58
51
  id (str): The ID of the message
59
52
  date (datetime): The date the message was created in ISO format
53
+ name (Optional[str]): The name of the sender of the message
54
+ content (str): The message content sent by the system
60
55
  """
61
56
 
62
57
  message_type: Literal["system_message"] = "system_message"
63
- content: Union[str, List[MessageContentUnion]]
58
+ content: str = Field(..., description="The message content sent by the system")
64
59
 
65
60
 
66
61
  class UserMessage(LettaMessage):
67
62
  """
68
63
  A message sent by the user. Never streamed back on a response, only used for cursor pagination.
69
64
 
70
- Attributes:
71
- content (Union[str, List[MessageContentUnion]]): The message content sent by the user (can be a string or an array of content parts)
65
+ Args:
72
66
  id (str): The ID of the message
73
67
  date (datetime): The date the message was created in ISO format
68
+ name (Optional[str]): The name of the sender of the message
69
+ content (Union[str, List[LettaUserMessageContentUnion]]): The message content sent by the user (can be a string or an array of multi-modal content parts)
74
70
  """
75
71
 
76
72
  message_type: Literal["user_message"] = "user_message"
77
- content: Union[str, List[MessageContentUnion]]
73
+ content: Union[str, List[LettaUserMessageContentUnion]] = Field(
74
+ ...,
75
+ description="The message content sent by the user (can be a string or an array of multi-modal content parts)",
76
+ json_schema_extra=get_letta_user_message_content_union_str_json_schema(),
77
+ )
78
78
 
79
79
 
80
80
  class ReasoningMessage(LettaMessage):
81
81
  """
82
82
  Representation of an agent's internal reasoning.
83
83
 
84
- Attributes:
84
+ Args:
85
+ id (str): The ID of the message
86
+ date (datetime): The date the message was created in ISO format
87
+ name (Optional[str]): The name of the sender of the message
88
+ source (Literal["reasoner_model", "non_reasoner_model"]): Whether the reasoning
89
+ content was generated natively by a reasoner model or derived via prompting
85
90
  reasoning (str): The internal reasoning of the agent
91
+ """
92
+
93
+ message_type: Literal["reasoning_message"] = "reasoning_message"
94
+ source: Literal["reasoner_model", "non_reasoner_model"] = "non_reasoner_model"
95
+ reasoning: str
96
+
97
+
98
+ class HiddenReasoningMessage(LettaMessage):
99
+ """
100
+ Representation of an agent's internal reasoning where reasoning content
101
+ has been hidden from the response.
102
+
103
+ Args:
86
104
  id (str): The ID of the message
87
105
  date (datetime): The date the message was created in ISO format
106
+ name (Optional[str]): The name of the sender of the message
107
+ state (Literal["redacted", "omitted"]): Whether the reasoning
108
+ content was redacted by the provider or simply omitted by the API
109
+ reasoning (str): The internal reasoning of the agent
88
110
  """
89
111
 
90
112
  message_type: Literal["reasoning_message"] = "reasoning_message"
113
+ state: Literal["redacted", "omitted"]
91
114
  reasoning: str
92
115
 
93
116
 
94
117
  class ToolCall(BaseModel):
95
-
96
118
  name: str
97
119
  arguments: str
98
120
  tool_call_id: str
99
121
 
100
122
 
101
123
  class ToolCallDelta(BaseModel):
102
-
103
124
  name: Optional[str]
104
125
  arguments: Optional[str]
105
126
  tool_call_id: Optional[str]
106
127
 
107
- # NOTE: this is a workaround to exclude None values from the JSON dump,
108
- # since the OpenAI style of returning chunks doesn't include keys with null values
109
128
  def model_dump(self, *args, **kwargs):
129
+ """
130
+ This is a workaround to exclude None values from the JSON dump since the
131
+ OpenAI style of returning chunks doesn't include keys with null values.
132
+ """
110
133
  kwargs["exclude_none"] = True
111
134
  return super().model_dump(*args, **kwargs)
112
135
 
@@ -118,17 +141,20 @@ class ToolCallMessage(LettaMessage):
118
141
  """
119
142
  A message representing a request to call a tool (generated by the LLM to trigger tool execution).
120
143
 
121
- Attributes:
122
- tool_call (Union[ToolCall, ToolCallDelta]): The tool call
144
+ Args:
123
145
  id (str): The ID of the message
124
146
  date (datetime): The date the message was created in ISO format
147
+ name (Optional[str]): The name of the sender of the message
148
+ tool_call (Union[ToolCall, ToolCallDelta]): The tool call
125
149
  """
126
150
 
127
151
  message_type: Literal["tool_call_message"] = "tool_call_message"
128
152
  tool_call: Union[ToolCall, ToolCallDelta]
129
153
 
130
- # NOTE: this is required for the ToolCallDelta exclude_none to work correctly
131
154
  def model_dump(self, *args, **kwargs):
155
+ """
156
+ Handling for the ToolCallDelta exclude_none to work correctly
157
+ """
132
158
  kwargs["exclude_none"] = True
133
159
  data = super().model_dump(*args, **kwargs)
134
160
  if isinstance(data["tool_call"], dict):
@@ -141,12 +167,14 @@ class ToolCallMessage(LettaMessage):
141
167
  ToolCall: lambda v: v.model_dump(exclude_none=True),
142
168
  }
143
169
 
144
- # NOTE: this is required to cast dicts into ToolCallMessage objects
145
- # Without this extra validator, Pydantic will throw an error if 'name' or 'arguments' are None
146
- # (instead of properly casting to ToolCallDelta instead of ToolCall)
147
170
  @field_validator("tool_call", mode="before")
148
171
  @classmethod
149
172
  def validate_tool_call(cls, v):
173
+ """
174
+ Casts dicts into ToolCallMessage objects. Without this extra validator, Pydantic will throw
175
+ an error if 'name' or 'arguments' are None instead of properly casting to ToolCallDelta
176
+ instead of ToolCall.
177
+ """
150
178
  if isinstance(v, dict):
151
179
  if "name" in v and "arguments" in v and "tool_call_id" in v:
152
180
  return ToolCall(name=v["name"], arguments=v["arguments"], tool_call_id=v["tool_call_id"])
@@ -161,11 +189,12 @@ class ToolReturnMessage(LettaMessage):
161
189
  """
162
190
  A message representing the return value of a tool call (generated by Letta executing the requested tool).
163
191
 
164
- Attributes:
165
- tool_return (str): The return value of the tool
166
- status (Literal["success", "error"]): The status of the tool call
192
+ Args:
167
193
  id (str): The ID of the message
168
194
  date (datetime): The date the message was created in ISO format
195
+ name (Optional[str]): The name of the sender of the message
196
+ tool_return (str): The return value of the tool
197
+ status (Literal["success", "error"]): The status of the tool call
169
198
  tool_call_id (str): A unique identifier for the tool call that generated this message
170
199
  stdout (Optional[List(str)]): Captured stdout (e.g. prints, logs) from the tool invocation
171
200
  stderr (Optional[List(str)]): Captured stderr from the tool invocation
@@ -179,12 +208,100 @@ class ToolReturnMessage(LettaMessage):
179
208
  stderr: Optional[List[str]] = None
180
209
 
181
210
 
182
- # Legacy Letta API had an additional type "assistant_message" and the "function_call" was a formatted string
211
+ class AssistantMessage(LettaMessage):
212
+ """
213
+ A message sent by the LLM in response to user input. Used in the LLM context.
183
214
 
215
+ Args:
216
+ id (str): The ID of the message
217
+ date (datetime): The date the message was created in ISO format
218
+ name (Optional[str]): The name of the sender of the message
219
+ content (Union[str, List[LettaAssistantMessageContentUnion]]): The message content sent by the agent (can be a string or an array of content parts)
220
+ """
184
221
 
185
- class AssistantMessage(LettaMessage):
186
222
  message_type: Literal["assistant_message"] = "assistant_message"
187
- content: Union[str, List[MessageContentUnion]]
223
+ content: Union[str, List[LettaAssistantMessageContentUnion]] = Field(
224
+ ...,
225
+ description="The message content sent by the agent (can be a string or an array of content parts)",
226
+ json_schema_extra=get_letta_assistant_message_content_union_str_json_schema(),
227
+ )
228
+
229
+
230
+ # NOTE: use Pydantic's discriminated unions feature: https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions
231
+ LettaMessageUnion = Annotated[
232
+ Union[SystemMessage, UserMessage, ReasoningMessage, ToolCallMessage, ToolReturnMessage, AssistantMessage],
233
+ Field(discriminator="message_type"),
234
+ ]
235
+
236
+
237
+ def create_letta_message_union_schema():
238
+ return {
239
+ "oneOf": [
240
+ {"$ref": "#/components/schemas/SystemMessage"},
241
+ {"$ref": "#/components/schemas/UserMessage"},
242
+ {"$ref": "#/components/schemas/ReasoningMessage"},
243
+ {"$ref": "#/components/schemas/ToolCallMessage"},
244
+ {"$ref": "#/components/schemas/ToolReturnMessage"},
245
+ {"$ref": "#/components/schemas/AssistantMessage"},
246
+ ],
247
+ "discriminator": {
248
+ "propertyName": "message_type",
249
+ "mapping": {
250
+ "system_message": "#/components/schemas/SystemMessage",
251
+ "user_message": "#/components/schemas/UserMessage",
252
+ "reasoning_message": "#/components/schemas/ReasoningMessage",
253
+ "tool_call_message": "#/components/schemas/ToolCallMessage",
254
+ "tool_return_message": "#/components/schemas/ToolReturnMessage",
255
+ "assistant_message": "#/components/schemas/AssistantMessage",
256
+ },
257
+ },
258
+ }
259
+
260
+
261
+ # --------------------------
262
+ # Message Update API Schemas
263
+ # --------------------------
264
+
265
+
266
+ class UpdateSystemMessage(BaseModel):
267
+ message_type: Literal["system_message"] = "system_message"
268
+ content: str = Field(
269
+ ..., description="The message content sent by the system (can be a string or an array of multi-modal content parts)"
270
+ )
271
+
272
+
273
+ class UpdateUserMessage(BaseModel):
274
+ message_type: Literal["user_message"] = "user_message"
275
+ content: Union[str, List[LettaUserMessageContentUnion]] = Field(
276
+ ...,
277
+ description="The message content sent by the user (can be a string or an array of multi-modal content parts)",
278
+ json_schema_extra=get_letta_user_message_content_union_str_json_schema(),
279
+ )
280
+
281
+
282
+ class UpdateReasoningMessage(BaseModel):
283
+ reasoning: str
284
+ message_type: Literal["reasoning_message"] = "reasoning_message"
285
+
286
+
287
+ class UpdateAssistantMessage(BaseModel):
288
+ message_type: Literal["assistant_message"] = "assistant_message"
289
+ content: Union[str, List[LettaAssistantMessageContentUnion]] = Field(
290
+ ...,
291
+ description="The message content sent by the assistant (can be a string or an array of content parts)",
292
+ json_schema_extra=get_letta_assistant_message_content_union_str_json_schema(),
293
+ )
294
+
295
+
296
+ LettaMessageUpdateUnion = Annotated[
297
+ Union[UpdateSystemMessage, UpdateUserMessage, UpdateReasoningMessage, UpdateAssistantMessage],
298
+ Field(discriminator="message_type"),
299
+ ]
300
+
301
+
302
+ # --------------------------
303
+ # Deprecated Message Schemas
304
+ # --------------------------
188
305
 
189
306
 
190
307
  class LegacyFunctionCallMessage(LettaMessage):
@@ -195,7 +312,7 @@ class LegacyFunctionReturn(LettaMessage):
195
312
  """
196
313
  A message representing the return value of a function call (generated by Letta executing the requested function).
197
314
 
198
- Attributes:
315
+ Args:
199
316
  function_return (str): The return value of the function
200
317
  status (Literal["success", "error"]): The status of the function call
201
318
  id (str): The ID of the message
@@ -217,7 +334,7 @@ class LegacyInternalMonologue(LettaMessage):
217
334
  """
218
335
  Representation of an agent's internal monologue.
219
336
 
220
- Attributes:
337
+ Args:
221
338
  internal_monologue (str): The internal monologue of the agent
222
339
  id (str): The ID of the message
223
340
  date (datetime): The date the message was created in ISO format
@@ -228,59 +345,3 @@ class LegacyInternalMonologue(LettaMessage):
228
345
 
229
346
 
230
347
  LegacyLettaMessage = Union[LegacyInternalMonologue, AssistantMessage, LegacyFunctionCallMessage, LegacyFunctionReturn]
231
-
232
-
233
- LettaMessageUnion = Annotated[
234
- Union[SystemMessage, UserMessage, ReasoningMessage, ToolCallMessage, ToolReturnMessage, AssistantMessage],
235
- Field(discriminator="message_type"),
236
- ]
237
-
238
-
239
- class UpdateSystemMessage(BaseModel):
240
- content: Union[str, List[MessageContentUnion]]
241
- message_type: Literal["system_message"] = "system_message"
242
-
243
-
244
- class UpdateUserMessage(BaseModel):
245
- content: Union[str, List[MessageContentUnion]]
246
- message_type: Literal["user_message"] = "user_message"
247
-
248
-
249
- class UpdateReasoningMessage(BaseModel):
250
- reasoning: Union[str, List[MessageContentUnion]]
251
- message_type: Literal["reasoning_message"] = "reasoning_message"
252
-
253
-
254
- class UpdateAssistantMessage(BaseModel):
255
- content: Union[str, List[MessageContentUnion]]
256
- message_type: Literal["assistant_message"] = "assistant_message"
257
-
258
-
259
- LettaMessageUpdateUnion = Annotated[
260
- Union[UpdateSystemMessage, UpdateUserMessage, UpdateReasoningMessage, UpdateAssistantMessage],
261
- Field(discriminator="message_type"),
262
- ]
263
-
264
-
265
- def create_letta_message_union_schema():
266
- return {
267
- "oneOf": [
268
- {"$ref": "#/components/schemas/SystemMessage"},
269
- {"$ref": "#/components/schemas/UserMessage"},
270
- {"$ref": "#/components/schemas/ReasoningMessage"},
271
- {"$ref": "#/components/schemas/ToolCallMessage"},
272
- {"$ref": "#/components/schemas/ToolReturnMessage"},
273
- {"$ref": "#/components/schemas/AssistantMessage"},
274
- ],
275
- "discriminator": {
276
- "propertyName": "message_type",
277
- "mapping": {
278
- "system_message": "#/components/schemas/SystemMessage",
279
- "user_message": "#/components/schemas/UserMessage",
280
- "reasoning_message": "#/components/schemas/ReasoningMessage",
281
- "tool_call_message": "#/components/schemas/ToolCallMessage",
282
- "tool_return_message": "#/components/schemas/ToolReturnMessage",
283
- "assistant_message": "#/components/schemas/AssistantMessage",
284
- },
285
- },
286
- }
@@ -0,0 +1,192 @@
1
+ from enum import Enum
2
+ from typing import Annotated, Literal, Optional, Union
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+ class MessageContentType(str, Enum):
8
+ text = "text"
9
+ tool_call = "tool_call"
10
+ tool_return = "tool_return"
11
+ reasoning = "reasoning"
12
+ redacted_reasoning = "redacted_reasoning"
13
+ omitted_reasoning = "omitted_reasoning"
14
+
15
+
16
+ class MessageContent(BaseModel):
17
+ type: MessageContentType = Field(..., description="The type of the message.")
18
+
19
+
20
+ # -------------------------------
21
+ # User Content Types
22
+ # -------------------------------
23
+
24
+
25
+ class TextContent(MessageContent):
26
+ type: Literal[MessageContentType.text] = Field(MessageContentType.text, description="The type of the message.")
27
+ text: str = Field(..., description="The text content of the message.")
28
+
29
+
30
+ LettaUserMessageContentUnion = Annotated[
31
+ Union[TextContent],
32
+ Field(discriminator="type"),
33
+ ]
34
+
35
+
36
+ def create_letta_user_message_content_union_schema():
37
+ return {
38
+ "oneOf": [
39
+ {"$ref": "#/components/schemas/TextContent"},
40
+ ],
41
+ "discriminator": {
42
+ "propertyName": "type",
43
+ "mapping": {
44
+ "text": "#/components/schemas/TextContent",
45
+ },
46
+ },
47
+ }
48
+
49
+
50
+ def get_letta_user_message_content_union_str_json_schema():
51
+ return {
52
+ "anyOf": [
53
+ {
54
+ "type": "array",
55
+ "items": {
56
+ "$ref": "#/components/schemas/LettaUserMessageContentUnion",
57
+ },
58
+ },
59
+ {"type": "string"},
60
+ ],
61
+ }
62
+
63
+
64
+ # -------------------------------
65
+ # Assistant Content Types
66
+ # -------------------------------
67
+
68
+
69
+ LettaAssistantMessageContentUnion = Annotated[
70
+ Union[TextContent],
71
+ Field(discriminator="type"),
72
+ ]
73
+
74
+
75
+ def create_letta_assistant_message_content_union_schema():
76
+ return {
77
+ "oneOf": [
78
+ {"$ref": "#/components/schemas/TextContent"},
79
+ ],
80
+ "discriminator": {
81
+ "propertyName": "type",
82
+ "mapping": {
83
+ "text": "#/components/schemas/TextContent",
84
+ },
85
+ },
86
+ }
87
+
88
+
89
+ def get_letta_assistant_message_content_union_str_json_schema():
90
+ return {
91
+ "anyOf": [
92
+ {
93
+ "type": "array",
94
+ "items": {
95
+ "$ref": "#/components/schemas/LettaAssistantMessageContentUnion",
96
+ },
97
+ },
98
+ {"type": "string"},
99
+ ],
100
+ }
101
+
102
+
103
+ # -------------------------------
104
+ # Intermediate Step Content Types
105
+ # -------------------------------
106
+
107
+
108
+ class ToolCallContent(MessageContent):
109
+ type: Literal[MessageContentType.tool_call] = Field(
110
+ MessageContentType.tool_call, description="Indicates this content represents a tool call event."
111
+ )
112
+ id: str = Field(..., description="A unique identifier for this specific tool call instance.")
113
+ name: str = Field(..., description="The name of the tool being called.")
114
+ input: dict = Field(
115
+ ..., description="The parameters being passed to the tool, structured as a dictionary of parameter names to values."
116
+ )
117
+
118
+
119
+ class ToolReturnContent(MessageContent):
120
+ type: Literal[MessageContentType.tool_return] = Field(
121
+ MessageContentType.tool_return, description="Indicates this content represents a tool return event."
122
+ )
123
+ tool_call_id: str = Field(..., description="References the ID of the ToolCallContent that initiated this tool call.")
124
+ content: str = Field(..., description="The content returned by the tool execution.")
125
+ is_error: bool = Field(..., description="Indicates whether the tool execution resulted in an error.")
126
+
127
+
128
+ class ReasoningContent(MessageContent):
129
+ type: Literal[MessageContentType.reasoning] = Field(
130
+ MessageContentType.reasoning, description="Indicates this is a reasoning/intermediate step."
131
+ )
132
+ is_native: bool = Field(..., description="Whether the reasoning content was generated by a reasoner model that processed this step.")
133
+ reasoning: str = Field(..., description="The intermediate reasoning or thought process content.")
134
+ signature: Optional[str] = Field(None, description="A unique identifier for this reasoning step.")
135
+
136
+
137
+ class RedactedReasoningContent(MessageContent):
138
+ type: Literal[MessageContentType.redacted_reasoning] = Field(
139
+ MessageContentType.redacted_reasoning, description="Indicates this is a redacted thinking step."
140
+ )
141
+ data: str = Field(..., description="The redacted or filtered intermediate reasoning content.")
142
+
143
+
144
+ class OmittedReasoningContent(MessageContent):
145
+ type: Literal[MessageContentType.omitted_reasoning] = Field(
146
+ MessageContentType.omitted_reasoning, description="Indicates this is an omitted reasoning step."
147
+ )
148
+ tokens: int = Field(..., description="The reasoning token count for intermediate reasoning content.")
149
+
150
+
151
+ LettaMessageContentUnion = Annotated[
152
+ Union[TextContent, ToolCallContent, ToolReturnContent, ReasoningContent, RedactedReasoningContent, OmittedReasoningContent],
153
+ Field(discriminator="type"),
154
+ ]
155
+
156
+
157
+ def create_letta_message_content_union_schema():
158
+ return {
159
+ "oneOf": [
160
+ {"$ref": "#/components/schemas/TextContent"},
161
+ {"$ref": "#/components/schemas/ToolCallContent"},
162
+ {"$ref": "#/components/schemas/ToolReturnContent"},
163
+ {"$ref": "#/components/schemas/ReasoningContent"},
164
+ {"$ref": "#/components/schemas/RedactedReasoningContent"},
165
+ {"$ref": "#/components/schemas/OmittedReasoningContent"},
166
+ ],
167
+ "discriminator": {
168
+ "propertyName": "type",
169
+ "mapping": {
170
+ "text": "#/components/schemas/TextContent",
171
+ "tool_call": "#/components/schemas/ToolCallContent",
172
+ "tool_return": "#/components/schemas/ToolCallContent",
173
+ "reasoning": "#/components/schemas/ReasoningContent",
174
+ "redacted_reasoning": "#/components/schemas/RedactedReasoningContent",
175
+ "omitted_reasoning": "#/components/schemas/OmittedReasoningContent",
176
+ },
177
+ },
178
+ }
179
+
180
+
181
+ def get_letta_message_content_union_str_json_schema():
182
+ return {
183
+ "anyOf": [
184
+ {
185
+ "type": "array",
186
+ "items": {
187
+ "$ref": "#/components/schemas/LettaMessageContentUnion",
188
+ },
189
+ },
190
+ {"type": "string"},
191
+ ],
192
+ }