pygeai 0.6.0b6__py3-none-any.whl → 0.6.0b7__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 (85) hide show
  1. pygeai/_docs/source/content/api_reference/admin.rst +161 -0
  2. pygeai/_docs/source/content/api_reference/assistant.rst +326 -0
  3. pygeai/_docs/source/content/api_reference/auth.rst +379 -0
  4. pygeai/_docs/source/content/api_reference/health.rst +58 -0
  5. pygeai/_docs/source/content/api_reference/project.rst +20 -18
  6. pygeai/_docs/source/content/api_reference/rerank.rst +94 -0
  7. pygeai/_docs/source/content/api_reference.rst +6 -1
  8. pygeai/_docs/source/index.rst +59 -7
  9. pygeai/_docs/source/pygeai.auth.rst +29 -0
  10. pygeai/_docs/source/pygeai.cli.commands.rst +16 -0
  11. pygeai/_docs/source/pygeai.core.utils.rst +16 -0
  12. pygeai/_docs/source/pygeai.rst +1 -0
  13. pygeai/_docs/source/pygeai.tests.auth.rst +21 -0
  14. pygeai/_docs/source/pygeai.tests.cli.commands.rst +16 -0
  15. pygeai/_docs/source/pygeai.tests.core.base.rst +8 -0
  16. pygeai/_docs/source/pygeai.tests.core.files.rst +8 -0
  17. pygeai/_docs/source/pygeai.tests.core.plugins.rst +21 -0
  18. pygeai/_docs/source/pygeai.tests.core.rst +1 -0
  19. pygeai/_docs/source/pygeai.tests.evaluation.dataset.rst +21 -0
  20. pygeai/_docs/source/pygeai.tests.evaluation.plan.rst +21 -0
  21. pygeai/_docs/source/pygeai.tests.evaluation.result.rst +21 -0
  22. pygeai/_docs/source/pygeai.tests.evaluation.rst +20 -0
  23. pygeai/_docs/source/pygeai.tests.integration.lab.processes.rst +8 -0
  24. pygeai/_docs/source/pygeai.tests.organization.rst +8 -0
  25. pygeai/_docs/source/pygeai.tests.rst +2 -0
  26. pygeai/_docs/source/pygeai.tests.snippets.auth.rst +10 -0
  27. pygeai/_docs/source/pygeai.tests.snippets.organization.rst +40 -0
  28. pygeai/_docs/source/pygeai.tests.snippets.rst +1 -0
  29. pygeai/admin/clients.py +7 -32
  30. pygeai/assistant/clients.py +9 -44
  31. pygeai/assistant/data/clients.py +1 -0
  32. pygeai/assistant/data_analyst/clients.py +4 -13
  33. pygeai/assistant/rag/clients.py +13 -67
  34. pygeai/auth/clients.py +88 -14
  35. pygeai/auth/endpoints.py +4 -0
  36. pygeai/chat/clients.py +1 -0
  37. pygeai/cli/commands/auth.py +178 -2
  38. pygeai/cli/commands/lab/ai_lab.py +0 -2
  39. pygeai/cli/commands/organization.py +241 -0
  40. pygeai/core/base/clients.py +1 -0
  41. pygeai/core/embeddings/clients.py +3 -7
  42. pygeai/core/feedback/clients.py +3 -8
  43. pygeai/core/files/clients.py +5 -18
  44. pygeai/core/llm/clients.py +7 -26
  45. pygeai/core/models.py +107 -0
  46. pygeai/core/plugins/clients.py +3 -7
  47. pygeai/core/rerank/clients.py +3 -8
  48. pygeai/core/secrets/clients.py +8 -37
  49. pygeai/core/utils/parsers.py +32 -0
  50. pygeai/core/utils/validators.py +10 -0
  51. pygeai/evaluation/clients.py +1 -0
  52. pygeai/evaluation/dataset/clients.py +1 -0
  53. pygeai/evaluation/plan/clients.py +1 -0
  54. pygeai/evaluation/result/clients.py +1 -0
  55. pygeai/gam/clients.py +6 -25
  56. pygeai/health/clients.py +3 -7
  57. pygeai/lab/agents/clients.py +13 -53
  58. pygeai/lab/agents/endpoints.py +2 -0
  59. pygeai/lab/clients.py +1 -0
  60. pygeai/lab/processes/clients.py +24 -127
  61. pygeai/lab/strategies/clients.py +7 -25
  62. pygeai/lab/tools/clients.py +22 -67
  63. pygeai/lab/tools/endpoints.py +3 -0
  64. pygeai/organization/clients.py +122 -51
  65. pygeai/organization/endpoints.py +6 -1
  66. pygeai/organization/limits/clients.py +17 -91
  67. pygeai/organization/managers.py +157 -1
  68. pygeai/organization/mappers.py +76 -2
  69. pygeai/organization/responses.py +25 -1
  70. pygeai/proxy/clients.py +1 -0
  71. pygeai/tests/auth/test_clients.py +183 -7
  72. pygeai/tests/organization/test_clients.py +184 -1
  73. pygeai/tests/organization/test_managers.py +122 -1
  74. pygeai/tests/snippets/auth/__init__.py +0 -0
  75. pygeai/tests/snippets/organization/get_memberships.py +12 -0
  76. pygeai/tests/snippets/organization/get_organization_members.py +6 -0
  77. pygeai/tests/snippets/organization/get_project_members.py +6 -0
  78. pygeai/tests/snippets/organization/get_project_memberships.py +12 -0
  79. pygeai/tests/snippets/organization/get_project_roles.py +6 -0
  80. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b7.dist-info}/METADATA +1 -1
  81. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b7.dist-info}/RECORD +85 -64
  82. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b7.dist-info}/WHEEL +0 -0
  83. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b7.dist-info}/entry_points.txt +0 -0
  84. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b7.dist-info}/licenses/LICENSE +0 -0
  85. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b7.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,9 @@
1
- from json import JSONDecodeError
2
1
 
3
2
  from pygeai import logger
4
3
  from pygeai.core.base.clients import BaseClient
5
4
  from pygeai.core.common.exceptions import InvalidAPIResponseException
5
+ from pygeai.core.utils.validators import validate_status_code
6
+ from pygeai.core.utils.parsers import parse_json_response
6
7
  from pygeai.organization.limits.endpoints import SET_ORGANIZATION_USAGE_LIMIT_V2, GET_ORGANIZATION_LATEST_USAGE_LIMIT_V2, \
7
8
  GET_ALL_ORGANIZATION_USAGE_LIMITS_V2, DELETE_ORGANIZATION_USAGE_LIMIT_V2, SET_ORGANIZATION_HARD_LIMIT_V2, \
8
9
  SET_ORGANIZATION_SOFT_LIMIT_V2, SET_ORGANIZATION_RENEWAL_STATUS_V2, SET_PROJECT_USAGE_LIMIT_V2, \
@@ -33,12 +34,7 @@ class UsageLimitClient(BaseClient):
33
34
  endpoint=endpoint,
34
35
  data=usage_limit
35
36
  )
36
- try:
37
- result = response.json()
38
- return result
39
- except JSONDecodeError as e:
40
- logger.error(f"Unable to set usage limit for organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
41
- raise InvalidAPIResponseException(f"Unable to set usage limit for organization '{organization}': {response.text}")
37
+ return parse_json_response(response, f"set usage limit for organization", organization=organization)
42
38
 
43
39
  def get_organization_latest_usage_limit(self, organization: str) -> dict:
44
40
  """
@@ -49,12 +45,7 @@ class UsageLimitClient(BaseClient):
49
45
  """
50
46
  endpoint = GET_ORGANIZATION_LATEST_USAGE_LIMIT_V2.format(organization=organization)
51
47
  response = self.api_service.get(endpoint=endpoint)
52
- try:
53
- result = response.json()
54
- return result
55
- except JSONDecodeError as e:
56
- logger.error(f"Unable to get latest usage limit for organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
57
- raise InvalidAPIResponseException(f"Unable to get latest usage limit for organization '{organization}': {response.text}")
48
+ return parse_json_response(response, f"get latest usage limit for organization", organization=organization)
58
49
 
59
50
  def get_all_usage_limits_from_organization(self, organization: str) -> dict:
60
51
  """
@@ -65,12 +56,7 @@ class UsageLimitClient(BaseClient):
65
56
  """
66
57
  endpoint = GET_ALL_ORGANIZATION_USAGE_LIMITS_V2.format(organization=organization)
67
58
  response = self.api_service.get(endpoint=endpoint)
68
- try:
69
- result = response.json()
70
- return result
71
- except JSONDecodeError as e:
72
- logger.error(f"Unable to get all usage limits for organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
73
- raise InvalidAPIResponseException(f"Unable to get all usage limits for organization '{organization}': {response.text}")
59
+ return parse_json_response(response, f"get all usage limits for organization", organization=organization)
74
60
 
75
61
  def delete_usage_limit_from_organization(self, organization: str, limit_id: str) -> dict:
76
62
  """
@@ -82,12 +68,7 @@ class UsageLimitClient(BaseClient):
82
68
  """
83
69
  endpoint = DELETE_ORGANIZATION_USAGE_LIMIT_V2.format(organization=organization, id=limit_id)
84
70
  response = self.api_service.delete(endpoint=endpoint)
85
- try:
86
- result = response.json()
87
- return result
88
- except JSONDecodeError as e:
89
- logger.error(f"Unable to delete usage limit with ID '{limit_id}' from organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
90
- raise InvalidAPIResponseException(f"Unable to delete usage limit with ID '{limit_id}' from organization '{organization}': {response.text}")
71
+ return parse_json_response(response, f"delete usage limit with ID '{limit_id}' from organization", organization=organization)
91
72
 
92
73
  def set_organization_hard_limit(self, organization: str, limit_id: str, hard_limit: float) -> dict:
93
74
  """
@@ -105,12 +86,7 @@ class UsageLimitClient(BaseClient):
105
86
  "hardLimit": hard_limit
106
87
  }
107
88
  )
108
- try:
109
- result = response.json()
110
- return result
111
- except JSONDecodeError as e:
112
- logger.error(f"Unable to set hard limit for usage limit ID '{limit_id}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
113
- raise InvalidAPIResponseException(f"Unable to set hard limit for usage limit ID '{limit_id}' in organization '{organization}': {response.text}")
89
+ return parse_json_response(response, f"set hard limit for usage limit ID '{limit_id}' in organization", organization=organization)
114
90
 
115
91
  def set_organization_soft_limit(self, organization: str, limit_id: str, soft_limit: float) -> dict:
116
92
  """
@@ -128,12 +104,7 @@ class UsageLimitClient(BaseClient):
128
104
  "softLimit": soft_limit
129
105
  }
130
106
  )
131
- try:
132
- result = response.json()
133
- return result
134
- except JSONDecodeError as e:
135
- logger.error(f"Unable to set soft limit for usage limit ID '{limit_id}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
136
- raise InvalidAPIResponseException(f"Unable to set soft limit for usage limit ID '{limit_id}' in organization '{organization}': {response.text}")
107
+ return parse_json_response(response, f"set soft limit for usage limit ID '{limit_id}' in organization", organization=organization)
137
108
 
138
109
  def set_organization_renewal_status(self, organization: str, limit_id: str, renewal_status: str) -> dict:
139
110
  """
@@ -151,12 +122,7 @@ class UsageLimitClient(BaseClient):
151
122
  "renewalStatus": renewal_status
152
123
  }
153
124
  )
154
- try:
155
- result = response.json()
156
- return result
157
- except JSONDecodeError as e:
158
- logger.error(f"Unable to set renewal status for usage limit ID '{limit_id}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
159
- raise InvalidAPIResponseException(f"Unable to set renewal status for usage limit ID '{limit_id}' in organization '{organization}': {response.text}")
125
+ return parse_json_response(response, f"set renewal status for usage limit ID '{limit_id}' in organization", organization=organization)
160
126
 
161
127
  def set_project_usage_limit(self, organization: str, project: str, usage_limit: dict) -> dict:
162
128
  """
@@ -179,12 +145,7 @@ class UsageLimitClient(BaseClient):
179
145
  endpoint=endpoint,
180
146
  data=usage_limit
181
147
  )
182
- try:
183
- result = response.json()
184
- return result
185
- except JSONDecodeError as e:
186
- logger.error(f"Unable to set usage limit for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
187
- raise InvalidAPIResponseException(f"Unable to set usage limit for project '{project}' in organization '{organization}': {response.text}")
148
+ return parse_json_response(response, f"set usage limit for project '{project}' in organization", organization=organization)
188
149
 
189
150
  def get_all_usage_limits_from_project(self, organization: str, project: str) -> dict:
190
151
  """
@@ -196,12 +157,7 @@ class UsageLimitClient(BaseClient):
196
157
  """
197
158
  endpoint = GET_ALL_PROJECT_USAGE_LIMIT_V2.format(organization=organization, project=project)
198
159
  response = self.api_service.get(endpoint=endpoint)
199
- try:
200
- result = response.json()
201
- return result
202
- except JSONDecodeError as e:
203
- logger.error(f"Unable to get all usage limits for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
204
- raise InvalidAPIResponseException(f"Unable to get all usage limits for project '{project}' in organization '{organization}': {response.text}")
160
+ return parse_json_response(response, f"get all usage limits for project '{project}' in organization", organization=organization)
205
161
 
206
162
  def get_latest_usage_limit_from_project(self, organization: str, project: str) -> dict:
207
163
  """
@@ -213,12 +169,7 @@ class UsageLimitClient(BaseClient):
213
169
  """
214
170
  endpoint = GET_LATEST_PROJECT_USAGE_LIMIT_V2.format(organization=organization, project=project)
215
171
  response = self.api_service.get(endpoint=endpoint)
216
- try:
217
- result = response.json()
218
- return result
219
- except JSONDecodeError as e:
220
- logger.error(f"Unable to get latest usage limit for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
221
- raise InvalidAPIResponseException(f"Unable to get latest usage limit for project '{project}' in organization '{organization}': {response.text}")
172
+ return parse_json_response(response, f"get latest usage limit for project '{project}' in organization", organization=organization)
222
173
 
223
174
  def get_active_usage_limit_from_project(self, organization: str, project: str) -> dict:
224
175
  """
@@ -230,12 +181,7 @@ class UsageLimitClient(BaseClient):
230
181
  """
231
182
  endpoint = GET_PROJECT_ACTIVE_USAGE_LIMIT_V2.format(organization=organization, project=project)
232
183
  response = self.api_service.get(endpoint=endpoint)
233
- try:
234
- result = response.json()
235
- return result
236
- except JSONDecodeError as e:
237
- logger.error(f"Unable to get active usage limit for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
238
- raise InvalidAPIResponseException(f"Unable to get active usage limit for project '{project}' in organization '{organization}': {response.text}")
184
+ return parse_json_response(response, f"get active usage limit for project '{project}' in organization", organization=organization)
239
185
 
240
186
  def delete_usage_limit_from_project(self, organization: str, project: str, limit_id: str) -> dict:
241
187
  """
@@ -248,12 +194,7 @@ class UsageLimitClient(BaseClient):
248
194
  """
249
195
  endpoint = DELETE_PROJECT_USAGE_LIMIT_V2.format(organization=organization, project=project, id=limit_id)
250
196
  response = self.api_service.delete(endpoint=endpoint)
251
- try:
252
- result = response.json()
253
- return result
254
- except JSONDecodeError as e:
255
- logger.error(f"Unable to delete usage limit with ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
256
- raise InvalidAPIResponseException(f"Unable to delete usage limit with ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
197
+ return parse_json_response(response, f"delete usage limit with ID '{limit_id}' for project '{project}' in organization", organization=organization)
257
198
 
258
199
  def set_hard_limit_for_active_usage_limit_from_project(
259
200
  self,
@@ -278,12 +219,7 @@ class UsageLimitClient(BaseClient):
278
219
  "hardLimit": hard_limit
279
220
  }
280
221
  )
281
- try:
282
- result = response.json()
283
- return result
284
- except JSONDecodeError as e:
285
- logger.error(f"Unable to set hard limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
286
- raise InvalidAPIResponseException(f"Unable to set hard limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
222
+ return parse_json_response(response, f"set hard limit for usage limit ID '{limit_id}' for project '{project}' in organization", organization=organization)
287
223
 
288
224
  def set_soft_limit_for_active_usage_limit_from_project(
289
225
  self,
@@ -308,12 +244,7 @@ class UsageLimitClient(BaseClient):
308
244
  "softLimit": soft_limit
309
245
  }
310
246
  )
311
- try:
312
- result = response.json()
313
- return result
314
- except JSONDecodeError as e:
315
- logger.error(f"Unable to set soft limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
316
- raise InvalidAPIResponseException(f"Unable to set soft limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
247
+ return parse_json_response(response, f"set soft limit for usage limit ID '{limit_id}' for project '{project}' in organization", organization=organization)
317
248
 
318
249
  def set_project_renewal_status(self, organization: str, project: str, limit_id: str, renewal_status: str) -> dict:
319
250
  """
@@ -332,9 +263,4 @@ class UsageLimitClient(BaseClient):
332
263
  "renewalStatus": renewal_status
333
264
  }
334
265
  )
335
- try:
336
- result = response.json()
337
- return result
338
- except JSONDecodeError as e:
339
- logger.error(f"Unable to set renewal status for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
340
- raise InvalidAPIResponseException(f"Unable to set renewal status for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
266
+ return parse_json_response(response, f"set renewal status for usage limit ID '{limit_id}' for project '{project}' in organization", organization=organization)
@@ -6,7 +6,8 @@ from pygeai.core.base.responses import EmptyResponse
6
6
  from pygeai.organization.clients import OrganizationClient
7
7
  from pygeai.organization.mappers import OrganizationResponseMapper
8
8
  from pygeai.organization.responses import AssistantListResponse, ProjectListResponse, ProjectDataResponse, \
9
- ProjectTokensResponse, ProjectItemListResponse
9
+ ProjectTokensResponse, ProjectItemListResponse, MembershipsResponse, ProjectMembershipsResponse, \
10
+ ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse
10
11
  from pygeai.core.common.exceptions import APIError
11
12
 
12
13
 
@@ -247,3 +248,158 @@ class OrganizationManager:
247
248
 
248
249
  result = OrganizationResponseMapper.map_to_item_list_response(response_data)
249
250
  return result
251
+
252
+ def get_memberships(
253
+ self,
254
+ email: str = None,
255
+ start_page: int = 1,
256
+ page_size: int = 20,
257
+ order_key: str = None,
258
+ order_direction: str = "desc",
259
+ role_types: str = None
260
+ ) -> MembershipsResponse:
261
+ """
262
+ Retrieves a list of Organizations and Projects a user belongs to with their Roles.
263
+
264
+ This method calls `OrganizationClient.get_memberships` to fetch membership data
265
+ and maps the response using `OrganizationResponseMapper.map_to_memberships_response`.
266
+
267
+ :param email: str, optional - The email address of the user to search for (case-insensitive).
268
+ :param start_page: int - The page number for pagination (default is 1).
269
+ :param page_size: int - The number of items per page (default is 20).
270
+ :param order_key: str, optional - Field for sorting. Only 'organizationName' is supported.
271
+ :param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
272
+ :param role_types: str, optional - Comma-separated list of role types: 'backend', 'frontend' (case-insensitive).
273
+ :return: MembershipsResponse - The mapped response containing organizations and projects with roles.
274
+ :raises APIError: If the API returns errors.
275
+ """
276
+ response_data = self.__organization_client.get_memberships(
277
+ email=email,
278
+ start_page=start_page,
279
+ page_size=page_size,
280
+ order_key=order_key,
281
+ order_direction=order_direction,
282
+ role_types=role_types
283
+ )
284
+ if ErrorHandler.has_errors(response_data):
285
+ error = ErrorHandler.extract_error(response_data)
286
+ logger.error(f"Error received while retrieving memberships: {error}")
287
+ raise APIError(f"Error received while retrieving memberships: {error}")
288
+
289
+ result = OrganizationResponseMapper.map_to_memberships_response(response_data)
290
+ return result
291
+
292
+ def get_project_memberships(
293
+ self,
294
+ email: str = None,
295
+ start_page: int = 1,
296
+ page_size: int = 20,
297
+ order_key: str = None,
298
+ order_direction: str = "desc",
299
+ role_types: str = None
300
+ ) -> ProjectMembershipsResponse:
301
+ """
302
+ Retrieves a list of Projects and Roles for a user within a specific Organization.
303
+
304
+ This method calls `OrganizationClient.get_project_memberships` to fetch project membership data
305
+ and maps the response using `OrganizationResponseMapper.map_to_project_memberships_response`.
306
+
307
+ :param email: str, optional - The email address of the user to search for (case-insensitive).
308
+ :param start_page: int - The page number for pagination (default is 1).
309
+ :param page_size: int - The number of items per page (default is 20).
310
+ :param order_key: str, optional - Field for sorting. Only 'projectName' is supported.
311
+ :param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
312
+ :param role_types: str, optional - Comma-separated list of role types: 'backend', 'frontend' (case-insensitive).
313
+ :return: ProjectMembershipsResponse - The mapped response containing projects with roles.
314
+ :raises APIError: If the API returns errors.
315
+ """
316
+ response_data = self.__organization_client.get_project_memberships(
317
+ email=email,
318
+ start_page=start_page,
319
+ page_size=page_size,
320
+ order_key=order_key,
321
+ order_direction=order_direction,
322
+ role_types=role_types
323
+ )
324
+ if ErrorHandler.has_errors(response_data):
325
+ error = ErrorHandler.extract_error(response_data)
326
+ logger.error(f"Error received while retrieving project memberships: {error}")
327
+ raise APIError(f"Error received while retrieving project memberships: {error}")
328
+
329
+ result = OrganizationResponseMapper.map_to_project_memberships_response(response_data)
330
+ return result
331
+
332
+ def get_project_roles(
333
+ self,
334
+ project_id: str
335
+ ) -> ProjectRolesResponse:
336
+ """
337
+ Retrieves all Roles supported by a specific Project.
338
+
339
+ This method calls `OrganizationClient.get_project_roles` to fetch project roles
340
+ and maps the response using `OrganizationResponseMapper.map_to_project_roles_response`.
341
+
342
+ :param project_id: str - The unique identifier of the project.
343
+ :return: ProjectRolesResponse - The mapped response containing the list of roles.
344
+ :raises APIError: If the API returns errors.
345
+ """
346
+ response_data = self.__organization_client.get_project_roles(
347
+ project_id=project_id
348
+ )
349
+ if ErrorHandler.has_errors(response_data):
350
+ error = ErrorHandler.extract_error(response_data)
351
+ logger.error(f"Error received while retrieving project roles: {error}")
352
+ raise APIError(f"Error received while retrieving project roles: {error}")
353
+
354
+ result = OrganizationResponseMapper.map_to_project_roles_response(response_data)
355
+ return result
356
+
357
+ def get_project_members(
358
+ self,
359
+ project_id: str
360
+ ) -> ProjectMembersResponse:
361
+ """
362
+ Retrieves all members and their Roles for a specific Project.
363
+
364
+ This method calls `OrganizationClient.get_project_members` to fetch project members
365
+ and maps the response using `OrganizationResponseMapper.map_to_project_members_response`.
366
+
367
+ :param project_id: str - The unique identifier of the project.
368
+ :return: ProjectMembersResponse - The mapped response containing members with their roles.
369
+ :raises APIError: If the API returns errors.
370
+ """
371
+ response_data = self.__organization_client.get_project_members(
372
+ project_id=project_id
373
+ )
374
+ if ErrorHandler.has_errors(response_data):
375
+ error = ErrorHandler.extract_error(response_data)
376
+ logger.error(f"Error received while retrieving project members: {error}")
377
+ raise APIError(f"Error received while retrieving project members: {error}")
378
+
379
+ result = OrganizationResponseMapper.map_to_project_members_response(response_data)
380
+ return result
381
+
382
+ def get_organization_members(
383
+ self,
384
+ organization_id: str
385
+ ) -> OrganizationMembersResponse:
386
+ """
387
+ Retrieves all members and their Roles for a specific Organization.
388
+
389
+ This method calls `OrganizationClient.get_organization_members` to fetch organization members
390
+ and maps the response using `OrganizationResponseMapper.map_to_organization_members_response`.
391
+
392
+ :param organization_id: str - The unique identifier of the organization.
393
+ :return: OrganizationMembersResponse - The mapped response containing members with their roles.
394
+ :raises APIError: If the API returns errors.
395
+ """
396
+ response_data = self.__organization_client.get_organization_members(
397
+ organization_id=organization_id
398
+ )
399
+ if ErrorHandler.has_errors(response_data):
400
+ error = ErrorHandler.extract_error(response_data)
401
+ logger.error(f"Error received while retrieving organization members: {error}")
402
+ raise APIError(f"Error received while retrieving organization members: {error}")
403
+
404
+ result = OrganizationResponseMapper.map_to_organization_members_response(response_data)
405
+ return result
@@ -1,7 +1,8 @@
1
1
  from pygeai.core.base.mappers import ModelMapper
2
- from pygeai.core.models import Assistant, Project
2
+ from pygeai.core.models import Assistant, Project, Role, Member, OrganizationMembership, ProjectMembership
3
3
  from pygeai.organization.responses import AssistantListResponse, ProjectListResponse, ProjectDataResponse, \
4
- ProjectTokensResponse, ProjectItemListResponse
4
+ ProjectTokensResponse, ProjectItemListResponse, MembershipsResponse, ProjectMembershipsResponse, \
5
+ ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse
5
6
 
6
7
 
7
8
  class OrganizationResponseMapper:
@@ -76,3 +77,76 @@ class OrganizationResponseMapper:
76
77
  items=item_list
77
78
  )
78
79
 
80
+ @classmethod
81
+ def map_to_memberships_response(cls, data: dict) -> MembershipsResponse:
82
+ count = data.get("count", 0)
83
+ pages = data.get("pages", 0)
84
+ organizations_data = data.get("organizations", [])
85
+ organizations = []
86
+
87
+ for org_data in organizations_data:
88
+ org = OrganizationMembership.model_validate(org_data)
89
+ organizations.append(org)
90
+
91
+ return MembershipsResponse(
92
+ count=count,
93
+ pages=pages,
94
+ organizations=organizations
95
+ )
96
+
97
+ @classmethod
98
+ def map_to_project_memberships_response(cls, data: dict) -> ProjectMembershipsResponse:
99
+ count = data.get("count", 0)
100
+ pages = data.get("pages", 0)
101
+ projects_data = data.get("projects", [])
102
+ projects = []
103
+
104
+ for project_data in projects_data:
105
+ project = ProjectMembership.model_validate(project_data)
106
+ projects.append(project)
107
+
108
+ return ProjectMembershipsResponse(
109
+ count=count,
110
+ pages=pages,
111
+ projects=projects
112
+ )
113
+
114
+ @classmethod
115
+ def map_to_project_roles_response(cls, data: dict) -> ProjectRolesResponse:
116
+ roles_data = data.get("roles", [])
117
+ roles = []
118
+
119
+ for role_data in roles_data:
120
+ role = Role.model_validate(role_data)
121
+ roles.append(role)
122
+
123
+ return ProjectRolesResponse(
124
+ roles=roles
125
+ )
126
+
127
+ @classmethod
128
+ def map_to_project_members_response(cls, data: dict) -> ProjectMembersResponse:
129
+ members_data = data.get("members", [])
130
+ members = []
131
+
132
+ for member_data in members_data:
133
+ member = Member.model_validate(member_data)
134
+ members.append(member)
135
+
136
+ return ProjectMembersResponse(
137
+ members=members
138
+ )
139
+
140
+ @classmethod
141
+ def map_to_organization_members_response(cls, data: dict) -> OrganizationMembersResponse:
142
+ members_data = data.get("members", [])
143
+ members = []
144
+
145
+ for member_data in members_data:
146
+ member = Member.model_validate(member_data)
147
+ members.append(member)
148
+
149
+ return OrganizationMembersResponse(
150
+ members=members
151
+ )
152
+
@@ -1,7 +1,7 @@
1
1
  from pydantic.main import BaseModel
2
2
 
3
3
  from pygeai.core.models import Assistant, Project, ProjectToken, \
4
- RequestItem
4
+ RequestItem, Role, Member, OrganizationMembership, ProjectMembership
5
5
 
6
6
 
7
7
  class AssistantListResponse(BaseModel):
@@ -45,3 +45,27 @@ class ProjectItemListResponse(BaseModel):
45
45
  if self.items is None:
46
46
  self.items = []
47
47
  self.items.append(item)
48
+
49
+
50
+ class MembershipsResponse(BaseModel):
51
+ count: int
52
+ pages: int
53
+ organizations: list[OrganizationMembership]
54
+
55
+
56
+ class ProjectMembershipsResponse(BaseModel):
57
+ count: int
58
+ pages: int
59
+ projects: list[ProjectMembership]
60
+
61
+
62
+ class ProjectRolesResponse(BaseModel):
63
+ roles: list[Role]
64
+
65
+
66
+ class ProjectMembersResponse(BaseModel):
67
+ members: list[Member]
68
+
69
+
70
+ class OrganizationMembersResponse(BaseModel):
71
+ members: list[Member]
pygeai/proxy/clients.py CHANGED
@@ -4,6 +4,7 @@ import uuid
4
4
  import requests
5
5
  from urllib3.exceptions import MaxRetryError
6
6
  from pygeai.proxy.tool import ProxiedTool
7
+ from pygeai.core.utils.validators import validate_status_code
7
8
 
8
9
 
9
10
  @dataclass