letta-nightly 0.6.2.dev20241210030340__py3-none-any.whl → 0.6.2.dev20241211031658__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 +32 -43
- letta/agent_store/db.py +12 -54
- letta/agent_store/storage.py +10 -9
- letta/cli/cli.py +1 -0
- letta/client/client.py +4 -3
- letta/config.py +2 -2
- letta/data_sources/connectors.py +4 -3
- letta/embeddings.py +29 -9
- letta/functions/function_sets/base.py +36 -11
- letta/metadata.py +13 -2
- letta/o1_agent.py +2 -3
- letta/offline_memory_agent.py +2 -1
- letta/orm/__init__.py +1 -0
- letta/orm/file.py +1 -0
- letta/orm/mixins.py +12 -2
- letta/orm/organization.py +3 -0
- letta/orm/passage.py +72 -0
- letta/orm/sqlalchemy_base.py +66 -10
- letta/orm/sqlite_functions.py +140 -0
- letta/orm/user.py +1 -1
- letta/schemas/agent.py +4 -3
- letta/schemas/letta_message.py +5 -1
- letta/schemas/letta_request.py +3 -3
- letta/schemas/passage.py +6 -4
- letta/schemas/sandbox_config.py +1 -0
- letta/schemas/tool_rule.py +0 -3
- letta/server/rest_api/app.py +34 -12
- letta/server/rest_api/routers/v1/agents.py +20 -7
- letta/server/server.py +76 -52
- letta/server/static_files/assets/{index-4848e3d7.js → index-048c9598.js} +1 -1
- letta/server/static_files/assets/{index-43ab4d62.css → index-0e31b727.css} +1 -1
- letta/server/static_files/index.html +2 -2
- letta/services/message_manager.py +3 -0
- letta/services/passage_manager.py +225 -0
- letta/services/source_manager.py +2 -1
- letta/services/tool_execution_sandbox.py +19 -7
- letta/settings.py +2 -0
- {letta_nightly-0.6.2.dev20241210030340.dist-info → letta_nightly-0.6.2.dev20241211031658.dist-info}/METADATA +10 -15
- {letta_nightly-0.6.2.dev20241210030340.dist-info → letta_nightly-0.6.2.dev20241211031658.dist-info}/RECORD +42 -40
- letta/agent_store/chroma.py +0 -297
- {letta_nightly-0.6.2.dev20241210030340.dist-info → letta_nightly-0.6.2.dev20241211031658.dist-info}/LICENSE +0 -0
- {letta_nightly-0.6.2.dev20241210030340.dist-info → letta_nightly-0.6.2.dev20241211031658.dist-info}/WHEEL +0 -0
- {letta_nightly-0.6.2.dev20241210030340.dist-info → letta_nightly-0.6.2.dev20241211031658.dist-info}/entry_points.txt +0 -0
letta/server/server.py
CHANGED
|
@@ -16,7 +16,6 @@ import letta.constants as constants
|
|
|
16
16
|
import letta.server.utils as server_utils
|
|
17
17
|
import letta.system as system
|
|
18
18
|
from letta.agent import Agent, save_agent
|
|
19
|
-
from letta.agent_store.db import attach_base
|
|
20
19
|
from letta.agent_store.storage import StorageConnector, TableType
|
|
21
20
|
from letta.chat_only_agent import ChatOnlyAgent
|
|
22
21
|
from letta.credentials import LettaCredentials
|
|
@@ -70,17 +69,18 @@ from letta.schemas.memory import (
|
|
|
70
69
|
)
|
|
71
70
|
from letta.schemas.message import Message, MessageCreate, MessageRole, MessageUpdate
|
|
72
71
|
from letta.schemas.organization import Organization
|
|
73
|
-
from letta.schemas.passage import Passage
|
|
72
|
+
from letta.schemas.passage import Passage as PydanticPassage
|
|
74
73
|
from letta.schemas.source import Source
|
|
75
74
|
from letta.schemas.tool import Tool, ToolCreate
|
|
76
75
|
from letta.schemas.usage import LettaUsageStatistics
|
|
77
|
-
from letta.schemas.user import User
|
|
76
|
+
from letta.schemas.user import User as PydanticUser
|
|
78
77
|
from letta.services.agents_tags_manager import AgentsTagsManager
|
|
79
78
|
from letta.services.block_manager import BlockManager
|
|
80
79
|
from letta.services.blocks_agents_manager import BlocksAgentsManager
|
|
81
80
|
from letta.services.job_manager import JobManager
|
|
82
81
|
from letta.services.message_manager import MessageManager
|
|
83
82
|
from letta.services.organization_manager import OrganizationManager
|
|
83
|
+
from letta.services.passage_manager import PassageManager
|
|
84
84
|
from letta.services.per_agent_lock_manager import PerAgentLockManager
|
|
85
85
|
from letta.services.sandbox_config_manager import SandboxConfigManager
|
|
86
86
|
from letta.services.source_manager import SourceManager
|
|
@@ -101,11 +101,6 @@ class Server(object):
|
|
|
101
101
|
"""List all available agents to a user"""
|
|
102
102
|
raise NotImplementedError
|
|
103
103
|
|
|
104
|
-
@abstractmethod
|
|
105
|
-
def get_agent_messages(self, user_id: str, agent_id: str, start: int, count: int) -> list:
|
|
106
|
-
"""Paginated query of in-context messages in agent message queue"""
|
|
107
|
-
raise NotImplementedError
|
|
108
|
-
|
|
109
104
|
@abstractmethod
|
|
110
105
|
def get_agent_memory(self, user_id: str, agent_id: str) -> dict:
|
|
111
106
|
"""Return the memory of an agent (core memory + non-core statistics)"""
|
|
@@ -130,7 +125,7 @@ class Server(object):
|
|
|
130
125
|
def create_agent(
|
|
131
126
|
self,
|
|
132
127
|
request: CreateAgent,
|
|
133
|
-
actor:
|
|
128
|
+
actor: PydanticUser,
|
|
134
129
|
# interface
|
|
135
130
|
interface: Union[AgentInterface, None] = None,
|
|
136
131
|
) -> AgentState:
|
|
@@ -171,8 +166,6 @@ from letta.settings import model_settings, settings, tool_settings
|
|
|
171
166
|
|
|
172
167
|
config = LettaConfig.load()
|
|
173
168
|
|
|
174
|
-
attach_base()
|
|
175
|
-
|
|
176
169
|
if settings.letta_pg_uri_no_default:
|
|
177
170
|
config.recall_storage_type = "postgres"
|
|
178
171
|
config.recall_storage_uri = settings.letta_pg_uri_no_default
|
|
@@ -250,6 +243,7 @@ class SyncServer(Server):
|
|
|
250
243
|
|
|
251
244
|
# Managers that interface with data models
|
|
252
245
|
self.organization_manager = OrganizationManager()
|
|
246
|
+
self.passage_manager = PassageManager()
|
|
253
247
|
self.user_manager = UserManager()
|
|
254
248
|
self.tool_manager = ToolManager()
|
|
255
249
|
self.block_manager = BlockManager()
|
|
@@ -384,6 +378,8 @@ class SyncServer(Server):
|
|
|
384
378
|
interface = interface or self.default_interface_factory()
|
|
385
379
|
if agent_state.agent_type == AgentType.memgpt_agent:
|
|
386
380
|
agent = Agent(agent_state=agent_state, interface=interface, user=actor, initial_message_sequence=initial_message_sequence)
|
|
381
|
+
elif agent_state.agent_type == AgentType.offline_memory_agent:
|
|
382
|
+
agent = OfflineMemoryAgent(agent_state=agent_state, interface=interface, user=actor, initial_message_sequence=initial_message_sequence)
|
|
387
383
|
else:
|
|
388
384
|
assert initial_message_sequence is None, f"Initial message sequence is not supported for O1Agents"
|
|
389
385
|
agent = O1Agent(agent_state=agent_state, interface=interface, user=actor)
|
|
@@ -501,7 +497,12 @@ class SyncServer(Server):
|
|
|
501
497
|
|
|
502
498
|
# attach data to agent from source
|
|
503
499
|
source_connector = StorageConnector.get_storage_connector(TableType.PASSAGES, self.config, user_id=user_id)
|
|
504
|
-
letta_agent.attach_source(
|
|
500
|
+
letta_agent.attach_source(
|
|
501
|
+
user=self.user_manager.get_user_by_id(user_id=user_id),
|
|
502
|
+
source_id=data_source,
|
|
503
|
+
source_manager=letta_agent.source_manager,
|
|
504
|
+
ms=self.ms
|
|
505
|
+
)
|
|
505
506
|
|
|
506
507
|
elif command.lower() == "dump" or command.lower().startswith("dump "):
|
|
507
508
|
# Check if there's an additional argument that's an integer
|
|
@@ -516,7 +517,7 @@ class SyncServer(Server):
|
|
|
516
517
|
letta_agent.interface.print_messages_raw(letta_agent.messages)
|
|
517
518
|
|
|
518
519
|
elif command.lower() == "memory":
|
|
519
|
-
ret_str = f"\nDumping memory contents:\n" + f"\n{str(letta_agent.agent_state.memory)}" + f"\n{str(letta_agent.
|
|
520
|
+
ret_str = f"\nDumping memory contents:\n" + f"\n{str(letta_agent.agent_state.memory)}" + f"\n{str(letta_agent.passage_manager)}"
|
|
520
521
|
return ret_str
|
|
521
522
|
|
|
522
523
|
elif command.lower() == "pop" or command.lower().startswith("pop "):
|
|
@@ -772,7 +773,7 @@ class SyncServer(Server):
|
|
|
772
773
|
def create_agent(
|
|
773
774
|
self,
|
|
774
775
|
request: CreateAgent,
|
|
775
|
-
actor:
|
|
776
|
+
actor: PydanticUser,
|
|
776
777
|
# interface
|
|
777
778
|
interface: Union[AgentInterface, None] = None,
|
|
778
779
|
) -> AgentState:
|
|
@@ -829,6 +830,12 @@ class SyncServer(Server):
|
|
|
829
830
|
if not user:
|
|
830
831
|
raise ValueError(f"cannot find user with associated client id: {user_id}")
|
|
831
832
|
|
|
833
|
+
if request.llm_config is None:
|
|
834
|
+
raise ValueError("llm_config is required")
|
|
835
|
+
|
|
836
|
+
if request.embedding_config is None:
|
|
837
|
+
raise ValueError("embedding_config is required")
|
|
838
|
+
|
|
832
839
|
# created and persist the agent state in the DB
|
|
833
840
|
agent_state = PersistedAgentState(
|
|
834
841
|
name=request.name,
|
|
@@ -848,7 +855,7 @@ class SyncServer(Server):
|
|
|
848
855
|
self.ms.create_agent(agent_state)
|
|
849
856
|
|
|
850
857
|
# create the agent object
|
|
851
|
-
if request.initial_message_sequence:
|
|
858
|
+
if request.initial_message_sequence is not None:
|
|
852
859
|
# init_messages = [Message(user_id=user_id, agent_id=agent_state.id, role=message.role, text=message.text) for message in request.initial_message_sequence]
|
|
853
860
|
init_messages = []
|
|
854
861
|
for message in request.initial_message_sequence:
|
|
@@ -918,6 +925,7 @@ class SyncServer(Server):
|
|
|
918
925
|
|
|
919
926
|
# get `Tool` objects
|
|
920
927
|
tools = [self.tool_manager.get_tool_by_name(tool_name=tool_name, actor=user) for tool_name in agent_state.tool_names]
|
|
928
|
+
tools = [tool for tool in tools if tool is not None]
|
|
921
929
|
|
|
922
930
|
# get `Source` objects
|
|
923
931
|
sources = self.list_attached_sources(agent_id=agent_id)
|
|
@@ -931,7 +939,7 @@ class SyncServer(Server):
|
|
|
931
939
|
def update_agent(
|
|
932
940
|
self,
|
|
933
941
|
request: UpdateAgentState,
|
|
934
|
-
actor:
|
|
942
|
+
actor: PydanticUser,
|
|
935
943
|
) -> AgentState:
|
|
936
944
|
"""Update the agents core memory block, return the new state"""
|
|
937
945
|
try:
|
|
@@ -1148,7 +1156,7 @@ class SyncServer(Server):
|
|
|
1148
1156
|
|
|
1149
1157
|
def get_archival_memory_summary(self, agent_id: str) -> ArchivalMemorySummary:
|
|
1150
1158
|
agent = self.load_agent(agent_id=agent_id)
|
|
1151
|
-
return ArchivalMemorySummary(size=
|
|
1159
|
+
return ArchivalMemorySummary(size=agent.passage_manager.size(actor=self.default_user))
|
|
1152
1160
|
|
|
1153
1161
|
def get_recall_memory_summary(self, agent_id: str) -> RecallMemorySummary:
|
|
1154
1162
|
agent = self.load_agent(agent_id=agent_id)
|
|
@@ -1222,7 +1230,7 @@ class SyncServer(Server):
|
|
|
1222
1230
|
|
|
1223
1231
|
return messages
|
|
1224
1232
|
|
|
1225
|
-
def get_agent_archival(self, user_id: str, agent_id: str,
|
|
1233
|
+
def get_agent_archival(self, user_id: str, agent_id: str, cursor: Optional[str] = None, limit: int = 50) -> List[PydanticPassage]:
|
|
1226
1234
|
"""Paginated query of all messages in agent archival memory"""
|
|
1227
1235
|
if self.user_manager.get_user_by_id(user_id=user_id) is None:
|
|
1228
1236
|
raise ValueError(f"User user_id={user_id} does not exist")
|
|
@@ -1233,22 +1241,22 @@ class SyncServer(Server):
|
|
|
1233
1241
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1234
1242
|
|
|
1235
1243
|
# iterate over records
|
|
1236
|
-
|
|
1244
|
+
records = letta_agent.passage_manager.list_passages(
|
|
1245
|
+
actor=self.default_user,
|
|
1246
|
+
agent_id=agent_id,
|
|
1247
|
+
cursor=cursor,
|
|
1248
|
+
limit=limit,
|
|
1249
|
+
)
|
|
1237
1250
|
|
|
1238
|
-
|
|
1239
|
-
page = next(db_iterator, [])
|
|
1240
|
-
return page
|
|
1251
|
+
return records
|
|
1241
1252
|
|
|
1242
1253
|
def get_agent_archival_cursor(
|
|
1243
1254
|
self,
|
|
1244
1255
|
user_id: str,
|
|
1245
1256
|
agent_id: str,
|
|
1246
|
-
|
|
1247
|
-
before: Optional[str] = None,
|
|
1257
|
+
cursor: Optional[str] = None,
|
|
1248
1258
|
limit: Optional[int] = 100,
|
|
1249
|
-
|
|
1250
|
-
reverse: Optional[bool] = False,
|
|
1251
|
-
) -> List[Passage]:
|
|
1259
|
+
) -> List[PydanticPassage]:
|
|
1252
1260
|
if self.user_manager.get_user_by_id(user_id=user_id) is None:
|
|
1253
1261
|
raise LettaUserNotFoundError(f"User user_id={user_id} does not exist")
|
|
1254
1262
|
if self.ms.get_agent(agent_id=agent_id, user_id=user_id) is None:
|
|
@@ -1257,14 +1265,15 @@ class SyncServer(Server):
|
|
|
1257
1265
|
# Get the agent object (loaded in memory)
|
|
1258
1266
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1259
1267
|
|
|
1260
|
-
# iterate over
|
|
1261
|
-
|
|
1262
|
-
|
|
1268
|
+
# iterate over records
|
|
1269
|
+
records = letta_agent.passage_manager.list_passages(
|
|
1270
|
+
actor=self.default_user, agent_id=agent_id, cursor=cursor, limit=limit,
|
|
1263
1271
|
)
|
|
1264
1272
|
return records
|
|
1265
1273
|
|
|
1266
|
-
def insert_archival_memory(self, user_id: str, agent_id: str, memory_contents: str) -> List[
|
|
1267
|
-
|
|
1274
|
+
def insert_archival_memory(self, user_id: str, agent_id: str, memory_contents: str) -> List[PydanticPassage]:
|
|
1275
|
+
actor = self.user_manager.get_user_by_id(user_id=user_id)
|
|
1276
|
+
if actor is None:
|
|
1268
1277
|
raise ValueError(f"User user_id={user_id} does not exist")
|
|
1269
1278
|
if self.ms.get_agent(agent_id=agent_id, user_id=user_id) is None:
|
|
1270
1279
|
raise ValueError(f"Agent agent_id={agent_id} does not exist")
|
|
@@ -1273,17 +1282,20 @@ class SyncServer(Server):
|
|
|
1273
1282
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1274
1283
|
|
|
1275
1284
|
# Insert into archival memory
|
|
1276
|
-
passage_ids =
|
|
1285
|
+
passage_ids = self.passage_manager.insert_passage(
|
|
1286
|
+
agent_state=letta_agent.agent_state, agent_id=agent_id, text=memory_contents, actor=actor, return_ids=True
|
|
1287
|
+
)
|
|
1277
1288
|
|
|
1278
1289
|
# Update the agent
|
|
1279
1290
|
# TODO: should this update the system prompt?
|
|
1280
1291
|
save_agent(letta_agent, self.ms)
|
|
1281
1292
|
|
|
1282
1293
|
# TODO: this is gross, fix
|
|
1283
|
-
return [
|
|
1294
|
+
return [self.passage_manager.get_passage_by_id(passage_id=passage_id, actor=actor) for passage_id in passage_ids]
|
|
1284
1295
|
|
|
1285
1296
|
def delete_archival_memory(self, user_id: str, agent_id: str, memory_id: str):
|
|
1286
|
-
|
|
1297
|
+
actor = self.user_manager.get_user_by_id(user_id=user_id)
|
|
1298
|
+
if actor is None:
|
|
1287
1299
|
raise ValueError(f"User user_id={user_id} does not exist")
|
|
1288
1300
|
if self.ms.get_agent(agent_id=agent_id, user_id=user_id) is None:
|
|
1289
1301
|
raise ValueError(f"Agent agent_id={agent_id} does not exist")
|
|
@@ -1295,7 +1307,7 @@ class SyncServer(Server):
|
|
|
1295
1307
|
|
|
1296
1308
|
# Delete by ID
|
|
1297
1309
|
# TODO check if it exists first, and throw error if not
|
|
1298
|
-
letta_agent.
|
|
1310
|
+
letta_agent.passage_manager.delete_passage_by_id(passage_id=memory_id, actor=actor)
|
|
1299
1311
|
|
|
1300
1312
|
# TODO: return archival memory
|
|
1301
1313
|
|
|
@@ -1303,7 +1315,8 @@ class SyncServer(Server):
|
|
|
1303
1315
|
self,
|
|
1304
1316
|
user_id: str,
|
|
1305
1317
|
agent_id: str,
|
|
1306
|
-
|
|
1318
|
+
after: Optional[str] = None,
|
|
1319
|
+
before: Optional[str] = None,
|
|
1307
1320
|
limit: Optional[int] = 100,
|
|
1308
1321
|
reverse: Optional[bool] = False,
|
|
1309
1322
|
return_message_object: bool = True,
|
|
@@ -1320,12 +1333,15 @@ class SyncServer(Server):
|
|
|
1320
1333
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1321
1334
|
|
|
1322
1335
|
# iterate over records
|
|
1323
|
-
|
|
1336
|
+
start_date = self.message_manager.get_message_by_id(after, actor=actor).created_at if after else None
|
|
1337
|
+
end_date = self.message_manager.get_message_by_id(before, actor=actor).created_at if before else None
|
|
1324
1338
|
records = letta_agent.message_manager.list_messages_for_agent(
|
|
1325
1339
|
agent_id=agent_id,
|
|
1326
1340
|
actor=actor,
|
|
1327
|
-
|
|
1341
|
+
start_date=start_date,
|
|
1342
|
+
end_date=end_date,
|
|
1328
1343
|
limit=limit,
|
|
1344
|
+
ascending=not reverse,
|
|
1329
1345
|
)
|
|
1330
1346
|
|
|
1331
1347
|
assert all(isinstance(m, Message) for m in records)
|
|
@@ -1437,6 +1453,12 @@ class SyncServer(Server):
|
|
|
1437
1453
|
except NoResultFound:
|
|
1438
1454
|
logger.error(f"Agent with id {agent_state.id} has nonexistent user {agent_state.user_id}")
|
|
1439
1455
|
|
|
1456
|
+
# delete all passages associated with this agent
|
|
1457
|
+
# TODO: REMOVE THIS ONCE WE MIGRATE AGENTMODEL TO ORM
|
|
1458
|
+
passages = self.passage_manager.list_passages(actor=actor, agent_id=agent_state.id)
|
|
1459
|
+
for passage in passages:
|
|
1460
|
+
self.passage_manager.delete_passage_by_id(passage.id, actor=actor)
|
|
1461
|
+
|
|
1440
1462
|
# First, if the agent is in the in-memory cache we should remove it
|
|
1441
1463
|
# List of {'user_id': user_id, 'agent_id': agent_id, 'agent': agent_obj} dicts
|
|
1442
1464
|
try:
|
|
@@ -1479,7 +1501,7 @@ class SyncServer(Server):
|
|
|
1479
1501
|
self.ms.delete_api_key(api_key=api_key)
|
|
1480
1502
|
return api_key_obj
|
|
1481
1503
|
|
|
1482
|
-
def delete_source(self, source_id: str, actor:
|
|
1504
|
+
def delete_source(self, source_id: str, actor: PydanticUser):
|
|
1483
1505
|
"""Delete a data source"""
|
|
1484
1506
|
self.source_manager.delete_source(source_id=source_id, actor=actor)
|
|
1485
1507
|
|
|
@@ -1489,7 +1511,7 @@ class SyncServer(Server):
|
|
|
1489
1511
|
|
|
1490
1512
|
# TODO: delete data from agent passage stores (?)
|
|
1491
1513
|
|
|
1492
|
-
def load_file_to_source(self, source_id: str, file_path: str, job_id: str, actor:
|
|
1514
|
+
def load_file_to_source(self, source_id: str, file_path: str, job_id: str, actor: PydanticUser) -> Job:
|
|
1493
1515
|
|
|
1494
1516
|
# update job
|
|
1495
1517
|
job = self.job_manager.get_job_by_id(job_id, actor=actor)
|
|
@@ -1516,6 +1538,7 @@ class SyncServer(Server):
|
|
|
1516
1538
|
user_id: str,
|
|
1517
1539
|
connector: DataConnector,
|
|
1518
1540
|
source_name: str,
|
|
1541
|
+
agent_id: Optional[str] = None,
|
|
1519
1542
|
) -> Tuple[int, int]:
|
|
1520
1543
|
"""Load data from a DataConnector into a source for a specified user_id"""
|
|
1521
1544
|
# TODO: this should be implemented as a batch job or at least async, since it may take a long time
|
|
@@ -1530,14 +1553,13 @@ class SyncServer(Server):
|
|
|
1530
1553
|
passage_store = StorageConnector.get_storage_connector(TableType.PASSAGES, self.config, user_id=user_id)
|
|
1531
1554
|
|
|
1532
1555
|
# load data into the document store
|
|
1533
|
-
passage_count, document_count = load_data(connector, source, passage_store, self.source_manager, actor=user)
|
|
1556
|
+
passage_count, document_count = load_data(connector, source, passage_store, self.source_manager, actor=user, agent_id=agent_id)
|
|
1534
1557
|
return passage_count, document_count
|
|
1535
1558
|
|
|
1536
1559
|
def attach_source_to_agent(
|
|
1537
1560
|
self,
|
|
1538
1561
|
user_id: str,
|
|
1539
1562
|
agent_id: str,
|
|
1540
|
-
# source_id: str,
|
|
1541
1563
|
source_id: Optional[str] = None,
|
|
1542
1564
|
source_name: Optional[str] = None,
|
|
1543
1565
|
) -> Source:
|
|
@@ -1549,15 +1571,14 @@ class SyncServer(Server):
|
|
|
1549
1571
|
data_source = self.source_manager.get_source_by_name(source_name=source_name, actor=user)
|
|
1550
1572
|
else:
|
|
1551
1573
|
raise ValueError(f"Need to provide at least source_id or source_name to find the source.")
|
|
1552
|
-
|
|
1553
|
-
source_connector = StorageConnector.get_storage_connector(TableType.PASSAGES, self.config, user_id=user_id)
|
|
1574
|
+
|
|
1554
1575
|
assert data_source, f"Data source with id={source_id} or name={source_name} does not exist"
|
|
1555
1576
|
|
|
1556
1577
|
# load agent
|
|
1557
1578
|
agent = self.load_agent(agent_id=agent_id)
|
|
1558
1579
|
|
|
1559
1580
|
# attach source to agent
|
|
1560
|
-
agent.attach_source(data_source.id,
|
|
1581
|
+
agent.attach_source(user=user, source_id=data_source.id, source_manager=self.source_manager, ms=self.ms)
|
|
1561
1582
|
|
|
1562
1583
|
return data_source
|
|
1563
1584
|
|
|
@@ -1580,8 +1601,7 @@ class SyncServer(Server):
|
|
|
1580
1601
|
|
|
1581
1602
|
# delete all Passage objects with source_id==source_id from agent's archival memory
|
|
1582
1603
|
agent = self.load_agent(agent_id=agent_id)
|
|
1583
|
-
|
|
1584
|
-
archival_memory.storage.delete({"source_id": source_id})
|
|
1604
|
+
agent.passage_manager.delete_passages(actor=user, limit=100, source_id=source_id)
|
|
1585
1605
|
|
|
1586
1606
|
# delete agent-source mapping
|
|
1587
1607
|
self.ms.detach_source(agent_id=agent_id, source_id=source_id)
|
|
@@ -1595,11 +1615,11 @@ class SyncServer(Server):
|
|
|
1595
1615
|
|
|
1596
1616
|
return [self.source_manager.get_source_by_id(source_id=id) for id in source_ids]
|
|
1597
1617
|
|
|
1598
|
-
def list_data_source_passages(self, user_id: str, source_id: str) -> List[
|
|
1618
|
+
def list_data_source_passages(self, user_id: str, source_id: str) -> List[PydanticPassage]:
|
|
1599
1619
|
warnings.warn("list_data_source_passages is not yet implemented, returning empty list.", category=UserWarning)
|
|
1600
1620
|
return []
|
|
1601
1621
|
|
|
1602
|
-
def list_all_sources(self, actor:
|
|
1622
|
+
def list_all_sources(self, actor: PydanticUser) -> List[Source]:
|
|
1603
1623
|
"""List all sources (w/ extra metadata) belonging to a user"""
|
|
1604
1624
|
|
|
1605
1625
|
sources = self.source_manager.list_sources(actor=actor)
|
|
@@ -1639,7 +1659,7 @@ class SyncServer(Server):
|
|
|
1639
1659
|
|
|
1640
1660
|
return sources_with_metadata
|
|
1641
1661
|
|
|
1642
|
-
def add_default_external_tools(self, actor:
|
|
1662
|
+
def add_default_external_tools(self, actor: PydanticUser) -> bool:
|
|
1643
1663
|
"""Add default langchain tools. Return true if successful, false otherwise."""
|
|
1644
1664
|
success = True
|
|
1645
1665
|
tool_creates = ToolCreate.load_default_langchain_tools()
|
|
@@ -1696,7 +1716,7 @@ class SyncServer(Server):
|
|
|
1696
1716
|
save_agent(letta_agent, self.ms)
|
|
1697
1717
|
return response
|
|
1698
1718
|
|
|
1699
|
-
def get_user_or_default(self, user_id: Optional[str]) ->
|
|
1719
|
+
def get_user_or_default(self, user_id: Optional[str]) -> PydanticUser:
|
|
1700
1720
|
"""Get the user object for user_id if it exists, otherwise return the default user object"""
|
|
1701
1721
|
if user_id is None:
|
|
1702
1722
|
user_id = self.user_manager.DEFAULT_USER_ID
|
|
@@ -1877,6 +1897,8 @@ class SyncServer(Server):
|
|
|
1877
1897
|
date=get_utc_time(),
|
|
1878
1898
|
status="success",
|
|
1879
1899
|
function_return=function_response,
|
|
1900
|
+
stdout=sandbox_run_result.stdout,
|
|
1901
|
+
stderr=sandbox_run_result.stderr,
|
|
1880
1902
|
)
|
|
1881
1903
|
except Exception as e:
|
|
1882
1904
|
# same as agent.py
|
|
@@ -1892,6 +1914,8 @@ class SyncServer(Server):
|
|
|
1892
1914
|
date=get_utc_time(),
|
|
1893
1915
|
status="error",
|
|
1894
1916
|
function_return=error_msg,
|
|
1917
|
+
stdout=[''],
|
|
1918
|
+
stderr=[traceback.format_exc()],
|
|
1895
1919
|
)
|
|
1896
1920
|
|
|
1897
1921
|
# Composio wrappers
|