letta-nightly 0.11.7.dev20251007104119__py3-none-any.whl → 0.11.7.dev20251008104128__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.
Files changed (145) hide show
  1. letta/adapters/letta_llm_adapter.py +1 -0
  2. letta/adapters/letta_llm_request_adapter.py +0 -1
  3. letta/adapters/letta_llm_stream_adapter.py +7 -2
  4. letta/adapters/simple_llm_request_adapter.py +88 -0
  5. letta/adapters/simple_llm_stream_adapter.py +192 -0
  6. letta/agents/agent_loop.py +6 -0
  7. letta/agents/ephemeral_summary_agent.py +2 -1
  8. letta/agents/helpers.py +142 -6
  9. letta/agents/letta_agent.py +13 -33
  10. letta/agents/letta_agent_batch.py +2 -4
  11. letta/agents/letta_agent_v2.py +87 -77
  12. letta/agents/letta_agent_v3.py +899 -0
  13. letta/agents/voice_agent.py +2 -6
  14. letta/constants.py +8 -4
  15. letta/errors.py +40 -0
  16. letta/functions/function_sets/base.py +84 -4
  17. letta/functions/function_sets/multi_agent.py +0 -3
  18. letta/functions/schema_generator.py +113 -71
  19. letta/groups/dynamic_multi_agent.py +3 -2
  20. letta/groups/helpers.py +1 -2
  21. letta/groups/round_robin_multi_agent.py +3 -2
  22. letta/groups/sleeptime_multi_agent.py +3 -2
  23. letta/groups/sleeptime_multi_agent_v2.py +1 -1
  24. letta/groups/sleeptime_multi_agent_v3.py +17 -17
  25. letta/groups/supervisor_multi_agent.py +84 -80
  26. letta/helpers/converters.py +3 -0
  27. letta/helpers/message_helper.py +4 -0
  28. letta/helpers/tool_rule_solver.py +92 -5
  29. letta/interfaces/anthropic_streaming_interface.py +409 -0
  30. letta/interfaces/gemini_streaming_interface.py +296 -0
  31. letta/interfaces/openai_streaming_interface.py +752 -1
  32. letta/llm_api/anthropic_client.py +126 -16
  33. letta/llm_api/bedrock_client.py +4 -2
  34. letta/llm_api/deepseek_client.py +4 -1
  35. letta/llm_api/google_vertex_client.py +123 -42
  36. letta/llm_api/groq_client.py +4 -1
  37. letta/llm_api/llm_api_tools.py +11 -4
  38. letta/llm_api/llm_client_base.py +6 -2
  39. letta/llm_api/openai.py +32 -2
  40. letta/llm_api/openai_client.py +423 -18
  41. letta/llm_api/xai_client.py +4 -1
  42. letta/main.py +9 -5
  43. letta/memory.py +1 -0
  44. letta/orm/__init__.py +1 -1
  45. letta/orm/agent.py +10 -0
  46. letta/orm/block.py +7 -16
  47. letta/orm/blocks_agents.py +8 -2
  48. letta/orm/files_agents.py +2 -0
  49. letta/orm/job.py +7 -5
  50. letta/orm/mcp_oauth.py +1 -0
  51. letta/orm/message.py +21 -6
  52. letta/orm/organization.py +2 -0
  53. letta/orm/provider.py +6 -2
  54. letta/orm/run.py +71 -0
  55. letta/orm/sandbox_config.py +7 -1
  56. letta/orm/sqlalchemy_base.py +0 -306
  57. letta/orm/step.py +6 -5
  58. letta/orm/step_metrics.py +5 -5
  59. letta/otel/tracing.py +28 -3
  60. letta/plugins/defaults.py +4 -4
  61. letta/prompts/system_prompts/__init__.py +2 -0
  62. letta/prompts/system_prompts/letta_v1.py +25 -0
  63. letta/schemas/agent.py +3 -2
  64. letta/schemas/agent_file.py +9 -3
  65. letta/schemas/block.py +23 -10
  66. letta/schemas/enums.py +21 -2
  67. letta/schemas/job.py +17 -4
  68. letta/schemas/letta_message_content.py +71 -2
  69. letta/schemas/letta_stop_reason.py +5 -5
  70. letta/schemas/llm_config.py +53 -3
  71. letta/schemas/memory.py +1 -1
  72. letta/schemas/message.py +504 -117
  73. letta/schemas/openai/responses_request.py +64 -0
  74. letta/schemas/providers/__init__.py +2 -0
  75. letta/schemas/providers/anthropic.py +16 -0
  76. letta/schemas/providers/ollama.py +115 -33
  77. letta/schemas/providers/openrouter.py +52 -0
  78. letta/schemas/providers/vllm.py +2 -1
  79. letta/schemas/run.py +48 -42
  80. letta/schemas/step.py +2 -2
  81. letta/schemas/step_metrics.py +1 -1
  82. letta/schemas/tool.py +15 -107
  83. letta/schemas/tool_rule.py +88 -5
  84. letta/serialize_schemas/marshmallow_agent.py +1 -0
  85. letta/server/db.py +86 -408
  86. letta/server/rest_api/app.py +61 -10
  87. letta/server/rest_api/dependencies.py +14 -0
  88. letta/server/rest_api/redis_stream_manager.py +19 -8
  89. letta/server/rest_api/routers/v1/agents.py +364 -292
  90. letta/server/rest_api/routers/v1/blocks.py +14 -20
  91. letta/server/rest_api/routers/v1/identities.py +45 -110
  92. letta/server/rest_api/routers/v1/internal_templates.py +21 -0
  93. letta/server/rest_api/routers/v1/jobs.py +23 -6
  94. letta/server/rest_api/routers/v1/messages.py +1 -1
  95. letta/server/rest_api/routers/v1/runs.py +126 -85
  96. letta/server/rest_api/routers/v1/sandbox_configs.py +10 -19
  97. letta/server/rest_api/routers/v1/tools.py +281 -594
  98. letta/server/rest_api/routers/v1/voice.py +1 -1
  99. letta/server/rest_api/streaming_response.py +29 -29
  100. letta/server/rest_api/utils.py +122 -64
  101. letta/server/server.py +160 -887
  102. letta/services/agent_manager.py +236 -919
  103. letta/services/agent_serialization_manager.py +16 -0
  104. letta/services/archive_manager.py +0 -100
  105. letta/services/block_manager.py +211 -168
  106. letta/services/file_manager.py +1 -1
  107. letta/services/files_agents_manager.py +24 -33
  108. letta/services/group_manager.py +0 -142
  109. letta/services/helpers/agent_manager_helper.py +7 -2
  110. letta/services/helpers/run_manager_helper.py +85 -0
  111. letta/services/job_manager.py +96 -411
  112. letta/services/lettuce/__init__.py +6 -0
  113. letta/services/lettuce/lettuce_client_base.py +86 -0
  114. letta/services/mcp_manager.py +38 -6
  115. letta/services/message_manager.py +165 -362
  116. letta/services/organization_manager.py +0 -36
  117. letta/services/passage_manager.py +0 -345
  118. letta/services/provider_manager.py +0 -80
  119. letta/services/run_manager.py +301 -0
  120. letta/services/sandbox_config_manager.py +0 -234
  121. letta/services/step_manager.py +62 -39
  122. letta/services/summarizer/summarizer.py +9 -7
  123. letta/services/telemetry_manager.py +0 -16
  124. letta/services/tool_executor/builtin_tool_executor.py +35 -0
  125. letta/services/tool_executor/core_tool_executor.py +397 -2
  126. letta/services/tool_executor/files_tool_executor.py +3 -3
  127. letta/services/tool_executor/multi_agent_tool_executor.py +30 -15
  128. letta/services/tool_executor/tool_execution_manager.py +6 -8
  129. letta/services/tool_executor/tool_executor_base.py +3 -3
  130. letta/services/tool_manager.py +85 -339
  131. letta/services/tool_sandbox/base.py +24 -13
  132. letta/services/tool_sandbox/e2b_sandbox.py +16 -1
  133. letta/services/tool_schema_generator.py +123 -0
  134. letta/services/user_manager.py +0 -99
  135. letta/settings.py +20 -4
  136. {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/METADATA +3 -5
  137. {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/RECORD +140 -132
  138. letta/agents/temporal/activities/__init__.py +0 -4
  139. letta/agents/temporal/activities/example_activity.py +0 -7
  140. letta/agents/temporal/activities/prepare_messages.py +0 -10
  141. letta/agents/temporal/temporal_agent_workflow.py +0 -56
  142. letta/agents/temporal/types.py +0 -25
  143. {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/WHEEL +0 -0
  144. {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.11.7.dev20251008104128.dist-info}/entry_points.txt +0 -0
  145. {letta_nightly-0.11.7.dev20251007104119.dist-info → letta_nightly-0.11.7.dev20251008104128.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(