letta-nightly 0.6.4.dev20241213193437__py3-none-any.whl → 0.6.4.dev20241215104129__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 +54 -45
- letta/chat_only_agent.py +6 -8
- letta/cli/cli.py +2 -10
- letta/client/client.py +121 -138
- letta/config.py +0 -161
- letta/main.py +3 -8
- letta/memory.py +3 -14
- letta/o1_agent.py +1 -5
- letta/offline_memory_agent.py +2 -6
- letta/orm/__init__.py +2 -0
- letta/orm/agent.py +109 -0
- letta/orm/agents_tags.py +10 -18
- letta/orm/block.py +29 -4
- letta/orm/blocks_agents.py +5 -11
- letta/orm/custom_columns.py +152 -0
- letta/orm/message.py +3 -38
- letta/orm/organization.py +2 -7
- letta/orm/passage.py +10 -32
- letta/orm/source.py +5 -25
- letta/orm/sources_agents.py +13 -0
- letta/orm/sqlalchemy_base.py +54 -30
- letta/orm/tool.py +1 -19
- letta/orm/tools_agents.py +7 -24
- letta/orm/user.py +3 -4
- letta/schemas/agent.py +48 -65
- letta/schemas/memory.py +2 -1
- letta/schemas/sandbox_config.py +12 -1
- letta/server/rest_api/app.py +0 -5
- letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +1 -1
- letta/server/rest_api/routers/v1/agents.py +99 -78
- letta/server/rest_api/routers/v1/blocks.py +22 -25
- letta/server/rest_api/routers/v1/jobs.py +4 -4
- letta/server/rest_api/routers/v1/sandbox_configs.py +10 -10
- letta/server/rest_api/routers/v1/sources.py +12 -12
- letta/server/rest_api/routers/v1/tools.py +35 -15
- letta/server/rest_api/routers/v1/users.py +0 -46
- letta/server/server.py +172 -716
- letta/server/ws_api/server.py +0 -5
- letta/services/agent_manager.py +405 -0
- letta/services/block_manager.py +13 -21
- letta/services/helpers/agent_manager_helper.py +90 -0
- letta/services/organization_manager.py +0 -1
- letta/services/passage_manager.py +62 -62
- letta/services/sandbox_config_manager.py +3 -3
- letta/services/source_manager.py +22 -1
- letta/services/user_manager.py +11 -6
- letta/utils.py +2 -2
- {letta_nightly-0.6.4.dev20241213193437.dist-info → letta_nightly-0.6.4.dev20241215104129.dist-info}/METADATA +1 -1
- {letta_nightly-0.6.4.dev20241213193437.dist-info → letta_nightly-0.6.4.dev20241215104129.dist-info}/RECORD +53 -57
- letta/metadata.py +0 -407
- letta/schemas/agents_tags.py +0 -33
- letta/schemas/api_key.py +0 -21
- letta/schemas/blocks_agents.py +0 -32
- letta/schemas/tools_agents.py +0 -32
- letta/server/rest_api/routers/openai/assistants/threads.py +0 -338
- letta/services/agents_tags_manager.py +0 -64
- letta/services/blocks_agents_manager.py +0 -106
- letta/services/tools_agents_manager.py +0 -94
- {letta_nightly-0.6.4.dev20241213193437.dist-info → letta_nightly-0.6.4.dev20241215104129.dist-info}/LICENSE +0 -0
- {letta_nightly-0.6.4.dev20241213193437.dist-info → letta_nightly-0.6.4.dev20241215104129.dist-info}/WHEEL +0 -0
- {letta_nightly-0.6.4.dev20241213193437.dist-info → letta_nightly-0.6.4.dev20241215104129.dist-info}/entry_points.txt +0 -0
letta/metadata.py
DELETED
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
""" Metadata store for user/agent/data_source information"""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import secrets
|
|
5
|
-
from typing import List, Optional, Union
|
|
6
|
-
|
|
7
|
-
from sqlalchemy import JSON, Column, DateTime, Index, String, TypeDecorator
|
|
8
|
-
from sqlalchemy.sql import func
|
|
9
|
-
|
|
10
|
-
from letta.config import LettaConfig
|
|
11
|
-
from letta.orm.base import Base
|
|
12
|
-
from letta.schemas.agent import PersistedAgentState
|
|
13
|
-
from letta.schemas.api_key import APIKey
|
|
14
|
-
from letta.schemas.embedding_config import EmbeddingConfig
|
|
15
|
-
from letta.schemas.enums import ToolRuleType
|
|
16
|
-
from letta.schemas.llm_config import LLMConfig
|
|
17
|
-
from letta.schemas.tool_rule import ChildToolRule, InitToolRule, TerminalToolRule
|
|
18
|
-
from letta.schemas.user import User
|
|
19
|
-
from letta.services.per_agent_lock_manager import PerAgentLockManager
|
|
20
|
-
from letta.settings import settings
|
|
21
|
-
from letta.utils import enforce_types, printd
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class LLMConfigColumn(TypeDecorator):
|
|
25
|
-
"""Custom type for storing LLMConfig as JSON"""
|
|
26
|
-
|
|
27
|
-
impl = JSON
|
|
28
|
-
cache_ok = True
|
|
29
|
-
|
|
30
|
-
def load_dialect_impl(self, dialect):
|
|
31
|
-
return dialect.type_descriptor(JSON())
|
|
32
|
-
|
|
33
|
-
def process_bind_param(self, value, dialect):
|
|
34
|
-
if value:
|
|
35
|
-
# return vars(value)
|
|
36
|
-
if isinstance(value, LLMConfig):
|
|
37
|
-
return value.model_dump()
|
|
38
|
-
return value
|
|
39
|
-
|
|
40
|
-
def process_result_value(self, value, dialect):
|
|
41
|
-
if value:
|
|
42
|
-
return LLMConfig(**value)
|
|
43
|
-
return value
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class EmbeddingConfigColumn(TypeDecorator):
|
|
47
|
-
"""Custom type for storing EmbeddingConfig as JSON"""
|
|
48
|
-
|
|
49
|
-
impl = JSON
|
|
50
|
-
cache_ok = True
|
|
51
|
-
|
|
52
|
-
def load_dialect_impl(self, dialect):
|
|
53
|
-
return dialect.type_descriptor(JSON())
|
|
54
|
-
|
|
55
|
-
def process_bind_param(self, value, dialect):
|
|
56
|
-
if value:
|
|
57
|
-
# return vars(value)
|
|
58
|
-
if isinstance(value, EmbeddingConfig):
|
|
59
|
-
return value.model_dump()
|
|
60
|
-
return value
|
|
61
|
-
|
|
62
|
-
def process_result_value(self, value, dialect):
|
|
63
|
-
if value:
|
|
64
|
-
return EmbeddingConfig(**value)
|
|
65
|
-
return value
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# TODO: eventually store providers?
|
|
69
|
-
# class Provider(Base):
|
|
70
|
-
# __tablename__ = "providers"
|
|
71
|
-
# __table_args__ = {"extend_existing": True}
|
|
72
|
-
#
|
|
73
|
-
# id = Column(String, primary_key=True)
|
|
74
|
-
# name = Column(String, nullable=False)
|
|
75
|
-
# created_at = Column(DateTime(timezone=True))
|
|
76
|
-
# api_key = Column(String, nullable=False)
|
|
77
|
-
# base_url = Column(String, nullable=False)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
class APIKeyModel(Base):
|
|
81
|
-
"""Data model for authentication tokens. One-to-many relationship with UserModel (1 User - N tokens)."""
|
|
82
|
-
|
|
83
|
-
__tablename__ = "tokens"
|
|
84
|
-
|
|
85
|
-
id = Column(String, primary_key=True)
|
|
86
|
-
# each api key is tied to a user account (that it validates access for)
|
|
87
|
-
user_id = Column(String, nullable=False)
|
|
88
|
-
# the api key
|
|
89
|
-
key = Column(String, nullable=False)
|
|
90
|
-
# extra (optional) metadata
|
|
91
|
-
name = Column(String)
|
|
92
|
-
|
|
93
|
-
Index(__tablename__ + "_idx_user", user_id),
|
|
94
|
-
Index(__tablename__ + "_idx_key", key),
|
|
95
|
-
|
|
96
|
-
def __repr__(self) -> str:
|
|
97
|
-
return f"<APIKey(id='{self.id}', key='{self.key}', name='{self.name}')>"
|
|
98
|
-
|
|
99
|
-
def to_record(self) -> User:
|
|
100
|
-
return APIKey(
|
|
101
|
-
id=self.id,
|
|
102
|
-
user_id=self.user_id,
|
|
103
|
-
key=self.key,
|
|
104
|
-
name=self.name,
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def generate_api_key(prefix="sk-", length=51) -> str:
|
|
109
|
-
# Generate 'length // 2' bytes because each byte becomes two hex digits. Adjust length for prefix.
|
|
110
|
-
actual_length = max(length - len(prefix), 1) // 2 # Ensure at least 1 byte is generated
|
|
111
|
-
random_bytes = secrets.token_bytes(actual_length)
|
|
112
|
-
new_key = prefix + random_bytes.hex()
|
|
113
|
-
return new_key
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
class ToolRulesColumn(TypeDecorator):
|
|
117
|
-
"""Custom type for storing a list of ToolRules as JSON"""
|
|
118
|
-
|
|
119
|
-
impl = JSON
|
|
120
|
-
cache_ok = True
|
|
121
|
-
|
|
122
|
-
def load_dialect_impl(self, dialect):
|
|
123
|
-
return dialect.type_descriptor(JSON())
|
|
124
|
-
|
|
125
|
-
def process_bind_param(self, value, dialect):
|
|
126
|
-
"""Convert a list of ToolRules to JSON-serializable format."""
|
|
127
|
-
if value:
|
|
128
|
-
data = [rule.model_dump() for rule in value]
|
|
129
|
-
for d in data:
|
|
130
|
-
d["type"] = d["type"].value
|
|
131
|
-
|
|
132
|
-
for d in data:
|
|
133
|
-
assert not (d["type"] == "ToolRule" and "children" not in d), "ToolRule does not have children field"
|
|
134
|
-
return data
|
|
135
|
-
return value
|
|
136
|
-
|
|
137
|
-
def process_result_value(self, value, dialect) -> List[Union[ChildToolRule, InitToolRule, TerminalToolRule]]:
|
|
138
|
-
"""Convert JSON back to a list of ToolRules."""
|
|
139
|
-
if value:
|
|
140
|
-
return [self.deserialize_tool_rule(rule_data) for rule_data in value]
|
|
141
|
-
return value
|
|
142
|
-
|
|
143
|
-
@staticmethod
|
|
144
|
-
def deserialize_tool_rule(data: dict) -> Union[ChildToolRule, InitToolRule, TerminalToolRule]:
|
|
145
|
-
"""Deserialize a dictionary to the appropriate ToolRule subclass based on the 'type'."""
|
|
146
|
-
rule_type = ToolRuleType(data.get("type")) # Remove 'type' field if it exists since it is a class var
|
|
147
|
-
if rule_type == ToolRuleType.run_first:
|
|
148
|
-
return InitToolRule(**data)
|
|
149
|
-
elif rule_type == ToolRuleType.exit_loop:
|
|
150
|
-
return TerminalToolRule(**data)
|
|
151
|
-
elif rule_type == ToolRuleType.constrain_child_tools:
|
|
152
|
-
rule = ChildToolRule(**data)
|
|
153
|
-
return rule
|
|
154
|
-
else:
|
|
155
|
-
raise ValueError(f"Unknown tool rule type: {rule_type}")
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
class AgentModel(Base):
|
|
159
|
-
"""Defines data model for storing Passages (consisting of text, embedding)"""
|
|
160
|
-
|
|
161
|
-
__tablename__ = "agents"
|
|
162
|
-
__table_args__ = {"extend_existing": True}
|
|
163
|
-
|
|
164
|
-
id = Column(String, primary_key=True)
|
|
165
|
-
user_id = Column(String, nullable=False)
|
|
166
|
-
name = Column(String, nullable=False)
|
|
167
|
-
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
|
168
|
-
description = Column(String)
|
|
169
|
-
|
|
170
|
-
# state (context compilation)
|
|
171
|
-
message_ids = Column(JSON)
|
|
172
|
-
system = Column(String)
|
|
173
|
-
|
|
174
|
-
# configs
|
|
175
|
-
agent_type = Column(String)
|
|
176
|
-
llm_config = Column(LLMConfigColumn)
|
|
177
|
-
embedding_config = Column(EmbeddingConfigColumn)
|
|
178
|
-
|
|
179
|
-
# state
|
|
180
|
-
metadata_ = Column(JSON)
|
|
181
|
-
|
|
182
|
-
# tools
|
|
183
|
-
tool_names = Column(JSON)
|
|
184
|
-
tool_rules = Column(ToolRulesColumn)
|
|
185
|
-
|
|
186
|
-
Index(__tablename__ + "_idx_user", user_id),
|
|
187
|
-
|
|
188
|
-
def __repr__(self) -> str:
|
|
189
|
-
return f"<Agent(id='{self.id}', name='{self.name}')>"
|
|
190
|
-
|
|
191
|
-
def to_record(self) -> PersistedAgentState:
|
|
192
|
-
agent_state = PersistedAgentState(
|
|
193
|
-
id=self.id,
|
|
194
|
-
user_id=self.user_id,
|
|
195
|
-
name=self.name,
|
|
196
|
-
created_at=self.created_at,
|
|
197
|
-
description=self.description,
|
|
198
|
-
message_ids=self.message_ids,
|
|
199
|
-
system=self.system,
|
|
200
|
-
tool_names=self.tool_names,
|
|
201
|
-
tool_rules=self.tool_rules,
|
|
202
|
-
agent_type=self.agent_type,
|
|
203
|
-
llm_config=self.llm_config,
|
|
204
|
-
embedding_config=self.embedding_config,
|
|
205
|
-
metadata_=self.metadata_,
|
|
206
|
-
)
|
|
207
|
-
return agent_state
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
class AgentSourceMappingModel(Base):
|
|
211
|
-
"""Stores mapping between agent -> source"""
|
|
212
|
-
|
|
213
|
-
__tablename__ = "agent_source_mapping"
|
|
214
|
-
|
|
215
|
-
id = Column(String, primary_key=True)
|
|
216
|
-
user_id = Column(String, nullable=False)
|
|
217
|
-
agent_id = Column(String, nullable=False)
|
|
218
|
-
source_id = Column(String, nullable=False)
|
|
219
|
-
Index(__tablename__ + "_idx_user", user_id, agent_id, source_id),
|
|
220
|
-
|
|
221
|
-
def __repr__(self) -> str:
|
|
222
|
-
return f"<AgentSourceMapping(user_id='{self.user_id}', agent_id='{self.agent_id}', source_id='{self.source_id}')>"
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
class MetadataStore:
|
|
226
|
-
uri: Optional[str] = None
|
|
227
|
-
|
|
228
|
-
def __init__(self, config: LettaConfig):
|
|
229
|
-
# TODO: get DB URI or path
|
|
230
|
-
if config.metadata_storage_type == "postgres":
|
|
231
|
-
# construct URI from enviornment variables
|
|
232
|
-
self.uri = settings.pg_uri if settings.pg_uri else config.metadata_storage_uri
|
|
233
|
-
|
|
234
|
-
elif config.metadata_storage_type == "sqlite":
|
|
235
|
-
path = os.path.join(config.metadata_storage_path, "sqlite.db")
|
|
236
|
-
self.uri = f"sqlite:///{path}"
|
|
237
|
-
else:
|
|
238
|
-
raise ValueError(f"Invalid metadata storage type: {config.metadata_storage_type}")
|
|
239
|
-
|
|
240
|
-
# Ensure valid URI
|
|
241
|
-
assert self.uri, "Database URI is not provided or is invalid."
|
|
242
|
-
|
|
243
|
-
from letta.server.server import db_context
|
|
244
|
-
|
|
245
|
-
self.session_maker = db_context
|
|
246
|
-
|
|
247
|
-
@enforce_types
|
|
248
|
-
def create_api_key(self, user_id: str, name: str) -> APIKey:
|
|
249
|
-
"""Create an API key for a user"""
|
|
250
|
-
new_api_key = generate_api_key()
|
|
251
|
-
with self.session_maker() as session:
|
|
252
|
-
if session.query(APIKeyModel).filter(APIKeyModel.key == new_api_key).count() > 0:
|
|
253
|
-
# NOTE duplicate API keys / tokens should never happen, but if it does don't allow it
|
|
254
|
-
raise ValueError(f"Token {new_api_key} already exists")
|
|
255
|
-
# TODO store the API keys as hashed
|
|
256
|
-
assert user_id and name, "User ID and name must be provided"
|
|
257
|
-
token = APIKey(user_id=user_id, key=new_api_key, name=name)
|
|
258
|
-
session.add(APIKeyModel(**vars(token)))
|
|
259
|
-
session.commit()
|
|
260
|
-
return self.get_api_key(api_key=new_api_key)
|
|
261
|
-
|
|
262
|
-
@enforce_types
|
|
263
|
-
def delete_api_key(self, api_key: str):
|
|
264
|
-
"""Delete an API key from the database"""
|
|
265
|
-
with self.session_maker() as session:
|
|
266
|
-
session.query(APIKeyModel).filter(APIKeyModel.key == api_key).delete()
|
|
267
|
-
session.commit()
|
|
268
|
-
|
|
269
|
-
@enforce_types
|
|
270
|
-
def get_api_key(self, api_key: str) -> Optional[APIKey]:
|
|
271
|
-
with self.session_maker() as session:
|
|
272
|
-
results = session.query(APIKeyModel).filter(APIKeyModel.key == api_key).all()
|
|
273
|
-
if len(results) == 0:
|
|
274
|
-
return None
|
|
275
|
-
assert len(results) == 1, f"Expected 1 result, got {len(results)}" # should only be one result
|
|
276
|
-
return results[0].to_record()
|
|
277
|
-
|
|
278
|
-
@enforce_types
|
|
279
|
-
def get_all_api_keys_for_user(self, user_id: str) -> List[APIKey]:
|
|
280
|
-
with self.session_maker() as session:
|
|
281
|
-
results = session.query(APIKeyModel).filter(APIKeyModel.user_id == user_id).all()
|
|
282
|
-
tokens = [r.to_record() for r in results]
|
|
283
|
-
return tokens
|
|
284
|
-
|
|
285
|
-
@enforce_types
|
|
286
|
-
def create_agent(self, agent: PersistedAgentState):
|
|
287
|
-
# insert into agent table
|
|
288
|
-
# make sure agent.name does not already exist for user user_id
|
|
289
|
-
with self.session_maker() as session:
|
|
290
|
-
if session.query(AgentModel).filter(AgentModel.name == agent.name).filter(AgentModel.user_id == agent.user_id).count() > 0:
|
|
291
|
-
raise ValueError(f"Agent with name {agent.name} already exists")
|
|
292
|
-
fields = vars(agent)
|
|
293
|
-
# fields["memory"] = agent.memory.to_dict()
|
|
294
|
-
# if "_internal_memory" in fields:
|
|
295
|
-
# del fields["_internal_memory"]
|
|
296
|
-
# else:
|
|
297
|
-
# warnings.warn(f"Agent {agent.id} has no _internal_memory field")
|
|
298
|
-
if "tags" in fields:
|
|
299
|
-
del fields["tags"]
|
|
300
|
-
# else:
|
|
301
|
-
# warnings.warn(f"Agent {agent.id} has no tags field")
|
|
302
|
-
session.add(AgentModel(**fields))
|
|
303
|
-
session.commit()
|
|
304
|
-
|
|
305
|
-
@enforce_types
|
|
306
|
-
def update_agent(self, agent: PersistedAgentState):
|
|
307
|
-
with self.session_maker() as session:
|
|
308
|
-
fields = vars(agent)
|
|
309
|
-
# if isinstance(agent.memory, Memory): # TODO: this is nasty but this whole class will soon be removed so whatever
|
|
310
|
-
# fields["memory"] = agent.memory.to_dict()
|
|
311
|
-
# if "_internal_memory" in fields:
|
|
312
|
-
# del fields["_internal_memory"]
|
|
313
|
-
# else:
|
|
314
|
-
# warnings.warn(f"Agent {agent.id} has no _internal_memory field")
|
|
315
|
-
if "tags" in fields:
|
|
316
|
-
del fields["tags"]
|
|
317
|
-
# else:
|
|
318
|
-
# warnings.warn(f"Agent {agent.id} has no tags field")
|
|
319
|
-
session.query(AgentModel).filter(AgentModel.id == agent.id).update(fields)
|
|
320
|
-
session.commit()
|
|
321
|
-
|
|
322
|
-
@enforce_types
|
|
323
|
-
def delete_agent(self, agent_id: str, per_agent_lock_manager: PerAgentLockManager):
|
|
324
|
-
# TODO: Remove this once Agent is on the ORM
|
|
325
|
-
# TODO: To prevent unbounded growth
|
|
326
|
-
per_agent_lock_manager.clear_lock(agent_id)
|
|
327
|
-
|
|
328
|
-
with self.session_maker() as session:
|
|
329
|
-
|
|
330
|
-
# delete agents
|
|
331
|
-
session.query(AgentModel).filter(AgentModel.id == agent_id).delete()
|
|
332
|
-
|
|
333
|
-
# delete mappings
|
|
334
|
-
session.query(AgentSourceMappingModel).filter(AgentSourceMappingModel.agent_id == agent_id).delete()
|
|
335
|
-
|
|
336
|
-
session.commit()
|
|
337
|
-
|
|
338
|
-
@enforce_types
|
|
339
|
-
def list_agents(self, user_id: str) -> List[PersistedAgentState]:
|
|
340
|
-
with self.session_maker() as session:
|
|
341
|
-
results = session.query(AgentModel).filter(AgentModel.user_id == user_id).all()
|
|
342
|
-
return [r.to_record() for r in results]
|
|
343
|
-
|
|
344
|
-
@enforce_types
|
|
345
|
-
def get_agent(
|
|
346
|
-
self, agent_id: Optional[str] = None, agent_name: Optional[str] = None, user_id: Optional[str] = None
|
|
347
|
-
) -> Optional[PersistedAgentState]:
|
|
348
|
-
with self.session_maker() as session:
|
|
349
|
-
if agent_id:
|
|
350
|
-
results = session.query(AgentModel).filter(AgentModel.id == agent_id).all()
|
|
351
|
-
else:
|
|
352
|
-
assert agent_name is not None and user_id is not None, "Must provide either agent_id or agent_name"
|
|
353
|
-
results = session.query(AgentModel).filter(AgentModel.name == agent_name).filter(AgentModel.user_id == user_id).all()
|
|
354
|
-
|
|
355
|
-
if len(results) == 0:
|
|
356
|
-
return None
|
|
357
|
-
assert len(results) == 1, f"Expected 1 result, got {len(results)}" # should only be one result
|
|
358
|
-
return results[0].to_record()
|
|
359
|
-
|
|
360
|
-
# agent source metadata
|
|
361
|
-
@enforce_types
|
|
362
|
-
def attach_source(self, user_id: str, agent_id: str, source_id: str):
|
|
363
|
-
with self.session_maker() as session:
|
|
364
|
-
# TODO: remove this (is a hack)
|
|
365
|
-
mapping_id = f"{user_id}-{agent_id}-{source_id}"
|
|
366
|
-
existing = session.query(AgentSourceMappingModel).filter(
|
|
367
|
-
AgentSourceMappingModel.id == mapping_id
|
|
368
|
-
).first()
|
|
369
|
-
|
|
370
|
-
if existing is None:
|
|
371
|
-
# Only create if it doesn't exist
|
|
372
|
-
session.add(AgentSourceMappingModel(
|
|
373
|
-
id=mapping_id,
|
|
374
|
-
user_id=user_id,
|
|
375
|
-
agent_id=agent_id,
|
|
376
|
-
source_id=source_id
|
|
377
|
-
))
|
|
378
|
-
session.commit()
|
|
379
|
-
|
|
380
|
-
@enforce_types
|
|
381
|
-
def list_attached_source_ids(self, agent_id: str) -> List[str]:
|
|
382
|
-
with self.session_maker() as session:
|
|
383
|
-
results = session.query(AgentSourceMappingModel).filter(AgentSourceMappingModel.agent_id == agent_id).all()
|
|
384
|
-
return [r.source_id for r in results]
|
|
385
|
-
|
|
386
|
-
@enforce_types
|
|
387
|
-
def list_attached_agents(self, source_id: str) -> List[str]:
|
|
388
|
-
with self.session_maker() as session:
|
|
389
|
-
results = session.query(AgentSourceMappingModel).filter(AgentSourceMappingModel.source_id == source_id).all()
|
|
390
|
-
|
|
391
|
-
agent_ids = []
|
|
392
|
-
# make sure agent exists
|
|
393
|
-
for r in results:
|
|
394
|
-
agent = self.get_agent(agent_id=r.agent_id)
|
|
395
|
-
if agent:
|
|
396
|
-
agent_ids.append(r.agent_id)
|
|
397
|
-
else:
|
|
398
|
-
printd(f"Warning: agent {r.agent_id} does not exist but exists in mapping database. This should never happen.")
|
|
399
|
-
return agent_ids
|
|
400
|
-
|
|
401
|
-
@enforce_types
|
|
402
|
-
def detach_source(self, agent_id: str, source_id: str):
|
|
403
|
-
with self.session_maker() as session:
|
|
404
|
-
session.query(AgentSourceMappingModel).filter(
|
|
405
|
-
AgentSourceMappingModel.agent_id == agent_id, AgentSourceMappingModel.source_id == source_id
|
|
406
|
-
).delete()
|
|
407
|
-
session.commit()
|
letta/schemas/agents_tags.py
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from pydantic import Field
|
|
5
|
-
|
|
6
|
-
from letta.schemas.letta_base import LettaBase
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class AgentsTagsBase(LettaBase):
|
|
10
|
-
__id_prefix__ = "agents_tags"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class AgentsTags(AgentsTagsBase):
|
|
14
|
-
"""
|
|
15
|
-
Schema representing the relationship between tags and agents.
|
|
16
|
-
|
|
17
|
-
Parameters:
|
|
18
|
-
agent_id (str): The ID of the associated agent.
|
|
19
|
-
tag_id (str): The ID of the associated tag.
|
|
20
|
-
tag_name (str): The name of the tag.
|
|
21
|
-
created_at (datetime): The date this relationship was created.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
id: str = AgentsTagsBase.generate_id_field()
|
|
25
|
-
agent_id: str = Field(..., description="The ID of the associated agent.")
|
|
26
|
-
tag: str = Field(..., description="The name of the tag.")
|
|
27
|
-
created_at: Optional[datetime] = Field(None, description="The creation date of the association.")
|
|
28
|
-
updated_at: Optional[datetime] = Field(None, description="The update date of the tag.")
|
|
29
|
-
is_deleted: bool = Field(False, description="Whether this tag is deleted or not.")
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class AgentsTagsCreate(AgentsTagsBase):
|
|
33
|
-
tag: str = Field(..., description="The tag name.")
|
letta/schemas/api_key.py
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
|
-
from pydantic import Field
|
|
4
|
-
|
|
5
|
-
from letta.schemas.letta_base import LettaBase
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class BaseAPIKey(LettaBase):
|
|
9
|
-
__id_prefix__ = "sk" # secret key
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class APIKey(BaseAPIKey):
|
|
13
|
-
id: str = BaseAPIKey.generate_id_field()
|
|
14
|
-
user_id: str = Field(..., description="The unique identifier of the user associated with the token.")
|
|
15
|
-
key: str = Field(..., description="The key value.")
|
|
16
|
-
name: str = Field(..., description="Name of the token.")
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class APIKeyCreate(BaseAPIKey):
|
|
20
|
-
user_id: str = Field(..., description="The unique identifier of the user associated with the token.")
|
|
21
|
-
name: Optional[str] = Field(None, description="Name of the token.")
|
letta/schemas/blocks_agents.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from pydantic import Field
|
|
5
|
-
|
|
6
|
-
from letta.schemas.letta_base import LettaBase
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class BlocksAgentsBase(LettaBase):
|
|
10
|
-
__id_prefix__ = "blocks_agents"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class BlocksAgents(BlocksAgentsBase):
|
|
14
|
-
"""
|
|
15
|
-
Schema representing the relationship between blocks and agents.
|
|
16
|
-
|
|
17
|
-
Parameters:
|
|
18
|
-
agent_id (str): The ID of the associated agent.
|
|
19
|
-
block_id (str): The ID of the associated block.
|
|
20
|
-
block_label (str): The label of the block.
|
|
21
|
-
created_at (datetime): The date this relationship was created.
|
|
22
|
-
updated_at (datetime): The date this relationship was last updated.
|
|
23
|
-
is_deleted (bool): Whether this block-agent relationship is deleted or not.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
id: str = BlocksAgentsBase.generate_id_field()
|
|
27
|
-
agent_id: str = Field(..., description="The ID of the associated agent.")
|
|
28
|
-
block_id: str = Field(..., description="The ID of the associated block.")
|
|
29
|
-
block_label: str = Field(..., description="The label of the block.")
|
|
30
|
-
created_at: Optional[datetime] = Field(None, description="The creation date of the association.")
|
|
31
|
-
updated_at: Optional[datetime] = Field(None, description="The update date of the association.")
|
|
32
|
-
is_deleted: bool = Field(False, description="Whether this block-agent relationship is deleted or not.")
|
letta/schemas/tools_agents.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from pydantic import Field
|
|
5
|
-
|
|
6
|
-
from letta.schemas.letta_base import LettaBase
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class ToolsAgentsBase(LettaBase):
|
|
10
|
-
__id_prefix__ = "tools_agents"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ToolsAgents(ToolsAgentsBase):
|
|
14
|
-
"""
|
|
15
|
-
Schema representing the relationship between tools and agents.
|
|
16
|
-
|
|
17
|
-
Parameters:
|
|
18
|
-
agent_id (str): The ID of the associated agent.
|
|
19
|
-
tool_id (str): The ID of the associated tool.
|
|
20
|
-
tool_name (str): The name of the tool.
|
|
21
|
-
created_at (datetime): The date this relationship was created.
|
|
22
|
-
updated_at (datetime): The date this relationship was last updated.
|
|
23
|
-
is_deleted (bool): Whether this tool-agent relationship is deleted or not.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
id: str = ToolsAgentsBase.generate_id_field()
|
|
27
|
-
agent_id: str = Field(..., description="The ID of the associated agent.")
|
|
28
|
-
tool_id: str = Field(..., description="The ID of the associated tool.")
|
|
29
|
-
tool_name: str = Field(..., description="The name of the tool.")
|
|
30
|
-
created_at: Optional[datetime] = Field(None, description="The creation date of the association.")
|
|
31
|
-
updated_at: Optional[datetime] = Field(None, description="The update date of the association.")
|
|
32
|
-
is_deleted: bool = Field(False, description="Whether this tool-agent relationship is deleted or not.")
|