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.
- letta/__init__.py +5 -3
- letta/agent.py +3 -2
- letta/agents/base_agent.py +4 -1
- letta/agents/voice_agent.py +1 -0
- letta/constants.py +4 -2
- letta/functions/schema_generator.py +2 -1
- letta/groups/dynamic_multi_agent.py +1 -0
- letta/helpers/converters.py +13 -5
- letta/helpers/json_helpers.py +6 -1
- letta/llm_api/anthropic.py +2 -2
- letta/llm_api/aws_bedrock.py +24 -94
- letta/llm_api/deepseek.py +1 -1
- letta/llm_api/google_ai_client.py +0 -38
- letta/llm_api/google_constants.py +6 -3
- letta/llm_api/helpers.py +1 -1
- letta/llm_api/llm_api_tools.py +4 -7
- letta/llm_api/mistral.py +12 -37
- letta/llm_api/openai.py +17 -17
- letta/llm_api/sample_response_jsons/aws_bedrock.json +38 -0
- letta/llm_api/sample_response_jsons/lmstudio_embedding_list.json +15 -0
- letta/llm_api/sample_response_jsons/lmstudio_model_list.json +15 -0
- letta/local_llm/constants.py +2 -23
- letta/local_llm/json_parser.py +11 -1
- letta/local_llm/llm_chat_completion_wrappers/airoboros.py +9 -9
- letta/local_llm/llm_chat_completion_wrappers/chatml.py +7 -8
- letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +6 -6
- letta/local_llm/llm_chat_completion_wrappers/dolphin.py +3 -3
- letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +1 -1
- letta/local_llm/ollama/api.py +2 -2
- letta/orm/__init__.py +1 -0
- letta/orm/agent.py +33 -2
- letta/orm/files_agents.py +13 -10
- letta/orm/mixins.py +8 -0
- letta/orm/prompt.py +13 -0
- letta/orm/sqlite_functions.py +61 -17
- letta/otel/db_pool_monitoring.py +13 -12
- letta/schemas/agent.py +69 -4
- letta/schemas/agent_file.py +2 -0
- letta/schemas/block.py +11 -0
- letta/schemas/embedding_config.py +15 -3
- letta/schemas/enums.py +2 -0
- letta/schemas/file.py +1 -1
- letta/schemas/folder.py +74 -0
- letta/schemas/memory.py +12 -6
- letta/schemas/prompt.py +9 -0
- letta/schemas/providers/__init__.py +47 -0
- letta/schemas/providers/anthropic.py +78 -0
- letta/schemas/providers/azure.py +80 -0
- letta/schemas/providers/base.py +201 -0
- letta/schemas/providers/bedrock.py +78 -0
- letta/schemas/providers/cerebras.py +79 -0
- letta/schemas/providers/cohere.py +18 -0
- letta/schemas/providers/deepseek.py +63 -0
- letta/schemas/providers/google_gemini.py +102 -0
- letta/schemas/providers/google_vertex.py +54 -0
- letta/schemas/providers/groq.py +35 -0
- letta/schemas/providers/letta.py +39 -0
- letta/schemas/providers/lmstudio.py +97 -0
- letta/schemas/providers/mistral.py +41 -0
- letta/schemas/providers/ollama.py +151 -0
- letta/schemas/providers/openai.py +241 -0
- letta/schemas/providers/together.py +85 -0
- letta/schemas/providers/vllm.py +57 -0
- letta/schemas/providers/xai.py +66 -0
- letta/server/db.py +0 -5
- letta/server/rest_api/app.py +4 -3
- letta/server/rest_api/routers/v1/__init__.py +2 -0
- letta/server/rest_api/routers/v1/agents.py +152 -4
- letta/server/rest_api/routers/v1/folders.py +490 -0
- letta/server/rest_api/routers/v1/providers.py +2 -2
- letta/server/rest_api/routers/v1/sources.py +21 -26
- letta/server/rest_api/routers/v1/tools.py +90 -15
- letta/server/server.py +50 -95
- letta/services/agent_manager.py +420 -81
- letta/services/agent_serialization_manager.py +707 -0
- letta/services/block_manager.py +132 -11
- letta/services/file_manager.py +104 -29
- letta/services/file_processor/embedder/pinecone_embedder.py +8 -2
- letta/services/file_processor/file_processor.py +75 -24
- letta/services/file_processor/parser/markitdown_parser.py +95 -0
- letta/services/files_agents_manager.py +57 -17
- letta/services/group_manager.py +7 -0
- letta/services/helpers/agent_manager_helper.py +25 -15
- letta/services/provider_manager.py +2 -2
- letta/services/source_manager.py +35 -16
- letta/services/tool_executor/files_tool_executor.py +12 -5
- letta/services/tool_manager.py +12 -0
- letta/services/tool_sandbox/e2b_sandbox.py +52 -48
- letta/settings.py +9 -6
- letta/streaming_utils.py +2 -1
- letta/utils.py +34 -1
- {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/METADATA +9 -8
- {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/RECORD +96 -68
- {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/LICENSE +0 -0
- {letta_nightly-0.8.17.dev20250723104501.dist-info → letta_nightly-0.9.0.dev20250724104456.dist-info}/WHEEL +0 -0
- {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
|
-
|
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
|
-
"
|
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
|
-
|
102
|
+
execution = await e2b_sandbox.run_code(code, envs=env_vars)
|
139
103
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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:
|
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
|
-
|
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=
|
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.
|
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.
|
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.
|
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 == "
|
78
|
-
Requires-Dist: pgvector (>=0.2.3,<0.3.0) ; extra == "postgres" or extra == "
|
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 == "
|
83
|
-
Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0) ; extra == "postgres" or extra == "
|
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
|
|