letta-nightly 0.11.7.dev20251006104136__py3-none-any.whl → 0.11.7.dev20251008104128__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.
Files changed (145) hide show
  1. letta/adapters/letta_llm_adapter.py +1 -0
  2. letta/adapters/letta_llm_request_adapter.py +0 -1
  3. letta/adapters/letta_llm_stream_adapter.py +7 -2
  4. letta/adapters/simple_llm_request_adapter.py +88 -0
  5. letta/adapters/simple_llm_stream_adapter.py +192 -0
  6. letta/agents/agent_loop.py +6 -0
  7. letta/agents/ephemeral_summary_agent.py +2 -1
  8. letta/agents/helpers.py +142 -6
  9. letta/agents/letta_agent.py +13 -33
  10. letta/agents/letta_agent_batch.py +2 -4
  11. letta/agents/letta_agent_v2.py +87 -77
  12. letta/agents/letta_agent_v3.py +899 -0
  13. letta/agents/voice_agent.py +2 -6
  14. letta/constants.py +8 -4
  15. letta/errors.py +40 -0
  16. letta/functions/function_sets/base.py +84 -4
  17. letta/functions/function_sets/multi_agent.py +0 -3
  18. letta/functions/schema_generator.py +113 -71
  19. letta/groups/dynamic_multi_agent.py +3 -2
  20. letta/groups/helpers.py +1 -2
  21. letta/groups/round_robin_multi_agent.py +3 -2
  22. letta/groups/sleeptime_multi_agent.py +3 -2
  23. letta/groups/sleeptime_multi_agent_v2.py +1 -1
  24. letta/groups/sleeptime_multi_agent_v3.py +17 -17
  25. letta/groups/supervisor_multi_agent.py +84 -80
  26. letta/helpers/converters.py +3 -0
  27. letta/helpers/message_helper.py +4 -0
  28. letta/helpers/tool_rule_solver.py +92 -5
  29. letta/interfaces/anthropic_streaming_interface.py +409 -0
  30. letta/interfaces/gemini_streaming_interface.py +296 -0
  31. letta/interfaces/openai_streaming_interface.py +752 -1
  32. letta/llm_api/anthropic_client.py +126 -16
  33. letta/llm_api/bedrock_client.py +4 -2
  34. letta/llm_api/deepseek_client.py +4 -1
  35. letta/llm_api/google_vertex_client.py +123 -42
  36. letta/llm_api/groq_client.py +4 -1
  37. letta/llm_api/llm_api_tools.py +11 -4
  38. letta/llm_api/llm_client_base.py +6 -2
  39. letta/llm_api/openai.py +32 -2
  40. letta/llm_api/openai_client.py +423 -18
  41. letta/llm_api/xai_client.py +4 -1
  42. letta/main.py +9 -5
  43. letta/memory.py +1 -0
  44. letta/orm/__init__.py +1 -1
  45. letta/orm/agent.py +10 -0
  46. letta/orm/block.py +7 -16
  47. letta/orm/blocks_agents.py +8 -2
  48. letta/orm/files_agents.py +2 -0
  49. letta/orm/job.py +7 -5
  50. letta/orm/mcp_oauth.py +1 -0
  51. letta/orm/message.py +21 -6
  52. letta/orm/organization.py +2 -0
  53. letta/orm/provider.py +6 -2
  54. letta/orm/run.py +71 -0
  55. letta/orm/sandbox_config.py +7 -1
  56. letta/orm/sqlalchemy_base.py +0 -306
  57. letta/orm/step.py +6 -5
  58. letta/orm/step_metrics.py +5 -5
  59. letta/otel/tracing.py +28 -3
  60. letta/plugins/defaults.py +4 -4
  61. letta/prompts/system_prompts/__init__.py +2 -0
  62. letta/prompts/system_prompts/letta_v1.py +25 -0
  63. letta/schemas/agent.py +3 -2
  64. letta/schemas/agent_file.py +9 -3
  65. letta/schemas/block.py +23 -10
  66. letta/schemas/enums.py +21 -2
  67. letta/schemas/job.py +17 -4
  68. letta/schemas/letta_message_content.py +71 -2
  69. letta/schemas/letta_stop_reason.py +5 -5
  70. letta/schemas/llm_config.py +53 -3
  71. letta/schemas/memory.py +1 -1
  72. letta/schemas/message.py +504 -117
  73. letta/schemas/openai/responses_request.py +64 -0
  74. letta/schemas/providers/__init__.py +2 -0
  75. letta/schemas/providers/anthropic.py +16 -0
  76. letta/schemas/providers/ollama.py +115 -33
  77. letta/schemas/providers/openrouter.py +52 -0
  78. letta/schemas/providers/vllm.py +2 -1
  79. letta/schemas/run.py +48 -42
  80. letta/schemas/step.py +2 -2
  81. letta/schemas/step_metrics.py +1 -1
  82. letta/schemas/tool.py +15 -107
  83. letta/schemas/tool_rule.py +88 -5
  84. letta/serialize_schemas/marshmallow_agent.py +1 -0
  85. letta/server/db.py +86 -408
  86. letta/server/rest_api/app.py +61 -10
  87. letta/server/rest_api/dependencies.py +14 -0
  88. letta/server/rest_api/redis_stream_manager.py +19 -8
  89. letta/server/rest_api/routers/v1/agents.py +364 -292
  90. letta/server/rest_api/routers/v1/blocks.py +14 -20
  91. letta/server/rest_api/routers/v1/identities.py +45 -110
  92. letta/server/rest_api/routers/v1/internal_templates.py +21 -0
  93. letta/server/rest_api/routers/v1/jobs.py +23 -6
  94. letta/server/rest_api/routers/v1/messages.py +1 -1
  95. letta/server/rest_api/routers/v1/runs.py +126 -85
  96. letta/server/rest_api/routers/v1/sandbox_configs.py +10 -19
  97. letta/server/rest_api/routers/v1/tools.py +281 -594
  98. letta/server/rest_api/routers/v1/voice.py +1 -1
  99. letta/server/rest_api/streaming_response.py +29 -29
  100. letta/server/rest_api/utils.py +122 -64
  101. letta/server/server.py +160 -887
  102. letta/services/agent_manager.py +236 -919
  103. letta/services/agent_serialization_manager.py +16 -0
  104. letta/services/archive_manager.py +0 -100
  105. letta/services/block_manager.py +211 -168
  106. letta/services/file_manager.py +1 -1
  107. letta/services/files_agents_manager.py +24 -33
  108. letta/services/group_manager.py +0 -142
  109. letta/services/helpers/agent_manager_helper.py +7 -2
  110. letta/services/helpers/run_manager_helper.py +85 -0
  111. letta/services/job_manager.py +96 -411
  112. letta/services/lettuce/__init__.py +6 -0
  113. letta/services/lettuce/lettuce_client_base.py +86 -0
  114. letta/services/mcp_manager.py +38 -6
  115. letta/services/message_manager.py +165 -362
  116. letta/services/organization_manager.py +0 -36
  117. letta/services/passage_manager.py +0 -345
  118. letta/services/provider_manager.py +0 -80
  119. letta/services/run_manager.py +301 -0
  120. letta/services/sandbox_config_manager.py +0 -234
  121. letta/services/step_manager.py +62 -39
  122. letta/services/summarizer/summarizer.py +9 -7
  123. letta/services/telemetry_manager.py +0 -16
  124. letta/services/tool_executor/builtin_tool_executor.py +35 -0
  125. letta/services/tool_executor/core_tool_executor.py +397 -2
  126. letta/services/tool_executor/files_tool_executor.py +3 -3
  127. letta/services/tool_executor/multi_agent_tool_executor.py +30 -15
  128. letta/services/tool_executor/tool_execution_manager.py +6 -8
  129. letta/services/tool_executor/tool_executor_base.py +3 -3
  130. letta/services/tool_manager.py +85 -339
  131. letta/services/tool_sandbox/base.py +24 -13
  132. letta/services/tool_sandbox/e2b_sandbox.py +16 -1
  133. letta/services/tool_schema_generator.py +123 -0
  134. letta/services/user_manager.py +0 -99
  135. letta/settings.py +20 -4
  136. {letta_nightly-0.11.7.dev20251006104136.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/METADATA +3 -5
  137. {letta_nightly-0.11.7.dev20251006104136.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/RECORD +140 -132
  138. letta/agents/temporal/activities/__init__.py +0 -4
  139. letta/agents/temporal/activities/example_activity.py +0 -7
  140. letta/agents/temporal/activities/prepare_messages.py +0 -10
  141. letta/agents/temporal/temporal_agent_workflow.py +0 -56
  142. letta/agents/temporal/types.py +0 -25
  143. {letta_nightly-0.11.7.dev20251006104136.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/WHEEL +0 -0
  144. {letta_nightly-0.11.7.dev20251006104136.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/entry_points.txt +0 -0
  145. {letta_nightly-0.11.7.dev20251006104136.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/licenses/LICENSE +0 -0
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  from typing import TYPE_CHECKING, Any, Dict, Optional
2
3
 
3
4
  from e2b.sandbox.commands.command_handle import CommandExitException
@@ -43,6 +44,7 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
43
44
  agent_state: Optional[AgentState] = None,
44
45
  additional_env_vars: Optional[Dict] = None,
45
46
  ) -> ToolExecutionResult:
47
+ await self._init_async()
46
48
  if self.provided_sandbox_config:
47
49
  sbx_config = self.provided_sandbox_config
48
50
  else:
@@ -65,14 +67,24 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
65
67
  code = await self.generate_execution_script(agent_state=agent_state)
66
68
 
67
69
  try:
70
+ logger.info(f"E2B execution started for ID {e2b_sandbox.sandbox_id}: {self.tool_name}")
68
71
  log_event(
69
72
  "e2b_execution_started",
70
73
  {"tool": self.tool_name, "sandbox_id": e2b_sandbox.sandbox_id, "code": code, "env_vars": envs},
71
74
  )
72
- execution = await e2b_sandbox.run_code(code, envs=envs)
75
+ try:
76
+ execution = await e2b_sandbox.run_code(code, envs=envs)
77
+ except asyncio.CancelledError:
78
+ logger.info(f"E2B execution cancelled for ID {e2b_sandbox.sandbox_id}: {self.tool_name}")
79
+ log_event(
80
+ "e2b_execution_cancelled",
81
+ {"tool": self.tool_name, "sandbox_id": e2b_sandbox.sandbox_id},
82
+ )
83
+ raise Exception("Execution cancelled. Transient failure, please retry.")
73
84
 
74
85
  if execution.results:
75
86
  func_return, agent_state = parse_stdout_best_effort(execution.results[0].text)
87
+ logger.info(f"E2B execution succeeded for ID {e2b_sandbox.sandbox_id}: {self.tool_name}")
76
88
  log_event(
77
89
  "e2b_execution_succeeded",
78
90
  {
@@ -90,6 +102,7 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
90
102
  function_name=self.tool_name, exception_name=execution.error.name, exception_message=execution.error.value
91
103
  )
92
104
  execution.logs.stderr.append(execution.error.traceback)
105
+ logger.info(f"E2B execution failed for ID {e2b_sandbox.sandbox_id}: {self.tool_name}")
93
106
  log_event(
94
107
  "e2b_execution_failed",
95
108
  {
@@ -101,6 +114,7 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
101
114
  },
102
115
  )
103
116
  else:
117
+ logger.info(f"E2B execution empty for ID {e2b_sandbox.sandbox_id}: {self.tool_name}")
104
118
  log_event(
105
119
  "e2b_execution_empty",
106
120
  {
@@ -120,6 +134,7 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
120
134
  sandbox_config_fingerprint=sbx_config.fingerprint(),
121
135
  )
122
136
  finally:
137
+ logger.info(f"E2B sandbox {e2b_sandbox.sandbox_id} killed")
123
138
  await e2b_sandbox.kill()
124
139
 
125
140
  @staticmethod
@@ -0,0 +1,123 @@
1
+ """Schema generation utilities for tool creation and updates."""
2
+
3
+ from typing import Optional
4
+
5
+ from letta.functions.ast_parsers import get_function_name_and_docstring
6
+ from letta.functions.functions import derive_openai_json_schema
7
+ from letta.functions.helpers import generate_model_from_args_json_schema
8
+ from letta.functions.schema_generator import generate_schema_from_args_schema_v2
9
+ from letta.log import get_logger
10
+ from letta.schemas.enums import ToolSourceType, ToolType
11
+ from letta.schemas.tool import Tool as PydanticTool
12
+
13
+ logger = get_logger(__name__)
14
+
15
+
16
+ def generate_schema_for_tool_creation(
17
+ tool: PydanticTool,
18
+ ) -> Optional[dict]:
19
+ """
20
+ Generate JSON schema for tool creation based on the provided parameters.
21
+
22
+ Args:
23
+ tool: The tool being created
24
+
25
+ Returns:
26
+ Generated JSON schema or None if not applicable
27
+ """
28
+ # Only generate schema for custom tools
29
+ if tool.tool_type != ToolType.CUSTOM:
30
+ return None
31
+
32
+ # If json_schema is already provided, use it
33
+ if tool.json_schema:
34
+ return tool.json_schema
35
+
36
+ # Must have source code for custom tools
37
+ if not tool.source_code:
38
+ logger.error("Custom tool is missing source_code field")
39
+ raise ValueError("Custom tool is missing source_code field.")
40
+
41
+ # TypeScript tools
42
+ if tool.source_type == ToolSourceType.typescript:
43
+ try:
44
+ from letta.functions.typescript_parser import derive_typescript_json_schema
45
+
46
+ return derive_typescript_json_schema(source_code=tool.source_code)
47
+ except Exception as e:
48
+ logger.error(f"Failed to derive TypeScript json schema: {e}")
49
+ raise ValueError(f"Failed to derive TypeScript json schema: {e}")
50
+
51
+ # Python tools (default if not specified for backwards compatibility)
52
+ elif tool.source_type == ToolSourceType.python or tool.source_type is None:
53
+ # If args_json_schema is provided, use it to generate full schema
54
+ if tool.args_json_schema:
55
+ name, description = get_function_name_and_docstring(tool.source_code, tool.name)
56
+ args_schema = generate_model_from_args_json_schema(tool.args_json_schema)
57
+ return generate_schema_from_args_schema_v2(
58
+ args_schema=args_schema,
59
+ name=name,
60
+ description=description,
61
+ append_heartbeat=False,
62
+ )
63
+ # Otherwise, attempt to parse from docstring with best effort
64
+ else:
65
+ try:
66
+ return derive_openai_json_schema(source_code=tool.source_code)
67
+ except Exception as e:
68
+ logger.error(f"Failed to derive json schema: {e}")
69
+ raise ValueError(f"Failed to derive json schema: {e}")
70
+ else:
71
+ # TODO: convert to explicit error
72
+ raise ValueError(f"Unknown tool source type: {tool.source_type}")
73
+
74
+
75
+ def generate_schema_for_tool_update(
76
+ current_tool: PydanticTool,
77
+ json_schema: Optional[dict] = None,
78
+ args_json_schema: Optional[dict] = None,
79
+ source_code: Optional[str] = None,
80
+ source_type: Optional[ToolSourceType] = None,
81
+ ) -> Optional[dict]:
82
+ """
83
+ Generate JSON schema for tool update based on the provided parameters.
84
+
85
+ Args:
86
+ current_tool: The current tool being updated
87
+ json_schema: Directly provided JSON schema (takes precedence)
88
+ args_json_schema: Schema for just the arguments
89
+ source_code: Updated source code (only used if explicitly updating source)
90
+ source_type: Source type for the tool
91
+
92
+ Returns:
93
+ Updated JSON schema or None if no update needed
94
+ """
95
+ # Only handle custom tools
96
+ if current_tool.tool_type != ToolType.CUSTOM:
97
+ return None
98
+
99
+ # If json_schema is directly provided, use it
100
+ if json_schema is not None:
101
+ # If args_json_schema is also provided, that's an error
102
+ if args_json_schema is not None:
103
+ raise ValueError("Cannot provide both json_schema and args_json_schema in update")
104
+ return json_schema
105
+
106
+ # If args_json_schema is provided, generate full schema from it
107
+ if args_json_schema is not None:
108
+ # Use updated source_code if provided, otherwise use current
109
+ code_to_parse = source_code if source_code is not None else current_tool.source_code
110
+ if not code_to_parse:
111
+ raise ValueError("Source code required when updating with args_json_schema")
112
+
113
+ name, description = get_function_name_and_docstring(code_to_parse, current_tool.name)
114
+ args_schema = generate_model_from_args_json_schema(args_json_schema)
115
+ return generate_schema_from_args_schema_v2(
116
+ args_schema=args_schema,
117
+ name=name,
118
+ description=description,
119
+ append_heartbeat=False,
120
+ )
121
+
122
+ # Otherwise, no schema updates (don't parse docstring)
123
+ return None
@@ -23,27 +23,6 @@ class UserManager:
23
23
  DEFAULT_USER_NAME = "default_user"
24
24
  DEFAULT_USER_ID = "user-00000000-0000-4000-8000-000000000000"
25
25
 
26
- @enforce_types
27
- @trace_method
28
- def create_default_user(self, org_id: str = DEFAULT_ORG_ID) -> PydanticUser:
29
- """Create the default user."""
30
- with db_registry.session() as session:
31
- # Make sure the org id exists
32
- try:
33
- OrganizationModel.read(db_session=session, identifier=org_id)
34
- except NoResultFound:
35
- raise ValueError(f"No organization with {org_id} exists in the organization table.")
36
-
37
- # Try to retrieve the user
38
- try:
39
- user = UserModel.read(db_session=session, identifier=self.DEFAULT_USER_ID)
40
- except NoResultFound:
41
- # If it doesn't exist, make it
42
- user = UserModel(id=self.DEFAULT_USER_ID, name=self.DEFAULT_USER_NAME, organization_id=org_id)
43
- user.create(session)
44
-
45
- return user.to_pydantic()
46
-
47
26
  @enforce_types
48
27
  @trace_method
49
28
  async def create_default_actor_async(self, org_id: str = DEFAULT_ORG_ID) -> PydanticUser:
@@ -66,15 +45,6 @@ class UserManager:
66
45
 
67
46
  return actor.to_pydantic()
68
47
 
69
- @enforce_types
70
- @trace_method
71
- def create_user(self, pydantic_user: PydanticUser) -> PydanticUser:
72
- """Create a new user if it doesn't already exist."""
73
- with db_registry.session() as session:
74
- new_user = UserModel(**pydantic_user.model_dump(to_orm=True))
75
- new_user.create(session)
76
- return new_user.to_pydantic()
77
-
78
48
  @enforce_types
79
49
  @trace_method
80
50
  async def create_actor_async(self, pydantic_user: PydanticUser) -> PydanticUser:
@@ -85,23 +55,6 @@ class UserManager:
85
55
  await self._invalidate_actor_cache(new_user.id)
86
56
  return new_user.to_pydantic()
87
57
 
88
- @enforce_types
89
- @trace_method
90
- def update_user(self, user_update: UserUpdate) -> PydanticUser:
91
- """Update user details."""
92
- with db_registry.session() as session:
93
- # Retrieve the existing user by ID
94
- existing_user = UserModel.read(db_session=session, identifier=user_update.id)
95
-
96
- # Update only the fields that are provided in UserUpdate
97
- update_data = user_update.model_dump(to_orm=True, exclude_unset=True, exclude_none=True)
98
- for key, value in update_data.items():
99
- setattr(existing_user, key, value)
100
-
101
- # Commit the updated user
102
- existing_user.update(session)
103
- return existing_user.to_pydantic()
104
-
105
58
  @enforce_types
106
59
  @trace_method
107
60
  async def update_actor_async(self, user_update: UserUpdate) -> PydanticUser:
@@ -120,17 +73,6 @@ class UserManager:
120
73
  await self._invalidate_actor_cache(user_update.id)
121
74
  return existing_user.to_pydantic()
122
75
 
123
- @enforce_types
124
- @trace_method
125
- def delete_user_by_id(self, user_id: str):
126
- """Delete a user and their associated records (agents, sources, mappings)."""
127
- with db_registry.session() as session:
128
- # Delete from user table
129
- user = UserModel.read(db_session=session, identifier=user_id)
130
- user.hard_delete(session)
131
-
132
- session.commit()
133
-
134
76
  @enforce_types
135
77
  @trace_method
136
78
  async def delete_actor_by_id_async(self, user_id: str):
@@ -141,14 +83,6 @@ class UserManager:
141
83
  await user.hard_delete_async(session)
142
84
  await self._invalidate_actor_cache(user_id)
143
85
 
144
- @enforce_types
145
- @trace_method
146
- def get_user_by_id(self, user_id: str) -> PydanticUser:
147
- """Fetch a user by ID."""
148
- with db_registry.session() as session:
149
- user = UserModel.read(db_session=session, identifier=user_id)
150
- return user.to_pydantic()
151
-
152
86
  @enforce_types
153
87
  @trace_method
154
88
  @async_redis_cache(key_func=lambda self, actor_id: f"actor_id:{actor_id}", model_class=PydanticUser)
@@ -164,27 +98,6 @@ class UserManager:
164
98
 
165
99
  return user.to_pydantic()
166
100
 
167
- @enforce_types
168
- @trace_method
169
- def get_default_user(self) -> PydanticUser:
170
- """Fetch the default user. If it doesn't exist, create it."""
171
- try:
172
- return self.get_user_by_id(self.DEFAULT_USER_ID)
173
- except NoResultFound:
174
- return self.create_default_user()
175
-
176
- @enforce_types
177
- @trace_method
178
- def get_user_or_default(self, user_id: Optional[str] = None):
179
- """Fetch the user or default user."""
180
- if not user_id:
181
- return self.get_default_user()
182
-
183
- try:
184
- return self.get_user_by_id(user_id=user_id)
185
- except NoResultFound:
186
- return self.get_default_user()
187
-
188
101
  @enforce_types
189
102
  @trace_method
190
103
  async def get_default_actor_async(self) -> PydanticUser:
@@ -206,18 +119,6 @@ class UserManager:
206
119
  user = await self.create_default_actor_async(org_id=DEFAULT_ORG_ID)
207
120
  return user
208
121
 
209
- @enforce_types
210
- @trace_method
211
- def list_users(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[PydanticUser]:
212
- """List all users with optional pagination."""
213
- with db_registry.session() as session:
214
- users = UserModel.list(
215
- db_session=session,
216
- after=after,
217
- limit=limit,
218
- )
219
- return [user.to_pydantic() for user in users]
220
-
221
122
  @enforce_types
222
123
  @trace_method
223
124
  async def list_actors_async(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[PydanticUser]:
letta/settings.py CHANGED
@@ -12,8 +12,6 @@ from letta.services.summarizer.enums import SummarizationMode
12
12
 
13
13
 
14
14
  class ToolSettings(BaseSettings):
15
- composio_api_key: str | None = Field(default=None, description="API key for Composio")
16
-
17
15
  # Sandbox Configurations
18
16
  e2b_api_key: str | None = Field(default=None, description="API key for using E2B as a tool sandbox")
19
17
  e2b_sandbox_template_id: str | None = Field(default=None, description="Template ID for E2B Sandbox. Updated Manually.")
@@ -111,6 +109,14 @@ class ModelSettings(BaseSettings):
111
109
  validation_alias=AliasChoices("OPENAI_BASE_URL", "OPENAI_API_BASE"), # pydantic-settings v1
112
110
  )
113
111
 
112
+ # openrouter
113
+ openrouter_api_key: Optional[str] = None
114
+ # Optional additional headers recommended by OpenRouter
115
+ # See https://openrouter.ai/docs/quick-start for details
116
+ openrouter_referer: Optional[str] = None # e.g., your site URL
117
+ openrouter_title: Optional[str] = None # e.g., your app name
118
+ openrouter_handle_base: Optional[str] = None
119
+
114
120
  # deepseek
115
121
  deepseek_api_key: Optional[str] = None
116
122
 
@@ -129,6 +135,16 @@ class ModelSettings(BaseSettings):
129
135
  # anthropic
130
136
  anthropic_api_key: Optional[str] = None
131
137
  anthropic_max_retries: int = 3
138
+ anthropic_sonnet_1m: bool = Field(
139
+ default=False,
140
+ description=(
141
+ "Enable 1M-token context window for Claude Sonnet 4/4.5. When true, adds the"
142
+ " 'context-1m-2025-08-07' beta to Anthropic requests and sets model context_window"
143
+ " to 1,000,000 instead of 200,000. Note: This feature is in beta and not available"
144
+ " to all orgs; once GA, this flag can be removed and behavior can default to on."
145
+ ),
146
+ alias="ANTHROPIC_SONNET_1M",
147
+ )
132
148
 
133
149
  # ollama
134
150
  ollama_base_url: Optional[str] = None
@@ -156,6 +172,7 @@ class ModelSettings(BaseSettings):
156
172
 
157
173
  # vLLM
158
174
  vllm_api_base: Optional[str] = None
175
+ vllm_handle_base: Optional[str] = None
159
176
 
160
177
  # lmstudio
161
178
  lmstudio_base_url: Optional[str] = None
@@ -232,7 +249,7 @@ class Settings(BaseSettings):
232
249
  pg_echo: bool = False # Logging
233
250
  pool_pre_ping: bool = True # Pre ping to check for dead connections
234
251
  pool_use_lifo: bool = True
235
- disable_sqlalchemy_pooling: bool = False
252
+ disable_sqlalchemy_pooling: bool = True
236
253
  db_max_concurrent_sessions: Optional[int] = None
237
254
 
238
255
  redis_host: Optional[str] = Field(default=None, description="Host for Redis instance")
@@ -271,7 +288,6 @@ class Settings(BaseSettings):
271
288
  event_loop_threadpool_max_workers: int = 43
272
289
 
273
290
  # experimental toggle
274
- use_experimental: bool = False
275
291
  use_vertex_structured_outputs_experimental: bool = False
276
292
  use_asyncio_shield: bool = True
277
293
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: letta-nightly
3
- Version: 0.11.7.dev20251006104136
3
+ Version: 0.11.7.dev20251008104128
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
@@ -14,12 +14,12 @@ Requires-Dist: black[jupyter]>=24.2.0
14
14
  Requires-Dist: brotli>=1.1.0
15
15
  Requires-Dist: certifi>=2025.6.15
16
16
  Requires-Dist: colorama>=0.4.6
17
- Requires-Dist: composio-core>=0.7.7
18
17
  Requires-Dist: datamodel-code-generator[http]>=0.25.0
19
18
  Requires-Dist: demjson3>=3.0.6
20
19
  Requires-Dist: docstring-parser<0.17,>=0.16
21
20
  Requires-Dist: exa-py>=1.15.4
22
21
  Requires-Dist: faker>=36.1.0
22
+ Requires-Dist: google-genai>=1.15.0
23
23
  Requires-Dist: grpcio-tools>=1.68.1
24
24
  Requires-Dist: grpcio>=1.68.1
25
25
  Requires-Dist: html2text>=2020.1.16
@@ -109,8 +109,6 @@ Requires-Dist: langchain-community>=0.3.7; extra == 'external-tools'
109
109
  Requires-Dist: langchain>=0.3.7; extra == 'external-tools'
110
110
  Requires-Dist: turbopuffer>=0.5.17; extra == 'external-tools'
111
111
  Requires-Dist: wikipedia>=1.4.0; extra == 'external-tools'
112
- Provides-Extra: google
113
- Requires-Dist: google-genai>=1.15.0; extra == 'google'
114
112
  Provides-Extra: modal
115
113
  Requires-Dist: modal>=1.1.0; extra == 'modal'
116
114
  Provides-Extra: pinecone
@@ -417,7 +415,7 @@ agent_state = client.agents.create(
417
415
 
418
416
  # Or attach tools to an existing agent
419
417
  client.agents.tool.attach(
420
- agent_id=agent_state.id,
418
+ agent_id=agent_state.id
421
419
  tool_id=tool.id
422
420
  )
423
421