letta-nightly 0.6.12.dev20250122104013__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.

Files changed (61) hide show
  1. letta/__init__.py +2 -2
  2. letta/agent.py +69 -100
  3. letta/chat_only_agent.py +1 -1
  4. letta/client/client.py +169 -149
  5. letta/constants.py +1 -8
  6. letta/data_sources/connectors.py +1 -1
  7. letta/functions/helpers.py +29 -4
  8. letta/functions/schema_generator.py +55 -0
  9. letta/llm_api/helpers.py +51 -1
  10. letta/memory.py +9 -7
  11. letta/orm/agent.py +2 -2
  12. letta/orm/block.py +3 -1
  13. letta/orm/custom_columns.py +5 -4
  14. letta/orm/enums.py +1 -0
  15. letta/orm/message.py +2 -2
  16. letta/orm/sqlalchemy_base.py +5 -0
  17. letta/schemas/agent.py +13 -13
  18. letta/schemas/block.py +2 -2
  19. letta/schemas/environment_variables.py +1 -1
  20. letta/schemas/job.py +1 -1
  21. letta/schemas/letta_base.py +6 -0
  22. letta/schemas/letta_message.py +6 -6
  23. letta/schemas/memory.py +3 -2
  24. letta/schemas/message.py +21 -13
  25. letta/schemas/passage.py +1 -1
  26. letta/schemas/source.py +4 -4
  27. letta/schemas/tool.py +38 -43
  28. letta/server/rest_api/app.py +1 -16
  29. letta/server/rest_api/routers/v1/agents.py +95 -118
  30. letta/server/rest_api/routers/v1/blocks.py +8 -46
  31. letta/server/rest_api/routers/v1/jobs.py +4 -4
  32. letta/server/rest_api/routers/v1/providers.py +2 -2
  33. letta/server/rest_api/routers/v1/runs.py +6 -6
  34. letta/server/rest_api/routers/v1/sources.py +8 -38
  35. letta/server/rest_api/routers/v1/tags.py +1 -1
  36. letta/server/rest_api/routers/v1/tools.py +6 -24
  37. letta/server/server.py +6 -6
  38. letta/services/agent_manager.py +43 -9
  39. letta/services/block_manager.py +3 -3
  40. letta/services/job_manager.py +5 -3
  41. letta/services/organization_manager.py +1 -1
  42. letta/services/passage_manager.py +3 -3
  43. letta/services/provider_manager.py +2 -2
  44. letta/services/sandbox_config_manager.py +2 -2
  45. letta/services/source_manager.py +3 -3
  46. letta/services/tool_execution_sandbox.py +3 -1
  47. letta/services/tool_manager.py +8 -3
  48. letta/services/user_manager.py +2 -2
  49. letta/settings.py +29 -0
  50. letta/system.py +2 -2
  51. {letta_nightly-0.6.12.dev20250122104013.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/METADATA +1 -1
  52. {letta_nightly-0.6.12.dev20250122104013.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/RECORD +55 -61
  53. letta/server/rest_api/routers/openai/__init__.py +0 -0
  54. letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
  55. letta/server/rest_api/routers/openai/assistants/assistants.py +0 -115
  56. letta/server/rest_api/routers/openai/assistants/schemas.py +0 -115
  57. letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
  58. letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -120
  59. {letta_nightly-0.6.12.dev20250122104013.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/LICENSE +0 -0
  60. {letta_nightly-0.6.12.dev20250122104013.dist-info → letta_nightly-0.6.14.dev20250123041709.dist-info}/WHEEL +0 -0
  61. {letta_nightly-0.6.12.dev20250122104013.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 add_tool_to_agent(self, agent_id: str, tool_id: str):
98
+ def attach_tool(self, agent_id: str, tool_id: str) -> AgentState:
99
99
  raise NotImplementedError
100
100
 
101
- def remove_tool_from_agent(self, agent_id: str, tool_id: str):
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 attach_source_to_agent(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None):
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 detach_source_from_agent(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None):
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
- "metadata_": metadata,
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[ToolCall]] = None,
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
- metadata_=metadata,
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 add_tool_to_agent(self, agent_id: str, tool_id: str):
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}/add-tool/{tool_id}", headers=self.headers)
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 remove_tool_from_agent(self, agent_id: str, tool_id: str):
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}/remove-tool/{tool_id}", headers=self.headers)
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
- response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory", headers=self.headers)
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}/memory", json=memory_update_dict, headers=self.headers
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}")
@@ -814,10 +849,10 @@ class RESTClient(AbstractClient):
814
849
  summary (ArchivalMemorySummary): Summary of the archival memory
815
850
 
816
851
  """
817
- response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/archival", headers=self.headers)
852
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/context", headers=self.headers)
818
853
  if response.status_code != 200:
819
854
  raise ValueError(f"Failed to get archival memory summary: {response.text}")
820
- return ArchivalMemorySummary(**response.json())
855
+ return ArchivalMemorySummary(size=response.json().get("num_archival_memory", 0))
821
856
 
822
857
  def get_recall_memory_summary(self, agent_id: str) -> RecallMemorySummary:
823
858
  """
@@ -829,10 +864,10 @@ class RESTClient(AbstractClient):
829
864
  Returns:
830
865
  summary (RecallMemorySummary): Summary of the recall memory
831
866
  """
832
- response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/recall", headers=self.headers)
867
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/context", headers=self.headers)
833
868
  if response.status_code != 200:
834
869
  raise ValueError(f"Failed to get recall memory summary: {response.text}")
835
- return RecallMemorySummary(**response.json())
870
+ return RecallMemorySummary(size=response.json().get("num_recall_memory", 0))
836
871
 
837
872
  def get_in_context_messages(self, agent_id: str) -> List[Message]:
838
873
  """
@@ -844,10 +879,10 @@ class RESTClient(AbstractClient):
844
879
  Returns:
845
880
  messages (List[Message]): List of in-context messages
846
881
  """
847
- response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/messages", headers=self.headers)
882
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/context", headers=self.headers)
848
883
  if response.status_code != 200:
849
- raise ValueError(f"Failed to get in-context messages: {response.text}")
850
- return [Message(**message) for message in response.json()]
884
+ raise ValueError(f"Failed to get recall memory summary: {response.text}")
885
+ return [Message(**message) for message in response.json().get("messages", "")]
851
886
 
852
887
  # agent interactions
853
888
 
@@ -889,7 +924,9 @@ class RESTClient(AbstractClient):
889
924
  params["before"] = str(before)
890
925
  if after:
891
926
  params["after"] = str(after)
892
- response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{str(agent_id)}/archival", params=params, headers=self.headers)
927
+ response = requests.get(
928
+ f"{self.base_url}/{self.api_prefix}/agents/{str(agent_id)}/archival-memory", params=params, headers=self.headers
929
+ )
893
930
  assert response.status_code == 200, f"Failed to get archival memory: {response.text}"
894
931
  return [Passage(**passage) for passage in response.json()]
895
932
 
@@ -906,7 +943,7 @@ class RESTClient(AbstractClient):
906
943
  """
907
944
  request = CreateArchivalMemory(text=memory)
908
945
  response = requests.post(
909
- f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/archival", headers=self.headers, json=request.model_dump()
946
+ f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/archival-memory", headers=self.headers, json=request.model_dump()
910
947
  )
911
948
  if response.status_code != 200:
912
949
  raise ValueError(f"Failed to insert archival memory: {response.text}")
@@ -920,7 +957,7 @@ class RESTClient(AbstractClient):
920
957
  agent_id (str): ID of the agent
921
958
  memory_id (str): ID of the memory
922
959
  """
923
- response = requests.delete(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/archival/{memory_id}", headers=self.headers)
960
+ response = requests.delete(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/archival-memory/{memory_id}", headers=self.headers)
924
961
  assert response.status_code == 200, f"Failed to delete archival memory: {response.text}"
925
962
 
926
963
  # messages (recall memory)
@@ -1431,7 +1468,7 @@ class RESTClient(AbstractClient):
1431
1468
  raise ValueError(f"Failed to update source: {response.text}")
1432
1469
  return Source(**response.json())
1433
1470
 
1434
- def attach_source_to_agent(self, source_id: str, agent_id: str):
1471
+ def attach_source(self, source_id: str, agent_id: str) -> AgentState:
1435
1472
  """
1436
1473
  Attach a source to an agent
1437
1474
 
@@ -1441,15 +1478,20 @@ class RESTClient(AbstractClient):
1441
1478
  source_name (str): Name of the source
1442
1479
  """
1443
1480
  params = {"agent_id": agent_id}
1444
- response = requests.post(f"{self.base_url}/{self.api_prefix}/sources/{source_id}/attach", params=params, headers=self.headers)
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
+ )
1445
1484
  assert response.status_code == 200, f"Failed to attach source to agent: {response.text}"
1485
+ return AgentState(**response.json())
1446
1486
 
1447
- def detach_source(self, source_id: str, agent_id: str):
1487
+ def detach_source(self, source_id: str, agent_id: str) -> AgentState:
1448
1488
  """Detach a source from an agent"""
1449
1489
  params = {"agent_id": str(agent_id)}
1450
- response = requests.post(f"{self.base_url}/{self.api_prefix}/sources/{source_id}/detach", params=params, headers=self.headers)
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
+ )
1451
1493
  assert response.status_code == 200, f"Failed to detach source from agent: {response.text}"
1452
- return Source(**response.json())
1494
+ return AgentState(**response.json())
1453
1495
 
1454
1496
  # tools
1455
1497
 
@@ -1463,12 +1505,29 @@ class RESTClient(AbstractClient):
1463
1505
  Returns:
1464
1506
  id (str): ID of the tool (`None` if not found)
1465
1507
  """
1466
- response = requests.get(f"{self.base_url}/{self.api_prefix}/tools/name/{tool_name}", headers=self.headers)
1467
- if response.status_code == 404:
1468
- return None
1469
- elif response.status_code != 200:
1508
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/tools", headers=self.headers)
1509
+ if response.status_code != 200:
1470
1510
  raise ValueError(f"Failed to get tool: {response.text}")
1471
- return response.json()
1511
+
1512
+ tools = [tool for tool in [Tool(**tool) for tool in response.json()] if tool.name == tool_name]
1513
+ if not tools:
1514
+ return None
1515
+ return tools[0].id
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()]
1472
1531
 
1473
1532
  def upsert_base_tools(self) -> List[Tool]:
1474
1533
  response = requests.post(f"{self.base_url}/{self.api_prefix}/tools/add-base-tools/", headers=self.headers)
@@ -1839,68 +1898,38 @@ class RESTClient(AbstractClient):
1839
1898
  block = self.get_agent_memory_block(agent_id, current_label)
1840
1899
  return self.update_block(block.id, label=new_label)
1841
1900
 
1842
- # TODO: remove this
1843
- def add_agent_memory_block(self, agent_id: str, create_block: CreateBlock) -> Memory:
1844
- """
1845
- Create and link a memory block to an agent's core memory
1846
-
1847
- Args:
1848
- agent_id (str): The agent ID
1849
- create_block (CreateBlock): The block to create
1850
-
1851
- Returns:
1852
- memory (Memory): The updated memory
1853
- """
1854
- response = requests.post(
1855
- f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block",
1856
- headers=self.headers,
1857
- json=create_block.model_dump(),
1858
- )
1859
- if response.status_code != 200:
1860
- raise ValueError(f"Failed to add agent memory block: {response.text}")
1861
- return Memory(**response.json())
1862
-
1863
- def link_agent_memory_block(self, agent_id: str, block_id: str) -> Memory:
1901
+ def attach_block(self, agent_id: str, block_id: str) -> AgentState:
1864
1902
  """
1865
- Link a block to an agent's core memory
1903
+ Attach a block to an agent.
1866
1904
 
1867
1905
  Args:
1868
- agent_id (str): The agent ID
1869
- block_id (str): The block ID
1870
-
1871
- Returns:
1872
- memory (Memory): The updated memory
1906
+ agent_id (str): ID of the agent
1907
+ block_id (str): ID of the block to attach
1873
1908
  """
1874
- params = {"agent_id": agent_id}
1875
1909
  response = requests.patch(
1876
- f"{self.base_url}/{self.api_prefix}/blocks/{block_id}/attach",
1877
- params=params,
1910
+ f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks/attach/{block_id}",
1878
1911
  headers=self.headers,
1879
1912
  )
1880
1913
  if response.status_code != 200:
1881
- raise ValueError(f"Failed to link agent memory block: {response.text}")
1882
- return Block(**response.json())
1914
+ raise ValueError(f"Failed to attach block to agent: {response.text}")
1915
+ return AgentState(**response.json())
1883
1916
 
1884
- def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
1917
+ def detach_block(self, agent_id: str, block_id: str) -> AgentState:
1885
1918
  """
1886
- Unlike a block from the agent's core memory
1919
+ Detach a block from an agent.
1887
1920
 
1888
1921
  Args:
1889
- agent_id (str): The agent ID
1890
- block_label (str): The block label
1891
-
1892
- Returns:
1893
- memory (Memory): The updated memory
1922
+ agent_id (str): ID of the agent
1923
+ block_id (str): ID of the block to detach
1894
1924
  """
1895
- response = requests.delete(
1896
- f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block/{block_label}",
1897
- 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
1898
1927
  )
1899
1928
  if response.status_code != 200:
1900
- raise ValueError(f"Failed to remove agent memory block: {response.text}")
1901
- return Memory(**response.json())
1929
+ raise ValueError(f"Failed to detach block from agent: {response.text}")
1930
+ return AgentState(**response.json())
1902
1931
 
1903
- def get_agent_memory_blocks(self, agent_id: str) -> List[Block]:
1932
+ def list_agent_memory_blocks(self, agent_id: str) -> List[Block]:
1904
1933
  """
1905
1934
  Get all the blocks in the agent's core memory
1906
1935
 
@@ -1910,7 +1939,7 @@ class RESTClient(AbstractClient):
1910
1939
  Returns:
1911
1940
  blocks (List[Block]): The blocks in the agent's core memory
1912
1941
  """
1913
- response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block", headers=self.headers)
1942
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks", headers=self.headers)
1914
1943
  if response.status_code != 200:
1915
1944
  raise ValueError(f"Failed to get agent memory blocks: {response.text}")
1916
1945
  return [Block(**block) for block in response.json()]
@@ -1927,7 +1956,7 @@ class RESTClient(AbstractClient):
1927
1956
  block (Block): The block corresponding to the label
1928
1957
  """
1929
1958
  response = requests.get(
1930
- f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block/{label}",
1959
+ f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks/{label}",
1931
1960
  headers=self.headers,
1932
1961
  )
1933
1962
  if response.status_code != 200:
@@ -1960,7 +1989,7 @@ class RESTClient(AbstractClient):
1960
1989
  if limit:
1961
1990
  data["limit"] = limit
1962
1991
  response = requests.patch(
1963
- f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block/{label}",
1992
+ f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/core-memory/blocks/{label}",
1964
1993
  headers=self.headers,
1965
1994
  json=data,
1966
1995
  )
@@ -2303,7 +2332,7 @@ class LocalClient(AbstractClient):
2303
2332
  # Create the base parameters
2304
2333
  create_params = {
2305
2334
  "description": description,
2306
- "metadata_": metadata,
2335
+ "metadata": metadata,
2307
2336
  "memory_blocks": [],
2308
2337
  "block_ids": [b.id for b in memory.get_blocks()] + block_ids,
2309
2338
  "tool_ids": tool_ids,
@@ -2337,7 +2366,7 @@ class LocalClient(AbstractClient):
2337
2366
  role: Optional[MessageRole] = None,
2338
2367
  text: Optional[str] = None,
2339
2368
  name: Optional[str] = None,
2340
- tool_calls: Optional[List[ToolCall]] = None,
2369
+ tool_calls: Optional[List[OpenAIToolCall]] = None,
2341
2370
  tool_call_id: Optional[str] = None,
2342
2371
  ) -> Message:
2343
2372
  message = self.server.update_agent_message(
@@ -2385,7 +2414,7 @@ class LocalClient(AbstractClient):
2385
2414
  Returns:
2386
2415
  agent_state (AgentState): State of the updated agent
2387
2416
  """
2388
- # TODO: add the abilitty to reset linked block_ids
2417
+ # TODO: add the ability to reset linked block_ids
2389
2418
  self.interface.clear()
2390
2419
  agent_state = self.server.agent_manager.update_agent(
2391
2420
  agent_id,
@@ -2395,7 +2424,7 @@ class LocalClient(AbstractClient):
2395
2424
  tool_ids=tool_ids,
2396
2425
  tags=tags,
2397
2426
  description=description,
2398
- metadata_=metadata,
2427
+ metadata=metadata,
2399
2428
  llm_config=llm_config,
2400
2429
  embedding_config=embedding_config,
2401
2430
  message_ids=message_ids,
@@ -2417,7 +2446,7 @@ class LocalClient(AbstractClient):
2417
2446
  self.interface.clear()
2418
2447
  return self.server.agent_manager.get_agent_by_id(agent_id=agent_id, actor=self.user).tools
2419
2448
 
2420
- def add_tool_to_agent(self, agent_id: str, tool_id: str):
2449
+ def attach_tool(self, agent_id: str, tool_id: str) -> AgentState:
2421
2450
  """
2422
2451
  Add tool to an existing agent
2423
2452
 
@@ -2432,7 +2461,7 @@ class LocalClient(AbstractClient):
2432
2461
  agent_state = self.server.agent_manager.attach_tool(agent_id=agent_id, tool_id=tool_id, actor=self.user)
2433
2462
  return agent_state
2434
2463
 
2435
- def remove_tool_from_agent(self, agent_id: str, tool_id: str):
2464
+ def detach_tool(self, agent_id: str, tool_id: str) -> AgentState:
2436
2465
  """
2437
2466
  Removes tools from an existing agent
2438
2467
 
@@ -2447,17 +2476,20 @@ class LocalClient(AbstractClient):
2447
2476
  agent_state = self.server.agent_manager.detach_tool(agent_id=agent_id, tool_id=tool_id, actor=self.user)
2448
2477
  return agent_state
2449
2478
 
2450
- def rename_agent(self, agent_id: str, new_name: str):
2479
+ def rename_agent(self, agent_id: str, new_name: str) -> AgentState:
2451
2480
  """
2452
2481
  Rename an agent
2453
2482
 
2454
2483
  Args:
2455
2484
  agent_id (str): ID of the agent
2456
2485
  new_name (str): New name for the agent
2486
+
2487
+ Returns:
2488
+ agent_state (AgentState): State of the updated agent
2457
2489
  """
2458
- self.update_agent(agent_id, name=new_name)
2490
+ return self.update_agent(agent_id, name=new_name)
2459
2491
 
2460
- def delete_agent(self, agent_id: str):
2492
+ def delete_agent(self, agent_id: str) -> None:
2461
2493
  """
2462
2494
  Delete an agent
2463
2495
 
@@ -2870,7 +2902,7 @@ class LocalClient(AbstractClient):
2870
2902
 
2871
2903
  def load_composio_tool(self, action: "ActionType") -> Tool:
2872
2904
  tool_create = ToolCreate.from_composio(action_name=action.name)
2873
- return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
2905
+ return self.server.tool_manager.create_or_update_composio_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
2874
2906
 
2875
2907
  def create_tool(
2876
2908
  self,
@@ -3032,6 +3064,18 @@ class LocalClient(AbstractClient):
3032
3064
  tool = self.server.tool_manager.get_tool_by_name(tool_name=name, actor=self.user)
3033
3065
  return tool.id if tool else None
3034
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
+
3035
3079
  def load_data(self, connector: DataConnector, source_name: str):
3036
3080
  """
3037
3081
  Load data into a source
@@ -3057,7 +3101,7 @@ class LocalClient(AbstractClient):
3057
3101
  job = Job(
3058
3102
  user_id=self.user_id,
3059
3103
  status=JobStatus.created,
3060
- metadata_={"type": "embedding", "filename": filename, "source_id": source_id},
3104
+ metadata={"type": "embedding", "filename": filename, "source_id": source_id},
3061
3105
  )
3062
3106
  job = self.server.job_manager.create_job(pydantic_job=job, actor=self.user)
3063
3107
 
@@ -3065,14 +3109,14 @@ class LocalClient(AbstractClient):
3065
3109
  self.server.load_file_to_source(source_id=source_id, file_path=filename, job_id=job.id, actor=self.user)
3066
3110
  return job
3067
3111
 
3068
- 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:
3069
3113
  self.server.source_manager.delete_file(file_id, actor=self.user)
3070
3114
 
3071
3115
  def get_job(self, job_id: str):
3072
3116
  return self.server.job_manager.get_job_by_id(job_id=job_id, actor=self.user)
3073
3117
 
3074
3118
  def delete_job(self, job_id: str):
3075
- return self.server.job_manager.delete_job(job_id=job_id, actor=self.user)
3119
+ return self.server.job_manager.delete_job_by_id(job_id=job_id, actor=self.user)
3076
3120
 
3077
3121
  def list_jobs(self):
3078
3122
  return self.server.job_manager.list_jobs(actor=self.user)
@@ -3131,7 +3175,7 @@ class LocalClient(AbstractClient):
3131
3175
  """
3132
3176
  return self.server.source_manager.get_source_by_name(source_name=source_name, actor=self.user).id
3133
3177
 
3134
- def attach_source_to_agent(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None):
3178
+ def attach_source(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None) -> AgentState:
3135
3179
  """
3136
3180
  Attach a source to an agent
3137
3181
 
@@ -3144,9 +3188,9 @@ class LocalClient(AbstractClient):
3144
3188
  source = self.server.source_manager.get_source_by_id(source_id=source_id, actor=self.user)
3145
3189
  source_id = source.id
3146
3190
 
3147
- 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)
3148
3192
 
3149
- def detach_source_from_agent(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None):
3193
+ def detach_source(self, agent_id: str, source_id: Optional[str] = None, source_name: Optional[str] = None) -> AgentState:
3150
3194
  """
3151
3195
  Detach a source from an agent by removing all `Passage` objects that were loaded from the source from archival memory.
3152
3196
  Args:
@@ -3479,50 +3523,6 @@ class LocalClient(AbstractClient):
3479
3523
  block = self.get_agent_memory_block(agent_id, current_label)
3480
3524
  return self.update_block(block.id, label=new_label)
3481
3525
 
3482
- # TODO: remove this
3483
- def add_agent_memory_block(self, agent_id: str, create_block: CreateBlock) -> Memory:
3484
- """
3485
- Create and link a memory block to an agent's core memory
3486
-
3487
- Args:
3488
- agent_id (str): The agent ID
3489
- create_block (CreateBlock): The block to create
3490
-
3491
- Returns:
3492
- memory (Memory): The updated memory
3493
- """
3494
- block_req = Block(**create_block.model_dump())
3495
- block = self.server.block_manager.create_or_update_block(actor=self.user, block=block_req)
3496
- # Link the block to the agent
3497
- agent = self.server.agent_manager.attach_block(agent_id=agent_id, block_id=block.id, actor=self.user)
3498
- return agent.memory
3499
-
3500
- def link_agent_memory_block(self, agent_id: str, block_id: str) -> Memory:
3501
- """
3502
- Link a block to an agent's core memory
3503
-
3504
- Args:
3505
- agent_id (str): The agent ID
3506
- block_id (str): The block ID
3507
-
3508
- Returns:
3509
- memory (Memory): The updated memory
3510
- """
3511
- return self.server.agent_manager.attach_block(agent_id=agent_id, block_id=block_id, actor=self.user)
3512
-
3513
- def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
3514
- """
3515
- Unlike a block from the agent's core memory
3516
-
3517
- Args:
3518
- agent_id (str): The agent ID
3519
- block_label (str): The block label
3520
-
3521
- Returns:
3522
- memory (Memory): The updated memory
3523
- """
3524
- return self.server.agent_manager.detach_block_with_label(agent_id=agent_id, block_label=block_label, actor=self.user)
3525
-
3526
3526
  def get_agent_memory_blocks(self, agent_id: str) -> List[Block]:
3527
3527
  """
3528
3528
  Get all the blocks in the agent's core memory
@@ -3604,6 +3604,26 @@ class LocalClient(AbstractClient):
3604
3604
  data["label"] = label
3605
3605
  return self.server.block_manager.update_block(block_id, actor=self.user, block_update=BlockUpdate(**data))
3606
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
+
3607
3627
  def get_run_messages(
3608
3628
  self,
3609
3629
  run_id: str,