letta-nightly 0.6.1.dev20241206104246__py3-none-any.whl → 0.6.1.dev20241208104134__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 +68 -76
- letta/agent_store/db.py +1 -77
- letta/agent_store/storage.py +0 -5
- letta/cli/cli.py +1 -4
- letta/client/client.py +11 -14
- letta/constants.py +1 -0
- letta/functions/function_sets/base.py +33 -5
- letta/functions/helpers.py +3 -3
- letta/llm_api/openai.py +0 -1
- letta/local_llm/llm_chat_completion_wrappers/chatml.py +13 -1
- letta/main.py +2 -2
- letta/memory.py +4 -82
- letta/metadata.py +0 -35
- letta/o1_agent.py +7 -2
- letta/offline_memory_agent.py +6 -0
- letta/orm/__init__.py +2 -0
- letta/orm/file.py +1 -1
- letta/orm/message.py +64 -0
- letta/orm/mixins.py +16 -0
- letta/orm/organization.py +1 -0
- letta/orm/sqlalchemy_base.py +118 -26
- letta/schemas/letta_base.py +7 -6
- letta/schemas/message.py +6 -12
- letta/schemas/tool.py +18 -11
- letta/server/rest_api/app.py +2 -3
- letta/server/rest_api/routers/v1/agents.py +7 -6
- letta/server/rest_api/routers/v1/blocks.py +2 -2
- letta/server/rest_api/routers/v1/tools.py +26 -4
- letta/server/rest_api/utils.py +3 -1
- letta/server/server.py +67 -62
- letta/server/static_files/assets/index-43ab4d62.css +1 -0
- letta/server/static_files/assets/index-4848e3d7.js +40 -0
- letta/server/static_files/index.html +2 -2
- letta/services/block_manager.py +1 -1
- letta/services/message_manager.py +194 -0
- letta/services/organization_manager.py +6 -9
- letta/services/sandbox_config_manager.py +16 -1
- letta/services/source_manager.py +1 -1
- letta/services/tool_manager.py +2 -4
- letta/services/user_manager.py +1 -1
- {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/METADATA +2 -2
- {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/RECORD +45 -45
- letta/agent_store/lancedb.py +0 -177
- letta/persistence_manager.py +0 -149
- letta/server/static_files/assets/index-1b5d1a41.js +0 -271
- letta/server/static_files/assets/index-56a3f8c6.css +0 -1
- {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/LICENSE +0 -0
- {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/WHEEL +0 -0
- {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/entry_points.txt +0 -0
letta/agent_store/lancedb.py
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# type: ignore
|
|
2
|
-
|
|
3
|
-
import uuid
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
from typing import Dict, Iterator, List, Optional
|
|
6
|
-
|
|
7
|
-
from lancedb.pydantic import LanceModel, Vector
|
|
8
|
-
|
|
9
|
-
from letta.agent_store.storage import StorageConnector, TableType
|
|
10
|
-
from letta.config import AgentConfig, LettaConfig
|
|
11
|
-
from letta.schemas.message import Message, Passage, Record
|
|
12
|
-
|
|
13
|
-
""" Initial implementation - not complete """
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def get_db_model(table_name: str, table_type: TableType):
|
|
17
|
-
config = LettaConfig.load()
|
|
18
|
-
|
|
19
|
-
if table_type == TableType.ARCHIVAL_MEMORY or table_type == TableType.PASSAGES:
|
|
20
|
-
# create schema for archival memory
|
|
21
|
-
class PassageModel(LanceModel):
|
|
22
|
-
"""Defines data model for storing Passages (consisting of text, embedding)"""
|
|
23
|
-
|
|
24
|
-
id: uuid.UUID
|
|
25
|
-
user_id: str
|
|
26
|
-
text: str
|
|
27
|
-
file_id: str
|
|
28
|
-
agent_id: str
|
|
29
|
-
data_source: str
|
|
30
|
-
embedding: Vector(config.default_embedding_config.embedding_dim)
|
|
31
|
-
metadata_: Dict
|
|
32
|
-
|
|
33
|
-
def __repr__(self):
|
|
34
|
-
return f"<Passage(passage_id='{self.id}', text='{self.text}', embedding='{self.embedding})>"
|
|
35
|
-
|
|
36
|
-
def to_record(self):
|
|
37
|
-
return Passage(
|
|
38
|
-
text=self.text,
|
|
39
|
-
embedding=self.embedding,
|
|
40
|
-
file_id=self.file_id,
|
|
41
|
-
user_id=self.user_id,
|
|
42
|
-
id=self.id,
|
|
43
|
-
data_source=self.data_source,
|
|
44
|
-
agent_id=self.agent_id,
|
|
45
|
-
metadata=self.metadata_,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
return PassageModel
|
|
49
|
-
elif table_type == TableType.RECALL_MEMORY:
|
|
50
|
-
|
|
51
|
-
class MessageModel(LanceModel):
|
|
52
|
-
"""Defines data model for storing Message objects"""
|
|
53
|
-
|
|
54
|
-
__abstract__ = True # this line is necessary
|
|
55
|
-
|
|
56
|
-
# Assuming message_id is the primary key
|
|
57
|
-
id: uuid.UUID
|
|
58
|
-
user_id: str
|
|
59
|
-
agent_id: str
|
|
60
|
-
|
|
61
|
-
# openai info
|
|
62
|
-
role: str
|
|
63
|
-
name: str
|
|
64
|
-
text: str
|
|
65
|
-
model: str
|
|
66
|
-
user: str
|
|
67
|
-
|
|
68
|
-
# function info
|
|
69
|
-
function_name: str
|
|
70
|
-
function_args: str
|
|
71
|
-
function_response: str
|
|
72
|
-
|
|
73
|
-
embedding = Vector(config.default_embedding_config.embedding_dim)
|
|
74
|
-
|
|
75
|
-
# Add a datetime column, with default value as the current time
|
|
76
|
-
created_at = datetime
|
|
77
|
-
|
|
78
|
-
def __repr__(self):
|
|
79
|
-
return f"<Message(message_id='{self.id}', text='{self.text}', embedding='{self.embedding})>"
|
|
80
|
-
|
|
81
|
-
def to_record(self):
|
|
82
|
-
return Message(
|
|
83
|
-
user_id=self.user_id,
|
|
84
|
-
agent_id=self.agent_id,
|
|
85
|
-
role=self.role,
|
|
86
|
-
name=self.name,
|
|
87
|
-
text=self.text,
|
|
88
|
-
model=self.model,
|
|
89
|
-
function_name=self.function_name,
|
|
90
|
-
function_args=self.function_args,
|
|
91
|
-
function_response=self.function_response,
|
|
92
|
-
embedding=self.embedding,
|
|
93
|
-
created_at=self.created_at,
|
|
94
|
-
id=self.id,
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
"""Create database model for table_name"""
|
|
98
|
-
return MessageModel
|
|
99
|
-
|
|
100
|
-
else:
|
|
101
|
-
raise ValueError(f"Table type {table_type} not implemented")
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
class LanceDBConnector(StorageConnector):
|
|
105
|
-
"""Storage via LanceDB"""
|
|
106
|
-
|
|
107
|
-
# TODO: this should probably eventually be moved into a parent DB class
|
|
108
|
-
|
|
109
|
-
def __init__(self, name: Optional[str] = None, agent_config: Optional[AgentConfig] = None):
|
|
110
|
-
# TODO
|
|
111
|
-
pass
|
|
112
|
-
|
|
113
|
-
def generate_where_filter(self, filters: Dict) -> str:
|
|
114
|
-
where_filters = []
|
|
115
|
-
for key, value in filters.items():
|
|
116
|
-
where_filters.append(f"{key}={value}")
|
|
117
|
-
return where_filters.join(" AND ")
|
|
118
|
-
|
|
119
|
-
@abstractmethod
|
|
120
|
-
def get_all_paginated(self, filters: Optional[Dict] = {}, page_size: Optional[int] = 1000) -> Iterator[List[Record]]:
|
|
121
|
-
# TODO
|
|
122
|
-
pass
|
|
123
|
-
|
|
124
|
-
@abstractmethod
|
|
125
|
-
def get_all(self, filters: Optional[Dict] = {}, limit=10) -> List[Record]:
|
|
126
|
-
# TODO
|
|
127
|
-
pass
|
|
128
|
-
|
|
129
|
-
@abstractmethod
|
|
130
|
-
def get(self, id: uuid.UUID) -> Optional[Record]:
|
|
131
|
-
# TODO
|
|
132
|
-
pass
|
|
133
|
-
|
|
134
|
-
@abstractmethod
|
|
135
|
-
def size(self, filters: Optional[Dict] = {}) -> int:
|
|
136
|
-
# TODO
|
|
137
|
-
pass
|
|
138
|
-
|
|
139
|
-
@abstractmethod
|
|
140
|
-
def insert(self, record: Record):
|
|
141
|
-
# TODO
|
|
142
|
-
pass
|
|
143
|
-
|
|
144
|
-
@abstractmethod
|
|
145
|
-
def insert_many(self, records: List[Record], show_progress=False):
|
|
146
|
-
# TODO
|
|
147
|
-
pass
|
|
148
|
-
|
|
149
|
-
@abstractmethod
|
|
150
|
-
def query(self, query: str, query_vec: List[float], top_k: int = 10, filters: Optional[Dict] = {}) -> List[Record]:
|
|
151
|
-
# TODO
|
|
152
|
-
pass
|
|
153
|
-
|
|
154
|
-
@abstractmethod
|
|
155
|
-
def query_date(self, start_date, end_date):
|
|
156
|
-
# TODO
|
|
157
|
-
pass
|
|
158
|
-
|
|
159
|
-
@abstractmethod
|
|
160
|
-
def query_text(self, query):
|
|
161
|
-
# TODO
|
|
162
|
-
pass
|
|
163
|
-
|
|
164
|
-
@abstractmethod
|
|
165
|
-
def delete_table(self):
|
|
166
|
-
# TODO
|
|
167
|
-
pass
|
|
168
|
-
|
|
169
|
-
@abstractmethod
|
|
170
|
-
def delete(self, filters: Optional[Dict] = {}):
|
|
171
|
-
# TODO
|
|
172
|
-
pass
|
|
173
|
-
|
|
174
|
-
@abstractmethod
|
|
175
|
-
def save(self):
|
|
176
|
-
# TODO
|
|
177
|
-
pass
|
letta/persistence_manager.py
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from typing import List
|
|
4
|
-
|
|
5
|
-
from letta.memory import BaseRecallMemory, EmbeddingArchivalMemory
|
|
6
|
-
from letta.schemas.agent import AgentState
|
|
7
|
-
from letta.schemas.memory import Memory
|
|
8
|
-
from letta.schemas.message import Message
|
|
9
|
-
from letta.utils import printd
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def parse_formatted_time(formatted_time: str):
|
|
13
|
-
# parse times returned by letta.utils.get_formatted_time()
|
|
14
|
-
try:
|
|
15
|
-
return datetime.strptime(formatted_time.strip(), "%Y-%m-%d %I:%M:%S %p %Z%z")
|
|
16
|
-
except:
|
|
17
|
-
return datetime.strptime(formatted_time.strip(), "%Y-%m-%d %I:%M:%S %p")
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class PersistenceManager(ABC):
|
|
21
|
-
@abstractmethod
|
|
22
|
-
def trim_messages(self, num):
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
@abstractmethod
|
|
26
|
-
def prepend_to_messages(self, added_messages):
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
@abstractmethod
|
|
30
|
-
def append_to_messages(self, added_messages):
|
|
31
|
-
pass
|
|
32
|
-
|
|
33
|
-
@abstractmethod
|
|
34
|
-
def swap_system_message(self, new_system_message):
|
|
35
|
-
pass
|
|
36
|
-
|
|
37
|
-
@abstractmethod
|
|
38
|
-
def update_memory(self, new_memory):
|
|
39
|
-
pass
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class LocalStateManager(PersistenceManager):
|
|
43
|
-
"""In-memory state manager has nothing to manage, all agents are held in-memory"""
|
|
44
|
-
|
|
45
|
-
recall_memory_cls = BaseRecallMemory
|
|
46
|
-
archival_memory_cls = EmbeddingArchivalMemory
|
|
47
|
-
|
|
48
|
-
def __init__(self, agent_state: AgentState):
|
|
49
|
-
# Memory held in-state useful for debugging stateful versions
|
|
50
|
-
self.memory = agent_state.memory
|
|
51
|
-
# self.messages = [] # current in-context messages
|
|
52
|
-
# self.all_messages = [] # all messages seen in current session (needed if lazily synchronizing state with DB)
|
|
53
|
-
self.archival_memory = EmbeddingArchivalMemory(agent_state)
|
|
54
|
-
self.recall_memory = BaseRecallMemory(agent_state)
|
|
55
|
-
# self.agent_state = agent_state
|
|
56
|
-
|
|
57
|
-
def save(self):
|
|
58
|
-
"""Ensure storage connectors save data"""
|
|
59
|
-
self.archival_memory.save()
|
|
60
|
-
self.recall_memory.save()
|
|
61
|
-
|
|
62
|
-
'''
|
|
63
|
-
def json_to_message(self, message_json) -> Message:
|
|
64
|
-
"""Convert agent message JSON into Message object"""
|
|
65
|
-
|
|
66
|
-
# get message
|
|
67
|
-
if "message" in message_json:
|
|
68
|
-
message = message_json["message"]
|
|
69
|
-
else:
|
|
70
|
-
message = message_json
|
|
71
|
-
|
|
72
|
-
# get timestamp
|
|
73
|
-
if "timestamp" in message_json:
|
|
74
|
-
timestamp = parse_formatted_time(message_json["timestamp"])
|
|
75
|
-
else:
|
|
76
|
-
timestamp = get_local_time()
|
|
77
|
-
|
|
78
|
-
# TODO: change this when we fully migrate to tool calls API
|
|
79
|
-
if "function_call" in message:
|
|
80
|
-
tool_calls = [
|
|
81
|
-
ToolCall(
|
|
82
|
-
id=message["tool_call_id"],
|
|
83
|
-
tool_call_type="function",
|
|
84
|
-
function={
|
|
85
|
-
"name": message["function_call"]["name"],
|
|
86
|
-
"arguments": message["function_call"]["arguments"],
|
|
87
|
-
},
|
|
88
|
-
)
|
|
89
|
-
]
|
|
90
|
-
printd(f"Saving tool calls {[vars(tc) for tc in tool_calls]}")
|
|
91
|
-
else:
|
|
92
|
-
tool_calls = None
|
|
93
|
-
|
|
94
|
-
# if message["role"] == "function":
|
|
95
|
-
# message["role"] = "tool"
|
|
96
|
-
|
|
97
|
-
return Message(
|
|
98
|
-
user_id=self.agent_state.user_id,
|
|
99
|
-
agent_id=self.agent_state.id,
|
|
100
|
-
role=message["role"],
|
|
101
|
-
text=message["content"],
|
|
102
|
-
name=message["name"] if "name" in message else None,
|
|
103
|
-
model=self.agent_state.llm_config.model,
|
|
104
|
-
created_at=timestamp,
|
|
105
|
-
tool_calls=tool_calls,
|
|
106
|
-
tool_call_id=message["tool_call_id"] if "tool_call_id" in message else None,
|
|
107
|
-
id=message["id"] if "id" in message else None,
|
|
108
|
-
)
|
|
109
|
-
'''
|
|
110
|
-
|
|
111
|
-
def trim_messages(self, num):
|
|
112
|
-
# printd(f"InMemoryStateManager.trim_messages")
|
|
113
|
-
# self.messages = [self.messages[0]] + self.messages[num:]
|
|
114
|
-
pass
|
|
115
|
-
|
|
116
|
-
def prepend_to_messages(self, added_messages: List[Message]):
|
|
117
|
-
# first tag with timestamps
|
|
118
|
-
# added_messages = [{"timestamp": get_local_time(), "message": msg} for msg in added_messages]
|
|
119
|
-
|
|
120
|
-
printd(f"{self.__class__.__name__}.prepend_to_message")
|
|
121
|
-
# self.messages = [self.messages[0]] + added_messages + self.messages[1:]
|
|
122
|
-
|
|
123
|
-
# add to recall memory
|
|
124
|
-
self.recall_memory.insert_many([m for m in added_messages])
|
|
125
|
-
|
|
126
|
-
def append_to_messages(self, added_messages: List[Message]):
|
|
127
|
-
# first tag with timestamps
|
|
128
|
-
# added_messages = [{"timestamp": get_local_time(), "message": msg} for msg in added_messages]
|
|
129
|
-
|
|
130
|
-
printd(f"{self.__class__.__name__}.append_to_messages")
|
|
131
|
-
# self.messages = self.messages + added_messages
|
|
132
|
-
|
|
133
|
-
# add to recall memory
|
|
134
|
-
self.recall_memory.insert_many([m for m in added_messages])
|
|
135
|
-
|
|
136
|
-
def swap_system_message(self, new_system_message: Message):
|
|
137
|
-
# first tag with timestamps
|
|
138
|
-
# new_system_message = {"timestamp": get_local_time(), "message": new_system_message}
|
|
139
|
-
|
|
140
|
-
printd(f"{self.__class__.__name__}.swap_system_message")
|
|
141
|
-
# self.messages[0] = new_system_message
|
|
142
|
-
|
|
143
|
-
# add to recall memory
|
|
144
|
-
self.recall_memory.insert(new_system_message)
|
|
145
|
-
|
|
146
|
-
def update_memory(self, new_memory: Memory):
|
|
147
|
-
printd(f"{self.__class__.__name__}.update_memory")
|
|
148
|
-
assert isinstance(new_memory, Memory), type(new_memory)
|
|
149
|
-
self.memory = new_memory
|