letta-nightly 0.6.13.dev20250122185528__py3-none-any.whl → 0.6.14.dev20250123041709__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 +69 -100
- letta/chat_only_agent.py +1 -1
- letta/client/client.py +153 -137
- letta/constants.py +1 -8
- letta/data_sources/connectors.py +1 -1
- letta/functions/helpers.py +29 -4
- letta/functions/schema_generator.py +55 -0
- letta/llm_api/helpers.py +51 -1
- letta/memory.py +9 -7
- letta/orm/agent.py +2 -2
- letta/orm/block.py +3 -1
- letta/orm/custom_columns.py +5 -4
- letta/orm/enums.py +1 -0
- letta/orm/message.py +2 -2
- letta/orm/sqlalchemy_base.py +5 -0
- letta/schemas/agent.py +3 -3
- letta/schemas/block.py +2 -2
- letta/schemas/environment_variables.py +1 -1
- letta/schemas/job.py +1 -1
- letta/schemas/letta_base.py +6 -0
- letta/schemas/letta_message.py +6 -6
- letta/schemas/memory.py +3 -2
- letta/schemas/message.py +21 -13
- letta/schemas/passage.py +1 -1
- letta/schemas/source.py +4 -4
- letta/schemas/tool.py +38 -43
- letta/server/rest_api/app.py +1 -16
- letta/server/rest_api/routers/v1/agents.py +101 -84
- letta/server/rest_api/routers/v1/blocks.py +8 -46
- letta/server/rest_api/routers/v1/jobs.py +4 -4
- letta/server/rest_api/routers/v1/providers.py +2 -2
- letta/server/rest_api/routers/v1/runs.py +6 -6
- letta/server/rest_api/routers/v1/sources.py +8 -38
- letta/server/rest_api/routers/v1/tags.py +1 -1
- letta/server/rest_api/routers/v1/tools.py +6 -7
- letta/server/server.py +3 -3
- letta/services/agent_manager.py +43 -9
- letta/services/block_manager.py +3 -3
- letta/services/job_manager.py +5 -3
- letta/services/organization_manager.py +1 -1
- letta/services/passage_manager.py +3 -3
- letta/services/provider_manager.py +2 -2
- letta/services/sandbox_config_manager.py +2 -2
- letta/services/source_manager.py +3 -3
- letta/services/tool_execution_sandbox.py +3 -1
- letta/services/tool_manager.py +8 -3
- letta/services/user_manager.py +2 -2
- letta/settings.py +29 -0
- letta/system.py +2 -2
- {letta_nightly-0.6.13.dev20250122185528.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/METADATA +1 -1
- {letta_nightly-0.6.13.dev20250122185528.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/RECORD +55 -61
- letta/server/rest_api/routers/openai/__init__.py +0 -0
- letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
- letta/server/rest_api/routers/openai/assistants/assistants.py +0 -115
- letta/server/rest_api/routers/openai/assistants/schemas.py +0 -115
- letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
- letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -120
- {letta_nightly-0.6.13.dev20250122185528.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/LICENSE +0 -0
- {letta_nightly-0.6.13.dev20250122185528.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/WHEEL +0 -0
- {letta_nightly-0.6.13.dev20250122185528.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/entry_points.txt +0 -0
letta/client/client.py
CHANGED
|
@@ -3,6 +3,7 @@ import time
|
|
|
3
3
|
from typing import Callable, Dict, Generator, List, Optional, Union
|
|
4
4
|
|
|
5
5
|
import requests
|
|
6
|
+
from openai.types.chat.chat_completion_message_tool_call import ChatCompletionMessageToolCall as OpenAIToolCall
|
|
6
7
|
|
|
7
8
|
import letta.utils
|
|
8
9
|
from letta.constants import ADMIN_PREFIX, BASE_MEMORY_TOOLS, BASE_TOOLS, DEFAULT_HUMAN, DEFAULT_PERSONA, FUNCTION_RETURN_CHAR_LIMIT
|
|
@@ -29,7 +30,6 @@ from letta.schemas.llm_config import LLMConfig
|
|
|
29
30
|
from letta.schemas.memory import ArchivalMemorySummary, ChatMemory, CreateArchivalMemory, Memory, RecallMemorySummary
|
|
30
31
|
from letta.schemas.message import Message, MessageCreate, MessageUpdate
|
|
31
32
|
from letta.schemas.openai.chat_completion_response import UsageStatistics
|
|
32
|
-
from letta.schemas.openai.chat_completions import ToolCall
|
|
33
33
|
from letta.schemas.organization import Organization
|
|
34
34
|
from letta.schemas.passage import Passage
|
|
35
35
|
from letta.schemas.run import Run
|
|
@@ -92,19 +92,19 @@ class AbstractClient(object):
|
|
|
92
92
|
):
|
|
93
93
|
raise NotImplementedError
|
|
94
94
|
|
|
95
|
-
def get_tools_from_agent(self, agent_id: str):
|
|
95
|
+
def get_tools_from_agent(self, agent_id: str) -> List[Tool]:
|
|
96
96
|
raise NotImplementedError
|
|
97
97
|
|
|
98
|
-
def
|
|
98
|
+
def attach_tool(self, agent_id: str, tool_id: str) -> AgentState:
|
|
99
99
|
raise NotImplementedError
|
|
100
100
|
|
|
101
|
-
def
|
|
101
|
+
def detach_tool(self, agent_id: str, tool_id: str) -> AgentState:
|
|
102
102
|
raise NotImplementedError
|
|
103
103
|
|
|
104
|
-
def rename_agent(self, agent_id: str, new_name: str):
|
|
104
|
+
def rename_agent(self, agent_id: str, new_name: str) -> AgentState:
|
|
105
105
|
raise NotImplementedError
|
|
106
106
|
|
|
107
|
-
def delete_agent(self, agent_id: str):
|
|
107
|
+
def delete_agent(self, agent_id: str) -> None:
|
|
108
108
|
raise NotImplementedError
|
|
109
109
|
|
|
110
110
|
def get_agent(self, agent_id: str) -> AgentState:
|
|
@@ -218,6 +218,18 @@ class AbstractClient(object):
|
|
|
218
218
|
def get_tool_id(self, name: str) -> Optional[str]:
|
|
219
219
|
raise NotImplementedError
|
|
220
220
|
|
|
221
|
+
def list_attached_tools(self, agent_id: str) -> List[Tool]:
|
|
222
|
+
"""
|
|
223
|
+
List all tools attached to an agent.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
agent_id (str): ID of the agent
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
List[Tool]: A list of attached tools
|
|
230
|
+
"""
|
|
231
|
+
raise NotImplementedError
|
|
232
|
+
|
|
221
233
|
def upsert_base_tools(self) -> List[Tool]:
|
|
222
234
|
raise NotImplementedError
|
|
223
235
|
|
|
@@ -242,10 +254,10 @@ class AbstractClient(object):
|
|
|
242
254
|
def get_source_id(self, source_name: str) -> str:
|
|
243
255
|
raise NotImplementedError
|
|
244
256
|
|
|
245
|
-
def
|
|
257
|
+
def attach_source(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None) -> AgentState:
|
|
246
258
|
raise NotImplementedError
|
|
247
259
|
|
|
248
|
-
def
|
|
260
|
+
def detach_source(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None) -> AgentState:
|
|
249
261
|
raise NotImplementedError
|
|
250
262
|
|
|
251
263
|
def list_sources(self) -> List[Source]:
|
|
@@ -397,6 +409,26 @@ class AbstractClient(object):
|
|
|
397
409
|
"""
|
|
398
410
|
raise NotImplementedError
|
|
399
411
|
|
|
412
|
+
def attach_block(self, agent_id: str, block_id: str) -> AgentState:
|
|
413
|
+
"""
|
|
414
|
+
Attach a block to an agent.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
agent_id (str): ID of the agent
|
|
418
|
+
block_id (str): ID of the block to attach
|
|
419
|
+
"""
|
|
420
|
+
raise NotImplementedError
|
|
421
|
+
|
|
422
|
+
def detach_block(self, agent_id: str, block_id: str) -> AgentState:
|
|
423
|
+
"""
|
|
424
|
+
Detach a block from an agent.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
agent_id (str): ID of the agent
|
|
428
|
+
block_id (str): ID of the block to detach
|
|
429
|
+
"""
|
|
430
|
+
raise NotImplementedError
|
|
431
|
+
|
|
400
432
|
|
|
401
433
|
class RESTClient(AbstractClient):
|
|
402
434
|
"""
|
|
@@ -554,7 +586,7 @@ class RESTClient(AbstractClient):
|
|
|
554
586
|
# create agent
|
|
555
587
|
create_params = {
|
|
556
588
|
"description": description,
|
|
557
|
-
"
|
|
589
|
+
"metadata": metadata,
|
|
558
590
|
"memory_blocks": [],
|
|
559
591
|
"block_ids": [b.id for b in memory.get_blocks()] + block_ids,
|
|
560
592
|
"tool_ids": tool_ids,
|
|
@@ -599,7 +631,7 @@ class RESTClient(AbstractClient):
|
|
|
599
631
|
role: Optional[MessageRole] = None,
|
|
600
632
|
text: Optional[str] = None,
|
|
601
633
|
name: Optional[str] = None,
|
|
602
|
-
tool_calls: Optional[List[
|
|
634
|
+
tool_calls: Optional[List[OpenAIToolCall]] = None,
|
|
603
635
|
tool_call_id: Optional[str] = None,
|
|
604
636
|
) -> Message:
|
|
605
637
|
request = MessageUpdate(
|
|
@@ -628,7 +660,7 @@ class RESTClient(AbstractClient):
|
|
|
628
660
|
embedding_config: Optional[EmbeddingConfig] = None,
|
|
629
661
|
message_ids: Optional[List[str]] = None,
|
|
630
662
|
tags: Optional[List[str]] = None,
|
|
631
|
-
):
|
|
663
|
+
) -> AgentState:
|
|
632
664
|
"""
|
|
633
665
|
Update an existing agent
|
|
634
666
|
|
|
@@ -653,7 +685,7 @@ class RESTClient(AbstractClient):
|
|
|
653
685
|
tool_ids=tool_ids,
|
|
654
686
|
tags=tags,
|
|
655
687
|
description=description,
|
|
656
|
-
|
|
688
|
+
metadata=metadata,
|
|
657
689
|
llm_config=llm_config,
|
|
658
690
|
embedding_config=embedding_config,
|
|
659
691
|
message_ids=message_ids,
|
|
@@ -678,7 +710,7 @@ class RESTClient(AbstractClient):
|
|
|
678
710
|
raise ValueError(f"Failed to get tools from agents: {response.text}")
|
|
679
711
|
return [Tool(**tool) for tool in response.json()]
|
|
680
712
|
|
|
681
|
-
def
|
|
713
|
+
def attach_tool(self, agent_id: str, tool_id: str) -> AgentState:
|
|
682
714
|
"""
|
|
683
715
|
Add tool to an existing agent
|
|
684
716
|
|
|
@@ -689,12 +721,12 @@ class RESTClient(AbstractClient):
|
|
|
689
721
|
Returns:
|
|
690
722
|
agent_state (AgentState): State of the updated agent
|
|
691
723
|
"""
|
|
692
|
-
response = requests.patch(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
724
|
+
response = requests.patch(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/tools/attach/{tool_id}", headers=self.headers)
|
|
693
725
|
if response.status_code != 200:
|
|
694
726
|
raise ValueError(f"Failed to update agent: {response.text}")
|
|
695
727
|
return AgentState(**response.json())
|
|
696
728
|
|
|
697
|
-
def
|
|
729
|
+
def detach_tool(self, agent_id: str, tool_id: str) -> AgentState:
|
|
698
730
|
"""
|
|
699
731
|
Removes tools from an existing agent
|
|
700
732
|
|
|
@@ -706,12 +738,12 @@ class RESTClient(AbstractClient):
|
|
|
706
738
|
agent_state (AgentState): State of the updated agent
|
|
707
739
|
"""
|
|
708
740
|
|
|
709
|
-
response = requests.patch(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
741
|
+
response = requests.patch(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/tools/detach/{tool_id}", headers=self.headers)
|
|
710
742
|
if response.status_code != 200:
|
|
711
743
|
raise ValueError(f"Failed to update agent: {response.text}")
|
|
712
744
|
return AgentState(**response.json())
|
|
713
745
|
|
|
714
|
-
def rename_agent(self, agent_id: str, new_name: str):
|
|
746
|
+
def rename_agent(self, agent_id: str, new_name: str) -> AgentState:
|
|
715
747
|
"""
|
|
716
748
|
Rename an agent
|
|
717
749
|
|
|
@@ -719,10 +751,12 @@ class RESTClient(AbstractClient):
|
|
|
719
751
|
agent_id (str): ID of the agent
|
|
720
752
|
new_name (str): New name for the agent
|
|
721
753
|
|
|
754
|
+
Returns:
|
|
755
|
+
agent_state (AgentState): State of the updated agent
|
|
722
756
|
"""
|
|
723
757
|
return self.update_agent(agent_id, name=new_name)
|
|
724
758
|
|
|
725
|
-
def delete_agent(self, agent_id: str):
|
|
759
|
+
def delete_agent(self, agent_id: str) -> None:
|
|
726
760
|
"""
|
|
727
761
|
Delete an agent
|
|
728
762
|
|
|
@@ -776,7 +810,8 @@ class RESTClient(AbstractClient):
|
|
|
776
810
|
Returns:
|
|
777
811
|
memory (Memory): In-context memory of the agent
|
|
778
812
|
"""
|
|
779
|
-
|
|
813
|
+
|
|
814
|
+
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory", headers=self.headers)
|
|
780
815
|
if response.status_code != 200:
|
|
781
816
|
raise ValueError(f"Failed to get in-context memory: {response.text}")
|
|
782
817
|
return Memory(**response.json())
|
|
@@ -797,7 +832,7 @@ class RESTClient(AbstractClient):
|
|
|
797
832
|
"""
|
|
798
833
|
memory_update_dict = {section: value}
|
|
799
834
|
response = requests.patch(
|
|
800
|
-
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
835
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory", json=memory_update_dict, headers=self.headers
|
|
801
836
|
)
|
|
802
837
|
if response.status_code != 200:
|
|
803
838
|
raise ValueError(f"Failed to update in-context memory: {response.text}")
|
|
@@ -890,7 +925,7 @@ class RESTClient(AbstractClient):
|
|
|
890
925
|
if after:
|
|
891
926
|
params["after"] = str(after)
|
|
892
927
|
response = requests.get(
|
|
893
|
-
f"{self.base_url}/{self.api_prefix}/agents/{str(agent_id)}/
|
|
928
|
+
f"{self.base_url}/{self.api_prefix}/agents/{str(agent_id)}/archival-memory", params=params, headers=self.headers
|
|
894
929
|
)
|
|
895
930
|
assert response.status_code == 200, f"Failed to get archival memory: {response.text}"
|
|
896
931
|
return [Passage(**passage) for passage in response.json()]
|
|
@@ -908,7 +943,7 @@ class RESTClient(AbstractClient):
|
|
|
908
943
|
"""
|
|
909
944
|
request = CreateArchivalMemory(text=memory)
|
|
910
945
|
response = requests.post(
|
|
911
|
-
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
946
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/archival-memory", headers=self.headers, json=request.model_dump()
|
|
912
947
|
)
|
|
913
948
|
if response.status_code != 200:
|
|
914
949
|
raise ValueError(f"Failed to insert archival memory: {response.text}")
|
|
@@ -922,7 +957,7 @@ class RESTClient(AbstractClient):
|
|
|
922
957
|
agent_id (str): ID of the agent
|
|
923
958
|
memory_id (str): ID of the memory
|
|
924
959
|
"""
|
|
925
|
-
response = requests.delete(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
960
|
+
response = requests.delete(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/archival-memory/{memory_id}", headers=self.headers)
|
|
926
961
|
assert response.status_code == 200, f"Failed to delete archival memory: {response.text}"
|
|
927
962
|
|
|
928
963
|
# messages (recall memory)
|
|
@@ -1433,7 +1468,7 @@ class RESTClient(AbstractClient):
|
|
|
1433
1468
|
raise ValueError(f"Failed to update source: {response.text}")
|
|
1434
1469
|
return Source(**response.json())
|
|
1435
1470
|
|
|
1436
|
-
def
|
|
1471
|
+
def attach_source(self, source_id: str, agent_id: str) -> AgentState:
|
|
1437
1472
|
"""
|
|
1438
1473
|
Attach a source to an agent
|
|
1439
1474
|
|
|
@@ -1443,15 +1478,20 @@ class RESTClient(AbstractClient):
|
|
|
1443
1478
|
source_name (str): Name of the source
|
|
1444
1479
|
"""
|
|
1445
1480
|
params = {"agent_id": agent_id}
|
|
1446
|
-
response = requests.
|
|
1481
|
+
response = requests.patch(
|
|
1482
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/sources/attach/{source_id}", params=params, headers=self.headers
|
|
1483
|
+
)
|
|
1447
1484
|
assert response.status_code == 200, f"Failed to attach source to agent: {response.text}"
|
|
1485
|
+
return AgentState(**response.json())
|
|
1448
1486
|
|
|
1449
|
-
def detach_source(self, source_id: str, agent_id: str):
|
|
1487
|
+
def detach_source(self, source_id: str, agent_id: str) -> AgentState:
|
|
1450
1488
|
"""Detach a source from an agent"""
|
|
1451
1489
|
params = {"agent_id": str(agent_id)}
|
|
1452
|
-
response = requests.
|
|
1490
|
+
response = requests.patch(
|
|
1491
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/sources/detach/{source_id}", params=params, headers=self.headers
|
|
1492
|
+
)
|
|
1453
1493
|
assert response.status_code == 200, f"Failed to detach source from agent: {response.text}"
|
|
1454
|
-
return
|
|
1494
|
+
return AgentState(**response.json())
|
|
1455
1495
|
|
|
1456
1496
|
# tools
|
|
1457
1497
|
|
|
@@ -1474,6 +1514,21 @@ class RESTClient(AbstractClient):
|
|
|
1474
1514
|
return None
|
|
1475
1515
|
return tools[0].id
|
|
1476
1516
|
|
|
1517
|
+
def list_attached_tools(self, agent_id: str) -> List[Tool]:
|
|
1518
|
+
"""
|
|
1519
|
+
List all tools attached to an agent.
|
|
1520
|
+
|
|
1521
|
+
Args:
|
|
1522
|
+
agent_id (str): ID of the agent
|
|
1523
|
+
|
|
1524
|
+
Returns:
|
|
1525
|
+
List[Tool]: A list of attached tools
|
|
1526
|
+
"""
|
|
1527
|
+
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/tools", headers=self.headers)
|
|
1528
|
+
if response.status_code != 200:
|
|
1529
|
+
raise ValueError(f"Failed to list attached tools: {response.text}")
|
|
1530
|
+
return [Tool(**tool) for tool in response.json()]
|
|
1531
|
+
|
|
1477
1532
|
def upsert_base_tools(self) -> List[Tool]:
|
|
1478
1533
|
response = requests.post(f"{self.base_url}/{self.api_prefix}/tools/add-base-tools/", headers=self.headers)
|
|
1479
1534
|
if response.status_code != 200:
|
|
@@ -1843,66 +1898,36 @@ class RESTClient(AbstractClient):
|
|
|
1843
1898
|
block = self.get_agent_memory_block(agent_id, current_label)
|
|
1844
1899
|
return self.update_block(block.id, label=new_label)
|
|
1845
1900
|
|
|
1846
|
-
|
|
1847
|
-
def add_agent_memory_block(self, agent_id: str, create_block: CreateBlock) -> Memory:
|
|
1848
|
-
"""
|
|
1849
|
-
Create and link a memory block to an agent's core memory
|
|
1850
|
-
|
|
1851
|
-
Args:
|
|
1852
|
-
agent_id (str): The agent ID
|
|
1853
|
-
create_block (CreateBlock): The block to create
|
|
1854
|
-
|
|
1855
|
-
Returns:
|
|
1856
|
-
memory (Memory): The updated memory
|
|
1901
|
+
def attach_block(self, agent_id: str, block_id: str) -> AgentState:
|
|
1857
1902
|
"""
|
|
1858
|
-
|
|
1859
|
-
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core_memory/blocks",
|
|
1860
|
-
headers=self.headers,
|
|
1861
|
-
json=create_block.model_dump(),
|
|
1862
|
-
)
|
|
1863
|
-
if response.status_code != 200:
|
|
1864
|
-
raise ValueError(f"Failed to add agent memory block: {response.text}")
|
|
1865
|
-
return Memory(**response.json())
|
|
1866
|
-
|
|
1867
|
-
def link_agent_memory_block(self, agent_id: str, block_id: str) -> Memory:
|
|
1868
|
-
"""
|
|
1869
|
-
Link a block to an agent's core memory
|
|
1903
|
+
Attach a block to an agent.
|
|
1870
1904
|
|
|
1871
1905
|
Args:
|
|
1872
|
-
agent_id (str):
|
|
1873
|
-
block_id (str):
|
|
1874
|
-
|
|
1875
|
-
Returns:
|
|
1876
|
-
memory (Memory): The updated memory
|
|
1906
|
+
agent_id (str): ID of the agent
|
|
1907
|
+
block_id (str): ID of the block to attach
|
|
1877
1908
|
"""
|
|
1878
|
-
params = {"agent_id": agent_id}
|
|
1879
1909
|
response = requests.patch(
|
|
1880
|
-
f"{self.base_url}/{self.api_prefix}/blocks/{block_id}
|
|
1881
|
-
params=params,
|
|
1910
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks/attach/{block_id}",
|
|
1882
1911
|
headers=self.headers,
|
|
1883
1912
|
)
|
|
1884
1913
|
if response.status_code != 200:
|
|
1885
|
-
raise ValueError(f"Failed to
|
|
1886
|
-
return
|
|
1914
|
+
raise ValueError(f"Failed to attach block to agent: {response.text}")
|
|
1915
|
+
return AgentState(**response.json())
|
|
1887
1916
|
|
|
1888
|
-
def
|
|
1917
|
+
def detach_block(self, agent_id: str, block_id: str) -> AgentState:
|
|
1889
1918
|
"""
|
|
1890
|
-
|
|
1919
|
+
Detach a block from an agent.
|
|
1891
1920
|
|
|
1892
1921
|
Args:
|
|
1893
|
-
agent_id (str):
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
Returns:
|
|
1897
|
-
memory (Memory): The updated memory
|
|
1922
|
+
agent_id (str): ID of the agent
|
|
1923
|
+
block_id (str): ID of the block to detach
|
|
1898
1924
|
"""
|
|
1899
|
-
response = requests.
|
|
1900
|
-
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
1901
|
-
headers=self.headers,
|
|
1925
|
+
response = requests.patch(
|
|
1926
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks/detach/{block_id}", headers=self.headers
|
|
1902
1927
|
)
|
|
1903
1928
|
if response.status_code != 200:
|
|
1904
|
-
raise ValueError(f"Failed to
|
|
1905
|
-
return
|
|
1929
|
+
raise ValueError(f"Failed to detach block from agent: {response.text}")
|
|
1930
|
+
return AgentState(**response.json())
|
|
1906
1931
|
|
|
1907
1932
|
def list_agent_memory_blocks(self, agent_id: str) -> List[Block]:
|
|
1908
1933
|
"""
|
|
@@ -1914,7 +1939,7 @@ class RESTClient(AbstractClient):
|
|
|
1914
1939
|
Returns:
|
|
1915
1940
|
blocks (List[Block]): The blocks in the agent's core memory
|
|
1916
1941
|
"""
|
|
1917
|
-
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
1942
|
+
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks", headers=self.headers)
|
|
1918
1943
|
if response.status_code != 200:
|
|
1919
1944
|
raise ValueError(f"Failed to get agent memory blocks: {response.text}")
|
|
1920
1945
|
return [Block(**block) for block in response.json()]
|
|
@@ -1931,7 +1956,7 @@ class RESTClient(AbstractClient):
|
|
|
1931
1956
|
block (Block): The block corresponding to the label
|
|
1932
1957
|
"""
|
|
1933
1958
|
response = requests.get(
|
|
1934
|
-
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
1959
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks/{label}",
|
|
1935
1960
|
headers=self.headers,
|
|
1936
1961
|
)
|
|
1937
1962
|
if response.status_code != 200:
|
|
@@ -1964,7 +1989,7 @@ class RESTClient(AbstractClient):
|
|
|
1964
1989
|
if limit:
|
|
1965
1990
|
data["limit"] = limit
|
|
1966
1991
|
response = requests.patch(
|
|
1967
|
-
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/
|
|
1992
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks/{label}",
|
|
1968
1993
|
headers=self.headers,
|
|
1969
1994
|
json=data,
|
|
1970
1995
|
)
|
|
@@ -2307,7 +2332,7 @@ class LocalClient(AbstractClient):
|
|
|
2307
2332
|
# Create the base parameters
|
|
2308
2333
|
create_params = {
|
|
2309
2334
|
"description": description,
|
|
2310
|
-
"
|
|
2335
|
+
"metadata": metadata,
|
|
2311
2336
|
"memory_blocks": [],
|
|
2312
2337
|
"block_ids": [b.id for b in memory.get_blocks()] + block_ids,
|
|
2313
2338
|
"tool_ids": tool_ids,
|
|
@@ -2341,7 +2366,7 @@ class LocalClient(AbstractClient):
|
|
|
2341
2366
|
role: Optional[MessageRole] = None,
|
|
2342
2367
|
text: Optional[str] = None,
|
|
2343
2368
|
name: Optional[str] = None,
|
|
2344
|
-
tool_calls: Optional[List[
|
|
2369
|
+
tool_calls: Optional[List[OpenAIToolCall]] = None,
|
|
2345
2370
|
tool_call_id: Optional[str] = None,
|
|
2346
2371
|
) -> Message:
|
|
2347
2372
|
message = self.server.update_agent_message(
|
|
@@ -2389,7 +2414,7 @@ class LocalClient(AbstractClient):
|
|
|
2389
2414
|
Returns:
|
|
2390
2415
|
agent_state (AgentState): State of the updated agent
|
|
2391
2416
|
"""
|
|
2392
|
-
# TODO: add the
|
|
2417
|
+
# TODO: add the ability to reset linked block_ids
|
|
2393
2418
|
self.interface.clear()
|
|
2394
2419
|
agent_state = self.server.agent_manager.update_agent(
|
|
2395
2420
|
agent_id,
|
|
@@ -2399,7 +2424,7 @@ class LocalClient(AbstractClient):
|
|
|
2399
2424
|
tool_ids=tool_ids,
|
|
2400
2425
|
tags=tags,
|
|
2401
2426
|
description=description,
|
|
2402
|
-
|
|
2427
|
+
metadata=metadata,
|
|
2403
2428
|
llm_config=llm_config,
|
|
2404
2429
|
embedding_config=embedding_config,
|
|
2405
2430
|
message_ids=message_ids,
|
|
@@ -2421,7 +2446,7 @@ class LocalClient(AbstractClient):
|
|
|
2421
2446
|
self.interface.clear()
|
|
2422
2447
|
return self.server.agent_manager.get_agent_by_id(agent_id=agent_id, actor=self.user).tools
|
|
2423
2448
|
|
|
2424
|
-
def
|
|
2449
|
+
def attach_tool(self, agent_id: str, tool_id: str) -> AgentState:
|
|
2425
2450
|
"""
|
|
2426
2451
|
Add tool to an existing agent
|
|
2427
2452
|
|
|
@@ -2436,7 +2461,7 @@ class LocalClient(AbstractClient):
|
|
|
2436
2461
|
agent_state = self.server.agent_manager.attach_tool(agent_id=agent_id, tool_id=tool_id, actor=self.user)
|
|
2437
2462
|
return agent_state
|
|
2438
2463
|
|
|
2439
|
-
def
|
|
2464
|
+
def detach_tool(self, agent_id: str, tool_id: str) -> AgentState:
|
|
2440
2465
|
"""
|
|
2441
2466
|
Removes tools from an existing agent
|
|
2442
2467
|
|
|
@@ -2451,17 +2476,20 @@ class LocalClient(AbstractClient):
|
|
|
2451
2476
|
agent_state = self.server.agent_manager.detach_tool(agent_id=agent_id, tool_id=tool_id, actor=self.user)
|
|
2452
2477
|
return agent_state
|
|
2453
2478
|
|
|
2454
|
-
def rename_agent(self, agent_id: str, new_name: str):
|
|
2479
|
+
def rename_agent(self, agent_id: str, new_name: str) -> AgentState:
|
|
2455
2480
|
"""
|
|
2456
2481
|
Rename an agent
|
|
2457
2482
|
|
|
2458
2483
|
Args:
|
|
2459
2484
|
agent_id (str): ID of the agent
|
|
2460
2485
|
new_name (str): New name for the agent
|
|
2486
|
+
|
|
2487
|
+
Returns:
|
|
2488
|
+
agent_state (AgentState): State of the updated agent
|
|
2461
2489
|
"""
|
|
2462
|
-
self.update_agent(agent_id, name=new_name)
|
|
2490
|
+
return self.update_agent(agent_id, name=new_name)
|
|
2463
2491
|
|
|
2464
|
-
def delete_agent(self, agent_id: str):
|
|
2492
|
+
def delete_agent(self, agent_id: str) -> None:
|
|
2465
2493
|
"""
|
|
2466
2494
|
Delete an agent
|
|
2467
2495
|
|
|
@@ -2874,7 +2902,7 @@ class LocalClient(AbstractClient):
|
|
|
2874
2902
|
|
|
2875
2903
|
def load_composio_tool(self, action: "ActionType") -> Tool:
|
|
2876
2904
|
tool_create = ToolCreate.from_composio(action_name=action.name)
|
|
2877
|
-
return self.server.tool_manager.
|
|
2905
|
+
return self.server.tool_manager.create_or_update_composio_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
|
|
2878
2906
|
|
|
2879
2907
|
def create_tool(
|
|
2880
2908
|
self,
|
|
@@ -3036,6 +3064,18 @@ class LocalClient(AbstractClient):
|
|
|
3036
3064
|
tool = self.server.tool_manager.get_tool_by_name(tool_name=name, actor=self.user)
|
|
3037
3065
|
return tool.id if tool else None
|
|
3038
3066
|
|
|
3067
|
+
def list_attached_tools(self, agent_id: str) -> List[Tool]:
|
|
3068
|
+
"""
|
|
3069
|
+
List all tools attached to an agent.
|
|
3070
|
+
|
|
3071
|
+
Args:
|
|
3072
|
+
agent_id (str): ID of the agent
|
|
3073
|
+
|
|
3074
|
+
Returns:
|
|
3075
|
+
List[Tool]: List of tools attached to the agent
|
|
3076
|
+
"""
|
|
3077
|
+
return self.server.agent_manager.list_attached_tools(agent_id=agent_id, actor=self.user)
|
|
3078
|
+
|
|
3039
3079
|
def load_data(self, connector: DataConnector, source_name: str):
|
|
3040
3080
|
"""
|
|
3041
3081
|
Load data into a source
|
|
@@ -3061,7 +3101,7 @@ class LocalClient(AbstractClient):
|
|
|
3061
3101
|
job = Job(
|
|
3062
3102
|
user_id=self.user_id,
|
|
3063
3103
|
status=JobStatus.created,
|
|
3064
|
-
|
|
3104
|
+
metadata={"type": "embedding", "filename": filename, "source_id": source_id},
|
|
3065
3105
|
)
|
|
3066
3106
|
job = self.server.job_manager.create_job(pydantic_job=job, actor=self.user)
|
|
3067
3107
|
|
|
@@ -3069,14 +3109,14 @@ class LocalClient(AbstractClient):
|
|
|
3069
3109
|
self.server.load_file_to_source(source_id=source_id, file_path=filename, job_id=job.id, actor=self.user)
|
|
3070
3110
|
return job
|
|
3071
3111
|
|
|
3072
|
-
def delete_file_from_source(self, source_id: str, file_id: str):
|
|
3112
|
+
def delete_file_from_source(self, source_id: str, file_id: str) -> None:
|
|
3073
3113
|
self.server.source_manager.delete_file(file_id, actor=self.user)
|
|
3074
3114
|
|
|
3075
3115
|
def get_job(self, job_id: str):
|
|
3076
3116
|
return self.server.job_manager.get_job_by_id(job_id=job_id, actor=self.user)
|
|
3077
3117
|
|
|
3078
3118
|
def delete_job(self, job_id: str):
|
|
3079
|
-
return self.server.job_manager.
|
|
3119
|
+
return self.server.job_manager.delete_job_by_id(job_id=job_id, actor=self.user)
|
|
3080
3120
|
|
|
3081
3121
|
def list_jobs(self):
|
|
3082
3122
|
return self.server.job_manager.list_jobs(actor=self.user)
|
|
@@ -3135,7 +3175,7 @@ class LocalClient(AbstractClient):
|
|
|
3135
3175
|
"""
|
|
3136
3176
|
return self.server.source_manager.get_source_by_name(source_name=source_name, actor=self.user).id
|
|
3137
3177
|
|
|
3138
|
-
def
|
|
3178
|
+
def attach_source(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None) -> AgentState:
|
|
3139
3179
|
"""
|
|
3140
3180
|
Attach a source to an agent
|
|
3141
3181
|
|
|
@@ -3148,9 +3188,9 @@ class LocalClient(AbstractClient):
|
|
|
3148
3188
|
source = self.server.source_manager.get_source_by_id(source_id=source_id, actor=self.user)
|
|
3149
3189
|
source_id = source.id
|
|
3150
3190
|
|
|
3151
|
-
self.server.agent_manager.attach_source(source_id=source_id, agent_id=agent_id, actor=self.user)
|
|
3191
|
+
return self.server.agent_manager.attach_source(source_id=source_id, agent_id=agent_id, actor=self.user)
|
|
3152
3192
|
|
|
3153
|
-
def
|
|
3193
|
+
def detach_source(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None) -> AgentState:
|
|
3154
3194
|
"""
|
|
3155
3195
|
Detach a source from an agent by removing all `Passage` objects that were loaded from the source from archival memory.
|
|
3156
3196
|
Args:
|
|
@@ -3483,51 +3523,7 @@ class LocalClient(AbstractClient):
|
|
|
3483
3523
|
block = self.get_agent_memory_block(agent_id, current_label)
|
|
3484
3524
|
return self.update_block(block.id, label=new_label)
|
|
3485
3525
|
|
|
3486
|
-
|
|
3487
|
-
def add_agent_memory_block(self, agent_id: str, create_block: CreateBlock) -> Memory:
|
|
3488
|
-
"""
|
|
3489
|
-
Create and link a memory block to an agent's core memory
|
|
3490
|
-
|
|
3491
|
-
Args:
|
|
3492
|
-
agent_id (str): The agent ID
|
|
3493
|
-
create_block (CreateBlock): The block to create
|
|
3494
|
-
|
|
3495
|
-
Returns:
|
|
3496
|
-
memory (Memory): The updated memory
|
|
3497
|
-
"""
|
|
3498
|
-
block_req = Block(**create_block.model_dump())
|
|
3499
|
-
block = self.server.block_manager.create_or_update_block(actor=self.user, block=block_req)
|
|
3500
|
-
# Link the block to the agent
|
|
3501
|
-
agent = self.server.agent_manager.attach_block(agent_id=agent_id, block_id=block.id, actor=self.user)
|
|
3502
|
-
return agent.memory
|
|
3503
|
-
|
|
3504
|
-
def link_agent_memory_block(self, agent_id: str, block_id: str) -> Memory:
|
|
3505
|
-
"""
|
|
3506
|
-
Link a block to an agent's core memory
|
|
3507
|
-
|
|
3508
|
-
Args:
|
|
3509
|
-
agent_id (str): The agent ID
|
|
3510
|
-
block_id (str): The block ID
|
|
3511
|
-
|
|
3512
|
-
Returns:
|
|
3513
|
-
memory (Memory): The updated memory
|
|
3514
|
-
"""
|
|
3515
|
-
return self.server.agent_manager.attach_block(agent_id=agent_id, block_id=block_id, actor=self.user)
|
|
3516
|
-
|
|
3517
|
-
def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
|
|
3518
|
-
"""
|
|
3519
|
-
Unlike a block from the agent's core memory
|
|
3520
|
-
|
|
3521
|
-
Args:
|
|
3522
|
-
agent_id (str): The agent ID
|
|
3523
|
-
block_label (str): The block label
|
|
3524
|
-
|
|
3525
|
-
Returns:
|
|
3526
|
-
memory (Memory): The updated memory
|
|
3527
|
-
"""
|
|
3528
|
-
return self.server.agent_manager.detach_block_with_label(agent_id=agent_id, block_label=block_label, actor=self.user)
|
|
3529
|
-
|
|
3530
|
-
def list_agent_memory_blocks(self, agent_id: str) -> List[Block]:
|
|
3526
|
+
def get_agent_memory_blocks(self, agent_id: str) -> List[Block]:
|
|
3531
3527
|
"""
|
|
3532
3528
|
Get all the blocks in the agent's core memory
|
|
3533
3529
|
|
|
@@ -3608,6 +3604,26 @@ class LocalClient(AbstractClient):
|
|
|
3608
3604
|
data["label"] = label
|
|
3609
3605
|
return self.server.block_manager.update_block(block_id, actor=self.user, block_update=BlockUpdate(**data))
|
|
3610
3606
|
|
|
3607
|
+
def attach_block(self, agent_id: str, block_id: str) -> AgentState:
|
|
3608
|
+
"""
|
|
3609
|
+
Attach a block to an agent.
|
|
3610
|
+
|
|
3611
|
+
Args:
|
|
3612
|
+
agent_id (str): ID of the agent
|
|
3613
|
+
block_id (str): ID of the block to attach
|
|
3614
|
+
"""
|
|
3615
|
+
return self.server.agent_manager.attach_block(agent_id=agent_id, block_id=block_id, actor=self.user)
|
|
3616
|
+
|
|
3617
|
+
def detach_block(self, agent_id: str, block_id: str) -> AgentState:
|
|
3618
|
+
"""
|
|
3619
|
+
Detach a block from an agent.
|
|
3620
|
+
|
|
3621
|
+
Args:
|
|
3622
|
+
agent_id (str): ID of the agent
|
|
3623
|
+
block_id (str): ID of the block to detach
|
|
3624
|
+
"""
|
|
3625
|
+
return self.server.agent_manager.detach_block(agent_id=agent_id, block_id=block_id, actor=self.user)
|
|
3626
|
+
|
|
3611
3627
|
def get_run_messages(
|
|
3612
3628
|
self,
|
|
3613
3629
|
run_id: str,
|
letta/constants.py
CHANGED
|
@@ -125,8 +125,6 @@ LLM_MAX_TOKENS = {
|
|
|
125
125
|
"gpt-3.5-turbo-16k-0613": 16385, # legacy
|
|
126
126
|
"gpt-3.5-turbo-0301": 4096, # legacy
|
|
127
127
|
}
|
|
128
|
-
# The amount of tokens before a sytem warning about upcoming truncation is sent to Letta
|
|
129
|
-
MESSAGE_SUMMARY_WARNING_FRAC = 0.75
|
|
130
128
|
# The error message that Letta will receive
|
|
131
129
|
# MESSAGE_SUMMARY_WARNING_STR = f"Warning: the conversation history will soon reach its maximum length and be trimmed. Make sure to save any important information from the conversation to your memory before it is removed."
|
|
132
130
|
# Much longer and more specific variant of the prompt
|
|
@@ -138,15 +136,10 @@ MESSAGE_SUMMARY_WARNING_STR = " ".join(
|
|
|
138
136
|
# "Remember to pass request_heartbeat = true if you would like to send a message immediately after.",
|
|
139
137
|
]
|
|
140
138
|
)
|
|
141
|
-
|
|
142
|
-
MESSAGE_SUMMARY_TRUNC_TOKEN_FRAC = 0.75
|
|
139
|
+
|
|
143
140
|
# The ackknowledgement message used in the summarize sequence
|
|
144
141
|
MESSAGE_SUMMARY_REQUEST_ACK = "Understood, I will respond with a summary of the message (and only the summary, nothing else) once I receive the conversation history. I'm ready."
|
|
145
142
|
|
|
146
|
-
# Even when summarizing, we want to keep a handful of recent messages
|
|
147
|
-
# These serve as in-context examples of how to use functions / what user messages look like
|
|
148
|
-
MESSAGE_SUMMARY_TRUNC_KEEP_N_LAST = 3
|
|
149
|
-
|
|
150
143
|
# Maximum length of an error message
|
|
151
144
|
MAX_ERROR_MESSAGE_CHAR_LIMIT = 500
|
|
152
145
|
|
letta/data_sources/connectors.py
CHANGED
|
@@ -77,7 +77,7 @@ def load_data(connector: DataConnector, source: Source, passage_manager: Passage
|
|
|
77
77
|
text=passage_text,
|
|
78
78
|
file_id=file_metadata.id,
|
|
79
79
|
source_id=source.id,
|
|
80
|
-
|
|
80
|
+
metadata=passage_metadata,
|
|
81
81
|
organization_id=source.organization_id,
|
|
82
82
|
embedding_config=source.embedding_config,
|
|
83
83
|
embedding=embedding,
|