letta-nightly 0.5.3.dev20241121022151__py3-none-any.whl → 0.5.4.dev20241122104229__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 +1 -1
- letta/agent.py +25 -22
- letta/client/client.py +71 -7
- letta/functions/helpers.py +5 -38
- letta/metadata.py +17 -4
- letta/schemas/block.py +15 -1
- letta/schemas/memory.py +33 -0
- letta/schemas/tool.py +2 -45
- letta/server/rest_api/routers/v1/agents.py +85 -1
- letta/server/server.py +149 -7
- letta/services/block_manager.py +1 -1
- {letta_nightly-0.5.3.dev20241121022151.dist-info → letta_nightly-0.5.4.dev20241122104229.dist-info}/METADATA +26 -27
- {letta_nightly-0.5.3.dev20241121022151.dist-info → letta_nightly-0.5.4.dev20241122104229.dist-info}/RECORD +16 -16
- {letta_nightly-0.5.3.dev20241121022151.dist-info → letta_nightly-0.5.4.dev20241122104229.dist-info}/LICENSE +0 -0
- {letta_nightly-0.5.3.dev20241121022151.dist-info → letta_nightly-0.5.4.dev20241122104229.dist-info}/WHEEL +0 -0
- {letta_nightly-0.5.3.dev20241121022151.dist-info → letta_nightly-0.5.4.dev20241122104229.dist-info}/entry_points.txt +0 -0
letta/__init__.py
CHANGED
letta/agent.py
CHANGED
|
@@ -1208,6 +1208,30 @@ class Agent(BaseAgent):
|
|
|
1208
1208
|
new_messages = [new_system_message_obj] + self._messages[1:] # swap index 0 (system)
|
|
1209
1209
|
self._messages = new_messages
|
|
1210
1210
|
|
|
1211
|
+
def update_memory_blocks_from_db(self):
|
|
1212
|
+
for block in self.memory.to_dict()["memory"].values():
|
|
1213
|
+
if block.get("templates", False):
|
|
1214
|
+
# we don't expect to update shared memory blocks that
|
|
1215
|
+
# are templates. this is something we could update in the
|
|
1216
|
+
# future if we expect templates to change often.
|
|
1217
|
+
continue
|
|
1218
|
+
block_id = block.get("id")
|
|
1219
|
+
|
|
1220
|
+
# TODO: This is really hacky and we should probably figure out how to
|
|
1221
|
+
db_block = BlockManager().get_block_by_id(block_id=block_id, actor=self.user)
|
|
1222
|
+
if db_block is None:
|
|
1223
|
+
# this case covers if someone has deleted a shared block by interacting
|
|
1224
|
+
# with some other agent.
|
|
1225
|
+
# in that case we should remove this shared block from the agent currently being
|
|
1226
|
+
# evaluated.
|
|
1227
|
+
printd(f"removing block: {block_id=}")
|
|
1228
|
+
continue
|
|
1229
|
+
if not isinstance(db_block.value, str):
|
|
1230
|
+
printd(f"skipping block update, unexpected value: {block_id=}")
|
|
1231
|
+
continue
|
|
1232
|
+
# TODO: we may want to update which columns we're updating from shared memory e.g. the limit
|
|
1233
|
+
self.memory.update_block_value(label=block.get("label", ""), value=db_block.value)
|
|
1234
|
+
|
|
1211
1235
|
def rebuild_memory(self, force=False, update_timestamp=True, ms: Optional[MetadataStore] = None):
|
|
1212
1236
|
"""Rebuilds the system message with the latest memory object and any shared memory block updates"""
|
|
1213
1237
|
curr_system_message = self.messages[0] # this is the system + memory bank, not just the system prompt
|
|
@@ -1219,28 +1243,7 @@ class Agent(BaseAgent):
|
|
|
1219
1243
|
return
|
|
1220
1244
|
|
|
1221
1245
|
if ms:
|
|
1222
|
-
|
|
1223
|
-
if block.get("templates", False):
|
|
1224
|
-
# we don't expect to update shared memory blocks that
|
|
1225
|
-
# are templates. this is something we could update in the
|
|
1226
|
-
# future if we expect templates to change often.
|
|
1227
|
-
continue
|
|
1228
|
-
block_id = block.get("id")
|
|
1229
|
-
|
|
1230
|
-
# TODO: This is really hacky and we should probably figure out how to
|
|
1231
|
-
db_block = BlockManager().get_block_by_id(block_id=block_id, actor=self.user)
|
|
1232
|
-
if db_block is None:
|
|
1233
|
-
# this case covers if someone has deleted a shared block by interacting
|
|
1234
|
-
# with some other agent.
|
|
1235
|
-
# in that case we should remove this shared block from the agent currently being
|
|
1236
|
-
# evaluated.
|
|
1237
|
-
printd(f"removing block: {block_id=}")
|
|
1238
|
-
continue
|
|
1239
|
-
if not isinstance(db_block.value, str):
|
|
1240
|
-
printd(f"skipping block update, unexpected value: {block_id=}")
|
|
1241
|
-
continue
|
|
1242
|
-
# TODO: we may want to update which columns we're updating from shared memory e.g. the limit
|
|
1243
|
-
self.memory.update_block_value(label=block.get("label", ""), value=db_block.value)
|
|
1246
|
+
self.update_memory_blocks_from_db()
|
|
1244
1247
|
|
|
1245
1248
|
# If the memory didn't update, we probably don't want to update the timestamp inside
|
|
1246
1249
|
# For example, if we're doing a system prompt swap, this should probably be False
|
letta/client/client.py
CHANGED
|
@@ -190,9 +190,6 @@ class AbstractClient(object):
|
|
|
190
190
|
def load_langchain_tool(self, langchain_tool: "LangChainBaseTool", additional_imports_module_attr_map: dict[str, str] = None) -> Tool:
|
|
191
191
|
raise NotImplementedError
|
|
192
192
|
|
|
193
|
-
def load_crewai_tool(self, crewai_tool: "CrewAIBaseTool", additional_imports_module_attr_map: dict[str, str] = None) -> Tool:
|
|
194
|
-
raise NotImplementedError
|
|
195
|
-
|
|
196
193
|
def load_composio_tool(self, action: "ActionType") -> Tool:
|
|
197
194
|
raise NotImplementedError
|
|
198
195
|
|
|
@@ -899,8 +896,8 @@ class RESTClient(AbstractClient):
|
|
|
899
896
|
else:
|
|
900
897
|
return Block(**response.json())
|
|
901
898
|
|
|
902
|
-
def update_block(self, block_id: str, name: Optional[str] = None, text: Optional[str] = None) -> Block:
|
|
903
|
-
request = BlockUpdate(id=block_id, template_name=name, value=text)
|
|
899
|
+
def update_block(self, block_id: str, name: Optional[str] = None, text: Optional[str] = None, limit: Optional[int] = None) -> Block:
|
|
900
|
+
request = BlockUpdate(id=block_id, template_name=name, value=text, limit=limit if limit else self.get_block(block_id).limit)
|
|
904
901
|
response = requests.post(f"{self.base_url}/{self.api_prefix}/blocks/{block_id}", json=request.model_dump(), headers=self.headers)
|
|
905
902
|
if response.status_code != 200:
|
|
906
903
|
raise ValueError(f"Failed to update block: {response.text}")
|
|
@@ -1568,6 +1565,53 @@ class RESTClient(AbstractClient):
|
|
|
1568
1565
|
# Parse and return the deleted organization
|
|
1569
1566
|
return Organization(**response.json())
|
|
1570
1567
|
|
|
1568
|
+
def update_agent_memory_label(self, agent_id: str, current_label: str, new_label: str) -> Memory:
|
|
1569
|
+
|
|
1570
|
+
# @router.patch("/{agent_id}/memory/label", response_model=Memory, operation_id="update_agent_memory_label")
|
|
1571
|
+
response = requests.patch(
|
|
1572
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/label",
|
|
1573
|
+
headers=self.headers,
|
|
1574
|
+
json={"current_label": current_label, "new_label": new_label},
|
|
1575
|
+
)
|
|
1576
|
+
if response.status_code != 200:
|
|
1577
|
+
raise ValueError(f"Failed to update agent memory label: {response.text}")
|
|
1578
|
+
return Memory(**response.json())
|
|
1579
|
+
|
|
1580
|
+
def add_agent_memory_block(self, agent_id: str, create_block: BlockCreate) -> Memory:
|
|
1581
|
+
|
|
1582
|
+
# @router.post("/{agent_id}/memory/block", response_model=Memory, operation_id="add_agent_memory_block")
|
|
1583
|
+
response = requests.post(
|
|
1584
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block",
|
|
1585
|
+
headers=self.headers,
|
|
1586
|
+
json=create_block.model_dump(),
|
|
1587
|
+
)
|
|
1588
|
+
if response.status_code != 200:
|
|
1589
|
+
raise ValueError(f"Failed to add agent memory block: {response.text}")
|
|
1590
|
+
return Memory(**response.json())
|
|
1591
|
+
|
|
1592
|
+
def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
|
|
1593
|
+
|
|
1594
|
+
# @router.delete("/{agent_id}/memory/block/{block_label}", response_model=Memory, operation_id="remove_agent_memory_block")
|
|
1595
|
+
response = requests.delete(
|
|
1596
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/block/{block_label}",
|
|
1597
|
+
headers=self.headers,
|
|
1598
|
+
)
|
|
1599
|
+
if response.status_code != 200:
|
|
1600
|
+
raise ValueError(f"Failed to remove agent memory block: {response.text}")
|
|
1601
|
+
return Memory(**response.json())
|
|
1602
|
+
|
|
1603
|
+
def update_agent_memory_limit(self, agent_id: str, block_label: str, limit: int) -> Memory:
|
|
1604
|
+
|
|
1605
|
+
# @router.patch("/{agent_id}/memory/limit", response_model=Memory, operation_id="update_agent_memory_limit")
|
|
1606
|
+
response = requests.patch(
|
|
1607
|
+
f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/memory/limit",
|
|
1608
|
+
headers=self.headers,
|
|
1609
|
+
json={"label": block_label, "limit": limit},
|
|
1610
|
+
)
|
|
1611
|
+
if response.status_code != 200:
|
|
1612
|
+
raise ValueError(f"Failed to update agent memory limit: {response.text}")
|
|
1613
|
+
return Memory(**response.json())
|
|
1614
|
+
|
|
1571
1615
|
|
|
1572
1616
|
class LocalClient(AbstractClient):
|
|
1573
1617
|
"""
|
|
@@ -2690,7 +2734,7 @@ class LocalClient(AbstractClient):
|
|
|
2690
2734
|
Block(label=label, template_name=template_name, value=value, is_template=is_template), actor=self.user
|
|
2691
2735
|
)
|
|
2692
2736
|
|
|
2693
|
-
def update_block(self, block_id: str, name: Optional[str] = None, text: Optional[str] = None) -> Block:
|
|
2737
|
+
def update_block(self, block_id: str, name: Optional[str] = None, text: Optional[str] = None, limit: Optional[int] = None) -> Block:
|
|
2694
2738
|
"""
|
|
2695
2739
|
Update a block
|
|
2696
2740
|
|
|
@@ -2703,7 +2747,9 @@ class LocalClient(AbstractClient):
|
|
|
2703
2747
|
block (Block): Updated block
|
|
2704
2748
|
"""
|
|
2705
2749
|
return self.server.block_manager.update_block(
|
|
2706
|
-
block_id=block_id,
|
|
2750
|
+
block_id=block_id,
|
|
2751
|
+
block_update=BlockUpdate(template_name=name, value=text, limit=limit if limit else self.get_block(block_id).limit),
|
|
2752
|
+
actor=self.user,
|
|
2707
2753
|
)
|
|
2708
2754
|
|
|
2709
2755
|
def get_block(self, block_id: str) -> Block:
|
|
@@ -2774,3 +2820,21 @@ class LocalClient(AbstractClient):
|
|
|
2774
2820
|
|
|
2775
2821
|
def delete_org(self, org_id: str) -> Organization:
|
|
2776
2822
|
return self.server.organization_manager.delete_organization_by_id(org_id=org_id)
|
|
2823
|
+
|
|
2824
|
+
def update_agent_memory_label(self, agent_id: str, current_label: str, new_label: str) -> Memory:
|
|
2825
|
+
return self.server.update_agent_memory_label(
|
|
2826
|
+
user_id=self.user_id, agent_id=agent_id, current_block_label=current_label, new_block_label=new_label
|
|
2827
|
+
)
|
|
2828
|
+
|
|
2829
|
+
def add_agent_memory_block(self, agent_id: str, create_block: BlockCreate) -> Memory:
|
|
2830
|
+
block_req = Block(**create_block.model_dump())
|
|
2831
|
+
block = self.server.block_manager.create_or_update_block(actor=self.user, block=block_req)
|
|
2832
|
+
# Link the block to the agent
|
|
2833
|
+
updated_memory = self.server.link_block_to_agent_memory(user_id=self.user_id, agent_id=agent_id, block_id=block.id)
|
|
2834
|
+
return updated_memory
|
|
2835
|
+
|
|
2836
|
+
def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
|
|
2837
|
+
return self.server.unlink_block_from_agent_memory(user_id=self.user_id, agent_id=agent_id, block_label=block_label)
|
|
2838
|
+
|
|
2839
|
+
def update_agent_memory_limit(self, agent_id: str, block_label: str, limit: int) -> Memory:
|
|
2840
|
+
return self.server.update_agent_memory_limit(user_id=self.user_id, agent_id=agent_id, block_label=block_label, limit=limit)
|
letta/functions/helpers.py
CHANGED
|
@@ -61,36 +61,6 @@ def {func_name}(**kwargs):
|
|
|
61
61
|
return func_name, wrapper_function_str
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
def generate_crewai_tool_wrapper(tool: "CrewAIBaseTool", additional_imports_module_attr_map: dict[str, str] = None) -> tuple[str, str]:
|
|
65
|
-
tool_name = tool.__class__.__name__
|
|
66
|
-
import_statement = f"from crewai_tools import {tool_name}"
|
|
67
|
-
extra_module_imports = generate_import_code(additional_imports_module_attr_map)
|
|
68
|
-
|
|
69
|
-
# Safety check that user has passed in all required imports:
|
|
70
|
-
assert_all_classes_are_imported(tool, additional_imports_module_attr_map)
|
|
71
|
-
|
|
72
|
-
tool_instantiation = f"tool = {generate_imported_tool_instantiation_call_str(tool)}"
|
|
73
|
-
run_call = f"return tool._run(**kwargs)"
|
|
74
|
-
func_name = humps.decamelize(tool_name)
|
|
75
|
-
|
|
76
|
-
# Combine all parts into the wrapper function
|
|
77
|
-
wrapper_function_str = f"""
|
|
78
|
-
def {func_name}(**kwargs):
|
|
79
|
-
if 'self' in kwargs:
|
|
80
|
-
del kwargs['self']
|
|
81
|
-
import importlib
|
|
82
|
-
{import_statement}
|
|
83
|
-
{extra_module_imports}
|
|
84
|
-
{tool_instantiation}
|
|
85
|
-
{run_call}
|
|
86
|
-
"""
|
|
87
|
-
|
|
88
|
-
# Compile safety check
|
|
89
|
-
assert_code_gen_compilable(wrapper_function_str)
|
|
90
|
-
|
|
91
|
-
return func_name, wrapper_function_str
|
|
92
|
-
|
|
93
|
-
|
|
94
64
|
def assert_code_gen_compilable(code_str):
|
|
95
65
|
try:
|
|
96
66
|
compile(code_str, "<string>", "exec")
|
|
@@ -98,9 +68,7 @@ def assert_code_gen_compilable(code_str):
|
|
|
98
68
|
print(f"Syntax error in code: {e}")
|
|
99
69
|
|
|
100
70
|
|
|
101
|
-
def assert_all_classes_are_imported(
|
|
102
|
-
tool: Union["LangChainBaseTool", "CrewAIBaseTool"], additional_imports_module_attr_map: dict[str, str]
|
|
103
|
-
) -> None:
|
|
71
|
+
def assert_all_classes_are_imported(tool: Union["LangChainBaseTool"], additional_imports_module_attr_map: dict[str, str]) -> None:
|
|
104
72
|
# Safety check that user has passed in all required imports:
|
|
105
73
|
tool_name = tool.__class__.__name__
|
|
106
74
|
current_class_imports = {tool_name}
|
|
@@ -114,7 +82,7 @@ def assert_all_classes_are_imported(
|
|
|
114
82
|
raise RuntimeError(err_msg)
|
|
115
83
|
|
|
116
84
|
|
|
117
|
-
def find_required_class_names_for_import(obj: Union["LangChainBaseTool",
|
|
85
|
+
def find_required_class_names_for_import(obj: Union["LangChainBaseTool", BaseModel]) -> list[str]:
|
|
118
86
|
"""
|
|
119
87
|
Finds all the class names for required imports when instantiating the `obj`.
|
|
120
88
|
NOTE: This does not return the full import path, only the class name.
|
|
@@ -202,10 +170,10 @@ def generate_imported_tool_instantiation_call_str(obj: Any) -> Optional[str]:
|
|
|
202
170
|
else:
|
|
203
171
|
# Otherwise, if it is none of the above, that usually means it is a custom Python class that is NOT a BaseModel
|
|
204
172
|
# Thus, we cannot get enough information about it to stringify it
|
|
205
|
-
# This may cause issues, but we are making the assumption that any of these custom Python types are handled correctly by the parent library, such as LangChain
|
|
173
|
+
# This may cause issues, but we are making the assumption that any of these custom Python types are handled correctly by the parent library, such as LangChain
|
|
206
174
|
# An example would be that WikipediaAPIWrapper has an argument that is a wikipedia (pip install wikipedia) object
|
|
207
175
|
# We cannot stringify this easily, but WikipediaAPIWrapper handles the setting of this parameter internally
|
|
208
|
-
# This assumption seems fair to me, since usually they are external imports, and LangChain
|
|
176
|
+
# This assumption seems fair to me, since usually they are external imports, and LangChain should be bundling those as module-level imports within the tool
|
|
209
177
|
# We throw a warning here anyway and provide the class name
|
|
210
178
|
print(
|
|
211
179
|
f"[WARNING] Skipping parsing unknown class {obj.__class__.__name__} (does not inherit from the Pydantic BaseModel and is not a basic Python type)"
|
|
@@ -219,10 +187,9 @@ def generate_imported_tool_instantiation_call_str(obj: Any) -> Optional[str]:
|
|
|
219
187
|
|
|
220
188
|
|
|
221
189
|
def is_base_model(obj: Any):
|
|
222
|
-
from crewai_tools.tools.base_tool import BaseModel as CrewAiBaseModel
|
|
223
190
|
from langchain_core.pydantic_v1 import BaseModel as LangChainBaseModel
|
|
224
191
|
|
|
225
|
-
return isinstance(obj, BaseModel) or isinstance(obj, LangChainBaseModel)
|
|
192
|
+
return isinstance(obj, BaseModel) or isinstance(obj, LangChainBaseModel)
|
|
226
193
|
|
|
227
194
|
|
|
228
195
|
def generate_import_code(module_attr_map: Optional[dict]):
|
letta/metadata.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import secrets
|
|
5
|
+
import warnings
|
|
5
6
|
from typing import List, Optional
|
|
6
7
|
|
|
7
8
|
from sqlalchemy import JSON, Column, DateTime, Index, String, TypeDecorator
|
|
@@ -353,8 +354,14 @@ class MetadataStore:
|
|
|
353
354
|
raise ValueError(f"Agent with name {agent.name} already exists")
|
|
354
355
|
fields = vars(agent)
|
|
355
356
|
fields["memory"] = agent.memory.to_dict()
|
|
356
|
-
|
|
357
|
-
|
|
357
|
+
if "_internal_memory" in fields:
|
|
358
|
+
del fields["_internal_memory"]
|
|
359
|
+
else:
|
|
360
|
+
warnings.warn(f"Agent {agent.id} has no _internal_memory field")
|
|
361
|
+
if "tags" in fields:
|
|
362
|
+
del fields["tags"]
|
|
363
|
+
else:
|
|
364
|
+
warnings.warn(f"Agent {agent.id} has no tags field")
|
|
358
365
|
session.add(AgentModel(**fields))
|
|
359
366
|
session.commit()
|
|
360
367
|
|
|
@@ -364,8 +371,14 @@ class MetadataStore:
|
|
|
364
371
|
fields = vars(agent)
|
|
365
372
|
if isinstance(agent.memory, Memory): # TODO: this is nasty but this whole class will soon be removed so whatever
|
|
366
373
|
fields["memory"] = agent.memory.to_dict()
|
|
367
|
-
|
|
368
|
-
|
|
374
|
+
if "_internal_memory" in fields:
|
|
375
|
+
del fields["_internal_memory"]
|
|
376
|
+
else:
|
|
377
|
+
warnings.warn(f"Agent {agent.id} has no _internal_memory field")
|
|
378
|
+
if "tags" in fields:
|
|
379
|
+
del fields["tags"]
|
|
380
|
+
else:
|
|
381
|
+
warnings.warn(f"Agent {agent.id} has no tags field")
|
|
369
382
|
session.query(AgentModel).filter(AgentModel.id == agent.id).update(fields)
|
|
370
383
|
session.commit()
|
|
371
384
|
|
letta/schemas/block.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from pydantic import Field, model_validator
|
|
3
|
+
from pydantic import BaseModel, Field, model_validator
|
|
4
4
|
from typing_extensions import Self
|
|
5
5
|
|
|
6
6
|
from letta.schemas.letta_base import LettaBase
|
|
@@ -95,6 +95,13 @@ class BlockCreate(BaseBlock):
|
|
|
95
95
|
label: str = Field(..., description="Label of the block.")
|
|
96
96
|
|
|
97
97
|
|
|
98
|
+
class BlockLabelUpdate(BaseModel):
|
|
99
|
+
"""Update the label of a block"""
|
|
100
|
+
|
|
101
|
+
current_label: str = Field(..., description="Current label of the block.")
|
|
102
|
+
new_label: str = Field(..., description="New label of the block.")
|
|
103
|
+
|
|
104
|
+
|
|
98
105
|
class CreatePersona(BlockCreate):
|
|
99
106
|
"""Create a persona block"""
|
|
100
107
|
|
|
@@ -117,6 +124,13 @@ class BlockUpdate(BaseBlock):
|
|
|
117
124
|
extra = "ignore" # Ignores extra fields
|
|
118
125
|
|
|
119
126
|
|
|
127
|
+
class BlockLimitUpdate(BaseModel):
|
|
128
|
+
"""Update the limit of a block"""
|
|
129
|
+
|
|
130
|
+
label: str = Field(..., description="Label of the block.")
|
|
131
|
+
limit: int = Field(..., description="New limit of the block.")
|
|
132
|
+
|
|
133
|
+
|
|
120
134
|
class UpdatePersona(BlockUpdate):
|
|
121
135
|
"""Update a persona block"""
|
|
122
136
|
|
letta/schemas/memory.py
CHANGED
|
@@ -158,6 +158,13 @@ class Memory(BaseModel, validate_assignment=True):
|
|
|
158
158
|
|
|
159
159
|
self.memory[block.label] = block
|
|
160
160
|
|
|
161
|
+
def unlink_block(self, block_label: str) -> Block:
|
|
162
|
+
"""Unlink a block from the memory object"""
|
|
163
|
+
if block_label not in self.memory:
|
|
164
|
+
raise ValueError(f"Block with label {block_label} does not exist")
|
|
165
|
+
|
|
166
|
+
return self.memory.pop(block_label)
|
|
167
|
+
|
|
161
168
|
def update_block_value(self, label: str, value: str):
|
|
162
169
|
"""Update the value of a block"""
|
|
163
170
|
if label not in self.memory:
|
|
@@ -167,6 +174,32 @@ class Memory(BaseModel, validate_assignment=True):
|
|
|
167
174
|
|
|
168
175
|
self.memory[label].value = value
|
|
169
176
|
|
|
177
|
+
def update_block_label(self, current_label: str, new_label: str):
|
|
178
|
+
"""Update the label of a block"""
|
|
179
|
+
if current_label not in self.memory:
|
|
180
|
+
raise ValueError(f"Block with label {current_label} does not exist")
|
|
181
|
+
if not isinstance(new_label, str):
|
|
182
|
+
raise ValueError(f"Provided new label must be a string")
|
|
183
|
+
|
|
184
|
+
# First change the label of the block
|
|
185
|
+
self.memory[current_label].label = new_label
|
|
186
|
+
|
|
187
|
+
# Then swap the block to the new label
|
|
188
|
+
self.memory[new_label] = self.memory.pop(current_label)
|
|
189
|
+
|
|
190
|
+
def update_block_limit(self, label: str, limit: int):
|
|
191
|
+
"""Update the limit of a block"""
|
|
192
|
+
if label not in self.memory:
|
|
193
|
+
raise ValueError(f"Block with label {label} does not exist")
|
|
194
|
+
if not isinstance(limit, int):
|
|
195
|
+
raise ValueError(f"Provided limit must be an integer")
|
|
196
|
+
|
|
197
|
+
# Check to make sure the new limit is greater than the current length of the block
|
|
198
|
+
if len(self.memory[label].value) > limit:
|
|
199
|
+
raise ValueError(f"New limit {limit} is less than the current length of the block {len(self.memory[label].value)}")
|
|
200
|
+
|
|
201
|
+
self.memory[label].limit = limit
|
|
202
|
+
|
|
170
203
|
|
|
171
204
|
# TODO: ideally this is refactored into ChatMemory and the subclasses are given more specific names.
|
|
172
205
|
class BasicBlockMemory(Memory):
|
letta/schemas/tool.py
CHANGED
|
@@ -4,13 +4,9 @@ from pydantic import Field
|
|
|
4
4
|
|
|
5
5
|
from letta.functions.helpers import (
|
|
6
6
|
generate_composio_tool_wrapper,
|
|
7
|
-
generate_crewai_tool_wrapper,
|
|
8
7
|
generate_langchain_tool_wrapper,
|
|
9
8
|
)
|
|
10
|
-
from letta.functions.schema_generator import
|
|
11
|
-
generate_schema_from_args_schema_v1,
|
|
12
|
-
generate_schema_from_args_schema_v2,
|
|
13
|
-
)
|
|
9
|
+
from letta.functions.schema_generator import generate_schema_from_args_schema_v2
|
|
14
10
|
from letta.schemas.letta_base import LettaBase
|
|
15
11
|
from letta.schemas.openai.chat_completions import ToolCall
|
|
16
12
|
|
|
@@ -132,37 +128,7 @@ class ToolCreate(LettaBase):
|
|
|
132
128
|
tags = ["langchain"]
|
|
133
129
|
# NOTE: langchain tools may come from different packages
|
|
134
130
|
wrapper_func_name, wrapper_function_str = generate_langchain_tool_wrapper(langchain_tool, additional_imports_module_attr_map)
|
|
135
|
-
json_schema =
|
|
136
|
-
|
|
137
|
-
return cls(
|
|
138
|
-
name=wrapper_func_name,
|
|
139
|
-
description=description,
|
|
140
|
-
source_type=source_type,
|
|
141
|
-
tags=tags,
|
|
142
|
-
source_code=wrapper_function_str,
|
|
143
|
-
json_schema=json_schema,
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
@classmethod
|
|
147
|
-
def from_crewai(
|
|
148
|
-
cls,
|
|
149
|
-
crewai_tool: "CrewAIBaseTool",
|
|
150
|
-
additional_imports_module_attr_map: dict[str, str] = None,
|
|
151
|
-
) -> "ToolCreate":
|
|
152
|
-
"""
|
|
153
|
-
Class method to create an instance of Tool from a crewAI BaseTool object.
|
|
154
|
-
|
|
155
|
-
Args:
|
|
156
|
-
crewai_tool (CrewAIBaseTool): An instance of a crewAI BaseTool (BaseTool from crewai)
|
|
157
|
-
|
|
158
|
-
Returns:
|
|
159
|
-
Tool: A Letta Tool initialized with attributes derived from the provided crewAI BaseTool object.
|
|
160
|
-
"""
|
|
161
|
-
description = crewai_tool.description
|
|
162
|
-
source_type = "python"
|
|
163
|
-
tags = ["crew-ai"]
|
|
164
|
-
wrapper_func_name, wrapper_function_str = generate_crewai_tool_wrapper(crewai_tool, additional_imports_module_attr_map)
|
|
165
|
-
json_schema = generate_schema_from_args_schema_v1(crewai_tool.args_schema, name=wrapper_func_name, description=description)
|
|
131
|
+
json_schema = generate_schema_from_args_schema_v2(langchain_tool.args_schema, name=wrapper_func_name, description=description)
|
|
166
132
|
|
|
167
133
|
return cls(
|
|
168
134
|
name=wrapper_func_name,
|
|
@@ -185,15 +151,6 @@ class ToolCreate(LettaBase):
|
|
|
185
151
|
|
|
186
152
|
return [wikipedia_tool]
|
|
187
153
|
|
|
188
|
-
@classmethod
|
|
189
|
-
def load_default_crewai_tools(cls) -> List["ToolCreate"]:
|
|
190
|
-
# For now, we only support scrape website tool
|
|
191
|
-
from crewai_tools import ScrapeWebsiteTool
|
|
192
|
-
|
|
193
|
-
web_scrape_tool = ToolCreate.from_crewai(ScrapeWebsiteTool())
|
|
194
|
-
|
|
195
|
-
return [web_scrape_tool]
|
|
196
|
-
|
|
197
154
|
@classmethod
|
|
198
155
|
def load_default_composio_tools(cls) -> List["ToolCreate"]:
|
|
199
156
|
from composio_langchain import Action
|
|
@@ -7,6 +7,7 @@ from fastapi.responses import JSONResponse, StreamingResponse
|
|
|
7
7
|
|
|
8
8
|
from letta.constants import DEFAULT_MESSAGE_TOOL, DEFAULT_MESSAGE_TOOL_KWARG
|
|
9
9
|
from letta.schemas.agent import AgentState, CreateAgent, UpdateAgentState
|
|
10
|
+
from letta.schemas.block import Block, BlockCreate, BlockLabelUpdate, BlockLimitUpdate
|
|
10
11
|
from letta.schemas.enums import MessageStreamStatus
|
|
11
12
|
from letta.schemas.letta_message import (
|
|
12
13
|
LegacyLettaMessage,
|
|
@@ -217,7 +218,9 @@ def update_agent_memory(
|
|
|
217
218
|
):
|
|
218
219
|
"""
|
|
219
220
|
Update the core memory of a specific agent.
|
|
220
|
-
|
|
221
|
+
This endpoint accepts new memory contents (labels as keys, and values as values) and updates the core memory of the agent identified by the user ID and agent ID.
|
|
222
|
+
This endpoint accepts new memory contents to update the core memory of the agent.
|
|
223
|
+
This endpoint only supports modifying existing blocks; it does not support deleting/unlinking or creating/linking blocks.
|
|
221
224
|
"""
|
|
222
225
|
actor = server.get_user_or_default(user_id=user_id)
|
|
223
226
|
|
|
@@ -225,6 +228,87 @@ def update_agent_memory(
|
|
|
225
228
|
return memory
|
|
226
229
|
|
|
227
230
|
|
|
231
|
+
@router.patch("/{agent_id}/memory/label", response_model=Memory, operation_id="update_agent_memory_label")
|
|
232
|
+
def update_agent_memory_label(
|
|
233
|
+
agent_id: str,
|
|
234
|
+
update_label: BlockLabelUpdate = Body(...),
|
|
235
|
+
server: "SyncServer" = Depends(get_letta_server),
|
|
236
|
+
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
237
|
+
):
|
|
238
|
+
"""
|
|
239
|
+
Update the label of a block in an agent's memory.
|
|
240
|
+
"""
|
|
241
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
242
|
+
|
|
243
|
+
memory = server.update_agent_memory_label(
|
|
244
|
+
user_id=actor.id, agent_id=agent_id, current_block_label=update_label.current_label, new_block_label=update_label.new_label
|
|
245
|
+
)
|
|
246
|
+
return memory
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@router.post("/{agent_id}/memory/block", response_model=Memory, operation_id="add_agent_memory_block")
|
|
250
|
+
def add_agent_memory_block(
|
|
251
|
+
agent_id: str,
|
|
252
|
+
create_block: BlockCreate = Body(...),
|
|
253
|
+
server: "SyncServer" = Depends(get_letta_server),
|
|
254
|
+
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
255
|
+
):
|
|
256
|
+
"""
|
|
257
|
+
Creates a memory block and links it to the agent.
|
|
258
|
+
"""
|
|
259
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
260
|
+
|
|
261
|
+
# Copied from POST /blocks
|
|
262
|
+
block_req = Block(**create_block.model_dump())
|
|
263
|
+
block = server.block_manager.create_or_update_block(actor=actor, block=block_req)
|
|
264
|
+
|
|
265
|
+
# Link the block to the agent
|
|
266
|
+
updated_memory = server.link_block_to_agent_memory(user_id=actor.id, agent_id=agent_id, block_id=block.id)
|
|
267
|
+
|
|
268
|
+
return updated_memory
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@router.delete("/{agent_id}/memory/block/{block_label}", response_model=Memory, operation_id="remove_agent_memory_block")
|
|
272
|
+
def remove_agent_memory_block(
|
|
273
|
+
agent_id: str,
|
|
274
|
+
# TODO should this be block_id, or the label?
|
|
275
|
+
# I think label is OK since it's user-friendly + guaranteed to be unique within a Memory object
|
|
276
|
+
block_label: str,
|
|
277
|
+
server: "SyncServer" = Depends(get_letta_server),
|
|
278
|
+
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
279
|
+
):
|
|
280
|
+
"""
|
|
281
|
+
Removes a memory block from an agent by unlnking it. If the block is not linked to any other agent, it is deleted.
|
|
282
|
+
"""
|
|
283
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
284
|
+
|
|
285
|
+
# Unlink the block from the agent
|
|
286
|
+
updated_memory = server.unlink_block_from_agent_memory(user_id=actor.id, agent_id=agent_id, block_label=block_label)
|
|
287
|
+
|
|
288
|
+
return updated_memory
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
@router.patch("/{agent_id}/memory/limit", response_model=Memory, operation_id="update_agent_memory_limit")
|
|
292
|
+
def update_agent_memory_limit(
|
|
293
|
+
agent_id: str,
|
|
294
|
+
update_label: BlockLimitUpdate = Body(...),
|
|
295
|
+
server: "SyncServer" = Depends(get_letta_server),
|
|
296
|
+
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
297
|
+
):
|
|
298
|
+
"""
|
|
299
|
+
Update the limit of a block in an agent's memory.
|
|
300
|
+
"""
|
|
301
|
+
actor = server.get_user_or_default(user_id=user_id)
|
|
302
|
+
|
|
303
|
+
memory = server.update_agent_memory_limit(
|
|
304
|
+
user_id=actor.id,
|
|
305
|
+
agent_id=agent_id,
|
|
306
|
+
block_label=update_label.label,
|
|
307
|
+
limit=update_label.limit,
|
|
308
|
+
)
|
|
309
|
+
return memory
|
|
310
|
+
|
|
311
|
+
|
|
228
312
|
@router.get("/{agent_id}/memory/recall", response_model=RecallMemorySummary, operation_id="get_agent_recall_memory_summary")
|
|
229
313
|
def get_agent_recall_memory_summary(
|
|
230
314
|
agent_id: str,
|
letta/server/server.py
CHANGED
|
@@ -328,6 +328,15 @@ class SyncServer(Server):
|
|
|
328
328
|
)
|
|
329
329
|
)
|
|
330
330
|
|
|
331
|
+
def save_agents(self):
|
|
332
|
+
"""Saves all the agents that are in the in-memory object store"""
|
|
333
|
+
for agent_d in self.active_agents:
|
|
334
|
+
try:
|
|
335
|
+
save_agent(agent_d["agent"], self.ms)
|
|
336
|
+
logger.info(f"Saved agent {agent_d['agent_id']}")
|
|
337
|
+
except Exception as e:
|
|
338
|
+
logger.exception(f"Error occurred while trying to save agent {agent_d['agent_id']}:\n{e}")
|
|
339
|
+
|
|
331
340
|
def _get_agent(self, user_id: str, agent_id: str) -> Union[Agent, None]:
|
|
332
341
|
"""Get the agent object from the in-memory object store"""
|
|
333
342
|
for d in self.active_agents:
|
|
@@ -400,8 +409,10 @@ class SyncServer(Server):
|
|
|
400
409
|
logger.exception(f"Error occurred while trying to get agent {agent_id}:\n{e}")
|
|
401
410
|
raise
|
|
402
411
|
|
|
403
|
-
def _get_or_load_agent(self, agent_id: str) -> Agent:
|
|
412
|
+
def _get_or_load_agent(self, agent_id: str, caching: bool = True) -> Agent:
|
|
404
413
|
"""Check if the agent is in-memory, then load"""
|
|
414
|
+
|
|
415
|
+
# Gets the agent state
|
|
405
416
|
agent_state = self.ms.get_agent(agent_id=agent_id)
|
|
406
417
|
if not agent_state:
|
|
407
418
|
raise ValueError(f"Agent does not exist")
|
|
@@ -409,11 +420,24 @@ class SyncServer(Server):
|
|
|
409
420
|
actor = self.user_manager.get_user_by_id(user_id)
|
|
410
421
|
|
|
411
422
|
logger.debug(f"Checking for agent user_id={user_id} agent_id={agent_id}")
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
423
|
+
if caching:
|
|
424
|
+
# TODO: consider disabling loading cached agents due to potential concurrency issues
|
|
425
|
+
letta_agent = self._get_agent(user_id=user_id, agent_id=agent_id)
|
|
426
|
+
if not letta_agent:
|
|
427
|
+
logger.debug(f"Agent not loaded, loading agent user_id={user_id} agent_id={agent_id}")
|
|
428
|
+
letta_agent = self._load_agent(agent_id=agent_id, actor=actor)
|
|
429
|
+
else:
|
|
430
|
+
# This breaks unit tests in test_local_client.py
|
|
416
431
|
letta_agent = self._load_agent(agent_id=agent_id, actor=actor)
|
|
432
|
+
|
|
433
|
+
# letta_agent = self._get_agent(user_id=user_id, agent_id=agent_id)
|
|
434
|
+
# if not letta_agent:
|
|
435
|
+
# logger.debug(f"Agent not loaded, loading agent user_id={user_id} agent_id={agent_id}")
|
|
436
|
+
|
|
437
|
+
# NOTE: no longer caching, always forcing a lot from the database
|
|
438
|
+
# Loads the agent objects
|
|
439
|
+
# letta_agent = self._load_agent(agent_id=agent_id, actor=actor)
|
|
440
|
+
|
|
417
441
|
return letta_agent
|
|
418
442
|
|
|
419
443
|
def _step(
|
|
@@ -1376,8 +1400,9 @@ class SyncServer(Server):
|
|
|
1376
1400
|
# Get the agent object (loaded in memory)
|
|
1377
1401
|
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1378
1402
|
assert isinstance(letta_agent.memory, Memory)
|
|
1379
|
-
agent_state = letta_agent.agent_state.model_copy(deep=True)
|
|
1380
1403
|
|
|
1404
|
+
letta_agent.update_memory_blocks_from_db()
|
|
1405
|
+
agent_state = letta_agent.agent_state.model_copy(deep=True)
|
|
1381
1406
|
# Load the tags in for the agent_state
|
|
1382
1407
|
agent_state.tags = self.agents_tags_manager.get_tags_for_agent(agent_id=agent_id, actor=user)
|
|
1383
1408
|
return agent_state
|
|
@@ -1431,6 +1456,7 @@ class SyncServer(Server):
|
|
|
1431
1456
|
# If we modified the memory contents, we need to rebuild the memory block inside the system message
|
|
1432
1457
|
if modified:
|
|
1433
1458
|
letta_agent.rebuild_memory()
|
|
1459
|
+
# letta_agent.rebuild_memory(force=True, ms=self.ms) # This breaks unit tests in test_local_client.py
|
|
1434
1460
|
# save agent
|
|
1435
1461
|
save_agent(letta_agent, self.ms)
|
|
1436
1462
|
|
|
@@ -1723,7 +1749,7 @@ class SyncServer(Server):
|
|
|
1723
1749
|
def add_default_external_tools(self, actor: User) -> bool:
|
|
1724
1750
|
"""Add default langchain tools. Return true if successful, false otherwise."""
|
|
1725
1751
|
success = True
|
|
1726
|
-
tool_creates = ToolCreate.load_default_langchain_tools()
|
|
1752
|
+
tool_creates = ToolCreate.load_default_langchain_tools()
|
|
1727
1753
|
if tool_settings.composio_api_key:
|
|
1728
1754
|
tool_creates += ToolCreate.load_default_composio_tools()
|
|
1729
1755
|
for tool_create in tool_creates:
|
|
@@ -1817,3 +1843,119 @@ class SyncServer(Server):
|
|
|
1817
1843
|
# Get the current message
|
|
1818
1844
|
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1819
1845
|
return letta_agent.get_context_window()
|
|
1846
|
+
|
|
1847
|
+
def update_agent_memory_label(self, user_id: str, agent_id: str, current_block_label: str, new_block_label: str) -> Memory:
|
|
1848
|
+
"""Update the label of a block in an agent's memory"""
|
|
1849
|
+
|
|
1850
|
+
# Get the user
|
|
1851
|
+
user = self.user_manager.get_user_by_id(user_id=user_id)
|
|
1852
|
+
|
|
1853
|
+
# Link a block to an agent's memory
|
|
1854
|
+
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1855
|
+
letta_agent.memory.update_block_label(current_label=current_block_label, new_label=new_block_label)
|
|
1856
|
+
assert new_block_label in letta_agent.memory.list_block_labels()
|
|
1857
|
+
self.block_manager.create_or_update_block(block=letta_agent.memory.get_block(new_block_label), actor=user)
|
|
1858
|
+
|
|
1859
|
+
# check that the block was updated
|
|
1860
|
+
updated_block = self.block_manager.get_block_by_id(block_id=letta_agent.memory.get_block(new_block_label).id, actor=user)
|
|
1861
|
+
|
|
1862
|
+
# Recompile the agent memory
|
|
1863
|
+
letta_agent.rebuild_memory(force=True, ms=self.ms)
|
|
1864
|
+
|
|
1865
|
+
# save agent
|
|
1866
|
+
save_agent(letta_agent, self.ms)
|
|
1867
|
+
|
|
1868
|
+
updated_agent = self.ms.get_agent(agent_id=agent_id)
|
|
1869
|
+
if updated_agent is None:
|
|
1870
|
+
raise ValueError(f"Agent with id {agent_id} not found after linking block")
|
|
1871
|
+
assert new_block_label in updated_agent.memory.list_block_labels()
|
|
1872
|
+
assert current_block_label not in updated_agent.memory.list_block_labels()
|
|
1873
|
+
return updated_agent.memory
|
|
1874
|
+
|
|
1875
|
+
def link_block_to_agent_memory(self, user_id: str, agent_id: str, block_id: str) -> Memory:
|
|
1876
|
+
"""Link a block to an agent's memory"""
|
|
1877
|
+
|
|
1878
|
+
# Get the user
|
|
1879
|
+
user = self.user_manager.get_user_by_id(user_id=user_id)
|
|
1880
|
+
|
|
1881
|
+
# Get the block first
|
|
1882
|
+
block = self.block_manager.get_block_by_id(block_id=block_id, actor=user)
|
|
1883
|
+
if block is None:
|
|
1884
|
+
raise ValueError(f"Block with id {block_id} not found")
|
|
1885
|
+
|
|
1886
|
+
# Link a block to an agent's memory
|
|
1887
|
+
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1888
|
+
letta_agent.memory.link_block(block=block)
|
|
1889
|
+
assert block.label in letta_agent.memory.list_block_labels()
|
|
1890
|
+
|
|
1891
|
+
# Recompile the agent memory
|
|
1892
|
+
letta_agent.rebuild_memory(force=True, ms=self.ms)
|
|
1893
|
+
|
|
1894
|
+
# save agent
|
|
1895
|
+
save_agent(letta_agent, self.ms)
|
|
1896
|
+
|
|
1897
|
+
updated_agent = self.ms.get_agent(agent_id=agent_id)
|
|
1898
|
+
if updated_agent is None:
|
|
1899
|
+
raise ValueError(f"Agent with id {agent_id} not found after linking block")
|
|
1900
|
+
assert block.label in updated_agent.memory.list_block_labels()
|
|
1901
|
+
|
|
1902
|
+
return updated_agent.memory
|
|
1903
|
+
|
|
1904
|
+
def unlink_block_from_agent_memory(self, user_id: str, agent_id: str, block_label: str, delete_if_no_ref: bool = True) -> Memory:
|
|
1905
|
+
"""Unlink a block from an agent's memory. If the block is not linked to any agent, delete it."""
|
|
1906
|
+
|
|
1907
|
+
# Get the user
|
|
1908
|
+
user = self.user_manager.get_user_by_id(user_id=user_id)
|
|
1909
|
+
|
|
1910
|
+
# Link a block to an agent's memory
|
|
1911
|
+
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1912
|
+
unlinked_block = letta_agent.memory.unlink_block(block_label=block_label)
|
|
1913
|
+
assert unlinked_block.label not in letta_agent.memory.list_block_labels()
|
|
1914
|
+
|
|
1915
|
+
# Check if the block is linked to any other agent
|
|
1916
|
+
# TODO needs reference counting GC to handle loose blocks
|
|
1917
|
+
# block = self.block_manager.get_block_by_id(block_id=unlinked_block.id, actor=user)
|
|
1918
|
+
# if block is None:
|
|
1919
|
+
# raise ValueError(f"Block with id {block_id} not found")
|
|
1920
|
+
|
|
1921
|
+
# Recompile the agent memory
|
|
1922
|
+
letta_agent.rebuild_memory(force=True, ms=self.ms)
|
|
1923
|
+
|
|
1924
|
+
# save agent
|
|
1925
|
+
save_agent(letta_agent, self.ms)
|
|
1926
|
+
|
|
1927
|
+
updated_agent = self.ms.get_agent(agent_id=agent_id)
|
|
1928
|
+
if updated_agent is None:
|
|
1929
|
+
raise ValueError(f"Agent with id {agent_id} not found after linking block")
|
|
1930
|
+
assert unlinked_block.label not in updated_agent.memory.list_block_labels()
|
|
1931
|
+
return updated_agent.memory
|
|
1932
|
+
|
|
1933
|
+
def update_agent_memory_limit(self, user_id: str, agent_id: str, block_label: str, limit: int) -> Memory:
|
|
1934
|
+
"""Update the limit of a block in an agent's memory"""
|
|
1935
|
+
|
|
1936
|
+
# Get the user
|
|
1937
|
+
user = self.user_manager.get_user_by_id(user_id=user_id)
|
|
1938
|
+
|
|
1939
|
+
# Link a block to an agent's memory
|
|
1940
|
+
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1941
|
+
letta_agent.memory.update_block_limit(label=block_label, limit=limit)
|
|
1942
|
+
assert block_label in letta_agent.memory.list_block_labels()
|
|
1943
|
+
|
|
1944
|
+
# write out the update the database
|
|
1945
|
+
self.block_manager.create_or_update_block(block=letta_agent.memory.get_block(block_label), actor=user)
|
|
1946
|
+
|
|
1947
|
+
# check that the block was updated
|
|
1948
|
+
updated_block = self.block_manager.get_block_by_id(block_id=letta_agent.memory.get_block(block_label).id, actor=user)
|
|
1949
|
+
assert updated_block and updated_block.limit == limit
|
|
1950
|
+
|
|
1951
|
+
# Recompile the agent memory
|
|
1952
|
+
letta_agent.rebuild_memory(force=True, ms=self.ms)
|
|
1953
|
+
|
|
1954
|
+
# save agent
|
|
1955
|
+
save_agent(letta_agent, self.ms)
|
|
1956
|
+
|
|
1957
|
+
updated_agent = self.ms.get_agent(agent_id=agent_id)
|
|
1958
|
+
if updated_agent is None:
|
|
1959
|
+
raise ValueError(f"Agent with id {agent_id} not found after linking block")
|
|
1960
|
+
assert updated_agent.memory.get_block(label=block_label).limit == limit
|
|
1961
|
+
return updated_agent.memory
|
letta/services/block_manager.py
CHANGED
|
@@ -34,7 +34,7 @@ class BlockManager:
|
|
|
34
34
|
return block.to_pydantic()
|
|
35
35
|
|
|
36
36
|
@enforce_types
|
|
37
|
-
def update_block(self, block_id: str, block_update: BlockUpdate, actor: PydanticUser) -> PydanticBlock:
|
|
37
|
+
def update_block(self, block_id: str, block_update: BlockUpdate, actor: PydanticUser, limit: Optional[int] = None) -> PydanticBlock:
|
|
38
38
|
"""Update a block by its ID with the given BlockUpdate object."""
|
|
39
39
|
with self.session_maker() as session:
|
|
40
40
|
block = BlockModel.read(db_session=session, identifier=block_id, actor=actor)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: letta-nightly
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4.dev20241122104229
|
|
4
4
|
Summary: Create LLM agents with long-term memory and custom tools
|
|
5
5
|
License: Apache License
|
|
6
6
|
Author: Letta Team
|
|
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Provides-Extra: all
|
|
14
15
|
Provides-Extra: autogen
|
|
15
16
|
Provides-Extra: dev
|
|
16
17
|
Provides-Extra: external-tools
|
|
@@ -21,48 +22,46 @@ Provides-Extra: qdrant
|
|
|
21
22
|
Provides-Extra: server
|
|
22
23
|
Provides-Extra: tests
|
|
23
24
|
Requires-Dist: alembic (>=1.13.3,<2.0.0)
|
|
24
|
-
Requires-Dist: autoflake (>=2.3.0,<3.0.0) ; extra == "dev"
|
|
25
|
-
Requires-Dist: black[jupyter] (>=24.2.0,<25.0.0) ; extra == "dev"
|
|
25
|
+
Requires-Dist: autoflake (>=2.3.0,<3.0.0) ; extra == "dev" or extra == "all"
|
|
26
|
+
Requires-Dist: black[jupyter] (>=24.2.0,<25.0.0) ; extra == "dev" or extra == "all"
|
|
26
27
|
Requires-Dist: chromadb (>=0.4.24,<0.5.0)
|
|
27
|
-
Requires-Dist: composio-core (>=0.5.34,<0.6.0) ; extra == "external-tools"
|
|
28
|
-
Requires-Dist: composio-langchain (>=0.5.28,<0.6.0) ; extra == "external-tools"
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist: crewai-tools (>=0.8.3,<0.9.0) ; extra == "external-tools"
|
|
31
|
-
Requires-Dist: datasets (>=2.14.6,<3.0.0) ; extra == "dev"
|
|
28
|
+
Requires-Dist: composio-core (>=0.5.34,<0.6.0) ; extra == "external-tools" or extra == "all"
|
|
29
|
+
Requires-Dist: composio-langchain (>=0.5.28,<0.6.0) ; extra == "external-tools" or extra == "all"
|
|
30
|
+
Requires-Dist: datasets (>=2.14.6,<3.0.0) ; extra == "dev" or extra == "all"
|
|
32
31
|
Requires-Dist: demjson3 (>=3.0.6,<4.0.0)
|
|
33
|
-
Requires-Dist: docker (>=7.1.0,<8.0.0) ; extra == "external-tools"
|
|
32
|
+
Requires-Dist: docker (>=7.1.0,<8.0.0) ; extra == "external-tools" or extra == "all"
|
|
34
33
|
Requires-Dist: docstring-parser (>=0.16,<0.17)
|
|
35
34
|
Requires-Dist: docx2txt (>=0.8,<0.9)
|
|
36
|
-
Requires-Dist: fastapi (>=0.104.1,<0.105.0) ; extra == "server"
|
|
35
|
+
Requires-Dist: fastapi (>=0.104.1,<0.105.0) ; extra == "server" or extra == "all"
|
|
37
36
|
Requires-Dist: html2text (>=2020.1.16,<2021.0.0)
|
|
38
37
|
Requires-Dist: httpx (>=0.27.2,<0.28.0)
|
|
39
38
|
Requires-Dist: httpx-sse (>=0.4.0,<0.5.0)
|
|
40
|
-
Requires-Dist: isort (>=5.13.2,<6.0.0) ; extra == "dev"
|
|
39
|
+
Requires-Dist: isort (>=5.13.2,<6.0.0) ; extra == "dev" or extra == "all"
|
|
41
40
|
Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
|
|
42
|
-
Requires-Dist: langchain (>=0.
|
|
43
|
-
Requires-Dist: langchain-community (>=0.
|
|
41
|
+
Requires-Dist: langchain (>=0.3.7,<0.4.0) ; extra == "external-tools" or extra == "all"
|
|
42
|
+
Requires-Dist: langchain-community (>=0.3.7,<0.4.0) ; extra == "external-tools" or extra == "all"
|
|
44
43
|
Requires-Dist: llama-index (>=0.11.9,<0.12.0)
|
|
45
|
-
Requires-Dist: llama-index-embeddings-ollama (>=0.3.1,<0.4.0) ; extra == "ollama"
|
|
44
|
+
Requires-Dist: llama-index-embeddings-ollama (>=0.3.1,<0.4.0) ; extra == "ollama" or extra == "all"
|
|
46
45
|
Requires-Dist: llama-index-embeddings-openai (>=0.2.5,<0.3.0)
|
|
47
|
-
Requires-Dist: locust (>=2.31.5,<3.0.0)
|
|
46
|
+
Requires-Dist: locust (>=2.31.5,<3.0.0) ; extra == "dev" or extra == "all"
|
|
48
47
|
Requires-Dist: nltk (>=3.8.1,<4.0.0)
|
|
49
48
|
Requires-Dist: numpy (>=1.26.2,<2.0.0)
|
|
50
49
|
Requires-Dist: pathvalidate (>=3.2.1,<4.0.0)
|
|
51
|
-
Requires-Dist: pexpect (>=4.9.0,<5.0.0) ; extra == "dev"
|
|
52
|
-
Requires-Dist: pg8000 (>=1.30.3,<2.0.0) ; extra == "postgres"
|
|
53
|
-
Requires-Dist: pgvector (>=0.2.3,<0.3.0) ; extra == "postgres"
|
|
54
|
-
Requires-Dist: pre-commit (>=3.5.0,<4.0.0) ; extra == "dev"
|
|
50
|
+
Requires-Dist: pexpect (>=4.9.0,<5.0.0) ; extra == "dev" or extra == "all"
|
|
51
|
+
Requires-Dist: pg8000 (>=1.30.3,<2.0.0) ; extra == "postgres" or extra == "all"
|
|
52
|
+
Requires-Dist: pgvector (>=0.2.3,<0.3.0) ; extra == "postgres" or extra == "all"
|
|
53
|
+
Requires-Dist: pre-commit (>=3.5.0,<4.0.0) ; extra == "dev" or extra == "all"
|
|
55
54
|
Requires-Dist: prettytable (>=3.9.0,<4.0.0)
|
|
56
|
-
Requires-Dist: psycopg2 (>=2.9.10,<3.0.0) ; extra == "postgres"
|
|
57
|
-
Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0) ; extra == "postgres"
|
|
55
|
+
Requires-Dist: psycopg2 (>=2.9.10,<3.0.0) ; extra == "postgres" or extra == "all"
|
|
56
|
+
Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0) ; extra == "postgres" or extra == "all"
|
|
58
57
|
Requires-Dist: pyautogen (==0.2.22) ; extra == "autogen"
|
|
59
58
|
Requires-Dist: pydantic (>=2.7.4,<2.10.0)
|
|
60
59
|
Requires-Dist: pydantic-settings (>=2.2.1,<3.0.0)
|
|
61
60
|
Requires-Dist: pyhumps (>=3.8.0,<4.0.0)
|
|
62
61
|
Requires-Dist: pymilvus (>=2.4.3,<3.0.0) ; extra == "milvus"
|
|
63
|
-
Requires-Dist: pyright (>=1.1.347,<2.0.0) ; extra == "dev"
|
|
64
|
-
Requires-Dist: pytest-asyncio (>=0.23.2,<0.24.0) ; extra == "dev"
|
|
65
|
-
Requires-Dist: pytest-order (>=1.2.0,<2.0.0) ; extra == "dev"
|
|
62
|
+
Requires-Dist: pyright (>=1.1.347,<2.0.0) ; extra == "dev" or extra == "all"
|
|
63
|
+
Requires-Dist: pytest-asyncio (>=0.23.2,<0.24.0) ; extra == "dev" or extra == "all"
|
|
64
|
+
Requires-Dist: pytest-order (>=1.2.0,<2.0.0) ; extra == "dev" or extra == "all"
|
|
66
65
|
Requires-Dist: python-box (>=7.1.1,<8.0.0)
|
|
67
66
|
Requires-Dist: python-multipart (>=0.0.9,<0.0.10)
|
|
68
67
|
Requires-Dist: pytz (>=2023.3.post1,<2024.0)
|
|
@@ -77,9 +76,9 @@ Requires-Dist: sqlmodel (>=0.0.16,<0.0.17)
|
|
|
77
76
|
Requires-Dist: tiktoken (>=0.7.0,<0.8.0)
|
|
78
77
|
Requires-Dist: tqdm (>=4.66.1,<5.0.0)
|
|
79
78
|
Requires-Dist: typer[all] (>=0.9.0,<0.10.0)
|
|
80
|
-
Requires-Dist: uvicorn (>=0.24.0.post1,<0.25.0) ; extra == "server"
|
|
81
|
-
Requires-Dist: websockets (>=12.0,<13.0) ; extra == "server"
|
|
82
|
-
Requires-Dist: wikipedia (>=1.4.0,<2.0.0) ; extra == "external-tools" or extra == "tests"
|
|
79
|
+
Requires-Dist: uvicorn (>=0.24.0.post1,<0.25.0) ; extra == "server" or extra == "all"
|
|
80
|
+
Requires-Dist: websockets (>=12.0,<13.0) ; extra == "server" or extra == "all"
|
|
81
|
+
Requires-Dist: wikipedia (>=1.4.0,<2.0.0) ; extra == "external-tools" or extra == "tests" or extra == "all"
|
|
83
82
|
Description-Content-Type: text/markdown
|
|
84
83
|
|
|
85
84
|
<p align="center">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
letta/__init__.py,sha256=
|
|
1
|
+
letta/__init__.py,sha256=lrj66PR9vRWLWUvQAgk4Qi8BebVsYk8J2poTTbuuBFQ,1014
|
|
2
2
|
letta/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
|
|
3
|
-
letta/agent.py,sha256=
|
|
3
|
+
letta/agent.py,sha256=7uc2v0mfAX46RdxPY-HIlfeO15mgBORfnr7bi84Ik4o,77430
|
|
4
4
|
letta/agent_store/chroma.py,sha256=upR5zGnGs6I6btulEYbiZdGG87BgKjxUJOQZ4Y-RQ_M,12492
|
|
5
5
|
letta/agent_store/db.py,sha256=dVBnNwVX57_kVdrD1oHnqze154QOoxWYSElJJUojyMs,23465
|
|
6
6
|
letta/agent_store/lancedb.py,sha256=i63d4VZwj9UIOTNs5f0JZ_r5yZD-jKWz4FAH4RMpXOE,5104
|
|
@@ -13,7 +13,7 @@ letta/cli/cli.py,sha256=1dJIZ8DIGM8mg0G0UGLKMTa3fwgHzrN8Hkxd5Uxx7X4,16946
|
|
|
13
13
|
letta/cli/cli_config.py,sha256=D-CpSZI1cDvdSQr3-zhGuDrJnZo1Ko7bi_wuxcBxxqo,8555
|
|
14
14
|
letta/cli/cli_load.py,sha256=x4L8s15GwIW13xrhKYFWHo_y-IVGtoPDHWWKcHDRP10,4587
|
|
15
15
|
letta/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
letta/client/client.py,sha256=
|
|
16
|
+
letta/client/client.py,sha256=GjSCpp7oy2e9SXcxRdFfsvGm0nmuYDO8yNB1yS7MWrE,102261
|
|
17
17
|
letta/client/streaming.py,sha256=Hh5pjlyrdCuO2V75ZCxSSOCPd3BmHdKFGaIUJC6fBp0,4775
|
|
18
18
|
letta/client/utils.py,sha256=OJlAKWrldc4I6M1WpcTWNtPJ4wfxlzlZqWLfCozkFtI,2872
|
|
19
19
|
letta/config.py,sha256=eK-ip06ELHNYriInkgfidDvJxQ2tD1u49I-VLXB87nE,18929
|
|
@@ -27,7 +27,7 @@ letta/functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
27
27
|
letta/functions/function_sets/base.py,sha256=N4QmOjL6gDEyOg67ocF6zVKM-NquTo-yXG_T8r18buA,6440
|
|
28
28
|
letta/functions/function_sets/extras.py,sha256=Jik3UiDqYTm4Lam1XPTvuVjvgUHwIAhopsnbmVhGMBg,4732
|
|
29
29
|
letta/functions/functions.py,sha256=VyA_7O56KRUj88iuMkLJTRfascaTCj1qFGT0BnDgC6k,4140
|
|
30
|
-
letta/functions/helpers.py,sha256=
|
|
30
|
+
letta/functions/helpers.py,sha256=_GcgDLeR7YAGY0HIGxxM_EoXGFgWISZaX-FfS39nLGc,8682
|
|
31
31
|
letta/functions/schema_generator.py,sha256=CoDZQfXsOKBp5VOv-024efcR833wyrchQbQIN7mL11A,8407
|
|
32
32
|
letta/helpers/__init__.py,sha256=p0luQ1Oe3Skc6sH4O58aHHA3Qbkyjifpuq0DZ1GAY0U,59
|
|
33
33
|
letta/helpers/tool_rule_solver.py,sha256=AZiUjW_oDlQx5uMI7oaL50KkI1InTW8qRkFdg6S54RQ,4744
|
|
@@ -85,7 +85,7 @@ letta/local_llm/webui/settings.py,sha256=gmLHfiOl1u4JmlAZU2d2O8YKF9lafdakyjwR_ft
|
|
|
85
85
|
letta/log.py,sha256=Oy5b71AXfrnQShxI_4ULo5U3kmZJG01bXbP_64Nr4Fk,2105
|
|
86
86
|
letta/main.py,sha256=cFnjnbzyrRRM5sZeRAnGVq_rPIgJRHRFyFNCY--sRI4,19163
|
|
87
87
|
letta/memory.py,sha256=YupXOvzVJXH59RW4XWBrd7qMNEYaMbtWXCheKeWZwpU,17873
|
|
88
|
-
letta/metadata.py,sha256=
|
|
88
|
+
letta/metadata.py,sha256=jcvkzrCfSlmUbv5puCbeFP6cqM-Ct_U49C5WFLpYJ0s,18180
|
|
89
89
|
letta/o1_agent.py,sha256=qYyAdLnKu7dQw6OxxsFQz32d-lLJLo64MnH165oQm7s,3180
|
|
90
90
|
letta/openai_backcompat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
91
|
letta/openai_backcompat/openai_object.py,sha256=Y1ZS1sATP60qxJiOsjOP3NbwSzuzvkNAvb3DeuhM5Uk,13490
|
|
@@ -131,7 +131,7 @@ letta/pytest.ini,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
131
131
|
letta/schemas/agent.py,sha256=f0khTBWIRGZva4_C15Nm_tkmn1cwaVQlWa7_7laRbEE,7866
|
|
132
132
|
letta/schemas/agents_tags.py,sha256=9DGr8fN2DHYdWvZ_qcXmrKI0w7YKCGz2lfEcrX2KAkI,1130
|
|
133
133
|
letta/schemas/api_key.py,sha256=u07yzzMn-hBAHZIIKbWY16KsgiFjSNR8lAghpMUo3_4,682
|
|
134
|
-
letta/schemas/block.py,sha256=
|
|
134
|
+
letta/schemas/block.py,sha256=4xYoyfLezvyjA7TN3c5AvPCyRh_Pz0_XVqVCwIaXoTo,4758
|
|
135
135
|
letta/schemas/embedding_config.py,sha256=1kD6NpiXeH4roVumxqDAKk7xt8SpXGWNhZs_XXUSlEU,2855
|
|
136
136
|
letta/schemas/enums.py,sha256=WfRYpLh_pD-VyhEnp3Y6pPfx063zq2o4jky6PulqO8w,629
|
|
137
137
|
letta/schemas/file.py,sha256=ChN2CWzLI2TT9WLItcfElEH0E8b7kzPylF2OQBr6Beg,1550
|
|
@@ -142,7 +142,7 @@ letta/schemas/letta_message.py,sha256=RuVVtwFbi85yP3dXQxowofQ6cI2cO_CdGtgpHGQzgH
|
|
|
142
142
|
letta/schemas/letta_request.py,sha256=_oiDshc_AoFWIfXRk2VX5-AxO5vDlyN-9r-gnyLj_30,1890
|
|
143
143
|
letta/schemas/letta_response.py,sha256=li_j4VUF_WtxdJy7ufRmmmchzvhVmr1idbOxtgFGiy0,6253
|
|
144
144
|
letta/schemas/llm_config.py,sha256=RbgnCaqYd_yl-Xs7t-DEI1NhpKD8WiVWjxcwq5mZd5M,4467
|
|
145
|
-
letta/schemas/memory.py,sha256=
|
|
145
|
+
letta/schemas/memory.py,sha256=skuTu-aYpEs9Q76yINWLgmLFELG5m8-JdCeTjtR41rU,13192
|
|
146
146
|
letta/schemas/message.py,sha256=DQxnRYrYgHXpTKfMzfS-bpCAe-BO_Rmcfc1Wf-4GHjw,33703
|
|
147
147
|
letta/schemas/openai/chat_completion_request.py,sha256=AOIwgbN3CZKVqkuXeMHeSa53u4h0wVq69t3T_LJ0vIE,3389
|
|
148
148
|
letta/schemas/openai/chat_completion_response.py,sha256=ub-oVSyLpuJd-5_yzCSIRR8tD3GM83IeDO1c1uAATa4,3970
|
|
@@ -152,7 +152,7 @@ letta/schemas/openai/openai.py,sha256=Hilo5BiLAGabzxCwnwfzK5QrWqwYD8epaEKFa4Pwnd
|
|
|
152
152
|
letta/schemas/organization.py,sha256=d2oN3IK2HeruEHKXwIzCbJ3Fxdi_BEe9JZ8J9aDbHwQ,698
|
|
153
153
|
letta/schemas/passage.py,sha256=eYQMxD_XjHAi72jmqcGBU4wM4VZtSU0XK8uhQxxN3Ug,3563
|
|
154
154
|
letta/schemas/source.py,sha256=B1VbaDJV-EGPv1nQXwCx_RAzeAJd50UqP_1m1cIRT8c,2854
|
|
155
|
-
letta/schemas/tool.py,sha256=
|
|
155
|
+
letta/schemas/tool.py,sha256=Ehdl4fB1tLG-kgUTVD7MAhvSs_H_Tim2aROu0S0diB8,8083
|
|
156
156
|
letta/schemas/tool_rule.py,sha256=zv4jE0b8LW78idP4UbJARnrZcnmaqjGNUk_YV99Y0c0,884
|
|
157
157
|
letta/schemas/usage.py,sha256=lvn1ooHwLEdv6gwQpw5PBUbcwn_gwdT6HA-fCiix6sY,817
|
|
158
158
|
letta/schemas/user.py,sha256=V32Tgl6oqB3KznkxUz12y7agkQicjzW7VocSpj78i6Q,1526
|
|
@@ -174,7 +174,7 @@ letta/server/rest_api/routers/openai/assistants/threads.py,sha256=WXVGBaBvSNPB7Z
|
|
|
174
174
|
letta/server/rest_api/routers/openai/chat_completions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
175
175
|
letta/server/rest_api/routers/openai/chat_completions/chat_completions.py,sha256=-uye6cm4SnoQGwxhr1N1FrSXOlnO2Hvbfj6k8JSc45k,4918
|
|
176
176
|
letta/server/rest_api/routers/v1/__init__.py,sha256=sqlVZa-u9DJwdRsp0_8YUGrac9DHguIB4wETlEDRylA,666
|
|
177
|
-
letta/server/rest_api/routers/v1/agents.py,sha256=
|
|
177
|
+
letta/server/rest_api/routers/v1/agents.py,sha256=yKpbqQauHHbvuV8IWgAPgri0lPmr6EWbYUx_C64RBGA,25541
|
|
178
178
|
letta/server/rest_api/routers/v1/blocks.py,sha256=ogJdn-Ir7h1ZEv28bHtUNNsR2zq9-wxXAMpu2t1EoIA,2946
|
|
179
179
|
letta/server/rest_api/routers/v1/health.py,sha256=pKCuVESlVOhGIb4VC4K-H82eZqfghmT6kvj2iOkkKuc,401
|
|
180
180
|
letta/server/rest_api/routers/v1/jobs.py,sha256=a-j0v-5A0un0pVCOHpfeWnzpOWkVDQO6ti42k_qAlZY,2272
|
|
@@ -185,7 +185,7 @@ letta/server/rest_api/routers/v1/tools.py,sha256=Bkb9oKswOycj5S3fBeim7LpDrZf37Sy
|
|
|
185
185
|
letta/server/rest_api/routers/v1/users.py,sha256=M1wEr2IyHzuRwINYxLXTkrbAH3osLe_cWjzrWrzR1aw,3729
|
|
186
186
|
letta/server/rest_api/static_files.py,sha256=NG8sN4Z5EJ8JVQdj19tkFa9iQ1kBPTab9f_CUxd_u4Q,3143
|
|
187
187
|
letta/server/rest_api/utils.py,sha256=GdHYCzXtbM5VCAYDPR0z5gnNZpRhwPld2BGZV7xT6cU,2924
|
|
188
|
-
letta/server/server.py,sha256=
|
|
188
|
+
letta/server/server.py,sha256=uD7wO6f6iDZO1IUzAclIADpalhk-JrVNnzbVA1tt-YY,83736
|
|
189
189
|
letta/server/startup.sh,sha256=wTOQOJJZw_Iec57WIu0UW0AVflk0ZMWYZWg8D3T_gSQ,698
|
|
190
190
|
letta/server/static_files/assets/index-3ab03d5b.css,sha256=OrA9W4iKJ5h2Wlr7GwdAT4wow0CM8hVit1yOxEL49Qw,54295
|
|
191
191
|
letta/server/static_files/assets/index-9fa459a2.js,sha256=j2oMcDJO9dWJaH5e-tsflbVpWK20gLWpZKJk4-Kuy6A,1815592
|
|
@@ -200,7 +200,7 @@ letta/server/ws_api/protocol.py,sha256=M_-gM5iuDBwa1cuN2IGNCG5GxMJwU2d3XW93XALv9
|
|
|
200
200
|
letta/server/ws_api/server.py,sha256=C2Kv48PCwl46DQFb0ZP30s86KJLQ6dZk2AhWQEZn9pY,6004
|
|
201
201
|
letta/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
202
202
|
letta/services/agents_tags_manager.py,sha256=zNqeXDpaf4dQ77jrRHiQfITdk4FawBzcND-9tWrj8gw,3127
|
|
203
|
-
letta/services/block_manager.py,sha256=
|
|
203
|
+
letta/services/block_manager.py,sha256=oxSeBTPILihcM65mZgvW9OD51z20wU232BFORxC-wlo,4468
|
|
204
204
|
letta/services/organization_manager.py,sha256=OfE2_NMmhqXURX4sg7hCOiFQVQpV5ZiPu7J3sboCSYc,3555
|
|
205
205
|
letta/services/source_manager.py,sha256=StX5Wfd7XSCKJet8qExIu3GMoI-eMIbEarAeTv2gq0s,6555
|
|
206
206
|
letta/services/tool_manager.py,sha256=Vr2_JQ3TQUSPSPNbmGwY26HIFjYw0NhzJGgpMvS6GV8,8163
|
|
@@ -210,8 +210,8 @@ letta/streaming_interface.py,sha256=_FPUWy58j50evHcpXyd7zB1wWqeCc71NCFeWh_TBvnw,
|
|
|
210
210
|
letta/streaming_utils.py,sha256=329fsvj1ZN0r0LpQtmMPZ2vSxkDBIUUwvGHZFkjm2I8,11745
|
|
211
211
|
letta/system.py,sha256=buKYPqG5n2x41hVmWpu6JUpyd7vTWED9Km2_M7dLrvk,6960
|
|
212
212
|
letta/utils.py,sha256=COwQLAt02eEM9tjp6p5kN8YeTqGXr714l5BvffLVCLU,32376
|
|
213
|
-
letta_nightly-0.5.
|
|
214
|
-
letta_nightly-0.5.
|
|
215
|
-
letta_nightly-0.5.
|
|
216
|
-
letta_nightly-0.5.
|
|
217
|
-
letta_nightly-0.5.
|
|
213
|
+
letta_nightly-0.5.4.dev20241122104229.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
|
|
214
|
+
letta_nightly-0.5.4.dev20241122104229.dist-info/METADATA,sha256=iD_Sb8bXV-LOgGdFN7FlJmO9h0Mwv8zuPhhqEErsUek,11395
|
|
215
|
+
letta_nightly-0.5.4.dev20241122104229.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
216
|
+
letta_nightly-0.5.4.dev20241122104229.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
|
|
217
|
+
letta_nightly-0.5.4.dev20241122104229.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|