letta-nightly 0.13.1.dev20251031234110__py3-none-any.whl → 0.13.1.dev20251101010313__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.

@@ -455,6 +455,13 @@ class LettaAgentV3(LettaAgentV2):
455
455
  request_data["parallel_tool_calls"] = True
456
456
  else:
457
457
  request_data["parallel_tool_calls"] = False
458
+
459
+ # Gemini (Google AI/Vertex) parallel tool use
460
+ elif self.agent_state.llm_config.model_endpoint_type in ["google_ai", "google_vertex"]:
461
+ # Gemini supports parallel tool calling natively through multiple parts in the response
462
+ # We just need to ensure the config flag is set for tracking purposes
463
+ # The actual handling happens in GoogleVertexClient.convert_response_to_chat_completion
464
+ pass # No specific request_data field needed for Gemini
458
465
  except Exception:
459
466
  # if this fails, we simply don't enable parallel tool use
460
467
  pass
letta/constants.py CHANGED
@@ -439,3 +439,6 @@ WEB_SEARCH_MODEL_ENV_VAR_DEFAULT_VALUE = "gpt-4.1-mini-2025-04-14"
439
439
  EXCLUDE_MODEL_KEYWORDS_FROM_BASE_TOOL_RULES = ["claude-4-sonnet", "claude-3-5-sonnet", "gpt-5", "gemini-2.5-pro"]
440
440
  # But include models with these keywords in base tool rules (overrides exclusion)
441
441
  INCLUDE_MODEL_KEYWORDS_BASE_TOOL_RULES = ["mini"]
442
+
443
+ # Default handle for model used to generate tools
444
+ DEFAULT_GENERATE_TOOL_MODEL_HANDLE = "openai/gpt-4.1"
@@ -444,14 +444,14 @@ class GoogleVertexClient(LLMClientBase):
444
444
  # NOTE(Apr 9, 2025): there's a very strange bug on 2.5 where the response has a part with broken text
445
445
  # {'candidates': [{'content': {'parts': [{'functionCall': {'name': 'send_message', 'args': {'request_heartbeat': False, 'message': 'Hello! How can I make your day better?', 'inner_thoughts': 'User has initiated contact. Sending a greeting.'}}}], 'role': 'model'}, 'finishReason': 'STOP', 'avgLogprobs': -0.25891534213362066}], 'usageMetadata': {'promptTokenCount': 2493, 'candidatesTokenCount': 29, 'totalTokenCount': 2522, 'promptTokensDetails': [{'modality': 'TEXT', 'tokenCount': 2493}], 'candidatesTokensDetails': [{'modality': 'TEXT', 'tokenCount': 29}]}, 'modelVersion': 'gemini-1.5-pro-002'}
446
446
  # To patch this, if we have multiple parts we can take the last one
447
- if len(parts) > 1 and not llm_config.enable_reasoner:
447
+ # Unless parallel tool calling is enabled, in which case multiple parts may be intentional
448
+ if len(parts) > 1 and not llm_config.enable_reasoner and not llm_config.parallel_tool_calls:
448
449
  logger.warning(f"Unexpected multiple parts in response from Google AI: {parts}")
449
- # only truncate if reasoning is off
450
+ # only truncate if reasoning is off and parallel tool calls are disabled
450
451
  parts = [parts[-1]]
451
452
 
452
453
  # TODO support parts / multimodal
453
- # TODO support parallel tool calling natively
454
- # TODO Alternative here is to throw away everything else except for the first part
454
+ # Parallel tool calling is now supported when llm_config.parallel_tool_calls is enabled
455
455
  openai_response_message = None
456
456
  for response_message in parts:
457
457
  # Convert the actual message style to OpenAI style
letta/orm/agent.py CHANGED
@@ -280,6 +280,8 @@ class Agent(SqlalchemyBase, OrganizationMixin, ProjectMixin, TemplateEntityMixin
280
280
  if resolver:
281
281
  state[field_name] = resolver()
282
282
 
283
+ state["model"] = self.llm_config._to_model() if self.llm_config else None
284
+
283
285
  return self.__pydantic_model__(**state)
284
286
 
285
287
  async def to_pydantic_async(
@@ -417,5 +419,6 @@ class Agent(SqlalchemyBase, OrganizationMixin, ProjectMixin, TemplateEntityMixin
417
419
  state["managed_group"] = multi_agent_group
418
420
  state["tool_exec_environment_variables"] = tool_exec_environment_variables
419
421
  state["secrets"] = tool_exec_environment_variables
422
+ state["model"] = self.llm_config._to_model() if self.llm_config else None
420
423
 
421
424
  return self.__pydantic_model__(**state)
letta/schemas/agent.py CHANGED
@@ -17,6 +17,7 @@ from letta.schemas.letta_base import OrmMetadataBase
17
17
  from letta.schemas.llm_config import LLMConfig
18
18
  from letta.schemas.memory import Memory
19
19
  from letta.schemas.message import Message, MessageCreate
20
+ from letta.schemas.model import EmbeddingModelSettings, ModelSettings
20
21
  from letta.schemas.openai.chat_completion_response import UsageStatistics
21
22
  from letta.schemas.response_format import ResponseFormatUnion
22
23
  from letta.schemas.source import Source
@@ -87,11 +88,19 @@ class AgentState(OrmMetadataBase, validate_assignment=True):
87
88
  # agent configuration
88
89
  agent_type: AgentType = Field(..., description="The type of agent.")
89
90
 
90
- # llm information
91
- llm_config: LLMConfig = Field(..., description="The LLM configuration used by the agent.")
92
- embedding_config: EmbeddingConfig = Field(..., description="The embedding configuration used by the agent.")
91
+ # model information
92
+ llm_config: LLMConfig = Field(
93
+ ..., description="Deprecated: Use `model` field instead. The LLM configuration used by the agent.", deprecated=True
94
+ )
95
+ embedding_config: EmbeddingConfig = Field(
96
+ ..., description="Deprecated: Use `embedding` field instead. The embedding configuration used by the agent.", deprecated=True
97
+ )
98
+ model: Optional[ModelSettings] = Field(None, description="The model used by the agent.")
99
+ embedding: Optional[EmbeddingModelSettings] = Field(None, description="The embedding model used by the agent.")
100
+
93
101
  response_format: Optional[ResponseFormatUnion] = Field(
94
- None, description="The response format used by the agent when returning from `send_message`."
102
+ None,
103
+ description="The response format used by the agent",
95
104
  )
96
105
 
97
106
  # This is an object representing the in-process state of a running `Agent`
@@ -99,7 +108,7 @@ class AgentState(OrmMetadataBase, validate_assignment=True):
99
108
  description: Optional[str] = Field(None, description="The description of the agent.")
100
109
  metadata: Optional[Dict] = Field(None, description="The metadata of the agent.")
101
110
 
102
- memory: Memory = Field(..., description="The in-context memory of the agent.", deprecated=True)
111
+ memory: Memory = Field(..., description="Deprecated: Use `blocks` field instead. The in-context memory of the agent.", deprecated=True)
103
112
  blocks: List[Block] = Field(..., description="The memory blocks used by the agent.")
104
113
  tools: List[Tool] = Field(..., description="The tools used by the agent.")
105
114
  sources: List[Source] = Field(..., description="The sources used by the agent.")
@@ -117,7 +126,9 @@ class AgentState(OrmMetadataBase, validate_assignment=True):
117
126
  base_template_id: Optional[str] = Field(None, description="The base template id of the agent.")
118
127
  deployment_id: Optional[str] = Field(None, description="The id of the deployment.")
119
128
  entity_id: Optional[str] = Field(None, description="The id of the entity within the template.")
120
- identity_ids: List[str] = Field([], description="The ids of the identities associated with this agent.", deprecated=True)
129
+ identity_ids: List[str] = Field(
130
+ [], description="Deprecated: Use `identities` field instead. The ids of the identities associated with this agent.", deprecated=True
131
+ )
121
132
  identities: List[Identity] = Field([], description="The identities associated with this agent.")
122
133
 
123
134
  # An advanced configuration that makes it so this agent does not remember any previous messages
@@ -130,7 +141,9 @@ class AgentState(OrmMetadataBase, validate_assignment=True):
130
141
  description="If set to True, memory management will move to a background agent thread.",
131
142
  )
132
143
 
133
- multi_agent_group: Optional[Group] = Field(None, description="The multi-agent group that this agent manages", deprecated=True)
144
+ multi_agent_group: Optional[Group] = Field(
145
+ None, description="Deprecated: Use `managed_group` field instead. The multi-agent group that this agent manages.", deprecated=True
146
+ )
134
147
  managed_group: Optional[Group] = Field(None, description="The multi-agent group that this agent manages")
135
148
  # Run metrics
136
149
  last_run_completion: Optional[datetime] = Field(None, description="The timestamp when the agent last completed a run.")
@@ -202,8 +215,6 @@ class CreateAgent(BaseModel, validate_assignment=True): #
202
215
  tags: Optional[List[str]] = Field(None, description="The tags associated with the agent.")
203
216
  system: Optional[str] = Field(None, description="The system prompt used by the agent.")
204
217
  agent_type: AgentType = Field(default_factory=lambda: AgentType.memgpt_v2_agent, description="The type of agent.")
205
- llm_config: Optional[LLMConfig] = Field(None, description="The LLM configuration used by the agent.")
206
- embedding_config: Optional[EmbeddingConfig] = Field(None, description="The embedding configuration used by the agent.")
207
218
  # Note: if this is None, then we'll populate with the standard "more human than human" initial message sequence
208
219
  # If the client wants to make this empty, then the client can set the arg to an empty list
209
220
  initial_message_sequence: Optional[List[MessageCreate]] = Field(
@@ -216,43 +227,78 @@ class CreateAgent(BaseModel, validate_assignment=True): #
216
227
  include_base_tool_rules: Optional[bool] = Field(
217
228
  None, description="If true, attaches the Letta base tool rules (e.g. deny all tools not explicitly allowed)."
218
229
  )
219
- include_default_source: bool = Field(
220
- False, description="If true, automatically creates and attaches a default data source for this agent."
230
+ include_default_source: bool = Field( # TODO: get rid of this
231
+ False, description="If true, automatically creates and attaches a default data source for this agent.", deprecated=True
221
232
  )
222
233
  description: Optional[str] = Field(None, description="The description of the agent.")
223
234
  metadata: Optional[Dict] = Field(None, description="The metadata of the agent.")
224
- model: Optional[str] = Field(
235
+
236
+ # model configuration
237
+ llm_config: Optional[LLMConfig] = Field(
238
+ None, description="Deprecated: Use `model` field instead. The LLM configuration used by the agent.", deprecated=True
239
+ )
240
+ embedding_config: Optional[EmbeddingConfig] = Field(
241
+ None, description="Deprecated: Use `embedding` field instead. The embedding configuration used by the agent.", deprecated=True
242
+ )
243
+ model: Optional[str | ModelSettings] = Field( # TODO: make this required (breaking change)
225
244
  None,
226
- description="The LLM configuration handle used by the agent, specified in the format "
227
- "provider/model-name, as an alternative to specifying llm_config.",
245
+ description="The model handle or model settings for the agent to use, specified either by a handle or an object. See the model schema for more information.",
228
246
  )
229
- embedding: Optional[str] = Field(
247
+ embedding: Optional[str | EmbeddingModelSettings] = Field(
230
248
  None, description="The embedding configuration handle used by the agent, specified in the format provider/model-name."
231
249
  )
250
+
232
251
  context_window_limit: Optional[int] = Field(None, description="The context window limit used by the agent.")
233
- embedding_chunk_size: Optional[int] = Field(DEFAULT_EMBEDDING_CHUNK_SIZE, description="The embedding chunk size used by the agent.")
252
+ embedding_chunk_size: Optional[int] = Field(
253
+ DEFAULT_EMBEDDING_CHUNK_SIZE, description="Deprecated: No longer used. The embedding chunk size used by the agent.", deprecated=True
254
+ )
234
255
  max_tokens: Optional[int] = Field(
235
256
  None,
236
- description="The maximum number of tokens to generate, including reasoning step. If not set, the model will use its default value.",
257
+ description="Deprecated: Use `model` field to configure max output tokens instead. The maximum number of tokens to generate, including reasoning step.",
258
+ deprecated=True,
237
259
  )
238
260
  max_reasoning_tokens: Optional[int] = Field(
239
- None, description="The maximum number of tokens to generate for reasoning step. If not set, the model will use its default value."
261
+ None,
262
+ description="Deprecated: Use `model` field to configure reasoning tokens instead. The maximum number of tokens to generate for reasoning step.",
263
+ deprecated=True,
264
+ )
265
+ enable_reasoner: Optional[bool] = Field(
266
+ True,
267
+ description="Deprecated: Use `model` field to configure reasoning instead. Whether to enable internal extended thinking step for a reasoner model.",
268
+ deprecated=True,
269
+ )
270
+ reasoning: Optional[bool] = Field(
271
+ None,
272
+ description="Deprecated: Use `model` field to configure reasoning instead. Whether to enable reasoning for this agent.",
273
+ deprecated=True,
274
+ )
275
+ from_template: Optional[str] = Field(
276
+ None, description="Deprecated: please use the 'create agents from a template' endpoint instead.", deprecated=True
240
277
  )
241
- enable_reasoner: Optional[bool] = Field(True, description="Whether to enable internal extended thinking step for a reasoner model.")
242
- reasoning: Optional[bool] = Field(None, description="Whether to enable reasoning for this agent.")
243
- from_template: Optional[str] = Field(None, description="Deprecated: please use the 'create agents from a template' endpoint instead.")
244
- template: bool = Field(False, description="Deprecated: No longer used")
278
+ template: bool = Field(False, description="Deprecated: No longer used.", deprecated=True)
245
279
  project: Optional[str] = Field(
246
280
  None,
247
281
  deprecated=True,
248
- description="Deprecated: Project should now be passed via the X-Project header instead of in the request body. If using the sdk, this can be done via the new x_project field below.",
282
+ description="Deprecated: Project should now be passed via the X-Project header instead of in the request body. If using the SDK, this can be done via the x_project parameter.",
283
+ )
284
+ tool_exec_environment_variables: Optional[Dict[str, str]] = Field(
285
+ None, description="Deprecated: Use `secrets` field instead. Environment variables for tool execution.", deprecated=True
249
286
  )
250
- tool_exec_environment_variables: Optional[Dict[str, str]] = Field(None, description="Deprecated: use `secrets` field instead.")
251
287
  secrets: Optional[Dict[str, str]] = Field(None, description="The environment variables for tool execution specific to this agent.")
252
- memory_variables: Optional[Dict[str, str]] = Field(None, description="The variables that should be set for the agent.")
253
- project_id: Optional[str] = Field(None, description="The id of the project the agent belongs to.")
254
- template_id: Optional[str] = Field(None, description="The id of the template the agent belongs to.")
255
- base_template_id: Optional[str] = Field(None, description="The base template id of the agent.")
288
+ memory_variables: Optional[Dict[str, str]] = Field(
289
+ None,
290
+ description="Deprecated: Only relevant for creating agents from a template. Use the 'create agents from a template' endpoint instead.",
291
+ deprecated=True,
292
+ )
293
+ project_id: Optional[str] = Field(
294
+ None, description="Deprecated: No longer used. The id of the project the agent belongs to.", deprecated=True
295
+ )
296
+ template_id: Optional[str] = Field(
297
+ None, description="Deprecated: No longer used. The id of the template the agent belongs to.", deprecated=True
298
+ )
299
+ base_template_id: Optional[str] = Field(
300
+ None, description="Deprecated: No longer used. The base template id of the agent.", deprecated=True
301
+ )
256
302
  identity_ids: Optional[List[str]] = Field(None, description="The ids of the identities associated with this agent.")
257
303
  message_buffer_autoclear: bool = Field(
258
304
  False,
@@ -271,9 +317,14 @@ class CreateAgent(BaseModel, validate_assignment=True): #
271
317
  )
272
318
  hidden: Optional[bool] = Field(
273
319
  None,
274
- description="If set to True, the agent will be hidden.",
320
+ description="Deprecated: No longer used. If set to True, the agent will be hidden.",
321
+ deprecated=True,
322
+ )
323
+ parallel_tool_calls: Optional[bool] = Field(
324
+ False,
325
+ description="Deprecated: Use `model` field to configure parallel tool calls instead. If set to True, enables parallel tool calling.",
326
+ deprecated=True,
275
327
  )
276
- parallel_tool_calls: Optional[bool] = Field(False, description="If set to True, enables parallel tool calling. Defaults to False.")
277
328
 
278
329
  @field_validator("name")
279
330
  @classmethod
@@ -355,8 +406,6 @@ class UpdateAgent(BaseModel):
355
406
  tags: Optional[List[str]] = Field(None, description="The tags associated with the agent.")
356
407
  system: Optional[str] = Field(None, description="The system prompt used by the agent.")
357
408
  tool_rules: Optional[List[ToolRule]] = Field(None, description="The tool rules governing the agent.")
358
- llm_config: Optional[LLMConfig] = Field(None, description="The LLM configuration used by the agent.")
359
- embedding_config: Optional[EmbeddingConfig] = Field(None, description="The embedding configuration used by the agent.")
360
409
  message_ids: Optional[List[str]] = Field(None, description="The ids of the messages in the agent's in-context memory.")
361
410
  description: Optional[str] = Field(None, description="The description of the agent.")
362
411
  metadata: Optional[Dict] = Field(None, description="The metadata of the agent.")
@@ -370,22 +419,42 @@ class UpdateAgent(BaseModel):
370
419
  None,
371
420
  description="If set to True, the agent will not remember previous messages (though the agent will still retain state via core memory blocks and archival/recall memory). Not recommended unless you have an advanced use case.",
372
421
  )
373
- model: Optional[str] = Field(
422
+
423
+ # model configuration
424
+ model: Optional[str | ModelSettings] = Field(
374
425
  None,
375
- description="The LLM configuration handle used by the agent, specified in the format "
376
- "provider/model-name, as an alternative to specifying llm_config.",
426
+ description="The model used by the agent, specified either by a handle or an object. See the model schema for more information.",
377
427
  )
378
- embedding: Optional[str] = Field(
428
+ embedding: Optional[str | EmbeddingModelSettings] = Field(
379
429
  None, description="The embedding configuration handle used by the agent, specified in the format provider/model-name."
380
430
  )
381
431
  context_window_limit: Optional[int] = Field(None, description="The context window limit used by the agent.")
432
+ reasoning: Optional[bool] = Field(
433
+ None,
434
+ description="Deprecated: Use `model` field to configure reasoning instead. Whether to enable reasoning for this agent.",
435
+ deprecated=True,
436
+ )
437
+ llm_config: Optional[LLMConfig] = Field(
438
+ None, description="Deprecated: Use `model` field instead. The LLM configuration used by the agent.", deprecated=True
439
+ )
440
+ embedding_config: Optional[EmbeddingConfig] = Field(None, description="The embedding configuration used by the agent.")
441
+ parallel_tool_calls: Optional[bool] = Field(
442
+ False,
443
+ description="Deprecated: Use `model` field to configure parallel tool calls instead. If set to True, enables parallel tool calling.",
444
+ deprecated=True,
445
+ )
446
+ response_format: Optional[ResponseFormatUnion] = Field(
447
+ None,
448
+ description="Deprecated: Use `model` field to configure response format instead. The response format for the agent.",
449
+ deprecated=True,
450
+ )
382
451
  max_tokens: Optional[int] = Field(
383
452
  None,
384
- description="The maximum number of tokens to generate, including reasoning step. If not set, the model will use its default value.",
453
+ description="Deprecated: Use `model` field to configure max output tokens instead. The maximum number of tokens to generate, including reasoning step.",
454
+ deprecated=True,
385
455
  )
386
- reasoning: Optional[bool] = Field(None, description="Whether to enable reasoning for this agent.")
456
+
387
457
  enable_sleeptime: Optional[bool] = Field(None, description="If set to True, memory management will move to a background agent thread.")
388
- response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the agent.")
389
458
  last_run_completion: Optional[datetime] = Field(None, description="The timestamp when the agent last completed a run.")
390
459
  last_run_duration_ms: Optional[int] = Field(None, description="The duration in milliseconds of the agent's last run.")
391
460
  timezone: Optional[str] = Field(None, description="The timezone of the agent (IANA format).")
@@ -401,7 +470,6 @@ class UpdateAgent(BaseModel):
401
470
  None,
402
471
  description="If set to True, the agent will be hidden.",
403
472
  )
404
- parallel_tool_calls: Optional[bool] = Field(False, description="If set to True, enables parallel tool calling. Defaults to False.")
405
473
 
406
474
  model_config = ConfigDict(extra="ignore") # Ignores extra fields
407
475
 
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Literal, Optional
1
+ from typing import TYPE_CHECKING, Annotated, Literal, Optional, Union
2
2
 
3
3
  from pydantic import BaseModel, ConfigDict, Field, model_validator
4
4
 
@@ -7,6 +7,9 @@ from letta.errors import LettaInvalidArgumentError
7
7
  from letta.log import get_logger
8
8
  from letta.schemas.enums import AgentType, ProviderCategory
9
9
 
10
+ if TYPE_CHECKING:
11
+ from letta.schemas.model import ModelSettings
12
+
10
13
  logger = get_logger(__name__)
11
14
 
12
15
 
@@ -252,6 +255,98 @@ class LLMConfig(BaseModel):
252
255
  + (f" [ip={self.model_endpoint}]" if self.model_endpoint else "")
253
256
  )
254
257
 
258
+ def _to_model(self) -> "ModelSettings":
259
+ """
260
+ Convert LLMConfig back into a Model schema (OpenAIModelSettings, AnthropicModelSettings, etc.).
261
+ This is the inverse of the _to_legacy_config_params() methods in model.py.
262
+ """
263
+ from letta.schemas.model import (
264
+ AnthropicModelSettings,
265
+ AnthropicThinking,
266
+ AzureModelSettings,
267
+ BedrockModelSettings,
268
+ DeepseekModelSettings,
269
+ GeminiThinkingConfig,
270
+ GoogleAIModelSettings,
271
+ GoogleVertexModelSettings,
272
+ GroqModelSettings,
273
+ Model,
274
+ OpenAIModelSettings,
275
+ OpenAIReasoning,
276
+ TogetherModelSettings,
277
+ XAIModelSettings,
278
+ )
279
+
280
+ if self.model_endpoint_type == "openai":
281
+ return OpenAIModelSettings(
282
+ model=self.model,
283
+ max_output_tokens=self.max_tokens or 4096,
284
+ temperature=self.temperature,
285
+ reasoning=OpenAIReasoning(reasoning_effort=self.reasoning_effort or "minimal"),
286
+ )
287
+ elif self.model_endpoint_type == "anthropic":
288
+ thinking_type = "enabled" if self.enable_reasoner else "disabled"
289
+ return AnthropicModelSettings(
290
+ model=self.model,
291
+ max_output_tokens=self.max_tokens or 4096,
292
+ temperature=self.temperature,
293
+ thinking=AnthropicThinking(type=thinking_type, budget_tokens=self.max_reasoning_tokens or 1024),
294
+ verbosity=self.verbosity,
295
+ )
296
+ elif self.model_endpoint_type == "google_ai":
297
+ return GoogleAIModelSettings(
298
+ model=self.model,
299
+ max_output_tokens=self.max_tokens or 65536,
300
+ temperature=self.temperature,
301
+ thinking_config=GeminiThinkingConfig(
302
+ include_thoughts=self.max_reasoning_tokens > 0, thinking_budget=self.max_reasoning_tokens or 1024
303
+ ),
304
+ )
305
+ elif self.model_endpoint_type == "google_vertex":
306
+ return GoogleVertexModelSettings(
307
+ model=self.model,
308
+ max_output_tokens=self.max_tokens or 65536,
309
+ temperature=self.temperature,
310
+ thinking_config=GeminiThinkingConfig(
311
+ include_thoughts=self.max_reasoning_tokens > 0, thinking_budget=self.max_reasoning_tokens or 1024
312
+ ),
313
+ )
314
+ elif self.model_endpoint_type == "azure":
315
+ return AzureModelSettings(
316
+ model=self.model,
317
+ max_output_tokens=self.max_tokens or 4096,
318
+ temperature=self.temperature,
319
+ )
320
+ elif self.model_endpoint_type == "xai":
321
+ return XAIModelSettings(
322
+ model=self.model,
323
+ max_output_tokens=self.max_tokens or 4096,
324
+ temperature=self.temperature,
325
+ )
326
+ elif self.model_endpoint_type == "groq":
327
+ return GroqModelSettings(
328
+ model=self.model,
329
+ max_output_tokens=self.max_tokens or 4096,
330
+ temperature=self.temperature,
331
+ )
332
+ elif self.model_endpoint_type == "deepseek":
333
+ return DeepseekModelSettings(
334
+ model=self.model,
335
+ max_output_tokens=self.max_tokens or 4096,
336
+ temperature=self.temperature,
337
+ )
338
+ elif self.model_endpoint_type == "together":
339
+ return TogetherModelSettings(
340
+ model=self.model,
341
+ max_output_tokens=self.max_tokens or 4096,
342
+ temperature=self.temperature,
343
+ )
344
+ elif self.model_endpoint_type == "bedrock":
345
+ return Model(model=self.model, max_output_tokens=self.max_tokens or 4096)
346
+ else:
347
+ # If we don't know the model type, use the default Model schema
348
+ return Model(model=self.model, max_output_tokens=self.max_tokens or 4096)
349
+
255
350
  @classmethod
256
351
  def is_openai_reasoning_model(cls, config: "LLMConfig") -> bool:
257
352
  from letta.llm_api.openai_client import is_openai_reasoning_model
letta/schemas/model.py ADDED
@@ -0,0 +1,265 @@
1
+ from typing import Annotated, Literal, Optional, Union
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from letta.schemas.embedding_config import EmbeddingConfig
6
+ from letta.schemas.enums import ProviderType
7
+ from letta.schemas.llm_config import LLMConfig
8
+ from letta.schemas.response_format import ResponseFormatUnion
9
+
10
+
11
+ class ModelBase(BaseModel):
12
+ handle: str = Field(..., description="Unique handle for API reference (format: provider_display_name/model_display_name)")
13
+ name: str = Field(..., description="The actual model name used by the provider")
14
+ display_name: str = Field(..., description="Display name for the model shown in UI")
15
+ provider_type: ProviderType = Field(..., description="The type of the provider")
16
+ provider_name: str = Field(..., description="The name of the provider")
17
+ model_type: Literal["llm", "embedding"] = Field(..., description="Type of model (llm or embedding)")
18
+
19
+
20
+ class Model(ModelBase):
21
+ model_type: Literal["llm"] = Field("llm", description="Type of model (llm or embedding)")
22
+ max_context_window: int = Field(..., description="The maximum context window for the model")
23
+ # supports_token_streaming: Optional[bool] = Field(None, description="Whether token streaming is supported")
24
+ # supports_tool_calling: Optional[bool] = Field(None, description="Whether tool calling is supported")
25
+
26
+ def _from_llm_config(self, llm_config: LLMConfig) -> "Model":
27
+ return self(
28
+ handle=llm_config.handle,
29
+ name=llm_config.model,
30
+ display_name=llm_config.display_name,
31
+ provider_type=llm_config.model_endpoint_type,
32
+ provider_name=llm_config.provider_name,
33
+ )
34
+
35
+
36
+ class EmbeddingModel(ModelBase):
37
+ model_type: Literal["embedding"] = Field("embedding", description="Type of model (llm or embedding)")
38
+ embedding_dim: int = Field(..., description="The dimension of the embedding")
39
+
40
+ def _from_embedding_config(self, embedding_config: EmbeddingConfig) -> "Model":
41
+ return self(
42
+ handle=embedding_config.handle,
43
+ name=embedding_config.embedding_model,
44
+ display_name=embedding_config.embedding_model,
45
+ provider_type=embedding_config.embedding_endpoint_type,
46
+ provider_name=embedding_config.embedding_endpoint_type,
47
+ )
48
+
49
+
50
+ class ModelSettings(BaseModel):
51
+ """Schema for defining settings for a model"""
52
+
53
+ model: str = Field(..., description="The name of the model.")
54
+ max_output_tokens: int = Field(4096, description="The maximum number of tokens the model can generate.")
55
+
56
+
57
+ class OpenAIReasoning(BaseModel):
58
+ reasoning_effort: Literal["minimal", "low", "medium", "high"] = Field(
59
+ "minimal", description="The reasoning effort to use when generating text reasoning models"
60
+ )
61
+
62
+ # TODO: implement support for this
63
+ # summary: Optional[Literal["auto", "detailed"]] = Field(
64
+ # None, description="The reasoning summary level to use when generating text reasoning models"
65
+ # )
66
+
67
+
68
+ class OpenAIModelSettings(ModelSettings):
69
+ provider: Literal["openai"] = Field("openai", description="The provider of the model.")
70
+ temperature: float = Field(0.7, description="The temperature of the model.")
71
+ reasoning: OpenAIReasoning = Field(OpenAIReasoning(reasoning_effort="high"), description="The reasoning configuration for the model.")
72
+ response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the model.")
73
+
74
+ # TODO: implement support for these
75
+ # reasoning_summary: Optional[Literal["none", "short", "detailed"]] = Field(
76
+ # None, description="The reasoning summary level to use when generating text reasoning models"
77
+ # )
78
+ # max_tool_calls: int = Field(10, description="The maximum number of tool calls the model can make.")
79
+ # parallel_tool_calls: bool = Field(False, description="Whether the model supports parallel tool calls.")
80
+ # top_logprobs: int = Field(10, description="The number of top logprobs to return.")
81
+ # top_p: float = Field(1.0, description="The top-p value to use when generating text.")
82
+
83
+ def _to_legacy_config_params(self) -> dict:
84
+ return {
85
+ "temperature": self.temperature,
86
+ "max_tokens": self.max_output_tokens,
87
+ "reasoning_effort": self.reasoning.reasoning_effort,
88
+ "response_format": self.response_format,
89
+ }
90
+
91
+
92
+ # "thinking": {
93
+ # "type": "enabled",
94
+ # "budget_tokens": 10000
95
+ # }
96
+
97
+
98
+ class AnthropicThinking(BaseModel):
99
+ type: Literal["enabled", "disabled"] = Field("enabled", description="The type of thinking to use.")
100
+ budget_tokens: int = Field(1024, description="The maximum number of tokens the model can use for extended thinking.")
101
+
102
+
103
+ class AnthropicModelSettings(ModelSettings):
104
+ provider: Literal["anthropic"] = Field("anthropic", description="The provider of the model.")
105
+ temperature: float = Field(1.0, description="The temperature of the model.")
106
+ thinking: AnthropicThinking = Field(
107
+ AnthropicThinking(type="enabled", budget_tokens=1024), description="The thinking configuration for the model."
108
+ )
109
+
110
+ # gpt-5 models only
111
+ verbosity: Optional[Literal["low", "medium", "high"]] = Field(
112
+ None,
113
+ description="Soft control for how verbose model output should be, used for GPT-5 models.",
114
+ )
115
+
116
+ # TODO: implement support for these
117
+ # top_k: Optional[int] = Field(None, description="The number of top tokens to return.")
118
+ # top_p: Optional[float] = Field(None, description="The top-p value to use when generating text.")
119
+
120
+ def _to_legacy_config_params(self) -> dict:
121
+ return {
122
+ "temperature": self.temperature,
123
+ "max_tokens": self.max_output_tokens,
124
+ "extended_thinking": self.thinking.type == "enabled",
125
+ "thinking_budget_tokens": self.thinking.budget_tokens,
126
+ "verbosity": self.verbosity,
127
+ }
128
+
129
+
130
+ class GeminiThinkingConfig(BaseModel):
131
+ include_thoughts: bool = Field(True, description="Whether to include thoughts in the model's response.")
132
+ thinking_budget: int = Field(1024, description="The thinking budget for the model.")
133
+
134
+
135
+ class GoogleAIModelSettings(ModelSettings):
136
+ provider: Literal["google_ai"] = Field("google_ai", description="The provider of the model.")
137
+ temperature: float = Field(0.7, description="The temperature of the model.")
138
+ thinking_config: GeminiThinkingConfig = Field(
139
+ GeminiThinkingConfig(include_thoughts=True, thinking_budget=1024), description="The thinking configuration for the model."
140
+ )
141
+ response_schema: Optional[ResponseFormatUnion] = Field(None, description="The response schema for the model.")
142
+ max_output_tokens: int = Field(65536, description="The maximum number of tokens the model can generate.")
143
+
144
+ def _to_legacy_config_params(self) -> dict:
145
+ return {
146
+ "temperature": self.temperature,
147
+ "max_tokens": self.max_output_tokens,
148
+ "max_reasoning_tokens": self.thinking_config.thinking_budget if self.thinking_config.include_thoughts else 0,
149
+ }
150
+
151
+
152
+ class GoogleVertexModelSettings(GoogleAIModelSettings):
153
+ provider: Literal["google_vertex"] = Field("google_vertex", description="The provider of the model.")
154
+
155
+
156
+ class AzureModelSettings(ModelSettings):
157
+ """Azure OpenAI model configuration (OpenAI-compatible)."""
158
+
159
+ provider: Literal["azure"] = Field("azure", description="The provider of the model.")
160
+ temperature: float = Field(0.7, description="The temperature of the model.")
161
+ response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the model.")
162
+
163
+ def _to_legacy_config_params(self) -> dict:
164
+ return {
165
+ "temperature": self.temperature,
166
+ "max_tokens": self.max_output_tokens,
167
+ "response_format": self.response_format,
168
+ }
169
+
170
+
171
+ class XAIModelSettings(ModelSettings):
172
+ """xAI model configuration (OpenAI-compatible)."""
173
+
174
+ provider: Literal["xai"] = Field("xai", description="The provider of the model.")
175
+ temperature: float = Field(0.7, description="The temperature of the model.")
176
+ response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the model.")
177
+
178
+ def _to_legacy_config_params(self) -> dict:
179
+ return {
180
+ "temperature": self.temperature,
181
+ "max_tokens": self.max_output_tokens,
182
+ "response_format": self.response_format,
183
+ }
184
+
185
+
186
+ class GroqModelSettings(ModelSettings):
187
+ """Groq model configuration (OpenAI-compatible)."""
188
+
189
+ provider: Literal["groq"] = Field("groq", description="The provider of the model.")
190
+ temperature: float = Field(0.7, description="The temperature of the model.")
191
+ response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the model.")
192
+
193
+ def _to_legacy_config_params(self) -> dict:
194
+ return {
195
+ "temperature": self.temperature,
196
+ "max_tokens": self.max_output_tokens,
197
+ "response_format": self.response_format,
198
+ }
199
+
200
+
201
+ class DeepseekModelSettings(ModelSettings):
202
+ """Deepseek model configuration (OpenAI-compatible)."""
203
+
204
+ provider: Literal["deepseek"] = Field("deepseek", description="The provider of the model.")
205
+ temperature: float = Field(0.7, description="The temperature of the model.")
206
+ response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the model.")
207
+
208
+ def _to_legacy_config_params(self) -> dict:
209
+ return {
210
+ "temperature": self.temperature,
211
+ "max_tokens": self.max_output_tokens,
212
+ "response_format": self.response_format,
213
+ }
214
+
215
+
216
+ class TogetherModelSettings(ModelSettings):
217
+ """Together AI model configuration (OpenAI-compatible)."""
218
+
219
+ provider: Literal["together"] = Field("together", description="The provider of the model.")
220
+ temperature: float = Field(0.7, description="The temperature of the model.")
221
+ response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the model.")
222
+
223
+ def _to_legacy_config_params(self) -> dict:
224
+ return {
225
+ "temperature": self.temperature,
226
+ "max_tokens": self.max_output_tokens,
227
+ "response_format": self.response_format,
228
+ }
229
+
230
+
231
+ class BedrockModelSettings(ModelSettings):
232
+ """AWS Bedrock model configuration."""
233
+
234
+ provider: Literal["bedrock"] = Field("bedrock", description="The provider of the model.")
235
+ temperature: float = Field(0.7, description="The temperature of the model.")
236
+ response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the model.")
237
+
238
+ def _to_legacy_config_params(self) -> dict:
239
+ return {
240
+ "temperature": self.temperature,
241
+ "max_tokens": self.max_output_tokens,
242
+ "response_format": self.response_format,
243
+ }
244
+
245
+
246
+ ModelSettingsUnion = Annotated[
247
+ Union[
248
+ OpenAIModelSettings,
249
+ AnthropicModelSettings,
250
+ GoogleAIModelSettings,
251
+ GoogleVertexModelSettings,
252
+ AzureModelSettings,
253
+ XAIModelSettings,
254
+ GroqModelSettings,
255
+ DeepseekModelSettings,
256
+ TogetherModelSettings,
257
+ BedrockModelSettings,
258
+ ],
259
+ Field(discriminator="provider"),
260
+ ]
261
+
262
+
263
+ class EmbeddingModelSettings(BaseModel):
264
+ model: str = Field(..., description="The name of the model.")
265
+ provider: Literal["openai", "ollama"] = Field(..., description="The provider of the model.")
@@ -7,6 +7,7 @@ from httpx import ConnectError, HTTPStatusError
7
7
  from pydantic import BaseModel, Field
8
8
  from starlette.responses import StreamingResponse
9
9
 
10
+ from letta.constants import DEFAULT_GENERATE_TOOL_MODEL_HANDLE
10
11
  from letta.errors import (
11
12
  LettaInvalidArgumentError,
12
13
  LettaInvalidMCPSchemaError,
@@ -817,7 +818,7 @@ async def generate_tool_from_prompt(
817
818
  Generate a tool from the given user prompt.
818
819
  """
819
820
  actor = await server.user_manager.get_actor_or_default_async(actor_id=headers.actor_id)
820
- llm_config = await server.get_cached_llm_config_async(actor=actor, handle=request.handle or "anthropic/claude-3-5-sonnet-20240620")
821
+ llm_config = await server.get_cached_llm_config_async(actor=actor, handle=request.handle or DEFAULT_GENERATE_TOOL_MODEL_HANDLE)
821
822
  formatted_prompt = (
822
823
  f"Generate a python function named {request.tool_name} using the instructions below "
823
824
  + (f"based on this starter code: \n\n```\n{request.starter_code}\n```\n\n" if request.starter_code else "\n")
letta/server/server.py CHANGED
@@ -414,18 +414,31 @@ class SyncServer(object):
414
414
  actor: User,
415
415
  ) -> AgentState:
416
416
  if request.llm_config is None:
417
+ additional_config_params = {}
417
418
  if request.model is None:
418
419
  if settings.default_llm_handle is None:
419
420
  raise LettaInvalidArgumentError("Must specify either model or llm_config in request", argument_name="model")
420
421
  else:
421
- request.model = settings.default_llm_handle
422
+ handle = settings.default_llm_handle
423
+ else:
424
+ if isinstance(request.model, str):
425
+ handle = request.model
426
+ elif isinstance(request.model, list):
427
+ raise LettaInvalidArgumentError("Multiple models are not supported yet")
428
+ else:
429
+ # EXTREMELEY HACKY, TEMPORARY WORKAROUND
430
+ handle = f"{request.model.provider}/{request.model.model}"
431
+ # TODO: figure out how to override various params
432
+ additional_config_params = request.model._to_legacy_config_params()
433
+
422
434
  config_params = {
423
- "handle": request.model,
435
+ "handle": handle,
424
436
  "context_window_limit": request.context_window_limit,
425
437
  "max_tokens": request.max_tokens,
426
438
  "max_reasoning_tokens": request.max_reasoning_tokens,
427
439
  "enable_reasoner": request.enable_reasoner,
428
440
  }
441
+ config_params.update(additional_config_params)
429
442
  log_event(name="start get_cached_llm_config", attributes=config_params)
430
443
  request.llm_config = await self.get_cached_llm_config_async(actor=actor, **config_params)
431
444
  log_event(name="end get_cached_llm_config", attributes=config_params)
@@ -102,7 +102,10 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
102
102
  function_name=self.tool_name, exception_name=execution.error.name, exception_message=execution.error.value
103
103
  )
104
104
  execution.logs.stderr.append(execution.error.traceback)
105
- logger.info(f"E2B execution failed for ID {e2b_sandbox.sandbox_id}: {self.tool_name}")
105
+ logger.info(
106
+ f"E2B execution failed for ID {e2b_sandbox.sandbox_id}: {self.tool_name} - {execution.error.name}: {execution.error.value}"
107
+ )
108
+ logger.info(f"Traceback from e2b sandbox: \n{execution.error.traceback}")
106
109
  log_event(
107
110
  "e2b_execution_failed",
108
111
  {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: letta-nightly
3
- Version: 0.13.1.dev20251031234110
3
+ Version: 0.13.1.dev20251101010313
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  Author-email: Letta Team <contact@letta.com>
6
6
  License: Apache License
@@ -1,6 +1,6 @@
1
1
  letta/__init__.py,sha256=YlR4nqIpZF60QUQkvQkraiAf38hf-XYQovJcX6p2dvg,1584
2
2
  letta/config.py,sha256=JFGY4TWW0Wm5fTbZamOwWqk5G8Nn-TXyhgByGoAqy2c,12375
3
- letta/constants.py,sha256=XAVJMQ4Vyhhgrz2zwZBXrT-D6NX8J-QaPnQvpfim-dE,17387
3
+ letta/constants.py,sha256=yinedHPbuiMOssZk5fPEAYQi1aufNKp3JPjiHSLExJQ,17492
4
4
  letta/database_utils.py,sha256=D0lIbOkUQDBd2cJL1bmepyrsD5Rl29ZZLMkwnB7z8o0,4492
5
5
  letta/embeddings.py,sha256=d2o1nOVTaofBk6j-WwsE0_ugvxa1nIOcceqGuJ4w_pc,2045
6
6
  letta/errors.py,sha256=NYotz1OUZYFzn0IV6Koe8n3BcVqo0_wSEvQEL8x4LjI,12323
@@ -31,7 +31,7 @@ letta/agents/helpers.py,sha256=p50RU_zXs0Xejiqjc3sSrDgAnoUizwUBieFTicfo4kU,18339
31
31
  letta/agents/letta_agent.py,sha256=SJu7Ydwy8Bb_DYfd08XOXK_d2_uPb9GIV566Eb5cHDI,98308
32
32
  letta/agents/letta_agent_batch.py,sha256=NizNeIHvFtG4XpZCIplOSF8GohwHvNEkAUvsFBSdtSs,27950
33
33
  letta/agents/letta_agent_v2.py,sha256=CDTdlEWVhQj9nxQmXsavmB1e_Crm4UsnWeY0ORLd0-I,60937
34
- letta/agents/letta_agent_v3.py,sha256=Fg_fGcZFLvfXAIAYbkzeuKV5zBZonQRnklAwPyBIPFE,56600
34
+ letta/agents/letta_agent_v3.py,sha256=JuNj_Wfkc8sv6X84LlbOA7H1hsqLqcz_R4JFA7-IC4A,57222
35
35
  letta/agents/voice_agent.py,sha256=4xhg4zU_2kTIC_WHe5cq5XP1JJ_PLmB2qPViq4iFuUI,23299
36
36
  letta/agents/voice_sleeptime_agent.py,sha256=9TyvhrqcmfCJFHQZCoYfkU1S9eRyTnHsFPm4Jq91xaA,8675
37
37
  letta/agents/temporal/constants.py,sha256=toRW2XGGCJVpW0Zeupw4tR4UCgsTrmqAAE5NwY2DPec,2600
@@ -114,7 +114,7 @@ letta/llm_api/bedrock_client.py,sha256=b1N5c7FCUMgrGN-KNZM7QWHE3sdNbQZ806ab5O64I
114
114
  letta/llm_api/deepseek_client.py,sha256=GOW_kHuZRuDmA6EntB6jq-6LIQhsV01T7r8dQg2QytE,17313
115
115
  letta/llm_api/google_ai_client.py,sha256=whFvP8kvPUBNzHGmpVdWGpgeE5pF4G6ziQMrIk57hEQ,7830
116
116
  letta/llm_api/google_constants.py,sha256=eOjOv-FImyJ4b4QGIaod-mEROMtrBFz0yhuYHqOEkwY,797
117
- letta/llm_api/google_vertex_client.py,sha256=t8LT5A_67f-iAgyISvd8u6ynqCaGErqBTaFhtMMFOrs,39585
117
+ letta/llm_api/google_vertex_client.py,sha256=SzOSnESLkiK8_RTEEj0DAqXoyyLf3Pb2bt3D1w0CLXk,39711
118
118
  letta/llm_api/groq_client.py,sha256=-b1LehNEvAzQ5ZjrMaIANrosf-ZxGMbRbpPih82fzz0,3421
119
119
  letta/llm_api/helpers.py,sha256=GVUWBv3N1PYDi1m4GvKykQIcUCJAPjVUmYRC9XHmPTQ,18874
120
120
  letta/llm_api/llm_api_tools.py,sha256=AMF4q-eZsuT9aAkjPJmhiNFTxAEKIHjZZuvhfxQihWA,12747
@@ -168,7 +168,7 @@ letta/local_llm/webui/settings.py,sha256=gmLHfiOl1u4JmlAZU2d2O8YKF9lafdakyjwR_ft
168
168
  letta/openai_backcompat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
169
  letta/openai_backcompat/openai_object.py,sha256=GSzeCTwLpLD2fH4X8wVqzwdmoTjKK2I4PnriBY453lc,13505
170
170
  letta/orm/__init__.py,sha256=ZlnnsQu3PSzpHyGmXsBnHZCfRiiszUkND3G69Ma6fr0,1707
171
- letta/orm/agent.py,sha256=vZoMUyeIX_WfF0E08sUkhJ-rqOtWFO5ccTZ0VSyzg6c,18967
171
+ letta/orm/agent.py,sha256=kWJf5VcHXIknM7CALyGFL5_q5rDVHk545JtkxaWSwL4,19132
172
172
  letta/orm/agents_tags.py,sha256=-rWR8DoEiHM4yc9vAHgHuvjIwgMXMWzKnTKFlBBu3TQ,1076
173
173
  letta/orm/archive.py,sha256=8O8k2gyoMi2EvG0P76WLOz1n1DPLm3VcZJlmKGWeVY8,4143
174
174
  letta/orm/archives_agents.py,sha256=hIhaIRQPuNv-etQVWnIQhEomiumLC1OWR-T_s0Y7snM,1273
@@ -254,7 +254,7 @@ letta/prompts/system_prompts/summary_system_prompt.py,sha256=-jy_PL6Cwxjs3p3AiTR
254
254
  letta/prompts/system_prompts/voice_chat.py,sha256=WLhjlVsVcQPc5S6y5hgw1SdVhdhtflNiwdpfSx3abwk,1871
255
255
  letta/prompts/system_prompts/voice_sleeptime.py,sha256=2rgZYqJEqSp5bcEAXNuqM1PVsvPF1vm8sAqmhoOfQow,3714
256
256
  letta/prompts/system_prompts/workflow.py,sha256=mth_46sY9JWx0rV-kqiGcu2IZGzZQfKY345qBUjvP-s,852
257
- letta/schemas/agent.py,sha256=8CFlsDUELHpFpDMtB3ABOGoH41tzBT_YBM_HvvzyA-Y,24402
257
+ letta/schemas/agent.py,sha256=3GkplXD1sAfkevh4J9KgdFGK-YIvRdIJWhBKiaZFf8o,26681
258
258
  letta/schemas/agent_file.py,sha256=M2NcfC8HQFtZy3CGII3VQ5yqcpCEYTLNXoLxjDbzXKA,15746
259
259
  letta/schemas/archive.py,sha256=cWnncf8HXm2qMoPSbGP3kNn-X-FKfEkew3408OnKt50,2094
260
260
  letta/schemas/block.py,sha256=WzeHzeRpyCAz32zQPaHDO_UGbZZVuOHcj6P41Rc2xvY,9167
@@ -275,12 +275,13 @@ letta/schemas/letta_request.py,sha256=Y7UMuS4m8z9PNDbZY07FRM9WW_TpyPxDsiT-57Ron5
275
275
  letta/schemas/letta_response.py,sha256=2I525MuW3R05sPyfYtFLvuhn6nfdhLrfCwirFFTVc2A,8896
276
276
  letta/schemas/letta_stop_reason.py,sha256=nwqB0oeEDjmDYuN-tF23AKHVEAV3Snjv8NvnW8vS1ZE,1552
277
277
  letta/schemas/llm_batch_job.py,sha256=_WD_maJGsfUQzeDxJC1sbkac4yySbRh-7OZLh85euDE,3191
278
- letta/schemas/llm_config.py,sha256=3aME4W7tnG8Pl5UBRcD2p3Prj0vCdZxlHN4E-4ZqSK4,18019
278
+ letta/schemas/llm_config.py,sha256=d8NvbBzgW0TdxKmpujhaK2O7TCm5QvoEzplC4Cabu38,22109
279
279
  letta/schemas/llm_config_overrides.py,sha256=E6qJuVA8TwAAy3VjGitJ5jSQo5PbN-6VPcZOF5qhP9A,1815
280
280
  letta/schemas/mcp.py,sha256=zCUvOxwuYk2goQ5A7JhYcmVrI7fnGqi_celO-vyKmcw,15282
281
281
  letta/schemas/mcp_server.py,sha256=EKAVV9eEBhuQMPFupZi_9nVxZ5DfU_VzDmUZc4VrROk,15557
282
282
  letta/schemas/memory.py,sha256=VWgSqhhNAqggM7U1-bygDo2uLrm4fM6XRyTXNE1JaiI,20851
283
283
  letta/schemas/message.py,sha256=ZfWCcgW2OOoAO8uDQNO0kRYmjQN3I1fMH9Tswpef26c,91437
284
+ letta/schemas/model.py,sha256=jl0cqqzbu-L3YMPSWeOprqvamD--4hy3Lrx9aPO0134,11527
284
285
  letta/schemas/npm_requirement.py,sha256=HkvBF7KjHUH-MG-RAEYJHO2MLRS2rxFUcmbpbZVznLk,457
285
286
  letta/schemas/organization.py,sha256=VUBG83eRptIDtTuDuDdmIkxfOiQs9vDQRwN04YKA72g,1352
286
287
  letta/schemas/passage.py,sha256=lgIQu6pikQtQzRhaYPRtBvW8ooM4jFPkJWNL-nuK4Pk,4004
@@ -340,7 +341,7 @@ letta/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
340
341
  letta/server/constants.py,sha256=yAdGbLkzlOU_dLTx0lKDmAnj0ZgRXCEaIcPJWO69eaE,92
341
342
  letta/server/db.py,sha256=bh294tLdOQxOrO9jICDrXa_UXTAYFByu_47tPXlKrjs,3006
342
343
  letta/server/generate_openapi_schema.sh,sha256=14Q6r0fbNNVVdf4X3Z-H0ZtyrVw5zYLzL5Doom3kM9k,351
343
- letta/server/server.py,sha256=JkOO1313si2CfuovHEA2WWCji9CRRhmVjvMl8BJUa6I,80281
344
+ letta/server/server.py,sha256=5xyWTgCEa1YW8rWxC-I2iHyVoVqDqr5idDuUcpEu7cs,80948
344
345
  letta/server/startup.sh,sha256=z-Fea-7LiuS_aG1tJqS8JAsDQaamwC_kuDhv9D3PPPY,2698
345
346
  letta/server/utils.py,sha256=rRvW6L1lzau4u9boamiyZH54lf5tQ91ypXzUW9cfSPA,1667
346
347
  letta/server/rest_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -386,7 +387,7 @@ letta/server/rest_api/routers/v1/sources.py,sha256=fAyjOnt9nWh6UHmuka3-rDoen8c3c
386
387
  letta/server/rest_api/routers/v1/steps.py,sha256=-2hL2le0m5a2UrAxk9XomDv51x2LPz_04s7vxD-eslo,7800
387
388
  letta/server/rest_api/routers/v1/tags.py,sha256=rGPO5GaVBn18hu7D3Ysyo45ka47g9DUir3UVh433DEc,1826
388
389
  letta/server/rest_api/routers/v1/telemetry.py,sha256=8rzSii17BK8BjRRfV4Yr6mrKrbZEHySlUaQBGBWhxwY,1124
389
- letta/server/rest_api/routers/v1/tools.py,sha256=CV3RWssZ_xLCjUA9K8Jgv9keKruUtu9lHt-uCGYafYo,38670
390
+ letta/server/rest_api/routers/v1/tools.py,sha256=lkECxbhAlR1Nbh41khc1IoLkAGy3FdKpJdUw-AYqbbU,38729
390
391
  letta/server/rest_api/routers/v1/users.py,sha256=yOEO0uoPlBFnFCpEIKHcAXbllekbI659Q5snGDYaZgg,2012
391
392
  letta/server/rest_api/routers/v1/voice.py,sha256=9rscer9YnFm_UEk6ujUM9Sk9wZNAii-HdO4gpVG9WLE,1714
392
393
  letta/server/static_files/favicon.ico,sha256=DezhLdFSbM8o81wCOZcV3riq7tFUOGQD4h6-vr-HuU0,342
@@ -475,7 +476,7 @@ letta/services/tool_executor/tool_execution_sandbox.py,sha256=mDK8ZrtC-Fe8MY9gmh
475
476
  letta/services/tool_executor/tool_executor_base.py,sha256=1U3Jlfb3uzLOJcMb6jM05axpvO4LFrpKsOMXkiwIUFc,1566
476
477
  letta/services/tool_sandbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
477
478
  letta/services/tool_sandbox/base.py,sha256=3CsViUfv63ot5k0TY-VfGJhUEcsp7GlFlE2my-ySge8,16184
478
- letta/services/tool_sandbox/e2b_sandbox.py,sha256=a2M1Qxj_kCLQBrJ5vWItreJ2phPWT1Cq3j43d3yvo_A,11260
479
+ letta/services/tool_sandbox/e2b_sandbox.py,sha256=48QDy94ftWVIFgW1ZCjfI8xdIHCWsxa2AocX-6hZo5Y,11438
479
480
  letta/services/tool_sandbox/local_sandbox.py,sha256=1WipHjp8f-QZaBYOKnwSc4ccwffeqMXAW0bP0S-7EME,11907
480
481
  letta/services/tool_sandbox/modal_constants.py,sha256=AaXPxSlCj2BhfY5DGwQvqHXfikpurhV2iFsN7zxM3Is,454
481
482
  letta/services/tool_sandbox/modal_deployment_manager.py,sha256=rNDcaHSC3ALA8gAgwAnMG-sbz67zqm6Oa8lgSku0Ah0,9157
@@ -488,8 +489,8 @@ letta/templates/sandbox_code_file.py.j2,sha256=eXga5J_04Z8-pGdwfOCDjcRnMceIqcF5i
488
489
  letta/templates/sandbox_code_file_async.py.j2,sha256=lb7nh_P2W9VZHzU_9TxSCEMUod7SDziPXgvT75xVds0,2748
489
490
  letta/templates/summary_request_text.j2,sha256=ZttQwXonW2lk4pJLYzLK0pmo4EO4EtUUIXjgXKiizuc,842
490
491
  letta/types/__init__.py,sha256=hokKjCVFGEfR7SLMrtZsRsBfsC7yTIbgKPLdGg4K1eY,147
491
- letta_nightly-0.13.1.dev20251031234110.dist-info/METADATA,sha256=WANw67-KRDs7pR_TuUEzaxrwm4uRME_Qba0IbBoYhl0,24544
492
- letta_nightly-0.13.1.dev20251031234110.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
493
- letta_nightly-0.13.1.dev20251031234110.dist-info/entry_points.txt,sha256=m-94Paj-kxiR6Ktu0us0_2qfhn29DzF2oVzqBE6cu8w,41
494
- letta_nightly-0.13.1.dev20251031234110.dist-info/licenses/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
495
- letta_nightly-0.13.1.dev20251031234110.dist-info/RECORD,,
492
+ letta_nightly-0.13.1.dev20251101010313.dist-info/METADATA,sha256=ZITsj59domKh92JEtvcy5vimGKdW9YDVZemDkVizRY4,24544
493
+ letta_nightly-0.13.1.dev20251101010313.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
494
+ letta_nightly-0.13.1.dev20251101010313.dist-info/entry_points.txt,sha256=m-94Paj-kxiR6Ktu0us0_2qfhn29DzF2oVzqBE6cu8w,41
495
+ letta_nightly-0.13.1.dev20251101010313.dist-info/licenses/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
496
+ letta_nightly-0.13.1.dev20251101010313.dist-info/RECORD,,