pygeai 0.6.0b6__py3-none-any.whl → 0.6.0b10__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 (227) hide show
  1. pygeai/_docs/source/conf.py +78 -6
  2. pygeai/_docs/source/content/api_reference/admin.rst +161 -0
  3. pygeai/_docs/source/content/api_reference/assistant.rst +326 -0
  4. pygeai/_docs/source/content/api_reference/auth.rst +379 -0
  5. pygeai/_docs/source/content/api_reference/embeddings.rst +31 -1
  6. pygeai/_docs/source/content/api_reference/evaluation.rst +590 -0
  7. pygeai/_docs/source/content/api_reference/feedback.rst +237 -0
  8. pygeai/_docs/source/content/api_reference/files.rst +592 -0
  9. pygeai/_docs/source/content/api_reference/gam.rst +401 -0
  10. pygeai/_docs/source/content/api_reference/health.rst +58 -0
  11. pygeai/_docs/source/content/api_reference/project.rst +20 -18
  12. pygeai/_docs/source/content/api_reference/proxy.rst +318 -0
  13. pygeai/_docs/source/content/api_reference/rerank.rst +94 -0
  14. pygeai/_docs/source/content/api_reference/secrets.rst +495 -0
  15. pygeai/_docs/source/content/api_reference/usage_limits.rst +390 -0
  16. pygeai/_docs/source/content/api_reference.rst +13 -1
  17. pygeai/_docs/source/content/debugger.rst +376 -83
  18. pygeai/_docs/source/content/migration.rst +528 -0
  19. pygeai/_docs/source/content/modules.rst +1 -1
  20. pygeai/_docs/source/index.rst +59 -7
  21. pygeai/_docs/source/pygeai.auth.rst +29 -0
  22. pygeai/_docs/source/pygeai.cli.commands.rst +16 -0
  23. pygeai/_docs/source/pygeai.cli.rst +8 -0
  24. pygeai/_docs/source/pygeai.core.utils.rst +16 -0
  25. pygeai/_docs/source/pygeai.rst +1 -0
  26. pygeai/_docs/source/pygeai.tests.auth.rst +21 -0
  27. pygeai/_docs/source/pygeai.tests.cli.commands.rst +16 -0
  28. pygeai/_docs/source/pygeai.tests.cli.rst +16 -0
  29. pygeai/_docs/source/pygeai.tests.core.base.rst +8 -0
  30. pygeai/_docs/source/pygeai.tests.core.embeddings.rst +16 -0
  31. pygeai/_docs/source/pygeai.tests.core.files.rst +8 -0
  32. pygeai/_docs/source/pygeai.tests.core.plugins.rst +21 -0
  33. pygeai/_docs/source/pygeai.tests.core.rst +1 -0
  34. pygeai/_docs/source/pygeai.tests.evaluation.dataset.rst +21 -0
  35. pygeai/_docs/source/pygeai.tests.evaluation.plan.rst +21 -0
  36. pygeai/_docs/source/pygeai.tests.evaluation.result.rst +21 -0
  37. pygeai/_docs/source/pygeai.tests.evaluation.rst +20 -0
  38. pygeai/_docs/source/pygeai.tests.integration.lab.processes.rst +8 -0
  39. pygeai/_docs/source/pygeai.tests.organization.rst +8 -0
  40. pygeai/_docs/source/pygeai.tests.rst +2 -0
  41. pygeai/_docs/source/pygeai.tests.snippets.auth.rst +10 -0
  42. pygeai/_docs/source/pygeai.tests.snippets.chat.rst +40 -0
  43. pygeai/_docs/source/pygeai.tests.snippets.dbg.rst +45 -0
  44. pygeai/_docs/source/pygeai.tests.snippets.embeddings.rst +40 -0
  45. pygeai/_docs/source/pygeai.tests.snippets.evaluation.dataset.rst +197 -0
  46. pygeai/_docs/source/pygeai.tests.snippets.evaluation.plan.rst +133 -0
  47. pygeai/_docs/source/pygeai.tests.snippets.evaluation.result.rst +37 -0
  48. pygeai/_docs/source/pygeai.tests.snippets.evaluation.rst +10 -0
  49. pygeai/_docs/source/pygeai.tests.snippets.organization.rst +40 -0
  50. pygeai/_docs/source/pygeai.tests.snippets.rst +2 -0
  51. pygeai/admin/clients.py +12 -32
  52. pygeai/assistant/clients.py +16 -44
  53. pygeai/assistant/data/clients.py +1 -0
  54. pygeai/assistant/data_analyst/clients.py +6 -13
  55. pygeai/assistant/rag/clients.py +24 -67
  56. pygeai/auth/clients.py +88 -14
  57. pygeai/auth/endpoints.py +4 -0
  58. pygeai/chat/clients.py +192 -25
  59. pygeai/chat/endpoints.py +2 -1
  60. pygeai/cli/commands/auth.py +178 -2
  61. pygeai/cli/commands/chat.py +227 -1
  62. pygeai/cli/commands/embeddings.py +56 -8
  63. pygeai/cli/commands/lab/ai_lab.py +0 -2
  64. pygeai/cli/commands/migrate.py +994 -434
  65. pygeai/cli/commands/organization.py +241 -0
  66. pygeai/cli/error_handler.py +116 -0
  67. pygeai/cli/geai.py +28 -10
  68. pygeai/cli/parsers.py +8 -2
  69. pygeai/core/base/clients.py +4 -1
  70. pygeai/core/common/exceptions.py +11 -10
  71. pygeai/core/embeddings/__init__.py +19 -0
  72. pygeai/core/embeddings/clients.py +20 -9
  73. pygeai/core/embeddings/mappers.py +16 -2
  74. pygeai/core/embeddings/responses.py +9 -2
  75. pygeai/core/feedback/clients.py +4 -8
  76. pygeai/core/files/clients.py +10 -25
  77. pygeai/core/files/managers.py +42 -0
  78. pygeai/core/llm/clients.py +11 -26
  79. pygeai/core/models.py +107 -0
  80. pygeai/core/plugins/clients.py +4 -7
  81. pygeai/core/rerank/clients.py +4 -8
  82. pygeai/core/secrets/clients.py +14 -37
  83. pygeai/core/services/rest.py +1 -1
  84. pygeai/core/utils/parsers.py +32 -0
  85. pygeai/core/utils/validators.py +10 -0
  86. pygeai/dbg/__init__.py +3 -0
  87. pygeai/dbg/debugger.py +565 -70
  88. pygeai/evaluation/clients.py +2 -1
  89. pygeai/evaluation/dataset/clients.py +46 -44
  90. pygeai/evaluation/plan/clients.py +28 -26
  91. pygeai/evaluation/result/clients.py +38 -5
  92. pygeai/gam/clients.py +10 -25
  93. pygeai/health/clients.py +4 -7
  94. pygeai/lab/agents/clients.py +21 -54
  95. pygeai/lab/agents/endpoints.py +2 -0
  96. pygeai/lab/clients.py +1 -0
  97. pygeai/lab/models.py +3 -3
  98. pygeai/lab/processes/clients.py +45 -127
  99. pygeai/lab/strategies/clients.py +11 -25
  100. pygeai/lab/tools/clients.py +23 -67
  101. pygeai/lab/tools/endpoints.py +3 -0
  102. pygeai/migration/__init__.py +31 -0
  103. pygeai/migration/strategies.py +404 -155
  104. pygeai/migration/tools.py +170 -3
  105. pygeai/organization/clients.py +135 -51
  106. pygeai/organization/endpoints.py +6 -1
  107. pygeai/organization/limits/clients.py +32 -91
  108. pygeai/organization/managers.py +157 -1
  109. pygeai/organization/mappers.py +76 -2
  110. pygeai/organization/responses.py +25 -1
  111. pygeai/proxy/clients.py +4 -1
  112. pygeai/tests/admin/test_clients.py +16 -11
  113. pygeai/tests/assistants/rag/test_clients.py +35 -23
  114. pygeai/tests/assistants/test_clients.py +22 -15
  115. pygeai/tests/auth/test_clients.py +191 -7
  116. pygeai/tests/chat/test_clients.py +211 -1
  117. pygeai/tests/cli/commands/test_embeddings.py +32 -9
  118. pygeai/tests/cli/commands/test_evaluation.py +7 -0
  119. pygeai/tests/cli/commands/test_migrate.py +112 -243
  120. pygeai/tests/cli/test_error_handler.py +225 -0
  121. pygeai/tests/cli/test_geai_driver.py +154 -0
  122. pygeai/tests/cli/test_parsers.py +5 -5
  123. pygeai/tests/core/embeddings/test_clients.py +144 -0
  124. pygeai/tests/core/embeddings/test_managers.py +171 -0
  125. pygeai/tests/core/embeddings/test_mappers.py +142 -0
  126. pygeai/tests/core/feedback/test_clients.py +2 -0
  127. pygeai/tests/core/files/test_clients.py +1 -0
  128. pygeai/tests/core/llm/test_clients.py +14 -9
  129. pygeai/tests/core/plugins/test_clients.py +5 -3
  130. pygeai/tests/core/rerank/test_clients.py +1 -0
  131. pygeai/tests/core/secrets/test_clients.py +19 -13
  132. pygeai/tests/dbg/test_debugger.py +453 -75
  133. pygeai/tests/evaluation/dataset/test_clients.py +3 -1
  134. pygeai/tests/evaluation/plan/test_clients.py +4 -2
  135. pygeai/tests/evaluation/result/test_clients.py +7 -5
  136. pygeai/tests/gam/test_clients.py +1 -1
  137. pygeai/tests/health/test_clients.py +1 -0
  138. pygeai/tests/lab/agents/test_clients.py +9 -0
  139. pygeai/tests/lab/processes/test_clients.py +36 -0
  140. pygeai/tests/lab/processes/test_mappers.py +3 -0
  141. pygeai/tests/lab/strategies/test_clients.py +14 -9
  142. pygeai/tests/migration/test_strategies.py +45 -218
  143. pygeai/tests/migration/test_tools.py +133 -9
  144. pygeai/tests/organization/limits/test_clients.py +17 -0
  145. pygeai/tests/organization/test_clients.py +206 -1
  146. pygeai/tests/organization/test_managers.py +122 -1
  147. pygeai/tests/proxy/test_clients.py +2 -0
  148. pygeai/tests/proxy/test_integration.py +1 -0
  149. pygeai/tests/snippets/auth/__init__.py +0 -0
  150. pygeai/tests/snippets/chat/chat_completion_with_reasoning_effort.py +18 -0
  151. pygeai/tests/snippets/chat/get_response.py +15 -0
  152. pygeai/tests/snippets/chat/get_response_streaming.py +20 -0
  153. pygeai/tests/snippets/chat/get_response_with_files.py +16 -0
  154. pygeai/tests/snippets/chat/get_response_with_tools.py +36 -0
  155. pygeai/tests/snippets/dbg/__init__.py +0 -0
  156. pygeai/tests/snippets/dbg/basic_debugging.py +32 -0
  157. pygeai/tests/snippets/dbg/breakpoint_management.py +48 -0
  158. pygeai/tests/snippets/dbg/stack_navigation.py +45 -0
  159. pygeai/tests/snippets/dbg/stepping_example.py +40 -0
  160. pygeai/tests/snippets/embeddings/cache_example.py +31 -0
  161. pygeai/tests/snippets/embeddings/cohere_example.py +41 -0
  162. pygeai/tests/snippets/embeddings/openai_base64_example.py +27 -0
  163. pygeai/tests/snippets/embeddings/openai_example.py +30 -0
  164. pygeai/tests/snippets/embeddings/similarity_example.py +42 -0
  165. pygeai/tests/snippets/evaluation/dataset/__init__.py +0 -0
  166. pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +195 -0
  167. pygeai/tests/snippets/evaluation/dataset/create_dataset.py +26 -0
  168. pygeai/tests/snippets/evaluation/dataset/create_dataset_from_file.py +11 -0
  169. pygeai/tests/snippets/evaluation/dataset/create_dataset_row.py +17 -0
  170. pygeai/tests/snippets/evaluation/dataset/create_expected_source.py +18 -0
  171. pygeai/tests/snippets/evaluation/dataset/create_filter_variable.py +19 -0
  172. pygeai/tests/snippets/evaluation/dataset/delete_dataset.py +9 -0
  173. pygeai/tests/snippets/evaluation/dataset/delete_dataset_row.py +10 -0
  174. pygeai/tests/snippets/evaluation/dataset/delete_expected_source.py +15 -0
  175. pygeai/tests/snippets/evaluation/dataset/delete_filter_variable.py +15 -0
  176. pygeai/tests/snippets/evaluation/dataset/get_dataset.py +9 -0
  177. pygeai/tests/snippets/evaluation/dataset/get_dataset_row.py +10 -0
  178. pygeai/tests/snippets/evaluation/dataset/get_expected_source.py +15 -0
  179. pygeai/tests/snippets/evaluation/dataset/get_filter_variable.py +15 -0
  180. pygeai/tests/snippets/evaluation/dataset/list_dataset_rows.py +9 -0
  181. pygeai/tests/snippets/evaluation/dataset/list_datasets.py +6 -0
  182. pygeai/tests/snippets/evaluation/dataset/list_expected_sources.py +10 -0
  183. pygeai/tests/snippets/evaluation/dataset/list_filter_variables.py +10 -0
  184. pygeai/tests/snippets/evaluation/dataset/update_dataset.py +15 -0
  185. pygeai/tests/snippets/evaluation/dataset/update_dataset_row.py +20 -0
  186. pygeai/tests/snippets/evaluation/dataset/update_expected_source.py +18 -0
  187. pygeai/tests/snippets/evaluation/dataset/update_filter_variable.py +19 -0
  188. pygeai/tests/snippets/evaluation/dataset/upload_dataset_rows_file.py +10 -0
  189. pygeai/tests/snippets/evaluation/plan/__init__.py +0 -0
  190. pygeai/tests/snippets/evaluation/plan/add_plan_system_metric.py +13 -0
  191. pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +136 -0
  192. pygeai/tests/snippets/evaluation/plan/create_evaluation_plan.py +24 -0
  193. pygeai/tests/snippets/evaluation/plan/create_rag_evaluation_plan.py +22 -0
  194. pygeai/tests/snippets/evaluation/plan/delete_evaluation_plan.py +9 -0
  195. pygeai/tests/snippets/evaluation/plan/delete_plan_system_metric.py +13 -0
  196. pygeai/tests/snippets/evaluation/plan/execute_evaluation_plan.py +11 -0
  197. pygeai/tests/snippets/evaluation/plan/get_evaluation_plan.py +9 -0
  198. pygeai/tests/snippets/evaluation/plan/get_plan_system_metric.py +13 -0
  199. pygeai/tests/snippets/evaluation/plan/get_system_metric.py +9 -0
  200. pygeai/tests/snippets/evaluation/plan/list_evaluation_plans.py +7 -0
  201. pygeai/tests/snippets/evaluation/plan/list_plan_system_metrics.py +9 -0
  202. pygeai/tests/snippets/evaluation/plan/list_system_metrics.py +7 -0
  203. pygeai/tests/snippets/evaluation/plan/update_evaluation_plan.py +22 -0
  204. pygeai/tests/snippets/evaluation/plan/update_plan_system_metric.py +14 -0
  205. pygeai/tests/snippets/evaluation/result/__init__.py +0 -0
  206. pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +150 -0
  207. pygeai/tests/snippets/evaluation/result/get_evaluation_result.py +26 -0
  208. pygeai/tests/snippets/evaluation/result/list_evaluation_results.py +17 -0
  209. pygeai/tests/snippets/migrate/__init__.py +45 -0
  210. pygeai/tests/snippets/migrate/agent_migration.py +110 -0
  211. pygeai/tests/snippets/migrate/assistant_migration.py +64 -0
  212. pygeai/tests/snippets/migrate/orchestrator_examples.py +179 -0
  213. pygeai/tests/snippets/migrate/process_migration.py +64 -0
  214. pygeai/tests/snippets/migrate/project_migration.py +42 -0
  215. pygeai/tests/snippets/migrate/tool_migration.py +64 -0
  216. pygeai/tests/snippets/organization/create_project.py +2 -2
  217. pygeai/tests/snippets/organization/get_memberships.py +12 -0
  218. pygeai/tests/snippets/organization/get_organization_members.py +6 -0
  219. pygeai/tests/snippets/organization/get_project_members.py +6 -0
  220. pygeai/tests/snippets/organization/get_project_memberships.py +12 -0
  221. pygeai/tests/snippets/organization/get_project_roles.py +6 -0
  222. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/METADATA +1 -1
  223. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/RECORD +227 -124
  224. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/WHEEL +0 -0
  225. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/entry_points.txt +0 -0
  226. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/licenses/LICENSE +0 -0
  227. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/top_level.txt +0 -0
pygeai/migration/tools.py CHANGED
@@ -1,13 +1,180 @@
1
+ from typing import List, Dict, Optional
2
+ from dataclasses import dataclass, field
3
+
4
+ from pygeai import logger
1
5
  from pygeai.migration.strategies import MigrationStrategy
6
+ from pygeai.core.utils.console import Console
2
7
 
3
8
 
4
9
  class MigrationTool:
10
+ """
11
+ Orchestrates migration operations using configurable strategies.
12
+
13
+ This class provides a flexible way to execute migrations with support for:
14
+ - Batch migrations of multiple resources
15
+ - Dependency ordering
16
+ - Progress tracking
17
+ - Dry-run mode
18
+ - Rollback capabilities
19
+ """
5
20
 
6
21
  def __init__(self, strategy: MigrationStrategy):
7
- self.strategy = strategy
22
+ self._strategy = strategy
8
23
 
9
24
  def set_strategy(self, strategy: MigrationStrategy):
10
- self.strategy = strategy
25
+ """
26
+ Update the migration strategy.
27
+
28
+ :param strategy: The new migration strategy to use
29
+ """
30
+ self._strategy = strategy
11
31
 
12
32
  def run_migration(self):
13
- self.strategy.migrate()
33
+ """
34
+ Execute the configured migration strategy.
35
+
36
+ :return: The result from the migration strategy (if any)
37
+ :raises ValueError: If migration fails
38
+ """
39
+ logger.info(f"Starting migration with strategy: {self._strategy.__class__.__name__}")
40
+ return self._strategy.migrate()
41
+
42
+
43
+ @dataclass
44
+ class MigrationPlan:
45
+ """
46
+ Defines a migration plan with multiple strategies and execution order.
47
+
48
+ :param strategies: List of migration strategies to execute
49
+ :param dependencies: Map of strategy index to list of dependent strategy indices
50
+ :param dry_run: If True, validate without executing migrations
51
+ :param stop_on_error: If True, stop execution on first error
52
+ """
53
+ strategies: List[MigrationStrategy]
54
+ dependencies: Dict[int, List[int]] = field(default_factory=dict)
55
+ dry_run: bool = False
56
+ stop_on_error: bool = True
57
+
58
+
59
+ class MigrationOrchestrator:
60
+ """
61
+ Advanced orchestration for complex migration scenarios.
62
+
63
+ Handles batch migrations, dependency resolution, progress tracking,
64
+ and rollback on failure.
65
+ """
66
+
67
+ def __init__(self, plan: MigrationPlan):
68
+ self._plan = plan
69
+ self._completed: List[int] = []
70
+ self._failed: List[int] = []
71
+
72
+ def execute(self) -> Dict[str, any]:
73
+ """
74
+ Execute the migration plan respecting dependencies.
75
+
76
+ :return: Summary of migration results
77
+ :raises ValueError: If migration fails and stop_on_error is True
78
+ """
79
+ logger.info(f"Executing migration plan with {len(self._plan.strategies)} strategies")
80
+
81
+ if self._plan.dry_run:
82
+ return self._validate_plan()
83
+
84
+ execution_order = self._resolve_dependencies()
85
+ total_strategies = len(execution_order)
86
+
87
+ Console.write_stdout("")
88
+ Console.write_stdout("=" * 60)
89
+ Console.write_stdout(f"Migration Progress: 0/{total_strategies} completed")
90
+ Console.write_stdout("=" * 60)
91
+
92
+ for position, idx in enumerate(execution_order, 1):
93
+ strategy = self._plan.strategies[idx]
94
+ display_info = strategy.get_display_info()
95
+
96
+ Console.write_stdout(f"\n[{position}/{total_strategies}] Migrating {display_info}...")
97
+
98
+ try:
99
+ logger.info(f"Executing strategy {idx + 1}/{len(self._plan.strategies)}: {strategy.__class__.__name__}")
100
+ strategy.migrate()
101
+ self._completed.append(idx)
102
+ Console.write_stdout(f"✓ Successfully migrated {display_info}")
103
+ except Exception as e:
104
+ logger.error(f"Strategy {idx} failed: {e}")
105
+ self._failed.append(idx)
106
+ Console.write_stdout(f"✗ Failed to migrate {display_info}: {e}")
107
+ if self._plan.stop_on_error:
108
+ raise ValueError(f"Migration failed at strategy {idx}: {e}") from e
109
+
110
+ Console.write_stdout("")
111
+ Console.write_stdout("=" * 60)
112
+ Console.write_stdout(f"Migration Complete: {len(self._completed)}/{total_strategies} successful")
113
+ Console.write_stdout("=" * 60)
114
+
115
+ return self._generate_summary()
116
+
117
+ def _resolve_dependencies(self) -> List[int]:
118
+ """
119
+ Resolve strategy execution order based on dependencies.
120
+
121
+ :return: Ordered list of strategy indices
122
+ :raises ValueError: If circular dependencies detected
123
+ """
124
+ visited = set()
125
+ order = []
126
+
127
+ def visit(idx: int, path: set):
128
+ if idx in path:
129
+ raise ValueError(f"Circular dependency detected at strategy {idx}")
130
+ if idx in visited:
131
+ return
132
+
133
+ path.add(idx)
134
+ for dep_idx in self._plan.dependencies.get(idx, []):
135
+ visit(dep_idx, path)
136
+ path.remove(idx)
137
+
138
+ visited.add(idx)
139
+ order.append(idx)
140
+
141
+ for idx in range(len(self._plan.strategies)):
142
+ visit(idx, set())
143
+
144
+ return order
145
+
146
+ def _validate_plan(self) -> Dict[str, any]:
147
+ """
148
+ Validate the migration plan without executing.
149
+
150
+ :return: Validation results
151
+ """
152
+ logger.info("Validating migration plan (dry-run mode)")
153
+ try:
154
+ execution_order = self._resolve_dependencies()
155
+ return {
156
+ "valid": True,
157
+ "execution_order": execution_order,
158
+ "total_strategies": len(self._plan.strategies)
159
+ }
160
+ except Exception as e:
161
+ logger.error(f"Validation failed: {e}")
162
+ return {
163
+ "valid": False,
164
+ "error": str(e)
165
+ }
166
+
167
+ def _generate_summary(self) -> Dict[str, any]:
168
+ """
169
+ Generate a summary of migration results.
170
+
171
+ :return: Summary dictionary with completed, failed, and pending migrations
172
+ """
173
+ return {
174
+ "total": len(self._plan.strategies),
175
+ "completed": len(self._completed),
176
+ "failed": len(self._failed),
177
+ "success_rate": len(self._completed) / len(self._plan.strategies) if self._plan.strategies else 0,
178
+ "completed_indices": self._completed,
179
+ "failed_indices": self._failed
180
+ }
@@ -1,11 +1,13 @@
1
- import json
2
- from json import JSONDecodeError
3
1
 
4
2
  from pygeai import logger
5
3
  from pygeai.core.common.exceptions import InvalidAPIResponseException
6
4
  from pygeai.organization.endpoints import GET_ASSISTANT_LIST_V1, GET_PROJECT_LIST_V1, GET_PROJECT_V1, \
7
- CREATE_PROJECT_V1, UPDATE_PROJECT_V1, DELETE_PROJECT_V1, GET_PROJECT_TOKENS_V1, GET_REQUEST_DATA_V1
5
+ CREATE_PROJECT_V1, UPDATE_PROJECT_V1, DELETE_PROJECT_V1, GET_PROJECT_TOKENS_V1, GET_REQUEST_DATA_V1, \
6
+ GET_MEMBERSHIPS_V2, GET_PROJECT_MEMBERSHIPS_V2, GET_PROJECT_ROLES_V2, GET_PROJECT_MEMBERS_V2, \
7
+ GET_ORGANIZATION_MEMBERS_V2
8
8
  from pygeai.core.base.clients import BaseClient
9
+ from pygeai.core.utils.validators import validate_status_code
10
+ from pygeai.core.utils.parsers import parse_json_response
9
11
 
10
12
 
11
13
  class OrganizationClient(BaseClient):
@@ -23,12 +25,8 @@ class OrganizationClient(BaseClient):
23
25
  :return: AssistantListResponse - The API response containing the list of assistants and the project.
24
26
  """
25
27
  response = self.api_service.get(endpoint=GET_ASSISTANT_LIST_V1, params={"detail": detail})
26
- try:
27
- result = response.json()
28
- return result
29
- except JSONDecodeError as e:
30
- logger.error(f"Unable to get assistant list: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
31
- raise InvalidAPIResponseException(f"Unable to get assistant list: {response.text}")
28
+ validate_status_code(response)
29
+ return parse_json_response(response, "get assistant list")
32
30
 
33
31
  def get_project_list(
34
32
  self,
@@ -59,12 +57,8 @@ class OrganizationClient(BaseClient):
59
57
  "detail": detail
60
58
  }
61
59
  )
62
- try:
63
- result = response.json()
64
- return result
65
- except JSONDecodeError as e:
66
- logger.error(f"Unable to get project list: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
67
- raise InvalidAPIResponseException(f"Unable to get project list: {response.text}")
60
+ validate_status_code(response)
61
+ return parse_json_response(response, "get project list")
68
62
 
69
63
  def get_project_data(
70
64
  self,
@@ -80,12 +74,8 @@ class OrganizationClient(BaseClient):
80
74
  response = self.api_service.get(
81
75
  endpoint=endpoint
82
76
  )
83
- try:
84
- result = response.json()
85
- return result
86
- except JSONDecodeError as e:
87
- logger.error(f"Unable to get project data for ID '{project_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
88
- raise InvalidAPIResponseException(f"Unable to get project data for ID '{project_id}': {response.text}")
77
+ validate_status_code(response)
78
+ return parse_json_response(response, "get project data for ID", project_id=project_id)
89
79
 
90
80
  def create_project(
91
81
  self,
@@ -122,12 +112,8 @@ class OrganizationClient(BaseClient):
122
112
  "description": description
123
113
  }
124
114
  )
125
- try:
126
- result = response.json()
127
- return result
128
- except JSONDecodeError as e:
129
- logger.error(f"Unable to create project with name '{name}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
130
- raise InvalidAPIResponseException(f"Unable to create project with name '{name}': {response.text}")
115
+ validate_status_code(response)
116
+ return parse_json_response(response, "create project with name", name=name)
131
117
 
132
118
  def update_project(
133
119
  self,
@@ -151,12 +137,8 @@ class OrganizationClient(BaseClient):
151
137
  "description": description
152
138
  }
153
139
  )
154
- try:
155
- result = response.json()
156
- return result
157
- except JSONDecodeError as e:
158
- logger.error(f"Unable to update project with ID '{project_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
159
- raise InvalidAPIResponseException(f"Unable to update project with ID '{project_id}': {response.text}")
140
+ validate_status_code(response)
141
+ return parse_json_response(response, "update project with ID", project_id=project_id)
160
142
 
161
143
  def delete_project(
162
144
  self,
@@ -170,12 +152,8 @@ class OrganizationClient(BaseClient):
170
152
  """
171
153
  endpoint = DELETE_PROJECT_V1.format(id=project_id)
172
154
  response = self.api_service.delete(endpoint=endpoint)
173
- try:
174
- result = response.json()
175
- return result
176
- except JSONDecodeError as e:
177
- logger.error(f"Unable to delete project with ID '{project_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
178
- raise InvalidAPIResponseException(f"Unable to delete project with ID '{project_id}': {response.text}")
155
+ validate_status_code(response)
156
+ return parse_json_response(response, "delete project with ID", project_id=project_id)
179
157
 
180
158
  def get_project_tokens(
181
159
  self,
@@ -189,12 +167,8 @@ class OrganizationClient(BaseClient):
189
167
  """
190
168
  endpoint = GET_PROJECT_TOKENS_V1.format(id=project_id)
191
169
  response = self.api_service.get(endpoint=endpoint)
192
- try:
193
- result = response.json()
194
- return result
195
- except JSONDecodeError as e:
196
- logger.error(f"Unable to get tokens for project with ID '{project_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
197
- raise InvalidAPIResponseException(f"Unable to get tokens for project with ID '{project_id}': {response.text}")
170
+ validate_status_code(response)
171
+ return parse_json_response(response, "get tokens for project with ID", project_id=project_id)
198
172
 
199
173
  def export_request_data(
200
174
  self,
@@ -221,9 +195,119 @@ class OrganizationClient(BaseClient):
221
195
  "count": count
222
196
  }
223
197
  )
224
- try:
225
- result = response.json()
226
- return result
227
- except JSONDecodeError as e:
228
- logger.error(f"Unable to export request data: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
229
- raise InvalidAPIResponseException(f"Unable to export request data: {response.text}")
198
+ validate_status_code(response)
199
+ return parse_json_response(response, "export request data")
200
+
201
+ def get_memberships(
202
+ self,
203
+ email: str = None,
204
+ start_page: int = 1,
205
+ page_size: int = 20,
206
+ order_key: str = None,
207
+ order_direction: str = "desc",
208
+ role_types: str = None
209
+ ) -> dict:
210
+ """
211
+ Retrieves a list of Organizations and Projects a user belongs to with their Roles.
212
+
213
+ :param email: str - The email address of the user to search for (optional, case-insensitive).
214
+ :param start_page: int - The page number for pagination (default is 1).
215
+ :param page_size: int - The number of items per page (default is 20).
216
+ :param order_key: str - Field for sorting. Only 'organizationName' is supported (optional).
217
+ :param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
218
+ :param role_types: str - Comma-separated list of role types: 'backend', 'frontend' (optional, case-insensitive).
219
+ :return: dict - The API response containing the list of organizations and projects with roles, in JSON format.
220
+ """
221
+ params = {
222
+ "startPage": start_page,
223
+ "pageSize": page_size,
224
+ "orderDirection": order_direction
225
+ }
226
+ if email:
227
+ params["email"] = email
228
+ if order_key:
229
+ params["orderKey"] = order_key
230
+ if role_types:
231
+ params["roleTypes"] = role_types
232
+
233
+ response = self.api_service.get(endpoint=GET_MEMBERSHIPS_V2, params=params)
234
+ validate_status_code(response)
235
+ return parse_json_response(response, "get memberships")
236
+
237
+ def get_project_memberships(
238
+ self,
239
+ email: str = None,
240
+ start_page: int = 1,
241
+ page_size: int = 20,
242
+ order_key: str = None,
243
+ order_direction: str = "desc",
244
+ role_types: str = None
245
+ ) -> dict:
246
+ """
247
+ Retrieves a list of Projects and Roles for a user within a specific Organization.
248
+
249
+ :param email: str - The email address of the user to search for (optional, case-insensitive).
250
+ :param start_page: int - The page number for pagination (default is 1).
251
+ :param page_size: int - The number of items per page (default is 20).
252
+ :param order_key: str - Field for sorting. Only 'projectName' is supported (optional).
253
+ :param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
254
+ :param role_types: str - Comma-separated list of role types: 'backend', 'frontend' (optional, case-insensitive).
255
+ :return: dict - The API response containing the list of projects with roles, in JSON format.
256
+ """
257
+ params = {
258
+ "startPage": start_page,
259
+ "pageSize": page_size,
260
+ "orderDirection": order_direction
261
+ }
262
+ if email:
263
+ params["email"] = email
264
+ if order_key:
265
+ params["orderKey"] = order_key
266
+ if role_types:
267
+ params["roleTypes"] = role_types
268
+
269
+ response = self.api_service.get(endpoint=GET_PROJECT_MEMBERSHIPS_V2, params=params)
270
+ validate_status_code(response)
271
+ return parse_json_response(response, "get project memberships")
272
+
273
+ def get_project_roles(
274
+ self,
275
+ project_id: str
276
+ ) -> dict:
277
+ """
278
+ Retrieves all Roles supported by a specific Project.
279
+
280
+ :param project_id: str - The unique identifier (GUID) of the project (required).
281
+ :return: dict - The API response containing the list of roles for the project, in JSON format.
282
+ """
283
+ response = self.api_service.get(endpoint=GET_PROJECT_ROLES_V2, params={"projectId": project_id})
284
+ validate_status_code(response)
285
+ return parse_json_response(response, "get project roles for project", project_id=project_id)
286
+
287
+ def get_project_members(
288
+ self,
289
+ project_id: str
290
+ ) -> dict:
291
+ """
292
+ Retrieves all members and their Roles for a specific Project.
293
+
294
+ :param project_id: str - The unique identifier (GUID) of the project (required).
295
+ :return: dict - The API response containing the list of members with their roles, in JSON format.
296
+ """
297
+ response = self.api_service.get(endpoint=GET_PROJECT_MEMBERS_V2, params={"projectId": project_id})
298
+ validate_status_code(response)
299
+ return parse_json_response(response, "get project members for project", project_id=project_id)
300
+
301
+ def get_organization_members(
302
+ self,
303
+ organization_id: str
304
+ ) -> dict:
305
+ """
306
+ Retrieves all members and their Roles for a specific Organization.
307
+
308
+ :param organization_id: str - The unique identifier (GUID) of the organization (required).
309
+ :return: dict - The API response containing the list of members with their roles, in JSON format.
310
+ """
311
+ response = self.api_service.get(endpoint=GET_ORGANIZATION_MEMBERS_V2, params={"organizationId": organization_id})
312
+ validate_status_code(response)
313
+ return parse_json_response(response, "get organization members for organization", organization_id=organization_id)
@@ -1,4 +1,4 @@
1
- GET_ASSISTANT_LIST_V1 = "v1/organization/assistants" # GET Gets the list of assistants
1
+ GET_ASSISTANT_LIST_V1 = "v1/organization/assistants" # GET - Gets the list of assistants
2
2
  GET_PROJECT_LIST_V1 = "v1/organization/projects" # GET - Gets the list of projects
3
3
  GET_PROJECT_V1 = "v1/organization/project/{id}" # GET - Gets project details
4
4
  CREATE_PROJECT_V1 = "v1/organization/project" # POST - Creates a project
@@ -6,3 +6,8 @@ UPDATE_PROJECT_V1 = "v1/organization/project/{id}" # PUT - Updat
6
6
  DELETE_PROJECT_V1 = "v1/organization/project/{id}" # DELETE - Deletes a project
7
7
  GET_PROJECT_TOKENS_V1 = "v1/organization/project/{id}/tokens" # GET - Gets the list of Tokens for the project
8
8
  GET_REQUEST_DATA_V1 = "v1/organization/request/export" # GET - Exports request data
9
+ GET_MEMBERSHIPS_V2 = "v2/accessControl/memberships" # GET - Lists Organizations and Projects a user belongs to with their Roles
10
+ GET_PROJECT_MEMBERSHIPS_V2 = "v2/accessControl/projects/memberships" # GET - Lists Projects and Roles for a user within a specific Organization
11
+ GET_PROJECT_ROLES_V2 = "v2/accessControl/projects/roles" # GET - Lists all Roles supported by a specific Project
12
+ GET_PROJECT_MEMBERS_V2 = "v2/accessControl/projects/members" # GET - Lists all members and their Roles for a specific Project
13
+ GET_ORGANIZATION_MEMBERS_V2 = "v2/accessControl/organizations/members" # GET - Lists all members and their Roles for a specific Organization