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.
- letta/agents/letta_agent_v3.py +7 -0
- letta/constants.py +3 -0
- letta/llm_api/google_vertex_client.py +4 -4
- letta/orm/agent.py +3 -0
- letta/schemas/agent.py +108 -40
- letta/schemas/llm_config.py +96 -1
- letta/schemas/model.py +265 -0
- letta/server/rest_api/routers/v1/tools.py +2 -1
- letta/server/server.py +15 -2
- letta/services/tool_sandbox/e2b_sandbox.py +4 -1
- {letta_nightly-0.13.1.dev20251031234110.dist-info → letta_nightly-0.13.1.dev20251101010313.dist-info}/METADATA +1 -1
- {letta_nightly-0.13.1.dev20251031234110.dist-info → letta_nightly-0.13.1.dev20251101010313.dist-info}/RECORD +15 -14
- {letta_nightly-0.13.1.dev20251031234110.dist-info → letta_nightly-0.13.1.dev20251101010313.dist-info}/WHEEL +0 -0
- {letta_nightly-0.13.1.dev20251031234110.dist-info → letta_nightly-0.13.1.dev20251101010313.dist-info}/entry_points.txt +0 -0
- {letta_nightly-0.13.1.dev20251031234110.dist-info → letta_nightly-0.13.1.dev20251101010313.dist-info}/licenses/LICENSE +0 -0
letta/agents/letta_agent_v3.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
91
|
-
llm_config: LLMConfig = Field(
|
|
92
|
-
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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(
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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
|
|
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(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
|
|
422
|
+
|
|
423
|
+
# model configuration
|
|
424
|
+
model: Optional[str | ModelSettings] = Field(
|
|
374
425
|
None,
|
|
375
|
-
description="The
|
|
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.
|
|
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
|
-
|
|
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
|
|
letta/schemas/llm_config.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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":
|
|
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(
|
|
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
|
letta/__init__.py,sha256=YlR4nqIpZF60QUQkvQkraiAf38hf-XYQovJcX6p2dvg,1584
|
|
2
2
|
letta/config.py,sha256=JFGY4TWW0Wm5fTbZamOwWqk5G8Nn-TXyhgByGoAqy2c,12375
|
|
3
|
-
letta/constants.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
492
|
-
letta_nightly-0.13.1.
|
|
493
|
-
letta_nightly-0.13.1.
|
|
494
|
-
letta_nightly-0.13.1.
|
|
495
|
-
letta_nightly-0.13.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|