letta-nightly 0.8.17.dev20250723104501__py3-none-any.whl → 0.9.0.dev20250724104456__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 (96) hide show
  1. letta/__init__.py +5 -3
  2. letta/agent.py +3 -2
  3. letta/agents/base_agent.py +4 -1
  4. letta/agents/voice_agent.py +1 -0
  5. letta/constants.py +4 -2
  6. letta/functions/schema_generator.py +2 -1
  7. letta/groups/dynamic_multi_agent.py +1 -0
  8. letta/helpers/converters.py +13 -5
  9. letta/helpers/json_helpers.py +6 -1
  10. letta/llm_api/anthropic.py +2 -2
  11. letta/llm_api/aws_bedrock.py +24 -94
  12. letta/llm_api/deepseek.py +1 -1
  13. letta/llm_api/google_ai_client.py +0 -38
  14. letta/llm_api/google_constants.py +6 -3
  15. letta/llm_api/helpers.py +1 -1
  16. letta/llm_api/llm_api_tools.py +4 -7
  17. letta/llm_api/mistral.py +12 -37
  18. letta/llm_api/openai.py +17 -17
  19. letta/llm_api/sample_response_jsons/aws_bedrock.json +38 -0
  20. letta/llm_api/sample_response_jsons/lmstudio_embedding_list.json +15 -0
  21. letta/llm_api/sample_response_jsons/lmstudio_model_list.json +15 -0
  22. letta/local_llm/constants.py +2 -23
  23. letta/local_llm/json_parser.py +11 -1
  24. letta/local_llm/llm_chat_completion_wrappers/airoboros.py +9 -9
  25. letta/local_llm/llm_chat_completion_wrappers/chatml.py +7 -8
  26. letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +6 -6
  27. letta/local_llm/llm_chat_completion_wrappers/dolphin.py +3 -3
  28. letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +1 -1
  29. letta/local_llm/ollama/api.py +2 -2
  30. letta/orm/__init__.py +1 -0
  31. letta/orm/agent.py +33 -2
  32. letta/orm/files_agents.py +13 -10
  33. letta/orm/mixins.py +8 -0
  34. letta/orm/prompt.py +13 -0
  35. letta/orm/sqlite_functions.py +61 -17
  36. letta/otel/db_pool_monitoring.py +13 -12
  37. letta/schemas/agent.py +69 -4
  38. letta/schemas/agent_file.py +2 -0
  39. letta/schemas/block.py +11 -0
  40. letta/schemas/embedding_config.py +15 -3
  41. letta/schemas/enums.py +2 -0
  42. letta/schemas/file.py +1 -1
  43. letta/schemas/folder.py +74 -0
  44. letta/schemas/memory.py +12 -6
  45. letta/schemas/prompt.py +9 -0
  46. letta/schemas/providers/__init__.py +47 -0
  47. letta/schemas/providers/anthropic.py +78 -0
  48. letta/schemas/providers/azure.py +80 -0
  49. letta/schemas/providers/base.py +201 -0
  50. letta/schemas/providers/bedrock.py +78 -0
  51. letta/schemas/providers/cerebras.py +79 -0
  52. letta/schemas/providers/cohere.py +18 -0
  53. letta/schemas/providers/deepseek.py +63 -0
  54. letta/schemas/providers/google_gemini.py +102 -0
  55. letta/schemas/providers/google_vertex.py +54 -0
  56. letta/schemas/providers/groq.py +35 -0
  57. letta/schemas/providers/letta.py +39 -0
  58. letta/schemas/providers/lmstudio.py +97 -0
  59. letta/schemas/providers/mistral.py +41 -0
  60. letta/schemas/providers/ollama.py +151 -0
  61. letta/schemas/providers/openai.py +241 -0
  62. letta/schemas/providers/together.py +85 -0
  63. letta/schemas/providers/vllm.py +57 -0
  64. letta/schemas/providers/xai.py +66 -0
  65. letta/server/db.py +0 -5
  66. letta/server/rest_api/app.py +4 -3
  67. letta/server/rest_api/routers/v1/__init__.py +2 -0
  68. letta/server/rest_api/routers/v1/agents.py +152 -4
  69. letta/server/rest_api/routers/v1/folders.py +490 -0
  70. letta/server/rest_api/routers/v1/providers.py +2 -2
  71. letta/server/rest_api/routers/v1/sources.py +21 -26
  72. letta/server/rest_api/routers/v1/tools.py +90 -15
  73. letta/server/server.py +50 -95
  74. letta/services/agent_manager.py +420 -81
  75. letta/services/agent_serialization_manager.py +707 -0
  76. letta/services/block_manager.py +132 -11
  77. letta/services/file_manager.py +104 -29
  78. letta/services/file_processor/embedder/pinecone_embedder.py +8 -2
  79. letta/services/file_processor/file_processor.py +75 -24
  80. letta/services/file_processor/parser/markitdown_parser.py +95 -0
  81. letta/services/files_agents_manager.py +57 -17
  82. letta/services/group_manager.py +7 -0
  83. letta/services/helpers/agent_manager_helper.py +25 -15
  84. letta/services/provider_manager.py +2 -2
  85. letta/services/source_manager.py +35 -16
  86. letta/services/tool_executor/files_tool_executor.py +12 -5
  87. letta/services/tool_manager.py +12 -0
  88. letta/services/tool_sandbox/e2b_sandbox.py +52 -48
  89. letta/settings.py +9 -6
  90. letta/streaming_utils.py +2 -1
  91. letta/utils.py +34 -1
  92. {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/METADATA +9 -8
  93. {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/RECORD +96 -68
  94. {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/LICENSE +0 -0
  95. {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/WHEEL +0 -0
  96. {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/entry_points.txt +0 -0
@@ -94,57 +94,61 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
94
94
  env_vars.update(additional_env_vars)
95
95
  code = self.generate_execution_script(agent_state=agent_state)
96
96
 
97
- log_event(
98
- "e2b_execution_started",
99
- {"tool": self.tool_name, "sandbox_id": e2b_sandbox.sandbox_id, "code": code, "env_vars": env_vars},
100
- )
101
- execution = await e2b_sandbox.run_code(code, envs=env_vars)
102
- if execution.results:
103
- func_return, agent_state = parse_stdout_best_effort(execution.results[0].text)
104
- log_event(
105
- "e2b_execution_succeeded",
106
- {
107
- "tool": self.tool_name,
108
- "sandbox_id": e2b_sandbox.sandbox_id,
109
- "func_return": func_return,
110
- },
111
- )
112
- elif execution.error:
113
- logger.error(f"Executing tool {self.tool_name} raised a {execution.error.name} with message: \n{execution.error.value}")
114
- logger.error(f"Traceback from e2b sandbox: \n{execution.error.traceback}")
115
- func_return = get_friendly_error_msg(
116
- function_name=self.tool_name, exception_name=execution.error.name, exception_message=execution.error.value
117
- )
118
- execution.logs.stderr.append(execution.error.traceback)
119
- log_event(
120
- "e2b_execution_failed",
121
- {
122
- "tool": self.tool_name,
123
- "sandbox_id": e2b_sandbox.sandbox_id,
124
- "error_type": execution.error.name,
125
- "error_message": execution.error.value,
126
- "func_return": func_return,
127
- },
128
- )
129
- else:
97
+ try:
130
98
  log_event(
131
- "e2b_execution_empty",
132
- {
133
- "tool": self.tool_name,
134
- "sandbox_id": e2b_sandbox.sandbox_id,
135
- "status": "no_results_no_error",
136
- },
99
+ "e2b_execution_started",
100
+ {"tool": self.tool_name, "sandbox_id": e2b_sandbox.sandbox_id, "code": code, "env_vars": env_vars},
137
101
  )
138
- raise ValueError(f"Tool {self.tool_name} returned execution with None")
102
+ execution = await e2b_sandbox.run_code(code, envs=env_vars)
139
103
 
140
- return ToolExecutionResult(
141
- func_return=func_return,
142
- agent_state=agent_state,
143
- stdout=execution.logs.stdout,
144
- stderr=execution.logs.stderr,
145
- status="error" if execution.error else "success",
146
- sandbox_config_fingerprint=sbx_config.fingerprint(),
147
- )
104
+ if execution.results:
105
+ func_return, agent_state = parse_stdout_best_effort(execution.results[0].text)
106
+ log_event(
107
+ "e2b_execution_succeeded",
108
+ {
109
+ "tool": self.tool_name,
110
+ "sandbox_id": e2b_sandbox.sandbox_id,
111
+ "func_return": func_return,
112
+ },
113
+ )
114
+ elif execution.error:
115
+ logger.error(f"Executing tool {self.tool_name} raised a {execution.error.name} with message: \n{execution.error.value}")
116
+ logger.error(f"Traceback from e2b sandbox: \n{execution.error.traceback}")
117
+ func_return = get_friendly_error_msg(
118
+ function_name=self.tool_name, exception_name=execution.error.name, exception_message=execution.error.value
119
+ )
120
+ execution.logs.stderr.append(execution.error.traceback)
121
+ log_event(
122
+ "e2b_execution_failed",
123
+ {
124
+ "tool": self.tool_name,
125
+ "sandbox_id": e2b_sandbox.sandbox_id,
126
+ "error_type": execution.error.name,
127
+ "error_message": execution.error.value,
128
+ "func_return": func_return,
129
+ },
130
+ )
131
+ else:
132
+ log_event(
133
+ "e2b_execution_empty",
134
+ {
135
+ "tool": self.tool_name,
136
+ "sandbox_id": e2b_sandbox.sandbox_id,
137
+ "status": "no_results_no_error",
138
+ },
139
+ )
140
+ raise ValueError(f"Tool {self.tool_name} returned execution with None")
141
+
142
+ return ToolExecutionResult(
143
+ func_return=func_return,
144
+ agent_state=agent_state,
145
+ stdout=execution.logs.stdout,
146
+ stderr=execution.logs.stderr,
147
+ status="error" if execution.error else "success",
148
+ sandbox_config_fingerprint=sbx_config.fingerprint(),
149
+ )
150
+ finally:
151
+ await e2b_sandbox.kill()
148
152
 
149
153
  @staticmethod
150
154
  def parse_exception_from_e2b_execution(e2b_execution: "Execution") -> Exception:
letta/settings.py CHANGED
@@ -6,7 +6,7 @@ from typing import Optional
6
6
  from pydantic import AliasChoices, Field
7
7
  from pydantic_settings import BaseSettings, SettingsConfigDict
8
8
 
9
- from letta.local_llm.constants import DEFAULT_WRAPPER_NAME
9
+ from letta.local_llm.constants import DEFAULT_WRAPPER_NAME, INNER_THOUGHTS_KWARG
10
10
  from letta.services.summarizer.enums import SummarizationMode
11
11
 
12
12
 
@@ -83,6 +83,8 @@ class ModelSettings(BaseSettings):
83
83
 
84
84
  global_max_context_window_limit: int = 32000
85
85
 
86
+ inner_thoughts_kwarg: str | None = Field(default=INNER_THOUGHTS_KWARG, description="Key used for passing in inner thoughts.")
87
+
86
88
  # env_prefix='my_prefix_'
87
89
 
88
90
  # when we use /completions APIs (instead of /chat/completions), we need to specify a model wrapper
@@ -150,9 +152,6 @@ class ModelSettings(BaseSettings):
150
152
  openllm_auth_type: Optional[str] = None
151
153
  openllm_api_key: Optional[str] = None
152
154
 
153
- # disable openapi schema generation
154
- disable_schema_generation: bool = False
155
-
156
155
 
157
156
  env_cors_origins = os.getenv("ACCEPTABLE_ORIGINS")
158
157
 
@@ -316,12 +315,16 @@ class Settings(BaseSettings):
316
315
  class TestSettings(Settings):
317
316
  model_config = SettingsConfigDict(env_prefix="letta_test_", extra="ignore")
318
317
 
319
- letta_dir: Optional[Path] = Field(Path.home() / ".letta/test", env="LETTA_TEST_DIR")
318
+ letta_dir: Path | None = Field(Path.home() / ".letta/test", env="LETTA_TEST_DIR")
320
319
 
321
320
 
322
321
  class LogSettings(BaseSettings):
323
322
  model_config = SettingsConfigDict(env_prefix="letta_logging_", extra="ignore")
324
- verbose_telemetry_logging: bool = False
323
+ debug: bool | None = Field(False, description="Enable debugging for logging")
324
+ json_logging: bool = Field(False, description="Enable json logging instead of text logging")
325
+ log_level: str | None = Field("WARNING", description="Logging level")
326
+ letta_log_path: Path | None = Field(Path.home() / ".letta" / "logs" / "Letta.log")
327
+ verbose_telemetry_logging: bool = Field(False)
325
328
 
326
329
 
327
330
  # singleton
letta/streaming_utils.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from typing import Optional, Tuple
2
2
 
3
3
  from letta.constants import DEFAULT_MESSAGE_TOOL_KWARG
4
+ from letta.local_llm.constants import INNER_THOUGHTS_KWARG
4
5
 
5
6
 
6
7
  class JSONInnerThoughtsExtractor:
@@ -34,7 +35,7 @@ class JSONInnerThoughtsExtractor:
34
35
 
35
36
  """
36
37
 
37
- def __init__(self, inner_thoughts_key="inner_thoughts", wait_for_first_key=False):
38
+ def __init__(self, inner_thoughts_key=INNER_THOUGHTS_KWARG, wait_for_first_key=False):
38
39
  self.inner_thoughts_key = inner_thoughts_key
39
40
  self.wait_for_first_key = wait_for_first_key
40
41
  self.main_buffer = ""
letta/utils.py CHANGED
@@ -17,7 +17,7 @@ from contextlib import contextmanager
17
17
  from datetime import datetime, timezone
18
18
  from functools import wraps
19
19
  from logging import Logger
20
- from typing import Any, Coroutine, Union, _GenericAlias, get_args, get_origin, get_type_hints
20
+ from typing import Any, Coroutine, Optional, Union, _GenericAlias, get_args, get_origin, get_type_hints
21
21
  from urllib.parse import urljoin, urlparse
22
22
 
23
23
  import demjson3 as demjson
@@ -30,6 +30,8 @@ from letta.constants import (
30
30
  CLI_WARNING_PREFIX,
31
31
  CORE_MEMORY_HUMAN_CHAR_LIMIT,
32
32
  CORE_MEMORY_PERSONA_CHAR_LIMIT,
33
+ DEFAULT_CORE_MEMORY_SOURCE_CHAR_LIMIT,
34
+ DEFAULT_MAX_FILES_OPEN,
33
35
  ERROR_MESSAGE_PREFIX,
34
36
  LETTA_DIR,
35
37
  MAX_FILENAME_LENGTH,
@@ -1206,3 +1208,34 @@ async def get_latest_alembic_revision() -> str:
1206
1208
  except Exception as e:
1207
1209
  logger.error(f"Error getting latest alembic revision: {e}")
1208
1210
  return "unknown"
1211
+
1212
+
1213
+ def calculate_file_defaults_based_on_context_window(context_window: Optional[int]) -> tuple[int, int]:
1214
+ """Calculate reasonable defaults for max_files_open and per_file_view_window_char_limit
1215
+ based on the model's context window size.
1216
+
1217
+ Args:
1218
+ context_window: The context window size of the model. If None, returns conservative defaults.
1219
+
1220
+ Returns:
1221
+ A tuple of (max_files_open, per_file_view_window_char_limit)
1222
+ """
1223
+ if not context_window:
1224
+ # If no context window info, use conservative defaults
1225
+ return DEFAULT_MAX_FILES_OPEN, DEFAULT_CORE_MEMORY_SOURCE_CHAR_LIMIT
1226
+
1227
+ # Define defaults based on context window ranges
1228
+ # Assuming ~4 chars per token
1229
+ # Available chars = available_tokens * 4
1230
+
1231
+ # TODO: Check my math here
1232
+ if context_window <= 8_000: # Small models (4K-8K)
1233
+ return 3, 5_000 # ~3.75K tokens
1234
+ elif context_window <= 32_000: # Medium models (16K-32K)
1235
+ return 5, 15_000 # ~18.75K tokens
1236
+ elif context_window <= 128_000: # Large models (100K-128K)
1237
+ return 10, 25_000 # ~62.5K tokens
1238
+ elif context_window <= 200_000: # Very large models (128K-200K)
1239
+ return 10, 50_000 # ~128k tokens
1240
+ else: # Extremely large models (200K+)
1241
+ return 15, 50_000 # ~187.5k tokens
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: letta-nightly
3
- Version: 0.8.17.dev20250723104501
3
+ Version: 0.9.0.dev20250724104456
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
@@ -56,16 +56,17 @@ Requires-Dist: isort (>=5.13.2,<6.0.0) ; extra == "dev" or extra == "all"
56
56
  Requires-Dist: jinja2 (>=3.1.5,<4.0.0)
57
57
  Requires-Dist: langchain (>=0.3.7,<0.4.0) ; extra == "external-tools" or extra == "desktop" or extra == "all"
58
58
  Requires-Dist: langchain-community (>=0.3.7,<0.4.0) ; extra == "external-tools" or extra == "desktop" or extra == "all"
59
- Requires-Dist: letta_client (>=0.1.197,<0.2.0)
59
+ Requires-Dist: letta_client (>=0.1.219,<0.2.0)
60
60
  Requires-Dist: llama-index (>=0.12.2,<0.13.0)
61
61
  Requires-Dist: llama-index-embeddings-openai (>=0.3.1,<0.4.0)
62
62
  Requires-Dist: locust (>=2.31.5,<3.0.0) ; extra == "dev" or extra == "desktop" or extra == "all"
63
+ Requires-Dist: markitdown[docx,pdf,pptx] (>=0.1.2,<0.2.0)
63
64
  Requires-Dist: marshmallow-sqlalchemy (>=1.4.1,<2.0.0)
64
65
  Requires-Dist: matplotlib (>=3.10.1,<4.0.0)
65
66
  Requires-Dist: mcp[cli] (>=1.9.4,<2.0.0)
66
67
  Requires-Dist: mistralai (>=1.8.1,<2.0.0)
67
68
  Requires-Dist: nltk (>=3.8.1,<4.0.0)
68
- Requires-Dist: numpy (>=1.26.2,<2.0.0)
69
+ Requires-Dist: numpy (>=2.1.0,<3.0.0)
69
70
  Requires-Dist: openai (>=1.60.0,<2.0.0)
70
71
  Requires-Dist: opentelemetry-api (==1.30.0)
71
72
  Requires-Dist: opentelemetry-exporter-otlp (==1.30.0)
@@ -74,13 +75,13 @@ Requires-Dist: opentelemetry-instrumentation-sqlalchemy (==0.51b0)
74
75
  Requires-Dist: opentelemetry-sdk (==1.30.0)
75
76
  Requires-Dist: pathvalidate (>=3.2.1,<4.0.0)
76
77
  Requires-Dist: pexpect (>=4.9.0,<5.0.0) ; extra == "dev" or extra == "all"
77
- Requires-Dist: pg8000 (>=1.30.3,<2.0.0) ; extra == "postgres" or extra == "desktop" or extra == "all"
78
- Requires-Dist: pgvector (>=0.2.3,<0.3.0) ; extra == "postgres" or extra == "desktop" or extra == "all"
78
+ Requires-Dist: pg8000 (>=1.30.3,<2.0.0) ; extra == "postgres" or extra == "all"
79
+ Requires-Dist: pgvector (>=0.2.3,<0.3.0) ; extra == "postgres" or extra == "all"
79
80
  Requires-Dist: pinecone[asyncio] (>=7.3.0,<8.0.0) ; extra == "pinecone" or extra == "all"
80
81
  Requires-Dist: pre-commit (>=3.5.0,<4.0.0) ; extra == "dev" or extra == "all"
81
82
  Requires-Dist: prettytable (>=3.9.0,<4.0.0)
82
- Requires-Dist: psycopg2 (>=2.9.10,<3.0.0) ; extra == "postgres" or extra == "desktop" or extra == "all"
83
- Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0) ; extra == "postgres" or extra == "desktop" or extra == "all"
83
+ Requires-Dist: psycopg2 (>=2.9.10,<3.0.0) ; extra == "postgres" or extra == "all"
84
+ Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0) ; extra == "postgres" or extra == "all"
84
85
  Requires-Dist: pydantic (>=2.10.6,<3.0.0)
85
86
  Requires-Dist: pydantic-settings (>=2.2.1,<3.0.0)
86
87
  Requires-Dist: pyhumps (>=3.8.0,<4.0.0)
@@ -105,7 +106,7 @@ Requires-Dist: tavily-python (>=0.7.2,<0.8.0)
105
106
  Requires-Dist: tqdm (>=4.66.1,<5.0.0)
106
107
  Requires-Dist: typer (>=0.15.2,<0.16.0)
107
108
  Requires-Dist: uvicorn (>=0.24.0.post1,<0.25.0) ; extra == "server" or extra == "desktop" or extra == "all"
108
- Requires-Dist: uvloop (>=0.21.0,<0.22.0) ; extra == "all"
109
+ Requires-Dist: uvloop (>=0.21.0,<0.22.0) ; extra == "experimental" or extra == "all"
109
110
  Requires-Dist: wikipedia (>=1.4.0,<2.0.0) ; extra == "external-tools" or extra == "tests" or extra == "desktop" or extra == "all"
110
111
  Description-Content-Type: text/markdown
111
112