pygeai 0.6.0b10__py3-none-any.whl → 0.6.0b12__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.
- pygeai/_docs/source/content/ai_lab/cli.rst +4 -4
- pygeai/_docs/source/content/ai_lab/models.rst +169 -35
- pygeai/_docs/source/content/ai_lab/runner.rst +2 -2
- pygeai/_docs/source/content/ai_lab/spec.rst +9 -9
- pygeai/_docs/source/content/ai_lab/usage.rst +34 -34
- pygeai/_docs/source/content/ai_lab.rst +1 -1
- pygeai/_docs/source/content/analytics.rst +598 -0
- pygeai/_docs/source/content/api_reference/chat.rst +428 -2
- pygeai/_docs/source/content/api_reference/embeddings.rst +1 -1
- pygeai/_docs/source/content/api_reference/project.rst +184 -0
- pygeai/_docs/source/content/api_reference/rag.rst +2 -2
- pygeai/_docs/source/content/authentication.rst +295 -0
- pygeai/_docs/source/content/cli.rst +79 -2
- pygeai/_docs/source/content/debugger.rst +1 -1
- pygeai/_docs/source/content/migration.rst +19 -2
- pygeai/_docs/source/index.rst +2 -0
- pygeai/_docs/source/pygeai.analytics.rst +53 -0
- pygeai/_docs/source/pygeai.cli.commands.rst +8 -0
- pygeai/_docs/source/pygeai.rst +1 -0
- pygeai/_docs/source/pygeai.tests.analytics.rst +45 -0
- pygeai/_docs/source/pygeai.tests.auth.rst +8 -0
- pygeai/_docs/source/pygeai.tests.rst +1 -1
- pygeai/analytics/__init__.py +0 -0
- pygeai/analytics/clients.py +505 -0
- pygeai/analytics/endpoints.py +35 -0
- pygeai/analytics/managers.py +606 -0
- pygeai/analytics/mappers.py +207 -0
- pygeai/analytics/responses.py +240 -0
- pygeai/chat/clients.py +46 -1
- pygeai/chat/endpoints.py +1 -0
- pygeai/cli/commands/analytics.py +525 -0
- pygeai/cli/commands/base.py +16 -0
- pygeai/cli/commands/chat.py +95 -0
- pygeai/cli/commands/common.py +28 -24
- pygeai/cli/commands/migrate.py +75 -6
- pygeai/cli/commands/organization.py +265 -0
- pygeai/cli/commands/validators.py +144 -1
- pygeai/cli/error_handler.py +41 -6
- pygeai/cli/geai.py +99 -16
- pygeai/cli/parsers.py +75 -31
- pygeai/cli/texts/help.py +75 -6
- pygeai/core/base/clients.py +18 -4
- pygeai/core/base/session.py +46 -7
- pygeai/core/common/config.py +25 -2
- pygeai/core/common/exceptions.py +64 -1
- pygeai/core/services/rest.py +20 -2
- pygeai/evaluation/clients.py +5 -3
- pygeai/lab/agents/clients.py +3 -3
- pygeai/lab/agents/endpoints.py +2 -2
- pygeai/lab/agents/mappers.py +50 -2
- pygeai/lab/clients.py +5 -2
- pygeai/lab/managers.py +7 -9
- pygeai/lab/models.py +70 -2
- pygeai/lab/tools/clients.py +1 -59
- pygeai/migration/__init__.py +3 -1
- pygeai/migration/strategies.py +72 -3
- pygeai/organization/clients.py +110 -1
- pygeai/organization/endpoints.py +11 -7
- pygeai/organization/managers.py +134 -2
- pygeai/organization/mappers.py +28 -2
- pygeai/organization/responses.py +11 -1
- pygeai/tests/analytics/__init__.py +0 -0
- pygeai/tests/analytics/test_clients.py +86 -0
- pygeai/tests/analytics/test_managers.py +94 -0
- pygeai/tests/analytics/test_mappers.py +84 -0
- pygeai/tests/analytics/test_responses.py +73 -0
- pygeai/tests/auth/test_oauth.py +172 -0
- pygeai/tests/cli/commands/test_migrate.py +14 -1
- pygeai/tests/cli/commands/test_organization.py +69 -1
- pygeai/tests/cli/test_error_handler.py +4 -4
- pygeai/tests/cli/test_geai_driver.py +1 -1
- pygeai/tests/lab/agents/test_mappers.py +128 -1
- pygeai/tests/lab/test_models.py +2 -0
- pygeai/tests/lab/tools/test_clients.py +2 -31
- pygeai/tests/organization/test_clients.py +180 -1
- pygeai/tests/organization/test_managers.py +40 -0
- pygeai/tests/snippets/analytics/__init__.py +0 -0
- pygeai/tests/snippets/analytics/get_agent_usage_per_user.py +16 -0
- pygeai/tests/snippets/analytics/get_agents_created_and_modified.py +11 -0
- pygeai/tests/snippets/analytics/get_average_cost_per_request.py +10 -0
- pygeai/tests/snippets/analytics/get_overall_error_rate.py +10 -0
- pygeai/tests/snippets/analytics/get_top_10_agents_by_requests.py +12 -0
- pygeai/tests/snippets/analytics/get_total_active_users.py +10 -0
- pygeai/tests/snippets/analytics/get_total_cost.py +10 -0
- pygeai/tests/snippets/analytics/get_total_requests_per_day.py +12 -0
- pygeai/tests/snippets/analytics/get_total_tokens.py +12 -0
- pygeai/tests/snippets/chat/get_response_complete_example.py +67 -0
- pygeai/tests/snippets/chat/get_response_with_instructions.py +19 -0
- pygeai/tests/snippets/chat/get_response_with_metadata.py +24 -0
- pygeai/tests/snippets/chat/get_response_with_parallel_tools.py +58 -0
- pygeai/tests/snippets/chat/get_response_with_reasoning.py +21 -0
- pygeai/tests/snippets/chat/get_response_with_store.py +38 -0
- pygeai/tests/snippets/chat/get_response_with_truncation.py +24 -0
- pygeai/tests/snippets/lab/agents/create_agent_with_permissions.py +39 -0
- pygeai/tests/snippets/lab/agents/create_agent_with_properties.py +46 -0
- pygeai/tests/snippets/lab/agents/get_agent_with_new_fields.py +62 -0
- pygeai/tests/snippets/lab/agents/update_agent_properties.py +50 -0
- pygeai/tests/snippets/organization/add_project_member.py +10 -0
- pygeai/tests/snippets/organization/add_project_member_batch.py +44 -0
- {pygeai-0.6.0b10.dist-info → pygeai-0.6.0b12.dist-info}/METADATA +1 -1
- {pygeai-0.6.0b10.dist-info → pygeai-0.6.0b12.dist-info}/RECORD +105 -95
- pygeai/_docs/source/pygeai.tests.snippets.assistants.data_analyst.rst +0 -37
- pygeai/_docs/source/pygeai.tests.snippets.assistants.rag.rst +0 -85
- pygeai/_docs/source/pygeai.tests.snippets.assistants.rst +0 -78
- pygeai/_docs/source/pygeai.tests.snippets.auth.rst +0 -10
- pygeai/_docs/source/pygeai.tests.snippets.chat.rst +0 -125
- pygeai/_docs/source/pygeai.tests.snippets.dbg.rst +0 -45
- pygeai/_docs/source/pygeai.tests.snippets.embeddings.rst +0 -61
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.dataset.rst +0 -197
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.plan.rst +0 -133
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.result.rst +0 -37
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.rst +0 -20
- pygeai/_docs/source/pygeai.tests.snippets.extras.rst +0 -37
- pygeai/_docs/source/pygeai.tests.snippets.files.rst +0 -53
- pygeai/_docs/source/pygeai.tests.snippets.gam.rst +0 -21
- pygeai/_docs/source/pygeai.tests.snippets.lab.agents.rst +0 -93
- pygeai/_docs/source/pygeai.tests.snippets.lab.processes.jobs.rst +0 -21
- pygeai/_docs/source/pygeai.tests.snippets.lab.processes.kbs.rst +0 -45
- pygeai/_docs/source/pygeai.tests.snippets.lab.processes.rst +0 -46
- pygeai/_docs/source/pygeai.tests.snippets.lab.rst +0 -82
- pygeai/_docs/source/pygeai.tests.snippets.lab.samples.rst +0 -21
- pygeai/_docs/source/pygeai.tests.snippets.lab.strategies.rst +0 -45
- pygeai/_docs/source/pygeai.tests.snippets.lab.tools.rst +0 -85
- pygeai/_docs/source/pygeai.tests.snippets.lab.use_cases.rst +0 -117
- pygeai/_docs/source/pygeai.tests.snippets.migrate.rst +0 -10
- pygeai/_docs/source/pygeai.tests.snippets.organization.rst +0 -109
- pygeai/_docs/source/pygeai.tests.snippets.rag.rst +0 -85
- pygeai/_docs/source/pygeai.tests.snippets.rerank.rst +0 -21
- pygeai/_docs/source/pygeai.tests.snippets.rst +0 -32
- pygeai/_docs/source/pygeai.tests.snippets.secrets.rst +0 -10
- pygeai/_docs/source/pygeai.tests.snippets.usage_limit.rst +0 -77
- {pygeai-0.6.0b10.dist-info → pygeai-0.6.0b12.dist-info}/WHEEL +0 -0
- {pygeai-0.6.0b10.dist-info → pygeai-0.6.0b12.dist-info}/entry_points.txt +0 -0
- {pygeai-0.6.0b10.dist-info → pygeai-0.6.0b12.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.6.0b10.dist-info → pygeai-0.6.0b12.dist-info}/top_level.txt +0 -0
pygeai/lab/tools/clients.py
CHANGED
|
@@ -6,7 +6,7 @@ from pygeai.core.utils.validators import validate_status_code
|
|
|
6
6
|
from pygeai.core.utils.parsers import parse_json_response
|
|
7
7
|
from pygeai.lab.constants import VALID_SCOPES, VALID_ACCESS_SCOPES, VALID_REPORT_EVENTS
|
|
8
8
|
from pygeai.lab.tools.endpoints import CREATE_TOOL_V2, LIST_TOOLS_V2, GET_TOOL_V2, UPDATE_TOOL_V2, UPSERT_TOOL_V2, \
|
|
9
|
-
PUBLISH_TOOL_REVISION_V2, GET_PARAMETER_V2, SET_PARAMETER_V2, DELETE_TOOL_V2
|
|
9
|
+
PUBLISH_TOOL_REVISION_V2, GET_PARAMETER_V2, SET_PARAMETER_V2, DELETE_TOOL_V2
|
|
10
10
|
from pygeai.lab.clients import AILabClient
|
|
11
11
|
|
|
12
12
|
|
|
@@ -103,23 +103,14 @@ class ToolClient(AILabClient):
|
|
|
103
103
|
if automatic_publish:
|
|
104
104
|
endpoint = f"{endpoint}?automaticPublish=true"
|
|
105
105
|
|
|
106
|
-
headers = {
|
|
107
|
-
"Accept": "application/json",
|
|
108
|
-
"Content-Type": "application/json",
|
|
109
|
-
"Authorization": self.api_service.token,
|
|
110
|
-
"ProjectId": self.project_id
|
|
111
|
-
}
|
|
112
|
-
|
|
113
106
|
response = self.api_service.post(
|
|
114
107
|
endpoint=endpoint,
|
|
115
|
-
headers=headers,
|
|
116
108
|
data=data
|
|
117
109
|
)
|
|
118
110
|
|
|
119
111
|
validate_status_code(response)
|
|
120
112
|
return parse_json_response(response, f"create tool for project {self.project_id}")
|
|
121
113
|
|
|
122
|
-
|
|
123
114
|
def list_tools(
|
|
124
115
|
self,
|
|
125
116
|
id: str = "",
|
|
@@ -141,10 +132,6 @@ class ToolClient(AILabClient):
|
|
|
141
132
|
:return: dict or str - JSON response containing the list of tools if successful, otherwise the raw response text.
|
|
142
133
|
"""
|
|
143
134
|
endpoint = LIST_TOOLS_V2
|
|
144
|
-
headers = {
|
|
145
|
-
"Authorization": self.api_service.token,
|
|
146
|
-
"ProjectId": self.project_id
|
|
147
|
-
}
|
|
148
135
|
|
|
149
136
|
if scope and scope not in VALID_SCOPES:
|
|
150
137
|
raise ValueError(f"Scope must be one of {', '.join(VALID_SCOPES)}.")
|
|
@@ -153,7 +140,6 @@ class ToolClient(AILabClient):
|
|
|
153
140
|
|
|
154
141
|
response = self.api_service.get(
|
|
155
142
|
endpoint=endpoint,
|
|
156
|
-
headers=headers,
|
|
157
143
|
params={
|
|
158
144
|
"id": id,
|
|
159
145
|
"count": count,
|
|
@@ -166,7 +152,6 @@ class ToolClient(AILabClient):
|
|
|
166
152
|
validate_status_code(response)
|
|
167
153
|
return parse_json_response(response, f"list tools for project {self.project_id}")
|
|
168
154
|
|
|
169
|
-
|
|
170
155
|
def get_tool(
|
|
171
156
|
self,
|
|
172
157
|
tool_id: str,
|
|
@@ -184,16 +169,10 @@ class ToolClient(AILabClient):
|
|
|
184
169
|
:return: dict or str - JSON response containing the tool details if successful, otherwise the raw response text.
|
|
185
170
|
"""
|
|
186
171
|
endpoint = GET_TOOL_V2.format(toolId=tool_id)
|
|
187
|
-
headers = {
|
|
188
|
-
"Authorization": self.api_service.token,
|
|
189
|
-
"ProjectId": self.project_id
|
|
190
|
-
}
|
|
191
|
-
|
|
192
172
|
logger.debug(f"Retrieving detail of tool with ID: {tool_id}")
|
|
193
173
|
|
|
194
174
|
response = self.api_service.get(
|
|
195
175
|
endpoint=endpoint,
|
|
196
|
-
headers=headers,
|
|
197
176
|
params={
|
|
198
177
|
"revision": revision,
|
|
199
178
|
"version": version,
|
|
@@ -222,10 +201,6 @@ class ToolClient(AILabClient):
|
|
|
222
201
|
raise ValueError("Either tool_id or tool_name must be provided.")
|
|
223
202
|
|
|
224
203
|
endpoint = DELETE_TOOL_V2.format(toolId=tool_id if tool_id else tool_name)
|
|
225
|
-
headers = {
|
|
226
|
-
"Authorization": self.api_service.token,
|
|
227
|
-
"ProjectId": self.project_id
|
|
228
|
-
}
|
|
229
204
|
|
|
230
205
|
if tool_id:
|
|
231
206
|
logger.debug(f"Deleting tool with ID {tool_id}")
|
|
@@ -234,7 +209,6 @@ class ToolClient(AILabClient):
|
|
|
234
209
|
|
|
235
210
|
response = self.api_service.delete(
|
|
236
211
|
endpoint=endpoint,
|
|
237
|
-
headers=headers
|
|
238
212
|
)
|
|
239
213
|
validate_status_code(response)
|
|
240
214
|
|
|
@@ -345,19 +319,13 @@ class ToolClient(AILabClient):
|
|
|
345
319
|
if automatic_publish:
|
|
346
320
|
endpoint = f"{endpoint}?automaticPublish=true"
|
|
347
321
|
|
|
348
|
-
headers = {
|
|
349
|
-
"Authorization": self.api_service.token,
|
|
350
|
-
"ProjectId": self.project_id
|
|
351
|
-
}
|
|
352
322
|
response = self.api_service.put(
|
|
353
323
|
endpoint=endpoint,
|
|
354
|
-
headers=headers,
|
|
355
324
|
data=data
|
|
356
325
|
)
|
|
357
326
|
validate_status_code(response)
|
|
358
327
|
return parse_json_response(response, f"update tool {tool_id} in project {self.project_id}")
|
|
359
328
|
|
|
360
|
-
|
|
361
329
|
def publish_tool_revision(
|
|
362
330
|
self,
|
|
363
331
|
tool_id: str,
|
|
@@ -371,16 +339,10 @@ class ToolClient(AILabClient):
|
|
|
371
339
|
:return: dict or str - JSON response containing the result of the publish operation if successful, otherwise the raw response text.
|
|
372
340
|
"""
|
|
373
341
|
endpoint = PUBLISH_TOOL_REVISION_V2.format(toolId=tool_id)
|
|
374
|
-
headers = {
|
|
375
|
-
"Authorization": self.api_service.token,
|
|
376
|
-
"ProjectId": self.project_id
|
|
377
|
-
}
|
|
378
|
-
|
|
379
342
|
logger.debug(f"Publishing revision {revision} for tool with ID {tool_id}")
|
|
380
343
|
|
|
381
344
|
response = self.api_service.post(
|
|
382
345
|
endpoint=endpoint,
|
|
383
|
-
headers=headers,
|
|
384
346
|
data={
|
|
385
347
|
"revision": revision,
|
|
386
348
|
}
|
|
@@ -417,14 +379,8 @@ class ToolClient(AILabClient):
|
|
|
417
379
|
logger.debug(f"Retrieving parameter for tool with name '{tool_public_name}'")
|
|
418
380
|
|
|
419
381
|
endpoint = GET_PARAMETER_V2.format(toolPublicName=tool_public_name) if tool_public_name else GET_PARAMETER_V2.format(toolPublicName=tool_id)
|
|
420
|
-
headers = {
|
|
421
|
-
"Authorization": self.api_service.token,
|
|
422
|
-
"ProjectId": self.project_id
|
|
423
|
-
}
|
|
424
|
-
|
|
425
382
|
response = self.api_service.get(
|
|
426
383
|
endpoint=endpoint,
|
|
427
|
-
headers=headers,
|
|
428
384
|
params={
|
|
429
385
|
"revision": revision,
|
|
430
386
|
"version": version,
|
|
@@ -435,7 +391,6 @@ class ToolClient(AILabClient):
|
|
|
435
391
|
tool_identifier = tool_id or tool_public_name
|
|
436
392
|
return parse_json_response(response, f"retrieve parameters for tool {tool_identifier} in project {self.project_id}")
|
|
437
393
|
|
|
438
|
-
|
|
439
394
|
def set_parameter(
|
|
440
395
|
self,
|
|
441
396
|
tool_id: str = None,
|
|
@@ -459,12 +414,6 @@ class ToolClient(AILabClient):
|
|
|
459
414
|
raise ValueError("Parameters list must be provided and non-empty.")
|
|
460
415
|
|
|
461
416
|
endpoint = SET_PARAMETER_V2.format(toolPublicName=tool_public_name) if tool_public_name else SET_PARAMETER_V2.format(toolPublicName=tool_id)
|
|
462
|
-
headers = {
|
|
463
|
-
"Authorization": self.api_service.token,
|
|
464
|
-
"ProjectId": self.project_id,
|
|
465
|
-
"Content-Type": "application/json",
|
|
466
|
-
"Accept": "application/json"
|
|
467
|
-
}
|
|
468
417
|
|
|
469
418
|
data = {
|
|
470
419
|
"parameterDefinition": {
|
|
@@ -479,7 +428,6 @@ class ToolClient(AILabClient):
|
|
|
479
428
|
|
|
480
429
|
response = self.api_service.post(
|
|
481
430
|
endpoint=endpoint,
|
|
482
|
-
headers=headers,
|
|
483
431
|
data=data
|
|
484
432
|
)
|
|
485
433
|
if response.status_code != 204:
|
|
@@ -506,16 +454,10 @@ class ToolClient(AILabClient):
|
|
|
506
454
|
raise MissingRequirementException("tool_id must be specified in order to retrieve the tool")
|
|
507
455
|
|
|
508
456
|
endpoint = EXPORT_TOOL_V4.format(toolId=tool_id)
|
|
509
|
-
headers = {
|
|
510
|
-
"Authorization": self.api_service.token,
|
|
511
|
-
"ProjectId": self.project_id
|
|
512
|
-
}
|
|
513
|
-
|
|
514
457
|
logger.debug(f"Exporting tool with ID {tool_id}")
|
|
515
458
|
|
|
516
459
|
response = self.api_service.get(
|
|
517
460
|
endpoint=endpoint,
|
|
518
|
-
headers=headers,
|
|
519
461
|
)
|
|
520
462
|
validate_status_code(response)
|
|
521
463
|
return parse_json_response(response, f"export tool {tool_id} for project {self.project_id}")
|
pygeai/migration/__init__.py
CHANGED
|
@@ -7,7 +7,8 @@ from pygeai.migration.strategies import (
|
|
|
7
7
|
TaskMigrationStrategy,
|
|
8
8
|
UsageLimitMigrationStrategy,
|
|
9
9
|
RAGAssistantMigrationStrategy,
|
|
10
|
-
FileMigrationStrategy
|
|
10
|
+
FileMigrationStrategy,
|
|
11
|
+
SecretMigrationStrategy
|
|
11
12
|
)
|
|
12
13
|
from pygeai.migration.tools import (
|
|
13
14
|
MigrationTool,
|
|
@@ -25,6 +26,7 @@ __all__ = [
|
|
|
25
26
|
"UsageLimitMigrationStrategy",
|
|
26
27
|
"RAGAssistantMigrationStrategy",
|
|
27
28
|
"FileMigrationStrategy",
|
|
29
|
+
"SecretMigrationStrategy",
|
|
28
30
|
"MigrationTool",
|
|
29
31
|
"MigrationPlan",
|
|
30
32
|
"MigrationOrchestrator"
|
pygeai/migration/strategies.py
CHANGED
|
@@ -3,6 +3,7 @@ from abc import ABC, abstractmethod
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
5
|
from pygeai import logger
|
|
6
|
+
from pygeai.core.files.responses import UploadFileResponse
|
|
6
7
|
from pygeai.core.models import Project, UsageLimit
|
|
7
8
|
from pygeai.core.base.responses import ErrorListResponse
|
|
8
9
|
from pygeai.core.utils.console import Console
|
|
@@ -14,6 +15,7 @@ from pygeai.organization.limits.managers import UsageLimitManager
|
|
|
14
15
|
from pygeai.organization.managers import OrganizationManager
|
|
15
16
|
from pygeai.assistant.managers import AssistantManager
|
|
16
17
|
from pygeai.assistant.rag.models import RAGAssistant
|
|
18
|
+
from pygeai.core.secrets.clients import SecretClient
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class MigrationStrategy(ABC):
|
|
@@ -507,10 +509,10 @@ class FileMigrationStrategy(MigrationStrategy):
|
|
|
507
509
|
|
|
508
510
|
:raises ValueError: If file retrieval or upload fails
|
|
509
511
|
"""
|
|
510
|
-
|
|
512
|
+
upload_file_response = self._migrate_file()
|
|
511
513
|
logger.info(f"Successfully migrated file {self.file_id}")
|
|
512
514
|
|
|
513
|
-
def _migrate_file(self) ->
|
|
515
|
+
def _migrate_file(self) -> UploadFileResponse:
|
|
514
516
|
"""
|
|
515
517
|
Retrieve file from source and upload to destination.
|
|
516
518
|
|
|
@@ -528,7 +530,74 @@ class FileMigrationStrategy(MigrationStrategy):
|
|
|
528
530
|
content=file_content,
|
|
529
531
|
folder=None
|
|
530
532
|
)
|
|
531
|
-
return upload_response
|
|
533
|
+
return upload_response
|
|
532
534
|
except Exception as e:
|
|
533
535
|
logger.error(f"File migration failed: {e}")
|
|
534
536
|
raise ValueError(f"File migration failed: {e}") from e
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
class SecretMigrationStrategy(MigrationStrategy):
|
|
540
|
+
"""
|
|
541
|
+
Migrate secret from a GEAI project.
|
|
542
|
+
The target project can be in another organization or the same one; in the same instance or another.
|
|
543
|
+
"""
|
|
544
|
+
|
|
545
|
+
def __init__(
|
|
546
|
+
self,
|
|
547
|
+
from_api_key: str,
|
|
548
|
+
from_instance: str,
|
|
549
|
+
secret_id: str,
|
|
550
|
+
to_api_key: Optional[str] = None,
|
|
551
|
+
to_instance: Optional[str] = None
|
|
552
|
+
):
|
|
553
|
+
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
554
|
+
self.secret_id = secret_id
|
|
555
|
+
self._source_client = SecretClient(
|
|
556
|
+
api_key=self.from_api_key,
|
|
557
|
+
base_url=self.from_instance
|
|
558
|
+
)
|
|
559
|
+
self._destination_client = SecretClient(
|
|
560
|
+
api_key=self.to_api_key,
|
|
561
|
+
base_url=self.to_instance
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
def get_display_info(self) -> str:
|
|
565
|
+
return f"secret {self.secret_id}"
|
|
566
|
+
|
|
567
|
+
def migrate(self):
|
|
568
|
+
"""
|
|
569
|
+
Execute the secret migration from source to destination project.
|
|
570
|
+
|
|
571
|
+
:raises ValueError: If secret retrieval or creation fails
|
|
572
|
+
"""
|
|
573
|
+
new_secret = self._migrate_secret()
|
|
574
|
+
logger.info(f"Successfully migrated secret {self.secret_id}")
|
|
575
|
+
|
|
576
|
+
def _migrate_secret(self) -> dict:
|
|
577
|
+
"""
|
|
578
|
+
Retrieve secret from source and create in destination.
|
|
579
|
+
|
|
580
|
+
:return: The newly created secret
|
|
581
|
+
:raises ValueError: If migration fails
|
|
582
|
+
"""
|
|
583
|
+
try:
|
|
584
|
+
source_secret = self._source_client.get_secret(secret_id=self.secret_id)
|
|
585
|
+
if not isinstance(source_secret, dict):
|
|
586
|
+
raise ValueError(f"Unable to retrieve secret {self.secret_id}")
|
|
587
|
+
|
|
588
|
+
secret_name = source_secret.get("name")
|
|
589
|
+
secret_string = source_secret.get("secretString")
|
|
590
|
+
secret_description = source_secret.get("description")
|
|
591
|
+
|
|
592
|
+
if not secret_name or not secret_string:
|
|
593
|
+
raise ValueError(f"Secret {self.secret_id} missing required fields (name or secretString)")
|
|
594
|
+
|
|
595
|
+
new_secret = self._destination_client.create_secret(
|
|
596
|
+
name=secret_name,
|
|
597
|
+
secret_string=secret_string,
|
|
598
|
+
description=secret_description
|
|
599
|
+
)
|
|
600
|
+
return new_secret
|
|
601
|
+
except Exception as e:
|
|
602
|
+
logger.error(f"Secret migration failed: {e}")
|
|
603
|
+
raise ValueError(f"Secret migration failed: {e}") from e
|
pygeai/organization/clients.py
CHANGED
|
@@ -4,7 +4,8 @@ from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
|
4
4
|
from pygeai.organization.endpoints import GET_ASSISTANT_LIST_V1, GET_PROJECT_LIST_V1, GET_PROJECT_V1, \
|
|
5
5
|
CREATE_PROJECT_V1, UPDATE_PROJECT_V1, DELETE_PROJECT_V1, GET_PROJECT_TOKENS_V1, GET_REQUEST_DATA_V1, \
|
|
6
6
|
GET_MEMBERSHIPS_V2, GET_PROJECT_MEMBERSHIPS_V2, GET_PROJECT_ROLES_V2, GET_PROJECT_MEMBERS_V2, \
|
|
7
|
-
GET_ORGANIZATION_MEMBERS_V2
|
|
7
|
+
GET_ORGANIZATION_MEMBERS_V2, ADD_PROJECT_MEMBER_V2, CREATE_ORGANIZATION_V2, GET_ORGANIZATION_LIST_V2, \
|
|
8
|
+
DELETE_ORGANIZATION_V2
|
|
8
9
|
from pygeai.core.base.clients import BaseClient
|
|
9
10
|
from pygeai.core.utils.validators import validate_status_code
|
|
10
11
|
from pygeai.core.utils.parsers import parse_json_response
|
|
@@ -311,3 +312,111 @@ class OrganizationClient(BaseClient):
|
|
|
311
312
|
response = self.api_service.get(endpoint=GET_ORGANIZATION_MEMBERS_V2, params={"organizationId": organization_id})
|
|
312
313
|
validate_status_code(response)
|
|
313
314
|
return parse_json_response(response, "get organization members for organization", organization_id=organization_id)
|
|
315
|
+
|
|
316
|
+
def add_project_member(
|
|
317
|
+
self,
|
|
318
|
+
project_id: str,
|
|
319
|
+
user_email: str,
|
|
320
|
+
roles: list
|
|
321
|
+
) -> dict:
|
|
322
|
+
"""
|
|
323
|
+
Adds a user to a project by sending an invitation with the specified roles.
|
|
324
|
+
|
|
325
|
+
:param project_id: str - The unique identifier (GUID) of the project (required). Will be sent as header.
|
|
326
|
+
:param user_email: str - The email address of the user to invite (required).
|
|
327
|
+
:param roles: list - A list of role names or GUIDs to assign to the user (required).
|
|
328
|
+
:return: dict - The API response confirming the invitation was sent, in JSON format.
|
|
329
|
+
"""
|
|
330
|
+
headers = {"project-id": project_id}
|
|
331
|
+
data = {
|
|
332
|
+
"userEmail": user_email,
|
|
333
|
+
"roles": roles
|
|
334
|
+
}
|
|
335
|
+
response = self.api_service.post(
|
|
336
|
+
endpoint=ADD_PROJECT_MEMBER_V2,
|
|
337
|
+
data=data,
|
|
338
|
+
headers=headers
|
|
339
|
+
)
|
|
340
|
+
validate_status_code(response)
|
|
341
|
+
return parse_json_response(response, "add project member", user_email=user_email)
|
|
342
|
+
|
|
343
|
+
def create_organization(
|
|
344
|
+
self,
|
|
345
|
+
name: str,
|
|
346
|
+
administrator_user_email: str
|
|
347
|
+
) -> dict:
|
|
348
|
+
"""
|
|
349
|
+
Creates a new organization with the provided details.
|
|
350
|
+
|
|
351
|
+
This endpoint requires an OAuth access token from the System Administrator role.
|
|
352
|
+
|
|
353
|
+
:param name: str - The name of the new organization (required).
|
|
354
|
+
:param administrator_user_email: str - The email address of the organization administrator (required).
|
|
355
|
+
:return: dict - The API response with details of the created organization in JSON format.
|
|
356
|
+
"""
|
|
357
|
+
response = self.api_service.post(
|
|
358
|
+
endpoint=CREATE_ORGANIZATION_V2,
|
|
359
|
+
data={
|
|
360
|
+
"name": name,
|
|
361
|
+
"administratorUserEmail": administrator_user_email
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
validate_status_code(response)
|
|
365
|
+
return parse_json_response(response, "create organization with name", name=name)
|
|
366
|
+
|
|
367
|
+
def get_organization_list(
|
|
368
|
+
self,
|
|
369
|
+
start_page: int = None,
|
|
370
|
+
page_size: int = None,
|
|
371
|
+
order_key: str = None,
|
|
372
|
+
order_direction: str = "desc",
|
|
373
|
+
filter_key: str = None,
|
|
374
|
+
filter_value: str = None
|
|
375
|
+
) -> dict:
|
|
376
|
+
"""
|
|
377
|
+
Retrieves a list of organizations based on the specified search criteria.
|
|
378
|
+
|
|
379
|
+
This endpoint requires an OAuth access token from the System Administrator role.
|
|
380
|
+
|
|
381
|
+
:param start_page: int - The page number for pagination (optional).
|
|
382
|
+
:param page_size: int - The number of items per page (optional).
|
|
383
|
+
:param order_key: str - Field for sorting. Only 'name' is supported (optional).
|
|
384
|
+
:param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
|
|
385
|
+
:param filter_key: str - Field for filtering. Only 'name' is supported (optional).
|
|
386
|
+
:param filter_value: str - Value to filter by (optional).
|
|
387
|
+
:return: dict - The API response containing the list of organizations in JSON format.
|
|
388
|
+
"""
|
|
389
|
+
params = {
|
|
390
|
+
"orderDirection": order_direction
|
|
391
|
+
}
|
|
392
|
+
if start_page is not None:
|
|
393
|
+
params["startPage"] = start_page
|
|
394
|
+
if page_size is not None:
|
|
395
|
+
params["pageSize"] = page_size
|
|
396
|
+
if order_key:
|
|
397
|
+
params["orderKey"] = order_key
|
|
398
|
+
if filter_key:
|
|
399
|
+
params["filterKey"] = filter_key
|
|
400
|
+
if filter_value:
|
|
401
|
+
params["filterValue"] = filter_value
|
|
402
|
+
|
|
403
|
+
response = self.api_service.get(endpoint=GET_ORGANIZATION_LIST_V2, params=params)
|
|
404
|
+
validate_status_code(response)
|
|
405
|
+
return parse_json_response(response, "get organization list")
|
|
406
|
+
|
|
407
|
+
def delete_organization(
|
|
408
|
+
self,
|
|
409
|
+
organization_id: str
|
|
410
|
+
) -> dict:
|
|
411
|
+
"""
|
|
412
|
+
Deletes an existing organization using its unique identifier.
|
|
413
|
+
|
|
414
|
+
This endpoint requires an OAuth access token from the System Administrator role.
|
|
415
|
+
|
|
416
|
+
:param organization_id: str - The unique identifier (GUID) of the organization to delete (required).
|
|
417
|
+
:return: dict - The API response confirming the deletion of the organization, in JSON format.
|
|
418
|
+
"""
|
|
419
|
+
endpoint = DELETE_ORGANIZATION_V2.format(organizationId=organization_id)
|
|
420
|
+
response = self.api_service.delete(endpoint=endpoint)
|
|
421
|
+
validate_status_code(response)
|
|
422
|
+
return parse_json_response(response, "delete organization with ID", organization_id=organization_id)
|
pygeai/organization/endpoints.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
GET_ASSISTANT_LIST_V1 = "v1/organization/assistants" # GET - Gets the list of assistants
|
|
2
|
-
GET_PROJECT_LIST_V1 = "v1/organization/projects"
|
|
3
|
-
GET_PROJECT_V1 = "v1/organization/project/{id}"
|
|
4
|
-
CREATE_PROJECT_V1 = "v1/organization/project"
|
|
5
|
-
UPDATE_PROJECT_V1 = "v1/organization/project/{id}"
|
|
6
|
-
DELETE_PROJECT_V1 = "v1/organization/project/{id}"
|
|
7
|
-
GET_PROJECT_TOKENS_V1 = "v1/organization/project/{id}/tokens"
|
|
8
|
-
GET_REQUEST_DATA_V1 = "v1/organization/request/export"
|
|
2
|
+
GET_PROJECT_LIST_V1 = "v1/organization/projects" # GET - Gets the list of projects
|
|
3
|
+
GET_PROJECT_V1 = "v1/organization/project/{id}" # GET - Gets project details
|
|
4
|
+
CREATE_PROJECT_V1 = "v1/organization/project" # POST - Creates a project
|
|
5
|
+
UPDATE_PROJECT_V1 = "v1/organization/project/{id}" # PUT - Updates a project
|
|
6
|
+
DELETE_PROJECT_V1 = "v1/organization/project/{id}" # DELETE - Deletes a project
|
|
7
|
+
GET_PROJECT_TOKENS_V1 = "v1/organization/project/{id}/tokens" # GET - Gets the list of Tokens for the project
|
|
8
|
+
GET_REQUEST_DATA_V1 = "v1/organization/request/export" # GET - Exports request data
|
|
9
9
|
GET_MEMBERSHIPS_V2 = "v2/accessControl/memberships" # GET - Lists Organizations and Projects a user belongs to with their Roles
|
|
10
10
|
GET_PROJECT_MEMBERSHIPS_V2 = "v2/accessControl/projects/memberships" # GET - Lists Projects and Roles for a user within a specific Organization
|
|
11
11
|
GET_PROJECT_ROLES_V2 = "v2/accessControl/projects/roles" # GET - Lists all Roles supported by a specific Project
|
|
12
12
|
GET_PROJECT_MEMBERS_V2 = "v2/accessControl/projects/members" # GET - Lists all members and their Roles for a specific Project
|
|
13
13
|
GET_ORGANIZATION_MEMBERS_V2 = "v2/accessControl/organizations/members" # GET - Lists all members and their Roles for a specific Organization
|
|
14
|
+
ADD_PROJECT_MEMBER_V2 = "v2/accessControl/projects/members" # POST - Adds a member to a project by sending an invitation
|
|
15
|
+
CREATE_ORGANIZATION_V2 = "v2/admin/organizations" # POST - Creates a new Organization
|
|
16
|
+
GET_ORGANIZATION_LIST_V2 = "v2/admin/organizations" # GET - Retrieves all the organizations available based on a given search criteria
|
|
17
|
+
DELETE_ORGANIZATION_V2 = "v2/admin/organizations/{organizationId}" # DELETE - Deletes the created Organization
|
pygeai/organization/managers.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from pygeai import logger
|
|
2
2
|
from pygeai.core.base.mappers import ErrorMapper, ResponseMapper
|
|
3
3
|
from pygeai.core.handlers import ErrorHandler
|
|
4
|
-
from pygeai.core.models import Project
|
|
4
|
+
from pygeai.core.models import Project, Organization
|
|
5
5
|
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
9
|
ProjectTokensResponse, ProjectItemListResponse, MembershipsResponse, ProjectMembershipsResponse, \
|
|
10
|
-
ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse
|
|
10
|
+
ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse, OrganizationListResponse, \
|
|
11
|
+
OrganizationDataResponse
|
|
11
12
|
from pygeai.core.common.exceptions import APIError
|
|
12
13
|
|
|
13
14
|
|
|
@@ -403,3 +404,134 @@ class OrganizationManager:
|
|
|
403
404
|
|
|
404
405
|
result = OrganizationResponseMapper.map_to_organization_members_response(response_data)
|
|
405
406
|
return result
|
|
407
|
+
|
|
408
|
+
def add_project_member(
|
|
409
|
+
self,
|
|
410
|
+
project_id: str,
|
|
411
|
+
user_email: str,
|
|
412
|
+
roles: list
|
|
413
|
+
) -> EmptyResponse:
|
|
414
|
+
"""
|
|
415
|
+
Adds a user to a project by sending an invitation with the specified roles.
|
|
416
|
+
|
|
417
|
+
This method calls `OrganizationClient.add_project_member` to invite a user to the project
|
|
418
|
+
and maps the response to an `EmptyResponse`.
|
|
419
|
+
|
|
420
|
+
:param project_id: str - The unique identifier of the project.
|
|
421
|
+
:param user_email: str - The email address of the user to invite.
|
|
422
|
+
:param roles: list - A list of role names or GUIDs to assign to the user.
|
|
423
|
+
:return: EmptyResponse - An empty response indicating successful invitation.
|
|
424
|
+
:raises APIError: If the API returns errors.
|
|
425
|
+
"""
|
|
426
|
+
response_data = self.__organization_client.add_project_member(
|
|
427
|
+
project_id=project_id,
|
|
428
|
+
user_email=user_email,
|
|
429
|
+
roles=roles
|
|
430
|
+
)
|
|
431
|
+
if ErrorHandler.has_errors(response_data):
|
|
432
|
+
error = ErrorHandler.extract_error(response_data)
|
|
433
|
+
logger.error(f"Error received while adding project member: {error}")
|
|
434
|
+
raise APIError(f"Error received while adding project member: {error}")
|
|
435
|
+
|
|
436
|
+
result = ResponseMapper.map_to_empty_response(response_data or "Invitation sent successfully")
|
|
437
|
+
return result
|
|
438
|
+
|
|
439
|
+
def create_organization(
|
|
440
|
+
self,
|
|
441
|
+
name: str,
|
|
442
|
+
administrator_user_email: str
|
|
443
|
+
) -> OrganizationDataResponse:
|
|
444
|
+
"""
|
|
445
|
+
Creates a new organization with the given details.
|
|
446
|
+
|
|
447
|
+
This endpoint requires an OAuth access token from the System Administrator role.
|
|
448
|
+
|
|
449
|
+
This method calls `OrganizationClient.create_organization` to create a new organization and maps the response
|
|
450
|
+
using `OrganizationResponseMapper` into an `OrganizationDataResponse` object.
|
|
451
|
+
|
|
452
|
+
:param name: str - The name of the new organization (required).
|
|
453
|
+
:param administrator_user_email: str - The email address of the organization administrator (required).
|
|
454
|
+
:return: OrganizationDataResponse - The mapped response containing the created organization details.
|
|
455
|
+
:raises APIError: If the API returns errors.
|
|
456
|
+
"""
|
|
457
|
+
response_data = self.__organization_client.create_organization(
|
|
458
|
+
name=name,
|
|
459
|
+
administrator_user_email=administrator_user_email
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
if ErrorHandler.has_errors(response_data):
|
|
463
|
+
error = ErrorHandler.extract_error(response_data)
|
|
464
|
+
logger.error(f"Error received while creating organization: {error}")
|
|
465
|
+
raise APIError(f"Error received while creating organization: {error}")
|
|
466
|
+
|
|
467
|
+
result = OrganizationResponseMapper.map_to_organization_data_response(response_data)
|
|
468
|
+
return result
|
|
469
|
+
|
|
470
|
+
def get_organization_list(
|
|
471
|
+
self,
|
|
472
|
+
start_page: int = None,
|
|
473
|
+
page_size: int = None,
|
|
474
|
+
order_key: str = None,
|
|
475
|
+
order_direction: str = "desc",
|
|
476
|
+
filter_key: str = None,
|
|
477
|
+
filter_value: str = None
|
|
478
|
+
) -> OrganizationListResponse:
|
|
479
|
+
"""
|
|
480
|
+
Retrieves a list of organizations based on the specified search criteria.
|
|
481
|
+
|
|
482
|
+
This endpoint requires an OAuth access token from the System Administrator role.
|
|
483
|
+
|
|
484
|
+
This method calls `OrganizationClient.get_organization_list` to fetch organization data
|
|
485
|
+
and maps the response using `OrganizationResponseMapper` into an `OrganizationListResponse` object.
|
|
486
|
+
|
|
487
|
+
:param start_page: int, optional - The page number for pagination.
|
|
488
|
+
:param page_size: int, optional - The number of items per page.
|
|
489
|
+
:param order_key: str, optional - Field for sorting. Only 'name' is supported.
|
|
490
|
+
:param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
|
|
491
|
+
:param filter_key: str, optional - Field for filtering. Only 'name' is supported.
|
|
492
|
+
:param filter_value: str, optional - Value to filter by.
|
|
493
|
+
:return: OrganizationListResponse - The mapped response containing the list of organizations.
|
|
494
|
+
:raises APIError: If the API returns errors.
|
|
495
|
+
"""
|
|
496
|
+
response_data = self.__organization_client.get_organization_list(
|
|
497
|
+
start_page=start_page,
|
|
498
|
+
page_size=page_size,
|
|
499
|
+
order_key=order_key,
|
|
500
|
+
order_direction=order_direction,
|
|
501
|
+
filter_key=filter_key,
|
|
502
|
+
filter_value=filter_value
|
|
503
|
+
)
|
|
504
|
+
if ErrorHandler.has_errors(response_data):
|
|
505
|
+
error = ErrorHandler.extract_error(response_data)
|
|
506
|
+
logger.error(f"Error received while retrieving organization list: {error}")
|
|
507
|
+
raise APIError(f"Error received while retrieving organization list: {error}")
|
|
508
|
+
|
|
509
|
+
result = OrganizationResponseMapper.map_to_organization_list_response(response_data)
|
|
510
|
+
return result
|
|
511
|
+
|
|
512
|
+
def delete_organization(
|
|
513
|
+
self,
|
|
514
|
+
organization_id: str
|
|
515
|
+
) -> EmptyResponse:
|
|
516
|
+
"""
|
|
517
|
+
Deletes an organization by its unique identifier.
|
|
518
|
+
|
|
519
|
+
This endpoint requires an OAuth access token from the System Administrator role.
|
|
520
|
+
|
|
521
|
+
This method calls `OrganizationClient.delete_organization` to remove an organization and maps the response
|
|
522
|
+
using `ResponseMapper.map_to_empty_response`.
|
|
523
|
+
|
|
524
|
+
:param organization_id: str - The unique identifier of the organization to be deleted.
|
|
525
|
+
:return: EmptyResponse - An empty response indicating successful deletion.
|
|
526
|
+
:raises APIError: If the API returns errors.
|
|
527
|
+
"""
|
|
528
|
+
response_data = self.__organization_client.delete_organization(
|
|
529
|
+
organization_id=organization_id
|
|
530
|
+
)
|
|
531
|
+
if ErrorHandler.has_errors(response_data):
|
|
532
|
+
error = ErrorHandler.extract_error(response_data)
|
|
533
|
+
logger.error(f"Error received while deleting organization: {error}")
|
|
534
|
+
raise APIError(f"Error received while deleting organization: {error}")
|
|
535
|
+
|
|
536
|
+
result = ResponseMapper.map_to_empty_response(response_data or "Organization deleted successfully")
|
|
537
|
+
return result
|
pygeai/organization/mappers.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from pygeai.core.base.mappers import ModelMapper
|
|
2
|
-
from pygeai.core.models import Assistant, Project, Role, Member, OrganizationMembership, ProjectMembership
|
|
2
|
+
from pygeai.core.models import Assistant, Project, Role, Member, OrganizationMembership, ProjectMembership, Organization
|
|
3
3
|
from pygeai.organization.responses import AssistantListResponse, ProjectListResponse, ProjectDataResponse, \
|
|
4
4
|
ProjectTokensResponse, ProjectItemListResponse, MembershipsResponse, ProjectMembershipsResponse, \
|
|
5
|
-
ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse
|
|
5
|
+
ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse, OrganizationListResponse, \
|
|
6
|
+
OrganizationDataResponse
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class OrganizationResponseMapper:
|
|
@@ -150,3 +151,28 @@ class OrganizationResponseMapper:
|
|
|
150
151
|
members=members
|
|
151
152
|
)
|
|
152
153
|
|
|
154
|
+
@classmethod
|
|
155
|
+
def map_to_organization_list_response(cls, data: dict) -> OrganizationListResponse:
|
|
156
|
+
count = data.get("count", 0)
|
|
157
|
+
pages = data.get("pages", 0)
|
|
158
|
+
organizations_data = data.get("organizations", [])
|
|
159
|
+
organizations = []
|
|
160
|
+
|
|
161
|
+
for org_data in organizations_data:
|
|
162
|
+
organization = Organization.model_validate(org_data)
|
|
163
|
+
organizations.append(organization)
|
|
164
|
+
|
|
165
|
+
return OrganizationListResponse(
|
|
166
|
+
count=count,
|
|
167
|
+
pages=pages,
|
|
168
|
+
organizations=organizations
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
def map_to_organization_data_response(cls, data: dict) -> OrganizationDataResponse:
|
|
173
|
+
organization = Organization.model_validate(data)
|
|
174
|
+
|
|
175
|
+
return OrganizationDataResponse(
|
|
176
|
+
organization=organization
|
|
177
|
+
)
|
|
178
|
+
|
pygeai/organization/responses.py
CHANGED
|
@@ -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, Role, Member, OrganizationMembership, ProjectMembership
|
|
4
|
+
RequestItem, Role, Member, OrganizationMembership, ProjectMembership, Organization
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class AssistantListResponse(BaseModel):
|
|
@@ -69,3 +69,13 @@ class ProjectMembersResponse(BaseModel):
|
|
|
69
69
|
|
|
70
70
|
class OrganizationMembersResponse(BaseModel):
|
|
71
71
|
members: list[Member]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class OrganizationListResponse(BaseModel):
|
|
75
|
+
count: int
|
|
76
|
+
pages: int
|
|
77
|
+
organizations: list[Organization]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class OrganizationDataResponse(BaseModel):
|
|
81
|
+
organization: Organization
|
|
File without changes
|