letta-nightly 0.5.4.dev20241127104220__py3-none-any.whl → 0.5.4.dev20241128000451__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 (38) hide show
  1. letta/__init__.py +1 -1
  2. letta/agent.py +102 -140
  3. letta/agent_store/chroma.py +2 -0
  4. letta/cli/cli.py +3 -5
  5. letta/client/client.py +360 -117
  6. letta/config.py +2 -2
  7. letta/constants.py +5 -0
  8. letta/functions/function_sets/base.py +38 -1
  9. letta/helpers/tool_rule_solver.py +6 -5
  10. letta/main.py +1 -1
  11. letta/metadata.py +39 -41
  12. letta/o1_agent.py +1 -4
  13. letta/persistence_manager.py +1 -0
  14. letta/schemas/agent.py +57 -52
  15. letta/schemas/block.py +69 -25
  16. letta/schemas/enums.py +14 -0
  17. letta/schemas/letta_base.py +1 -1
  18. letta/schemas/letta_request.py +11 -23
  19. letta/schemas/letta_response.py +1 -2
  20. letta/schemas/memory.py +31 -100
  21. letta/schemas/message.py +3 -3
  22. letta/schemas/tool_rule.py +13 -5
  23. letta/server/rest_api/interface.py +12 -19
  24. letta/server/rest_api/routers/openai/assistants/threads.py +2 -3
  25. letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -2
  26. letta/server/rest_api/routers/v1/agents.py +90 -86
  27. letta/server/rest_api/routers/v1/blocks.py +50 -5
  28. letta/server/server.py +237 -459
  29. letta/server/static_files/assets/index-9fa459a2.js +1 -1
  30. letta/services/block_manager.py +6 -3
  31. letta/services/blocks_agents_manager.py +15 -0
  32. letta/services/tool_execution_sandbox.py +1 -1
  33. letta/services/tool_manager.py +2 -1
  34. {letta_nightly-0.5.4.dev20241127104220.dist-info → letta_nightly-0.5.4.dev20241128000451.dist-info}/METADATA +1 -1
  35. {letta_nightly-0.5.4.dev20241127104220.dist-info → letta_nightly-0.5.4.dev20241128000451.dist-info}/RECORD +38 -38
  36. {letta_nightly-0.5.4.dev20241127104220.dist-info → letta_nightly-0.5.4.dev20241128000451.dist-info}/LICENSE +0 -0
  37. {letta_nightly-0.5.4.dev20241127104220.dist-info → letta_nightly-0.5.4.dev20241128000451.dist-info}/WHEEL +0 -0
  38. {letta_nightly-0.5.4.dev20241127104220.dist-info → letta_nightly-0.5.4.dev20241128000451.dist-info}/entry_points.txt +0 -0
letta/client/client.py CHANGED
@@ -5,20 +5,17 @@ from typing import Callable, Dict, Generator, List, Optional, Union
5
5
  import requests
6
6
 
7
7
  import letta.utils
8
- from letta.constants import ADMIN_PREFIX, BASE_TOOLS, DEFAULT_HUMAN, DEFAULT_PERSONA
8
+ from letta.constants import (
9
+ ADMIN_PREFIX,
10
+ BASE_MEMORY_TOOLS,
11
+ BASE_TOOLS,
12
+ DEFAULT_HUMAN,
13
+ DEFAULT_PERSONA,
14
+ )
9
15
  from letta.data_sources.connectors import DataConnector
10
16
  from letta.functions.functions import parse_source_code
11
- from letta.memory import get_memory_functions
12
17
  from letta.schemas.agent import AgentState, AgentType, CreateAgent, UpdateAgentState
13
- from letta.schemas.block import (
14
- Block,
15
- BlockCreate,
16
- BlockUpdate,
17
- Human,
18
- Persona,
19
- UpdateHuman,
20
- UpdatePersona,
21
- )
18
+ from letta.schemas.block import Block, BlockUpdate, CreateBlock, Human, Persona
22
19
  from letta.schemas.embedding_config import EmbeddingConfig
23
20
 
24
21
  # new schemas
@@ -82,7 +79,7 @@ class AbstractClient(object):
82
79
  agent_type: Optional[AgentType] = AgentType.memgpt_agent,
83
80
  embedding_config: Optional[EmbeddingConfig] = None,
84
81
  llm_config: Optional[LLMConfig] = None,
85
- memory: Memory = ChatMemory(human=get_human_text(DEFAULT_HUMAN), persona=get_persona_text(DEFAULT_PERSONA)),
82
+ memory=None,
86
83
  system: Optional[str] = None,
87
84
  tools: Optional[List[str]] = None,
88
85
  tool_rules: Optional[List[BaseToolRule]] = None,
@@ -154,11 +151,10 @@ class AbstractClient(object):
154
151
  stream: Optional[bool] = False,
155
152
  stream_steps: bool = False,
156
153
  stream_tokens: bool = False,
157
- include_full_message: Optional[bool] = False,
158
154
  ) -> LettaResponse:
159
155
  raise NotImplementedError
160
156
 
161
- def user_message(self, agent_id: str, message: str, include_full_message: Optional[bool] = False) -> LettaResponse:
157
+ def user_message(self, agent_id: str, message: str) -> LettaResponse:
162
158
  raise NotImplementedError
163
159
 
164
160
  def create_human(self, name: str, text: str) -> Human:
@@ -523,27 +519,13 @@ class RESTClient(AbstractClient):
523
519
  Returns:
524
520
  agent_state (AgentState): State of the created agent
525
521
  """
526
-
527
- # TODO: implement this check once name lookup works
528
- # if name:
529
- # exist_agent_id = self.get_agent_id(agent_name=name)
530
-
531
- # raise ValueError(f"Agent with name {name} already exists")
532
-
533
- # construct list of tools
534
522
  tool_names = []
535
523
  if tools:
536
524
  tool_names += tools
537
525
  if include_base_tools:
538
526
  tool_names += BASE_TOOLS
527
+ tool_names += BASE_MEMORY_TOOLS
539
528
 
540
- # add memory tools
541
- memory_functions = get_memory_functions(memory)
542
- for func_name, func in memory_functions.items():
543
- tool = self.create_or_update_tool(func, name=func_name, tags=["memory", "letta-base"])
544
- tool_names.append(tool.name)
545
-
546
- # check if default configs are provided
547
529
  assert embedding_config or self._default_embedding_config, f"Embedding config must be provided"
548
530
  assert llm_config or self._default_llm_config, f"LLM config must be provided"
549
531
 
@@ -552,7 +534,7 @@ class RESTClient(AbstractClient):
552
534
  name=name,
553
535
  description=description,
554
536
  metadata_=metadata,
555
- memory=memory,
537
+ memory_blocks=[],
556
538
  tools=tool_names,
557
539
  tool_rules=tool_rules,
558
540
  system=system,
@@ -574,7 +556,20 @@ class RESTClient(AbstractClient):
574
556
 
575
557
  if response.status_code != 200:
576
558
  raise ValueError(f"Status {response.status_code} - Failed to create agent: {response.text}")
577
- return AgentState(**response.json())
559
+
560
+ # gather agent state
561
+ agent_state = AgentState(**response.json())
562
+
563
+ # create and link blocks
564
+ for block in memory.get_blocks():
565
+ if not self.get_block(block.id):
566
+ # note: this does not update existing blocks
567
+ # WARNING: this resets the block ID - this method is a hack for backwards compat, should eventually use CreateBlock not Memory
568
+ block = self.create_block(label=block.label, value=block.value, limit=block.limit)
569
+ self.link_agent_memory_block(agent_id=agent_state.id, block_id=block.id)
570
+
571
+ # refresh and return agent
572
+ return self.get_agent(agent_state.id)
578
573
 
579
574
  def update_message(
580
575
  self,
@@ -607,12 +602,11 @@ class RESTClient(AbstractClient):
607
602
  name: Optional[str] = None,
608
603
  description: Optional[str] = None,
609
604
  system: Optional[str] = None,
610
- tools: Optional[List[str]] = None,
605
+ tool_names: Optional[List[str]] = None,
611
606
  metadata: Optional[Dict] = None,
612
607
  llm_config: Optional[LLMConfig] = None,
613
608
  embedding_config: Optional[EmbeddingConfig] = None,
614
609
  message_ids: Optional[List[str]] = None,
615
- memory: Optional[Memory] = None,
616
610
  tags: Optional[List[str]] = None,
617
611
  ):
618
612
  """
@@ -623,12 +617,11 @@ class RESTClient(AbstractClient):
623
617
  name (str): Name of the agent
624
618
  description (str): Description of the agent
625
619
  system (str): System configuration
626
- tools (List[str]): List of tools
620
+ tool_names (List[str]): List of tools
627
621
  metadata (Dict): Metadata
628
622
  llm_config (LLMConfig): LLM configuration
629
623
  embedding_config (EmbeddingConfig): Embedding configuration
630
624
  message_ids (List[str]): List of message IDs
631
- memory (Memory): Memory configuration
632
625
  tags (List[str]): Tags for filtering agents
633
626
 
634
627
  Returns:
@@ -638,14 +631,13 @@ class RESTClient(AbstractClient):
638
631
  id=agent_id,
639
632
  name=name,
640
633
  system=system,
641
- tools=tools,
634
+ tool_names=tool_names,
642
635
  tags=tags,
643
636
  description=description,
644
637
  metadata_=metadata,
645
638
  llm_config=llm_config,
646
639
  embedding_config=embedding_config,
647
640
  message_ids=message_ids,
648
- memory=memory,
649
641
  )
650
642
  response = requests.patch(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}", json=request.model_dump(), headers=self.headers)
651
643
  if response.status_code != 200:
@@ -839,7 +831,7 @@ class RESTClient(AbstractClient):
839
831
 
840
832
  # agent interactions
841
833
 
842
- def user_message(self, agent_id: str, message: str, include_full_message: Optional[bool] = False) -> LettaResponse:
834
+ def user_message(self, agent_id: str, message: str) -> LettaResponse:
843
835
  """
844
836
  Send a message to an agent as a user
845
837
 
@@ -850,7 +842,7 @@ class RESTClient(AbstractClient):
850
842
  Returns:
851
843
  response (LettaResponse): Response from the agent
852
844
  """
853
- return self.send_message(agent_id, message, role="user", include_full_message=include_full_message)
845
+ return self.send_message(agent_id=agent_id, message=message, role="user")
854
846
 
855
847
  def save(self):
856
848
  raise NotImplementedError
@@ -937,13 +929,13 @@ class RESTClient(AbstractClient):
937
929
 
938
930
  def send_message(
939
931
  self,
940
- agent_id: str,
941
932
  message: str,
942
933
  role: str,
934
+ agent_id: Optional[str] = None,
943
935
  name: Optional[str] = None,
936
+ stream: Optional[bool] = False,
944
937
  stream_steps: bool = False,
945
938
  stream_tokens: bool = False,
946
- include_full_message: bool = False,
947
939
  ) -> Union[LettaResponse, Generator[LettaStreamingResponse, None, None]]:
948
940
  """
949
941
  Send a message to an agent
@@ -964,17 +956,11 @@ class RESTClient(AbstractClient):
964
956
  # TODO: figure out how to handle stream_steps and stream_tokens
965
957
 
966
958
  # When streaming steps is True, stream_tokens must be False
967
- request = LettaRequest(
968
- messages=messages,
969
- stream_steps=stream_steps,
970
- stream_tokens=stream_tokens,
971
- return_message_object=include_full_message,
972
- )
959
+ request = LettaRequest(messages=messages)
973
960
  if stream_tokens or stream_steps:
974
961
  from letta.client.streaming import _sse_post
975
962
 
976
- request.return_message_object = False
977
- return _sse_post(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/messages", request.model_dump(), self.headers)
963
+ return _sse_post(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/messages/stream", request.model_dump(), self.headers)
978
964
  else:
979
965
  response = requests.post(
980
966
  f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/messages", json=request.model_dump(), headers=self.headers
@@ -1008,8 +994,12 @@ class RESTClient(AbstractClient):
1008
994
  else:
1009
995
  return [Block(**block) for block in response.json()]
1010
996
 
1011
- def create_block(self, label: str, value: str, template_name: Optional[str] = None, is_template: bool = False) -> Block: #
1012
- request = BlockCreate(label=label, value=value, template=is_template, template_name=template_name)
997
+ def create_block(
998
+ self, label: str, value: str, limit: Optional[int] = None, template_name: Optional[str] = None, is_template: bool = False
999
+ ) -> Block: #
1000
+ request = CreateBlock(label=label, value=value, template=is_template, template_name=template_name)
1001
+ if limit:
1002
+ request.limit = limit
1013
1003
  response = requests.post(f"{self.base_url}/{self.api_prefix}/blocks", json=request.model_dump(), headers=self.headers)
1014
1004
  if response.status_code != 200:
1015
1005
  raise ValueError(f"Failed to create block: {response.text}")
@@ -1779,21 +1769,32 @@ class RESTClient(AbstractClient):
1779
1769
  raise ValueError(f"Failed to list environment variables for sandbox config ID '{sandbox_config_id}': {response.text}")
1780
1770
  return [SandboxEnvironmentVariable(**var_data) for var_data in response.json()]
1781
1771
 
1782
- def update_agent_memory_label(self, agent_id: str, current_label: str, new_label: str) -> Memory:
1772
+ def update_agent_memory_block_label(self, agent_id: str, current_label: str, new_label: str) -> Memory:
1773
+ """Rename a block in the agent's core memory
1783
1774
 
1784
- # @router.patch("/{agent_id}/memory/label", response_model=Memory, operation_id="update_agent_memory_label")
1785
- response = requests.patch(
1786
- f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/label",
1787
- headers=self.headers,
1788
- json={"current_label": current_label, "new_label": new_label},
1789
- )
1790
- if response.status_code != 200:
1791
- raise ValueError(f"Failed to update agent memory label: {response.text}")
1792
- return Memory(**response.json())
1775
+ Args:
1776
+ agent_id (str): The agent ID
1777
+ current_label (str): The current label of the block
1778
+ new_label (str): The new label of the block
1779
+
1780
+ Returns:
1781
+ memory (Memory): The updated memory
1782
+ """
1783
+ block = self.get_agent_memory_block(agent_id, current_label)
1784
+ return self.update_block(block.id, label=new_label)
1785
+
1786
+ # TODO: remove this
1787
+ def add_agent_memory_block(self, agent_id: str, create_block: CreateBlock) -> Memory:
1788
+ """
1789
+ Create and link a memory block to an agent's core memory
1793
1790
 
1794
- def add_agent_memory_block(self, agent_id: str, create_block: BlockCreate) -> Memory:
1791
+ Args:
1792
+ agent_id (str): The agent ID
1793
+ create_block (CreateBlock): The block to create
1795
1794
 
1796
- # @router.post("/{agent_id}/memory/block", response_model=Memory, operation_id="add_agent_memory_block")
1795
+ Returns:
1796
+ memory (Memory): The updated memory
1797
+ """
1797
1798
  response = requests.post(
1798
1799
  f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block",
1799
1800
  headers=self.headers,
@@ -1803,9 +1804,38 @@ class RESTClient(AbstractClient):
1803
1804
  raise ValueError(f"Failed to add agent memory block: {response.text}")
1804
1805
  return Memory(**response.json())
1805
1806
 
1807
+ def link_agent_memory_block(self, agent_id: str, block_id: str) -> Memory:
1808
+ """
1809
+ Link a block to an agent's core memory
1810
+
1811
+ Args:
1812
+ agent_id (str): The agent ID
1813
+ block_id (str): The block ID
1814
+
1815
+ Returns:
1816
+ memory (Memory): The updated memory
1817
+ """
1818
+ params = {"agent_id": agent_id}
1819
+ response = requests.patch(
1820
+ f"{self.base_url}/{self.api_prefix}/blocks/{block_id}/attach",
1821
+ params=params,
1822
+ headers=self.headers,
1823
+ )
1824
+ if response.status_code != 200:
1825
+ raise ValueError(f"Failed to link agent memory block: {response.text}")
1826
+ return Block(**response.json())
1827
+
1806
1828
  def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
1829
+ """
1830
+ Unlike a block from the agent's core memory
1807
1831
 
1808
- # @router.delete("/{agent_id}/memory/block/{block_label}", response_model=Memory, operation_id="remove_agent_memory_block")
1832
+ Args:
1833
+ agent_id (str): The agent ID
1834
+ block_label (str): The block label
1835
+
1836
+ Returns:
1837
+ memory (Memory): The updated memory
1838
+ """
1809
1839
  response = requests.delete(
1810
1840
  f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block/{block_label}",
1811
1841
  headers=self.headers,
@@ -1814,17 +1844,108 @@ class RESTClient(AbstractClient):
1814
1844
  raise ValueError(f"Failed to remove agent memory block: {response.text}")
1815
1845
  return Memory(**response.json())
1816
1846
 
1817
- def update_agent_memory_limit(self, agent_id: str, block_label: str, limit: int) -> Memory:
1847
+ def get_agent_memory_blocks(self, agent_id: str) -> List[Block]:
1848
+ """
1849
+ Get all the blocks in the agent's core memory
1818
1850
 
1819
- # @router.patch("/{agent_id}/memory/limit", response_model=Memory, operation_id="update_agent_memory_limit")
1851
+ Args:
1852
+ agent_id (str): The agent ID
1853
+
1854
+ Returns:
1855
+ blocks (List[Block]): The blocks in the agent's core memory
1856
+ """
1857
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block", headers=self.headers)
1858
+ if response.status_code != 200:
1859
+ raise ValueError(f"Failed to get agent memory blocks: {response.text}")
1860
+ return [Block(**block) for block in response.json()]
1861
+
1862
+ def get_agent_memory_block(self, agent_id: str, label: str) -> Block:
1863
+ """
1864
+ Get a block in the agent's core memory by its label
1865
+
1866
+ Args:
1867
+ agent_id (str): The agent ID
1868
+ label (str): The label in the agent's core memory
1869
+
1870
+ Returns:
1871
+ block (Block): The block corresponding to the label
1872
+ """
1873
+ response = requests.get(
1874
+ f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block/{label}",
1875
+ headers=self.headers,
1876
+ )
1877
+ if response.status_code != 200:
1878
+ raise ValueError(f"Failed to get agent memory block: {response.text}")
1879
+ return Block(**response.json())
1880
+
1881
+ def update_agent_memory_block(
1882
+ self,
1883
+ agent_id: str,
1884
+ label: str,
1885
+ value: Optional[str] = None,
1886
+ limit: Optional[int] = None,
1887
+ ):
1888
+ """
1889
+ Update a block in the agent's core memory by specifying its label
1890
+
1891
+ Args:
1892
+ agent_id (str): The agent ID
1893
+ label (str): The label of the block
1894
+ value (str): The new value of the block
1895
+ limit (int): The new limit of the block
1896
+
1897
+ Returns:
1898
+ block (Block): The updated block
1899
+ """
1900
+ # setup data
1901
+ data = {}
1902
+ if value:
1903
+ data["value"] = value
1904
+ if limit:
1905
+ data["limit"] = limit
1820
1906
  response = requests.patch(
1821
- f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/limit",
1907
+ f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block/{label}",
1822
1908
  headers=self.headers,
1823
- json={"label": block_label, "limit": limit},
1909
+ json=data,
1824
1910
  )
1825
1911
  if response.status_code != 200:
1826
- raise ValueError(f"Failed to update agent memory limit: {response.text}")
1827
- return Memory(**response.json())
1912
+ raise ValueError(f"Failed to update agent memory block: {response.text}")
1913
+ return Block(**response.json())
1914
+
1915
+ def update_block(
1916
+ self,
1917
+ block_id: str,
1918
+ label: Optional[str] = None,
1919
+ value: Optional[str] = None,
1920
+ limit: Optional[int] = None,
1921
+ ):
1922
+ """
1923
+ Update a block given the ID with the provided fields
1924
+
1925
+ Args:
1926
+ block_id (str): ID of the block
1927
+ label (str): Label to assign to the block
1928
+ value (str): Value to assign to the block
1929
+ limit (int): Token limit to assign to the block
1930
+
1931
+ Returns:
1932
+ block (Block): Updated block
1933
+ """
1934
+ data = {}
1935
+ if value:
1936
+ data["value"] = value
1937
+ if limit:
1938
+ data["limit"] = limit
1939
+ if label:
1940
+ data["label"] = label
1941
+ response = requests.patch(
1942
+ f"{self.base_url}/{self.api_prefix}/blocks/{block_id}",
1943
+ headers=self.headers,
1944
+ json=data,
1945
+ )
1946
+ if response.status_code != 200:
1947
+ raise ValueError(f"Failed to update block: {response.text}")
1948
+ return Block(**response.json())
1828
1949
 
1829
1950
 
1830
1951
  class LocalClient(AbstractClient):
@@ -1923,6 +2044,11 @@ class LocalClient(AbstractClient):
1923
2044
  llm_config: LLMConfig = None,
1924
2045
  # memory
1925
2046
  memory: Memory = ChatMemory(human=get_human_text(DEFAULT_HUMAN), persona=get_persona_text(DEFAULT_PERSONA)),
2047
+ # TODO: change to this when we are ready to migrate all the tests/examples (matches the REST API)
2048
+ # memory_blocks=[
2049
+ # {"label": "human", "value": get_human_text(DEFAULT_HUMAN), "limit": 5000},
2050
+ # {"label": "persona", "value": get_persona_text(DEFAULT_PERSONA), "limit": 5000},
2051
+ # ],
1926
2052
  # system
1927
2053
  system: Optional[str] = None,
1928
2054
  # tools
@@ -1941,7 +2067,7 @@ class LocalClient(AbstractClient):
1941
2067
  name (str): Name of the agent
1942
2068
  embedding_config (EmbeddingConfig): Embedding configuration
1943
2069
  llm_config (LLMConfig): LLM configuration
1944
- memory (Memory): Memory configuration
2070
+ memory_blocks (List[Dict]): List of configurations for the memory blocks (placed in core-memory)
1945
2071
  system (str): System configuration
1946
2072
  tools (List[str]): List of tools
1947
2073
  tool_rules (Optional[List[BaseToolRule]]): List of tool rules
@@ -1963,14 +2089,7 @@ class LocalClient(AbstractClient):
1963
2089
  tool_names += tools
1964
2090
  if include_base_tools:
1965
2091
  tool_names += BASE_TOOLS
1966
-
1967
- # add memory tools
1968
- memory_functions = get_memory_functions(memory)
1969
- for func_name, func in memory_functions.items():
1970
- tool = self.create_or_update_tool(func, name=func_name, tags=["memory", "letta-base"])
1971
- tool_names.append(tool.name)
1972
-
1973
- self.interface.clear()
2092
+ tool_names += BASE_MEMORY_TOOLS
1974
2093
 
1975
2094
  # check if default configs are provided
1976
2095
  assert embedding_config or self._default_embedding_config, f"Embedding config must be provided"
@@ -1982,7 +2101,10 @@ class LocalClient(AbstractClient):
1982
2101
  name=name,
1983
2102
  description=description,
1984
2103
  metadata_=metadata,
1985
- memory=memory,
2104
+ # memory=memory,
2105
+ memory_blocks=[],
2106
+ # memory_blocks = memory.get_blocks(),
2107
+ # memory_tools=memory_tools,
1986
2108
  tools=tool_names,
1987
2109
  tool_rules=tool_rules,
1988
2110
  system=system,
@@ -1994,7 +2116,18 @@ class LocalClient(AbstractClient):
1994
2116
  ),
1995
2117
  actor=self.user,
1996
2118
  )
1997
- return agent_state
2119
+
2120
+ # TODO: remove when we fully migrate to block creation CreateAgent model
2121
+ # Link additional blocks to the agent (block ids created on the client)
2122
+ # This needs to happen since the create agent does not allow passing in blocks which have already been persisted and have an ID
2123
+ # So we create the agent and then link the blocks afterwards
2124
+ user = self.server.get_user_or_default(self.user_id)
2125
+ for block in memory.get_blocks():
2126
+ self.server.block_manager.create_or_update_block(block, actor=user)
2127
+ self.server.link_block_to_agent_memory(user_id=self.user_id, agent_id=agent_state.id, block_id=block.id)
2128
+
2129
+ # TODO: get full agent state
2130
+ return self.server.get_agent(agent_state.id)
1998
2131
 
1999
2132
  def update_message(
2000
2133
  self,
@@ -2031,7 +2164,6 @@ class LocalClient(AbstractClient):
2031
2164
  llm_config: Optional[LLMConfig] = None,
2032
2165
  embedding_config: Optional[EmbeddingConfig] = None,
2033
2166
  message_ids: Optional[List[str]] = None,
2034
- memory: Optional[Memory] = None,
2035
2167
  ):
2036
2168
  """
2037
2169
  Update an existing agent
@@ -2046,26 +2178,25 @@ class LocalClient(AbstractClient):
2046
2178
  llm_config (LLMConfig): LLM configuration
2047
2179
  embedding_config (EmbeddingConfig): Embedding configuration
2048
2180
  message_ids (List[str]): List of message IDs
2049
- memory (Memory): Memory configuration
2050
2181
  tags (List[str]): Tags for filtering agents
2051
2182
 
2052
2183
  Returns:
2053
2184
  agent_state (AgentState): State of the updated agent
2054
2185
  """
2186
+ # TODO: add the abilitty to reset linked block_ids
2055
2187
  self.interface.clear()
2056
2188
  agent_state = self.server.update_agent(
2057
2189
  UpdateAgentState(
2058
2190
  id=agent_id,
2059
2191
  name=name,
2060
2192
  system=system,
2061
- tools=tools,
2193
+ tool_names=tools,
2062
2194
  tags=tags,
2063
2195
  description=description,
2064
2196
  metadata_=metadata,
2065
2197
  llm_config=llm_config,
2066
2198
  embedding_config=embedding_config,
2067
2199
  message_ids=message_ids,
2068
- memory=memory,
2069
2200
  ),
2070
2201
  actor=self.user,
2071
2202
  )
@@ -2204,7 +2335,7 @@ class LocalClient(AbstractClient):
2204
2335
 
2205
2336
  """
2206
2337
  # TODO: implement this (not sure what it should look like)
2207
- memory = self.server.update_agent_core_memory(user_id=self.user_id, agent_id=agent_id, new_memory_contents={section: value})
2338
+ memory = self.server.update_agent_core_memory(user_id=self.user_id, agent_id=agent_id, label=section, value=value)
2208
2339
  return memory
2209
2340
 
2210
2341
  def get_archival_memory_summary(self, agent_id: str) -> ArchivalMemorySummary:
@@ -2250,7 +2381,6 @@ class LocalClient(AbstractClient):
2250
2381
  self,
2251
2382
  agent_id: str,
2252
2383
  messages: List[Union[Message | MessageCreate]],
2253
- include_full_message: Optional[bool] = False,
2254
2384
  ):
2255
2385
  """
2256
2386
  Send pre-packed messages to an agent.
@@ -2270,15 +2400,7 @@ class LocalClient(AbstractClient):
2270
2400
  self.save()
2271
2401
 
2272
2402
  # format messages
2273
- messages = self.interface.to_list()
2274
- if include_full_message:
2275
- letta_messages = messages
2276
- else:
2277
- letta_messages = []
2278
- for m in messages:
2279
- letta_messages += m.to_letta_message()
2280
-
2281
- return LettaResponse(messages=letta_messages, usage=usage)
2403
+ return LettaResponse(messages=messages, usage=usage)
2282
2404
 
2283
2405
  def send_message(
2284
2406
  self,
@@ -2289,7 +2411,6 @@ class LocalClient(AbstractClient):
2289
2411
  agent_name: Optional[str] = None,
2290
2412
  stream_steps: bool = False,
2291
2413
  stream_tokens: bool = False,
2292
- include_full_message: Optional[bool] = False,
2293
2414
  ) -> LettaResponse:
2294
2415
  """
2295
2416
  Send a message to an agent
@@ -2338,16 +2459,13 @@ class LocalClient(AbstractClient):
2338
2459
 
2339
2460
  # format messages
2340
2461
  messages = self.interface.to_list()
2341
- if include_full_message:
2342
- letta_messages = messages
2343
- else:
2344
- letta_messages = []
2345
- for m in messages:
2346
- letta_messages += m.to_letta_message()
2462
+ letta_messages = []
2463
+ for m in messages:
2464
+ letta_messages += m.to_letta_message()
2347
2465
 
2348
2466
  return LettaResponse(messages=letta_messages, usage=usage)
2349
2467
 
2350
- def user_message(self, agent_id: str, message: str, include_full_message: Optional[bool] = False) -> LettaResponse:
2468
+ def user_message(self, agent_id: str, message: str) -> LettaResponse:
2351
2469
  """
2352
2470
  Send a message to an agent as a user
2353
2471
 
@@ -2359,7 +2477,7 @@ class LocalClient(AbstractClient):
2359
2477
  response (LettaResponse): Response from the agent
2360
2478
  """
2361
2479
  self.interface.clear()
2362
- return self.send_message(role="user", agent_id=agent_id, message=message, include_full_message=include_full_message)
2480
+ return self.send_message(role="user", agent_id=agent_id, message=message)
2363
2481
 
2364
2482
  def run_command(self, agent_id: str, command: str) -> LettaResponse:
2365
2483
  """
@@ -2951,7 +3069,6 @@ class LocalClient(AbstractClient):
2951
3069
  after=after,
2952
3070
  limit=limit,
2953
3071
  reverse=True,
2954
- return_message_object=True,
2955
3072
  )
2956
3073
 
2957
3074
  def list_blocks(self, label: Optional[str] = None, templates_only: Optional[bool] = True) -> List[Block]:
@@ -2967,7 +3084,9 @@ class LocalClient(AbstractClient):
2967
3084
  """
2968
3085
  return self.server.block_manager.get_blocks(actor=self.user, label=label, is_template=templates_only)
2969
3086
 
2970
- def create_block(self, label: str, value: str, template_name: Optional[str] = None, is_template: bool = False) -> Block: #
3087
+ def create_block(
3088
+ self, label: str, value: str, limit: Optional[int] = None, template_name: Optional[str] = None, is_template: bool = False
3089
+ ) -> Block: #
2971
3090
  """
2972
3091
  Create a block
2973
3092
 
@@ -2975,13 +3094,15 @@ class LocalClient(AbstractClient):
2975
3094
  label (str): Label of the block
2976
3095
  name (str): Name of the block
2977
3096
  text (str): Text of the block
3097
+ limit (int): Character of the block
2978
3098
 
2979
3099
  Returns:
2980
3100
  block (Block): Created block
2981
3101
  """
2982
- return self.server.block_manager.create_or_update_block(
2983
- Block(label=label, template_name=template_name, value=value, is_template=is_template), actor=self.user
2984
- )
3102
+ block = Block(label=label, template_name=template_name, value=value, is_template=is_template)
3103
+ if limit:
3104
+ block.limit = limit
3105
+ return self.server.block_manager.create_or_update_block(block, actor=self.user)
2985
3106
 
2986
3107
  def update_block(self, block_id: str, name: Optional[str] = None, text: Optional[str] = None, limit: Optional[int] = None) -> Block:
2987
3108
  """
@@ -3136,20 +3257,142 @@ class LocalClient(AbstractClient):
3136
3257
  sandbox_config_id=sandbox_config_id, actor=self.user, limit=limit, cursor=cursor
3137
3258
  )
3138
3259
 
3139
- def update_agent_memory_label(self, agent_id: str, current_label: str, new_label: str) -> Memory:
3140
- return self.server.update_agent_memory_label(
3141
- user_id=self.user_id, agent_id=agent_id, current_block_label=current_label, new_block_label=new_label
3142
- )
3260
+ def update_agent_memory_block_label(self, agent_id: str, current_label: str, new_label: str) -> Memory:
3261
+ """Rename a block in the agent's core memory
3262
+
3263
+ Args:
3264
+ agent_id (str): The agent ID
3265
+ current_label (str): The current label of the block
3266
+ new_label (str): The new label of the block
3267
+
3268
+ Returns:
3269
+ memory (Memory): The updated memory
3270
+ """
3271
+ block = self.get_agent_memory_block(agent_id, current_label)
3272
+ return self.update_block(block.id, label=new_label)
3273
+
3274
+ # TODO: remove this
3275
+ def add_agent_memory_block(self, agent_id: str, create_block: CreateBlock) -> Memory:
3276
+ """
3277
+ Create and link a memory block to an agent's core memory
3278
+
3279
+ Args:
3280
+ agent_id (str): The agent ID
3281
+ create_block (CreateBlock): The block to create
3143
3282
 
3144
- def add_agent_memory_block(self, agent_id: str, create_block: BlockCreate) -> Memory:
3283
+ Returns:
3284
+ memory (Memory): The updated memory
3285
+ """
3145
3286
  block_req = Block(**create_block.model_dump())
3146
3287
  block = self.server.block_manager.create_or_update_block(actor=self.user, block=block_req)
3147
3288
  # Link the block to the agent
3148
3289
  updated_memory = self.server.link_block_to_agent_memory(user_id=self.user_id, agent_id=agent_id, block_id=block.id)
3149
3290
  return updated_memory
3150
3291
 
3292
+ def link_agent_memory_block(self, agent_id: str, block_id: str) -> Memory:
3293
+ """
3294
+ Link a block to an agent's core memory
3295
+
3296
+ Args:
3297
+ agent_id (str): The agent ID
3298
+ block_id (str): The block ID
3299
+
3300
+ Returns:
3301
+ memory (Memory): The updated memory
3302
+ """
3303
+ return self.server.link_block_to_agent_memory(user_id=self.user_id, agent_id=agent_id, block_id=block_id)
3304
+
3151
3305
  def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
3306
+ """
3307
+ Unlike a block from the agent's core memory
3308
+
3309
+ Args:
3310
+ agent_id (str): The agent ID
3311
+ block_label (str): The block label
3312
+
3313
+ Returns:
3314
+ memory (Memory): The updated memory
3315
+ """
3152
3316
  return self.server.unlink_block_from_agent_memory(user_id=self.user_id, agent_id=agent_id, block_label=block_label)
3153
3317
 
3154
- def update_agent_memory_limit(self, agent_id: str, block_label: str, limit: int) -> Memory:
3155
- return self.server.update_agent_memory_limit(user_id=self.user_id, agent_id=agent_id, block_label=block_label, limit=limit)
3318
+ def get_agent_memory_blocks(self, agent_id: str) -> List[Block]:
3319
+ """
3320
+ Get all the blocks in the agent's core memory
3321
+
3322
+ Args:
3323
+ agent_id (str): The agent ID
3324
+
3325
+ Returns:
3326
+ blocks (List[Block]): The blocks in the agent's core memory
3327
+ """
3328
+ block_ids = self.server.blocks_agents_manager.list_block_ids_for_agent(agent_id=agent_id)
3329
+ return [self.server.block_manager.get_block_by_id(block_id, actor=self.user) for block_id in block_ids]
3330
+
3331
+ def get_agent_memory_block(self, agent_id: str, label: str) -> Block:
3332
+ """
3333
+ Get a block in the agent's core memory by its label
3334
+
3335
+ Args:
3336
+ agent_id (str): The agent ID
3337
+ label (str): The label in the agent's core memory
3338
+
3339
+ Returns:
3340
+ block (Block): The block corresponding to the label
3341
+ """
3342
+ block_id = self.server.blocks_agents_manager.get_block_id_for_label(agent_id=agent_id, block_label=label)
3343
+ return self.server.block_manager.get_block_by_id(block_id, actor=self.user)
3344
+
3345
+ def update_agent_memory_block(
3346
+ self,
3347
+ agent_id: str,
3348
+ label: str,
3349
+ value: Optional[str] = None,
3350
+ limit: Optional[int] = None,
3351
+ ):
3352
+ """
3353
+ Update a block in the agent's core memory by specifying its label
3354
+
3355
+ Args:
3356
+ agent_id (str): The agent ID
3357
+ label (str): The label of the block
3358
+ value (str): The new value of the block
3359
+ limit (int): The new limit of the block
3360
+
3361
+ Returns:
3362
+ block (Block): The updated block
3363
+ """
3364
+ block = self.get_agent_memory_block(agent_id, label)
3365
+ data = {}
3366
+ if value:
3367
+ data["value"] = value
3368
+ if limit:
3369
+ data["limit"] = limit
3370
+ return self.server.block_manager.update_block(block.id, actor=self.user, block_update=BlockUpdate(**data))
3371
+
3372
+ def update_block(
3373
+ self,
3374
+ block_id: str,
3375
+ label: Optional[str] = None,
3376
+ value: Optional[str] = None,
3377
+ limit: Optional[int] = None,
3378
+ ):
3379
+ """
3380
+ Update a block given the ID with the provided fields
3381
+
3382
+ Args:
3383
+ block_id (str): ID of the block
3384
+ label (str): Label to assign to the block
3385
+ value (str): Value to assign to the block
3386
+ limit (int): Token limit to assign to the block
3387
+
3388
+ Returns:
3389
+ block (Block): Updated block
3390
+ """
3391
+ data = {}
3392
+ if value:
3393
+ data["value"] = value
3394
+ if limit:
3395
+ data["limit"] = limit
3396
+ if label:
3397
+ data["label"] = label
3398
+ return self.server.block_manager.update_block(block_id, actor=self.user, block_update=BlockUpdate(**data))