agentrun-mem0ai 0.0.11__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 (150) hide show
  1. agentrun_mem0/__init__.py +6 -0
  2. agentrun_mem0/client/__init__.py +0 -0
  3. agentrun_mem0/client/main.py +1747 -0
  4. agentrun_mem0/client/project.py +931 -0
  5. agentrun_mem0/client/utils.py +115 -0
  6. agentrun_mem0/configs/__init__.py +0 -0
  7. agentrun_mem0/configs/base.py +90 -0
  8. agentrun_mem0/configs/embeddings/__init__.py +0 -0
  9. agentrun_mem0/configs/embeddings/base.py +110 -0
  10. agentrun_mem0/configs/enums.py +7 -0
  11. agentrun_mem0/configs/llms/__init__.py +0 -0
  12. agentrun_mem0/configs/llms/anthropic.py +56 -0
  13. agentrun_mem0/configs/llms/aws_bedrock.py +192 -0
  14. agentrun_mem0/configs/llms/azure.py +57 -0
  15. agentrun_mem0/configs/llms/base.py +62 -0
  16. agentrun_mem0/configs/llms/deepseek.py +56 -0
  17. agentrun_mem0/configs/llms/lmstudio.py +59 -0
  18. agentrun_mem0/configs/llms/ollama.py +56 -0
  19. agentrun_mem0/configs/llms/openai.py +79 -0
  20. agentrun_mem0/configs/llms/vllm.py +56 -0
  21. agentrun_mem0/configs/prompts.py +459 -0
  22. agentrun_mem0/configs/rerankers/__init__.py +0 -0
  23. agentrun_mem0/configs/rerankers/base.py +17 -0
  24. agentrun_mem0/configs/rerankers/cohere.py +15 -0
  25. agentrun_mem0/configs/rerankers/config.py +12 -0
  26. agentrun_mem0/configs/rerankers/huggingface.py +17 -0
  27. agentrun_mem0/configs/rerankers/llm.py +48 -0
  28. agentrun_mem0/configs/rerankers/sentence_transformer.py +16 -0
  29. agentrun_mem0/configs/rerankers/zero_entropy.py +28 -0
  30. agentrun_mem0/configs/vector_stores/__init__.py +0 -0
  31. agentrun_mem0/configs/vector_stores/alibabacloud_mysql.py +64 -0
  32. agentrun_mem0/configs/vector_stores/aliyun_tablestore.py +32 -0
  33. agentrun_mem0/configs/vector_stores/azure_ai_search.py +57 -0
  34. agentrun_mem0/configs/vector_stores/azure_mysql.py +84 -0
  35. agentrun_mem0/configs/vector_stores/baidu.py +27 -0
  36. agentrun_mem0/configs/vector_stores/chroma.py +58 -0
  37. agentrun_mem0/configs/vector_stores/databricks.py +61 -0
  38. agentrun_mem0/configs/vector_stores/elasticsearch.py +65 -0
  39. agentrun_mem0/configs/vector_stores/faiss.py +37 -0
  40. agentrun_mem0/configs/vector_stores/langchain.py +30 -0
  41. agentrun_mem0/configs/vector_stores/milvus.py +42 -0
  42. agentrun_mem0/configs/vector_stores/mongodb.py +25 -0
  43. agentrun_mem0/configs/vector_stores/neptune.py +27 -0
  44. agentrun_mem0/configs/vector_stores/opensearch.py +41 -0
  45. agentrun_mem0/configs/vector_stores/pgvector.py +52 -0
  46. agentrun_mem0/configs/vector_stores/pinecone.py +55 -0
  47. agentrun_mem0/configs/vector_stores/qdrant.py +47 -0
  48. agentrun_mem0/configs/vector_stores/redis.py +24 -0
  49. agentrun_mem0/configs/vector_stores/s3_vectors.py +28 -0
  50. agentrun_mem0/configs/vector_stores/supabase.py +44 -0
  51. agentrun_mem0/configs/vector_stores/upstash_vector.py +34 -0
  52. agentrun_mem0/configs/vector_stores/valkey.py +15 -0
  53. agentrun_mem0/configs/vector_stores/vertex_ai_vector_search.py +28 -0
  54. agentrun_mem0/configs/vector_stores/weaviate.py +41 -0
  55. agentrun_mem0/embeddings/__init__.py +0 -0
  56. agentrun_mem0/embeddings/aws_bedrock.py +100 -0
  57. agentrun_mem0/embeddings/azure_openai.py +55 -0
  58. agentrun_mem0/embeddings/base.py +31 -0
  59. agentrun_mem0/embeddings/configs.py +30 -0
  60. agentrun_mem0/embeddings/gemini.py +39 -0
  61. agentrun_mem0/embeddings/huggingface.py +44 -0
  62. agentrun_mem0/embeddings/langchain.py +35 -0
  63. agentrun_mem0/embeddings/lmstudio.py +29 -0
  64. agentrun_mem0/embeddings/mock.py +11 -0
  65. agentrun_mem0/embeddings/ollama.py +53 -0
  66. agentrun_mem0/embeddings/openai.py +49 -0
  67. agentrun_mem0/embeddings/together.py +31 -0
  68. agentrun_mem0/embeddings/vertexai.py +64 -0
  69. agentrun_mem0/exceptions.py +503 -0
  70. agentrun_mem0/graphs/__init__.py +0 -0
  71. agentrun_mem0/graphs/configs.py +105 -0
  72. agentrun_mem0/graphs/neptune/__init__.py +0 -0
  73. agentrun_mem0/graphs/neptune/base.py +497 -0
  74. agentrun_mem0/graphs/neptune/neptunedb.py +511 -0
  75. agentrun_mem0/graphs/neptune/neptunegraph.py +474 -0
  76. agentrun_mem0/graphs/tools.py +371 -0
  77. agentrun_mem0/graphs/utils.py +97 -0
  78. agentrun_mem0/llms/__init__.py +0 -0
  79. agentrun_mem0/llms/anthropic.py +87 -0
  80. agentrun_mem0/llms/aws_bedrock.py +665 -0
  81. agentrun_mem0/llms/azure_openai.py +141 -0
  82. agentrun_mem0/llms/azure_openai_structured.py +91 -0
  83. agentrun_mem0/llms/base.py +131 -0
  84. agentrun_mem0/llms/configs.py +34 -0
  85. agentrun_mem0/llms/deepseek.py +107 -0
  86. agentrun_mem0/llms/gemini.py +201 -0
  87. agentrun_mem0/llms/groq.py +88 -0
  88. agentrun_mem0/llms/langchain.py +94 -0
  89. agentrun_mem0/llms/litellm.py +87 -0
  90. agentrun_mem0/llms/lmstudio.py +114 -0
  91. agentrun_mem0/llms/ollama.py +117 -0
  92. agentrun_mem0/llms/openai.py +147 -0
  93. agentrun_mem0/llms/openai_structured.py +52 -0
  94. agentrun_mem0/llms/sarvam.py +89 -0
  95. agentrun_mem0/llms/together.py +88 -0
  96. agentrun_mem0/llms/vllm.py +107 -0
  97. agentrun_mem0/llms/xai.py +52 -0
  98. agentrun_mem0/memory/__init__.py +0 -0
  99. agentrun_mem0/memory/base.py +63 -0
  100. agentrun_mem0/memory/graph_memory.py +698 -0
  101. agentrun_mem0/memory/kuzu_memory.py +713 -0
  102. agentrun_mem0/memory/main.py +2229 -0
  103. agentrun_mem0/memory/memgraph_memory.py +689 -0
  104. agentrun_mem0/memory/setup.py +56 -0
  105. agentrun_mem0/memory/storage.py +218 -0
  106. agentrun_mem0/memory/telemetry.py +90 -0
  107. agentrun_mem0/memory/utils.py +208 -0
  108. agentrun_mem0/proxy/__init__.py +0 -0
  109. agentrun_mem0/proxy/main.py +189 -0
  110. agentrun_mem0/reranker/__init__.py +9 -0
  111. agentrun_mem0/reranker/base.py +20 -0
  112. agentrun_mem0/reranker/cohere_reranker.py +85 -0
  113. agentrun_mem0/reranker/huggingface_reranker.py +147 -0
  114. agentrun_mem0/reranker/llm_reranker.py +142 -0
  115. agentrun_mem0/reranker/sentence_transformer_reranker.py +107 -0
  116. agentrun_mem0/reranker/zero_entropy_reranker.py +96 -0
  117. agentrun_mem0/utils/factory.py +283 -0
  118. agentrun_mem0/utils/gcp_auth.py +167 -0
  119. agentrun_mem0/vector_stores/__init__.py +0 -0
  120. agentrun_mem0/vector_stores/alibabacloud_mysql.py +547 -0
  121. agentrun_mem0/vector_stores/aliyun_tablestore.py +252 -0
  122. agentrun_mem0/vector_stores/azure_ai_search.py +396 -0
  123. agentrun_mem0/vector_stores/azure_mysql.py +463 -0
  124. agentrun_mem0/vector_stores/baidu.py +368 -0
  125. agentrun_mem0/vector_stores/base.py +58 -0
  126. agentrun_mem0/vector_stores/chroma.py +332 -0
  127. agentrun_mem0/vector_stores/configs.py +67 -0
  128. agentrun_mem0/vector_stores/databricks.py +761 -0
  129. agentrun_mem0/vector_stores/elasticsearch.py +237 -0
  130. agentrun_mem0/vector_stores/faiss.py +479 -0
  131. agentrun_mem0/vector_stores/langchain.py +180 -0
  132. agentrun_mem0/vector_stores/milvus.py +250 -0
  133. agentrun_mem0/vector_stores/mongodb.py +310 -0
  134. agentrun_mem0/vector_stores/neptune_analytics.py +467 -0
  135. agentrun_mem0/vector_stores/opensearch.py +292 -0
  136. agentrun_mem0/vector_stores/pgvector.py +404 -0
  137. agentrun_mem0/vector_stores/pinecone.py +382 -0
  138. agentrun_mem0/vector_stores/qdrant.py +270 -0
  139. agentrun_mem0/vector_stores/redis.py +295 -0
  140. agentrun_mem0/vector_stores/s3_vectors.py +176 -0
  141. agentrun_mem0/vector_stores/supabase.py +237 -0
  142. agentrun_mem0/vector_stores/upstash_vector.py +293 -0
  143. agentrun_mem0/vector_stores/valkey.py +824 -0
  144. agentrun_mem0/vector_stores/vertex_ai_vector_search.py +635 -0
  145. agentrun_mem0/vector_stores/weaviate.py +343 -0
  146. agentrun_mem0ai-0.0.11.data/data/README.md +205 -0
  147. agentrun_mem0ai-0.0.11.dist-info/METADATA +277 -0
  148. agentrun_mem0ai-0.0.11.dist-info/RECORD +150 -0
  149. agentrun_mem0ai-0.0.11.dist-info/WHEEL +4 -0
  150. agentrun_mem0ai-0.0.11.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,931 @@
1
+ import logging
2
+ from abc import ABC, abstractmethod
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ import httpx
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+
8
+ from agentrun_mem0.client.utils import api_error_handler
9
+ from agentrun_mem0.memory.telemetry import capture_client_event
10
+ # Exception classes are referenced in docstrings only
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class ProjectConfig(BaseModel):
16
+ """
17
+ Configuration for project management operations.
18
+ """
19
+
20
+ org_id: Optional[str] = Field(default=None, description="Organization ID")
21
+ project_id: Optional[str] = Field(default=None, description="Project ID")
22
+ user_email: Optional[str] = Field(default=None, description="User email")
23
+
24
+ model_config = ConfigDict(validate_assignment=True, extra="forbid")
25
+
26
+
27
+ class BaseProject(ABC):
28
+ """
29
+ Abstract base class for project management operations.
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ client: Any,
35
+ config: Optional[ProjectConfig] = None,
36
+ org_id: Optional[str] = None,
37
+ project_id: Optional[str] = None,
38
+ user_email: Optional[str] = None,
39
+ ):
40
+ """
41
+ Initialize the project manager.
42
+
43
+ Args:
44
+ client: HTTP client instance
45
+ config: Project manager configuration
46
+ org_id: Organization ID
47
+ project_id: Project ID
48
+ user_email: User email
49
+ """
50
+ self._client = client
51
+
52
+ # Handle config initialization
53
+ if config is not None:
54
+ self.config = config
55
+ else:
56
+ # Create config from parameters
57
+ self.config = ProjectConfig(org_id=org_id, project_id=project_id, user_email=user_email)
58
+
59
+ @property
60
+ def org_id(self) -> Optional[str]:
61
+ """Get the organization ID."""
62
+ return self.config.org_id
63
+
64
+ @property
65
+ def project_id(self) -> Optional[str]:
66
+ """Get the project ID."""
67
+ return self.config.project_id
68
+
69
+ @property
70
+ def user_email(self) -> Optional[str]:
71
+ """Get the user email."""
72
+ return self.config.user_email
73
+
74
+ def _validate_org_project(self) -> None:
75
+ """
76
+ Validate that both org_id and project_id are set.
77
+
78
+ Raises:
79
+ ValueError: If org_id or project_id are not set.
80
+ """
81
+ if not (self.config.org_id and self.config.project_id):
82
+ raise ValueError("org_id and project_id must be set to access project operations")
83
+
84
+ def _prepare_params(self, kwargs: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
85
+ """
86
+ Prepare query parameters for API requests.
87
+
88
+ Args:
89
+ kwargs: Additional keyword arguments.
90
+
91
+ Returns:
92
+ Dictionary containing prepared parameters.
93
+
94
+ Raises:
95
+ ValueError: If org_id or project_id validation fails.
96
+ """
97
+ if kwargs is None:
98
+ kwargs = {}
99
+
100
+ # Add org_id and project_id if available
101
+ if self.config.org_id and self.config.project_id:
102
+ kwargs["org_id"] = self.config.org_id
103
+ kwargs["project_id"] = self.config.project_id
104
+ elif self.config.org_id or self.config.project_id:
105
+ raise ValueError("Please provide both org_id and project_id")
106
+
107
+ return {k: v for k, v in kwargs.items() if v is not None}
108
+
109
+ def _prepare_org_params(self, kwargs: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
110
+ """
111
+ Prepare query parameters for organization-level API requests.
112
+
113
+ Args:
114
+ kwargs: Additional keyword arguments.
115
+
116
+ Returns:
117
+ Dictionary containing prepared parameters.
118
+
119
+ Raises:
120
+ ValueError: If org_id is not provided.
121
+ """
122
+ if kwargs is None:
123
+ kwargs = {}
124
+
125
+ # Add org_id if available
126
+ if self.config.org_id:
127
+ kwargs["org_id"] = self.config.org_id
128
+ else:
129
+ raise ValueError("org_id must be set for organization-level operations")
130
+
131
+ return {k: v for k, v in kwargs.items() if v is not None}
132
+
133
+ @abstractmethod
134
+ def get(self, fields: Optional[List[str]] = None) -> Dict[str, Any]:
135
+ """
136
+ Get project details.
137
+
138
+ Args:
139
+ fields: List of fields to retrieve
140
+
141
+ Returns:
142
+ Dictionary containing the requested project fields.
143
+
144
+ Raises:
145
+ ValidationError: If the input data is invalid.
146
+ AuthenticationError: If authentication fails.
147
+ RateLimitError: If rate limits are exceeded.
148
+ NetworkError: If network connectivity issues occur.
149
+ ValueError: If org_id or project_id are not set.
150
+ """
151
+ pass
152
+
153
+ @abstractmethod
154
+ def create(self, name: str, description: Optional[str] = None) -> Dict[str, Any]:
155
+ """
156
+ Create a new project within the organization.
157
+
158
+ Args:
159
+ name: Name of the project to be created
160
+ description: Optional description for the project
161
+
162
+ Returns:
163
+ Dictionary containing the created project details.
164
+
165
+ Raises:
166
+ ValidationError: If the input data is invalid.
167
+ AuthenticationError: If authentication fails.
168
+ RateLimitError: If rate limits are exceeded.
169
+ NetworkError: If network connectivity issues occur.
170
+ ValueError: If org_id is not set.
171
+ """
172
+ pass
173
+
174
+ @abstractmethod
175
+ def update(
176
+ self,
177
+ custom_instructions: Optional[str] = None,
178
+ custom_categories: Optional[List[str]] = None,
179
+ retrieval_criteria: Optional[List[Dict[str, Any]]] = None,
180
+ enable_graph: Optional[bool] = None,
181
+ ) -> Dict[str, Any]:
182
+ """
183
+ Update project settings.
184
+
185
+ Args:
186
+ custom_instructions: New instructions for the project
187
+ custom_categories: New categories for the project
188
+ retrieval_criteria: New retrieval criteria for the project
189
+ enable_graph: Enable or disable the graph for the project
190
+
191
+ Returns:
192
+ Dictionary containing the API response.
193
+
194
+ Raises:
195
+ ValidationError: If the input data is invalid.
196
+ AuthenticationError: If authentication fails.
197
+ RateLimitError: If rate limits are exceeded.
198
+ NetworkError: If network connectivity issues occur.
199
+ ValueError: If org_id or project_id are not set.
200
+ """
201
+ pass
202
+
203
+ @abstractmethod
204
+ def delete(self) -> Dict[str, Any]:
205
+ """
206
+ Delete the current project and its related data.
207
+
208
+ Returns:
209
+ Dictionary containing the API response.
210
+
211
+ Raises:
212
+ ValidationError: If the input data is invalid.
213
+ AuthenticationError: If authentication fails.
214
+ RateLimitError: If rate limits are exceeded.
215
+ NetworkError: If network connectivity issues occur.
216
+ ValueError: If org_id or project_id are not set.
217
+ """
218
+ pass
219
+
220
+ @abstractmethod
221
+ def get_members(self) -> Dict[str, Any]:
222
+ """
223
+ Get all members of the current project.
224
+
225
+ Returns:
226
+ Dictionary containing the list of project members.
227
+
228
+ Raises:
229
+ ValidationError: If the input data is invalid.
230
+ AuthenticationError: If authentication fails.
231
+ RateLimitError: If rate limits are exceeded.
232
+ NetworkError: If network connectivity issues occur.
233
+ ValueError: If org_id or project_id are not set.
234
+ """
235
+ pass
236
+
237
+ @abstractmethod
238
+ def add_member(self, email: str, role: str = "READER") -> Dict[str, Any]:
239
+ """
240
+ Add a new member to the current project.
241
+
242
+ Args:
243
+ email: Email address of the user to add
244
+ role: Role to assign ("READER" or "OWNER")
245
+
246
+ Returns:
247
+ Dictionary containing the API response.
248
+
249
+ Raises:
250
+ ValidationError: If the input data is invalid.
251
+ AuthenticationError: If authentication fails.
252
+ RateLimitError: If rate limits are exceeded.
253
+ NetworkError: If network connectivity issues occur.
254
+ ValueError: If org_id or project_id are not set.
255
+ """
256
+ pass
257
+
258
+ @abstractmethod
259
+ def update_member(self, email: str, role: str) -> Dict[str, Any]:
260
+ """
261
+ Update a member's role in the current project.
262
+
263
+ Args:
264
+ email: Email address of the user to update
265
+ role: New role to assign ("READER" or "OWNER")
266
+
267
+ Returns:
268
+ Dictionary containing the API response.
269
+
270
+ Raises:
271
+ ValidationError: If the input data is invalid.
272
+ AuthenticationError: If authentication fails.
273
+ RateLimitError: If rate limits are exceeded.
274
+ NetworkError: If network connectivity issues occur.
275
+ ValueError: If org_id or project_id are not set.
276
+ """
277
+ pass
278
+
279
+ @abstractmethod
280
+ def remove_member(self, email: str) -> Dict[str, Any]:
281
+ """
282
+ Remove a member from the current project.
283
+
284
+ Args:
285
+ email: Email address of the user to remove
286
+
287
+ Returns:
288
+ Dictionary containing the API response.
289
+
290
+ Raises:
291
+ ValidationError: If the input data is invalid.
292
+ AuthenticationError: If authentication fails.
293
+ RateLimitError: If rate limits are exceeded.
294
+ NetworkError: If network connectivity issues occur.
295
+ ValueError: If org_id or project_id are not set.
296
+ """
297
+ pass
298
+
299
+
300
+ class Project(BaseProject):
301
+ """
302
+ Synchronous project management operations.
303
+ """
304
+
305
+ def __init__(
306
+ self,
307
+ client: httpx.Client,
308
+ config: Optional[ProjectConfig] = None,
309
+ org_id: Optional[str] = None,
310
+ project_id: Optional[str] = None,
311
+ user_email: Optional[str] = None,
312
+ ):
313
+ """
314
+ Initialize the synchronous project manager.
315
+
316
+ Args:
317
+ client: HTTP client instance
318
+ config: Project manager configuration
319
+ org_id: Organization ID
320
+ project_id: Project ID
321
+ user_email: User email
322
+ """
323
+ super().__init__(client, config, org_id, project_id, user_email)
324
+ self._validate_org_project()
325
+
326
+ @api_error_handler
327
+ def get(self, fields: Optional[List[str]] = None) -> Dict[str, Any]:
328
+ """
329
+ Get project details.
330
+
331
+ Args:
332
+ fields: List of fields to retrieve
333
+
334
+ Returns:
335
+ Dictionary containing the requested project fields.
336
+
337
+ Raises:
338
+ ValidationError: If the input data is invalid.
339
+ AuthenticationError: If authentication fails.
340
+ RateLimitError: If rate limits are exceeded.
341
+ NetworkError: If network connectivity issues occur.
342
+ ValueError: If org_id or project_id are not set.
343
+ """
344
+ params = self._prepare_params({"fields": fields})
345
+ response = self._client.get(
346
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/",
347
+ params=params,
348
+ )
349
+ response.raise_for_status()
350
+ capture_client_event(
351
+ "client.project.get",
352
+ self,
353
+ {"fields": fields, "sync_type": "sync"},
354
+ )
355
+ return response.json()
356
+
357
+ @api_error_handler
358
+ def create(self, name: str, description: Optional[str] = None) -> Dict[str, Any]:
359
+ """
360
+ Create a new project within the organization.
361
+
362
+ Args:
363
+ name: Name of the project to be created
364
+ description: Optional description for the project
365
+
366
+ Returns:
367
+ Dictionary containing the created project details.
368
+
369
+ Raises:
370
+ ValidationError: If the input data is invalid.
371
+ AuthenticationError: If authentication fails.
372
+ RateLimitError: If rate limits are exceeded.
373
+ NetworkError: If network connectivity issues occur.
374
+ ValueError: If org_id is not set.
375
+ """
376
+ if not self.config.org_id:
377
+ raise ValueError("org_id must be set to create a project")
378
+
379
+ payload = {"name": name}
380
+ if description is not None:
381
+ payload["description"] = description
382
+
383
+ response = self._client.post(
384
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/",
385
+ json=payload,
386
+ )
387
+ response.raise_for_status()
388
+ capture_client_event(
389
+ "client.project.create",
390
+ self,
391
+ {"name": name, "description": description, "sync_type": "sync"},
392
+ )
393
+ return response.json()
394
+
395
+ @api_error_handler
396
+ def update(
397
+ self,
398
+ custom_instructions: Optional[str] = None,
399
+ custom_categories: Optional[List[str]] = None,
400
+ retrieval_criteria: Optional[List[Dict[str, Any]]] = None,
401
+ enable_graph: Optional[bool] = None,
402
+ ) -> Dict[str, Any]:
403
+ """
404
+ Update project settings.
405
+
406
+ Args:
407
+ custom_instructions: New instructions for the project
408
+ custom_categories: New categories for the project
409
+ retrieval_criteria: New retrieval criteria for the project
410
+ enable_graph: Enable or disable the graph for the project
411
+
412
+ Returns:
413
+ Dictionary containing the API response.
414
+
415
+ Raises:
416
+ ValidationError: If the input data is invalid.
417
+ AuthenticationError: If authentication fails.
418
+ RateLimitError: If rate limits are exceeded.
419
+ NetworkError: If network connectivity issues occur.
420
+ ValueError: If org_id or project_id are not set.
421
+ """
422
+ if (
423
+ custom_instructions is None
424
+ and custom_categories is None
425
+ and retrieval_criteria is None
426
+ and enable_graph is None
427
+ ):
428
+ raise ValueError(
429
+ "At least one parameter must be provided for update: "
430
+ "custom_instructions, custom_categories, retrieval_criteria, "
431
+ "enable_graph"
432
+ )
433
+
434
+ payload = self._prepare_params(
435
+ {
436
+ "custom_instructions": custom_instructions,
437
+ "custom_categories": custom_categories,
438
+ "retrieval_criteria": retrieval_criteria,
439
+ "enable_graph": enable_graph,
440
+ }
441
+ )
442
+ response = self._client.patch(
443
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/",
444
+ json=payload,
445
+ )
446
+ response.raise_for_status()
447
+ capture_client_event(
448
+ "client.project.update",
449
+ self,
450
+ {
451
+ "custom_instructions": custom_instructions,
452
+ "custom_categories": custom_categories,
453
+ "retrieval_criteria": retrieval_criteria,
454
+ "enable_graph": enable_graph,
455
+ "sync_type": "sync",
456
+ },
457
+ )
458
+ return response.json()
459
+
460
+ @api_error_handler
461
+ def delete(self) -> Dict[str, Any]:
462
+ """
463
+ Delete the current project and its related data.
464
+
465
+ Returns:
466
+ Dictionary containing the API response.
467
+
468
+ Raises:
469
+ ValidationError: If the input data is invalid.
470
+ AuthenticationError: If authentication fails.
471
+ RateLimitError: If rate limits are exceeded.
472
+ NetworkError: If network connectivity issues occur.
473
+ ValueError: If org_id or project_id are not set.
474
+ """
475
+ response = self._client.delete(
476
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/",
477
+ )
478
+ response.raise_for_status()
479
+ capture_client_event(
480
+ "client.project.delete",
481
+ self,
482
+ {"sync_type": "sync"},
483
+ )
484
+ return response.json()
485
+
486
+ @api_error_handler
487
+ def get_members(self) -> Dict[str, Any]:
488
+ """
489
+ Get all members of the current project.
490
+
491
+ Returns:
492
+ Dictionary containing the list of project members.
493
+
494
+ Raises:
495
+ ValidationError: If the input data is invalid.
496
+ AuthenticationError: If authentication fails.
497
+ RateLimitError: If rate limits are exceeded.
498
+ NetworkError: If network connectivity issues occur.
499
+ ValueError: If org_id or project_id are not set.
500
+ """
501
+ response = self._client.get(
502
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
503
+ )
504
+ response.raise_for_status()
505
+ capture_client_event(
506
+ "client.project.get_members",
507
+ self,
508
+ {"sync_type": "sync"},
509
+ )
510
+ return response.json()
511
+
512
+ @api_error_handler
513
+ def add_member(self, email: str, role: str = "READER") -> Dict[str, Any]:
514
+ """
515
+ Add a new member to the current project.
516
+
517
+ Args:
518
+ email: Email address of the user to add
519
+ role: Role to assign ("READER" or "OWNER")
520
+
521
+ Returns:
522
+ Dictionary containing the API response.
523
+
524
+ Raises:
525
+ ValidationError: If the input data is invalid.
526
+ AuthenticationError: If authentication fails.
527
+ RateLimitError: If rate limits are exceeded.
528
+ NetworkError: If network connectivity issues occur.
529
+ ValueError: If org_id or project_id are not set.
530
+ """
531
+ if role not in ["READER", "OWNER"]:
532
+ raise ValueError("Role must be either 'READER' or 'OWNER'")
533
+
534
+ payload = {"email": email, "role": role}
535
+
536
+ response = self._client.post(
537
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
538
+ json=payload,
539
+ )
540
+ response.raise_for_status()
541
+ capture_client_event(
542
+ "client.project.add_member",
543
+ self,
544
+ {"email": email, "role": role, "sync_type": "sync"},
545
+ )
546
+ return response.json()
547
+
548
+ @api_error_handler
549
+ def update_member(self, email: str, role: str) -> Dict[str, Any]:
550
+ """
551
+ Update a member's role in the current project.
552
+
553
+ Args:
554
+ email: Email address of the user to update
555
+ role: New role to assign ("READER" or "OWNER")
556
+
557
+ Returns:
558
+ Dictionary containing the API response.
559
+
560
+ Raises:
561
+ ValidationError: If the input data is invalid.
562
+ AuthenticationError: If authentication fails.
563
+ RateLimitError: If rate limits are exceeded.
564
+ NetworkError: If network connectivity issues occur.
565
+ ValueError: If org_id or project_id are not set.
566
+ """
567
+ if role not in ["READER", "OWNER"]:
568
+ raise ValueError("Role must be either 'READER' or 'OWNER'")
569
+
570
+ payload = {"email": email, "role": role}
571
+
572
+ response = self._client.put(
573
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
574
+ json=payload,
575
+ )
576
+ response.raise_for_status()
577
+ capture_client_event(
578
+ "client.project.update_member",
579
+ self,
580
+ {"email": email, "role": role, "sync_type": "sync"},
581
+ )
582
+ return response.json()
583
+
584
+ @api_error_handler
585
+ def remove_member(self, email: str) -> Dict[str, Any]:
586
+ """
587
+ Remove a member from the current project.
588
+
589
+ Args:
590
+ email: Email address of the user to remove
591
+
592
+ Returns:
593
+ Dictionary containing the API response.
594
+
595
+ Raises:
596
+ ValidationError: If the input data is invalid.
597
+ AuthenticationError: If authentication fails.
598
+ RateLimitError: If rate limits are exceeded.
599
+ NetworkError: If network connectivity issues occur.
600
+ ValueError: If org_id or project_id are not set.
601
+ """
602
+ params = {"email": email}
603
+
604
+ response = self._client.delete(
605
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
606
+ params=params,
607
+ )
608
+ response.raise_for_status()
609
+ capture_client_event(
610
+ "client.project.remove_member",
611
+ self,
612
+ {"email": email, "sync_type": "sync"},
613
+ )
614
+ return response.json()
615
+
616
+
617
+ class AsyncProject(BaseProject):
618
+ """
619
+ Asynchronous project management operations.
620
+ """
621
+
622
+ def __init__(
623
+ self,
624
+ client: httpx.AsyncClient,
625
+ config: Optional[ProjectConfig] = None,
626
+ org_id: Optional[str] = None,
627
+ project_id: Optional[str] = None,
628
+ user_email: Optional[str] = None,
629
+ ):
630
+ """
631
+ Initialize the asynchronous project manager.
632
+
633
+ Args:
634
+ client: HTTP client instance
635
+ config: Project manager configuration
636
+ org_id: Organization ID
637
+ project_id: Project ID
638
+ user_email: User email
639
+ """
640
+ super().__init__(client, config, org_id, project_id, user_email)
641
+ self._validate_org_project()
642
+
643
+ @api_error_handler
644
+ async def get(self, fields: Optional[List[str]] = None) -> Dict[str, Any]:
645
+ """
646
+ Get project details.
647
+
648
+ Args:
649
+ fields: List of fields to retrieve
650
+
651
+ Returns:
652
+ Dictionary containing the requested project fields.
653
+
654
+ Raises:
655
+ ValidationError: If the input data is invalid.
656
+ AuthenticationError: If authentication fails.
657
+ RateLimitError: If rate limits are exceeded.
658
+ NetworkError: If network connectivity issues occur.
659
+ ValueError: If org_id or project_id are not set.
660
+ """
661
+ params = self._prepare_params({"fields": fields})
662
+ response = await self._client.get(
663
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/",
664
+ params=params,
665
+ )
666
+ response.raise_for_status()
667
+ capture_client_event(
668
+ "client.project.get",
669
+ self,
670
+ {"fields": fields, "sync_type": "async"},
671
+ )
672
+ return response.json()
673
+
674
+ @api_error_handler
675
+ async def create(self, name: str, description: Optional[str] = None) -> Dict[str, Any]:
676
+ """
677
+ Create a new project within the organization.
678
+
679
+ Args:
680
+ name: Name of the project to be created
681
+ description: Optional description for the project
682
+
683
+ Returns:
684
+ Dictionary containing the created project details.
685
+
686
+ Raises:
687
+ ValidationError: If the input data is invalid.
688
+ AuthenticationError: If authentication fails.
689
+ RateLimitError: If rate limits are exceeded.
690
+ NetworkError: If network connectivity issues occur.
691
+ ValueError: If org_id is not set.
692
+ """
693
+ if not self.config.org_id:
694
+ raise ValueError("org_id must be set to create a project")
695
+
696
+ payload = {"name": name}
697
+ if description is not None:
698
+ payload["description"] = description
699
+
700
+ response = await self._client.post(
701
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/",
702
+ json=payload,
703
+ )
704
+ response.raise_for_status()
705
+ capture_client_event(
706
+ "client.project.create",
707
+ self,
708
+ {"name": name, "description": description, "sync_type": "async"},
709
+ )
710
+ return response.json()
711
+
712
+ @api_error_handler
713
+ async def update(
714
+ self,
715
+ custom_instructions: Optional[str] = None,
716
+ custom_categories: Optional[List[str]] = None,
717
+ retrieval_criteria: Optional[List[Dict[str, Any]]] = None,
718
+ enable_graph: Optional[bool] = None,
719
+ ) -> Dict[str, Any]:
720
+ """
721
+ Update project settings.
722
+
723
+ Args:
724
+ custom_instructions: New instructions for the project
725
+ custom_categories: New categories for the project
726
+ retrieval_criteria: New retrieval criteria for the project
727
+ enable_graph: Enable or disable the graph for the project
728
+
729
+ Returns:
730
+ Dictionary containing the API response.
731
+
732
+ Raises:
733
+ ValidationError: If the input data is invalid.
734
+ AuthenticationError: If authentication fails.
735
+ RateLimitError: If rate limits are exceeded.
736
+ NetworkError: If network connectivity issues occur.
737
+ ValueError: If org_id or project_id are not set.
738
+ """
739
+ if (
740
+ custom_instructions is None
741
+ and custom_categories is None
742
+ and retrieval_criteria is None
743
+ and enable_graph is None
744
+ ):
745
+ raise ValueError(
746
+ "At least one parameter must be provided for update: "
747
+ "custom_instructions, custom_categories, retrieval_criteria, "
748
+ "enable_graph"
749
+ )
750
+
751
+ payload = self._prepare_params(
752
+ {
753
+ "custom_instructions": custom_instructions,
754
+ "custom_categories": custom_categories,
755
+ "retrieval_criteria": retrieval_criteria,
756
+ "enable_graph": enable_graph,
757
+ }
758
+ )
759
+ response = await self._client.patch(
760
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/",
761
+ json=payload,
762
+ )
763
+ response.raise_for_status()
764
+ capture_client_event(
765
+ "client.project.update",
766
+ self,
767
+ {
768
+ "custom_instructions": custom_instructions,
769
+ "custom_categories": custom_categories,
770
+ "retrieval_criteria": retrieval_criteria,
771
+ "enable_graph": enable_graph,
772
+ "sync_type": "async",
773
+ },
774
+ )
775
+ return response.json()
776
+
777
+ @api_error_handler
778
+ async def delete(self) -> Dict[str, Any]:
779
+ """
780
+ Delete the current project and its related data.
781
+
782
+ Returns:
783
+ Dictionary containing the API response.
784
+
785
+ Raises:
786
+ ValidationError: If the input data is invalid.
787
+ AuthenticationError: If authentication fails.
788
+ RateLimitError: If rate limits are exceeded.
789
+ NetworkError: If network connectivity issues occur.
790
+ ValueError: If org_id or project_id are not set.
791
+ """
792
+ response = await self._client.delete(
793
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/",
794
+ )
795
+ response.raise_for_status()
796
+ capture_client_event(
797
+ "client.project.delete",
798
+ self,
799
+ {"sync_type": "async"},
800
+ )
801
+ return response.json()
802
+
803
+ @api_error_handler
804
+ async def get_members(self) -> Dict[str, Any]:
805
+ """
806
+ Get all members of the current project.
807
+
808
+ Returns:
809
+ Dictionary containing the list of project members.
810
+
811
+ Raises:
812
+ ValidationError: If the input data is invalid.
813
+ AuthenticationError: If authentication fails.
814
+ RateLimitError: If rate limits are exceeded.
815
+ NetworkError: If network connectivity issues occur.
816
+ ValueError: If org_id or project_id are not set.
817
+ """
818
+ response = await self._client.get(
819
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
820
+ )
821
+ response.raise_for_status()
822
+ capture_client_event(
823
+ "client.project.get_members",
824
+ self,
825
+ {"sync_type": "async"},
826
+ )
827
+ return response.json()
828
+
829
+ @api_error_handler
830
+ async def add_member(self, email: str, role: str = "READER") -> Dict[str, Any]:
831
+ """
832
+ Add a new member to the current project.
833
+
834
+ Args:
835
+ email: Email address of the user to add
836
+ role: Role to assign ("READER" or "OWNER")
837
+
838
+ Returns:
839
+ Dictionary containing the API response.
840
+
841
+ Raises:
842
+ ValidationError: If the input data is invalid.
843
+ AuthenticationError: If authentication fails.
844
+ RateLimitError: If rate limits are exceeded.
845
+ NetworkError: If network connectivity issues occur.
846
+ ValueError: If org_id or project_id are not set.
847
+ """
848
+ if role not in ["READER", "OWNER"]:
849
+ raise ValueError("Role must be either 'READER' or 'OWNER'")
850
+
851
+ payload = {"email": email, "role": role}
852
+
853
+ response = await self._client.post(
854
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
855
+ json=payload,
856
+ )
857
+ response.raise_for_status()
858
+ capture_client_event(
859
+ "client.project.add_member",
860
+ self,
861
+ {"email": email, "role": role, "sync_type": "async"},
862
+ )
863
+ return response.json()
864
+
865
+ @api_error_handler
866
+ async def update_member(self, email: str, role: str) -> Dict[str, Any]:
867
+ """
868
+ Update a member's role in the current project.
869
+
870
+ Args:
871
+ email: Email address of the user to update
872
+ role: New role to assign ("READER" or "OWNER")
873
+
874
+ Returns:
875
+ Dictionary containing the API response.
876
+
877
+ Raises:
878
+ ValidationError: If the input data is invalid.
879
+ AuthenticationError: If authentication fails.
880
+ RateLimitError: If rate limits are exceeded.
881
+ NetworkError: If network connectivity issues occur.
882
+ ValueError: If org_id or project_id are not set.
883
+ """
884
+ if role not in ["READER", "OWNER"]:
885
+ raise ValueError("Role must be either 'READER' or 'OWNER'")
886
+
887
+ payload = {"email": email, "role": role}
888
+
889
+ response = await self._client.put(
890
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
891
+ json=payload,
892
+ )
893
+ response.raise_for_status()
894
+ capture_client_event(
895
+ "client.project.update_member",
896
+ self,
897
+ {"email": email, "role": role, "sync_type": "async"},
898
+ )
899
+ return response.json()
900
+
901
+ @api_error_handler
902
+ async def remove_member(self, email: str) -> Dict[str, Any]:
903
+ """
904
+ Remove a member from the current project.
905
+
906
+ Args:
907
+ email: Email address of the user to remove
908
+
909
+ Returns:
910
+ Dictionary containing the API response.
911
+
912
+ Raises:
913
+ ValidationError: If the input data is invalid.
914
+ AuthenticationError: If authentication fails.
915
+ RateLimitError: If rate limits are exceeded.
916
+ NetworkError: If network connectivity issues occur.
917
+ ValueError: If org_id or project_id are not set.
918
+ """
919
+ params = {"email": email}
920
+
921
+ response = await self._client.delete(
922
+ f"/api/v1/orgs/organizations/{self.config.org_id}/projects/{self.config.project_id}/members/",
923
+ params=params,
924
+ )
925
+ response.raise_for_status()
926
+ capture_client_event(
927
+ "client.project.remove_member",
928
+ self,
929
+ {"email": email, "sync_type": "async"},
930
+ )
931
+ return response.json()