letta-nightly 0.4.1.dev20241007104134__py3-none-any.whl → 0.4.1.dev20241008104105__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/agent.py +19 -9
- letta/credentials.py +1 -1
- letta/errors.py +1 -1
- letta/llm_api/azure_openai.py +15 -19
- letta/llm_api/helpers.py +153 -0
- letta/llm_api/llm_api_tools.py +39 -215
- letta/llm_api/openai.py +70 -2
- letta/providers.py +5 -1
- letta/schemas/llm_config.py +5 -2
- letta/server/rest_api/admin/tools.py +0 -1
- letta/server/rest_api/app.py +1 -17
- letta/server/rest_api/routers/openai/assistants/threads.py +9 -6
- letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +4 -2
- letta/server/rest_api/routers/v1/agents.py +23 -13
- letta/server/rest_api/routers/v1/blocks.py +5 -3
- letta/server/rest_api/routers/v1/jobs.py +5 -3
- letta/server/rest_api/routers/v1/sources.py +24 -12
- letta/server/rest_api/routers/v1/tools.py +11 -6
- letta/server/server.py +17 -34
- letta/settings.py +2 -1
- {letta_nightly-0.4.1.dev20241007104134.dist-info → letta_nightly-0.4.1.dev20241008104105.dist-info}/METADATA +1 -1
- {letta_nightly-0.4.1.dev20241007104134.dist-info → letta_nightly-0.4.1.dev20241008104105.dist-info}/RECORD +25 -24
- {letta_nightly-0.4.1.dev20241007104134.dist-info → letta_nightly-0.4.1.dev20241008104105.dist-info}/LICENSE +0 -0
- {letta_nightly-0.4.1.dev20241007104134.dist-info → letta_nightly-0.4.1.dev20241008104105.dist-info}/WHEEL +0 -0
- {letta_nightly-0.4.1.dev20241007104134.dist-info → letta_nightly-0.4.1.dev20241008104105.dist-info}/entry_points.txt +0 -0
|
@@ -2,7 +2,7 @@ import asyncio
|
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
from typing import Dict, List, Optional, Union
|
|
4
4
|
|
|
5
|
-
from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
|
|
5
|
+
from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, status
|
|
6
6
|
from fastapi.responses import JSONResponse, StreamingResponse
|
|
7
7
|
from starlette.responses import StreamingResponse
|
|
8
8
|
|
|
@@ -40,12 +40,13 @@ router = APIRouter(prefix="/agents", tags=["agents"])
|
|
|
40
40
|
@router.get("/", response_model=List[AgentState], operation_id="list_agents")
|
|
41
41
|
def list_agents(
|
|
42
42
|
server: "SyncServer" = Depends(get_letta_server),
|
|
43
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
43
44
|
):
|
|
44
45
|
"""
|
|
45
46
|
List all agents associated with a given user.
|
|
46
47
|
This endpoint retrieves a list of all agents and their configurations associated with the specified user ID.
|
|
47
48
|
"""
|
|
48
|
-
actor = server.
|
|
49
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
49
50
|
|
|
50
51
|
return server.list_agents(user_id=actor.id)
|
|
51
52
|
|
|
@@ -54,11 +55,12 @@ def list_agents(
|
|
|
54
55
|
def create_agent(
|
|
55
56
|
agent: CreateAgent = Body(...),
|
|
56
57
|
server: "SyncServer" = Depends(get_letta_server),
|
|
58
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
57
59
|
):
|
|
58
60
|
"""
|
|
59
61
|
Create a new agent with the specified configuration.
|
|
60
62
|
"""
|
|
61
|
-
actor = server.
|
|
63
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
62
64
|
agent.user_id = actor.id
|
|
63
65
|
# TODO: sarah make general
|
|
64
66
|
# TODO: eventually remove this
|
|
@@ -74,9 +76,10 @@ def update_agent(
|
|
|
74
76
|
agent_id: str,
|
|
75
77
|
update_agent: UpdateAgentState = Body(...),
|
|
76
78
|
server: "SyncServer" = Depends(get_letta_server),
|
|
79
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
77
80
|
):
|
|
78
81
|
"""Update an exsiting agent"""
|
|
79
|
-
actor = server.
|
|
82
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
80
83
|
|
|
81
84
|
update_agent.id = agent_id
|
|
82
85
|
return server.update_agent(update_agent, user_id=actor.id)
|
|
@@ -86,11 +89,12 @@ def update_agent(
|
|
|
86
89
|
def get_agent_state(
|
|
87
90
|
agent_id: str,
|
|
88
91
|
server: "SyncServer" = Depends(get_letta_server),
|
|
92
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
89
93
|
):
|
|
90
94
|
"""
|
|
91
95
|
Get the state of the agent.
|
|
92
96
|
"""
|
|
93
|
-
actor = server.
|
|
97
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
94
98
|
|
|
95
99
|
if not server.ms.get_agent(user_id=actor.id, agent_id=agent_id):
|
|
96
100
|
# agent does not exist
|
|
@@ -103,11 +107,12 @@ def get_agent_state(
|
|
|
103
107
|
def delete_agent(
|
|
104
108
|
agent_id: str,
|
|
105
109
|
server: "SyncServer" = Depends(get_letta_server),
|
|
110
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
106
111
|
):
|
|
107
112
|
"""
|
|
108
113
|
Delete an agent.
|
|
109
114
|
"""
|
|
110
|
-
actor = server.
|
|
115
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
111
116
|
|
|
112
117
|
return server.delete_agent(user_id=actor.id, agent_id=agent_id)
|
|
113
118
|
|
|
@@ -120,7 +125,6 @@ def get_agent_sources(
|
|
|
120
125
|
"""
|
|
121
126
|
Get the sources associated with an agent.
|
|
122
127
|
"""
|
|
123
|
-
server.get_current_user()
|
|
124
128
|
|
|
125
129
|
return server.list_attached_sources(agent_id)
|
|
126
130
|
|
|
@@ -155,12 +159,13 @@ def update_agent_memory(
|
|
|
155
159
|
agent_id: str,
|
|
156
160
|
request: Dict = Body(...),
|
|
157
161
|
server: "SyncServer" = Depends(get_letta_server),
|
|
162
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
158
163
|
):
|
|
159
164
|
"""
|
|
160
165
|
Update the core memory of a specific agent.
|
|
161
166
|
This endpoint accepts new memory contents (human and persona) and updates the core memory of the agent identified by the user ID and agent ID.
|
|
162
167
|
"""
|
|
163
|
-
actor = server.
|
|
168
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
164
169
|
|
|
165
170
|
memory = server.update_agent_core_memory(user_id=actor.id, agent_id=agent_id, new_memory_contents=request)
|
|
166
171
|
return memory
|
|
@@ -197,11 +202,12 @@ def get_agent_archival_memory(
|
|
|
197
202
|
after: Optional[int] = Query(None, description="Unique ID of the memory to start the query range at."),
|
|
198
203
|
before: Optional[int] = Query(None, description="Unique ID of the memory to end the query range at."),
|
|
199
204
|
limit: Optional[int] = Query(None, description="How many results to include in the response."),
|
|
205
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
200
206
|
):
|
|
201
207
|
"""
|
|
202
208
|
Retrieve the memories in an agent's archival memory store (paginated query).
|
|
203
209
|
"""
|
|
204
|
-
actor = server.
|
|
210
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
205
211
|
|
|
206
212
|
# TODO need to add support for non-postgres here
|
|
207
213
|
# chroma will throw:
|
|
@@ -221,11 +227,12 @@ def insert_agent_archival_memory(
|
|
|
221
227
|
agent_id: str,
|
|
222
228
|
request: CreateArchivalMemory = Body(...),
|
|
223
229
|
server: "SyncServer" = Depends(get_letta_server),
|
|
230
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
224
231
|
):
|
|
225
232
|
"""
|
|
226
233
|
Insert a memory into an agent's archival memory store.
|
|
227
234
|
"""
|
|
228
|
-
actor = server.
|
|
235
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
229
236
|
|
|
230
237
|
return server.insert_archival_memory(user_id=actor.id, agent_id=agent_id, memory_contents=request.text)
|
|
231
238
|
|
|
@@ -238,11 +245,12 @@ def delete_agent_archival_memory(
|
|
|
238
245
|
memory_id: str,
|
|
239
246
|
# memory_id: str = Query(..., description="Unique ID of the memory to be deleted."),
|
|
240
247
|
server: "SyncServer" = Depends(get_letta_server),
|
|
248
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
241
249
|
):
|
|
242
250
|
"""
|
|
243
251
|
Delete a memory from an agent's archival memory store.
|
|
244
252
|
"""
|
|
245
|
-
actor = server.
|
|
253
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
246
254
|
|
|
247
255
|
server.delete_archival_memory(user_id=actor.id, agent_id=agent_id, memory_id=memory_id)
|
|
248
256
|
return JSONResponse(status_code=status.HTTP_200_OK, content={"message": f"Memory id={memory_id} successfully deleted"})
|
|
@@ -268,11 +276,12 @@ def get_agent_messages(
|
|
|
268
276
|
DEFAULT_MESSAGE_TOOL_KWARG,
|
|
269
277
|
description="[Only applicable if use_assistant_message is True] The name of the message argument in the designated message tool.",
|
|
270
278
|
),
|
|
279
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
271
280
|
):
|
|
272
281
|
"""
|
|
273
282
|
Retrieve message history for an agent.
|
|
274
283
|
"""
|
|
275
|
-
actor = server.
|
|
284
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
276
285
|
|
|
277
286
|
return server.get_agent_recall_cursor(
|
|
278
287
|
user_id=actor.id,
|
|
@@ -306,13 +315,14 @@ async def send_message(
|
|
|
306
315
|
agent_id: str,
|
|
307
316
|
server: SyncServer = Depends(get_letta_server),
|
|
308
317
|
request: LettaRequest = Body(...),
|
|
318
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
309
319
|
):
|
|
310
320
|
"""
|
|
311
321
|
Process a user message and return the agent's response.
|
|
312
322
|
This endpoint accepts a message from a user and processes it through the agent.
|
|
313
323
|
It can optionally stream the response if 'stream_steps' or 'stream_tokens' is set to True.
|
|
314
324
|
"""
|
|
315
|
-
actor = server.
|
|
325
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
316
326
|
|
|
317
327
|
# TODO(charles): support sending multiple messages
|
|
318
328
|
assert len(request.messages) == 1, f"Multiple messages not supported: {request.messages}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List, Optional
|
|
2
2
|
|
|
3
|
-
from fastapi import APIRouter, Body, Depends, HTTPException, Query
|
|
3
|
+
from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query
|
|
4
4
|
|
|
5
5
|
from letta.schemas.block import Block, CreateBlock, UpdateBlock
|
|
6
6
|
from letta.server.rest_api.utils import get_letta_server
|
|
@@ -19,8 +19,9 @@ def list_blocks(
|
|
|
19
19
|
templates_only: bool = Query(True, description="Whether to include only templates"),
|
|
20
20
|
name: Optional[str] = Query(None, description="Name of the block"),
|
|
21
21
|
server: SyncServer = Depends(get_letta_server),
|
|
22
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
22
23
|
):
|
|
23
|
-
actor = server.
|
|
24
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
24
25
|
|
|
25
26
|
blocks = server.get_blocks(user_id=actor.id, label=label, template=templates_only, name=name)
|
|
26
27
|
if blocks is None:
|
|
@@ -32,8 +33,9 @@ def list_blocks(
|
|
|
32
33
|
def create_block(
|
|
33
34
|
create_block: CreateBlock = Body(...),
|
|
34
35
|
server: SyncServer = Depends(get_letta_server),
|
|
36
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
35
37
|
):
|
|
36
|
-
actor = server.
|
|
38
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
37
39
|
|
|
38
40
|
create_block.user_id = actor.id
|
|
39
41
|
return server.create_block(user_id=actor.id, request=create_block)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import List, Optional
|
|
2
2
|
|
|
3
|
-
from fastapi import APIRouter, Depends, Query
|
|
3
|
+
from fastapi import APIRouter, Depends, Header, Query
|
|
4
4
|
|
|
5
5
|
from letta.schemas.job import Job
|
|
6
6
|
from letta.server.rest_api.utils import get_letta_server
|
|
@@ -13,11 +13,12 @@ router = APIRouter(prefix="/jobs", tags=["jobs"])
|
|
|
13
13
|
def list_jobs(
|
|
14
14
|
server: "SyncServer" = Depends(get_letta_server),
|
|
15
15
|
source_id: Optional[str] = Query(None, description="Only list jobs associated with the source."),
|
|
16
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
16
17
|
):
|
|
17
18
|
"""
|
|
18
19
|
List all jobs.
|
|
19
20
|
"""
|
|
20
|
-
actor = server.
|
|
21
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
21
22
|
|
|
22
23
|
# TODO: add filtering by status
|
|
23
24
|
jobs = server.list_jobs(user_id=actor.id)
|
|
@@ -33,11 +34,12 @@ def list_jobs(
|
|
|
33
34
|
@router.get("/active", response_model=List[Job], operation_id="list_active_jobs")
|
|
34
35
|
def list_active_jobs(
|
|
35
36
|
server: "SyncServer" = Depends(get_letta_server),
|
|
37
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
36
38
|
):
|
|
37
39
|
"""
|
|
38
40
|
List all active jobs.
|
|
39
41
|
"""
|
|
40
|
-
actor = server.
|
|
42
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
41
43
|
|
|
42
44
|
return server.list_active_jobs(user_id=actor.id)
|
|
43
45
|
|
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
import tempfile
|
|
3
3
|
from typing import List
|
|
4
4
|
|
|
5
|
-
from fastapi import APIRouter, BackgroundTasks, Depends, Query, UploadFile
|
|
5
|
+
from fastapi import APIRouter, BackgroundTasks, Depends, Header, Query, UploadFile
|
|
6
6
|
|
|
7
7
|
from letta.schemas.document import Document
|
|
8
8
|
from letta.schemas.job import Job
|
|
@@ -21,11 +21,12 @@ router = APIRouter(prefix="/sources", tags=["sources"])
|
|
|
21
21
|
def get_source(
|
|
22
22
|
source_id: str,
|
|
23
23
|
server: "SyncServer" = Depends(get_letta_server),
|
|
24
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
24
25
|
):
|
|
25
26
|
"""
|
|
26
27
|
Get all sources
|
|
27
28
|
"""
|
|
28
|
-
actor = server.
|
|
29
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
29
30
|
|
|
30
31
|
return server.get_source(source_id=source_id, user_id=actor.id)
|
|
31
32
|
|
|
@@ -34,11 +35,12 @@ def get_source(
|
|
|
34
35
|
def get_source_id_by_name(
|
|
35
36
|
source_name: str,
|
|
36
37
|
server: "SyncServer" = Depends(get_letta_server),
|
|
38
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
37
39
|
):
|
|
38
40
|
"""
|
|
39
41
|
Get a source by name
|
|
40
42
|
"""
|
|
41
|
-
actor = server.
|
|
43
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
42
44
|
|
|
43
45
|
source_id = server.get_source_id(source_name=source_name, user_id=actor.id)
|
|
44
46
|
return source_id
|
|
@@ -47,11 +49,12 @@ def get_source_id_by_name(
|
|
|
47
49
|
@router.get("/", response_model=List[Source], operation_id="list_sources")
|
|
48
50
|
def list_sources(
|
|
49
51
|
server: "SyncServer" = Depends(get_letta_server),
|
|
52
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
50
53
|
):
|
|
51
54
|
"""
|
|
52
55
|
List all data sources created by a user.
|
|
53
56
|
"""
|
|
54
|
-
actor = server.
|
|
57
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
55
58
|
|
|
56
59
|
return server.list_all_sources(user_id=actor.id)
|
|
57
60
|
|
|
@@ -60,11 +63,12 @@ def list_sources(
|
|
|
60
63
|
def create_source(
|
|
61
64
|
source: SourceCreate,
|
|
62
65
|
server: "SyncServer" = Depends(get_letta_server),
|
|
66
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
63
67
|
):
|
|
64
68
|
"""
|
|
65
69
|
Create a new data source.
|
|
66
70
|
"""
|
|
67
|
-
actor = server.
|
|
71
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
68
72
|
|
|
69
73
|
return server.create_source(request=source, user_id=actor.id)
|
|
70
74
|
|
|
@@ -74,11 +78,13 @@ def update_source(
|
|
|
74
78
|
source_id: str,
|
|
75
79
|
source: SourceUpdate,
|
|
76
80
|
server: "SyncServer" = Depends(get_letta_server),
|
|
81
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
77
82
|
):
|
|
78
83
|
"""
|
|
79
84
|
Update the name or documentation of an existing data source.
|
|
80
85
|
"""
|
|
81
|
-
actor = server.
|
|
86
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
87
|
+
|
|
82
88
|
assert source.id == source_id, "Source ID in path must match ID in request body"
|
|
83
89
|
|
|
84
90
|
return server.update_source(request=source, user_id=actor.id)
|
|
@@ -88,11 +94,12 @@ def update_source(
|
|
|
88
94
|
def delete_source(
|
|
89
95
|
source_id: str,
|
|
90
96
|
server: "SyncServer" = Depends(get_letta_server),
|
|
97
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
91
98
|
):
|
|
92
99
|
"""
|
|
93
100
|
Delete a data source.
|
|
94
101
|
"""
|
|
95
|
-
actor = server.
|
|
102
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
96
103
|
|
|
97
104
|
server.delete_source(source_id=source_id, user_id=actor.id)
|
|
98
105
|
|
|
@@ -102,11 +109,12 @@ def attach_source_to_agent(
|
|
|
102
109
|
source_id: str,
|
|
103
110
|
agent_id: str = Query(..., description="The unique identifier of the agent to attach the source to."),
|
|
104
111
|
server: "SyncServer" = Depends(get_letta_server),
|
|
112
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
105
113
|
):
|
|
106
114
|
"""
|
|
107
115
|
Attach a data source to an existing agent.
|
|
108
116
|
"""
|
|
109
|
-
actor = server.
|
|
117
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
110
118
|
|
|
111
119
|
source = server.ms.get_source(source_id=source_id, user_id=actor.id)
|
|
112
120
|
assert source is not None, f"Source with id={source_id} not found."
|
|
@@ -119,11 +127,12 @@ def detach_source_from_agent(
|
|
|
119
127
|
source_id: str,
|
|
120
128
|
agent_id: str = Query(..., description="The unique identifier of the agent to detach the source from."),
|
|
121
129
|
server: "SyncServer" = Depends(get_letta_server),
|
|
130
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
122
131
|
) -> None:
|
|
123
132
|
"""
|
|
124
133
|
Detach a data source from an existing agent.
|
|
125
134
|
"""
|
|
126
|
-
actor = server.
|
|
135
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
127
136
|
|
|
128
137
|
return server.detach_source_from_agent(source_id=source_id, agent_id=agent_id, user_id=actor.id)
|
|
129
138
|
|
|
@@ -134,11 +143,12 @@ def upload_file_to_source(
|
|
|
134
143
|
source_id: str,
|
|
135
144
|
background_tasks: BackgroundTasks,
|
|
136
145
|
server: "SyncServer" = Depends(get_letta_server),
|
|
146
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
137
147
|
):
|
|
138
148
|
"""
|
|
139
149
|
Upload a file to a data source.
|
|
140
150
|
"""
|
|
141
|
-
actor = server.
|
|
151
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
142
152
|
|
|
143
153
|
source = server.ms.get_source(source_id=source_id, user_id=actor.id)
|
|
144
154
|
assert source is not None, f"Source with id={source_id} not found."
|
|
@@ -166,11 +176,12 @@ def upload_file_to_source(
|
|
|
166
176
|
def list_passages(
|
|
167
177
|
source_id: str,
|
|
168
178
|
server: SyncServer = Depends(get_letta_server),
|
|
179
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
169
180
|
):
|
|
170
181
|
"""
|
|
171
182
|
List all passages associated with a data source.
|
|
172
183
|
"""
|
|
173
|
-
actor = server.
|
|
184
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
174
185
|
passages = server.list_data_source_passages(user_id=actor.id, source_id=source_id)
|
|
175
186
|
return passages
|
|
176
187
|
|
|
@@ -179,11 +190,12 @@ def list_passages(
|
|
|
179
190
|
def list_documents(
|
|
180
191
|
source_id: str,
|
|
181
192
|
server: "SyncServer" = Depends(get_letta_server),
|
|
193
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
182
194
|
):
|
|
183
195
|
"""
|
|
184
196
|
List all documents associated with a data source.
|
|
185
197
|
"""
|
|
186
|
-
actor = server.
|
|
198
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
187
199
|
|
|
188
200
|
documents = server.list_data_source_documents(user_id=actor.id, source_id=source_id)
|
|
189
201
|
return documents
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
|
|
3
|
-
from fastapi import APIRouter, Body, Depends, HTTPException
|
|
3
|
+
from fastapi import APIRouter, Body, Depends, Header, HTTPException
|
|
4
4
|
|
|
5
5
|
from letta.schemas.tool import Tool, ToolCreate, ToolUpdate
|
|
6
6
|
from letta.server.rest_api.utils import get_letta_server
|
|
@@ -13,11 +13,12 @@ router = APIRouter(prefix="/tools", tags=["tools"])
|
|
|
13
13
|
def delete_tool(
|
|
14
14
|
tool_id: str,
|
|
15
15
|
server: SyncServer = Depends(get_letta_server),
|
|
16
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
16
17
|
):
|
|
17
18
|
"""
|
|
18
19
|
Delete a tool by name
|
|
19
20
|
"""
|
|
20
|
-
# actor = server.
|
|
21
|
+
# actor = server.get_user_or_default(user_id=user_id)
|
|
21
22
|
server.delete_tool(tool_id=tool_id)
|
|
22
23
|
|
|
23
24
|
|
|
@@ -42,11 +43,12 @@ def get_tool(
|
|
|
42
43
|
def get_tool_id(
|
|
43
44
|
tool_name: str,
|
|
44
45
|
server: SyncServer = Depends(get_letta_server),
|
|
46
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
45
47
|
):
|
|
46
48
|
"""
|
|
47
49
|
Get a tool ID by name
|
|
48
50
|
"""
|
|
49
|
-
actor = server.
|
|
51
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
50
52
|
|
|
51
53
|
tool_id = server.get_tool_id(tool_name, user_id=actor.id)
|
|
52
54
|
if tool_id is None:
|
|
@@ -58,11 +60,12 @@ def get_tool_id(
|
|
|
58
60
|
@router.get("/", response_model=List[Tool], operation_id="list_tools")
|
|
59
61
|
def list_all_tools(
|
|
60
62
|
server: SyncServer = Depends(get_letta_server),
|
|
63
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
61
64
|
):
|
|
62
65
|
"""
|
|
63
66
|
Get a list of all tools available to agents created by a user
|
|
64
67
|
"""
|
|
65
|
-
actor = server.
|
|
68
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
66
69
|
actor.id
|
|
67
70
|
|
|
68
71
|
# TODO: add back when user-specific
|
|
@@ -75,11 +78,12 @@ def create_tool(
|
|
|
75
78
|
tool: ToolCreate = Body(...),
|
|
76
79
|
update: bool = False,
|
|
77
80
|
server: SyncServer = Depends(get_letta_server),
|
|
81
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
78
82
|
):
|
|
79
83
|
"""
|
|
80
84
|
Create a new tool
|
|
81
85
|
"""
|
|
82
|
-
actor = server.
|
|
86
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
83
87
|
|
|
84
88
|
return server.create_tool(
|
|
85
89
|
request=tool,
|
|
@@ -94,10 +98,11 @@ def update_tool(
|
|
|
94
98
|
tool_id: str,
|
|
95
99
|
request: ToolUpdate = Body(...),
|
|
96
100
|
server: SyncServer = Depends(get_letta_server),
|
|
101
|
+
user_id: str = Header(None), # Extract user_id from header, default to None if not present
|
|
97
102
|
):
|
|
98
103
|
"""
|
|
99
104
|
Update an existing tool
|
|
100
105
|
"""
|
|
101
106
|
assert tool_id == request.id, "Tool ID in path must match tool ID in request body"
|
|
102
|
-
server.
|
|
107
|
+
# actor = server.get_user_or_default(user_id=user_id)
|
|
103
108
|
return server.update_tool(request)
|
letta/server/server.py
CHANGED
|
@@ -45,6 +45,7 @@ from letta.metadata import MetadataStore
|
|
|
45
45
|
from letta.prompts import gpt_system
|
|
46
46
|
from letta.providers import (
|
|
47
47
|
AnthropicProvider,
|
|
48
|
+
AzureProvider,
|
|
48
49
|
GoogleAIProvider,
|
|
49
50
|
OllamaProvider,
|
|
50
51
|
OpenAIProvider,
|
|
@@ -270,6 +271,8 @@ class SyncServer(Server):
|
|
|
270
271
|
self._enabled_providers.append(VLLMProvider(base_url=model_settings.vllm_base_url))
|
|
271
272
|
if model_settings.gemini_api_key:
|
|
272
273
|
self._enabled_providers.append(GoogleAIProvider(api_key=model_settings.gemini_api_key))
|
|
274
|
+
if model_settings.azure_api_key and model_settings.azure_base_url:
|
|
275
|
+
self._enabled_providers.append(AzureProvider(api_key=model_settings.azure_api_key, base_url=model_settings.azure_base_url))
|
|
273
276
|
|
|
274
277
|
def save_agents(self):
|
|
275
278
|
"""Saves all the agents that are in the in-memory object store"""
|
|
@@ -1064,7 +1067,11 @@ class SyncServer(Server):
|
|
|
1064
1067
|
|
|
1065
1068
|
def get_user(self, user_id: str) -> User:
|
|
1066
1069
|
"""Get the user"""
|
|
1067
|
-
|
|
1070
|
+
user = self.ms.get_user(user_id=user_id)
|
|
1071
|
+
if user is None:
|
|
1072
|
+
raise ValueError(f"User with user_id {user_id} does not exist")
|
|
1073
|
+
else:
|
|
1074
|
+
return user
|
|
1068
1075
|
|
|
1069
1076
|
def get_agent_memory(self, agent_id: str) -> Memory:
|
|
1070
1077
|
"""Return the memory of an agent (core memory)"""
|
|
@@ -1880,20 +1887,6 @@ class SyncServer(Server):
|
|
|
1880
1887
|
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1881
1888
|
return letta_agent.retry_message()
|
|
1882
1889
|
|
|
1883
|
-
def set_current_user(self, user_id: Optional[str]):
|
|
1884
|
-
"""Very hacky way to set the current user for the server, to be replaced once server becomes stateless
|
|
1885
|
-
|
|
1886
|
-
NOTE: clearly not thread-safe, only exists to provide basic user_id support for REST API for now
|
|
1887
|
-
"""
|
|
1888
|
-
|
|
1889
|
-
# Make sure the user_id actually exists
|
|
1890
|
-
if user_id is not None:
|
|
1891
|
-
user_obj = self.get_user(user_id)
|
|
1892
|
-
if not user_obj:
|
|
1893
|
-
raise ValueError(f"User with id {user_id} not found")
|
|
1894
|
-
|
|
1895
|
-
self._current_user = user_id
|
|
1896
|
-
|
|
1897
1890
|
def get_default_user(self) -> User:
|
|
1898
1891
|
|
|
1899
1892
|
from letta.constants import (
|
|
@@ -1910,8 +1903,9 @@ class SyncServer(Server):
|
|
|
1910
1903
|
self.ms.create_organization(org)
|
|
1911
1904
|
|
|
1912
1905
|
# check if default user exists
|
|
1913
|
-
|
|
1914
|
-
|
|
1906
|
+
try:
|
|
1907
|
+
self.get_user(DEFAULT_USER_ID)
|
|
1908
|
+
except ValueError:
|
|
1915
1909
|
user = User(name=DEFAULT_USER_NAME, org_id=DEFAULT_ORG_ID, id=DEFAULT_USER_ID)
|
|
1916
1910
|
self.ms.create_user(user)
|
|
1917
1911
|
|
|
@@ -1922,23 +1916,12 @@ class SyncServer(Server):
|
|
|
1922
1916
|
# check if default org exists
|
|
1923
1917
|
return self.get_user(DEFAULT_USER_ID)
|
|
1924
1918
|
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
"""
|
|
1932
|
-
|
|
1933
|
-
# Check if _current_user is set and if it's non-null:
|
|
1934
|
-
if hasattr(self, "_current_user") and self._current_user is not None:
|
|
1935
|
-
current_user = self.get_user(self._current_user)
|
|
1936
|
-
if not current_user:
|
|
1937
|
-
warnings.warn(f"Provided user '{self._current_user}' not found, using default user")
|
|
1938
|
-
else:
|
|
1939
|
-
return current_user
|
|
1940
|
-
|
|
1941
|
-
return self.get_default_user()
|
|
1919
|
+
def get_user_or_default(self, user_id: Optional[str]) -> User:
|
|
1920
|
+
"""Get the user object for user_id if it exists, otherwise return the default user object"""
|
|
1921
|
+
if user_id is None:
|
|
1922
|
+
return self.get_default_user()
|
|
1923
|
+
else:
|
|
1924
|
+
return self.get_user(user_id=user_id)
|
|
1942
1925
|
|
|
1943
1926
|
def list_llm_models(self) -> List[LLMConfig]:
|
|
1944
1927
|
"""List available models"""
|
letta/settings.py
CHANGED
|
@@ -23,7 +23,8 @@ class ModelSettings(BaseSettings):
|
|
|
23
23
|
ollama_base_url: Optional[str] = None
|
|
24
24
|
|
|
25
25
|
# azure
|
|
26
|
-
|
|
26
|
+
azure_api_key: Optional[str] = None
|
|
27
|
+
azure_base_url: Optional[str] = None
|
|
27
28
|
|
|
28
29
|
# google ai
|
|
29
30
|
gemini_api_key: Optional[str] = None
|