letta-nightly 0.7.30.dev20250603104343__py3-none-any.whl → 0.8.0.dev20250604104349__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 (136) hide show
  1. letta/__init__.py +7 -1
  2. letta/agent.py +14 -7
  3. letta/agents/base_agent.py +1 -0
  4. letta/agents/ephemeral_summary_agent.py +104 -0
  5. letta/agents/helpers.py +35 -3
  6. letta/agents/letta_agent.py +492 -176
  7. letta/agents/letta_agent_batch.py +22 -16
  8. letta/agents/prompts/summary_system_prompt.txt +62 -0
  9. letta/agents/voice_agent.py +22 -7
  10. letta/agents/voice_sleeptime_agent.py +13 -8
  11. letta/constants.py +33 -1
  12. letta/data_sources/connectors.py +52 -36
  13. letta/errors.py +4 -0
  14. letta/functions/ast_parsers.py +13 -30
  15. letta/functions/function_sets/base.py +3 -1
  16. letta/functions/functions.py +2 -0
  17. letta/functions/mcp_client/base_client.py +151 -97
  18. letta/functions/mcp_client/sse_client.py +49 -31
  19. letta/functions/mcp_client/stdio_client.py +107 -106
  20. letta/functions/schema_generator.py +22 -22
  21. letta/groups/helpers.py +3 -4
  22. letta/groups/sleeptime_multi_agent.py +4 -4
  23. letta/groups/sleeptime_multi_agent_v2.py +22 -0
  24. letta/helpers/composio_helpers.py +16 -0
  25. letta/helpers/converters.py +20 -0
  26. letta/helpers/datetime_helpers.py +1 -6
  27. letta/helpers/tool_rule_solver.py +2 -1
  28. letta/interfaces/anthropic_streaming_interface.py +17 -2
  29. letta/interfaces/openai_chat_completions_streaming_interface.py +1 -0
  30. letta/interfaces/openai_streaming_interface.py +18 -2
  31. letta/llm_api/anthropic_client.py +24 -3
  32. letta/llm_api/google_ai_client.py +0 -15
  33. letta/llm_api/google_vertex_client.py +6 -5
  34. letta/llm_api/llm_client_base.py +15 -0
  35. letta/llm_api/openai.py +2 -2
  36. letta/llm_api/openai_client.py +60 -8
  37. letta/orm/__init__.py +2 -0
  38. letta/orm/agent.py +45 -43
  39. letta/orm/base.py +0 -2
  40. letta/orm/block.py +1 -0
  41. letta/orm/custom_columns.py +13 -0
  42. letta/orm/enums.py +5 -0
  43. letta/orm/file.py +3 -1
  44. letta/orm/files_agents.py +68 -0
  45. letta/orm/mcp_server.py +48 -0
  46. letta/orm/message.py +1 -0
  47. letta/orm/organization.py +11 -2
  48. letta/orm/passage.py +25 -10
  49. letta/orm/sandbox_config.py +5 -2
  50. letta/orm/sqlalchemy_base.py +171 -110
  51. letta/prompts/system/memgpt_base.txt +6 -1
  52. letta/prompts/system/memgpt_v2_chat.txt +57 -0
  53. letta/prompts/system/sleeptime.txt +2 -0
  54. letta/prompts/system/sleeptime_v2.txt +28 -0
  55. letta/schemas/agent.py +87 -20
  56. letta/schemas/block.py +7 -1
  57. letta/schemas/file.py +57 -0
  58. letta/schemas/mcp.py +74 -0
  59. letta/schemas/memory.py +5 -2
  60. letta/schemas/message.py +9 -0
  61. letta/schemas/openai/openai.py +0 -6
  62. letta/schemas/providers.py +33 -4
  63. letta/schemas/tool.py +26 -21
  64. letta/schemas/tool_execution_result.py +5 -0
  65. letta/server/db.py +23 -8
  66. letta/server/rest_api/app.py +73 -56
  67. letta/server/rest_api/interface.py +4 -4
  68. letta/server/rest_api/routers/v1/agents.py +132 -47
  69. letta/server/rest_api/routers/v1/blocks.py +3 -2
  70. letta/server/rest_api/routers/v1/embeddings.py +3 -3
  71. letta/server/rest_api/routers/v1/groups.py +3 -3
  72. letta/server/rest_api/routers/v1/jobs.py +14 -17
  73. letta/server/rest_api/routers/v1/organizations.py +10 -10
  74. letta/server/rest_api/routers/v1/providers.py +12 -10
  75. letta/server/rest_api/routers/v1/runs.py +3 -3
  76. letta/server/rest_api/routers/v1/sandbox_configs.py +12 -12
  77. letta/server/rest_api/routers/v1/sources.py +108 -43
  78. letta/server/rest_api/routers/v1/steps.py +8 -6
  79. letta/server/rest_api/routers/v1/tools.py +134 -95
  80. letta/server/rest_api/utils.py +12 -1
  81. letta/server/server.py +272 -73
  82. letta/services/agent_manager.py +246 -313
  83. letta/services/block_manager.py +30 -9
  84. letta/services/context_window_calculator/__init__.py +0 -0
  85. letta/services/context_window_calculator/context_window_calculator.py +150 -0
  86. letta/services/context_window_calculator/token_counter.py +82 -0
  87. letta/services/file_processor/__init__.py +0 -0
  88. letta/services/file_processor/chunker/__init__.py +0 -0
  89. letta/services/file_processor/chunker/llama_index_chunker.py +29 -0
  90. letta/services/file_processor/embedder/__init__.py +0 -0
  91. letta/services/file_processor/embedder/openai_embedder.py +84 -0
  92. letta/services/file_processor/file_processor.py +123 -0
  93. letta/services/file_processor/parser/__init__.py +0 -0
  94. letta/services/file_processor/parser/base_parser.py +9 -0
  95. letta/services/file_processor/parser/mistral_parser.py +54 -0
  96. letta/services/file_processor/types.py +0 -0
  97. letta/services/files_agents_manager.py +184 -0
  98. letta/services/group_manager.py +118 -0
  99. letta/services/helpers/agent_manager_helper.py +76 -21
  100. letta/services/helpers/tool_execution_helper.py +3 -0
  101. letta/services/helpers/tool_parser_helper.py +100 -0
  102. letta/services/identity_manager.py +44 -42
  103. letta/services/job_manager.py +21 -10
  104. letta/services/mcp/base_client.py +5 -2
  105. letta/services/mcp/sse_client.py +3 -5
  106. letta/services/mcp/stdio_client.py +3 -5
  107. letta/services/mcp_manager.py +281 -0
  108. letta/services/message_manager.py +40 -26
  109. letta/services/organization_manager.py +55 -19
  110. letta/services/passage_manager.py +211 -13
  111. letta/services/provider_manager.py +48 -2
  112. letta/services/sandbox_config_manager.py +105 -0
  113. letta/services/source_manager.py +4 -5
  114. letta/services/step_manager.py +9 -6
  115. letta/services/summarizer/summarizer.py +50 -23
  116. letta/services/telemetry_manager.py +7 -0
  117. letta/services/tool_executor/tool_execution_manager.py +11 -52
  118. letta/services/tool_executor/tool_execution_sandbox.py +4 -34
  119. letta/services/tool_executor/tool_executor.py +107 -105
  120. letta/services/tool_manager.py +56 -17
  121. letta/services/tool_sandbox/base.py +39 -92
  122. letta/services/tool_sandbox/e2b_sandbox.py +16 -11
  123. letta/services/tool_sandbox/local_sandbox.py +51 -23
  124. letta/services/user_manager.py +36 -3
  125. letta/settings.py +10 -3
  126. letta/templates/__init__.py +0 -0
  127. letta/templates/sandbox_code_file.py.j2 +47 -0
  128. letta/templates/template_helper.py +16 -0
  129. letta/tracing.py +30 -1
  130. letta/types/__init__.py +7 -0
  131. letta/utils.py +25 -1
  132. {letta_nightly-0.7.30.dev20250603104343.dist-info → letta_nightly-0.8.0.dev20250604104349.dist-info}/METADATA +7 -2
  133. {letta_nightly-0.7.30.dev20250603104343.dist-info → letta_nightly-0.8.0.dev20250604104349.dist-info}/RECORD +136 -110
  134. {letta_nightly-0.7.30.dev20250603104343.dist-info → letta_nightly-0.8.0.dev20250604104349.dist-info}/LICENSE +0 -0
  135. {letta_nightly-0.7.30.dev20250603104343.dist-info → letta_nightly-0.8.0.dev20250604104349.dist-info}/WHEEL +0 -0
  136. {letta_nightly-0.7.30.dev20250603104343.dist-info → letta_nightly-0.8.0.dev20250604104349.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,47 @@
1
+ {{ 'from __future__ import annotations' if future_import else '' }}
2
+ from typing import *
3
+ import pickle
4
+ import sys
5
+ import base64
6
+ import struct
7
+ import hashlib
8
+
9
+ {# Additional imports to support agent state #}
10
+ {% if inject_agent_state %}
11
+ import letta
12
+ from letta import *
13
+ {% endif %}
14
+
15
+ {# Add schema code if available #}
16
+ {{ schema_imports or ''}}
17
+
18
+ {# Load agent state #}
19
+ agent_state = {{ 'pickle.loads(' ~ agent_state_pickle ~ ')' if agent_state_pickle else 'None' }}
20
+
21
+ {{ tool_args }}
22
+
23
+ {# The tool's source code #}
24
+ {{ tool_source_code }}
25
+
26
+ {# Invoke the function and store the result in a global variable #}
27
+ {{ local_sandbox_result_var_name }} = {
28
+ "results": {{ invoke_function_call }},
29
+ "agent_state": agent_state
30
+ }
31
+
32
+ {{ local_sandbox_result_var_name }}_pkl = pickle.dumps({{ local_sandbox_result_var_name }})
33
+
34
+ {% if wrap_print_with_markers %}
35
+ {# Combine everything to flush and write at once. #}
36
+ data_checksum = hashlib.md5({{ local_sandbox_result_var_name }}_pkl).hexdigest().encode('ascii')
37
+ {{ local_sandbox_result_var_name }}_msg = (
38
+ {{ start_marker }} +
39
+ struct.pack('>I', len({{ local_sandbox_result_var_name }}_pkl)) +
40
+ data_checksum +
41
+ {{ local_sandbox_result_var_name }}_pkl
42
+ )
43
+ sys.stdout.buffer.write({{ local_sandbox_result_var_name }}_msg)
44
+ sys.stdout.buffer.flush()
45
+ {% else %}
46
+ base64.b64encode({{ local_sandbox_result_var_name }}_pkl).decode('utf-8')
47
+ {% endif %}
@@ -0,0 +1,16 @@
1
+ import os
2
+
3
+ from jinja2 import Environment, FileSystemLoader, StrictUndefined
4
+
5
+ TEMPLATE_DIR = os.path.dirname(__file__)
6
+ jinja_env = Environment(
7
+ loader=FileSystemLoader(TEMPLATE_DIR),
8
+ undefined=StrictUndefined,
9
+ trim_blocks=True,
10
+ lstrip_blocks=True,
11
+ )
12
+
13
+
14
+ def render_template(template_name: str, **kwargs):
15
+ template = jinja_env.get_template(template_name)
16
+ return template.render(**kwargs)
letta/tracing.py CHANGED
@@ -16,6 +16,8 @@ from opentelemetry.sdk.trace import TracerProvider
16
16
  from opentelemetry.sdk.trace.export import BatchSpanProcessor
17
17
  from opentelemetry.trace import Status, StatusCode
18
18
 
19
+ from letta import __version__ as letta_version
20
+
19
21
  tracer = trace.get_tracer(__name__)
20
22
  _is_tracing_initialized = False
21
23
  _excluded_v1_endpoints_regex: List[str] = [
@@ -24,6 +26,7 @@ _excluded_v1_endpoints_regex: List[str] = [
24
26
  # "^GET /v1/agents/(?P<agent_id>[^/]+)/archival-memory$",
25
27
  # "^GET /v1/agents/(?P<agent_id>[^/]+)/sources$",
26
28
  # r"^POST /v1/voice-beta/.*/chat/completions$",
29
+ "^GET /v1/health$",
27
30
  ]
28
31
 
29
32
 
@@ -80,6 +83,31 @@ async def update_trace_attributes(request: Request):
80
83
  if user_id:
81
84
  span.set_attribute("user.id", user_id)
82
85
 
86
+ # Add organization_id if available
87
+ organization_id = request.headers.get("x-organization-id")
88
+ if organization_id:
89
+ span.set_attribute("organization.id", organization_id)
90
+
91
+ # Add project_id if available
92
+ project_id = request.headers.get("x-project-id")
93
+ if project_id:
94
+ span.set_attribute("project.id", project_id)
95
+
96
+ # Add agent_id if available
97
+ agent_id = request.headers.get("x-agent-id")
98
+ if agent_id:
99
+ span.set_attribute("agent.id", agent_id)
100
+
101
+ # Add template_id if available
102
+ template_id = request.headers.get("x-template-id")
103
+ if template_id:
104
+ span.set_attribute("template.id", template_id)
105
+
106
+ # Add base_template_id if available
107
+ base_template_id = request.headers.get("x-base-template-id")
108
+ if base_template_id:
109
+ span.set_attribute("base_template.id", base_template_id)
110
+
83
111
  # Add request body if available
84
112
  try:
85
113
  body = await request.json()
@@ -124,7 +152,8 @@ def setup_tracing(
124
152
  resource=Resource.create(
125
153
  {
126
154
  "service.name": service_name,
127
- "device.id": uuid.getnode(), # MAC address as unique device identifier
155
+ "device.id": uuid.getnode(), # MAC address as unique device identifier,
156
+ "letta.version": letta_version,
128
157
  }
129
158
  )
130
159
  )
letta/types/__init__.py CHANGED
@@ -0,0 +1,7 @@
1
+ from typing import Any, TypeAlias
2
+
3
+ from pydantic import JsonValue
4
+
5
+ JsonDict: TypeAlias = dict[str, JsonValue]
6
+
7
+ __all__ = ["JsonDict", "JsonValue"]
letta/utils.py CHANGED
@@ -1018,7 +1018,7 @@ def sanitize_filename(filename: str) -> str:
1018
1018
  base = base[:max_base_length]
1019
1019
 
1020
1020
  # Append a unique UUID suffix for uniqueness
1021
- unique_suffix = uuid.uuid4().hex
1021
+ unique_suffix = uuid.uuid4().hex[:4]
1022
1022
  sanitized_filename = f"{base}_{unique_suffix}{ext}"
1023
1023
 
1024
1024
  # Return the sanitized filename
@@ -1034,6 +1034,20 @@ def get_friendly_error_msg(function_name: str, exception_name: str, exception_me
1034
1034
  return error_msg
1035
1035
 
1036
1036
 
1037
+ def parse_stderr_error_msg(stderr_txt: str, last_n_lines: int = 3) -> tuple[str, str]:
1038
+ """
1039
+ Parses out from the last `last_n_line` of `stderr_txt` the Exception type and message.
1040
+ """
1041
+ index = -(last_n_lines + 1)
1042
+ pattern = r"(\w+(?:Error|Exception)): (.+?)$"
1043
+ for line in stderr_txt.split("\n")[:index:-1]:
1044
+ if "Error" in line or "Exception" in line:
1045
+ match = re.search(pattern, line)
1046
+ if match:
1047
+ return match.group(1), match.group(2)
1048
+ return "", ""
1049
+
1050
+
1037
1051
  def run_async_task(coro: Coroutine[Any, Any, Any]) -> Any:
1038
1052
  """
1039
1053
  Safely runs an asynchronous coroutine in a synchronous context.
@@ -1074,3 +1088,13 @@ def log_telemetry(logger: Logger, event: str, **kwargs):
1074
1088
 
1075
1089
  def make_key(*args, **kwargs):
1076
1090
  return str((args, tuple(sorted(kwargs.items()))))
1091
+
1092
+
1093
+ def safe_create_task(coro, logger: Logger, label: str = "background task"):
1094
+ async def wrapper():
1095
+ try:
1096
+ await coro
1097
+ except Exception as e:
1098
+ logger.exception(f"{label} failed with {type(e).__name__}: {e}")
1099
+
1100
+ return asyncio.create_task(wrapper())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: letta-nightly
3
- Version: 0.7.30.dev20250603104343
3
+ Version: 0.8.0.dev20250604104349
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
@@ -16,6 +16,7 @@ Provides-Extra: bedrock
16
16
  Provides-Extra: cloud-tool-sandbox
17
17
  Provides-Extra: desktop
18
18
  Provides-Extra: dev
19
+ Provides-Extra: experimental
19
20
  Provides-Extra: external-tools
20
21
  Provides-Extra: google
21
22
  Provides-Extra: postgres
@@ -27,7 +28,8 @@ Requires-Dist: aiosqlite (>=0.21.0,<0.22.0)
27
28
  Requires-Dist: alembic (>=1.13.3,<2.0.0)
28
29
  Requires-Dist: anthropic (>=0.49.0,<0.50.0)
29
30
  Requires-Dist: apscheduler (>=3.11.0,<4.0.0)
30
- Requires-Dist: asyncpg (>=0.30.0,<0.31.0)
31
+ Requires-Dist: async-lru (>=2.0.5,<3.0.0)
32
+ Requires-Dist: asyncpg (>=0.30.0,<0.31.0) ; extra == "postgres"
31
33
  Requires-Dist: autoflake (>=2.3.0,<3.0.0) ; extra == "dev" or extra == "all"
32
34
  Requires-Dist: black[jupyter] (>=24.2.0,<25.0.0) ; extra == "dev" or extra == "all"
33
35
  Requires-Dist: boto3 (>=1.36.24,<2.0.0) ; extra == "bedrock"
@@ -43,6 +45,7 @@ Requires-Dist: faker (>=36.1.0,<37.0.0)
43
45
  Requires-Dist: fastapi (>=0.115.6,<0.116.0) ; extra == "server" or extra == "desktop" or extra == "all"
44
46
  Requires-Dist: firecrawl-py (>=1.15.0,<2.0.0)
45
47
  Requires-Dist: google-genai (>=1.15.0,<2.0.0) ; extra == "google"
48
+ Requires-Dist: granian[reload,uvloop] (>=2.3.2,<3.0.0) ; extra == "experimental" or extra == "all"
46
49
  Requires-Dist: grpcio (>=1.68.1,<2.0.0)
47
50
  Requires-Dist: grpcio-tools (>=1.68.1,<2.0.0)
48
51
  Requires-Dist: html2text (>=2020.1.16,<2021.0.0)
@@ -59,6 +62,7 @@ Requires-Dist: locust (>=2.31.5,<3.0.0) ; extra == "dev" or extra == "desktop" o
59
62
  Requires-Dist: marshmallow-sqlalchemy (>=1.4.1,<2.0.0)
60
63
  Requires-Dist: matplotlib (>=3.10.1,<4.0.0)
61
64
  Requires-Dist: mcp (>=1.3.0,<2.0.0)
65
+ Requires-Dist: mistralai (>=1.8.1,<2.0.0)
62
66
  Requires-Dist: nltk (>=3.8.1,<4.0.0)
63
67
  Requires-Dist: numpy (>=1.26.2,<2.0.0)
64
68
  Requires-Dist: openai (>=1.60.0,<2.0.0)
@@ -97,6 +101,7 @@ Requires-Dist: tavily-python (>=0.7.2,<0.8.0)
97
101
  Requires-Dist: tqdm (>=4.66.1,<5.0.0)
98
102
  Requires-Dist: typer[all] (>=0.9.0,<0.10.0)
99
103
  Requires-Dist: uvicorn (>=0.24.0.post1,<0.25.0) ; extra == "server" or extra == "desktop" or extra == "all"
104
+ Requires-Dist: uvloop (>=0.21.0,<0.22.0) ; extra == "experimental" or extra == "all"
100
105
  Requires-Dist: wikipedia (>=1.4.0,<2.0.0) ; extra == "external-tools" or extra == "tests" or extra == "desktop" or extra == "all"
101
106
  Description-Content-Type: text/markdown
102
107