letta-nightly 0.5.5.dev20241122170833__py3-none-any.whl → 0.6.0.dev20241204052927__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/__init__.py +2 -2
- letta/agent.py +155 -166
- letta/agent_store/chroma.py +2 -0
- letta/agent_store/db.py +1 -1
- letta/cli/cli.py +12 -8
- letta/cli/cli_config.py +1 -1
- letta/client/client.py +765 -137
- letta/config.py +2 -2
- letta/constants.py +10 -14
- letta/errors.py +12 -0
- letta/functions/function_sets/base.py +38 -1
- letta/functions/functions.py +40 -57
- letta/functions/helpers.py +0 -4
- letta/functions/schema_generator.py +279 -18
- letta/helpers/tool_rule_solver.py +6 -5
- letta/llm_api/helpers.py +99 -5
- letta/llm_api/openai.py +8 -2
- letta/local_llm/utils.py +13 -6
- letta/log.py +7 -9
- letta/main.py +1 -1
- letta/metadata.py +53 -38
- letta/o1_agent.py +1 -4
- letta/orm/__init__.py +2 -0
- letta/orm/block.py +7 -3
- letta/orm/blocks_agents.py +32 -0
- letta/orm/errors.py +8 -0
- letta/orm/mixins.py +8 -0
- letta/orm/organization.py +8 -1
- letta/orm/sandbox_config.py +56 -0
- letta/orm/sqlalchemy_base.py +68 -10
- letta/persistence_manager.py +1 -0
- letta/schemas/agent.py +57 -52
- letta/schemas/block.py +85 -26
- letta/schemas/blocks_agents.py +32 -0
- letta/schemas/enums.py +14 -0
- letta/schemas/letta_base.py +10 -1
- letta/schemas/letta_request.py +11 -23
- letta/schemas/letta_response.py +1 -2
- letta/schemas/memory.py +41 -76
- letta/schemas/message.py +3 -3
- letta/schemas/sandbox_config.py +114 -0
- letta/schemas/tool.py +37 -1
- letta/schemas/tool_rule.py +13 -5
- letta/server/rest_api/app.py +5 -4
- letta/server/rest_api/interface.py +12 -19
- letta/server/rest_api/routers/openai/assistants/threads.py +2 -3
- letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -2
- letta/server/rest_api/routers/v1/__init__.py +4 -9
- letta/server/rest_api/routers/v1/agents.py +145 -61
- letta/server/rest_api/routers/v1/blocks.py +50 -5
- letta/server/rest_api/routers/v1/sandbox_configs.py +127 -0
- letta/server/rest_api/routers/v1/sources.py +8 -1
- letta/server/rest_api/routers/v1/tools.py +139 -13
- letta/server/rest_api/utils.py +6 -0
- letta/server/server.py +397 -340
- letta/server/static_files/assets/index-9fa459a2.js +1 -1
- letta/services/block_manager.py +23 -2
- letta/services/blocks_agents_manager.py +106 -0
- letta/services/per_agent_lock_manager.py +18 -0
- letta/services/sandbox_config_manager.py +256 -0
- letta/services/tool_execution_sandbox.py +352 -0
- letta/services/tool_manager.py +16 -22
- letta/services/tool_sandbox_env/.gitkeep +0 -0
- letta/settings.py +4 -0
- letta/utils.py +0 -7
- {letta_nightly-0.5.5.dev20241122170833.dist-info → letta_nightly-0.6.0.dev20241204052927.dist-info}/METADATA +10 -8
- {letta_nightly-0.5.5.dev20241122170833.dist-info → letta_nightly-0.6.0.dev20241204052927.dist-info}/RECORD +70 -60
- {letta_nightly-0.5.5.dev20241122170833.dist-info → letta_nightly-0.6.0.dev20241204052927.dist-info}/LICENSE +0 -0
- {letta_nightly-0.5.5.dev20241122170833.dist-info → letta_nightly-0.6.0.dev20241204052927.dist-info}/WHEEL +0 -0
- {letta_nightly-0.5.5.dev20241122170833.dist-info → letta_nightly-0.6.0.dev20241204052927.dist-info}/entry_points.txt +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from typing import List, Optional
|
|
2
2
|
|
|
3
|
+
from composio.client.collections import ActionModel, AppModel
|
|
3
4
|
from fastapi import APIRouter, Body, Depends, Header, HTTPException
|
|
4
5
|
|
|
5
|
-
from letta.
|
|
6
|
-
from letta.
|
|
6
|
+
from letta.errors import LettaToolCreateError
|
|
7
|
+
from letta.orm.errors import UniqueConstraintViolationError
|
|
8
|
+
from letta.schemas.letta_message import FunctionReturn
|
|
9
|
+
from letta.schemas.tool import Tool, ToolCreate, ToolRunFromSource, ToolUpdate
|
|
7
10
|
from letta.server.rest_api.utils import get_letta_server
|
|
8
11
|
from letta.server.server import SyncServer
|
|
9
12
|
|
|
@@ -14,12 +17,13 @@ router = APIRouter(prefix="/tools", tags=["tools"])
|
|
|
14
17
|
def delete_tool(
|
|
15
18
|
tool_id: str,
|
|
16
19
|
server: SyncServer = Depends(get_letta_server),
|
|
20
|
+
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
17
21
|
):
|
|
18
22
|
"""
|
|
19
23
|
Delete a tool by name
|
|
20
24
|
"""
|
|
21
|
-
|
|
22
|
-
server.tool_manager.
|
|
25
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
26
|
+
server.tool_manager.delete_tool_by_id(tool_id=tool_id, actor=actor)
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
@router.get("/{tool_id}", response_model=Tool, operation_id="get_tool")
|
|
@@ -49,11 +53,10 @@ def get_tool_id(
|
|
|
49
53
|
Get a tool ID by name
|
|
50
54
|
"""
|
|
51
55
|
actor = server.get_user_or_default(user_id=user_id)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
tool = server.tool_manager.get_tool_by_name(tool_name=tool_name, actor=actor)
|
|
56
|
+
tool = server.tool_manager.get_tool_by_name(tool_name=tool_name, actor=actor)
|
|
57
|
+
if tool:
|
|
55
58
|
return tool.id
|
|
56
|
-
|
|
59
|
+
else:
|
|
57
60
|
raise HTTPException(status_code=404, detail=f"Tool with name {tool_name} and organization id {actor.organization_id} not found.")
|
|
58
61
|
|
|
59
62
|
|
|
@@ -85,12 +88,50 @@ def create_tool(
|
|
|
85
88
|
"""
|
|
86
89
|
Create a new tool
|
|
87
90
|
"""
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
try:
|
|
92
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
93
|
+
tool = Tool(**request.model_dump())
|
|
94
|
+
return server.tool_manager.create_tool(pydantic_tool=tool, actor=actor)
|
|
95
|
+
except UniqueConstraintViolationError as e:
|
|
96
|
+
# Log or print the full exception here for debugging
|
|
97
|
+
print(f"Error occurred: {e}")
|
|
98
|
+
clean_error_message = f"Tool with name {request.name} already exists."
|
|
99
|
+
raise HTTPException(status_code=409, detail=clean_error_message)
|
|
100
|
+
except LettaToolCreateError as e:
|
|
101
|
+
# HTTP 400 == Bad Request
|
|
102
|
+
print(f"Error occurred during tool creation: {e}")
|
|
103
|
+
# print the full stack trace
|
|
104
|
+
import traceback
|
|
105
|
+
|
|
106
|
+
print(traceback.format_exc())
|
|
107
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
108
|
+
except Exception as e:
|
|
109
|
+
# Catch other unexpected errors and raise an internal server error
|
|
110
|
+
print(f"Unexpected error occurred: {e}")
|
|
111
|
+
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
|
|
90
112
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
113
|
+
|
|
114
|
+
@router.put("/", response_model=Tool, operation_id="upsert_tool")
|
|
115
|
+
def upsert_tool(
|
|
116
|
+
request: ToolCreate = Body(...),
|
|
117
|
+
server: SyncServer = Depends(get_letta_server),
|
|
118
|
+
user_id: Optional[str] = Header(None, alias="user_id"),
|
|
119
|
+
):
|
|
120
|
+
"""
|
|
121
|
+
Create or update a tool
|
|
122
|
+
"""
|
|
123
|
+
try:
|
|
124
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
125
|
+
tool = server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**request.model_dump()), actor=actor)
|
|
126
|
+
return tool
|
|
127
|
+
except UniqueConstraintViolationError as e:
|
|
128
|
+
# Log the error and raise a conflict exception
|
|
129
|
+
print(f"Unique constraint violation occurred: {e}")
|
|
130
|
+
raise HTTPException(status_code=409, detail=str(e))
|
|
131
|
+
except Exception as e:
|
|
132
|
+
# Catch other unexpected errors and raise an internal server error
|
|
133
|
+
print(f"Unexpected error occurred: {e}")
|
|
134
|
+
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
|
|
94
135
|
|
|
95
136
|
|
|
96
137
|
@router.patch("/{tool_id}", response_model=Tool, operation_id="update_tool")
|
|
@@ -117,3 +158,88 @@ def add_base_tools(
|
|
|
117
158
|
"""
|
|
118
159
|
actor = server.get_user_or_default(user_id=user_id)
|
|
119
160
|
return server.tool_manager.add_base_tools(actor=actor)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# NOTE: can re-enable if needed
|
|
164
|
+
# @router.post("/{tool_id}/run", response_model=FunctionReturn, operation_id="run_tool")
|
|
165
|
+
# def run_tool(
|
|
166
|
+
# server: SyncServer = Depends(get_letta_server),
|
|
167
|
+
# request: ToolRun = Body(...),
|
|
168
|
+
# user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
169
|
+
# ):
|
|
170
|
+
# """
|
|
171
|
+
# Run an existing tool on provided arguments
|
|
172
|
+
# """
|
|
173
|
+
# actor = server.get_user_or_default(user_id=user_id)
|
|
174
|
+
|
|
175
|
+
# return server.run_tool(tool_id=request.tool_id, tool_args=request.tool_args, user_id=actor.id)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@router.post("/run", response_model=FunctionReturn, operation_id="run_tool_from_source")
|
|
179
|
+
def run_tool_from_source(
|
|
180
|
+
server: SyncServer = Depends(get_letta_server),
|
|
181
|
+
request: ToolRunFromSource = Body(...),
|
|
182
|
+
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
183
|
+
):
|
|
184
|
+
"""
|
|
185
|
+
Attempt to build a tool from source, then run it on the provided arguments
|
|
186
|
+
"""
|
|
187
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
return server.run_tool_from_source(
|
|
191
|
+
tool_source=request.source_code,
|
|
192
|
+
tool_source_type=request.source_type,
|
|
193
|
+
tool_args=request.args,
|
|
194
|
+
tool_name=request.name,
|
|
195
|
+
user_id=actor.id,
|
|
196
|
+
)
|
|
197
|
+
except LettaToolCreateError as e:
|
|
198
|
+
# HTTP 400 == Bad Request
|
|
199
|
+
print(f"Error occurred during tool creation: {e}")
|
|
200
|
+
# print the full stack trace
|
|
201
|
+
import traceback
|
|
202
|
+
|
|
203
|
+
print(traceback.format_exc())
|
|
204
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
205
|
+
|
|
206
|
+
except Exception as e:
|
|
207
|
+
# Catch other unexpected errors and raise an internal server error
|
|
208
|
+
print(f"Unexpected error occurred: {e}")
|
|
209
|
+
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# Specific routes for Composio
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@router.get("/composio/apps", response_model=List[AppModel], operation_id="list_composio_apps")
|
|
216
|
+
def list_composio_apps(server: SyncServer = Depends(get_letta_server)):
|
|
217
|
+
"""
|
|
218
|
+
Get a list of all Composio apps
|
|
219
|
+
"""
|
|
220
|
+
return server.get_composio_apps()
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@router.get("/composio/apps/{composio_app_name}/actions", response_model=List[ActionModel], operation_id="list_composio_actions_by_app")
|
|
224
|
+
def list_composio_actions_by_app(
|
|
225
|
+
composio_app_name: str,
|
|
226
|
+
server: SyncServer = Depends(get_letta_server),
|
|
227
|
+
):
|
|
228
|
+
"""
|
|
229
|
+
Get a list of all Composio actions for a specific app
|
|
230
|
+
"""
|
|
231
|
+
return server.get_composio_actions_from_app_name(composio_app_name=composio_app_name)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@router.post("/composio/{composio_action_name}", response_model=Tool, operation_id="add_composio_tool")
|
|
235
|
+
def add_composio_tool(
|
|
236
|
+
composio_action_name: str,
|
|
237
|
+
server: SyncServer = Depends(get_letta_server),
|
|
238
|
+
user_id: Optional[str] = Header(None, alias="user_id"),
|
|
239
|
+
):
|
|
240
|
+
"""
|
|
241
|
+
Add a new Composio tool by action name (Composio refers to each tool as an `Action`)
|
|
242
|
+
"""
|
|
243
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
244
|
+
tool_create = ToolCreate.from_composio(action=composio_action_name)
|
|
245
|
+
return server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=actor)
|
letta/server/rest_api/utils.py
CHANGED
|
@@ -5,6 +5,7 @@ import warnings
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from typing import AsyncGenerator, Optional, Union
|
|
7
7
|
|
|
8
|
+
from fastapi import Header
|
|
8
9
|
from pydantic import BaseModel
|
|
9
10
|
|
|
10
11
|
from letta.schemas.usage import LettaUsageStatistics
|
|
@@ -84,5 +85,10 @@ def get_letta_server() -> SyncServer:
|
|
|
84
85
|
return server
|
|
85
86
|
|
|
86
87
|
|
|
88
|
+
# Dependency to get user_id from headers
|
|
89
|
+
def get_user_id(user_id: Optional[str] = Header(None, alias="user_id")) -> Optional[str]:
|
|
90
|
+
return user_id
|
|
91
|
+
|
|
92
|
+
|
|
87
93
|
def get_current_interface() -> StreamingServerInterface:
|
|
88
94
|
return StreamingServerInterface
|