letta-nightly 0.11.7.dev20251007104119__py3-none-any.whl → 0.12.0.dev20251009104148__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.
- letta/__init__.py +1 -1
- letta/adapters/letta_llm_adapter.py +1 -0
- letta/adapters/letta_llm_request_adapter.py +0 -1
- letta/adapters/letta_llm_stream_adapter.py +7 -2
- letta/adapters/simple_llm_request_adapter.py +88 -0
- letta/adapters/simple_llm_stream_adapter.py +192 -0
- letta/agents/agent_loop.py +6 -0
- letta/agents/ephemeral_summary_agent.py +2 -1
- letta/agents/helpers.py +142 -6
- letta/agents/letta_agent.py +13 -33
- letta/agents/letta_agent_batch.py +2 -4
- letta/agents/letta_agent_v2.py +87 -77
- letta/agents/letta_agent_v3.py +927 -0
- letta/agents/voice_agent.py +2 -6
- letta/constants.py +8 -4
- letta/database_utils.py +161 -0
- letta/errors.py +40 -0
- letta/functions/function_sets/base.py +84 -4
- letta/functions/function_sets/multi_agent.py +0 -3
- letta/functions/schema_generator.py +113 -71
- letta/groups/dynamic_multi_agent.py +3 -2
- letta/groups/helpers.py +1 -2
- letta/groups/round_robin_multi_agent.py +3 -2
- letta/groups/sleeptime_multi_agent.py +3 -2
- letta/groups/sleeptime_multi_agent_v2.py +1 -1
- letta/groups/sleeptime_multi_agent_v3.py +17 -17
- letta/groups/supervisor_multi_agent.py +84 -80
- letta/helpers/converters.py +3 -0
- letta/helpers/message_helper.py +4 -0
- letta/helpers/tool_rule_solver.py +92 -5
- letta/interfaces/anthropic_streaming_interface.py +409 -0
- letta/interfaces/gemini_streaming_interface.py +296 -0
- letta/interfaces/openai_streaming_interface.py +752 -1
- letta/llm_api/anthropic_client.py +127 -16
- letta/llm_api/bedrock_client.py +4 -2
- letta/llm_api/deepseek_client.py +4 -1
- letta/llm_api/google_vertex_client.py +124 -42
- letta/llm_api/groq_client.py +4 -1
- letta/llm_api/llm_api_tools.py +11 -4
- letta/llm_api/llm_client_base.py +6 -2
- letta/llm_api/openai.py +32 -2
- letta/llm_api/openai_client.py +423 -18
- letta/llm_api/xai_client.py +4 -1
- letta/main.py +9 -5
- letta/memory.py +1 -0
- letta/orm/__init__.py +2 -1
- letta/orm/agent.py +10 -0
- letta/orm/block.py +7 -16
- letta/orm/blocks_agents.py +8 -2
- letta/orm/files_agents.py +2 -0
- letta/orm/job.py +7 -5
- letta/orm/mcp_oauth.py +1 -0
- letta/orm/message.py +21 -6
- letta/orm/organization.py +2 -0
- letta/orm/provider.py +6 -2
- letta/orm/run.py +71 -0
- letta/orm/run_metrics.py +82 -0
- letta/orm/sandbox_config.py +7 -1
- letta/orm/sqlalchemy_base.py +0 -306
- letta/orm/step.py +6 -5
- letta/orm/step_metrics.py +5 -5
- letta/otel/tracing.py +28 -3
- letta/plugins/defaults.py +4 -4
- letta/prompts/system_prompts/__init__.py +2 -0
- letta/prompts/system_prompts/letta_v1.py +25 -0
- letta/schemas/agent.py +3 -2
- letta/schemas/agent_file.py +9 -3
- letta/schemas/block.py +23 -10
- letta/schemas/enums.py +21 -2
- letta/schemas/job.py +17 -4
- letta/schemas/letta_message_content.py +71 -2
- letta/schemas/letta_stop_reason.py +5 -5
- letta/schemas/llm_config.py +53 -3
- letta/schemas/memory.py +1 -1
- letta/schemas/message.py +564 -117
- letta/schemas/openai/responses_request.py +64 -0
- letta/schemas/providers/__init__.py +2 -0
- letta/schemas/providers/anthropic.py +16 -0
- letta/schemas/providers/ollama.py +115 -33
- letta/schemas/providers/openrouter.py +52 -0
- letta/schemas/providers/vllm.py +2 -1
- letta/schemas/run.py +48 -42
- letta/schemas/run_metrics.py +21 -0
- letta/schemas/step.py +2 -2
- letta/schemas/step_metrics.py +1 -1
- letta/schemas/tool.py +15 -107
- letta/schemas/tool_rule.py +88 -5
- letta/serialize_schemas/marshmallow_agent.py +1 -0
- letta/server/db.py +79 -408
- letta/server/rest_api/app.py +61 -10
- letta/server/rest_api/dependencies.py +14 -0
- letta/server/rest_api/redis_stream_manager.py +19 -8
- letta/server/rest_api/routers/v1/agents.py +364 -292
- letta/server/rest_api/routers/v1/blocks.py +14 -20
- letta/server/rest_api/routers/v1/identities.py +45 -110
- letta/server/rest_api/routers/v1/internal_templates.py +21 -0
- letta/server/rest_api/routers/v1/jobs.py +23 -6
- letta/server/rest_api/routers/v1/messages.py +1 -1
- letta/server/rest_api/routers/v1/runs.py +149 -99
- letta/server/rest_api/routers/v1/sandbox_configs.py +10 -19
- letta/server/rest_api/routers/v1/tools.py +281 -594
- letta/server/rest_api/routers/v1/voice.py +1 -1
- letta/server/rest_api/streaming_response.py +29 -29
- letta/server/rest_api/utils.py +122 -64
- letta/server/server.py +160 -887
- letta/services/agent_manager.py +236 -919
- letta/services/agent_serialization_manager.py +16 -0
- letta/services/archive_manager.py +0 -100
- letta/services/block_manager.py +211 -168
- letta/services/context_window_calculator/token_counter.py +1 -1
- letta/services/file_manager.py +1 -1
- letta/services/files_agents_manager.py +24 -33
- letta/services/group_manager.py +0 -142
- letta/services/helpers/agent_manager_helper.py +7 -2
- letta/services/helpers/run_manager_helper.py +69 -0
- letta/services/job_manager.py +96 -411
- letta/services/lettuce/__init__.py +6 -0
- letta/services/lettuce/lettuce_client_base.py +86 -0
- letta/services/mcp_manager.py +38 -6
- letta/services/message_manager.py +165 -362
- letta/services/organization_manager.py +0 -36
- letta/services/passage_manager.py +0 -345
- letta/services/provider_manager.py +0 -80
- letta/services/run_manager.py +364 -0
- letta/services/sandbox_config_manager.py +0 -234
- letta/services/step_manager.py +62 -39
- letta/services/summarizer/summarizer.py +9 -7
- letta/services/telemetry_manager.py +0 -16
- letta/services/tool_executor/builtin_tool_executor.py +35 -0
- letta/services/tool_executor/core_tool_executor.py +397 -2
- letta/services/tool_executor/files_tool_executor.py +3 -3
- letta/services/tool_executor/multi_agent_tool_executor.py +30 -15
- letta/services/tool_executor/tool_execution_manager.py +6 -8
- letta/services/tool_executor/tool_executor_base.py +3 -3
- letta/services/tool_manager.py +85 -339
- letta/services/tool_sandbox/base.py +24 -13
- letta/services/tool_sandbox/e2b_sandbox.py +16 -1
- letta/services/tool_schema_generator.py +123 -0
- letta/services/user_manager.py +0 -99
- letta/settings.py +20 -4
- letta/system.py +5 -1
- {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.12.0.dev20251009104148.dist-info}/METADATA +3 -5
- {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.12.0.dev20251009104148.dist-info}/RECORD +146 -135
- letta/agents/temporal/activities/__init__.py +0 -4
- letta/agents/temporal/activities/example_activity.py +0 -7
- letta/agents/temporal/activities/prepare_messages.py +0 -10
- letta/agents/temporal/temporal_agent_workflow.py +0 -56
- letta/agents/temporal/types.py +0 -25
- {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.12.0.dev20251009104148.dist-info}/WHEEL +0 -0
- {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.12.0.dev20251009104148.dist-info}/entry_points.txt +0 -0
- {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.12.0.dev20251009104148.dist-info}/licenses/LICENSE +0 -0
@@ -18,14 +18,6 @@ class OrganizationManager:
|
|
18
18
|
"""Fetch the default organization."""
|
19
19
|
return await self.get_organization_by_id_async(DEFAULT_ORG_ID)
|
20
20
|
|
21
|
-
@enforce_types
|
22
|
-
@trace_method
|
23
|
-
def get_organization_by_id(self, org_id: str) -> Optional[PydanticOrganization]:
|
24
|
-
"""Fetch an organization by ID."""
|
25
|
-
with db_registry.session() as session:
|
26
|
-
organization = OrganizationModel.read(db_session=session, identifier=org_id)
|
27
|
-
return organization.to_pydantic()
|
28
|
-
|
29
21
|
@enforce_types
|
30
22
|
@trace_method
|
31
23
|
async def get_organization_by_id_async(self, org_id: str) -> Optional[PydanticOrganization]:
|
@@ -34,19 +26,6 @@ class OrganizationManager:
|
|
34
26
|
organization = await OrganizationModel.read_async(db_session=session, identifier=org_id)
|
35
27
|
return organization.to_pydantic()
|
36
28
|
|
37
|
-
@enforce_types
|
38
|
-
@trace_method
|
39
|
-
def create_organization(self, pydantic_org: PydanticOrganization) -> PydanticOrganization:
|
40
|
-
"""Create the default organization."""
|
41
|
-
with db_registry.session() as session:
|
42
|
-
try:
|
43
|
-
organization = OrganizationModel.read(db_session=session, identifier=pydantic_org.id)
|
44
|
-
return organization.to_pydantic()
|
45
|
-
except:
|
46
|
-
organization = OrganizationModel(**pydantic_org.model_dump(to_orm=True))
|
47
|
-
organization = organization.create(session)
|
48
|
-
return organization.to_pydantic()
|
49
|
-
|
50
29
|
@enforce_types
|
51
30
|
@trace_method
|
52
31
|
async def create_organization_async(self, pydantic_org: PydanticOrganization) -> PydanticOrganization:
|
@@ -65,13 +44,6 @@ class OrganizationManager:
|
|
65
44
|
await org.create_async(session)
|
66
45
|
return org.to_pydantic()
|
67
46
|
|
68
|
-
@enforce_types
|
69
|
-
@trace_method
|
70
|
-
def create_default_organization(self) -> PydanticOrganization:
|
71
|
-
"""Create the default organization."""
|
72
|
-
pydantic_org = PydanticOrganization(name=DEFAULT_ORG_NAME, id=DEFAULT_ORG_ID)
|
73
|
-
return self.create_organization(pydantic_org)
|
74
|
-
|
75
47
|
@enforce_types
|
76
48
|
@trace_method
|
77
49
|
async def create_default_organization_async(self) -> PydanticOrganization:
|
@@ -102,14 +74,6 @@ class OrganizationManager:
|
|
102
74
|
await org.update_async(session)
|
103
75
|
return org.to_pydantic()
|
104
76
|
|
105
|
-
@enforce_types
|
106
|
-
@trace_method
|
107
|
-
def delete_organization_by_id(self, org_id: str):
|
108
|
-
"""Delete an organization by marking it as deleted."""
|
109
|
-
with db_registry.session() as session:
|
110
|
-
organization = OrganizationModel.read(db_session=session, identifier=org_id)
|
111
|
-
organization.hard_delete(session)
|
112
|
-
|
113
77
|
@enforce_types
|
114
78
|
@trace_method
|
115
79
|
async def delete_organization_by_id_async(self, org_id: str):
|
@@ -93,17 +93,6 @@ class PassageManager:
|
|
93
93
|
return created_tags
|
94
94
|
|
95
95
|
# AGENT PASSAGE METHODS
|
96
|
-
@enforce_types
|
97
|
-
@trace_method
|
98
|
-
def get_agent_passage_by_id(self, passage_id: str, actor: PydanticUser) -> Optional[PydanticPassage]:
|
99
|
-
"""Fetch an agent passage by ID."""
|
100
|
-
with db_registry.session() as session:
|
101
|
-
try:
|
102
|
-
passage = ArchivalPassage.read(db_session=session, identifier=passage_id, actor=actor)
|
103
|
-
return passage.to_pydantic()
|
104
|
-
except NoResultFound:
|
105
|
-
raise NoResultFound(f"Agent passage with id {passage_id} not found in database.")
|
106
|
-
|
107
96
|
@enforce_types
|
108
97
|
@trace_method
|
109
98
|
async def get_agent_passage_by_id_async(self, passage_id: str, actor: PydanticUser) -> Optional[PydanticPassage]:
|
@@ -116,17 +105,6 @@ class PassageManager:
|
|
116
105
|
raise NoResultFound(f"Agent passage with id {passage_id} not found in database.")
|
117
106
|
|
118
107
|
# SOURCE PASSAGE METHODS
|
119
|
-
@enforce_types
|
120
|
-
@trace_method
|
121
|
-
def get_source_passage_by_id(self, passage_id: str, actor: PydanticUser) -> Optional[PydanticPassage]:
|
122
|
-
"""Fetch a source passage by ID."""
|
123
|
-
with db_registry.session() as session:
|
124
|
-
try:
|
125
|
-
passage = SourcePassage.read(db_session=session, identifier=passage_id, actor=actor)
|
126
|
-
return passage.to_pydantic()
|
127
|
-
except NoResultFound:
|
128
|
-
raise NoResultFound(f"Source passage with id {passage_id} not found in database.")
|
129
|
-
|
130
108
|
@enforce_types
|
131
109
|
@trace_method
|
132
110
|
async def get_source_passage_by_id_async(self, passage_id: str, actor: PydanticUser) -> Optional[PydanticPassage]:
|
@@ -138,32 +116,6 @@ class PassageManager:
|
|
138
116
|
except NoResultFound:
|
139
117
|
raise NoResultFound(f"Source passage with id {passage_id} not found in database.")
|
140
118
|
|
141
|
-
# DEPRECATED - Use specific methods above
|
142
|
-
@enforce_types
|
143
|
-
@trace_method
|
144
|
-
def get_passage_by_id(self, passage_id: str, actor: PydanticUser) -> Optional[PydanticPassage]:
|
145
|
-
"""DEPRECATED: Use get_agent_passage_by_id() or get_source_passage_by_id() instead."""
|
146
|
-
import warnings
|
147
|
-
|
148
|
-
warnings.warn(
|
149
|
-
"get_passage_by_id is deprecated. Use get_agent_passage_by_id() or get_source_passage_by_id() instead.",
|
150
|
-
DeprecationWarning,
|
151
|
-
stacklevel=2,
|
152
|
-
)
|
153
|
-
|
154
|
-
with db_registry.session() as session:
|
155
|
-
# Try source passages first
|
156
|
-
try:
|
157
|
-
passage = SourcePassage.read(db_session=session, identifier=passage_id, actor=actor)
|
158
|
-
return passage.to_pydantic()
|
159
|
-
except NoResultFound:
|
160
|
-
# Try archival passages
|
161
|
-
try:
|
162
|
-
passage = ArchivalPassage.read(db_session=session, identifier=passage_id, actor=actor)
|
163
|
-
return passage.to_pydantic()
|
164
|
-
except NoResultFound:
|
165
|
-
raise NoResultFound(f"Passage with id {passage_id} not found in database.")
|
166
|
-
|
167
119
|
@enforce_types
|
168
120
|
@trace_method
|
169
121
|
async def get_passage_by_id_async(self, passage_id: str, actor: PydanticUser) -> Optional[PydanticPassage]:
|
@@ -189,40 +141,6 @@ class PassageManager:
|
|
189
141
|
except NoResultFound:
|
190
142
|
raise NoResultFound(f"Passage with id {passage_id} not found in database.")
|
191
143
|
|
192
|
-
@enforce_types
|
193
|
-
@trace_method
|
194
|
-
def create_agent_passage(self, pydantic_passage: PydanticPassage, actor: PydanticUser) -> PydanticPassage:
|
195
|
-
"""Create a new agent passage."""
|
196
|
-
if not pydantic_passage.archive_id:
|
197
|
-
raise ValueError("Agent passage must have archive_id")
|
198
|
-
if pydantic_passage.source_id:
|
199
|
-
raise ValueError("Agent passage cannot have source_id")
|
200
|
-
|
201
|
-
data = pydantic_passage.model_dump(to_orm=True)
|
202
|
-
|
203
|
-
# Deduplicate tags if provided (for dual storage consistency)
|
204
|
-
tags = data.get("tags")
|
205
|
-
if tags:
|
206
|
-
tags = list(set(tags))
|
207
|
-
|
208
|
-
common_fields = {
|
209
|
-
"id": data.get("id"),
|
210
|
-
"text": data["text"],
|
211
|
-
"embedding": data["embedding"],
|
212
|
-
"embedding_config": data["embedding_config"],
|
213
|
-
"organization_id": data["organization_id"],
|
214
|
-
"metadata_": data.get("metadata", {}),
|
215
|
-
"tags": tags,
|
216
|
-
"is_deleted": data.get("is_deleted", False),
|
217
|
-
"created_at": data.get("created_at", datetime.now(timezone.utc)),
|
218
|
-
}
|
219
|
-
agent_fields = {"archive_id": data["archive_id"]}
|
220
|
-
passage = ArchivalPassage(**common_fields, **agent_fields)
|
221
|
-
|
222
|
-
with db_registry.session() as session:
|
223
|
-
passage.create(session, actor=actor)
|
224
|
-
return passage.to_pydantic()
|
225
|
-
|
226
144
|
@enforce_types
|
227
145
|
@trace_method
|
228
146
|
async def create_agent_passage_async(self, pydantic_passage: PydanticPassage, actor: PydanticUser) -> PydanticPassage:
|
@@ -269,46 +187,6 @@ class PassageManager:
|
|
269
187
|
|
270
188
|
return passage.to_pydantic()
|
271
189
|
|
272
|
-
@enforce_types
|
273
|
-
@trace_method
|
274
|
-
def create_source_passage(
|
275
|
-
self, pydantic_passage: PydanticPassage, file_metadata: PydanticFileMetadata, actor: PydanticUser
|
276
|
-
) -> PydanticPassage:
|
277
|
-
"""Create a new source passage."""
|
278
|
-
if not pydantic_passage.source_id:
|
279
|
-
raise ValueError("Source passage must have source_id")
|
280
|
-
if pydantic_passage.archive_id:
|
281
|
-
raise ValueError("Source passage cannot have archive_id")
|
282
|
-
|
283
|
-
data = pydantic_passage.model_dump(to_orm=True)
|
284
|
-
|
285
|
-
# Deduplicate tags if provided (for dual storage consistency)
|
286
|
-
tags = data.get("tags")
|
287
|
-
if tags:
|
288
|
-
tags = list(set(tags))
|
289
|
-
|
290
|
-
common_fields = {
|
291
|
-
"id": data.get("id"),
|
292
|
-
"text": data["text"],
|
293
|
-
"embedding": data["embedding"],
|
294
|
-
"embedding_config": data["embedding_config"],
|
295
|
-
"organization_id": data["organization_id"],
|
296
|
-
"metadata_": data.get("metadata", {}),
|
297
|
-
"tags": tags,
|
298
|
-
"is_deleted": data.get("is_deleted", False),
|
299
|
-
"created_at": data.get("created_at", datetime.now(timezone.utc)),
|
300
|
-
}
|
301
|
-
source_fields = {
|
302
|
-
"source_id": data["source_id"],
|
303
|
-
"file_id": data.get("file_id"),
|
304
|
-
"file_name": file_metadata.file_name,
|
305
|
-
}
|
306
|
-
passage = SourcePassage(**common_fields, **source_fields)
|
307
|
-
|
308
|
-
with db_registry.session() as session:
|
309
|
-
passage.create(session, actor=actor)
|
310
|
-
return passage.to_pydantic()
|
311
|
-
|
312
190
|
@enforce_types
|
313
191
|
@trace_method
|
314
192
|
async def create_source_passage_async(
|
@@ -349,23 +227,6 @@ class PassageManager:
|
|
349
227
|
passage = await passage.create_async(session, actor=actor)
|
350
228
|
return passage.to_pydantic()
|
351
229
|
|
352
|
-
# DEPRECATED - Use specific methods above
|
353
|
-
@enforce_types
|
354
|
-
@trace_method
|
355
|
-
def create_passage(self, pydantic_passage: PydanticPassage, actor: PydanticUser) -> PydanticPassage:
|
356
|
-
"""DEPRECATED: Use create_agent_passage() or create_source_passage() instead."""
|
357
|
-
import warnings
|
358
|
-
|
359
|
-
warnings.warn(
|
360
|
-
"create_passage is deprecated. Use create_agent_passage() or create_source_passage() instead.", DeprecationWarning, stacklevel=2
|
361
|
-
)
|
362
|
-
|
363
|
-
passage = self._preprocess_passage_for_creation(pydantic_passage=pydantic_passage)
|
364
|
-
|
365
|
-
with db_registry.session() as session:
|
366
|
-
passage.create(session, actor=actor)
|
367
|
-
return passage.to_pydantic()
|
368
|
-
|
369
230
|
@enforce_types
|
370
231
|
@trace_method
|
371
232
|
async def create_passage_async(self, pydantic_passage: PydanticPassage, actor: PydanticUser) -> PydanticPassage:
|
@@ -654,34 +515,6 @@ class PassageManager:
|
|
654
515
|
embeddings = await embedding_client.request_embeddings(text_chunks, embedding_config)
|
655
516
|
return embeddings
|
656
517
|
|
657
|
-
@enforce_types
|
658
|
-
@trace_method
|
659
|
-
def update_agent_passage_by_id(
|
660
|
-
self, passage_id: str, passage: PydanticPassage, actor: PydanticUser, **kwargs
|
661
|
-
) -> Optional[PydanticPassage]:
|
662
|
-
"""Update an agent passage."""
|
663
|
-
if not passage_id:
|
664
|
-
raise ValueError("Passage ID must be provided.")
|
665
|
-
|
666
|
-
with db_registry.session() as session:
|
667
|
-
try:
|
668
|
-
curr_passage = ArchivalPassage.read(
|
669
|
-
db_session=session,
|
670
|
-
identifier=passage_id,
|
671
|
-
actor=actor,
|
672
|
-
)
|
673
|
-
except NoResultFound:
|
674
|
-
raise ValueError(f"Agent passage with id {passage_id} does not exist.")
|
675
|
-
|
676
|
-
# Update the database record with values from the provided record
|
677
|
-
update_data = passage.model_dump(to_orm=True, exclude_unset=True, exclude_none=True)
|
678
|
-
for key, value in update_data.items():
|
679
|
-
setattr(curr_passage, key, value)
|
680
|
-
|
681
|
-
# Commit changes
|
682
|
-
curr_passage.update(session, actor=actor)
|
683
|
-
return curr_passage.to_pydantic()
|
684
|
-
|
685
518
|
@enforce_types
|
686
519
|
@trace_method
|
687
520
|
async def update_agent_passage_by_id_async(
|
@@ -738,34 +571,6 @@ class PassageManager:
|
|
738
571
|
await curr_passage.update_async(session, actor=actor)
|
739
572
|
return curr_passage.to_pydantic()
|
740
573
|
|
741
|
-
@enforce_types
|
742
|
-
@trace_method
|
743
|
-
def update_source_passage_by_id(
|
744
|
-
self, passage_id: str, passage: PydanticPassage, actor: PydanticUser, **kwargs
|
745
|
-
) -> Optional[PydanticPassage]:
|
746
|
-
"""Update a source passage."""
|
747
|
-
if not passage_id:
|
748
|
-
raise ValueError("Passage ID must be provided.")
|
749
|
-
|
750
|
-
with db_registry.session() as session:
|
751
|
-
try:
|
752
|
-
curr_passage = SourcePassage.read(
|
753
|
-
db_session=session,
|
754
|
-
identifier=passage_id,
|
755
|
-
actor=actor,
|
756
|
-
)
|
757
|
-
except NoResultFound:
|
758
|
-
raise ValueError(f"Source passage with id {passage_id} does not exist.")
|
759
|
-
|
760
|
-
# Update the database record with values from the provided record
|
761
|
-
update_data = passage.model_dump(to_orm=True, exclude_unset=True, exclude_none=True)
|
762
|
-
for key, value in update_data.items():
|
763
|
-
setattr(curr_passage, key, value)
|
764
|
-
|
765
|
-
# Commit changes
|
766
|
-
curr_passage.update(session, actor=actor)
|
767
|
-
return curr_passage.to_pydantic()
|
768
|
-
|
769
574
|
@enforce_types
|
770
575
|
@trace_method
|
771
576
|
async def update_source_passage_by_id_async(
|
@@ -794,21 +599,6 @@ class PassageManager:
|
|
794
599
|
await curr_passage.update_async(session, actor=actor)
|
795
600
|
return curr_passage.to_pydantic()
|
796
601
|
|
797
|
-
@enforce_types
|
798
|
-
@trace_method
|
799
|
-
def delete_agent_passage_by_id(self, passage_id: str, actor: PydanticUser) -> bool:
|
800
|
-
"""Delete an agent passage."""
|
801
|
-
if not passage_id:
|
802
|
-
raise ValueError("Passage ID must be provided.")
|
803
|
-
|
804
|
-
with db_registry.session() as session:
|
805
|
-
try:
|
806
|
-
passage = ArchivalPassage.read(db_session=session, identifier=passage_id, actor=actor)
|
807
|
-
passage.hard_delete(session, actor=actor)
|
808
|
-
return True
|
809
|
-
except NoResultFound:
|
810
|
-
raise NoResultFound(f"Agent passage with id {passage_id} not found.")
|
811
|
-
|
812
602
|
@enforce_types
|
813
603
|
@trace_method
|
814
604
|
async def delete_agent_passage_by_id_async(self, passage_id: str, actor: PydanticUser, strict_mode: bool = False) -> bool:
|
@@ -842,21 +632,6 @@ class PassageManager:
|
|
842
632
|
except NoResultFound:
|
843
633
|
raise NoResultFound(f"Agent passage with id {passage_id} not found.")
|
844
634
|
|
845
|
-
@enforce_types
|
846
|
-
@trace_method
|
847
|
-
def delete_source_passage_by_id(self, passage_id: str, actor: PydanticUser) -> bool:
|
848
|
-
"""Delete a source passage."""
|
849
|
-
if not passage_id:
|
850
|
-
raise ValueError("Passage ID must be provided.")
|
851
|
-
|
852
|
-
with db_registry.session() as session:
|
853
|
-
try:
|
854
|
-
passage = SourcePassage.read(db_session=session, identifier=passage_id, actor=actor)
|
855
|
-
passage.hard_delete(session, actor=actor)
|
856
|
-
return True
|
857
|
-
except NoResultFound:
|
858
|
-
raise NoResultFound(f"Source passage with id {passage_id} not found.")
|
859
|
-
|
860
635
|
@enforce_types
|
861
636
|
@trace_method
|
862
637
|
async def delete_source_passage_by_id_async(self, passage_id: str, actor: PydanticUser) -> bool:
|
@@ -872,80 +647,6 @@ class PassageManager:
|
|
872
647
|
except NoResultFound:
|
873
648
|
raise NoResultFound(f"Source passage with id {passage_id} not found.")
|
874
649
|
|
875
|
-
# DEPRECATED - Use specific methods above
|
876
|
-
@enforce_types
|
877
|
-
@trace_method
|
878
|
-
def update_passage_by_id(self, passage_id: str, passage: PydanticPassage, actor: PydanticUser, **kwargs) -> Optional[PydanticPassage]:
|
879
|
-
"""DEPRECATED: Use update_agent_passage_by_id() or update_source_passage_by_id() instead."""
|
880
|
-
import warnings
|
881
|
-
|
882
|
-
warnings.warn(
|
883
|
-
"update_passage_by_id is deprecated. Use update_agent_passage_by_id() or update_source_passage_by_id() instead.",
|
884
|
-
DeprecationWarning,
|
885
|
-
stacklevel=2,
|
886
|
-
)
|
887
|
-
|
888
|
-
if not passage_id:
|
889
|
-
raise ValueError("Passage ID must be provided.")
|
890
|
-
|
891
|
-
with db_registry.session() as session:
|
892
|
-
# Try source passages first
|
893
|
-
try:
|
894
|
-
curr_passage = SourcePassage.read(
|
895
|
-
db_session=session,
|
896
|
-
identifier=passage_id,
|
897
|
-
actor=actor,
|
898
|
-
)
|
899
|
-
except NoResultFound:
|
900
|
-
# Try agent passages
|
901
|
-
try:
|
902
|
-
curr_passage = ArchivalPassage.read(
|
903
|
-
db_session=session,
|
904
|
-
identifier=passage_id,
|
905
|
-
actor=actor,
|
906
|
-
)
|
907
|
-
except NoResultFound:
|
908
|
-
raise ValueError(f"Passage with id {passage_id} does not exist.")
|
909
|
-
|
910
|
-
# Update the database record with values from the provided record
|
911
|
-
update_data = passage.model_dump(to_orm=True, exclude_unset=True, exclude_none=True)
|
912
|
-
for key, value in update_data.items():
|
913
|
-
setattr(curr_passage, key, value)
|
914
|
-
|
915
|
-
# Commit changes
|
916
|
-
curr_passage.update(session, actor=actor)
|
917
|
-
return curr_passage.to_pydantic()
|
918
|
-
|
919
|
-
@enforce_types
|
920
|
-
@trace_method
|
921
|
-
def delete_passage_by_id(self, passage_id: str, actor: PydanticUser) -> bool:
|
922
|
-
"""DEPRECATED: Use delete_agent_passage_by_id() or delete_source_passage_by_id() instead."""
|
923
|
-
import warnings
|
924
|
-
|
925
|
-
warnings.warn(
|
926
|
-
"delete_passage_by_id is deprecated. Use delete_agent_passage_by_id() or delete_source_passage_by_id() instead.",
|
927
|
-
DeprecationWarning,
|
928
|
-
stacklevel=2,
|
929
|
-
)
|
930
|
-
|
931
|
-
if not passage_id:
|
932
|
-
raise ValueError("Passage ID must be provided.")
|
933
|
-
|
934
|
-
with db_registry.session() as session:
|
935
|
-
# Try source passages first
|
936
|
-
try:
|
937
|
-
passage = SourcePassage.read(db_session=session, identifier=passage_id, actor=actor)
|
938
|
-
passage.hard_delete(session, actor=actor)
|
939
|
-
return True
|
940
|
-
except NoResultFound:
|
941
|
-
# Try archival passages
|
942
|
-
try:
|
943
|
-
passage = ArchivalPassage.read(db_session=session, identifier=passage_id, actor=actor)
|
944
|
-
passage.hard_delete(session, actor=actor)
|
945
|
-
return True
|
946
|
-
except NoResultFound:
|
947
|
-
raise NoResultFound(f"Passage with id {passage_id} not found.")
|
948
|
-
|
949
650
|
@enforce_types
|
950
651
|
@trace_method
|
951
652
|
async def delete_passage_by_id_async(self, passage_id: str, actor: PydanticUser) -> bool:
|
@@ -1077,36 +778,6 @@ class PassageManager:
|
|
1077
778
|
self.delete_passage_by_id(passage_id=passage.id, actor=actor)
|
1078
779
|
return True
|
1079
780
|
|
1080
|
-
@enforce_types
|
1081
|
-
@trace_method
|
1082
|
-
def agent_passage_size(
|
1083
|
-
self,
|
1084
|
-
actor: PydanticUser,
|
1085
|
-
agent_id: Optional[str] = None,
|
1086
|
-
) -> int:
|
1087
|
-
"""Get the total count of agent passages with optional filters.
|
1088
|
-
|
1089
|
-
Args:
|
1090
|
-
actor: The user requesting the count
|
1091
|
-
agent_id: The agent ID of the messages
|
1092
|
-
"""
|
1093
|
-
with db_registry.session() as session:
|
1094
|
-
if agent_id:
|
1095
|
-
# Count passages through the archives relationship
|
1096
|
-
return (
|
1097
|
-
session.query(ArchivalPassage)
|
1098
|
-
.join(ArchivesAgents, ArchivalPassage.archive_id == ArchivesAgents.archive_id)
|
1099
|
-
.filter(
|
1100
|
-
ArchivesAgents.agent_id == agent_id,
|
1101
|
-
ArchivalPassage.organization_id == actor.organization_id,
|
1102
|
-
ArchivalPassage.is_deleted == False,
|
1103
|
-
)
|
1104
|
-
.count()
|
1105
|
-
)
|
1106
|
-
else:
|
1107
|
-
# Count all archival passages in the organization
|
1108
|
-
return ArchivalPassage.size(db_session=session, actor=actor)
|
1109
|
-
|
1110
781
|
# DEPRECATED - Use agent_passage_size() instead since this only counted agent passages anyway
|
1111
782
|
@enforce_types
|
1112
783
|
@trace_method
|
@@ -1152,22 +823,6 @@ class PassageManager:
|
|
1152
823
|
# Count all archival passages in the organization
|
1153
824
|
return await ArchivalPassage.size_async(db_session=session, actor=actor)
|
1154
825
|
|
1155
|
-
@enforce_types
|
1156
|
-
@trace_method
|
1157
|
-
def source_passage_size(
|
1158
|
-
self,
|
1159
|
-
actor: PydanticUser,
|
1160
|
-
source_id: Optional[str] = None,
|
1161
|
-
) -> int:
|
1162
|
-
"""Get the total count of source passages with optional filters.
|
1163
|
-
|
1164
|
-
Args:
|
1165
|
-
actor: The user requesting the count
|
1166
|
-
source_id: The source ID of the passages
|
1167
|
-
"""
|
1168
|
-
with db_registry.session() as session:
|
1169
|
-
return SourcePassage.size(db_session=session, actor=actor, source_id=source_id)
|
1170
|
-
|
1171
826
|
@enforce_types
|
1172
827
|
@trace_method
|
1173
828
|
async def source_passage_size_async(
|
@@ -10,27 +10,6 @@ from letta.utils import enforce_types
|
|
10
10
|
|
11
11
|
|
12
12
|
class ProviderManager:
|
13
|
-
@enforce_types
|
14
|
-
@trace_method
|
15
|
-
def create_provider(self, request: ProviderCreate, actor: PydanticUser) -> PydanticProvider:
|
16
|
-
"""Create a new provider if it doesn't already exist."""
|
17
|
-
with db_registry.session() as session:
|
18
|
-
provider_create_args = {**request.model_dump(), "provider_category": ProviderCategory.byok}
|
19
|
-
provider = PydanticProvider(**provider_create_args)
|
20
|
-
|
21
|
-
if provider.name == provider.provider_type.value:
|
22
|
-
raise ValueError("Provider name must be unique and different from provider type")
|
23
|
-
|
24
|
-
# Assign the organization id based on the actor
|
25
|
-
provider.organization_id = actor.organization_id
|
26
|
-
|
27
|
-
# Lazily create the provider id prior to persistence
|
28
|
-
provider.resolve_identifier()
|
29
|
-
|
30
|
-
new_provider = ProviderModel(**provider.model_dump(to_orm=True, exclude_unset=True))
|
31
|
-
new_provider.create(session, actor=actor)
|
32
|
-
return new_provider.to_pydantic()
|
33
|
-
|
34
13
|
@enforce_types
|
35
14
|
@trace_method
|
36
15
|
async def create_provider_async(self, request: ProviderCreate, actor: PydanticUser) -> PydanticProvider:
|
@@ -52,23 +31,6 @@ class ProviderManager:
|
|
52
31
|
await new_provider.create_async(session, actor=actor)
|
53
32
|
return new_provider.to_pydantic()
|
54
33
|
|
55
|
-
@enforce_types
|
56
|
-
@trace_method
|
57
|
-
def update_provider(self, provider_id: str, provider_update: ProviderUpdate, actor: PydanticUser) -> PydanticProvider:
|
58
|
-
"""Update provider details."""
|
59
|
-
with db_registry.session() as session:
|
60
|
-
# Retrieve the existing provider by ID
|
61
|
-
existing_provider = ProviderModel.read(db_session=session, identifier=provider_id, actor=actor, check_is_deleted=True)
|
62
|
-
|
63
|
-
# Update only the fields that are provided in ProviderUpdate
|
64
|
-
update_data = provider_update.model_dump(to_orm=True, exclude_unset=True, exclude_none=True)
|
65
|
-
for key, value in update_data.items():
|
66
|
-
setattr(existing_provider, key, value)
|
67
|
-
|
68
|
-
# Commit the updated provider
|
69
|
-
existing_provider.update(session, actor=actor)
|
70
|
-
return existing_provider.to_pydantic()
|
71
|
-
|
72
34
|
@enforce_types
|
73
35
|
@trace_method
|
74
36
|
async def update_provider_async(self, provider_id: str, provider_update: ProviderUpdate, actor: PydanticUser) -> PydanticProvider:
|
@@ -88,21 +50,6 @@ class ProviderManager:
|
|
88
50
|
await existing_provider.update_async(session, actor=actor)
|
89
51
|
return existing_provider.to_pydantic()
|
90
52
|
|
91
|
-
@enforce_types
|
92
|
-
@trace_method
|
93
|
-
def delete_provider_by_id(self, provider_id: str, actor: PydanticUser):
|
94
|
-
"""Delete a provider."""
|
95
|
-
with db_registry.session() as session:
|
96
|
-
# Clear api key field
|
97
|
-
existing_provider = ProviderModel.read(db_session=session, identifier=provider_id, actor=actor, check_is_deleted=True)
|
98
|
-
existing_provider.api_key = None
|
99
|
-
existing_provider.update(session, actor=actor)
|
100
|
-
|
101
|
-
# Soft delete in provider table
|
102
|
-
existing_provider.delete(session, actor=actor)
|
103
|
-
|
104
|
-
session.commit()
|
105
|
-
|
106
53
|
@enforce_types
|
107
54
|
@trace_method
|
108
55
|
async def delete_provider_by_id_async(self, provider_id: str, actor: PydanticUser):
|
@@ -120,33 +67,6 @@ class ProviderManager:
|
|
120
67
|
|
121
68
|
await session.commit()
|
122
69
|
|
123
|
-
@enforce_types
|
124
|
-
@trace_method
|
125
|
-
def list_providers(
|
126
|
-
self,
|
127
|
-
actor: PydanticUser,
|
128
|
-
name: Optional[str] = None,
|
129
|
-
provider_type: Optional[ProviderType] = None,
|
130
|
-
after: Optional[str] = None,
|
131
|
-
limit: Optional[int] = 50,
|
132
|
-
) -> List[PydanticProvider]:
|
133
|
-
"""List all providers with optional pagination."""
|
134
|
-
filter_kwargs = {}
|
135
|
-
if name:
|
136
|
-
filter_kwargs["name"] = name
|
137
|
-
if provider_type:
|
138
|
-
filter_kwargs["provider_type"] = provider_type
|
139
|
-
with db_registry.session() as session:
|
140
|
-
providers = ProviderModel.list(
|
141
|
-
db_session=session,
|
142
|
-
after=after,
|
143
|
-
limit=limit,
|
144
|
-
actor=actor,
|
145
|
-
check_is_deleted=True,
|
146
|
-
**filter_kwargs,
|
147
|
-
)
|
148
|
-
return [provider.to_pydantic() for provider in providers]
|
149
|
-
|
150
70
|
@enforce_types
|
151
71
|
@trace_method
|
152
72
|
async def list_providers_async(
|