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.
- pygeai/_docs/source/conf.py +78 -6
- pygeai/_docs/source/content/api_reference/admin.rst +161 -0
- pygeai/_docs/source/content/api_reference/assistant.rst +326 -0
- pygeai/_docs/source/content/api_reference/auth.rst +379 -0
- pygeai/_docs/source/content/api_reference/embeddings.rst +31 -1
- pygeai/_docs/source/content/api_reference/evaluation.rst +590 -0
- pygeai/_docs/source/content/api_reference/feedback.rst +237 -0
- pygeai/_docs/source/content/api_reference/files.rst +592 -0
- pygeai/_docs/source/content/api_reference/gam.rst +401 -0
- pygeai/_docs/source/content/api_reference/health.rst +58 -0
- pygeai/_docs/source/content/api_reference/project.rst +20 -18
- pygeai/_docs/source/content/api_reference/proxy.rst +318 -0
- pygeai/_docs/source/content/api_reference/rerank.rst +94 -0
- pygeai/_docs/source/content/api_reference/secrets.rst +495 -0
- pygeai/_docs/source/content/api_reference/usage_limits.rst +390 -0
- pygeai/_docs/source/content/api_reference.rst +13 -1
- pygeai/_docs/source/content/debugger.rst +376 -83
- pygeai/_docs/source/content/migration.rst +528 -0
- pygeai/_docs/source/content/modules.rst +1 -1
- pygeai/_docs/source/index.rst +59 -7
- pygeai/_docs/source/pygeai.auth.rst +29 -0
- pygeai/_docs/source/pygeai.cli.commands.rst +16 -0
- pygeai/_docs/source/pygeai.cli.rst +8 -0
- pygeai/_docs/source/pygeai.core.utils.rst +16 -0
- pygeai/_docs/source/pygeai.rst +1 -0
- pygeai/_docs/source/pygeai.tests.auth.rst +21 -0
- pygeai/_docs/source/pygeai.tests.cli.commands.rst +16 -0
- pygeai/_docs/source/pygeai.tests.cli.rst +16 -0
- pygeai/_docs/source/pygeai.tests.core.base.rst +8 -0
- pygeai/_docs/source/pygeai.tests.core.embeddings.rst +16 -0
- pygeai/_docs/source/pygeai.tests.core.files.rst +8 -0
- pygeai/_docs/source/pygeai.tests.core.plugins.rst +21 -0
- pygeai/_docs/source/pygeai.tests.core.rst +1 -0
- pygeai/_docs/source/pygeai.tests.evaluation.dataset.rst +21 -0
- pygeai/_docs/source/pygeai.tests.evaluation.plan.rst +21 -0
- pygeai/_docs/source/pygeai.tests.evaluation.result.rst +21 -0
- pygeai/_docs/source/pygeai.tests.evaluation.rst +20 -0
- pygeai/_docs/source/pygeai.tests.integration.lab.processes.rst +8 -0
- pygeai/_docs/source/pygeai.tests.organization.rst +8 -0
- pygeai/_docs/source/pygeai.tests.rst +2 -0
- pygeai/_docs/source/pygeai.tests.snippets.auth.rst +10 -0
- pygeai/_docs/source/pygeai.tests.snippets.chat.rst +40 -0
- pygeai/_docs/source/pygeai.tests.snippets.dbg.rst +45 -0
- pygeai/_docs/source/pygeai.tests.snippets.embeddings.rst +40 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.dataset.rst +197 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.plan.rst +133 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.result.rst +37 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.rst +10 -0
- pygeai/_docs/source/pygeai.tests.snippets.organization.rst +40 -0
- pygeai/_docs/source/pygeai.tests.snippets.rst +2 -0
- pygeai/admin/clients.py +12 -32
- pygeai/assistant/clients.py +16 -44
- pygeai/assistant/data/clients.py +1 -0
- pygeai/assistant/data_analyst/clients.py +6 -13
- pygeai/assistant/rag/clients.py +24 -67
- pygeai/auth/clients.py +88 -14
- pygeai/auth/endpoints.py +4 -0
- pygeai/chat/clients.py +192 -25
- pygeai/chat/endpoints.py +2 -1
- pygeai/cli/commands/auth.py +178 -2
- pygeai/cli/commands/chat.py +227 -1
- pygeai/cli/commands/embeddings.py +56 -8
- pygeai/cli/commands/lab/ai_lab.py +0 -2
- pygeai/cli/commands/migrate.py +994 -434
- pygeai/cli/commands/organization.py +241 -0
- pygeai/cli/error_handler.py +116 -0
- pygeai/cli/geai.py +28 -10
- pygeai/cli/parsers.py +8 -2
- pygeai/core/base/clients.py +4 -1
- pygeai/core/common/exceptions.py +11 -10
- pygeai/core/embeddings/__init__.py +19 -0
- pygeai/core/embeddings/clients.py +20 -9
- pygeai/core/embeddings/mappers.py +16 -2
- pygeai/core/embeddings/responses.py +9 -2
- pygeai/core/feedback/clients.py +4 -8
- pygeai/core/files/clients.py +10 -25
- pygeai/core/files/managers.py +42 -0
- pygeai/core/llm/clients.py +11 -26
- pygeai/core/models.py +107 -0
- pygeai/core/plugins/clients.py +4 -7
- pygeai/core/rerank/clients.py +4 -8
- pygeai/core/secrets/clients.py +14 -37
- pygeai/core/services/rest.py +1 -1
- pygeai/core/utils/parsers.py +32 -0
- pygeai/core/utils/validators.py +10 -0
- pygeai/dbg/__init__.py +3 -0
- pygeai/dbg/debugger.py +565 -70
- pygeai/evaluation/clients.py +2 -1
- pygeai/evaluation/dataset/clients.py +46 -44
- pygeai/evaluation/plan/clients.py +28 -26
- pygeai/evaluation/result/clients.py +38 -5
- pygeai/gam/clients.py +10 -25
- pygeai/health/clients.py +4 -7
- pygeai/lab/agents/clients.py +21 -54
- pygeai/lab/agents/endpoints.py +2 -0
- pygeai/lab/clients.py +1 -0
- pygeai/lab/models.py +3 -3
- pygeai/lab/processes/clients.py +45 -127
- pygeai/lab/strategies/clients.py +11 -25
- pygeai/lab/tools/clients.py +23 -67
- pygeai/lab/tools/endpoints.py +3 -0
- pygeai/migration/__init__.py +31 -0
- pygeai/migration/strategies.py +404 -155
- pygeai/migration/tools.py +170 -3
- pygeai/organization/clients.py +135 -51
- pygeai/organization/endpoints.py +6 -1
- pygeai/organization/limits/clients.py +32 -91
- pygeai/organization/managers.py +157 -1
- pygeai/organization/mappers.py +76 -2
- pygeai/organization/responses.py +25 -1
- pygeai/proxy/clients.py +4 -1
- pygeai/tests/admin/test_clients.py +16 -11
- pygeai/tests/assistants/rag/test_clients.py +35 -23
- pygeai/tests/assistants/test_clients.py +22 -15
- pygeai/tests/auth/test_clients.py +191 -7
- pygeai/tests/chat/test_clients.py +211 -1
- pygeai/tests/cli/commands/test_embeddings.py +32 -9
- pygeai/tests/cli/commands/test_evaluation.py +7 -0
- pygeai/tests/cli/commands/test_migrate.py +112 -243
- pygeai/tests/cli/test_error_handler.py +225 -0
- pygeai/tests/cli/test_geai_driver.py +154 -0
- pygeai/tests/cli/test_parsers.py +5 -5
- pygeai/tests/core/embeddings/test_clients.py +144 -0
- pygeai/tests/core/embeddings/test_managers.py +171 -0
- pygeai/tests/core/embeddings/test_mappers.py +142 -0
- pygeai/tests/core/feedback/test_clients.py +2 -0
- pygeai/tests/core/files/test_clients.py +1 -0
- pygeai/tests/core/llm/test_clients.py +14 -9
- pygeai/tests/core/plugins/test_clients.py +5 -3
- pygeai/tests/core/rerank/test_clients.py +1 -0
- pygeai/tests/core/secrets/test_clients.py +19 -13
- pygeai/tests/dbg/test_debugger.py +453 -75
- pygeai/tests/evaluation/dataset/test_clients.py +3 -1
- pygeai/tests/evaluation/plan/test_clients.py +4 -2
- pygeai/tests/evaluation/result/test_clients.py +7 -5
- pygeai/tests/gam/test_clients.py +1 -1
- pygeai/tests/health/test_clients.py +1 -0
- pygeai/tests/lab/agents/test_clients.py +9 -0
- pygeai/tests/lab/processes/test_clients.py +36 -0
- pygeai/tests/lab/processes/test_mappers.py +3 -0
- pygeai/tests/lab/strategies/test_clients.py +14 -9
- pygeai/tests/migration/test_strategies.py +45 -218
- pygeai/tests/migration/test_tools.py +133 -9
- pygeai/tests/organization/limits/test_clients.py +17 -0
- pygeai/tests/organization/test_clients.py +206 -1
- pygeai/tests/organization/test_managers.py +122 -1
- pygeai/tests/proxy/test_clients.py +2 -0
- pygeai/tests/proxy/test_integration.py +1 -0
- pygeai/tests/snippets/auth/__init__.py +0 -0
- pygeai/tests/snippets/chat/chat_completion_with_reasoning_effort.py +18 -0
- pygeai/tests/snippets/chat/get_response.py +15 -0
- pygeai/tests/snippets/chat/get_response_streaming.py +20 -0
- pygeai/tests/snippets/chat/get_response_with_files.py +16 -0
- pygeai/tests/snippets/chat/get_response_with_tools.py +36 -0
- pygeai/tests/snippets/dbg/__init__.py +0 -0
- pygeai/tests/snippets/dbg/basic_debugging.py +32 -0
- pygeai/tests/snippets/dbg/breakpoint_management.py +48 -0
- pygeai/tests/snippets/dbg/stack_navigation.py +45 -0
- pygeai/tests/snippets/dbg/stepping_example.py +40 -0
- pygeai/tests/snippets/embeddings/cache_example.py +31 -0
- pygeai/tests/snippets/embeddings/cohere_example.py +41 -0
- pygeai/tests/snippets/embeddings/openai_base64_example.py +27 -0
- pygeai/tests/snippets/embeddings/openai_example.py +30 -0
- pygeai/tests/snippets/embeddings/similarity_example.py +42 -0
- pygeai/tests/snippets/evaluation/dataset/__init__.py +0 -0
- pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +195 -0
- pygeai/tests/snippets/evaluation/dataset/create_dataset.py +26 -0
- pygeai/tests/snippets/evaluation/dataset/create_dataset_from_file.py +11 -0
- pygeai/tests/snippets/evaluation/dataset/create_dataset_row.py +17 -0
- pygeai/tests/snippets/evaluation/dataset/create_expected_source.py +18 -0
- pygeai/tests/snippets/evaluation/dataset/create_filter_variable.py +19 -0
- pygeai/tests/snippets/evaluation/dataset/delete_dataset.py +9 -0
- pygeai/tests/snippets/evaluation/dataset/delete_dataset_row.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/delete_expected_source.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/delete_filter_variable.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/get_dataset.py +9 -0
- pygeai/tests/snippets/evaluation/dataset/get_dataset_row.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/get_expected_source.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/get_filter_variable.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/list_dataset_rows.py +9 -0
- pygeai/tests/snippets/evaluation/dataset/list_datasets.py +6 -0
- pygeai/tests/snippets/evaluation/dataset/list_expected_sources.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/list_filter_variables.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/update_dataset.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/update_dataset_row.py +20 -0
- pygeai/tests/snippets/evaluation/dataset/update_expected_source.py +18 -0
- pygeai/tests/snippets/evaluation/dataset/update_filter_variable.py +19 -0
- pygeai/tests/snippets/evaluation/dataset/upload_dataset_rows_file.py +10 -0
- pygeai/tests/snippets/evaluation/plan/__init__.py +0 -0
- pygeai/tests/snippets/evaluation/plan/add_plan_system_metric.py +13 -0
- pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +136 -0
- pygeai/tests/snippets/evaluation/plan/create_evaluation_plan.py +24 -0
- pygeai/tests/snippets/evaluation/plan/create_rag_evaluation_plan.py +22 -0
- pygeai/tests/snippets/evaluation/plan/delete_evaluation_plan.py +9 -0
- pygeai/tests/snippets/evaluation/plan/delete_plan_system_metric.py +13 -0
- pygeai/tests/snippets/evaluation/plan/execute_evaluation_plan.py +11 -0
- pygeai/tests/snippets/evaluation/plan/get_evaluation_plan.py +9 -0
- pygeai/tests/snippets/evaluation/plan/get_plan_system_metric.py +13 -0
- pygeai/tests/snippets/evaluation/plan/get_system_metric.py +9 -0
- pygeai/tests/snippets/evaluation/plan/list_evaluation_plans.py +7 -0
- pygeai/tests/snippets/evaluation/plan/list_plan_system_metrics.py +9 -0
- pygeai/tests/snippets/evaluation/plan/list_system_metrics.py +7 -0
- pygeai/tests/snippets/evaluation/plan/update_evaluation_plan.py +22 -0
- pygeai/tests/snippets/evaluation/plan/update_plan_system_metric.py +14 -0
- pygeai/tests/snippets/evaluation/result/__init__.py +0 -0
- pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +150 -0
- pygeai/tests/snippets/evaluation/result/get_evaluation_result.py +26 -0
- pygeai/tests/snippets/evaluation/result/list_evaluation_results.py +17 -0
- pygeai/tests/snippets/migrate/__init__.py +45 -0
- pygeai/tests/snippets/migrate/agent_migration.py +110 -0
- pygeai/tests/snippets/migrate/assistant_migration.py +64 -0
- pygeai/tests/snippets/migrate/orchestrator_examples.py +179 -0
- pygeai/tests/snippets/migrate/process_migration.py +64 -0
- pygeai/tests/snippets/migrate/project_migration.py +42 -0
- pygeai/tests/snippets/migrate/tool_migration.py +64 -0
- pygeai/tests/snippets/organization/create_project.py +2 -2
- pygeai/tests/snippets/organization/get_memberships.py +12 -0
- pygeai/tests/snippets/organization/get_organization_members.py +6 -0
- pygeai/tests/snippets/organization/get_project_members.py +6 -0
- pygeai/tests/snippets/organization/get_project_memberships.py +12 -0
- pygeai/tests/snippets/organization/get_project_roles.py +6 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/METADATA +1 -1
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/RECORD +227 -124
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/WHEEL +0 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/entry_points.txt +0 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/top_level.txt +0 -0
pygeai/migration/strategies.py
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Optional
|
|
3
4
|
|
|
4
|
-
from pygeai
|
|
5
|
+
from pygeai import logger
|
|
6
|
+
from pygeai.core.models import Project, UsageLimit
|
|
5
7
|
from pygeai.core.base.responses import ErrorListResponse
|
|
6
8
|
from pygeai.core.utils.console import Console
|
|
9
|
+
from pygeai.core.files.managers import FileManager
|
|
10
|
+
from pygeai.core.files.models import File
|
|
7
11
|
from pygeai.lab.managers import AILabManager
|
|
8
12
|
from pygeai.lab.models import Agent, Tool, AgenticProcess, Task
|
|
13
|
+
from pygeai.organization.limits.managers import UsageLimitManager
|
|
9
14
|
from pygeai.organization.managers import OrganizationManager
|
|
15
|
+
from pygeai.assistant.managers import AssistantManager
|
|
16
|
+
from pygeai.assistant.rag.models import RAGAssistant
|
|
10
17
|
|
|
11
18
|
|
|
12
19
|
class MigrationStrategy(ABC):
|
|
13
20
|
|
|
14
21
|
def __init__(
|
|
15
22
|
self,
|
|
16
|
-
from_api_key: str
|
|
17
|
-
from_instance: str
|
|
18
|
-
to_api_key: str = None,
|
|
19
|
-
to_instance: str = None
|
|
23
|
+
from_api_key: str,
|
|
24
|
+
from_instance: str,
|
|
25
|
+
to_api_key: Optional[str] = None,
|
|
26
|
+
to_instance: Optional[str] = None
|
|
20
27
|
):
|
|
21
28
|
self.from_api_key = from_api_key
|
|
22
29
|
self.from_instance = from_instance
|
|
@@ -27,65 +34,196 @@ class MigrationStrategy(ABC):
|
|
|
27
34
|
def migrate(self):
|
|
28
35
|
pass
|
|
29
36
|
|
|
37
|
+
def get_display_info(self) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Return a human-readable description of what this strategy will migrate.
|
|
40
|
+
Used for progress tracking and logging.
|
|
41
|
+
|
|
42
|
+
:return: String description like "agent abc-123" or "project MyProject"
|
|
43
|
+
"""
|
|
44
|
+
return self.__class__.__name__.replace("MigrationStrategy", "").lower()
|
|
45
|
+
|
|
30
46
|
|
|
31
47
|
class ProjectMigrationStrategy(MigrationStrategy):
|
|
32
48
|
"""
|
|
33
49
|
Migrate a project from a GEAI instance.
|
|
34
50
|
The target project can be in another organization or the same one; in the same instance or another.
|
|
51
|
+
|
|
52
|
+
Note: This strategy requires organization scope API keys for both source and destination,
|
|
53
|
+
as it needs to create projects and manage usage limits using the Organization API.
|
|
54
|
+
See: https://docs.globant.ai/en/wiki?22,Organization+API
|
|
35
55
|
"""
|
|
36
56
|
|
|
37
57
|
def __init__(
|
|
38
58
|
self,
|
|
39
|
-
from_api_key: str
|
|
40
|
-
from_instance: str
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
59
|
+
from_api_key: str,
|
|
60
|
+
from_instance: str,
|
|
61
|
+
from_project_id: str,
|
|
62
|
+
to_project_name: str,
|
|
63
|
+
admin_email: str,
|
|
64
|
+
to_api_key: Optional[str] = None,
|
|
65
|
+
to_instance: Optional[str] = None
|
|
46
66
|
):
|
|
47
67
|
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
48
68
|
self.from_project_id = from_project_id
|
|
49
69
|
self.to_project_name = to_project_name
|
|
50
70
|
self.admin_email = admin_email
|
|
51
|
-
self.
|
|
71
|
+
self._source_manager = OrganizationManager(
|
|
52
72
|
api_key=self.from_api_key,
|
|
53
73
|
base_url=self.from_instance
|
|
54
74
|
)
|
|
55
|
-
self.
|
|
75
|
+
self._destination_manager = OrganizationManager(
|
|
56
76
|
api_key=self.to_api_key,
|
|
57
77
|
base_url=self.to_instance
|
|
58
78
|
)
|
|
59
79
|
|
|
80
|
+
def get_display_info(self) -> str:
|
|
81
|
+
return f"project '{self.to_project_name}'"
|
|
82
|
+
|
|
60
83
|
def migrate(self):
|
|
61
|
-
|
|
84
|
+
"""
|
|
85
|
+
Execute the project migration from source to destination instance.
|
|
86
|
+
|
|
87
|
+
:return: The ID of the created project
|
|
88
|
+
:raises ValueError: If project data cannot be retrieved or migration fails
|
|
89
|
+
"""
|
|
90
|
+
new_project = self._migrate_project()
|
|
91
|
+
project_name = getattr(new_project, 'name', 'Unknown')
|
|
92
|
+
project_id = getattr(new_project, 'id', None)
|
|
93
|
+
logger.info(f"Successfully migrated project {self.from_project_id} to {project_name}")
|
|
94
|
+
return project_id
|
|
95
|
+
|
|
96
|
+
def _migrate_project(self) -> Project:
|
|
97
|
+
"""
|
|
98
|
+
Migrate the project data and create it in the destination instance.
|
|
99
|
+
|
|
100
|
+
:return: The newly created project
|
|
101
|
+
:raises ValueError: If project retrieval or creation fails
|
|
102
|
+
"""
|
|
103
|
+
project_data = self._source_manager.get_project_data(project_id=self.from_project_id)
|
|
104
|
+
|
|
105
|
+
if not hasattr(project_data, "project"):
|
|
106
|
+
raise ValueError(f"Unable to retrieve project data for project {self.from_project_id}")
|
|
107
|
+
|
|
108
|
+
new_project = project_data.project
|
|
109
|
+
new_project.name = self.to_project_name
|
|
110
|
+
new_project.email = self.admin_email
|
|
111
|
+
|
|
112
|
+
logger.debug(f"Creating project with destination manager:")
|
|
113
|
+
logger.debug(f" - API Key (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
114
|
+
logger.debug(f" - Base URL: {self.to_instance}")
|
|
115
|
+
logger.debug(f" - Project Name: {self.to_project_name}")
|
|
116
|
+
logger.debug(f" - Admin Email: {self.admin_email}")
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
response = self._destination_manager.create_project(new_project)
|
|
120
|
+
except Exception as e:
|
|
121
|
+
error_msg = f"Create project failed: {e}"
|
|
122
|
+
logger.error(error_msg)
|
|
123
|
+
logger.error(f" - Operation: Create project")
|
|
124
|
+
logger.error(f" - Base URL: {self.to_instance}")
|
|
125
|
+
logger.error(f" - API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
126
|
+
Console.write_stderr(f"\nDEBUG: Operation failed: Create project")
|
|
127
|
+
Console.write_stderr(f"DEBUG: Base URL: {self.to_instance}")
|
|
128
|
+
Console.write_stderr(f"DEBUG: API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
129
|
+
raise ValueError(error_msg) from e
|
|
130
|
+
|
|
62
131
|
if isinstance(response, ErrorListResponse):
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
132
|
+
error_detail = response.to_dict()
|
|
133
|
+
logger.error(f"Create project returned error response: {error_detail}")
|
|
134
|
+
logger.error(f" - Operation: Create project")
|
|
135
|
+
logger.error(f" - Base URL: {self.to_instance}")
|
|
136
|
+
logger.error(f" - API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
137
|
+
Console.write_stderr(f"\nDEBUG: Operation failed: Create project")
|
|
138
|
+
Console.write_stderr(f"DEBUG: Base URL: {self.to_instance}")
|
|
139
|
+
Console.write_stderr(f"DEBUG: API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
140
|
+
raise ValueError(f"Failed to create project: {error_detail}")
|
|
141
|
+
|
|
142
|
+
if not response or not hasattr(response, "project"):
|
|
143
|
+
raise ValueError("Project creation returned invalid response")
|
|
144
|
+
|
|
145
|
+
return response.project
|
|
146
|
+
|
|
147
|
+
def _migrate_assistants(self, new_project: Project):
|
|
148
|
+
"""
|
|
149
|
+
Migrate assistants associated with the project.
|
|
150
|
+
|
|
151
|
+
:param new_project: The newly created project to migrate assistants to
|
|
152
|
+
"""
|
|
153
|
+
pass
|
|
68
154
|
|
|
69
|
-
self.__migrate_assistants(new_project)
|
|
70
155
|
|
|
71
|
-
|
|
156
|
+
class _LabResourceMigrationStrategy(MigrationStrategy):
|
|
157
|
+
"""
|
|
158
|
+
Base class for migrating AI Lab resources (agents, tools, processes, tasks).
|
|
159
|
+
Provides common functionality for resource migration.
|
|
160
|
+
"""
|
|
72
161
|
|
|
73
|
-
def
|
|
74
|
-
|
|
162
|
+
def __init__(
|
|
163
|
+
self,
|
|
164
|
+
from_api_key: str,
|
|
165
|
+
from_instance: str,
|
|
166
|
+
to_api_key: Optional[str] = None,
|
|
167
|
+
to_instance: Optional[str] = None
|
|
168
|
+
):
|
|
169
|
+
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
170
|
+
self._source_manager = AILabManager(
|
|
171
|
+
api_key=self.from_api_key,
|
|
172
|
+
base_url=self.from_instance
|
|
173
|
+
)
|
|
174
|
+
self._destination_manager = AILabManager(
|
|
175
|
+
api_key=self.to_api_key,
|
|
176
|
+
base_url=self.to_instance
|
|
177
|
+
)
|
|
75
178
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
response = self.destination_manager.create_project(new_project)
|
|
179
|
+
@abstractmethod
|
|
180
|
+
def _get_resource(self, resource_id: str):
|
|
181
|
+
"""Retrieve the resource from source instance"""
|
|
182
|
+
pass
|
|
81
183
|
|
|
82
|
-
|
|
184
|
+
@abstractmethod
|
|
185
|
+
def _create_resource(self, resource):
|
|
186
|
+
"""Create the resource in destination instance"""
|
|
187
|
+
pass
|
|
83
188
|
|
|
84
|
-
|
|
189
|
+
@abstractmethod
|
|
190
|
+
def _get_resource_name(self) -> str:
|
|
191
|
+
"""Return the name of the resource type for logging/errors"""
|
|
85
192
|
pass
|
|
86
193
|
|
|
194
|
+
def get_display_info(self) -> str:
|
|
195
|
+
resource_id = getattr(self, f"{self._get_resource_name()}_id", "unknown")
|
|
196
|
+
return f"{self._get_resource_name()} {resource_id}"
|
|
87
197
|
|
|
88
|
-
|
|
198
|
+
def migrate(self):
|
|
199
|
+
"""
|
|
200
|
+
Execute the resource migration from source to destination instance.
|
|
201
|
+
|
|
202
|
+
:raises ValueError: If resource retrieval or creation fails
|
|
203
|
+
"""
|
|
204
|
+
resource_id = getattr(self, f"{self._get_resource_name()}_id")
|
|
205
|
+
new_resource = self._migrate_resource(resource_id)
|
|
206
|
+
Console.write_stdout(f"New {self._get_resource_name()} detail: \n{new_resource}")
|
|
207
|
+
logger.info(f"Successfully migrated {self._get_resource_name()} {resource_id}")
|
|
208
|
+
|
|
209
|
+
def _migrate_resource(self, resource_id: str):
|
|
210
|
+
"""
|
|
211
|
+
Retrieve resource from source and create in destination.
|
|
212
|
+
|
|
213
|
+
:param resource_id: The ID of the resource to migrate
|
|
214
|
+
:return: The newly created resource
|
|
215
|
+
:raises ValueError: If migration fails
|
|
216
|
+
"""
|
|
217
|
+
try:
|
|
218
|
+
source_resource = self._get_resource(resource_id)
|
|
219
|
+
new_resource = self._create_resource(source_resource)
|
|
220
|
+
return new_resource
|
|
221
|
+
except Exception as e:
|
|
222
|
+
logger.error(f"{self._get_resource_name().capitalize()} migration failed: {e}")
|
|
223
|
+
raise ValueError(f"{self._get_resource_name().capitalize()} migration failed: {e}") from e
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class AgentMigrationStrategy(_LabResourceMigrationStrategy):
|
|
89
227
|
"""
|
|
90
228
|
Migrate an agent from a GEAI instance.
|
|
91
229
|
The target project can be in another organization or the same one; in the same instance or another.
|
|
@@ -93,49 +231,29 @@ class AgentMigrationStrategy(MigrationStrategy):
|
|
|
93
231
|
|
|
94
232
|
def __init__(
|
|
95
233
|
self,
|
|
96
|
-
from_api_key: str
|
|
97
|
-
from_instance: str
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
to_project_id: str = None,
|
|
102
|
-
agent_id: str = None
|
|
234
|
+
from_api_key: str,
|
|
235
|
+
from_instance: str,
|
|
236
|
+
agent_id: str,
|
|
237
|
+
to_api_key: Optional[str] = None,
|
|
238
|
+
to_instance: Optional[str] = None
|
|
103
239
|
):
|
|
104
240
|
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
105
|
-
self.from_project_id = from_project_id
|
|
106
|
-
self.to_project_id = to_project_id
|
|
107
241
|
self.agent_id = agent_id
|
|
108
|
-
self.source_manager = AILabManager(
|
|
109
|
-
api_key=self.from_api_key,
|
|
110
|
-
base_url=self.from_instance
|
|
111
|
-
)
|
|
112
|
-
self.destination_manager = AILabManager(
|
|
113
|
-
api_key=self.to_api_key,
|
|
114
|
-
base_url=self.to_instance
|
|
115
|
-
)
|
|
116
242
|
|
|
117
|
-
def
|
|
118
|
-
|
|
119
|
-
if isinstance(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
Console.write_stdout(f"New agent detail: \n{new_agent}")
|
|
123
|
-
|
|
124
|
-
def __migrate_agent(self):
|
|
125
|
-
new_agent = None
|
|
126
|
-
try:
|
|
127
|
-
source_agent = self.source_manager.get_agent(agent_id=self.agent_id)
|
|
128
|
-
if not isinstance(source_agent, Agent):
|
|
129
|
-
raise ValueError("Unable to retrieve requested agent.")
|
|
243
|
+
def _get_resource(self, resource_id: str) -> Agent:
|
|
244
|
+
agent = self._source_manager.get_agent(agent_id=resource_id)
|
|
245
|
+
if not isinstance(agent, Agent):
|
|
246
|
+
raise ValueError(f"Unable to retrieve agent {resource_id}")
|
|
247
|
+
return agent
|
|
130
248
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
Console.write_stderr(f"Agent migration failed: {e} \n")
|
|
249
|
+
def _create_resource(self, resource: Agent) -> Agent:
|
|
250
|
+
return self._destination_manager.create_agent(agent=resource)
|
|
134
251
|
|
|
135
|
-
|
|
252
|
+
def _get_resource_name(self) -> str:
|
|
253
|
+
return "agent"
|
|
136
254
|
|
|
137
255
|
|
|
138
|
-
class ToolMigrationStrategy(
|
|
256
|
+
class ToolMigrationStrategy(_LabResourceMigrationStrategy):
|
|
139
257
|
"""
|
|
140
258
|
Migrate a tool from a GEAI instance.
|
|
141
259
|
The target project can be in another organization or the same one; in the same instance or another.
|
|
@@ -143,143 +261,274 @@ class ToolMigrationStrategy(MigrationStrategy):
|
|
|
143
261
|
|
|
144
262
|
def __init__(
|
|
145
263
|
self,
|
|
146
|
-
from_api_key: str
|
|
147
|
-
from_instance: str
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
to_project_id: str = None,
|
|
152
|
-
tool_id: str = None
|
|
264
|
+
from_api_key: str,
|
|
265
|
+
from_instance: str,
|
|
266
|
+
tool_id: str,
|
|
267
|
+
to_api_key: Optional[str] = None,
|
|
268
|
+
to_instance: Optional[str] = None
|
|
153
269
|
):
|
|
154
270
|
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
155
|
-
self.from_project_id = from_project_id
|
|
156
|
-
self.to_project_id = to_project_id
|
|
157
271
|
self.tool_id = tool_id
|
|
158
|
-
|
|
272
|
+
|
|
273
|
+
def _get_resource(self, resource_id: str) -> Tool:
|
|
274
|
+
tool = self._source_manager.get_tool(tool_id=resource_id)
|
|
275
|
+
if not isinstance(tool, Tool):
|
|
276
|
+
raise ValueError(f"Unable to retrieve tool {resource_id}")
|
|
277
|
+
return tool
|
|
278
|
+
|
|
279
|
+
def _create_resource(self, resource: Tool) -> Tool:
|
|
280
|
+
return self._destination_manager.create_tool(tool=resource)
|
|
281
|
+
|
|
282
|
+
def _get_resource_name(self) -> str:
|
|
283
|
+
return "tool"
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class AgenticProcessMigrationStrategy(_LabResourceMigrationStrategy):
|
|
287
|
+
"""
|
|
288
|
+
Migrate an agentic process from a GEAI instance.
|
|
289
|
+
The target project can be in another organization or the same one; in the same instance or another.
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
def __init__(
|
|
293
|
+
self,
|
|
294
|
+
from_api_key: str,
|
|
295
|
+
from_instance: str,
|
|
296
|
+
process_id: str,
|
|
297
|
+
to_api_key: Optional[str] = None,
|
|
298
|
+
to_instance: Optional[str] = None
|
|
299
|
+
):
|
|
300
|
+
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
301
|
+
self.process_id = process_id
|
|
302
|
+
|
|
303
|
+
def _get_resource(self, resource_id: str) -> AgenticProcess:
|
|
304
|
+
process = self._source_manager.get_process(process_id=resource_id)
|
|
305
|
+
if not isinstance(process, AgenticProcess):
|
|
306
|
+
raise ValueError(f"Unable to retrieve process {resource_id}")
|
|
307
|
+
return process
|
|
308
|
+
|
|
309
|
+
def _create_resource(self, resource: AgenticProcess) -> AgenticProcess:
|
|
310
|
+
return self._destination_manager.create_process(process=resource)
|
|
311
|
+
|
|
312
|
+
def _get_resource_name(self) -> str:
|
|
313
|
+
return "process"
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
class TaskMigrationStrategy(_LabResourceMigrationStrategy):
|
|
317
|
+
"""
|
|
318
|
+
Migrate a task from a GEAI instance.
|
|
319
|
+
The target project can be in another organization or the same one; in the same instance or another.
|
|
320
|
+
"""
|
|
321
|
+
|
|
322
|
+
def __init__(
|
|
323
|
+
self,
|
|
324
|
+
from_api_key: str,
|
|
325
|
+
from_instance: str,
|
|
326
|
+
task_id: str,
|
|
327
|
+
to_api_key: Optional[str] = None,
|
|
328
|
+
to_instance: Optional[str] = None
|
|
329
|
+
):
|
|
330
|
+
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
331
|
+
self.task_id = task_id
|
|
332
|
+
|
|
333
|
+
def _get_resource(self, resource_id: str) -> Task:
|
|
334
|
+
task = self._source_manager.get_task(task_id=resource_id)
|
|
335
|
+
if not isinstance(task, Task):
|
|
336
|
+
raise ValueError(f"Unable to retrieve task {resource_id}")
|
|
337
|
+
return task
|
|
338
|
+
|
|
339
|
+
def _create_resource(self, resource: Task) -> Task:
|
|
340
|
+
return self._destination_manager.create_task(task=resource)
|
|
341
|
+
|
|
342
|
+
def _get_resource_name(self) -> str:
|
|
343
|
+
return "task"
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class UsageLimitMigrationStrategy(MigrationStrategy):
|
|
347
|
+
"""
|
|
348
|
+
Migrate usage limit from a GEAI organization.
|
|
349
|
+
The target organization can be in the same instance or another.
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
def __init__(
|
|
353
|
+
self,
|
|
354
|
+
from_api_key: str,
|
|
355
|
+
from_instance: str,
|
|
356
|
+
from_organization_id: str,
|
|
357
|
+
to_organization_id: str,
|
|
358
|
+
to_api_key: Optional[str] = None,
|
|
359
|
+
to_instance: Optional[str] = None
|
|
360
|
+
):
|
|
361
|
+
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
362
|
+
self.from_organization_id = from_organization_id
|
|
363
|
+
self.to_organization_id = to_organization_id
|
|
364
|
+
self._source_manager = UsageLimitManager(
|
|
159
365
|
api_key=self.from_api_key,
|
|
160
|
-
base_url=self.from_instance
|
|
366
|
+
base_url=self.from_instance,
|
|
367
|
+
organization_id=self.from_organization_id
|
|
161
368
|
)
|
|
162
|
-
self.
|
|
369
|
+
self._destination_manager = UsageLimitManager(
|
|
163
370
|
api_key=self.to_api_key,
|
|
164
|
-
base_url=self.to_instance
|
|
371
|
+
base_url=self.to_instance,
|
|
372
|
+
organization_id=self.to_organization_id
|
|
165
373
|
)
|
|
166
374
|
|
|
375
|
+
def get_display_info(self) -> str:
|
|
376
|
+
return f"usage limits (org {self.from_organization_id})"
|
|
377
|
+
|
|
167
378
|
def migrate(self):
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
379
|
+
"""
|
|
380
|
+
Execute the usage limit migration from source to destination organization.
|
|
381
|
+
|
|
382
|
+
:raises ValueError: If usage limit retrieval or creation fails
|
|
383
|
+
"""
|
|
384
|
+
new_limit = self._migrate_usage_limit()
|
|
385
|
+
logger.info(f"Successfully migrated usage limit from org {self.from_organization_id} to {self.to_organization_id}")
|
|
386
|
+
|
|
387
|
+
def _migrate_usage_limit(self) -> UsageLimit:
|
|
388
|
+
"""
|
|
389
|
+
Retrieve latest usage limit from source and create in destination.
|
|
390
|
+
|
|
391
|
+
:return: The newly created usage limit
|
|
392
|
+
:raises ValueError: If migration fails
|
|
393
|
+
"""
|
|
176
394
|
try:
|
|
177
|
-
|
|
178
|
-
if not isinstance(
|
|
179
|
-
raise ValueError("Unable to retrieve
|
|
395
|
+
source_limit = self._source_manager.get_latest_usage_limit_from_organization()
|
|
396
|
+
if not isinstance(source_limit, UsageLimit):
|
|
397
|
+
raise ValueError("Unable to retrieve usage limit from source organization")
|
|
180
398
|
|
|
181
|
-
|
|
399
|
+
source_limit.id = None
|
|
400
|
+
new_limit = self._destination_manager.set_organization_usage_limit(source_limit)
|
|
401
|
+
return new_limit
|
|
182
402
|
except Exception as e:
|
|
183
|
-
|
|
403
|
+
logger.error(f"Usage limit migration failed: {e}")
|
|
404
|
+
raise ValueError(f"Usage limit migration failed: {e}") from e
|
|
184
405
|
|
|
185
|
-
return new_tool
|
|
186
406
|
|
|
187
|
-
|
|
188
|
-
class AgenticProcessMigrationStrategy(MigrationStrategy):
|
|
407
|
+
class RAGAssistantMigrationStrategy(MigrationStrategy):
|
|
189
408
|
"""
|
|
190
|
-
Migrate
|
|
191
|
-
The target
|
|
409
|
+
Migrate RAG assistant from a GEAI instance.
|
|
410
|
+
The target instance can be the same or another.
|
|
192
411
|
"""
|
|
193
412
|
|
|
194
413
|
def __init__(
|
|
195
414
|
self,
|
|
196
|
-
from_api_key: str
|
|
197
|
-
from_instance: str
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
to_project_id: str = None,
|
|
202
|
-
process_id: str = None
|
|
415
|
+
from_api_key: str,
|
|
416
|
+
from_instance: str,
|
|
417
|
+
assistant_name: str,
|
|
418
|
+
to_api_key: Optional[str] = None,
|
|
419
|
+
to_instance: Optional[str] = None
|
|
203
420
|
):
|
|
204
421
|
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
205
|
-
self.
|
|
206
|
-
self.
|
|
207
|
-
self.process_id = process_id
|
|
208
|
-
self.source_manager = AILabManager(
|
|
422
|
+
self.assistant_name = assistant_name
|
|
423
|
+
self._source_manager = AssistantManager(
|
|
209
424
|
api_key=self.from_api_key,
|
|
210
425
|
base_url=self.from_instance
|
|
211
426
|
)
|
|
212
|
-
self.
|
|
427
|
+
self._destination_manager = AssistantManager(
|
|
213
428
|
api_key=self.to_api_key,
|
|
214
429
|
base_url=self.to_instance
|
|
215
430
|
)
|
|
216
431
|
|
|
432
|
+
def get_display_info(self) -> str:
|
|
433
|
+
return f"RAG assistant '{self.assistant_name}'"
|
|
434
|
+
|
|
217
435
|
def migrate(self):
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
436
|
+
"""
|
|
437
|
+
Execute the RAG assistant migration from source to destination instance.
|
|
438
|
+
|
|
439
|
+
:raises ValueError: If assistant retrieval or creation fails
|
|
440
|
+
"""
|
|
441
|
+
new_assistant = self._migrate_assistant()
|
|
442
|
+
logger.info(f"Successfully migrated RAG assistant {self.assistant_name}")
|
|
443
|
+
|
|
444
|
+
def _migrate_assistant(self) -> RAGAssistant:
|
|
445
|
+
"""
|
|
446
|
+
Retrieve RAG assistant from source and create in destination.
|
|
447
|
+
|
|
448
|
+
:return: The newly created RAG assistant
|
|
449
|
+
:raises ValueError: If migration fails
|
|
450
|
+
"""
|
|
226
451
|
try:
|
|
227
|
-
|
|
228
|
-
if not isinstance(
|
|
229
|
-
raise ValueError("
|
|
452
|
+
source_assistant = self._source_manager.get_assistant_data(assistant_name=self.assistant_name)
|
|
453
|
+
if not isinstance(source_assistant, RAGAssistant):
|
|
454
|
+
raise ValueError(f"Assistant {self.assistant_name} is not a RAG assistant")
|
|
230
455
|
|
|
231
|
-
|
|
456
|
+
source_assistant.id = None
|
|
457
|
+
new_assistant = self._destination_manager.create_assistant(source_assistant)
|
|
458
|
+
return new_assistant
|
|
232
459
|
except Exception as e:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return new_process
|
|
460
|
+
logger.error(f"RAG assistant migration failed: {e}")
|
|
461
|
+
raise ValueError(f"RAG assistant migration failed: {e}") from e
|
|
236
462
|
|
|
237
463
|
|
|
238
|
-
class
|
|
464
|
+
class FileMigrationStrategy(MigrationStrategy):
|
|
239
465
|
"""
|
|
240
|
-
Migrate
|
|
466
|
+
Migrate file from a GEAI project.
|
|
241
467
|
The target project can be in another organization or the same one; in the same instance or another.
|
|
242
468
|
"""
|
|
243
469
|
|
|
244
470
|
def __init__(
|
|
245
471
|
self,
|
|
246
|
-
from_api_key: str
|
|
247
|
-
from_instance: str
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
to_project_id: str
|
|
252
|
-
|
|
472
|
+
from_api_key: str,
|
|
473
|
+
from_instance: str,
|
|
474
|
+
from_organization_id: str,
|
|
475
|
+
from_project_id: str,
|
|
476
|
+
to_organization_id: str,
|
|
477
|
+
to_project_id: str,
|
|
478
|
+
file_id: str,
|
|
479
|
+
to_api_key: Optional[str] = None,
|
|
480
|
+
to_instance: Optional[str] = None
|
|
253
481
|
):
|
|
254
482
|
super().__init__(from_api_key, from_instance, to_api_key, to_instance)
|
|
483
|
+
self.from_organization_id = from_organization_id
|
|
255
484
|
self.from_project_id = from_project_id
|
|
485
|
+
self.to_organization_id = to_organization_id
|
|
256
486
|
self.to_project_id = to_project_id
|
|
257
|
-
self.
|
|
258
|
-
self.
|
|
487
|
+
self.file_id = file_id
|
|
488
|
+
self._source_manager = FileManager(
|
|
259
489
|
api_key=self.from_api_key,
|
|
260
|
-
base_url=self.from_instance
|
|
490
|
+
base_url=self.from_instance,
|
|
491
|
+
organization_id=self.from_organization_id,
|
|
492
|
+
project_id=self.from_project_id
|
|
261
493
|
)
|
|
262
|
-
self.
|
|
494
|
+
self._destination_manager = FileManager(
|
|
263
495
|
api_key=self.to_api_key,
|
|
264
|
-
base_url=self.to_instance
|
|
496
|
+
base_url=self.to_instance,
|
|
497
|
+
organization_id=self.to_organization_id,
|
|
498
|
+
project_id=self.to_project_id
|
|
265
499
|
)
|
|
266
500
|
|
|
501
|
+
def get_display_info(self) -> str:
|
|
502
|
+
return f"file {self.file_id}"
|
|
503
|
+
|
|
267
504
|
def migrate(self):
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
505
|
+
"""
|
|
506
|
+
Execute the file migration from source to destination project.
|
|
507
|
+
|
|
508
|
+
:raises ValueError: If file retrieval or upload fails
|
|
509
|
+
"""
|
|
510
|
+
new_file = self._migrate_file()
|
|
511
|
+
logger.info(f"Successfully migrated file {self.file_id}")
|
|
512
|
+
|
|
513
|
+
def _migrate_file(self) -> File:
|
|
514
|
+
"""
|
|
515
|
+
Retrieve file from source and upload to destination.
|
|
516
|
+
|
|
517
|
+
:return: The newly uploaded file
|
|
518
|
+
:raises ValueError: If migration fails
|
|
519
|
+
"""
|
|
276
520
|
try:
|
|
277
|
-
|
|
278
|
-
if not isinstance(
|
|
279
|
-
raise ValueError("Unable to retrieve
|
|
280
|
-
|
|
281
|
-
|
|
521
|
+
source_file = self._source_manager.get_file_data(file_id=self.file_id)
|
|
522
|
+
if not isinstance(source_file, File):
|
|
523
|
+
raise ValueError(f"Unable to retrieve file {self.file_id}")
|
|
524
|
+
|
|
525
|
+
file_content = self._source_manager.get_file_content(file_id=self.file_id)
|
|
526
|
+
upload_response = self._destination_manager.upload_file_from_content(
|
|
527
|
+
file_name=source_file.name,
|
|
528
|
+
content=file_content,
|
|
529
|
+
folder=None
|
|
530
|
+
)
|
|
531
|
+
return upload_response.file
|
|
282
532
|
except Exception as e:
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
return new_task
|
|
533
|
+
logger.error(f"File migration failed: {e}")
|
|
534
|
+
raise ValueError(f"File migration failed: {e}") from e
|