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
@@ -288,6 +288,202 @@ export_request_data_options = [
288
288
  )
289
289
  ]
290
290
 
291
+
292
+ def get_memberships(option_list: list):
293
+ email = None
294
+ start_page = 1
295
+ page_size = 20
296
+ order_key = None
297
+ order_direction = "desc"
298
+ role_types = None
299
+
300
+ for option_flag, option_arg in option_list:
301
+ if option_flag.name == "email":
302
+ email = option_arg
303
+ if option_flag.name == "start_page":
304
+ start_page = int(option_arg)
305
+ if option_flag.name == "page_size":
306
+ page_size = int(option_arg)
307
+ if option_flag.name == "order_key":
308
+ order_key = option_arg
309
+ if option_flag.name == "order_direction":
310
+ order_direction = option_arg
311
+ if option_flag.name == "role_types":
312
+ role_types = option_arg
313
+
314
+ client = OrganizationClient()
315
+ result = client.get_memberships(email, start_page, page_size, order_key, order_direction, role_types)
316
+ Console.write_stdout(f"Memberships: \n{result}")
317
+
318
+
319
+ get_memberships_options = [
320
+ Option(
321
+ "email",
322
+ ["--email", "-e"],
323
+ "Email address of the user (optional, case-insensitive)",
324
+ True
325
+ ),
326
+ Option(
327
+ "start_page",
328
+ ["--start-page"],
329
+ "Page number for pagination (default: 1)",
330
+ True
331
+ ),
332
+ Option(
333
+ "page_size",
334
+ ["--page-size"],
335
+ "Number of items per page (default: 20)",
336
+ True
337
+ ),
338
+ Option(
339
+ "order_key",
340
+ ["--order-key"],
341
+ "Field for sorting (only 'organizationName' supported)",
342
+ True
343
+ ),
344
+ Option(
345
+ "order_direction",
346
+ ["--order-direction"],
347
+ "Sort direction: asc or desc (default: desc)",
348
+ True
349
+ ),
350
+ Option(
351
+ "role_types",
352
+ ["--role-types"],
353
+ "Comma-separated list: backend, frontend (optional, case-insensitive)",
354
+ True
355
+ ),
356
+ ]
357
+
358
+
359
+ def get_project_memberships(option_list: list):
360
+ email = None
361
+ start_page = 1
362
+ page_size = 20
363
+ order_key = None
364
+ order_direction = "desc"
365
+ role_types = None
366
+
367
+ for option_flag, option_arg in option_list:
368
+ if option_flag.name == "email":
369
+ email = option_arg
370
+ if option_flag.name == "start_page":
371
+ start_page = int(option_arg)
372
+ if option_flag.name == "page_size":
373
+ page_size = int(option_arg)
374
+ if option_flag.name == "order_key":
375
+ order_key = option_arg
376
+ if option_flag.name == "order_direction":
377
+ order_direction = option_arg
378
+ if option_flag.name == "role_types":
379
+ role_types = option_arg
380
+
381
+ client = OrganizationClient()
382
+ result = client.get_project_memberships(email, start_page, page_size, order_key, order_direction, role_types)
383
+ Console.write_stdout(f"Project memberships: \n{result}")
384
+
385
+
386
+ get_project_memberships_options = [
387
+ Option(
388
+ "email",
389
+ ["--email", "-e"],
390
+ "Email address of the user (optional, case-insensitive)",
391
+ True
392
+ ),
393
+ Option(
394
+ "start_page",
395
+ ["--start-page"],
396
+ "Page number for pagination (default: 1)",
397
+ True
398
+ ),
399
+ Option(
400
+ "page_size",
401
+ ["--page-size"],
402
+ "Number of items per page (default: 20)",
403
+ True
404
+ ),
405
+ Option(
406
+ "order_key",
407
+ ["--order-key"],
408
+ "Field for sorting (only 'projectName' supported)",
409
+ True
410
+ ),
411
+ Option(
412
+ "order_direction",
413
+ ["--order-direction"],
414
+ "Sort direction: asc or desc (default: desc)",
415
+ True
416
+ ),
417
+ Option(
418
+ "role_types",
419
+ ["--role-types"],
420
+ "Comma-separated list: backend, frontend (optional, case-insensitive)",
421
+ True
422
+ ),
423
+ ]
424
+
425
+
426
+ def get_project_roles(option_list: list):
427
+ project_id = None
428
+ for option_flag, option_arg in option_list:
429
+ if option_flag.name == "project_id":
430
+ project_id = option_arg
431
+
432
+ if not project_id:
433
+ raise MissingRequirementException("Cannot retrieve project roles without project-id")
434
+
435
+ client = OrganizationClient()
436
+ result = client.get_project_roles(project_id)
437
+ Console.write_stdout(f"Project roles: \n{result}")
438
+
439
+
440
+ get_project_roles_options = [
441
+ PROJECT_ID_OPTION,
442
+ ]
443
+
444
+
445
+ def get_project_members(option_list: list):
446
+ project_id = None
447
+ for option_flag, option_arg in option_list:
448
+ if option_flag.name == "project_id":
449
+ project_id = option_arg
450
+
451
+ if not project_id:
452
+ raise MissingRequirementException("Cannot retrieve project members without project-id")
453
+
454
+ client = OrganizationClient()
455
+ result = client.get_project_members(project_id)
456
+ Console.write_stdout(f"Project members: \n{result}")
457
+
458
+
459
+ get_project_members_options = [
460
+ PROJECT_ID_OPTION,
461
+ ]
462
+
463
+
464
+ def get_organization_members(option_list: list):
465
+ organization_id = None
466
+ for option_flag, option_arg in option_list:
467
+ if option_flag.name == "organization_id":
468
+ organization_id = option_arg
469
+
470
+ if not organization_id:
471
+ raise MissingRequirementException("Cannot retrieve organization members without organization-id")
472
+
473
+ client = OrganizationClient()
474
+ result = client.get_organization_members(organization_id)
475
+ Console.write_stdout(f"Organization members: \n{result}")
476
+
477
+
478
+ get_organization_members_options = [
479
+ Option(
480
+ "organization_id",
481
+ ["--organization-id", "--oid"],
482
+ "GUID of the organization (required)",
483
+ True
484
+ ),
485
+ ]
486
+
291
487
  organization_commands = [
292
488
  Command(
293
489
  "help",
@@ -370,4 +566,49 @@ organization_commands = [
370
566
  [],
371
567
  export_request_data_options
372
568
  ),
569
+ Command(
570
+ "get_memberships",
571
+ ["get-memberships"],
572
+ "Get user memberships across organizations and projects",
573
+ get_memberships,
574
+ ArgumentsEnum.OPTIONAL,
575
+ [],
576
+ get_memberships_options
577
+ ),
578
+ Command(
579
+ "get_project_memberships",
580
+ ["get-project-memberships"],
581
+ "Get user project memberships within an organization",
582
+ get_project_memberships,
583
+ ArgumentsEnum.OPTIONAL,
584
+ [],
585
+ get_project_memberships_options
586
+ ),
587
+ Command(
588
+ "get_project_roles",
589
+ ["get-project-roles"],
590
+ "Get all roles supported by a project",
591
+ get_project_roles,
592
+ ArgumentsEnum.REQUIRED,
593
+ [],
594
+ get_project_roles_options
595
+ ),
596
+ Command(
597
+ "get_project_members",
598
+ ["get-project-members"],
599
+ "Get all members and their roles for a project",
600
+ get_project_members,
601
+ ArgumentsEnum.REQUIRED,
602
+ [],
603
+ get_project_members_options
604
+ ),
605
+ Command(
606
+ "get_organization_members",
607
+ ["get-organization-members"],
608
+ "Get all members and their roles for an organization",
609
+ get_organization_members,
610
+ ArgumentsEnum.REQUIRED,
611
+ [],
612
+ get_organization_members_options
613
+ ),
373
614
  ]
@@ -3,6 +3,7 @@ from abc import ABC
3
3
  from pygeai.core.base.session import get_session, Session
4
4
  from pygeai.core.common.exceptions import MissingRequirementException
5
5
  from pygeai.core.services.rest import ApiService
6
+ from pygeai.core.utils.validators import validate_status_code
6
7
 
7
8
 
8
9
  class BaseClient(ABC):
@@ -1,9 +1,10 @@
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
6
5
  from pygeai.core.embeddings.endpoints import GENERATE_EMBEDDINGS
6
+ from pygeai.core.utils.validators import validate_status_code
7
+ from pygeai.core.utils.parsers import parse_json_response
7
8
 
8
9
 
9
10
  class EmbeddingsClient(BaseClient):
@@ -73,10 +74,5 @@ class EmbeddingsClient(BaseClient):
73
74
  data=data,
74
75
  headers=headers
75
76
  )
76
- try:
77
- result = response.json()
78
- return result
79
- except JSONDecodeError as e:
80
- logger.error(f"Unable to generate embeddings: JSON parsin error: {e}; Response: {response.text}")
81
- raise InvalidAPIResponseException(f"Unable to generate embeddings: {response.text}")
77
+ return parse_json_response(response, "generate embeddings")
82
78
 
@@ -1,11 +1,11 @@
1
- import json
2
- from json import JSONDecodeError
3
1
  from typing import Any, Union
4
2
 
5
3
  from pygeai import logger
6
4
  from pygeai.core.base.clients import BaseClient
7
5
  from pygeai.core.common.exceptions import InvalidAPIResponseException
8
6
  from pygeai.core.feedback.endpoints import SEND_FEEDBACK_V1
7
+ from pygeai.core.utils.validators import validate_status_code
8
+ from pygeai.core.utils.parsers import parse_json_response
9
9
 
10
10
 
11
11
  class FeedbackClient(BaseClient):
@@ -45,10 +45,5 @@ class FeedbackClient(BaseClient):
45
45
  endpoint=endpoint,
46
46
  data=data
47
47
  )
48
- try:
49
- result = response.json()
50
- return result
51
- except JSONDecodeError as e:
52
- logger.error(f"Unable to send feedback. JSON parsing error: {e}. Response: {e}")
53
- raise InvalidAPIResponseException(f"Unable to send feedback for request {request_id}: {response.text}")
48
+ return parse_json_response(response, "send feedback. JSON parsing error")
54
49
 
@@ -7,6 +7,8 @@ from pygeai.core.base.clients import BaseClient
7
7
  from pygeai.core.common.exceptions import InvalidAPIResponseException
8
8
  from pygeai.core.files.endpoints import UPLOAD_FILE_V1, GET_FILE_V1, DELETE_FILE_V1, GET_FILE_CONTENT_V1, \
9
9
  GET_ALL_FILES_V1
10
+ from pygeai.core.utils.validators import validate_status_code
11
+ from pygeai.core.utils.parsers import parse_json_response
10
12
 
11
13
 
12
14
  class FileClient(BaseClient):
@@ -82,12 +84,7 @@ class FileClient(BaseClient):
82
84
  }
83
85
  )
84
86
  logger.debug(f"Retrieving file details for id {file_id}")
85
- try:
86
- result = response.json()
87
- return result
88
- except JSONDecodeError as e:
89
- logger.error(f"Unable to retrieve file details for id {file_id} in project {project}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
90
- raise InvalidAPIResponseException(f"Unable to retrieve file details for id {file_id}: {response.text}")
87
+ return parse_json_response(response, "retrieve file details for id in project", file_id=file_id, project=project)
91
88
 
92
89
  def delete_file(self, organization: str, project: str, file_id: str) -> dict:
93
90
  """
@@ -113,12 +110,7 @@ class FileClient(BaseClient):
113
110
  "project": project
114
111
  }
115
112
  )
116
- try:
117
- result = response.json()
118
- return result
119
- except JSONDecodeError as e:
120
- logger.error(f"Unable to delete file with id {file_id} in project {project}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
121
- raise InvalidAPIResponseException(f"Unable to delete file with id {file_id}: {response.text}")
113
+ return parse_json_response(response, "delete file with id in project", file_id=file_id, project=project)
122
114
 
123
115
  def get_file_content(self, organization: str, project: str, file_id: str) -> bytes:
124
116
  """
@@ -163,9 +155,4 @@ class FileClient(BaseClient):
163
155
  "project": project
164
156
  }
165
157
  )
166
- try:
167
- result = response.json()
168
- return result
169
- except JSONDecodeError as e:
170
- logger.error(f"Unable to retrieve file list for project {project}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
171
- raise InvalidAPIResponseException(f"Unable to retrieve file list for project {project}: {response.text}")
158
+ return parse_json_response(response, "retrieve file list for project", project=project)
@@ -1,11 +1,11 @@
1
- import json
2
- from json import JSONDecodeError
3
1
 
4
2
  from pygeai import logger
5
3
  from pygeai.core.base.clients import BaseClient
6
4
  from pygeai.core.common.exceptions import InvalidAPIResponseException
7
5
  from pygeai.core.llm.endpoints import GET_PROVIDER_LIST_V2, GET_PROVIDER_DATA_V2, GET_PROVIDER_MODELS_V2, \
8
6
  GET_MODEL_DATA_V2
7
+ from pygeai.core.utils.validators import validate_status_code
8
+ from pygeai.core.utils.parsers import parse_json_response
9
9
 
10
10
 
11
11
  class LlmClient(BaseClient):
@@ -13,12 +13,7 @@ class LlmClient(BaseClient):
13
13
  def get_provider_list(self) -> dict:
14
14
  logger.debug("Obtaining provider list")
15
15
  response = self.api_service.get(endpoint=GET_PROVIDER_LIST_V2)
16
- try:
17
- result = response.json()
18
- return result
19
- except JSONDecodeError as e:
20
- logger.error(f"Unable to obtain provider list: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
21
- raise InvalidAPIResponseException(f"Unable to obtain provider list: {response.text}")
16
+ return parse_json_response(response, "obtain provider list")
22
17
 
23
18
  def get_provider_data(self, provider_name: str) -> dict:
24
19
  endpoint = GET_PROVIDER_DATA_V2.format(providerName=provider_name)
@@ -26,12 +21,7 @@ class LlmClient(BaseClient):
26
21
  logger.debug(f"Obtaining provider data for {provider_name}")
27
22
 
28
23
  response = self.api_service.get(endpoint=endpoint)
29
- try:
30
- result = response.json()
31
- return result
32
- except JSONDecodeError as e:
33
- logger.error(f"Unable to obtain provider data for {provider_name}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
34
- raise InvalidAPIResponseException(f"Unable to obtain provider data for {provider_name}: {response.text}")
24
+ return parse_json_response(response, "obtain provider data", provider_name=provider_name)
35
25
 
36
26
  def get_provider_models(self, provider_name: str) -> dict:
37
27
  endpoint = GET_PROVIDER_MODELS_V2.format(providerName=provider_name)
@@ -39,12 +29,7 @@ class LlmClient(BaseClient):
39
29
  logger.debug(f"Obtaining provider models for {provider_name}")
40
30
 
41
31
  response = self.api_service.get(endpoint=endpoint)
42
- try:
43
- result = response.json()
44
- return result
45
- except JSONDecodeError as e:
46
- logger.error(f"Unable to obtain provider models for {provider_name}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
47
- raise InvalidAPIResponseException(f"Unable to obtain provider models for {provider_name}: {response.text}")
32
+ return parse_json_response(response, "obtain provider models", provider_name=provider_name)
48
33
 
49
34
  def get_model_data(
50
35
  self,
@@ -60,9 +45,5 @@ class LlmClient(BaseClient):
60
45
  logger.debug(f"Obtaining model data for {provider_name}/{model_name or model_id}")
61
46
 
62
47
  response = self.api_service.get(endpoint=endpoint)
63
- try:
64
- result = response.json()
65
- return result
66
- except JSONDecodeError as e:
67
- logger.error(f"Unable to obtain model data for {provider_name}/{model_name or model_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
68
- raise InvalidAPIResponseException(f"Unable to obtain model data for {provider_name}/{model_name or model_id}: {response.text}")
48
+ model_identifier = model_name or model_id
49
+ return parse_json_response(response, f"obtain model data for {provider_name}/{model_identifier}")
pygeai/core/models.py CHANGED
@@ -690,3 +690,110 @@ class DataAnalystAssistant(Assistant):
690
690
 
691
691
  class ChatWithDataAssistant(Assistant):
692
692
  type: Literal["ChatWithData"] = "ChatWithData"
693
+
694
+
695
+ class Role(CustomBaseModel):
696
+ """
697
+ {
698
+ "id": "string",
699
+ "name": "string",
700
+ "externalId": "string",
701
+ "type": "string",
702
+ "origin": "string"
703
+ }
704
+ """
705
+ id: str = Field(..., alias="id")
706
+ name: str = Field(..., alias="name")
707
+ external_id: Optional[str] = Field(None, alias="externalId")
708
+ type: Optional[str] = Field(None, alias="type")
709
+ origin: Optional[str] = Field(None, alias="origin")
710
+
711
+ def to_dict(self):
712
+ return self.model_dump(by_alias=True, exclude_none=True)
713
+
714
+ def __str__(self):
715
+ return str(self.to_dict())
716
+
717
+
718
+ class Member(CustomBaseModel):
719
+ """
720
+ {
721
+ "email": "string",
722
+ "roles": [...]
723
+ }
724
+ """
725
+ email: str = Field(..., alias="email")
726
+ roles: Optional[List[Role]] = Field(default_factory=list, alias="roles")
727
+
728
+ @field_validator("roles", mode="before")
729
+ @classmethod
730
+ def normalize_roles(cls, value):
731
+ if isinstance(value, list):
732
+ return [Role.model_validate(item) if isinstance(item, dict) else item for item in value]
733
+ return value
734
+
735
+ def to_dict(self):
736
+ return self.model_dump(by_alias=True, exclude_none=True)
737
+
738
+ def __str__(self):
739
+ return str(self.to_dict())
740
+
741
+
742
+ class ProjectMembership(CustomBaseModel):
743
+ """
744
+ {
745
+ "organizationId": "string",
746
+ "organizationName": "string",
747
+ "projectDescription": "string",
748
+ "projectId": "string",
749
+ "projectName": "string",
750
+ "roles": [...]
751
+ }
752
+ """
753
+ organization_id: Optional[str] = Field(None, alias="organizationId")
754
+ organization_name: Optional[str] = Field(None, alias="organizationName")
755
+ project_description: Optional[str] = Field(None, alias="projectDescription")
756
+ project_id: str = Field(..., alias="projectId")
757
+ project_name: str = Field(..., alias="projectName")
758
+ roles: Optional[List[Role]] = Field(default_factory=list, alias="roles")
759
+
760
+ @field_validator("roles", mode="before")
761
+ @classmethod
762
+ def normalize_roles(cls, value):
763
+ if isinstance(value, list):
764
+ return [Role.model_validate(item) if isinstance(item, dict) else item for item in value]
765
+ return value
766
+
767
+ def to_dict(self):
768
+ return self.model_dump(by_alias=True, exclude_none=True)
769
+
770
+ def __str__(self):
771
+ return str(self.to_dict())
772
+
773
+
774
+ class OrganizationMembership(CustomBaseModel):
775
+ """
776
+ {
777
+ "isStationAvailable": true,
778
+ "organizationId": "string",
779
+ "organizationName": "string",
780
+ "projects": [...]
781
+ }
782
+ """
783
+ is_station_available: Optional[bool] = Field(None, alias="isStationAvailable")
784
+ organization_id: str = Field(..., alias="organizationId")
785
+ organization_name: str = Field(..., alias="organizationName")
786
+ projects: Optional[List[ProjectMembership]] = Field(default_factory=list, alias="projects")
787
+
788
+ @field_validator("projects", mode="before")
789
+ @classmethod
790
+ def normalize_projects(cls, value):
791
+ if isinstance(value, list):
792
+ return [ProjectMembership.model_validate(item) if isinstance(item, dict) else item for item in value]
793
+ return value
794
+
795
+ def to_dict(self):
796
+ return self.model_dump(by_alias=True, exclude_none=True)
797
+
798
+ def __str__(self):
799
+ return str(self.to_dict())
@@ -1,10 +1,11 @@
1
- from json import JSONDecodeError
2
1
  from typing import Optional, List, Dict
3
2
 
4
3
  from pygeai import logger
5
4
  from pygeai.core.base.clients import BaseClient
6
5
  from pygeai.core.common.exceptions import InvalidAPIResponseException
7
6
  from pygeai.core.plugins.endpoints import LIST_ASSISTANTS_PLUGINS_V1
7
+ from pygeai.core.utils.validators import validate_status_code
8
+ from pygeai.core.utils.parsers import parse_json_response
8
9
 
9
10
 
10
11
  class PluginClient(BaseClient):
@@ -26,10 +27,5 @@ class PluginClient(BaseClient):
26
27
  endpoint=LIST_ASSISTANTS_PLUGINS_V1,
27
28
  params=params
28
29
  )
29
- try:
30
- result = response.json()
31
- return result
32
- except JSONDecodeError as e:
33
- logger.error(f"Unable to list assistants for organization {organization_id} and project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
34
- raise InvalidAPIResponseException(f"Unable to list assistants for organization {organization_id} and project {project_id}: {response.text}")
30
+ return parse_json_response(response, f"list assistants for organization {organization_id} and project {project_id}")
35
31
 
@@ -1,11 +1,11 @@
1
- import json
2
- from json import JSONDecodeError
3
1
  from typing import Any, Union
4
2
 
5
3
  from pygeai import logger
6
4
  from pygeai.core.base.clients import BaseClient
7
5
  from pygeai.core.common.exceptions import InvalidAPIResponseException
8
6
  from pygeai.core.rerank.endpoints import RERANK_V1
7
+ from pygeai.core.utils.validators import validate_status_code
8
+ from pygeai.core.utils.parsers import parse_json_response
9
9
 
10
10
 
11
11
  class RerankClient(BaseClient):
@@ -30,10 +30,5 @@ class RerankClient(BaseClient):
30
30
  endpoint=RERANK_V1,
31
31
  data=data
32
32
  )
33
- try:
34
- result = response.json()
35
- return result
36
- except JSONDecodeError as e:
37
- logger.error(f"Unable to rerank chunks for query '{query}' with model {model}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
38
- raise InvalidAPIResponseException(f"Unable to rerank chunks for query '{query}' with model {model}: {response.text}")
33
+ return parse_json_response(response, "rerank chunks for query with model", query=query, model=model)
39
34
 
@@ -1,4 +1,3 @@
1
- from json import JSONDecodeError
2
1
  from typing import Optional, List, Dict
3
2
 
4
3
  from pygeai import logger
@@ -6,6 +5,8 @@ from pygeai.core.base.clients import BaseClient
6
5
  from pygeai.core.common.exceptions import InvalidAPIResponseException
7
6
  from pygeai.core.secrets.endpoints import LIST_SECRETS_V1, GET_SECRET_V1, CREATE_SECRET_V1, UPDATE_SECRET_V1, \
8
7
  SET_SECRET_ACCESSES_V1, GET_SECRET_ACCESSES_V1
8
+ from pygeai.core.utils.validators import validate_status_code
9
+ from pygeai.core.utils.parsers import parse_json_response
9
10
 
10
11
 
11
12
  class SecretClient(BaseClient):
@@ -44,12 +45,7 @@ class SecretClient(BaseClient):
44
45
  endpoint=LIST_SECRETS_V1,
45
46
  params=params
46
47
  )
47
- try:
48
- result = response.json()
49
- return result
50
- except JSONDecodeError as e:
51
- logger.error(f"Unable to list secrets with params {params}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
52
- raise InvalidAPIResponseException(f"Unable to list secrets with params {params}: {response.text}")
48
+ return parse_json_response(response, "list secrets with params")
53
49
 
54
50
  def get_secret(self, secret_id: str) -> dict:
55
51
  """
@@ -69,12 +65,7 @@ class SecretClient(BaseClient):
69
65
  response = self.api_service.get(
70
66
  endpoint=endpoint
71
67
  )
72
- try:
73
- result = response.json()
74
- return result
75
- except JSONDecodeError as e:
76
- logger.error(f"Unable to get secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
77
- raise InvalidAPIResponseException(f"Unable to get secret with ID '{secret_id}': {response.text}")
68
+ return parse_json_response(response, "get secret with ID", secret_id=secret_id)
78
69
 
79
70
  def create_secret(
80
71
  self,
@@ -111,12 +102,7 @@ class SecretClient(BaseClient):
111
102
  endpoint=CREATE_SECRET_V1,
112
103
  data=data
113
104
  )
114
- try:
115
- result = response.json()
116
- return result
117
- except JSONDecodeError as e:
118
- logger.error(f"Unable to create secret with name '{name}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
119
- raise InvalidAPIResponseException(f"Unable to create secret with name '{name}': {response.text}")
105
+ return parse_json_response(response, "create secret with name", name=name)
120
106
 
121
107
  def update_secret(
122
108
  self,
@@ -157,12 +143,7 @@ class SecretClient(BaseClient):
157
143
  endpoint=endpoint,
158
144
  data=data
159
145
  )
160
- try:
161
- result = response.json()
162
- return result
163
- except JSONDecodeError as e:
164
- logger.error(f"Unable to update secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
165
- raise InvalidAPIResponseException(f"Unable to update secret with ID '{secret_id}': {response.text}")
146
+ return parse_json_response(response, "update secret with ID", secret_id=secret_id)
166
147
 
167
148
  def set_secret_accesses(
168
149
  self,
@@ -202,12 +183,7 @@ class SecretClient(BaseClient):
202
183
  endpoint=endpoint,
203
184
  data=data
204
185
  )
205
- try:
206
- result = response.json()
207
- return result
208
- except JSONDecodeError as e:
209
- logger.error(f"Unable to set accesses for secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
210
- raise InvalidAPIResponseException(f"Unable to set accesses for secret with ID '{secret_id}': {response.text}")
186
+ return parse_json_response(response, "set accesses for secret with ID", secret_id=secret_id)
211
187
 
212
188
  def get_secret_accesses(self, secret_id: str) -> dict:
213
189
  """
@@ -227,9 +203,4 @@ class SecretClient(BaseClient):
227
203
  response = self.api_service.get(
228
204
  endpoint=endpoint
229
205
  )
230
- try:
231
- result = response.json()
232
- return result
233
- except JSONDecodeError as e:
234
- logger.error(f"Unable to get accesses for secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
235
- raise InvalidAPIResponseException(f"Unable to get accesses for secret with ID '{secret_id}': {response.text}")
206
+ return parse_json_response(response, "get accesses for secret with ID", secret_id=secret_id)