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/core/feedback/clients.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from json import JSONDecodeError
|
|
3
1
|
from typing import Any, Union
|
|
4
2
|
|
|
5
3
|
from pygeai import logger
|
|
6
4
|
from pygeai.core.base.clients import BaseClient
|
|
7
5
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
8
6
|
from pygeai.core.feedback.endpoints import SEND_FEEDBACK_V1
|
|
7
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
8
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class FeedbackClient(BaseClient):
|
|
@@ -45,10 +45,6 @@ class FeedbackClient(BaseClient):
|
|
|
45
45
|
endpoint=endpoint,
|
|
46
46
|
data=data
|
|
47
47
|
)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return result
|
|
51
|
-
except JSONDecodeError as e:
|
|
52
|
-
logger.error(f"Unable to send feedback. JSON parsing error: {e}. Response: {e}")
|
|
53
|
-
raise InvalidAPIResponseException(f"Unable to send feedback for request {request_id}: {response.text}")
|
|
48
|
+
validate_status_code(response)
|
|
49
|
+
return parse_json_response(response, "send feedback. JSON parsing error")
|
|
54
50
|
|
pygeai/core/files/clients.py
CHANGED
|
@@ -7,6 +7,8 @@ from pygeai.core.base.clients import BaseClient
|
|
|
7
7
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
8
8
|
from pygeai.core.files.endpoints import UPLOAD_FILE_V1, GET_FILE_V1, DELETE_FILE_V1, GET_FILE_CONTENT_V1, \
|
|
9
9
|
GET_ALL_FILES_V1
|
|
10
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
11
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
class FileClient(BaseClient):
|
|
@@ -53,13 +55,8 @@ class FileClient(BaseClient):
|
|
|
53
55
|
headers=headers,
|
|
54
56
|
files=files
|
|
55
57
|
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return result
|
|
59
|
-
except JSONDecodeError as e:
|
|
60
|
-
logger.error(
|
|
61
|
-
f"Unable to upload file {file_name} in project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
62
|
-
raise InvalidAPIResponseException(f"Unable to upload file {file_name}: {response.text}")
|
|
58
|
+
validate_status_code(response)
|
|
59
|
+
return parse_json_response(response, "upload file in project", file_name=file_name, project_id=project_id)
|
|
63
60
|
|
|
64
61
|
finally:
|
|
65
62
|
files["file"].close()
|
|
@@ -82,12 +79,8 @@ class FileClient(BaseClient):
|
|
|
82
79
|
}
|
|
83
80
|
)
|
|
84
81
|
logger.debug(f"Retrieving file details for id {file_id}")
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return result
|
|
88
|
-
except JSONDecodeError as e:
|
|
89
|
-
logger.error(f"Unable to retrieve file details for id {file_id} in project {project}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
90
|
-
raise InvalidAPIResponseException(f"Unable to retrieve file details for id {file_id}: {response.text}")
|
|
82
|
+
validate_status_code(response)
|
|
83
|
+
return parse_json_response(response, "retrieve file details for id in project", file_id=file_id, project=project)
|
|
91
84
|
|
|
92
85
|
def delete_file(self, organization: str, project: str, file_id: str) -> dict:
|
|
93
86
|
"""
|
|
@@ -113,12 +106,8 @@ class FileClient(BaseClient):
|
|
|
113
106
|
"project": project
|
|
114
107
|
}
|
|
115
108
|
)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return result
|
|
119
|
-
except JSONDecodeError as e:
|
|
120
|
-
logger.error(f"Unable to delete file with id {file_id} in project {project}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
121
|
-
raise InvalidAPIResponseException(f"Unable to delete file with id {file_id}: {response.text}")
|
|
109
|
+
validate_status_code(response)
|
|
110
|
+
return parse_json_response(response, "delete file with id in project", file_id=file_id, project=project)
|
|
122
111
|
|
|
123
112
|
def get_file_content(self, organization: str, project: str, file_id: str) -> bytes:
|
|
124
113
|
"""
|
|
@@ -163,9 +152,5 @@ class FileClient(BaseClient):
|
|
|
163
152
|
"project": project
|
|
164
153
|
}
|
|
165
154
|
)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return result
|
|
169
|
-
except JSONDecodeError as e:
|
|
170
|
-
logger.error(f"Unable to retrieve file list for project {project}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
171
|
-
raise InvalidAPIResponseException(f"Unable to retrieve file list for project {project}: {response.text}")
|
|
155
|
+
validate_status_code(response)
|
|
156
|
+
return parse_json_response(response, "retrieve file list for project", project=project)
|
pygeai/core/files/managers.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
1
5
|
from pygeai import logger
|
|
2
6
|
from pygeai.admin.clients import AdminClient
|
|
3
7
|
from pygeai.core.base.mappers import ErrorMapper, ResponseMapper
|
|
@@ -180,3 +184,41 @@ class FileManager:
|
|
|
180
184
|
|
|
181
185
|
result = FileResponseMapper.map_to_file_list_response(response_data)
|
|
182
186
|
return result
|
|
187
|
+
|
|
188
|
+
def upload_file_from_content(
|
|
189
|
+
self,
|
|
190
|
+
file_name: str,
|
|
191
|
+
content: bytes,
|
|
192
|
+
folder: Optional[str] = None
|
|
193
|
+
) -> UploadFileResponse:
|
|
194
|
+
"""
|
|
195
|
+
Uploads a file from binary content to the specified organization and project.
|
|
196
|
+
|
|
197
|
+
This method creates a temporary file from the provided content, uploads it,
|
|
198
|
+
and then cleans up the temporary file.
|
|
199
|
+
|
|
200
|
+
:param file_name: str - The name for the uploaded file.
|
|
201
|
+
:param content: bytes - The binary content of the file.
|
|
202
|
+
:param folder: str, optional - Destination folder (default is None, which means temporary storage).
|
|
203
|
+
:return: UploadFileResponse - The response object containing the uploaded file details.
|
|
204
|
+
:raises APIError: If the API returns errors.
|
|
205
|
+
"""
|
|
206
|
+
temp_file = None
|
|
207
|
+
try:
|
|
208
|
+
suffix = Path(file_name).suffix or ""
|
|
209
|
+
with tempfile.NamedTemporaryFile(mode='wb', suffix=suffix, delete=False) as temp_file:
|
|
210
|
+
temp_file.write(content)
|
|
211
|
+
temp_file_path = temp_file.name
|
|
212
|
+
|
|
213
|
+
upload_file = UploadFile(
|
|
214
|
+
path=temp_file_path,
|
|
215
|
+
name=file_name,
|
|
216
|
+
folder=folder
|
|
217
|
+
)
|
|
218
|
+
return self.upload_file(upload_file)
|
|
219
|
+
finally:
|
|
220
|
+
if temp_file:
|
|
221
|
+
try:
|
|
222
|
+
Path(temp_file_path).unlink(missing_ok=True)
|
|
223
|
+
except Exception as e:
|
|
224
|
+
logger.warning(f"Failed to delete temporary file {temp_file_path}: {e}")
|
pygeai/core/llm/clients.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from json import JSONDecodeError
|
|
3
1
|
|
|
4
2
|
from pygeai import logger
|
|
5
3
|
from pygeai.core.base.clients import BaseClient
|
|
6
4
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
7
5
|
from pygeai.core.llm.endpoints import GET_PROVIDER_LIST_V2, GET_PROVIDER_DATA_V2, GET_PROVIDER_MODELS_V2, \
|
|
8
6
|
GET_MODEL_DATA_V2
|
|
7
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
8
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class LlmClient(BaseClient):
|
|
@@ -13,12 +13,8 @@ class LlmClient(BaseClient):
|
|
|
13
13
|
def get_provider_list(self) -> dict:
|
|
14
14
|
logger.debug("Obtaining provider list")
|
|
15
15
|
response = self.api_service.get(endpoint=GET_PROVIDER_LIST_V2)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return result
|
|
19
|
-
except JSONDecodeError as e:
|
|
20
|
-
logger.error(f"Unable to obtain provider list: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
21
|
-
raise InvalidAPIResponseException(f"Unable to obtain provider list: {response.text}")
|
|
16
|
+
validate_status_code(response)
|
|
17
|
+
return parse_json_response(response, "obtain provider list")
|
|
22
18
|
|
|
23
19
|
def get_provider_data(self, provider_name: str) -> dict:
|
|
24
20
|
endpoint = GET_PROVIDER_DATA_V2.format(providerName=provider_name)
|
|
@@ -26,12 +22,8 @@ class LlmClient(BaseClient):
|
|
|
26
22
|
logger.debug(f"Obtaining provider data for {provider_name}")
|
|
27
23
|
|
|
28
24
|
response = self.api_service.get(endpoint=endpoint)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return result
|
|
32
|
-
except JSONDecodeError as e:
|
|
33
|
-
logger.error(f"Unable to obtain provider data for {provider_name}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
34
|
-
raise InvalidAPIResponseException(f"Unable to obtain provider data for {provider_name}: {response.text}")
|
|
25
|
+
validate_status_code(response)
|
|
26
|
+
return parse_json_response(response, "obtain provider data", provider_name=provider_name)
|
|
35
27
|
|
|
36
28
|
def get_provider_models(self, provider_name: str) -> dict:
|
|
37
29
|
endpoint = GET_PROVIDER_MODELS_V2.format(providerName=provider_name)
|
|
@@ -39,12 +31,8 @@ class LlmClient(BaseClient):
|
|
|
39
31
|
logger.debug(f"Obtaining provider models for {provider_name}")
|
|
40
32
|
|
|
41
33
|
response = self.api_service.get(endpoint=endpoint)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return result
|
|
45
|
-
except JSONDecodeError as e:
|
|
46
|
-
logger.error(f"Unable to obtain provider models for {provider_name}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
47
|
-
raise InvalidAPIResponseException(f"Unable to obtain provider models for {provider_name}: {response.text}")
|
|
34
|
+
validate_status_code(response)
|
|
35
|
+
return parse_json_response(response, "obtain provider models", provider_name=provider_name)
|
|
48
36
|
|
|
49
37
|
def get_model_data(
|
|
50
38
|
self,
|
|
@@ -60,9 +48,6 @@ class LlmClient(BaseClient):
|
|
|
60
48
|
logger.debug(f"Obtaining model data for {provider_name}/{model_name or model_id}")
|
|
61
49
|
|
|
62
50
|
response = self.api_service.get(endpoint=endpoint)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
except JSONDecodeError as e:
|
|
67
|
-
logger.error(f"Unable to obtain model data for {provider_name}/{model_name or model_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
68
|
-
raise InvalidAPIResponseException(f"Unable to obtain model data for {provider_name}/{model_name or model_id}: {response.text}")
|
|
51
|
+
model_identifier = model_name or model_id
|
|
52
|
+
validate_status_code(response)
|
|
53
|
+
return parse_json_response(response, f"obtain model data for {provider_name}/{model_identifier}")
|
pygeai/core/models.py
CHANGED
|
@@ -690,3 +690,110 @@ class DataAnalystAssistant(Assistant):
|
|
|
690
690
|
|
|
691
691
|
class ChatWithDataAssistant(Assistant):
|
|
692
692
|
type: Literal["ChatWithData"] = "ChatWithData"
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
class Role(CustomBaseModel):
|
|
696
|
+
"""
|
|
697
|
+
{
|
|
698
|
+
"id": "string",
|
|
699
|
+
"name": "string",
|
|
700
|
+
"externalId": "string",
|
|
701
|
+
"type": "string",
|
|
702
|
+
"origin": "string"
|
|
703
|
+
}
|
|
704
|
+
"""
|
|
705
|
+
id: str = Field(..., alias="id")
|
|
706
|
+
name: str = Field(..., alias="name")
|
|
707
|
+
external_id: Optional[str] = Field(None, alias="externalId")
|
|
708
|
+
type: Optional[str] = Field(None, alias="type")
|
|
709
|
+
origin: Optional[str] = Field(None, alias="origin")
|
|
710
|
+
|
|
711
|
+
def to_dict(self):
|
|
712
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
713
|
+
|
|
714
|
+
def __str__(self):
|
|
715
|
+
return str(self.to_dict())
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
class Member(CustomBaseModel):
|
|
719
|
+
"""
|
|
720
|
+
{
|
|
721
|
+
"email": "string",
|
|
722
|
+
"roles": [...]
|
|
723
|
+
}
|
|
724
|
+
"""
|
|
725
|
+
email: str = Field(..., alias="email")
|
|
726
|
+
roles: Optional[List[Role]] = Field(default_factory=list, alias="roles")
|
|
727
|
+
|
|
728
|
+
@field_validator("roles", mode="before")
|
|
729
|
+
@classmethod
|
|
730
|
+
def normalize_roles(cls, value):
|
|
731
|
+
if isinstance(value, list):
|
|
732
|
+
return [Role.model_validate(item) if isinstance(item, dict) else item for item in value]
|
|
733
|
+
return value
|
|
734
|
+
|
|
735
|
+
def to_dict(self):
|
|
736
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
737
|
+
|
|
738
|
+
def __str__(self):
|
|
739
|
+
return str(self.to_dict())
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
class ProjectMembership(CustomBaseModel):
|
|
743
|
+
"""
|
|
744
|
+
{
|
|
745
|
+
"organizationId": "string",
|
|
746
|
+
"organizationName": "string",
|
|
747
|
+
"projectDescription": "string",
|
|
748
|
+
"projectId": "string",
|
|
749
|
+
"projectName": "string",
|
|
750
|
+
"roles": [...]
|
|
751
|
+
}
|
|
752
|
+
"""
|
|
753
|
+
organization_id: Optional[str] = Field(None, alias="organizationId")
|
|
754
|
+
organization_name: Optional[str] = Field(None, alias="organizationName")
|
|
755
|
+
project_description: Optional[str] = Field(None, alias="projectDescription")
|
|
756
|
+
project_id: str = Field(..., alias="projectId")
|
|
757
|
+
project_name: str = Field(..., alias="projectName")
|
|
758
|
+
roles: Optional[List[Role]] = Field(default_factory=list, alias="roles")
|
|
759
|
+
|
|
760
|
+
@field_validator("roles", mode="before")
|
|
761
|
+
@classmethod
|
|
762
|
+
def normalize_roles(cls, value):
|
|
763
|
+
if isinstance(value, list):
|
|
764
|
+
return [Role.model_validate(item) if isinstance(item, dict) else item for item in value]
|
|
765
|
+
return value
|
|
766
|
+
|
|
767
|
+
def to_dict(self):
|
|
768
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
769
|
+
|
|
770
|
+
def __str__(self):
|
|
771
|
+
return str(self.to_dict())
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
class OrganizationMembership(CustomBaseModel):
|
|
775
|
+
"""
|
|
776
|
+
{
|
|
777
|
+
"isStationAvailable": true,
|
|
778
|
+
"organizationId": "string",
|
|
779
|
+
"organizationName": "string",
|
|
780
|
+
"projects": [...]
|
|
781
|
+
}
|
|
782
|
+
"""
|
|
783
|
+
is_station_available: Optional[bool] = Field(None, alias="isStationAvailable")
|
|
784
|
+
organization_id: str = Field(..., alias="organizationId")
|
|
785
|
+
organization_name: str = Field(..., alias="organizationName")
|
|
786
|
+
projects: Optional[List[ProjectMembership]] = Field(default_factory=list, alias="projects")
|
|
787
|
+
|
|
788
|
+
@field_validator("projects", mode="before")
|
|
789
|
+
@classmethod
|
|
790
|
+
def normalize_projects(cls, value):
|
|
791
|
+
if isinstance(value, list):
|
|
792
|
+
return [ProjectMembership.model_validate(item) if isinstance(item, dict) else item for item in value]
|
|
793
|
+
return value
|
|
794
|
+
|
|
795
|
+
def to_dict(self):
|
|
796
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
797
|
+
|
|
798
|
+
def __str__(self):
|
|
799
|
+
return str(self.to_dict())
|
pygeai/core/plugins/clients.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from json import JSONDecodeError
|
|
2
1
|
from typing import Optional, List, Dict
|
|
3
2
|
|
|
4
3
|
from pygeai import logger
|
|
5
4
|
from pygeai.core.base.clients import BaseClient
|
|
6
5
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
7
6
|
from pygeai.core.plugins.endpoints import LIST_ASSISTANTS_PLUGINS_V1
|
|
7
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
8
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class PluginClient(BaseClient):
|
|
@@ -26,10 +27,6 @@ class PluginClient(BaseClient):
|
|
|
26
27
|
endpoint=LIST_ASSISTANTS_PLUGINS_V1,
|
|
27
28
|
params=params
|
|
28
29
|
)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return result
|
|
32
|
-
except JSONDecodeError as e:
|
|
33
|
-
logger.error(f"Unable to list assistants for organization {organization_id} and project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
34
|
-
raise InvalidAPIResponseException(f"Unable to list assistants for organization {organization_id} and project {project_id}: {response.text}")
|
|
30
|
+
validate_status_code(response)
|
|
31
|
+
return parse_json_response(response, f"list assistants for organization {organization_id} and project {project_id}")
|
|
35
32
|
|
pygeai/core/rerank/clients.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from json import JSONDecodeError
|
|
3
1
|
from typing import Any, Union
|
|
4
2
|
|
|
5
3
|
from pygeai import logger
|
|
6
4
|
from pygeai.core.base.clients import BaseClient
|
|
7
5
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
8
6
|
from pygeai.core.rerank.endpoints import RERANK_V1
|
|
7
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
8
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class RerankClient(BaseClient):
|
|
@@ -30,10 +30,6 @@ class RerankClient(BaseClient):
|
|
|
30
30
|
endpoint=RERANK_V1,
|
|
31
31
|
data=data
|
|
32
32
|
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return result
|
|
36
|
-
except JSONDecodeError as e:
|
|
37
|
-
logger.error(f"Unable to rerank chunks for query '{query}' with model {model}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
38
|
-
raise InvalidAPIResponseException(f"Unable to rerank chunks for query '{query}' with model {model}: {response.text}")
|
|
33
|
+
validate_status_code(response)
|
|
34
|
+
return parse_json_response(response, "rerank chunks for query with model", query=query, model=model)
|
|
39
35
|
|
pygeai/core/secrets/clients.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from json import JSONDecodeError
|
|
2
1
|
from typing import Optional, List, Dict
|
|
3
2
|
|
|
4
3
|
from pygeai import logger
|
|
@@ -6,6 +5,8 @@ from pygeai.core.base.clients import BaseClient
|
|
|
6
5
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
7
6
|
from pygeai.core.secrets.endpoints import LIST_SECRETS_V1, GET_SECRET_V1, CREATE_SECRET_V1, UPDATE_SECRET_V1, \
|
|
8
7
|
SET_SECRET_ACCESSES_V1, GET_SECRET_ACCESSES_V1
|
|
8
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
9
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class SecretClient(BaseClient):
|
|
@@ -44,12 +45,8 @@ class SecretClient(BaseClient):
|
|
|
44
45
|
endpoint=LIST_SECRETS_V1,
|
|
45
46
|
params=params
|
|
46
47
|
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return result
|
|
50
|
-
except JSONDecodeError as e:
|
|
51
|
-
logger.error(f"Unable to list secrets with params {params}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
52
|
-
raise InvalidAPIResponseException(f"Unable to list secrets with params {params}: {response.text}")
|
|
48
|
+
validate_status_code(response)
|
|
49
|
+
return parse_json_response(response, "list secrets with params")
|
|
53
50
|
|
|
54
51
|
def get_secret(self, secret_id: str) -> dict:
|
|
55
52
|
"""
|
|
@@ -69,12 +66,8 @@ class SecretClient(BaseClient):
|
|
|
69
66
|
response = self.api_service.get(
|
|
70
67
|
endpoint=endpoint
|
|
71
68
|
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return result
|
|
75
|
-
except JSONDecodeError as e:
|
|
76
|
-
logger.error(f"Unable to get secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
77
|
-
raise InvalidAPIResponseException(f"Unable to get secret with ID '{secret_id}': {response.text}")
|
|
69
|
+
validate_status_code(response)
|
|
70
|
+
return parse_json_response(response, "get secret with ID", secret_id=secret_id)
|
|
78
71
|
|
|
79
72
|
def create_secret(
|
|
80
73
|
self,
|
|
@@ -111,12 +104,8 @@ class SecretClient(BaseClient):
|
|
|
111
104
|
endpoint=CREATE_SECRET_V1,
|
|
112
105
|
data=data
|
|
113
106
|
)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return result
|
|
117
|
-
except JSONDecodeError as e:
|
|
118
|
-
logger.error(f"Unable to create secret with name '{name}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
119
|
-
raise InvalidAPIResponseException(f"Unable to create secret with name '{name}': {response.text}")
|
|
107
|
+
validate_status_code(response)
|
|
108
|
+
return parse_json_response(response, "create secret with name", name=name)
|
|
120
109
|
|
|
121
110
|
def update_secret(
|
|
122
111
|
self,
|
|
@@ -157,12 +146,8 @@ class SecretClient(BaseClient):
|
|
|
157
146
|
endpoint=endpoint,
|
|
158
147
|
data=data
|
|
159
148
|
)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return result
|
|
163
|
-
except JSONDecodeError as e:
|
|
164
|
-
logger.error(f"Unable to update secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
165
|
-
raise InvalidAPIResponseException(f"Unable to update secret with ID '{secret_id}': {response.text}")
|
|
149
|
+
validate_status_code(response)
|
|
150
|
+
return parse_json_response(response, "update secret with ID", secret_id=secret_id)
|
|
166
151
|
|
|
167
152
|
def set_secret_accesses(
|
|
168
153
|
self,
|
|
@@ -202,12 +187,8 @@ class SecretClient(BaseClient):
|
|
|
202
187
|
endpoint=endpoint,
|
|
203
188
|
data=data
|
|
204
189
|
)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return result
|
|
208
|
-
except JSONDecodeError as e:
|
|
209
|
-
logger.error(f"Unable to set accesses for secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
210
|
-
raise InvalidAPIResponseException(f"Unable to set accesses for secret with ID '{secret_id}': {response.text}")
|
|
190
|
+
validate_status_code(response)
|
|
191
|
+
return parse_json_response(response, "set accesses for secret with ID", secret_id=secret_id)
|
|
211
192
|
|
|
212
193
|
def get_secret_accesses(self, secret_id: str) -> dict:
|
|
213
194
|
"""
|
|
@@ -227,9 +208,5 @@ class SecretClient(BaseClient):
|
|
|
227
208
|
response = self.api_service.get(
|
|
228
209
|
endpoint=endpoint
|
|
229
210
|
)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return result
|
|
233
|
-
except JSONDecodeError as e:
|
|
234
|
-
logger.error(f"Unable to get accesses for secret with ID '{secret_id}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
235
|
-
raise InvalidAPIResponseException(f"Unable to get accesses for secret with ID '{secret_id}': {response.text}")
|
|
211
|
+
validate_status_code(response)
|
|
212
|
+
return parse_json_response(response, "get accesses for secret with ID", secret_id=secret_id)
|
pygeai/core/services/rest.py
CHANGED
|
@@ -388,7 +388,7 @@ class ApiService:
|
|
|
388
388
|
|
|
389
389
|
def _add_endpoint_to_url(self, endpoint: str):
|
|
390
390
|
clean_base_url = self.base_url.rstrip('/')
|
|
391
|
-
url = f"{clean_base_url}/{endpoint}" if self._has_valid_protocol(clean_base_url) else f"https://{clean_base_url}/{endpoint}"
|
|
391
|
+
url = f"{clean_base_url}/{endpoint.lstrip('/')}" if self._has_valid_protocol(clean_base_url) else f"https://{clean_base_url}/{endpoint}"
|
|
392
392
|
return url
|
|
393
393
|
|
|
394
394
|
def _has_valid_protocol(self, url: str):
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from json import JSONDecodeError
|
|
2
|
+
|
|
3
|
+
from pygeai import logger
|
|
4
|
+
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_json_response(response, operation: str, **context):
|
|
8
|
+
"""
|
|
9
|
+
Parse JSON response with standardized error handling.
|
|
10
|
+
|
|
11
|
+
:param response: HTTP response object
|
|
12
|
+
:param operation: Description of operation (e.g., "get project API token")
|
|
13
|
+
:param context: Additional context (e.g., api_token_id="123")
|
|
14
|
+
:return: Parsed JSON response
|
|
15
|
+
:raises InvalidAPIResponseException: If JSON parsing fails
|
|
16
|
+
"""
|
|
17
|
+
try:
|
|
18
|
+
return response.json()
|
|
19
|
+
except JSONDecodeError as e:
|
|
20
|
+
full_msg = f"Unable to {operation}"
|
|
21
|
+
if context:
|
|
22
|
+
if len(context) == 1:
|
|
23
|
+
# Single context value: append as 'value'
|
|
24
|
+
value = list(context.values())[0]
|
|
25
|
+
full_msg += f" '{value}'"
|
|
26
|
+
else:
|
|
27
|
+
# Multiple context values: format as (key1='value1', key2='value2')
|
|
28
|
+
context_str = ", ".join([f"{k}='{v}'" for k, v in context.items()])
|
|
29
|
+
full_msg += f" ({context_str})"
|
|
30
|
+
|
|
31
|
+
logger.error(f"{full_msg}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
32
|
+
raise InvalidAPIResponseException(f"{full_msg}: {response.text}")
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pygeai import logger
|
|
2
|
+
from pygeai.core.common.exceptions import APIResponseError
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def validate_status_code(response):
|
|
6
|
+
if response.status_code >= 300:
|
|
7
|
+
logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
|
|
8
|
+
raise APIResponseError(f"API returned an error: {response.text}")
|
|
9
|
+
|
|
10
|
+
|
pygeai/dbg/__init__.py
CHANGED