thestage 0.6.7__py3-none-any.whl → 0.6.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. thestage/__init__.py +1 -1
  2. thestage/cli_command_helper.py +2 -2
  3. thestage/config/__init__.py +1 -1
  4. thestage/{services → config/business}/app_config_service.py +3 -4
  5. thestage/{services/config_provider → config/business}/config_provider.py +6 -5
  6. thestage/config/{config_storage.py → business/config_storage.py} +1 -1
  7. thestage/{services → config/business}/validation_service.py +9 -10
  8. thestage/{controllers/config_controller.py → config/communication/config_command.py} +7 -7
  9. thestage/{services/connect → connect/business}/connect_service.py +22 -19
  10. thestage/{services → connect/business}/remote_server_service.py +4 -5
  11. thestage/connect/communication/connect_api_client.py +84 -0
  12. thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_response.py +0 -1
  13. thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_response.py +1 -4
  14. thestage/{services/clients/thestage_api/dtos/base_controller → connect/dto}/connect_resolve_response.py +0 -1
  15. thestage/controllers/base_controller.py +2 -2
  16. thestage/debug_main.dist.py +16 -14
  17. thestage/{services/container → docker_container/business}/container_service.py +27 -22
  18. thestage/{services/container → docker_container/business}/mapper/container_mapper.py +3 -3
  19. thestage/docker_container/communication/__init__.py +0 -0
  20. thestage/{controllers/container_controller.py → docker_container/communication/docker_command.py} +17 -23
  21. thestage/docker_container/communication/docker_container_api_client.py +99 -0
  22. thestage/docker_container/dto/__init__.py +0 -0
  23. thestage/docker_container/dto/container_action_request.py +11 -0
  24. thestage/{services/clients/thestage_api/dtos → docker_container/dto}/container_response.py +4 -4
  25. thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_response.py +3 -5
  26. thestage/docker_container/dto/enum/__init__.py +0 -0
  27. thestage/git/__init__.py +0 -0
  28. thestage/git/business/__init__.py +0 -0
  29. thestage/git/communication/__init__.py +0 -0
  30. thestage/{services/clients/git → git/communication}/git_client.py +4 -4
  31. thestage/global_dto/__init__.py +0 -0
  32. thestage/global_dto/enums/__init__.py +0 -0
  33. thestage/helpers/error_handler.py +3 -3
  34. thestage/helpers/logger/app_logger.py +1 -3
  35. thestage/i18n/en_GB/messages.po +14 -14
  36. thestage/inference_model/__init__.py +0 -0
  37. thestage/inference_model/business/__init__.py +0 -0
  38. thestage/inference_model/business/inference_model_service.py +281 -0
  39. thestage/inference_model/business/mapper/__init__.py +0 -0
  40. thestage/{services/project/mapper/project_inference_simulator_model_mapper.py → inference_model/business/mapper/inference_model_mapper.py} +5 -5
  41. thestage/inference_model/communication/__init__.py +0 -0
  42. thestage/inference_model/communication/inference_model_api_client.py +139 -0
  43. thestage/inference_model/communication/inference_model_command.py +246 -0
  44. thestage/inference_model/dto/__init__.py +0 -0
  45. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_response.py +0 -1
  46. thestage/inference_model/dto/enum/__init__.py +0 -0
  47. thestage/{services/project/dto/inference_simulator_model_dto.py → inference_model/dto/inference_model.py} +1 -1
  48. thestage/{entities/project_inference_simulator_model.py → inference_model/dto/inference_model_entity.py} +1 -1
  49. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_response.py +2 -3
  50. thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py → inference_model/dto/push_inference_simulator_model_request.py} +1 -1
  51. thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py → inference_model/dto/push_inference_simulator_model_response.py} +1 -1
  52. thestage/inference_simulator/__init__.py +0 -0
  53. thestage/inference_simulator/business/__init__.py +0 -0
  54. thestage/inference_simulator/business/inference_simulator_service.py +338 -0
  55. thestage/inference_simulator/business/mapper/__init__.py +0 -0
  56. thestage/{services/project/mapper/project_inference_simulator_mapper.py → inference_simulator/business/mapper/inference_simulator_mapper.py} +5 -5
  57. thestage/inference_simulator/communication/__init__.py +0 -0
  58. thestage/inference_simulator/communication/inference_simulator_api_client.py +114 -0
  59. thestage/inference_simulator/communication/inference_simulator_command.py +347 -0
  60. thestage/inference_simulator/dto/__init__.py +0 -0
  61. thestage/inference_simulator/dto/enum/__init__.py +0 -0
  62. thestage/inference_simulator/dto/get_inference_simulator_response.py +12 -0
  63. thestage/{services/project/dto/inference_simulator_dto.py → inference_simulator/dto/inference_simulator.py} +1 -1
  64. thestage/{entities/project_inference_simulator.py → inference_simulator/dto/inference_simulator_entity.py} +1 -1
  65. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_response.py +2 -2
  66. thestage/{services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py → inference_simulator/dto/start_inference_simulator_request.py} +1 -1
  67. thestage/inference_simulator/dto/start_inference_simulator_response.py +10 -0
  68. thestage/instance/__init__.py +0 -0
  69. thestage/instance/business/__init__.py +0 -0
  70. thestage/{services/instance → instance/business}/instance_service.py +26 -27
  71. thestage/instance/business/mapper/__init__.py +0 -0
  72. thestage/{services/instance/mapper/instance_mapper.py → instance/business/mapper/rented_instance_mapper.py} +3 -3
  73. thestage/{services/instance/mapper/selfhosted_mapper.py → instance/business/mapper/selfhosted_instance_mapper.py} +5 -7
  74. thestage/instance/communication/__init__.py +0 -0
  75. thestage/instance/communication/instance_api_client.py +150 -0
  76. thestage/{controllers/instance_controller.py → instance/communication/instance_command.py} +5 -5
  77. thestage/instance/dto/__init__.py +0 -0
  78. thestage/instance/dto/enum/__init__.py +0 -0
  79. thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_detected_gpus.py +1 -2
  80. thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_rented_response.py +2 -2
  81. thestage/{services/clients/thestage_api/dtos → instance/dto}/selfhosted_instance_response.py +2 -3
  82. thestage/logging/__init__.py +0 -0
  83. thestage/logging/business/__init__.py +0 -0
  84. thestage/{services/logging → logging/business}/logging_service.py +40 -28
  85. thestage/logging/communication/__init__.py +0 -0
  86. thestage/logging/communication/logging_api_client.py +63 -0
  87. thestage/logging/dto/__init__.py +0 -0
  88. thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_response.py +2 -2
  89. thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_response.py +2 -2
  90. thestage/main.py +47 -8
  91. thestage/project/__init__.py +0 -0
  92. thestage/project/business/__init__.py +0 -0
  93. thestage/project/business/project_service.py +480 -0
  94. thestage/project/communication/__init__.py +0 -0
  95. thestage/project/communication/project_api_client.py +46 -0
  96. thestage/project/communication/project_command.py +284 -0
  97. thestage/project/dto/__init__.py +0 -0
  98. thestage/services/clients/thestage_api/core/api_client_core.py +1 -1
  99. thestage/services/clients/thestage_api/dtos/entity_filter_request.py +1 -1
  100. thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +1 -1
  101. thestage/services/filesystem_service.py +2 -2
  102. thestage/services/service_factory.py +130 -43
  103. thestage/task/__init__.py +0 -0
  104. thestage/task/business/__init__.py +0 -0
  105. thestage/task/business/mapper/__init__.py +0 -0
  106. thestage/{services/project/mapper/project_task_mapper.py → task/business/mapper/task_mapper.py} +5 -5
  107. thestage/task/business/task_service.py +304 -0
  108. thestage/task/communication/__init__.py +0 -0
  109. thestage/task/communication/task_api_client.py +122 -0
  110. thestage/task/communication/task_command.py +212 -0
  111. thestage/task/dto/__init__.py +0 -0
  112. thestage/task/dto/enum/__init__.py +0 -0
  113. thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py → task/dto/list_for_project_response.py} +2 -2
  114. thestage/{services/clients/thestage_api/dtos/project_controller/project_run_task_request.py → task/dto/run_task_request.py} +1 -1
  115. thestage/task/dto/run_task_response.py +13 -0
  116. thestage/{services/task/dto/task_dto.py → task/dto/task.py} +1 -4
  117. thestage/{entities/project_task.py → task/dto/task_entity.py} +1 -1
  118. thestage/{services/clients/thestage_api/dtos/task_controller/task_view_response.py → task/dto/view_response.py} +2 -2
  119. {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/METADATA +1 -1
  120. thestage-0.6.8.dist-info/RECORD +219 -0
  121. {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/WHEEL +1 -1
  122. thestage/controllers/project_controller.py +0 -1056
  123. thestage/services/clients/thestage_api/api_client.py +0 -751
  124. thestage/services/clients/thestage_api/dtos/container_param_request.py +0 -11
  125. thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +0 -13
  126. thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +0 -13
  127. thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +0 -10
  128. thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +0 -12
  129. thestage/services/project/project_service.py +0 -1287
  130. thestage-0.6.7.dist-info/RECORD +0 -167
  131. /thestage/{entities → color_scheme}/__init__.py +0 -0
  132. /thestage/{entities/enums → config/business}/__init__.py +0 -0
  133. /thestage/{services/clients/git → config/communication}/__init__.py +0 -0
  134. /thestage/{services/clients/thestage_api/dtos/enums → config/dto}/__init__.py +0 -0
  135. /thestage/{services/core_files → config/dto}/config_entity.py +0 -0
  136. /thestage/{services/connect → config}/dto/remote_server_config.py +0 -0
  137. /thestage/{services/config_provider → connect}/__init__.py +0 -0
  138. /thestage/{services/container → connect/business}/__init__.py +0 -0
  139. /thestage/{services/container/mapper → connect/communication}/__init__.py +0 -0
  140. /thestage/{services/instance → connect/dto}/__init__.py +0 -0
  141. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_request.py +0 -0
  142. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_request.py +0 -0
  143. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_request.py +0 -0
  144. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_response.py +0 -0
  145. /thestage/{services/instance/mapper → docker_container}/__init__.py +0 -0
  146. /thestage/{services/project → docker_container/business}/__init__.py +0 -0
  147. /thestage/{services/project → docker_container/business}/mapper/__init__.py +0 -0
  148. /thestage/{entities/container.py → docker_container/dto/container_entity.py} +0 -0
  149. /thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_request.py +0 -0
  150. /thestage/{services/clients/thestage_api/dtos → docker_container/dto}/docker_container_mapping.py +0 -0
  151. /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_pending_action.py +0 -0
  152. /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_status.py +0 -0
  153. /thestage/{services/logging/exception → exceptions}/log_polling_exception.py +0 -0
  154. /thestage/git/{ProgressPrinter.py → business/ProgressPrinter.py} +0 -0
  155. /thestage/{entities → global_dto}/enums/order_direction_type.py +0 -0
  156. /thestage/{entities → global_dto}/enums/shell_type.py +0 -0
  157. /thestage/{entities → global_dto}/enums/tail_output_type.py +0 -0
  158. /thestage/{entities → global_dto}/enums/yes_no_response.py +0 -0
  159. /thestage/{entities → global_dto}/file_item.py +0 -0
  160. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_request.py +0 -0
  161. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_request.py +0 -0
  162. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_response.py +0 -0
  163. /thestage/{services/clients/thestage_api/dtos/enums → inference_model/dto/enum}/inference_model_status.py +0 -0
  164. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_request.py +0 -0
  165. /thestage/{services/clients/thestage_api/dtos → inference_model/dto}/inference_simulator_model_response.py +0 -0
  166. /thestage/{services/clients/thestage_api/dtos/enums → inference_simulator/dto/enum}/inference_simulator_status.py +0 -0
  167. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/get_inference_simulator_request.py +0 -0
  168. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_request.py +0 -0
  169. /thestage/{services/clients/thestage_api/dtos → inference_simulator/dto}/inference_simulator_response.py +0 -0
  170. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/cpu_type.py +0 -0
  171. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/gpu_name.py +0 -0
  172. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/instance_rented_status.py +0 -0
  173. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/provider_name.py +0 -0
  174. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/selfhosted_status.py +0 -0
  175. /thestage/{entities → instance/dto}/rented_instance.py +0 -0
  176. /thestage/{entities → instance/dto}/self_hosted_instance.py +0 -0
  177. /thestage/{services/logging → logging}/byte_print_style.py +0 -0
  178. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/docker_container_log_stream_request.py +0 -0
  179. /thestage/{services/logging → logging}/dto/log_message.py +0 -0
  180. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_request.py +0 -0
  181. /thestage/{services/logging → logging}/dto/log_type.py +0 -0
  182. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/task_log_stream_request.py +0 -0
  183. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_request.py +0 -0
  184. /thestage/{services/logging → logging}/logging_constants.py +0 -0
  185. /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py → project/dto/get_deploy_ssh_key_request.py} +0 -0
  186. /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py → project/dto/get_deploy_ssh_key_response.py} +0 -0
  187. /thestage/{services/project → project}/dto/project_config.py +0 -0
  188. /thestage/{services/clients/thestage_api/dtos → project/dto}/project_response.py +0 -0
  189. /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_execution_status.py +0 -0
  190. /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_status.py +0 -0
  191. /thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py → task/dto/list_for_project_request.py} +0 -0
  192. /thestage/{services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py → task/dto/status_localized_map_response.py} +0 -0
  193. {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/entry_points.txt +0 -0
  194. {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,751 +0,0 @@
1
- from typing import Optional, List, Tuple, Dict, Iterator
2
-
3
- import httpx
4
-
5
- from thestage.helpers.error_handler import error_handler
6
- from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
7
- from thestage.services.clients.thestage_api.dtos.base_controller.connect_resolve_response import \
8
- ConnectResolveOptionsResponse
9
- from thestage.services.clients.thestage_api.dtos.docker_container_controller.docker_container_list_request import \
10
- DockerContainerListRequest
11
- from thestage.services.clients.thestage_api.dtos.docker_container_controller.docker_container_list_response import \
12
- DockerContainerListResponse
13
- from thestage.services.clients.thestage_api.dtos.entity_filter_request import EntityFilterRequest
14
- from thestage.services.clients.thestage_api.dtos.inference_controller.deploy_inference_model_to_instance_request import \
15
- DeployInferenceModelToInstanceRequest
16
- from thestage.services.clients.thestage_api.dtos.inference_controller.deploy_inference_model_to_instance_response import \
17
- DeployInferenceModelToInstanceResponse
18
- from thestage.services.clients.thestage_api.dtos.inference_controller.deploy_inference_model_to_sagemaker_request import \
19
- DeployInferenceModelToSagemakerRequest
20
- from thestage.services.clients.thestage_api.dtos.inference_controller.deploy_inference_model_to_sagemaker_response import \
21
- DeployInferenceModelToSagemakerResponse
22
- from thestage.services.clients.thestage_api.dtos.inference_controller.get_inference_simulator_request import \
23
- GetInferenceSimulatorRequest
24
- from thestage.services.clients.thestage_api.dtos.inference_controller.get_inference_simulator_response import \
25
- GetInferenceSimulatorResponse
26
- from thestage.services.clients.thestage_api.dtos.inference_controller.inference_simulator_list_request import \
27
- InferenceSimulatorListRequest
28
- from thestage.services.clients.thestage_api.dtos.inference_controller.inference_simulator_list_response import \
29
- InferenceSimulatorListResponse
30
- from thestage.services.clients.thestage_api.dtos.inference_controller.inference_simulator_model_list_for_project_request import \
31
- InferenceSimulatorModelListForProjectRequest
32
- from thestage.services.clients.thestage_api.dtos.inference_controller.inference_simulator_model_list_for_project_response import \
33
- InferenceSimulatorModelListForProjectResponse
34
- from thestage.services.clients.thestage_api.dtos.inference_simulator_model_response import \
35
- InferenceSimulatorModelStatusMapperResponse
36
- from thestage.services.clients.thestage_api.dtos.inference_simulator_response import \
37
- InferenceSimulatorStatusMapperResponse
38
- from thestage.services.clients.thestage_api.dtos.logging_controller.log_polling_request import LogPollingRequest
39
- from thestage.services.clients.thestage_api.dtos.logging_controller.log_polling_response import LogPollingResponse
40
- from thestage.services.clients.thestage_api.dtos.logging_controller.user_logs_query_request import UserLogsQueryRequest
41
- from thestage.services.clients.thestage_api.dtos.logging_controller.user_logs_query_response import \
42
- UserLogsQueryResponse
43
- from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
44
- from thestage.services.clients.thestage_api.dtos.project_controller.project_get_deploy_ssh_key_request import \
45
- ProjectGetDeploySshKeyRequest
46
- from thestage.services.clients.thestage_api.dtos.project_controller.project_get_deploy_ssh_key_response import \
47
- ProjectGetDeploySshKeyResponse
48
- from thestage.services.clients.thestage_api.dtos.project_controller.project_push_inference_simulator_model_request import \
49
- ProjectPushInferenceSimulatorModelRequest
50
- from thestage.services.clients.thestage_api.dtos.project_controller.project_push_inference_simulator_model_response import \
51
- ProjectPushInferenceSimulatorModelResponse
52
- from thestage.services.clients.thestage_api.dtos.project_controller.project_run_task_request import \
53
- ProjectRunTaskRequest
54
- from thestage.services.clients.thestage_api.dtos.project_controller.project_run_task_response import \
55
- ProjectRunTaskResponse
56
- from thestage.services.clients.thestage_api.dtos.project_controller.project_start_inference_simulator_request import \
57
- ProjectStartInferenceSimulatorRequest
58
- from thestage.services.clients.thestage_api.dtos.project_controller.project_start_inference_simulator_response import \
59
- ProjectStartInferenceSimulatorResponse
60
- from thestage.services.clients.thestage_api.dtos.project_response import ProjectDto, ProjectViewResponse
61
- from thestage.services.clients.thestage_api.dtos.selfhosted_instance_response import SelfHostedInstanceListResponse, \
62
- SelfHostedInstanceDto, SelfHostedRentedItemResponse, SelfHostedRentedRentedBusinessStatusMapperResponse
63
- from thestage.services.clients.thestage_api.dtos.container_param_request import DockerContainerActionRequestDto
64
- from thestage.services.clients.thestage_api.dtos.container_response import DockerContainerDto, \
65
- DockerContainerViewResponse, ContainerBusinessStatusMapperResponse
66
- from thestage.entities.enums.order_direction_type import OrderDirectionType
67
- from thestage.services.clients.thestage_api.dtos.ssh_key_controller.add_ssh_key_to_user_request import \
68
- AddSshKeyToUserRequest
69
- from thestage.services.clients.thestage_api.dtos.ssh_key_controller.add_ssh_key_to_user_response import \
70
- AddSshKeyToUserResponse
71
- from thestage.services.clients.thestage_api.dtos.ssh_key_controller.add_ssh_public_key_to_instance_request import \
72
- AddSshPublicKeyToInstanceRequest
73
- from thestage.services.clients.thestage_api.dtos.ssh_key_controller.add_ssh_public_key_to_instance_response import \
74
- AddSshPublicKeyToInstanceResponse
75
- from thestage.services.clients.thestage_api.dtos.ssh_key_controller.is_user_has_public_ssh_key_request import \
76
- IsUserHasSshPublicKeyRequest
77
- from thestage.services.clients.thestage_api.dtos.ssh_key_controller.is_user_has_public_ssh_key_response import \
78
- IsUserHasSshPublicKeyResponse
79
- from thestage.services.clients.thestage_api.dtos.task_controller.task_list_for_project_request import \
80
- TaskListForProjectRequest
81
- from thestage.services.clients.thestage_api.dtos.task_controller.task_list_for_project_response import \
82
- TaskListForProjectResponse
83
- from thestage.services.clients.thestage_api.dtos.task_controller.task_status_localized_map_response import \
84
- TaskStatusLocalizedMapResponse
85
- from thestage.services.clients.thestage_api.dtos.task_controller.task_view_response import TaskViewResponse
86
- from thestage.services.clients.thestage_api.dtos.instance_rented_response import InstanceRentedListResponse, \
87
- InstanceRentedDto, InstanceRentedItemResponse, InstanceRentedBusinessStatusMapperResponse
88
-
89
- from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
90
- from thestage.services.config_provider.config_provider import ConfigProvider
91
- from thestage.services.project.dto.inference_simulator_dto import InferenceSimulatorDto
92
- from thestage.services.project.dto.inference_simulator_model_dto import InferenceSimulatorModelDto
93
- from thestage.services.task.dto.task_dto import TaskDto
94
-
95
-
96
- class TheStageApiClient(TheStageApiClientCore):
97
- __config_provider: ConfigProvider = None
98
-
99
- def __init__(
100
- self,
101
- config_provider: ConfigProvider,
102
- ):
103
- # TODO this is super bullshit, remove all abstract classes
104
- super().__init__(url=config_provider.get_config().main.thestage_api_url)
105
- self.__config_provider = config_provider
106
-
107
- def get_task(
108
- self,
109
- task_public_id: str,
110
- ) -> Optional[TaskViewResponse]:
111
- data = {
112
- "taskPublicId": task_public_id,
113
- }
114
-
115
- response = self._request(
116
- method='POST',
117
- url='/user-api/v2/task/view',
118
- data=data,
119
- token=self.__config_provider.get_config().main.thestage_auth_token,
120
- )
121
-
122
- result = TaskViewResponse.model_validate(response) if response else None
123
- return result if result and result.is_success else None
124
-
125
- def get_task_list_for_project(
126
- self,
127
- project_public_id: Optional[str],
128
- project_slug: Optional[str],
129
- page: int = 1,
130
- limit: int = 10,
131
- ) -> Optional[PaginatedEntityList[TaskDto]]:
132
- request = TaskListForProjectRequest(
133
- projectPublicId=project_public_id,
134
- projectSlug=project_slug,
135
- entityFilterRequest=EntityFilterRequest(
136
- orderByField="createdAt",
137
- orderByDirection=OrderDirectionType.DESC,
138
- page=page,
139
- limit=limit,
140
- ),
141
- )
142
-
143
- response = self._request(
144
- method='POST',
145
- url='/user-api/v2/task/list',
146
- data=request.model_dump(),
147
- token=self.__config_provider.get_config().main.thestage_auth_token,
148
- )
149
-
150
- result = TaskListForProjectResponse.model_validate(response) if response else None
151
- return result.tasks if result and result.is_success else None
152
-
153
- def get_inference_simulator_list(
154
- self,
155
- project_public_id: Optional[str],
156
- project_slug: Optional[str],
157
- statuses: List[str] = [],
158
- page: int = 1,
159
- limit: int = 10,
160
- ) -> Optional[PaginatedEntityList[InferenceSimulatorDto]]:
161
- request = InferenceSimulatorListRequest(
162
- projectPublicId=project_public_id,
163
- projectSlug=project_slug,
164
- statuses=statuses,
165
- entityFilterRequest=EntityFilterRequest(
166
- orderByField="createdAt",
167
- orderByDirection=OrderDirectionType.DESC,
168
- page=page,
169
- limit=limit,
170
- ),
171
- )
172
-
173
- response = self._request(
174
- method='POST',
175
- url='/user-api/v2/inference-simulator/list',
176
- data=request.model_dump(),
177
- token=self.__config_provider.get_config().main.thestage_auth_token,
178
- )
179
- result = InferenceSimulatorListResponse.model_validate(response) if response else None
180
- return result.inferenceSimulators if result and result.is_success else None
181
-
182
- def get_inference_simulator_model_list_for_project(
183
- self,
184
- project_public_id: Optional[str],
185
- project_slug: Optional[str],
186
- statuses: Optional[List[str]] = None,
187
- page: int = 1,
188
- limit: int = 10,
189
- ) -> Optional[PaginatedEntityList[InferenceSimulatorModelDto]]:
190
- request = InferenceSimulatorModelListForProjectRequest(
191
- projectPublicId=project_public_id,
192
- projectSlug=project_slug,
193
- statuses=statuses,
194
- entityFilterRequest=EntityFilterRequest(
195
- orderByField="createdAt",
196
- orderByDirection=OrderDirectionType.DESC,
197
- page=page,
198
- limit=limit,
199
- ),
200
- )
201
-
202
- response = self._request(
203
- method='POST',
204
- url='/user-api/v2/inference-simulator-model/list',
205
- data=request.model_dump(),
206
- token=self.__config_provider.get_config().main.thestage_auth_token,
207
- )
208
- result = InferenceSimulatorModelListForProjectResponse.model_validate(response) if response else None
209
- return result.inferenceSimulatorModels if result and result.is_success else None
210
-
211
- def get_rented_instance_list(
212
- self,
213
- statuses: List[str],
214
- page: int = 1,
215
- limit: int = 10,
216
- ) -> PaginatedEntityList[InstanceRentedDto]:
217
- data = {
218
- #"statuses": [item.value for item in statuses],
219
- "entityFilterRequest": {
220
- "orderByField": "createdAt",
221
- "orderByDirection": "DESC",
222
- "page": page,
223
- "limit": limit
224
- },
225
- }
226
-
227
- if statuses:
228
- data['businessStatuses'] = statuses
229
-
230
- response = self._request(
231
- method='POST',
232
- url='/user-api/v3/instance-rented/list',
233
- data=data,
234
- token=self.__config_provider.get_config().main.thestage_auth_token,
235
- )
236
-
237
- result = InstanceRentedListResponse.model_validate(response) if response else None
238
- return result.paginated_list if result and result.paginated_list else ([], None)
239
-
240
- def get_rented_business_status_map(self) -> Optional[Dict[str, str]]:
241
- response = self._request(
242
- method='POST',
243
- url='/user-api/v2/instance-rented/business-status-localized-map',
244
- data=None,
245
- token=self.__config_provider.get_config().main.thestage_auth_token,
246
- )
247
-
248
- data = InstanceRentedBusinessStatusMapperResponse.model_validate(response) if response else None
249
-
250
- return data.instance_rented_business_status_map if data else None
251
-
252
- def get_task_localized_status_map(self) -> Optional[Dict[str, str]]:
253
- response = self._request(
254
- method='POST',
255
- url='/user-api/v1/task/status-localized-mapping',
256
- data=None,
257
- token=self.__config_provider.get_config().main.thestage_auth_token,
258
- )
259
-
260
- data = TaskStatusLocalizedMapResponse.model_validate(response) if response else None
261
-
262
- return data.taskStatusMap if data else None
263
-
264
- def get_rented_instance(
265
- self,
266
- instance_public_id: Optional[str] = None,
267
- instance_slug: Optional[str] = None,
268
- ) -> Optional[InstanceRentedDto]:
269
- if not instance_slug and not instance_public_id:
270
- return None
271
-
272
- data = {
273
- "instanceRentedPublicId": instance_public_id,
274
- "instanceRentedSlug": instance_slug,
275
- }
276
-
277
- response = self._request(
278
- method='POST',
279
- url='/user-api/v3/instance-rented/view',
280
- data=data,
281
- token=self.__config_provider.get_config().main.thestage_auth_token,
282
- )
283
-
284
- return InstanceRentedItemResponse.model_validate(response).instance_rented if response else None
285
-
286
- def get_selfhosted_instance(
287
- self,
288
- instance_public_id: Optional[str] = None,
289
- instance_slug: Optional[str] = None,
290
- ) -> Optional[SelfHostedInstanceDto]:
291
- if not instance_slug and not instance_public_id:
292
- return None
293
-
294
- data = {
295
- "selfhostedInstancePublicId": instance_public_id,
296
- "selfhostedInstanceSlug": instance_slug,
297
- }
298
-
299
- response = self._request(
300
- method='POST',
301
- url='/user-api/v3/self-hosted-instance/view',
302
- data=data,
303
- token=self.__config_provider.get_config().main.thestage_auth_token,
304
- )
305
-
306
- return SelfHostedRentedItemResponse.model_validate(response).selfhosted_instance if response else None
307
-
308
- def get_selfhosted_instance_list(
309
- self,
310
- statuses: List[str],
311
- page: int = 1,
312
- limit: int = 10,
313
- ) -> PaginatedEntityList[SelfHostedInstanceDto]:
314
- data = {
315
- "entityFilterRequest": {
316
- "orderByField": "createdAt",
317
- "orderByDirection": "DESC",
318
- "page": page,
319
- "limit": limit
320
- }
321
- }
322
-
323
- if statuses:
324
- data['businessStatuses'] = statuses
325
-
326
- response = self._request(
327
- method='POST',
328
- url='/user-api/v3/self-hosted-instance/list',
329
- data=data,
330
- token=self.__config_provider.get_config().main.thestage_auth_token,
331
- )
332
-
333
- result = SelfHostedInstanceListResponse.model_validate(response) if response else None
334
- return result.paginated_list if result and result.paginated_list else ([], None)
335
-
336
- def get_selfhosted_business_status_map(self) -> Optional[Dict[str, str]]:
337
- response = self._request(
338
- method='POST',
339
- url='/user-api/v2/self-hosted-instance/business-status-localized-map',
340
- data=None,
341
- token=self.__config_provider.get_config().main.thestage_auth_token,
342
- )
343
-
344
- data = SelfHostedRentedRentedBusinessStatusMapperResponse.model_validate(response) if response else None
345
- return data.selfhosted_instance_business_status_map if data else None
346
-
347
-
348
- def cancel_task(
349
- self,
350
- task_public_id: str,
351
- ) -> Optional[TheStageBaseResponse]:
352
- data = {
353
- "taskPublicId": task_public_id,
354
- }
355
-
356
- response = self._request(
357
- method='POST',
358
- url='/user-api/v2/task/cancel',
359
- data=data,
360
- token=self.__config_provider.get_config().main.thestage_auth_token,
361
- )
362
-
363
- result = TheStageBaseResponse.model_validate(response) if response else None
364
- return result if result else None
365
-
366
- def get_container_list(
367
- self,
368
- project_public_id: Optional[str] = None,
369
- project_slug: Optional[str] = None,
370
- statuses: List[str] = [],
371
- page: int = 1,
372
- limit: int = 10,
373
- ) -> PaginatedEntityList[DockerContainerDto]:
374
- request = DockerContainerListRequest(
375
- statuses=statuses,
376
- projectPublicId=project_public_id,
377
- projectSlug=project_slug,
378
- entityFilterRequest=EntityFilterRequest(
379
- orderByField="createdAt",
380
- orderByDirection=OrderDirectionType.DESC,
381
- page=page,
382
- limit=limit,
383
- ),
384
- )
385
-
386
- response = self._request(
387
- method='POST',
388
- url='/user-api/v2/docker-container/list',
389
- data=request.model_dump(),
390
- token=self.__config_provider.get_config().main.thestage_auth_token
391
- )
392
-
393
- result = DockerContainerListResponse.model_validate(response) if response else None
394
- # return result.paginatedList.entities, result.paginatedList.pagination_data.total_pages if result and result.is_success else None
395
- return result.paginatedList if result and result.is_success else None
396
-
397
- def get_container(
398
- self,
399
- container_slug: Optional[str] = None,
400
- container_public_id: Optional[str] = None,
401
- ) -> Optional[DockerContainerDto]:
402
- data = {
403
- "dockerContainerPublicId": container_public_id,
404
- "dockerContainerSlug": container_slug,
405
- }
406
-
407
- response = self._request(
408
- method='POST',
409
- url='/user-api/v2/docker-container/view',
410
- data=data,
411
- token=self.__config_provider.get_config().main.thestage_auth_token,
412
- )
413
-
414
- return DockerContainerViewResponse.model_validate(response).docker_container if response else None
415
-
416
- def container_action(
417
- self,
418
- request_param: DockerContainerActionRequestDto,
419
- ) -> TheStageBaseResponse:
420
-
421
- response = self._request(
422
- method='POST',
423
- url='/user-api/v2/docker-container/action',
424
- data=request_param.model_dump(by_alias=True),
425
- token=self.__config_provider.get_config().main.thestage_auth_token,
426
- )
427
-
428
- result = TheStageBaseResponse.model_validate(response) if response else None
429
- return result
430
-
431
- def get_container_business_status_map(self) -> Optional[Dict[str, str]]:
432
- response = self._request(
433
- method='POST',
434
- url='/user-api/v1/docker-container/status-localized-mapping',
435
- data=None,
436
- token=self.__config_provider.get_config().main.thestage_auth_token,
437
- )
438
-
439
- data = ContainerBusinessStatusMapperResponse.model_validate(response) if response else None
440
- return data.docker_container_status_map if data else None
441
-
442
- def get_project(self, slug: Optional[str], public_id: Optional[str]) -> Optional[ProjectDto]:
443
- data = {
444
- "projectSlug": slug,
445
- "projectPublicId": public_id,
446
- }
447
-
448
- response = self._request(
449
- method='POST',
450
- url='/user-api/v2/project/view',
451
- data=data,
452
- token=self.__config_provider.get_config().main.thestage_auth_token,
453
- )
454
-
455
- result = ProjectViewResponse.model_validate(response) if response else None
456
- project = ProjectDto.model_validate(result.project) if result else None
457
- return project if result and result.is_success else None
458
-
459
- def get_project_deploy_ssh_key(self, public_id: str) -> str:
460
- request = ProjectGetDeploySshKeyRequest(
461
- projectPublicId=public_id,
462
- )
463
-
464
- response = self._request(
465
- method='POST',
466
- url='/user-api/v1/project/get-deploy-ssh-key',
467
- data=request.model_dump(),
468
- token=self.__config_provider.get_config().main.thestage_auth_token,
469
- )
470
-
471
- result = ProjectGetDeploySshKeyResponse.model_validate(response) if response else None
472
- return result.privateKey if result and result.is_success else None
473
-
474
- def execute_project_task(
475
- self,
476
- project_public_id: str,
477
- run_command: str,
478
- task_title: str,
479
- docker_container_public_id: str,
480
- commit_hash: Optional[str] = None,
481
- ) -> Optional[ProjectRunTaskResponse]:
482
- request = ProjectRunTaskRequest(
483
- projectPublicId=project_public_id,
484
- dockerContainerPublicId=docker_container_public_id,
485
- commitHash=commit_hash,
486
- runCommand=run_command,
487
- taskTitle=task_title,
488
- )
489
-
490
- response = self._request(
491
- method='POST',
492
- url='/user-api/v2/task/execute',
493
- data=request.model_dump(),
494
- token=self.__config_provider.get_config().main.thestage_auth_token,
495
- )
496
-
497
- return ProjectRunTaskResponse.model_validate(response) if response else None
498
-
499
- async def poll_logs_httpx(self, docker_container_public_id: Optional[str], last_log_timestamp: str,
500
- last_log_id: str, task_public_id: Optional[str] = None,
501
- inference_simulator_public_id: Optional[str] = None) -> Optional[LogPollingResponse]:
502
- request_headers = {'Content-Type': 'application/json'}
503
- token = self.__config_provider.get_config().main.thestage_auth_token
504
- if token: request_headers['Authorization'] = f"Bearer {token}"
505
-
506
- request = LogPollingRequest(
507
- inferenceSimulatorPublicId=inference_simulator_public_id,
508
- taskPublicId=task_public_id,
509
- dockerContainerPublicId=docker_container_public_id,
510
- lastLogTimestamp=last_log_timestamp,
511
- lastLogId=last_log_id
512
- )
513
-
514
- async with httpx.AsyncClient() as client:
515
- response = await client.post(
516
- url=f"{self._get_host()}/user-api/v2/logging/poll",
517
- headers=request_headers,
518
- json=request.model_dump(),
519
- timeout=3.5
520
- )
521
-
522
- return LogPollingResponse.model_validate(response.json()) if response else None
523
-
524
- def add_public_ssh_key_to_user(self, public_key: str, note: str) -> AddSshKeyToUserResponse:
525
- request = AddSshKeyToUserRequest(
526
- sshKey=public_key,
527
- note=note
528
- )
529
-
530
- response = self._request(
531
- method='POST',
532
- url='/user-api/v2/ssh-key/add-public-key-to-user',
533
- data=request.model_dump(),
534
- token=self.__config_provider.get_config().main.thestage_auth_token,
535
- )
536
-
537
- result = AddSshKeyToUserResponse.model_validate(response) if response else None
538
- return result
539
-
540
- def is_user_has_ssh_public_key(self, public_key: str) -> IsUserHasSshPublicKeyResponse:
541
- request = IsUserHasSshPublicKeyRequest(
542
- sshKey=public_key,
543
- )
544
-
545
- response = self._request(
546
- method='POST',
547
- url='/user-api/v2/ssh-key/is-user-has-public-ssh-key',
548
- data=request.model_dump(),
549
- token=self.__config_provider.get_config().main.thestage_auth_token,
550
- )
551
-
552
- result = IsUserHasSshPublicKeyResponse.model_validate(response) if response else None
553
- return result
554
-
555
- def add_public_ssh_key_to_instance_rented(self, instance_rented_public_id: str,
556
- ssh_key_pair_public_id: str) -> AddSshPublicKeyToInstanceResponse:
557
- request = AddSshPublicKeyToInstanceRequest(
558
- instanceRentedPublicId=instance_rented_public_id,
559
- sshPublicKeyPublicId=ssh_key_pair_public_id,
560
- )
561
-
562
- response = self._request(
563
- method='POST',
564
- url='/user-api/v2/ssh-key/add-public-ssh-key-to-instance-rented',
565
- data=request.model_dump(),
566
- token=self.__config_provider.get_config().main.thestage_auth_token,
567
- )
568
-
569
- result = AddSshPublicKeyToInstanceResponse.model_validate(response) if response else None
570
- return result
571
-
572
- def start_project_inference_simulator(
573
- self,
574
- project_public_id: str,
575
- commit_hash: Optional[str] = None,
576
- rented_instance_public_id: Optional[str] = None,
577
- rented_instance_slug: Optional[str] = None,
578
- self_hosted_instance_public_id: Optional[str] = None,
579
- self_hosted_instance_slug: Optional[str] = None,
580
- inference_dir: Optional[str] = None,
581
- is_skip_installation: Optional[bool] = False,
582
- ) -> Optional[ProjectStartInferenceSimulatorResponse]:
583
- request = ProjectStartInferenceSimulatorRequest(
584
- projectPublicId=project_public_id,
585
- commitHash=commit_hash,
586
- instanceRentedPublicId=rented_instance_public_id,
587
- instanceRentedSlug=rented_instance_slug,
588
- selfhostedInstancePublicId=self_hosted_instance_public_id,
589
- selfhostedInstanceSlug=self_hosted_instance_slug,
590
- inferenceDir=inference_dir,
591
- isSkipInstallation=is_skip_installation,
592
- )
593
-
594
- response = self._request(
595
- method='POST',
596
- url='/user-api/v2/project/inference-simulator/create',
597
- data=request.model_dump(),
598
- token=self.__config_provider.get_config().main.thestage_auth_token,
599
- )
600
-
601
- return ProjectStartInferenceSimulatorResponse.model_validate(response) if response else None
602
-
603
- def push_project_inference_simulator_model(
604
- self,
605
- public_id: Optional[str],
606
- slug: Optional[str],
607
- ) -> Optional[ProjectPushInferenceSimulatorModelResponse]:
608
- request = ProjectPushInferenceSimulatorModelRequest(
609
- inferenceSimulatorPublicId=public_id,
610
- inferenceSimulatorSlug=slug,
611
- )
612
-
613
- response = self._request(
614
- method='POST',
615
- url='/user-api/v2/inference-simulator/push-model',
616
- data=request.model_dump(),
617
- token=self.__config_provider.get_config().main.thestage_auth_token,
618
- )
619
-
620
- return ProjectPushInferenceSimulatorModelResponse.model_validate(response) if response else None
621
-
622
- def get_inference_simulator_business_status_map(self) -> Optional[Dict[str, str]]:
623
- response = self._request(
624
- method='POST',
625
- url='/user-api/v1/inference-simulator/status-localized-mapping',
626
- data=None,
627
- token=self.__config_provider.get_config().main.thestage_auth_token,
628
- )
629
-
630
- data = InferenceSimulatorStatusMapperResponse.model_validate(response) if response else None
631
-
632
- return data.inference_simulator_status_map if data else None
633
-
634
- def get_inference_simulator_model_business_status_map(self) -> Optional[Dict[str, str]]:
635
- response = self._request(
636
- method='POST',
637
- url='/user-api/v1/inference-simulator-model/status-localized-mapping',
638
- data=None,
639
- token=self.__config_provider.get_config().main.thestage_auth_token,
640
- )
641
-
642
- data = InferenceSimulatorModelStatusMapperResponse.model_validate(response) if response else None
643
-
644
- return data.inference_simulator_model_status_map if data else None
645
-
646
- @error_handler()
647
- def get_inference_simulator(
648
- self,
649
- public_id: Optional[str] = None,
650
- slug: Optional[str] = None,
651
- ) -> Optional[GetInferenceSimulatorResponse]:
652
- request = GetInferenceSimulatorRequest(
653
- publicId=public_id,
654
- slug=slug,
655
- )
656
-
657
- response = self._request(
658
- method='POST',
659
- url='/user-api/v2/inference-simulator/get',
660
- data=request.model_dump(),
661
- token=self.__config_provider.get_config().main.thestage_auth_token,
662
- )
663
- return GetInferenceSimulatorResponse.model_validate(response) if response else None
664
-
665
- @error_handler()
666
- def deploy_inference_model_to_instance(
667
- self,
668
- model_public_id: str,
669
- model_slug: str,
670
- rented_instance_public_id: Optional[str] = None,
671
- rented_instance_slug: Optional[str] = None,
672
- self_hosted_instance_public_id: Optional[str] = None,
673
- self_hosted_instance_slug: Optional[str] = None,
674
-
675
- ) -> Optional[DeployInferenceModelToInstanceResponse]:
676
- request = DeployInferenceModelToInstanceRequest(
677
- modelPublicId=model_public_id,
678
- modelSlug=model_slug,
679
- instanceRentedPublicId=rented_instance_public_id,
680
- instanceRentedSlug=rented_instance_slug,
681
- selfhostedInstancePublicId=self_hosted_instance_public_id,
682
- selfhostedInstanceSlug=self_hosted_instance_slug
683
- )
684
-
685
- response = self._request(
686
- method='POST',
687
- url='/user-api/v2/inference-simulator-model/deploy/instance',
688
- data=request.model_dump(),
689
- token=self.__config_provider.get_config().main.thestage_auth_token,
690
- )
691
- return DeployInferenceModelToInstanceResponse.model_validate(response) if response else None
692
-
693
- @error_handler()
694
- def deploy_inference_model_to_sagemaker(
695
- self,
696
- model_public_id: Optional[str],
697
- model_slug: Optional[str],
698
- arn: Optional[str] = None,
699
- ) -> Optional[DeployInferenceModelToSagemakerResponse]:
700
- request = DeployInferenceModelToSagemakerRequest(
701
- modelPublicId=model_public_id,
702
- modelSlug=model_slug,
703
- arn=arn,
704
- )
705
-
706
- response = self._request(
707
- method='POST',
708
- url='/user-api/v1/inference-simulator-model/grant-user-arn-access',
709
- data=request.model_dump(),
710
- token=self.__config_provider.get_config().main.thestage_auth_token,
711
- )
712
- return DeployInferenceModelToSagemakerResponse.model_validate(response) if response else None
713
-
714
- def query_user_logs(self, limit: int, task_public_id: Optional[str] = None,
715
- inference_simulator_public_id: Optional[str] = None,
716
- container_public_id: Optional[str] = None) -> UserLogsQueryResponse:
717
- request = UserLogsQueryRequest(
718
- inferenceSimulatorPublicId=inference_simulator_public_id,
719
- taskPublicId=task_public_id,
720
- containerPublicId=container_public_id,
721
- limit=limit,
722
- ascendingOrder=False,
723
- )
724
-
725
- response = self._request(
726
- method='POST',
727
- url='/user-api/v2/logging/query-user-logs',
728
- data=request.model_dump(),
729
- token=self.__config_provider.get_config().main.thestage_auth_token,
730
- )
731
-
732
- result = UserLogsQueryResponse.model_validate(response) if response else None
733
- return result
734
-
735
-
736
- def resolve_user_input(
737
- self,
738
- entity_identifier: str
739
- ) -> Optional[ConnectResolveOptionsResponse]:
740
- data = {
741
- "entityIdentifier": entity_identifier,
742
- }
743
-
744
- response = self._request(
745
- method='POST',
746
- url='/user-api/v1/resolve-user-input',
747
- data=data,
748
- token=self.__config_provider.get_config().main.thestage_auth_token,
749
- )
750
-
751
- return ConnectResolveOptionsResponse.model_validate(response) if response else None