letta-nightly 0.5.1.dev20241105104128__py3-none-any.whl → 0.5.1.dev20241106104104__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of letta-nightly might be problematic. Click here for more details.
- letta/agent.py +4 -0
- letta/agent_store/db.py +19 -19
- letta/client/client.py +11 -6
- letta/orm/base.py +5 -2
- letta/orm/mixins.py +2 -53
- letta/orm/organization.py +3 -1
- letta/orm/sqlalchemy_base.py +6 -45
- letta/orm/tool.py +3 -2
- letta/orm/user.py +3 -1
- letta/schemas/memory.py +4 -0
- letta/schemas/organization.py +4 -4
- letta/schemas/tool.py +7 -7
- letta/schemas/user.py +1 -1
- letta/server/rest_api/routers/v1/agents.py +6 -1
- letta/server/rest_api/routers/v1/organizations.py +2 -1
- letta/server/rest_api/routers/v1/tools.py +2 -1
- letta/server/rest_api/routers/v1/users.py +2 -2
- letta/server/server.py +2 -2
- letta/services/organization_manager.py +4 -4
- letta/services/tool_manager.py +17 -16
- letta/services/user_manager.py +3 -3
- {letta_nightly-0.5.1.dev20241105104128.dist-info → letta_nightly-0.5.1.dev20241106104104.dist-info}/METADATA +2 -2
- {letta_nightly-0.5.1.dev20241105104128.dist-info → letta_nightly-0.5.1.dev20241106104104.dist-info}/RECORD +26 -26
- {letta_nightly-0.5.1.dev20241105104128.dist-info → letta_nightly-0.5.1.dev20241106104104.dist-info}/LICENSE +0 -0
- {letta_nightly-0.5.1.dev20241105104128.dist-info → letta_nightly-0.5.1.dev20241106104104.dist-info}/WHEEL +0 -0
- {letta_nightly-0.5.1.dev20241105104128.dist-info → letta_nightly-0.5.1.dev20241106104104.dist-info}/entry_points.txt +0 -0
letta/agent.py
CHANGED
|
@@ -3,6 +3,7 @@ import inspect
|
|
|
3
3
|
import traceback
|
|
4
4
|
import warnings
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
|
+
from lib2to3.fixer_util import is_list
|
|
6
7
|
from typing import List, Literal, Optional, Tuple, Union
|
|
7
8
|
|
|
8
9
|
from tqdm import tqdm
|
|
@@ -250,6 +251,9 @@ class Agent(BaseAgent):
|
|
|
250
251
|
# if there are tool rules, print out a warning
|
|
251
252
|
warnings.warn("Tool rules only work reliably for the latest OpenAI models that support structured outputs.")
|
|
252
253
|
# add default rule for having send_message be a terminal tool
|
|
254
|
+
|
|
255
|
+
if not is_list(agent_state.tool_rules):
|
|
256
|
+
agent_state.tool_rules = []
|
|
253
257
|
agent_state.tool_rules.append(TerminalToolRule(tool_name="send_message"))
|
|
254
258
|
self.tool_rules_solver = ToolRulesSolver(tool_rules=agent_state.tool_rules)
|
|
255
259
|
|
letta/agent_store/db.py
CHANGED
|
@@ -358,26 +358,26 @@ class PostgresStorageConnector(SQLStorageConnector):
|
|
|
358
358
|
# construct URI from enviornment variables
|
|
359
359
|
if settings.pg_uri:
|
|
360
360
|
self.uri = settings.pg_uri
|
|
361
|
+
|
|
362
|
+
# use config URI
|
|
363
|
+
# TODO: remove this eventually (config should NOT contain URI)
|
|
364
|
+
if table_type == TableType.ARCHIVAL_MEMORY or table_type == TableType.PASSAGES:
|
|
365
|
+
self.uri = self.config.archival_storage_uri
|
|
366
|
+
self.db_model = PassageModel
|
|
367
|
+
if self.config.archival_storage_uri is None:
|
|
368
|
+
raise ValueError(f"Must specify archival_storage_uri in config {self.config.config_path}")
|
|
369
|
+
elif table_type == TableType.RECALL_MEMORY:
|
|
370
|
+
self.uri = self.config.recall_storage_uri
|
|
371
|
+
self.db_model = MessageModel
|
|
372
|
+
if self.config.recall_storage_uri is None:
|
|
373
|
+
raise ValueError(f"Must specify recall_storage_uri in config {self.config.config_path}")
|
|
374
|
+
elif table_type == TableType.FILES:
|
|
375
|
+
self.uri = self.config.metadata_storage_uri
|
|
376
|
+
self.db_model = FileMetadataModel
|
|
377
|
+
if self.config.metadata_storage_uri is None:
|
|
378
|
+
raise ValueError(f"Must specify metadata_storage_uri in config {self.config.config_path}")
|
|
361
379
|
else:
|
|
362
|
-
|
|
363
|
-
# TODO: remove this eventually (config should NOT contain URI)
|
|
364
|
-
if table_type == TableType.ARCHIVAL_MEMORY or table_type == TableType.PASSAGES:
|
|
365
|
-
self.uri = self.config.archival_storage_uri
|
|
366
|
-
self.db_model = PassageModel
|
|
367
|
-
if self.config.archival_storage_uri is None:
|
|
368
|
-
raise ValueError(f"Must specify archival_storage_uri in config {self.config.config_path}")
|
|
369
|
-
elif table_type == TableType.RECALL_MEMORY:
|
|
370
|
-
self.uri = self.config.recall_storage_uri
|
|
371
|
-
self.db_model = MessageModel
|
|
372
|
-
if self.config.recall_storage_uri is None:
|
|
373
|
-
raise ValueError(f"Must specify recall_storage_uri in config {self.config.config_path}")
|
|
374
|
-
elif table_type == TableType.FILES:
|
|
375
|
-
self.uri = self.config.metadata_storage_uri
|
|
376
|
-
self.db_model = FileMetadataModel
|
|
377
|
-
if self.config.metadata_storage_uri is None:
|
|
378
|
-
raise ValueError(f"Must specify metadata_storage_uri in config {self.config.config_path}")
|
|
379
|
-
else:
|
|
380
|
-
raise ValueError(f"Table type {table_type} not implemented")
|
|
380
|
+
raise ValueError(f"Table type {table_type} not implemented")
|
|
381
381
|
|
|
382
382
|
for c in self.db_model.__table__.columns:
|
|
383
383
|
if c.name == "embedding":
|
letta/client/client.py
CHANGED
|
@@ -612,7 +612,12 @@ class RESTClient(AbstractClient):
|
|
|
612
612
|
agent_id (str): ID of the agent
|
|
613
613
|
"""
|
|
614
614
|
# TODO: implement this
|
|
615
|
-
|
|
615
|
+
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents", headers=self.headers, params={"name": agent_name})
|
|
616
|
+
agents = [AgentState(**agent) for agent in response.json()]
|
|
617
|
+
if len(agents) == 0:
|
|
618
|
+
return None
|
|
619
|
+
assert len(agents) == 1, f"Multiple agents with the same name: {agents}"
|
|
620
|
+
return agents[0].id
|
|
616
621
|
|
|
617
622
|
# memory
|
|
618
623
|
def get_in_context_memory(self, agent_id: str) -> Memory:
|
|
@@ -2267,18 +2272,18 @@ class LocalClient(AbstractClient):
|
|
|
2267
2272
|
langchain_tool=langchain_tool,
|
|
2268
2273
|
additional_imports_module_attr_map=additional_imports_module_attr_map,
|
|
2269
2274
|
)
|
|
2270
|
-
return self.server.tool_manager.create_or_update_tool(tool_create, actor=self.user)
|
|
2275
|
+
return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
|
|
2271
2276
|
|
|
2272
2277
|
def load_crewai_tool(self, crewai_tool: "CrewAIBaseTool", additional_imports_module_attr_map: dict[str, str] = None) -> Tool:
|
|
2273
2278
|
tool_create = ToolCreate.from_crewai(
|
|
2274
2279
|
crewai_tool=crewai_tool,
|
|
2275
2280
|
additional_imports_module_attr_map=additional_imports_module_attr_map,
|
|
2276
2281
|
)
|
|
2277
|
-
return self.server.tool_manager.create_or_update_tool(tool_create, actor=self.user)
|
|
2282
|
+
return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
|
|
2278
2283
|
|
|
2279
2284
|
def load_composio_tool(self, action: "ActionType") -> Tool:
|
|
2280
2285
|
tool_create = ToolCreate.from_composio(action=action)
|
|
2281
|
-
return self.server.tool_manager.create_or_update_tool(tool_create, actor=self.user)
|
|
2286
|
+
return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
|
|
2282
2287
|
|
|
2283
2288
|
# TODO: Use the above function `add_tool` here as there is duplicate logic
|
|
2284
2289
|
def create_tool(
|
|
@@ -2310,7 +2315,7 @@ class LocalClient(AbstractClient):
|
|
|
2310
2315
|
|
|
2311
2316
|
# call server function
|
|
2312
2317
|
return self.server.tool_manager.create_or_update_tool(
|
|
2313
|
-
|
|
2318
|
+
Tool(
|
|
2314
2319
|
source_type=source_type,
|
|
2315
2320
|
source_code=source_code,
|
|
2316
2321
|
name=name,
|
|
@@ -2738,7 +2743,7 @@ class LocalClient(AbstractClient):
|
|
|
2738
2743
|
return self.server.list_embedding_models()
|
|
2739
2744
|
|
|
2740
2745
|
def create_org(self, name: Optional[str] = None) -> Organization:
|
|
2741
|
-
return self.server.organization_manager.create_organization(name=name)
|
|
2746
|
+
return self.server.organization_manager.create_organization(pydantic_org=Organization(name=name))
|
|
2742
2747
|
|
|
2743
2748
|
def list_orgs(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[Organization]:
|
|
2744
2749
|
return self.server.organization_manager.list_organizations(cursor=cursor, limit=limit)
|
letta/orm/base.py
CHANGED
|
@@ -67,7 +67,7 @@ class CommonSqlalchemyMetaMixins(Base):
|
|
|
67
67
|
prop_value = getattr(self, full_prop, None)
|
|
68
68
|
if not prop_value:
|
|
69
69
|
return
|
|
70
|
-
return
|
|
70
|
+
return prop_value
|
|
71
71
|
|
|
72
72
|
def _user_id_setter(self, prop: str, value: str) -> None:
|
|
73
73
|
"""returns the user id for the specified property"""
|
|
@@ -75,6 +75,9 @@ class CommonSqlalchemyMetaMixins(Base):
|
|
|
75
75
|
if not value:
|
|
76
76
|
setattr(self, full_prop, None)
|
|
77
77
|
return
|
|
78
|
+
# Safety check
|
|
78
79
|
prefix, id_ = value.split("-", 1)
|
|
79
80
|
assert prefix == "user", f"{prefix} is not a valid id prefix for a user id"
|
|
80
|
-
|
|
81
|
+
|
|
82
|
+
# Set the full value
|
|
83
|
+
setattr(self, full_prop, value)
|
letta/orm/mixins.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
1
|
from uuid import UUID
|
|
3
2
|
|
|
4
3
|
from sqlalchemy import ForeignKey, String
|
|
5
4
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
6
5
|
|
|
7
6
|
from letta.orm.base import Base
|
|
8
|
-
from letta.orm.errors import MalformedIdError
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
def is_valid_uuid4(uuid_string: str) -> bool:
|
|
@@ -17,53 +15,12 @@ def is_valid_uuid4(uuid_string: str) -> bool:
|
|
|
17
15
|
return False
|
|
18
16
|
|
|
19
17
|
|
|
20
|
-
def _relation_getter(instance: "Base", prop: str) -> Optional[str]:
|
|
21
|
-
"""Get relation and return id with prefix as a string."""
|
|
22
|
-
prefix = prop.replace("_", "")
|
|
23
|
-
formatted_prop = f"_{prop}_id"
|
|
24
|
-
try:
|
|
25
|
-
id_ = getattr(instance, formatted_prop) # Get the string id directly
|
|
26
|
-
return f"{prefix}-{id_}"
|
|
27
|
-
except AttributeError:
|
|
28
|
-
return None
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def _relation_setter(instance: "Base", prop: str, value: str) -> None:
|
|
32
|
-
"""Set relation using the id with prefix, ensuring the id is a valid UUIDv4."""
|
|
33
|
-
formatted_prop = f"_{prop}_id"
|
|
34
|
-
prefix = prop.replace("_", "")
|
|
35
|
-
if not value:
|
|
36
|
-
setattr(instance, formatted_prop, None)
|
|
37
|
-
return
|
|
38
|
-
try:
|
|
39
|
-
found_prefix, id_ = value.split("-", 1)
|
|
40
|
-
except ValueError as e:
|
|
41
|
-
raise MalformedIdError(f"{value} is not a valid ID.") from e
|
|
42
|
-
|
|
43
|
-
# Ensure prefix matches
|
|
44
|
-
assert found_prefix == prefix, f"{found_prefix} is not a valid id prefix, expecting {prefix}"
|
|
45
|
-
|
|
46
|
-
# Validate that the id is a valid UUID4 string
|
|
47
|
-
if not is_valid_uuid4(id_):
|
|
48
|
-
raise MalformedIdError(f"Hash segment of {value} is not a valid UUID4")
|
|
49
|
-
|
|
50
|
-
setattr(instance, formatted_prop, id_) # Store id as a string
|
|
51
|
-
|
|
52
|
-
|
|
53
18
|
class OrganizationMixin(Base):
|
|
54
19
|
"""Mixin for models that belong to an organization."""
|
|
55
20
|
|
|
56
21
|
__abstract__ = True
|
|
57
22
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@property
|
|
61
|
-
def organization_id(self) -> str:
|
|
62
|
-
return _relation_getter(self, "organization")
|
|
63
|
-
|
|
64
|
-
@organization_id.setter
|
|
65
|
-
def organization_id(self, value: str) -> None:
|
|
66
|
-
_relation_setter(self, "organization", value)
|
|
23
|
+
organization_id: Mapped[str] = mapped_column(String, ForeignKey("organizations.id"))
|
|
67
24
|
|
|
68
25
|
|
|
69
26
|
class UserMixin(Base):
|
|
@@ -71,12 +28,4 @@ class UserMixin(Base):
|
|
|
71
28
|
|
|
72
29
|
__abstract__ = True
|
|
73
30
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@property
|
|
77
|
-
def user_id(self) -> str:
|
|
78
|
-
return _relation_getter(self, "user")
|
|
79
|
-
|
|
80
|
-
@user_id.setter
|
|
81
|
-
def user_id(self, value: str) -> None:
|
|
82
|
-
_relation_setter(self, "user", value)
|
|
31
|
+
user_id: Mapped[str] = mapped_column(String, ForeignKey("users.id"))
|
letta/orm/organization.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
|
+
from sqlalchemy import String
|
|
3
4
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
4
5
|
|
|
5
6
|
from letta.orm.sqlalchemy_base import SqlalchemyBase
|
|
@@ -14,9 +15,10 @@ if TYPE_CHECKING:
|
|
|
14
15
|
class Organization(SqlalchemyBase):
|
|
15
16
|
"""The highest level of the object tree. All Entities belong to one and only one Organization."""
|
|
16
17
|
|
|
17
|
-
__tablename__ = "
|
|
18
|
+
__tablename__ = "organizations"
|
|
18
19
|
__pydantic_model__ = PydanticOrganization
|
|
19
20
|
|
|
21
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
20
22
|
name: Mapped[str] = mapped_column(doc="The display name of the organization.")
|
|
21
23
|
|
|
22
24
|
users: Mapped[List["User"]] = relationship("User", back_populates="organization", cascade="all, delete-orphan")
|
letta/orm/sqlalchemy_base.py
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List, Literal, Optional, Type
|
|
2
|
-
from uuid import uuid4
|
|
3
2
|
|
|
4
|
-
from
|
|
5
|
-
from sqlalchemy import Boolean, String, select
|
|
3
|
+
from sqlalchemy import String, select
|
|
6
4
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
7
5
|
|
|
8
6
|
from letta.log import get_logger
|
|
9
7
|
from letta.orm.base import Base, CommonSqlalchemyMetaMixins
|
|
10
8
|
from letta.orm.errors import NoResultFound
|
|
11
|
-
from letta.orm.mixins import is_valid_uuid4
|
|
12
9
|
|
|
13
10
|
if TYPE_CHECKING:
|
|
14
11
|
from pydantic import BaseModel
|
|
@@ -24,27 +21,7 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
24
21
|
|
|
25
22
|
__order_by_default__ = "created_at"
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
deleted: Mapped[bool] = mapped_column(Boolean, default=False, doc="Is this record deleted? Used for universal soft deletes.")
|
|
30
|
-
|
|
31
|
-
@classmethod
|
|
32
|
-
def __prefix__(cls) -> str:
|
|
33
|
-
return depascalize(cls.__name__)
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def id(self) -> Optional[str]:
|
|
37
|
-
if self._id:
|
|
38
|
-
return f"{self.__prefix__()}-{self._id}"
|
|
39
|
-
|
|
40
|
-
@id.setter
|
|
41
|
-
def id(self, value: str) -> None:
|
|
42
|
-
if not value:
|
|
43
|
-
return
|
|
44
|
-
prefix, id_ = value.split("-", 1)
|
|
45
|
-
assert prefix == self.__prefix__(), f"{prefix} is not a valid id prefix for {self.__class__.__name__}"
|
|
46
|
-
assert is_valid_uuid4(id_), f"{id_} is not a valid uuid4"
|
|
47
|
-
self._id = id_
|
|
24
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
48
25
|
|
|
49
26
|
@classmethod
|
|
50
27
|
def list(
|
|
@@ -57,11 +34,10 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
57
34
|
|
|
58
35
|
# Add a cursor condition if provided
|
|
59
36
|
if cursor:
|
|
60
|
-
|
|
61
|
-
query = query.where(cls._id > cursor_uuid)
|
|
37
|
+
query = query.where(cls.id > cursor)
|
|
62
38
|
|
|
63
39
|
# Add a limit to the query if provided
|
|
64
|
-
query = query.order_by(cls.
|
|
40
|
+
query = query.order_by(cls.id).limit(limit)
|
|
65
41
|
|
|
66
42
|
# Handle soft deletes if the class has the 'is_deleted' attribute
|
|
67
43
|
if hasattr(cls, "is_deleted"):
|
|
@@ -70,20 +46,6 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
70
46
|
# Execute the query and return the results as a list of model instances
|
|
71
47
|
return list(session.execute(query).scalars())
|
|
72
48
|
|
|
73
|
-
@classmethod
|
|
74
|
-
def get_uid_from_identifier(cls, identifier: str, indifferent: Optional[bool] = False) -> str:
|
|
75
|
-
"""converts the id into a uuid object
|
|
76
|
-
Args:
|
|
77
|
-
identifier: the string identifier, such as `organization-xxxx-xx...`
|
|
78
|
-
indifferent: if True, will not enforce the prefix check
|
|
79
|
-
"""
|
|
80
|
-
try:
|
|
81
|
-
uuid_string = identifier.split("-", 1)[1] if indifferent else identifier.replace(f"{cls.__prefix__()}-", "")
|
|
82
|
-
assert is_valid_uuid4(uuid_string)
|
|
83
|
-
return uuid_string
|
|
84
|
-
except ValueError as e:
|
|
85
|
-
raise ValueError(f"{identifier} is not a valid identifier for class {cls.__name__}") from e
|
|
86
|
-
|
|
87
49
|
@classmethod
|
|
88
50
|
def read(
|
|
89
51
|
cls,
|
|
@@ -112,8 +74,7 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
112
74
|
|
|
113
75
|
# If an identifier is provided, add it to the query conditions
|
|
114
76
|
if identifier is not None:
|
|
115
|
-
|
|
116
|
-
query = query.where(cls._id == identifier)
|
|
77
|
+
query = query.where(cls.id == identifier)
|
|
117
78
|
query_conditions.append(f"id='{identifier}'")
|
|
118
79
|
|
|
119
80
|
if kwargs:
|
|
@@ -183,7 +144,7 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
183
144
|
org_id = getattr(actor, "organization_id", None)
|
|
184
145
|
if not org_id:
|
|
185
146
|
raise ValueError(f"object {actor} has no organization accessor")
|
|
186
|
-
return query.where(cls.
|
|
147
|
+
return query.where(cls.organization_id == org_id, cls.is_deleted == False)
|
|
187
148
|
|
|
188
149
|
@property
|
|
189
150
|
def __pydantic_model__(self) -> Type["BaseModel"]:
|
letta/orm/tool.py
CHANGED
|
@@ -21,13 +21,14 @@ class Tool(SqlalchemyBase, OrganizationMixin):
|
|
|
21
21
|
more granular permissions.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
__tablename__ = "
|
|
24
|
+
__tablename__ = "tools"
|
|
25
25
|
__pydantic_model__ = PydanticTool
|
|
26
26
|
|
|
27
27
|
# Add unique constraint on (name, _organization_id)
|
|
28
28
|
# An organization should not have multiple tools with the same name
|
|
29
|
-
__table_args__ = (UniqueConstraint("name", "
|
|
29
|
+
__table_args__ = (UniqueConstraint("name", "organization_id", name="uix_name_organization"),)
|
|
30
30
|
|
|
31
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
31
32
|
name: Mapped[str] = mapped_column(doc="The display name of the tool.")
|
|
32
33
|
description: Mapped[Optional[str]] = mapped_column(nullable=True, doc="The description of the tool.")
|
|
33
34
|
tags: Mapped[List] = mapped_column(JSON, doc="Metadata tags used to filter tools.")
|
letta/orm/user.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING
|
|
2
2
|
|
|
3
|
+
from sqlalchemy import String
|
|
3
4
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
4
5
|
|
|
5
6
|
from letta.orm.mixins import OrganizationMixin
|
|
@@ -13,9 +14,10 @@ if TYPE_CHECKING:
|
|
|
13
14
|
class User(SqlalchemyBase, OrganizationMixin):
|
|
14
15
|
"""User ORM class"""
|
|
15
16
|
|
|
16
|
-
__tablename__ = "
|
|
17
|
+
__tablename__ = "users"
|
|
17
18
|
__pydantic_model__ = PydanticUser
|
|
18
19
|
|
|
20
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
19
21
|
name: Mapped[str] = mapped_column(nullable=False, doc="The display name of the user.")
|
|
20
22
|
|
|
21
23
|
# relationships
|
letta/schemas/memory.py
CHANGED
|
@@ -106,6 +106,10 @@ class Memory(BaseModel, validate_assignment=True):
|
|
|
106
106
|
# New format
|
|
107
107
|
obj.prompt_template = state["prompt_template"]
|
|
108
108
|
for key, value in state["memory"].items():
|
|
109
|
+
# TODO: This is migration code, please take a look at a later time to get rid of this
|
|
110
|
+
if "name" in value:
|
|
111
|
+
value["template_name"] = value["name"]
|
|
112
|
+
value.pop("name")
|
|
109
113
|
obj.memory[key] = Block(**value)
|
|
110
114
|
else:
|
|
111
115
|
# Old format (pre-template)
|
letta/schemas/organization.py
CHANGED
|
@@ -4,16 +4,16 @@ from typing import Optional
|
|
|
4
4
|
from pydantic import Field
|
|
5
5
|
|
|
6
6
|
from letta.schemas.letta_base import LettaBase
|
|
7
|
-
from letta.utils import get_utc_time
|
|
7
|
+
from letta.utils import create_random_username, get_utc_time
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class OrganizationBase(LettaBase):
|
|
11
|
-
__id_prefix__ = "
|
|
11
|
+
__id_prefix__ = "org"
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class Organization(OrganizationBase):
|
|
15
|
-
id: str =
|
|
16
|
-
name: str = Field(
|
|
15
|
+
id: str = OrganizationBase.generate_id_field()
|
|
16
|
+
name: str = Field(create_random_username(), description="The name of the organization.")
|
|
17
17
|
created_at: Optional[datetime] = Field(default_factory=get_utc_time, description="The creation date of the organization.")
|
|
18
18
|
|
|
19
19
|
|
letta/schemas/tool.py
CHANGED
|
@@ -33,21 +33,21 @@ class Tool(BaseTool):
|
|
|
33
33
|
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
-
id: str =
|
|
36
|
+
id: str = BaseTool.generate_id_field()
|
|
37
37
|
description: Optional[str] = Field(None, description="The description of the tool.")
|
|
38
38
|
source_type: Optional[str] = Field(None, description="The type of the source code.")
|
|
39
39
|
module: Optional[str] = Field(None, description="The module of the function.")
|
|
40
|
-
organization_id: str = Field(
|
|
41
|
-
name: str = Field(
|
|
42
|
-
tags: List[str] = Field(
|
|
40
|
+
organization_id: Optional[str] = Field(None, description="The unique identifier of the organization associated with the tool.")
|
|
41
|
+
name: Optional[str] = Field(None, description="The name of the function.")
|
|
42
|
+
tags: List[str] = Field([], description="Metadata tags.")
|
|
43
43
|
|
|
44
44
|
# code
|
|
45
45
|
source_code: str = Field(..., description="The source code of the function.")
|
|
46
|
-
json_schema: Dict = Field(
|
|
46
|
+
json_schema: Optional[Dict] = Field(None, description="The JSON schema of the function.")
|
|
47
47
|
|
|
48
48
|
# metadata fields
|
|
49
|
-
created_by_id: str = Field(
|
|
50
|
-
last_updated_by_id: str = Field(
|
|
49
|
+
created_by_id: Optional[str] = Field(None, description="The id of the user that made this Tool.")
|
|
50
|
+
last_updated_by_id: Optional[str] = Field(None, description="The id of the user that made this Tool.")
|
|
51
51
|
|
|
52
52
|
def to_dict(self):
|
|
53
53
|
"""
|
letta/schemas/user.py
CHANGED
|
@@ -21,7 +21,7 @@ class User(UserBase):
|
|
|
21
21
|
created_at (datetime): The creation date of the user.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
id: str =
|
|
24
|
+
id: str = UserBase.generate_id_field()
|
|
25
25
|
organization_id: Optional[str] = Field(OrganizationManager.DEFAULT_ORG_ID, description="The organization id of the user")
|
|
26
26
|
name: str = Field(..., description="The name of the user.")
|
|
27
27
|
created_at: Optional[datetime] = Field(default_factory=datetime.utcnow, description="The creation date of the user.")
|
|
@@ -40,6 +40,7 @@ router = APIRouter(prefix="/agents", tags=["agents"])
|
|
|
40
40
|
|
|
41
41
|
@router.get("/", response_model=List[AgentState], operation_id="list_agents")
|
|
42
42
|
def list_agents(
|
|
43
|
+
name: Optional[str] = Query(None, description="Name of the agent"),
|
|
43
44
|
server: "SyncServer" = Depends(get_letta_server),
|
|
44
45
|
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
|
|
45
46
|
):
|
|
@@ -49,7 +50,11 @@ def list_agents(
|
|
|
49
50
|
"""
|
|
50
51
|
actor = server.get_user_or_default(user_id=user_id)
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
agents = server.list_agents(user_id=actor.id)
|
|
54
|
+
# TODO: move this logic to the ORM
|
|
55
|
+
if name:
|
|
56
|
+
agents = [a for a in agents if a.name == name]
|
|
57
|
+
return agents
|
|
53
58
|
|
|
54
59
|
|
|
55
60
|
@router.get("/{agent_id}/context", response_model=ContextWindowOverview, operation_id="get_agent_context_window")
|
|
@@ -38,7 +38,8 @@ def create_org(
|
|
|
38
38
|
"""
|
|
39
39
|
Create a new org in the database
|
|
40
40
|
"""
|
|
41
|
-
org =
|
|
41
|
+
org = Organization(**request.model_dump())
|
|
42
|
+
org = server.organization_manager.create_organization(pydantic_org=org)
|
|
42
43
|
return org
|
|
43
44
|
|
|
44
45
|
|
|
@@ -89,7 +89,8 @@ def create_tool(
|
|
|
89
89
|
actor = server.get_user_or_default(user_id=user_id)
|
|
90
90
|
|
|
91
91
|
# Send request to create the tool
|
|
92
|
-
|
|
92
|
+
tool = Tool(**request.model_dump())
|
|
93
|
+
return server.tool_manager.create_or_update_tool(pydantic_tool=tool, actor=actor)
|
|
93
94
|
|
|
94
95
|
|
|
95
96
|
@router.patch("/{tool_id}", response_model=Tool, operation_id="update_tool")
|
letta/server/server.py
CHANGED
|
@@ -824,7 +824,7 @@ class SyncServer(Server):
|
|
|
824
824
|
source_type = "python"
|
|
825
825
|
tags = ["memory", "memgpt-base"]
|
|
826
826
|
tool = self.tool_manager.create_or_update_tool(
|
|
827
|
-
|
|
827
|
+
Tool(
|
|
828
828
|
source_code=source_code,
|
|
829
829
|
source_type=source_type,
|
|
830
830
|
tags=tags,
|
|
@@ -1766,7 +1766,7 @@ class SyncServer(Server):
|
|
|
1766
1766
|
tool_creates += ToolCreate.load_default_composio_tools()
|
|
1767
1767
|
for tool_create in tool_creates:
|
|
1768
1768
|
try:
|
|
1769
|
-
self.tool_manager.create_or_update_tool(tool_create, actor=actor)
|
|
1769
|
+
self.tool_manager.create_or_update_tool(Tool(**tool_create.model_dump()), actor=actor)
|
|
1770
1770
|
except Exception as e:
|
|
1771
1771
|
warnings.warn(f"An error occurred while creating tool {tool_create}: {e}")
|
|
1772
1772
|
warnings.warn(traceback.format_exc())
|
|
@@ -3,13 +3,13 @@ from typing import List, Optional
|
|
|
3
3
|
from letta.orm.errors import NoResultFound
|
|
4
4
|
from letta.orm.organization import Organization as OrganizationModel
|
|
5
5
|
from letta.schemas.organization import Organization as PydanticOrganization
|
|
6
|
-
from letta.utils import
|
|
6
|
+
from letta.utils import enforce_types
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class OrganizationManager:
|
|
10
10
|
"""Manager class to handle business logic related to Organizations."""
|
|
11
11
|
|
|
12
|
-
DEFAULT_ORG_ID = "
|
|
12
|
+
DEFAULT_ORG_ID = "org-00000000-0000-4000-8000-000000000000"
|
|
13
13
|
DEFAULT_ORG_NAME = "default_org"
|
|
14
14
|
|
|
15
15
|
def __init__(self):
|
|
@@ -37,10 +37,10 @@ class OrganizationManager:
|
|
|
37
37
|
raise ValueError(f"Organization with id {org_id} not found.")
|
|
38
38
|
|
|
39
39
|
@enforce_types
|
|
40
|
-
def create_organization(self,
|
|
40
|
+
def create_organization(self, pydantic_org: PydanticOrganization) -> PydanticOrganization:
|
|
41
41
|
"""Create a new organization. If a name is provided, it is used, otherwise, a random one is generated."""
|
|
42
42
|
with self.session_maker() as session:
|
|
43
|
-
org = OrganizationModel(
|
|
43
|
+
org = OrganizationModel(**pydantic_org.model_dump())
|
|
44
44
|
org.create(session)
|
|
45
45
|
return org.to_pydantic()
|
|
46
46
|
|
letta/services/tool_manager.py
CHANGED
|
@@ -7,10 +7,9 @@ from letta.functions.functions import derive_openai_json_schema, load_function_s
|
|
|
7
7
|
|
|
8
8
|
# TODO: Remove this once we translate all of these to the ORM
|
|
9
9
|
from letta.orm.errors import NoResultFound
|
|
10
|
-
from letta.orm.organization import Organization as OrganizationModel
|
|
11
10
|
from letta.orm.tool import Tool as ToolModel
|
|
12
11
|
from letta.schemas.tool import Tool as PydanticTool
|
|
13
|
-
from letta.schemas.tool import
|
|
12
|
+
from letta.schemas.tool import ToolUpdate
|
|
14
13
|
from letta.schemas.user import User as PydanticUser
|
|
15
14
|
from letta.utils import enforce_types, printd
|
|
16
15
|
|
|
@@ -33,20 +32,20 @@ class ToolManager:
|
|
|
33
32
|
self.session_maker = db_context
|
|
34
33
|
|
|
35
34
|
@enforce_types
|
|
36
|
-
def create_or_update_tool(self,
|
|
35
|
+
def create_or_update_tool(self, pydantic_tool: PydanticTool, actor: PydanticUser) -> PydanticTool:
|
|
37
36
|
"""Create a new tool based on the ToolCreate schema."""
|
|
38
37
|
# Derive json_schema
|
|
39
|
-
derived_json_schema =
|
|
40
|
-
source_code=
|
|
38
|
+
derived_json_schema = pydantic_tool.json_schema or derive_openai_json_schema(
|
|
39
|
+
source_code=pydantic_tool.source_code, name=pydantic_tool.name
|
|
41
40
|
)
|
|
42
|
-
derived_name =
|
|
41
|
+
derived_name = pydantic_tool.name or derived_json_schema["name"]
|
|
43
42
|
|
|
44
43
|
try:
|
|
45
44
|
# NOTE: We use the organization id here
|
|
46
45
|
# This is important, because even if it's a different user, adding the same tool to the org should not happen
|
|
47
46
|
tool = self.get_tool_by_name(tool_name=derived_name, actor=actor)
|
|
48
47
|
# Put to dict and remove fields that should not be reset
|
|
49
|
-
update_data =
|
|
48
|
+
update_data = pydantic_tool.model_dump(exclude={"module"}, exclude_unset=True, exclude_none=True)
|
|
50
49
|
# Remove redundant update fields
|
|
51
50
|
update_data = {key: value for key, value in update_data.items() if getattr(tool, key) != value}
|
|
52
51
|
|
|
@@ -55,22 +54,24 @@ class ToolManager:
|
|
|
55
54
|
self.update_tool_by_id(tool.id, ToolUpdate(**update_data), actor)
|
|
56
55
|
else:
|
|
57
56
|
printd(
|
|
58
|
-
f"`create_or_update_tool` was called with user_id={actor.id}, organization_id={actor.organization_id}, name={
|
|
57
|
+
f"`create_or_update_tool` was called with user_id={actor.id}, organization_id={actor.organization_id}, name={pydantic_tool.name}, but found existing tool with nothing to update."
|
|
59
58
|
)
|
|
60
59
|
except NoResultFound:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
tool = self.create_tool(
|
|
60
|
+
pydantic_tool.json_schema = derived_json_schema
|
|
61
|
+
pydantic_tool.name = derived_name
|
|
62
|
+
tool = self.create_tool(pydantic_tool, actor=actor)
|
|
64
63
|
|
|
65
64
|
return tool
|
|
66
65
|
|
|
67
66
|
@enforce_types
|
|
68
|
-
def create_tool(self,
|
|
67
|
+
def create_tool(self, pydantic_tool: PydanticTool, actor: PydanticUser) -> PydanticTool:
|
|
69
68
|
"""Create a new tool based on the ToolCreate schema."""
|
|
70
69
|
# Create the tool
|
|
71
70
|
with self.session_maker() as session:
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
# Set the organization id at the ORM layer
|
|
72
|
+
pydantic_tool.organization_id = actor.organization_id
|
|
73
|
+
tool_data = pydantic_tool.model_dump()
|
|
74
|
+
tool = ToolModel(**tool_data)
|
|
74
75
|
tool.create(session, actor=actor)
|
|
75
76
|
|
|
76
77
|
return tool.to_pydantic()
|
|
@@ -99,7 +100,7 @@ class ToolManager:
|
|
|
99
100
|
db_session=session,
|
|
100
101
|
cursor=cursor,
|
|
101
102
|
limit=limit,
|
|
102
|
-
|
|
103
|
+
organization_id=actor.organization_id,
|
|
103
104
|
)
|
|
104
105
|
return [tool.to_pydantic() for tool in tools]
|
|
105
106
|
|
|
@@ -176,7 +177,7 @@ class ToolManager:
|
|
|
176
177
|
# create to tool
|
|
177
178
|
tools.append(
|
|
178
179
|
self.create_or_update_tool(
|
|
179
|
-
|
|
180
|
+
PydanticTool(
|
|
180
181
|
name=name,
|
|
181
182
|
tags=tags,
|
|
182
183
|
source_type="python",
|
letta/services/user_manager.py
CHANGED
|
@@ -4,7 +4,7 @@ from letta.orm.errors import NoResultFound
|
|
|
4
4
|
from letta.orm.organization import Organization as OrganizationModel
|
|
5
5
|
from letta.orm.user import User as UserModel
|
|
6
6
|
from letta.schemas.user import User as PydanticUser
|
|
7
|
-
from letta.schemas.user import
|
|
7
|
+
from letta.schemas.user import UserUpdate
|
|
8
8
|
from letta.services.organization_manager import OrganizationManager
|
|
9
9
|
from letta.utils import enforce_types
|
|
10
10
|
|
|
@@ -42,10 +42,10 @@ class UserManager:
|
|
|
42
42
|
return user.to_pydantic()
|
|
43
43
|
|
|
44
44
|
@enforce_types
|
|
45
|
-
def create_user(self,
|
|
45
|
+
def create_user(self, pydantic_user: PydanticUser) -> PydanticUser:
|
|
46
46
|
"""Create a new user if it doesn't already exist."""
|
|
47
47
|
with self.session_maker() as session:
|
|
48
|
-
new_user = UserModel(**
|
|
48
|
+
new_user = UserModel(**pydantic_user.model_dump())
|
|
49
49
|
new_user.create(session)
|
|
50
50
|
return new_user.to_pydantic()
|
|
51
51
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: letta-nightly
|
|
3
|
-
Version: 0.5.1.
|
|
3
|
+
Version: 0.5.1.dev20241106104104
|
|
4
4
|
Summary: Create LLM agents with long-term memory and custom tools
|
|
5
5
|
License: Apache License
|
|
6
6
|
Author: Letta Team
|
|
@@ -99,7 +99,7 @@ Description-Content-Type: text/markdown
|
|
|
99
99
|
</h3>
|
|
100
100
|
|
|
101
101
|
**👾 Letta** is an open source framework for building stateful LLM applications. You can use Letta to build **stateful agents** with advanced reasoning capabilities and transparent long-term memory. The Letta framework is white box and model-agnostic.
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
[](https://discord.gg/letta)
|
|
104
104
|
[](https://twitter.com/Letta_AI)
|
|
105
105
|
[](https://arxiv.org/abs/2310.08560)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
letta/__init__.py,sha256=zlZXKr0iQIsC7FTkN9fjTvAgQGPXyr0nnkMJ7_OE1D0,1014
|
|
2
2
|
letta/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
|
|
3
|
-
letta/agent.py,sha256=
|
|
3
|
+
letta/agent.py,sha256=D4d0ASMYn4Wfq-AKoho7KUM1i9rWKIk5zEYod6zq418,76319
|
|
4
4
|
letta/agent_store/chroma.py,sha256=upR5zGnGs6I6btulEYbiZdGG87BgKjxUJOQZ4Y-RQ_M,12492
|
|
5
|
-
letta/agent_store/db.py,sha256=
|
|
5
|
+
letta/agent_store/db.py,sha256=bOchnK54xpXjiAlvUqFDyGS8Q6T-nVearxoSU0i8Q_Q,23346
|
|
6
6
|
letta/agent_store/lancedb.py,sha256=i63d4VZwj9UIOTNs5f0JZ_r5yZD-jKWz4FAH4RMpXOE,5104
|
|
7
7
|
letta/agent_store/milvus.py,sha256=xUu-D9a6N10MuGJ-R-QWR2IHX77ueqAp88tV4gg9B4M,8470
|
|
8
8
|
letta/agent_store/qdrant.py,sha256=6_33V-FEDpT9LG5zmr6-3y9slw1YFLswxpahiyMkvHA,7880
|
|
@@ -13,7 +13,7 @@ letta/cli/cli.py,sha256=JP5-nw38f2BjCOU4pU4LsDBQmTJNNhJcJuviw-9a2Yw,16142
|
|
|
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=hboYStQk5VC4rC7mIbylZdlb36XhkG7xwK-2IOSE9zQ,97082
|
|
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
|
|
@@ -91,14 +91,14 @@ letta/openai_backcompat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
|
91
91
|
letta/openai_backcompat/openai_object.py,sha256=Y1ZS1sATP60qxJiOsjOP3NbwSzuzvkNAvb3DeuhM5Uk,13490
|
|
92
92
|
letta/orm/__all__.py,sha256=2gh2MZTkA3Hw67VWVKK3JIStJOqTeLdpCvYSVYNeEDA,692
|
|
93
93
|
letta/orm/__init__.py,sha256=J2GZpfXQunxU0ChavjkhoaSruluRFrLYknXD2m0BP_g,144
|
|
94
|
-
letta/orm/base.py,sha256=
|
|
94
|
+
letta/orm/base.py,sha256=K_LpNUURbsj44ycHbzvNXG_n8pBOjf1YvDaikIPDpQA,2716
|
|
95
95
|
letta/orm/enums.py,sha256=KfHcFt_fR6GUmSlmfsa-TetvmuRxGESNve8MStRYW64,145
|
|
96
96
|
letta/orm/errors.py,sha256=somsGtotFlb3SDM6tKdZ5TDGwEEP3ppx47ICAvNMnkg,225
|
|
97
|
-
letta/orm/mixins.py,sha256=
|
|
98
|
-
letta/orm/organization.py,sha256=
|
|
99
|
-
letta/orm/sqlalchemy_base.py,sha256=
|
|
100
|
-
letta/orm/tool.py,sha256=
|
|
101
|
-
letta/orm/user.py,sha256
|
|
97
|
+
letta/orm/mixins.py,sha256=fW4oa1cUFbgVE46KSQlW_hwzsZSqEBSSV-U3xJC6fyw,749
|
|
98
|
+
letta/orm/organization.py,sha256=KpoSStoxThbBHfG4nowkpyACwcW6R_kZFuPsp6aHGPA,1561
|
|
99
|
+
letta/orm/sqlalchemy_base.py,sha256=jxOQP3eAherFVD-0SbTanANEwbBfATXWqp9ix2pqhC0,6556
|
|
100
|
+
letta/orm/tool.py,sha256=7FIeldPJTEOLA5ygasTOVXqUcm2aouYYARUOJXdaC4Y,2151
|
|
101
|
+
letta/orm/user.py,sha256=-KNdpfnKRVJtSw0NrGRrVoSBBv7ASDchVempKtUuk-A,1229
|
|
102
102
|
letta/persistence_manager.py,sha256=LlLgEDpSafCPAiyKmuq0NvVAnfBkZo6TWbGIKYQjQBs,5200
|
|
103
103
|
letta/personas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
104
104
|
letta/personas/examples/anna_pa.txt,sha256=zgiNdSNhy1HQy58cF_6RFPzcg2i37F9v38YuL1CW40A,1849
|
|
@@ -137,20 +137,20 @@ letta/schemas/letta_message.py,sha256=RuVVtwFbi85yP3dXQxowofQ6cI2cO_CdGtgpHGQzgH
|
|
|
137
137
|
letta/schemas/letta_request.py,sha256=_oiDshc_AoFWIfXRk2VX5-AxO5vDlyN-9r-gnyLj_30,1890
|
|
138
138
|
letta/schemas/letta_response.py,sha256=ClI0LKyhMVI0N5CSnTAbcHaw7simkyrUTKYX0fr0qzw,1610
|
|
139
139
|
letta/schemas/llm_config.py,sha256=eFA48vKBTO70qaob8pak2CWOH7TCQeqWuClkMBc2vbY,4172
|
|
140
|
-
letta/schemas/memory.py,sha256=
|
|
140
|
+
letta/schemas/memory.py,sha256=fHkJZr8CrGcHhbJlckWgfRYMhLkRliKCU-hRxqr19ks,11725
|
|
141
141
|
letta/schemas/message.py,sha256=DQxnRYrYgHXpTKfMzfS-bpCAe-BO_Rmcfc1Wf-4GHjw,33703
|
|
142
142
|
letta/schemas/openai/chat_completion_request.py,sha256=AOIwgbN3CZKVqkuXeMHeSa53u4h0wVq69t3T_LJ0vIE,3389
|
|
143
143
|
letta/schemas/openai/chat_completion_response.py,sha256=05FRfm1EsVivyeWo2aoJk34h3W4pAb4lBCPn1eujjcw,3916
|
|
144
144
|
letta/schemas/openai/chat_completions.py,sha256=V0ZPIIk-ds3O6MAkNHMz8zh1hqMFSPrTcYr88WDYzWE,3588
|
|
145
145
|
letta/schemas/openai/embedding_response.py,sha256=WKIZpXab1Av7v6sxKG8feW3ZtpQUNosmLVSuhXYa_xU,357
|
|
146
146
|
letta/schemas/openai/openai.py,sha256=Hilo5BiLAGabzxCwnwfzK5QrWqwYD8epaEKFa4Pwndk,7970
|
|
147
|
-
letta/schemas/organization.py,sha256=
|
|
147
|
+
letta/schemas/organization.py,sha256=d2oN3IK2HeruEHKXwIzCbJ3Fxdi_BEe9JZ8J9aDbHwQ,698
|
|
148
148
|
letta/schemas/passage.py,sha256=eYQMxD_XjHAi72jmqcGBU4wM4VZtSU0XK8uhQxxN3Ug,3563
|
|
149
149
|
letta/schemas/source.py,sha256=hB4Ai6Nj8dFdbxv5_Qaf4uN_cmdGmnzgc-4QnHXcV3o,2562
|
|
150
|
-
letta/schemas/tool.py,sha256=
|
|
150
|
+
letta/schemas/tool.py,sha256=GuZUMGCKERtBlLIBu0f6ZjOfmI4LXSjebyLBZUeaIPk,9415
|
|
151
151
|
letta/schemas/tool_rule.py,sha256=dHEwVOZ40lMEVCrry7wlZM0IJo5SJrZqXKYpXe40bjY,778
|
|
152
152
|
letta/schemas/usage.py,sha256=lvn1ooHwLEdv6gwQpw5PBUbcwn_gwdT6HA-fCiix6sY,817
|
|
153
|
-
letta/schemas/user.py,sha256=
|
|
153
|
+
letta/schemas/user.py,sha256=V32Tgl6oqB3KznkxUz12y7agkQicjzW7VocSpj78i6Q,1526
|
|
154
154
|
letta/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
155
155
|
letta/server/constants.py,sha256=yAdGbLkzlOU_dLTx0lKDmAnj0ZgRXCEaIcPJWO69eaE,92
|
|
156
156
|
letta/server/rest_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -168,18 +168,18 @@ letta/server/rest_api/routers/openai/assistants/threads.py,sha256=WXVGBaBvSNPB7Z
|
|
|
168
168
|
letta/server/rest_api/routers/openai/chat_completions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
169
169
|
letta/server/rest_api/routers/openai/chat_completions/chat_completions.py,sha256=-uye6cm4SnoQGwxhr1N1FrSXOlnO2Hvbfj6k8JSc45k,4918
|
|
170
170
|
letta/server/rest_api/routers/v1/__init__.py,sha256=sqlVZa-u9DJwdRsp0_8YUGrac9DHguIB4wETlEDRylA,666
|
|
171
|
-
letta/server/rest_api/routers/v1/agents.py,sha256=
|
|
171
|
+
letta/server/rest_api/routers/v1/agents.py,sha256=1qB56MaoE_cU_tOKAFkCLeBb06_TzxN0lHcWs4sOggM,25708
|
|
172
172
|
letta/server/rest_api/routers/v1/blocks.py,sha256=0WekE_yBD2U3jYgPxI0DCFjACWavCAlvm_Ybw5SZBnw,2583
|
|
173
173
|
letta/server/rest_api/routers/v1/health.py,sha256=pKCuVESlVOhGIb4VC4K-H82eZqfghmT6kvj2iOkkKuc,401
|
|
174
174
|
letta/server/rest_api/routers/v1/jobs.py,sha256=a-j0v-5A0un0pVCOHpfeWnzpOWkVDQO6ti42k_qAlZY,2272
|
|
175
175
|
letta/server/rest_api/routers/v1/llms.py,sha256=TcyvSx6MEM3je5F4DysL7ligmssL_pFlJaaO4uL95VY,877
|
|
176
|
-
letta/server/rest_api/routers/v1/organizations.py,sha256=
|
|
176
|
+
letta/server/rest_api/routers/v1/organizations.py,sha256=tyqVzXTpMtk3sKxI3Iz4aS6RhbGEbXDzFBB_CpW18v4,2080
|
|
177
177
|
letta/server/rest_api/routers/v1/sources.py,sha256=eY_pk9jRL2Y9yIZdsTjH6EuKsfH1neaTU15MKNL0dvw,8749
|
|
178
|
-
letta/server/rest_api/routers/v1/tools.py,sha256=
|
|
179
|
-
letta/server/rest_api/routers/v1/users.py,sha256=
|
|
178
|
+
letta/server/rest_api/routers/v1/tools.py,sha256=3QiHmEh3auDX8xi-QzUrh_r242amcitXF232pF6QfoY,4273
|
|
179
|
+
letta/server/rest_api/routers/v1/users.py,sha256=EfqXZk1X3YNajVKMud6dts8WojSUUkD18N4Wibi0ndU,3410
|
|
180
180
|
letta/server/rest_api/static_files.py,sha256=NG8sN4Z5EJ8JVQdj19tkFa9iQ1kBPTab9f_CUxd_u4Q,3143
|
|
181
181
|
letta/server/rest_api/utils.py,sha256=GdHYCzXtbM5VCAYDPR0z5gnNZpRhwPld2BGZV7xT6cU,2924
|
|
182
|
-
letta/server/server.py,sha256=
|
|
182
|
+
letta/server/server.py,sha256=dz2pYza0ImLucFF7BLm7Vvtry3Dl3JbhJDd6SRnx8jQ,78931
|
|
183
183
|
letta/server/startup.sh,sha256=Atyf4hL5XLpC4aA3esEyOeNWfemlgXlgpeKB59fDFvw,334
|
|
184
184
|
letta/server/static_files/assets/index-3ab03d5b.css,sha256=OrA9W4iKJ5h2Wlr7GwdAT4wow0CM8hVit1yOxEL49Qw,54295
|
|
185
185
|
letta/server/static_files/assets/index-9fa459a2.js,sha256=j2oMcDJO9dWJaH5e-tsflbVpWK20gLWpZKJk4-Kuy6A,1815592
|
|
@@ -193,16 +193,16 @@ letta/server/ws_api/interface.py,sha256=TWl9vkcMCnLsUtgsuENZ-ku2oMDA-OUTzLh_yNRo
|
|
|
193
193
|
letta/server/ws_api/protocol.py,sha256=M_-gM5iuDBwa1cuN2IGNCG5GxMJwU2d3XW93XALv9s8,1821
|
|
194
194
|
letta/server/ws_api/server.py,sha256=C2Kv48PCwl46DQFb0ZP30s86KJLQ6dZk2AhWQEZn9pY,6004
|
|
195
195
|
letta/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
196
|
-
letta/services/organization_manager.py,sha256=
|
|
197
|
-
letta/services/tool_manager.py,sha256=
|
|
198
|
-
letta/services/user_manager.py,sha256=
|
|
196
|
+
letta/services/organization_manager.py,sha256=2RMmA8TRE9OFkomnT2NptEuFL4Y1lU3H2w1YjacI-o8,3613
|
|
197
|
+
letta/services/tool_manager.py,sha256=IFfOX2fNGH7LYv5qI30CUTnUceW6zffs4O7qAQz5CTA,8397
|
|
198
|
+
letta/services/user_manager.py,sha256=UJa0hqCjz0yXtvrCR8OVBqlSR5lC_Ejn-uG__58zLds,4398
|
|
199
199
|
letta/settings.py,sha256=yiYNmnYKj_BdTm0cBEIvQKYGU-lCmFntqsyVfRUy3_k,3411
|
|
200
200
|
letta/streaming_interface.py,sha256=_FPUWy58j50evHcpXyd7zB1wWqeCc71NCFeWh_TBvnw,15736
|
|
201
201
|
letta/streaming_utils.py,sha256=329fsvj1ZN0r0LpQtmMPZ2vSxkDBIUUwvGHZFkjm2I8,11745
|
|
202
202
|
letta/system.py,sha256=buKYPqG5n2x41hVmWpu6JUpyd7vTWED9Km2_M7dLrvk,6960
|
|
203
203
|
letta/utils.py,sha256=SXLEYhyp3gHyIjrxNIKNZZ5ittKo3KOj6zxgC_Trex0,31012
|
|
204
|
-
letta_nightly-0.5.1.
|
|
205
|
-
letta_nightly-0.5.1.
|
|
206
|
-
letta_nightly-0.5.1.
|
|
207
|
-
letta_nightly-0.5.1.
|
|
208
|
-
letta_nightly-0.5.1.
|
|
204
|
+
letta_nightly-0.5.1.dev20241106104104.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
|
|
205
|
+
letta_nightly-0.5.1.dev20241106104104.dist-info/METADATA,sha256=LkoZ6XlBdXxzQ9lizd3w-BTqshhQgwEHGlAr2cPfIbo,10793
|
|
206
|
+
letta_nightly-0.5.1.dev20241106104104.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
207
|
+
letta_nightly-0.5.1.dev20241106104104.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
|
|
208
|
+
letta_nightly-0.5.1.dev20241106104104.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|