digitalkin 0.2.25rc0__py3-none-any.whl → 0.3.2.dev14__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.
- base_server/server_async_insecure.py +6 -5
- base_server/server_async_secure.py +6 -5
- base_server/server_sync_insecure.py +5 -4
- base_server/server_sync_secure.py +5 -4
- digitalkin/__version__.py +1 -1
- digitalkin/core/__init__.py +1 -0
- digitalkin/core/common/__init__.py +9 -0
- digitalkin/core/common/factories.py +156 -0
- digitalkin/core/job_manager/__init__.py +1 -0
- digitalkin/{modules → core}/job_manager/base_job_manager.py +138 -32
- digitalkin/core/job_manager/single_job_manager.py +373 -0
- digitalkin/{modules → core}/job_manager/taskiq_broker.py +121 -26
- digitalkin/core/job_manager/taskiq_job_manager.py +541 -0
- digitalkin/core/task_manager/__init__.py +1 -0
- digitalkin/core/task_manager/base_task_manager.py +539 -0
- digitalkin/core/task_manager/local_task_manager.py +108 -0
- digitalkin/core/task_manager/remote_task_manager.py +87 -0
- digitalkin/core/task_manager/surrealdb_repository.py +266 -0
- digitalkin/core/task_manager/task_executor.py +249 -0
- digitalkin/core/task_manager/task_session.py +368 -0
- digitalkin/grpc_servers/__init__.py +1 -19
- digitalkin/grpc_servers/_base_server.py +3 -3
- digitalkin/grpc_servers/module_server.py +120 -195
- digitalkin/grpc_servers/module_servicer.py +81 -44
- digitalkin/grpc_servers/utils/__init__.py +1 -0
- digitalkin/grpc_servers/utils/exceptions.py +0 -8
- digitalkin/grpc_servers/utils/grpc_client_wrapper.py +25 -9
- digitalkin/grpc_servers/utils/grpc_error_handler.py +53 -0
- digitalkin/grpc_servers/utils/utility_schema_extender.py +100 -0
- digitalkin/logger.py +64 -27
- digitalkin/mixins/__init__.py +19 -0
- digitalkin/mixins/base_mixin.py +10 -0
- digitalkin/mixins/callback_mixin.py +24 -0
- digitalkin/mixins/chat_history_mixin.py +110 -0
- digitalkin/mixins/cost_mixin.py +76 -0
- digitalkin/mixins/file_history_mixin.py +93 -0
- digitalkin/mixins/filesystem_mixin.py +46 -0
- digitalkin/mixins/logger_mixin.py +51 -0
- digitalkin/mixins/storage_mixin.py +79 -0
- digitalkin/models/__init__.py +1 -1
- digitalkin/models/core/__init__.py +1 -0
- digitalkin/{modules/job_manager → models/core}/job_manager_models.py +3 -11
- digitalkin/models/core/task_monitor.py +74 -0
- digitalkin/models/grpc_servers/__init__.py +1 -0
- digitalkin/{grpc_servers/utils → models/grpc_servers}/models.py +92 -7
- digitalkin/models/module/__init__.py +18 -11
- digitalkin/models/module/base_types.py +61 -0
- digitalkin/models/module/module.py +9 -1
- digitalkin/models/module/module_context.py +282 -6
- digitalkin/models/module/module_types.py +29 -105
- digitalkin/models/module/setup_types.py +490 -0
- digitalkin/models/module/tool_cache.py +68 -0
- digitalkin/models/module/tool_reference.py +117 -0
- digitalkin/models/module/utility.py +167 -0
- digitalkin/models/services/__init__.py +9 -0
- digitalkin/models/services/cost.py +1 -0
- digitalkin/models/services/registry.py +35 -0
- digitalkin/models/services/storage.py +39 -5
- digitalkin/modules/__init__.py +5 -1
- digitalkin/modules/_base_module.py +265 -167
- digitalkin/modules/archetype_module.py +6 -1
- digitalkin/modules/tool_module.py +16 -3
- digitalkin/modules/trigger_handler.py +7 -6
- digitalkin/modules/triggers/__init__.py +8 -0
- digitalkin/modules/triggers/healthcheck_ping_trigger.py +45 -0
- digitalkin/modules/triggers/healthcheck_services_trigger.py +63 -0
- digitalkin/modules/triggers/healthcheck_status_trigger.py +52 -0
- digitalkin/services/__init__.py +4 -0
- digitalkin/services/communication/__init__.py +7 -0
- digitalkin/services/communication/communication_strategy.py +76 -0
- digitalkin/services/communication/default_communication.py +101 -0
- digitalkin/services/communication/grpc_communication.py +234 -0
- digitalkin/services/cost/__init__.py +9 -2
- digitalkin/services/cost/grpc_cost.py +9 -42
- digitalkin/services/filesystem/default_filesystem.py +0 -2
- digitalkin/services/filesystem/grpc_filesystem.py +10 -39
- digitalkin/services/registry/__init__.py +22 -1
- digitalkin/services/registry/default_registry.py +135 -4
- digitalkin/services/registry/exceptions.py +47 -0
- digitalkin/services/registry/grpc_registry.py +306 -0
- digitalkin/services/registry/registry_models.py +15 -0
- digitalkin/services/registry/registry_strategy.py +88 -4
- digitalkin/services/services_config.py +25 -3
- digitalkin/services/services_models.py +5 -1
- digitalkin/services/setup/default_setup.py +6 -7
- digitalkin/services/setup/grpc_setup.py +52 -15
- digitalkin/services/storage/grpc_storage.py +4 -4
- digitalkin/services/user_profile/__init__.py +12 -0
- digitalkin/services/user_profile/default_user_profile.py +55 -0
- digitalkin/services/user_profile/grpc_user_profile.py +69 -0
- digitalkin/services/user_profile/user_profile_strategy.py +25 -0
- digitalkin/utils/__init__.py +28 -0
- digitalkin/utils/arg_parser.py +1 -1
- digitalkin/utils/development_mode_action.py +2 -2
- digitalkin/utils/dynamic_schema.py +483 -0
- digitalkin/utils/package_discover.py +1 -2
- digitalkin/utils/schema_splitter.py +207 -0
- {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/METADATA +11 -30
- digitalkin-0.3.2.dev14.dist-info/RECORD +143 -0
- {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/top_level.txt +1 -0
- modules/archetype_with_tools_module.py +244 -0
- modules/cpu_intensive_module.py +1 -1
- modules/dynamic_setup_module.py +338 -0
- modules/minimal_llm_module.py +1 -1
- modules/text_transform_module.py +1 -1
- monitoring/digitalkin_observability/__init__.py +46 -0
- monitoring/digitalkin_observability/http_server.py +150 -0
- monitoring/digitalkin_observability/interceptors.py +176 -0
- monitoring/digitalkin_observability/metrics.py +201 -0
- monitoring/digitalkin_observability/prometheus.py +137 -0
- monitoring/tests/test_metrics.py +172 -0
- services/filesystem_module.py +7 -5
- services/storage_module.py +4 -2
- digitalkin/grpc_servers/registry_server.py +0 -65
- digitalkin/grpc_servers/registry_servicer.py +0 -456
- digitalkin/grpc_servers/utils/factory.py +0 -180
- digitalkin/modules/job_manager/single_job_manager.py +0 -294
- digitalkin/modules/job_manager/taskiq_job_manager.py +0 -290
- digitalkin-0.2.25rc0.dist-info/RECORD +0 -89
- /digitalkin/{grpc_servers/utils → models/grpc_servers}/types.py +0 -0
- {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/WHEEL +0 -0
- {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,7 +5,7 @@ from contextlib import contextmanager
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
import grpc
|
|
8
|
-
from
|
|
8
|
+
from agentic_mesh_protocol.setup.v1 import (
|
|
9
9
|
setup_pb2,
|
|
10
10
|
setup_service_pb2_grpc,
|
|
11
11
|
)
|
|
@@ -15,8 +15,8 @@ from pydantic import ValidationError
|
|
|
15
15
|
|
|
16
16
|
from digitalkin.grpc_servers.utils.exceptions import ServerError
|
|
17
17
|
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
18
|
-
from digitalkin.grpc_servers.utils.models import ClientConfig
|
|
19
18
|
from digitalkin.logger import logger
|
|
19
|
+
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
20
20
|
from digitalkin.services.setup.setup_strategy import SetupData, SetupServiceError, SetupStrategy, SetupVersionData
|
|
21
21
|
|
|
22
22
|
|
|
@@ -30,10 +30,10 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
30
30
|
"""
|
|
31
31
|
channel = self._init_channel(config)
|
|
32
32
|
self.stub = setup_service_pb2_grpc.SetupServiceStub(channel)
|
|
33
|
-
logger.debug("Channel client 'setup' initialized
|
|
33
|
+
logger.debug("Channel client 'setup' initialized successfully")
|
|
34
34
|
|
|
35
35
|
@contextmanager
|
|
36
|
-
def
|
|
36
|
+
def handle_grpc_errors(self, operation: str) -> Generator[Any, Any, Any]: # noqa: PLR6301
|
|
37
37
|
"""Context manager for consistent gRPC error handling.
|
|
38
38
|
|
|
39
39
|
Yields:
|
|
@@ -76,7 +76,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
76
76
|
ServerError: If gRPC operation fails.
|
|
77
77
|
SetupServiceError: For any unexpected internal error.
|
|
78
78
|
"""
|
|
79
|
-
with self.
|
|
79
|
+
with self.handle_grpc_errors("Setup Creation"):
|
|
80
80
|
valid_data = SetupData.model_validate(setup_dict)
|
|
81
81
|
|
|
82
82
|
request = setup_pb2.CreateSetupRequest(
|
|
@@ -104,7 +104,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
104
104
|
ServerError: If gRPC operation fails.
|
|
105
105
|
SetupServiceError: For any unexpected internal error.
|
|
106
106
|
"""
|
|
107
|
-
with self.
|
|
107
|
+
with self.handle_grpc_errors("Get Setup"):
|
|
108
108
|
if "setup_id" not in setup_dict:
|
|
109
109
|
msg = "Setup name is required"
|
|
110
110
|
raise ValidationError(msg)
|
|
@@ -132,7 +132,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
132
132
|
"""
|
|
133
133
|
current_setup_version = None
|
|
134
134
|
|
|
135
|
-
with self.
|
|
135
|
+
with self.handle_grpc_errors("Setup Update"):
|
|
136
136
|
valid_data = SetupData.model_validate(setup_dict)
|
|
137
137
|
|
|
138
138
|
if valid_data.current_setup_version is not None:
|
|
@@ -162,7 +162,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
162
162
|
ServerError: If gRPC operation fails.
|
|
163
163
|
SetupServiceError: For any unexpected internal error.
|
|
164
164
|
"""
|
|
165
|
-
with self.
|
|
165
|
+
with self.handle_grpc_errors("Setup Deletion"):
|
|
166
166
|
setup_id = setup_dict.get("setup_id")
|
|
167
167
|
if not setup_id:
|
|
168
168
|
msg = "Setup name is required for deletion"
|
|
@@ -186,7 +186,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
186
186
|
ServerError: If gRPC operation fails.
|
|
187
187
|
SetupServiceError: For any unexpected internal error.
|
|
188
188
|
"""
|
|
189
|
-
with self.
|
|
189
|
+
with self.handle_grpc_errors("Setup Version Creation"):
|
|
190
190
|
valid_data = SetupVersionData.model_validate(setup_version_dict)
|
|
191
191
|
content_struct = Struct()
|
|
192
192
|
content_struct.update(valid_data.content)
|
|
@@ -216,14 +216,16 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
216
216
|
ServerError: If gRPC operation fails.
|
|
217
217
|
SetupServiceError: For any unexpected internal error.
|
|
218
218
|
"""
|
|
219
|
-
with self.
|
|
219
|
+
with self.handle_grpc_errors("Get Setup Version"):
|
|
220
220
|
setup_version_id = setup_version_dict.get("setup_version_id")
|
|
221
221
|
if not setup_version_id:
|
|
222
222
|
msg = "Setup version id is required"
|
|
223
223
|
raise ValidationError(msg)
|
|
224
224
|
request = setup_pb2.GetSetupVersionRequest(setup_version_id=setup_version_id)
|
|
225
225
|
response = self.exec_grpc_query("GetSetupVersion", request)
|
|
226
|
-
return SetupVersionData(
|
|
226
|
+
return SetupVersionData(
|
|
227
|
+
**json_format.MessageToDict(response.setup_version, preserving_proto_field_name=True)
|
|
228
|
+
)
|
|
227
229
|
|
|
228
230
|
def search_setup_versions(self, setup_version_dict: dict[str, Any]) -> list[SetupVersionData]:
|
|
229
231
|
"""Search for setup versions based on filters.
|
|
@@ -239,7 +241,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
239
241
|
SetupServiceError: For any unexpected internal error.
|
|
240
242
|
ValidationError: If both name and version are not provided.
|
|
241
243
|
"""
|
|
242
|
-
with self.
|
|
244
|
+
with self.handle_grpc_errors("Search Setup Versions"):
|
|
243
245
|
if "name" not in setup_version_dict and "version" not in setup_version_dict:
|
|
244
246
|
msg = "Either name or version must be provided"
|
|
245
247
|
raise ValidationError(msg)
|
|
@@ -248,7 +250,10 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
248
250
|
version=setup_version_dict.get("version", ""),
|
|
249
251
|
)
|
|
250
252
|
response = self.exec_grpc_query("SearchSetupVersions", request)
|
|
251
|
-
return [
|
|
253
|
+
return [
|
|
254
|
+
SetupVersionData(**json_format.MessageToDict(sv, preserving_proto_field_name=True))
|
|
255
|
+
for sv in response.setup_versions
|
|
256
|
+
]
|
|
252
257
|
|
|
253
258
|
def update_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
|
|
254
259
|
"""Update an existing setup version.
|
|
@@ -264,7 +269,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
264
269
|
ServerError: If gRPC operation fails.
|
|
265
270
|
SetupServiceError: For any unexpected internal error.
|
|
266
271
|
"""
|
|
267
|
-
with self.
|
|
272
|
+
with self.handle_grpc_errors("Setup Version Update"):
|
|
268
273
|
valid_data = SetupVersionData.model_validate(setup_version_dict)
|
|
269
274
|
content_struct = Struct()
|
|
270
275
|
content_struct.update(valid_data.content)
|
|
@@ -295,7 +300,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
295
300
|
ServerError: If gRPC operation fails.
|
|
296
301
|
SetupServiceError: For any unexpected internal error.
|
|
297
302
|
"""
|
|
298
|
-
with self.
|
|
303
|
+
with self.handle_grpc_errors("Setup Version Deletion"):
|
|
299
304
|
setup_version_id = setup_version_dict.get("setup_version_id")
|
|
300
305
|
if not setup_version_id:
|
|
301
306
|
msg = "Setup version id is required for deletion"
|
|
@@ -304,3 +309,35 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
304
309
|
response = self.exec_grpc_query("DeleteSetupVersion", request)
|
|
305
310
|
logger.debug("Setup Version '%s' query sent successfully", setup_version_id)
|
|
306
311
|
return getattr(response, "success", False)
|
|
312
|
+
|
|
313
|
+
def list_setups(self, list_dict: dict[str, Any]) -> dict[str, Any]:
|
|
314
|
+
"""List setups with optional filtering and pagination.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
list_dict: Dictionary with optional filters:
|
|
318
|
+
- organisation_id: Filter by organisation
|
|
319
|
+
- owner_id: Filter by owner
|
|
320
|
+
- limit: Maximum number of results
|
|
321
|
+
- offset: Number of results to skip
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
dict[str, Any]: Dictionary with 'setups' list and 'total_count'.
|
|
325
|
+
|
|
326
|
+
Raises:
|
|
327
|
+
ServerError: If gRPC operation fails.
|
|
328
|
+
SetupServiceError: For any unexpected internal error.
|
|
329
|
+
"""
|
|
330
|
+
with self.handle_grpc_errors("List Setups"):
|
|
331
|
+
request = setup_pb2.ListSetupsRequest(
|
|
332
|
+
organisation_id=list_dict.get("organisation_id", ""),
|
|
333
|
+
owner_id=list_dict.get("owner_id", ""),
|
|
334
|
+
limit=list_dict.get("limit", 0),
|
|
335
|
+
offset=list_dict.get("offset", 0),
|
|
336
|
+
)
|
|
337
|
+
response = self.exec_grpc_query("ListSetups", request)
|
|
338
|
+
return {
|
|
339
|
+
"setups": [
|
|
340
|
+
json_format.MessageToDict(setup, preserving_proto_field_name=True) for setup in response.setups
|
|
341
|
+
],
|
|
342
|
+
"total_count": response.total_count,
|
|
343
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""This module implements the default storage strategy."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from agentic_mesh_protocol.storage.v1 import data_pb2, storage_service_pb2_grpc
|
|
4
4
|
from google.protobuf import json_format
|
|
5
5
|
from google.protobuf.struct_pb2 import Struct
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
8
|
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
9
|
-
from digitalkin.grpc_servers.utils.models import ClientConfig
|
|
10
9
|
from digitalkin.logger import logger
|
|
10
|
+
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
11
11
|
from digitalkin.services.storage.storage_strategy import (
|
|
12
12
|
DataType,
|
|
13
13
|
StorageRecord,
|
|
@@ -128,7 +128,7 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
|
|
|
128
128
|
resp = self.exec_grpc_query("UpdateRecord", req)
|
|
129
129
|
return self._build_record_from_proto(resp.stored_data)
|
|
130
130
|
except Exception:
|
|
131
|
-
logger.
|
|
131
|
+
logger.warning("gRPC UpdateRecord failed for %s:%s", collection, record_id)
|
|
132
132
|
return None
|
|
133
133
|
|
|
134
134
|
def _remove(self, collection: str, record_id: str) -> bool:
|
|
@@ -211,4 +211,4 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
|
|
|
211
211
|
|
|
212
212
|
channel = self._init_channel(client_config)
|
|
213
213
|
self.stub = storage_service_pb2_grpc.StorageServiceStub(channel)
|
|
214
|
-
logger.debug("Channel client 'storage' initialized
|
|
214
|
+
logger.debug("Channel client 'storage' initialized successfully")
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""UserProfile service package."""
|
|
2
|
+
|
|
3
|
+
from digitalkin.services.user_profile.default_user_profile import DefaultUserProfile
|
|
4
|
+
from digitalkin.services.user_profile.grpc_user_profile import GrpcUserProfile
|
|
5
|
+
from digitalkin.services.user_profile.user_profile_strategy import UserProfileServiceError, UserProfileStrategy
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"DefaultUserProfile",
|
|
9
|
+
"GrpcUserProfile",
|
|
10
|
+
"UserProfileServiceError",
|
|
11
|
+
"UserProfileStrategy",
|
|
12
|
+
]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Default user profile implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from digitalkin.logger import logger
|
|
6
|
+
from digitalkin.services.user_profile.user_profile_strategy import (
|
|
7
|
+
UserProfileServiceError,
|
|
8
|
+
UserProfileStrategy,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DefaultUserProfile(UserProfileStrategy):
|
|
13
|
+
"""Default user profile strategy with in-memory storage."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
mission_id: str,
|
|
18
|
+
setup_id: str,
|
|
19
|
+
setup_version_id: str,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Initialize the strategy.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
mission_id: The ID of the mission this strategy is associated with
|
|
25
|
+
setup_id: The ID of the setup
|
|
26
|
+
setup_version_id: The ID of the setup version
|
|
27
|
+
"""
|
|
28
|
+
super().__init__(mission_id=mission_id, setup_id=setup_id, setup_version_id=setup_version_id)
|
|
29
|
+
self.db: dict[str, dict[str, Any]] = {}
|
|
30
|
+
|
|
31
|
+
def get_user_profile(self) -> dict[str, Any]:
|
|
32
|
+
"""Get user profile from in-memory storage.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
dict[str, Any]: User profile data
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
UserProfileServiceError: If the user profile is not found
|
|
39
|
+
"""
|
|
40
|
+
if self.mission_id not in self.db:
|
|
41
|
+
msg = f"User profile for mission {self.mission_id} not found in the database."
|
|
42
|
+
logger.warning(msg)
|
|
43
|
+
raise UserProfileServiceError(msg)
|
|
44
|
+
|
|
45
|
+
logger.debug(f"Retrieved user profile for mission_id: {self.mission_id}")
|
|
46
|
+
return self.db[self.mission_id]
|
|
47
|
+
|
|
48
|
+
def add_user_profile(self, user_profile_data: dict[str, Any]) -> None:
|
|
49
|
+
"""Add a user profile to the in-memory database (helper for testing).
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
user_profile_data: Dictionary containing user profile data
|
|
53
|
+
"""
|
|
54
|
+
self.db[self.mission_id] = user_profile_data
|
|
55
|
+
logger.debug(f"Added user profile for mission_id: {self.mission_id}")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Digital Kin UserProfile Service gRPC Client."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from agentic_mesh_protocol.user_profile.v1 import (
|
|
6
|
+
user_profile_pb2,
|
|
7
|
+
user_profile_service_pb2_grpc,
|
|
8
|
+
)
|
|
9
|
+
from google.protobuf import json_format
|
|
10
|
+
|
|
11
|
+
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
12
|
+
from digitalkin.grpc_servers.utils.grpc_error_handler import GrpcErrorHandlerMixin
|
|
13
|
+
from digitalkin.logger import logger
|
|
14
|
+
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
15
|
+
from digitalkin.services.user_profile.user_profile_strategy import UserProfileServiceError, UserProfileStrategy
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GrpcUserProfile(UserProfileStrategy, GrpcClientWrapper, GrpcErrorHandlerMixin):
|
|
19
|
+
"""This class implements the gRPC user profile service."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
mission_id: str,
|
|
24
|
+
setup_id: str,
|
|
25
|
+
setup_version_id: str,
|
|
26
|
+
client_config: ClientConfig,
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Initialize the user profile service.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
mission_id: The ID of the mission this strategy is associated with
|
|
32
|
+
setup_id: The ID of the setup
|
|
33
|
+
setup_version_id: The ID of the setup version
|
|
34
|
+
client_config: Client configuration for gRPC connection
|
|
35
|
+
"""
|
|
36
|
+
super().__init__(mission_id=mission_id, setup_id=setup_id, setup_version_id=setup_version_id)
|
|
37
|
+
channel = self._init_channel(client_config)
|
|
38
|
+
self.stub = user_profile_service_pb2_grpc.UserProfileServiceStub(channel)
|
|
39
|
+
logger.debug("Channel client 'UserProfile' initialized successfully")
|
|
40
|
+
|
|
41
|
+
def get_user_profile(self) -> dict[str, Any]:
|
|
42
|
+
"""Get user profile by mission_id (which maps to user_id).
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
dict[str, Any]: User profile data
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
UserProfileServiceError: If the user profile cannot be retrieved
|
|
49
|
+
ServerError: If gRPC operation fails
|
|
50
|
+
"""
|
|
51
|
+
with self.handle_grpc_errors("GetUserProfile", UserProfileServiceError):
|
|
52
|
+
# mission_id typically contains user context
|
|
53
|
+
request = user_profile_pb2.GetUserProfileRequest(mission_id=self.mission_id)
|
|
54
|
+
response = self.exec_grpc_query("GetUserProfile", request)
|
|
55
|
+
|
|
56
|
+
if not response.success:
|
|
57
|
+
msg = f"Failed to get user profile for mission_id: {self.mission_id}"
|
|
58
|
+
logger.error(msg)
|
|
59
|
+
raise UserProfileServiceError(msg)
|
|
60
|
+
|
|
61
|
+
# Convert proto to dict
|
|
62
|
+
user_profile_dict = json_format.MessageToDict(
|
|
63
|
+
response.user_profile,
|
|
64
|
+
preserving_proto_field_name=True,
|
|
65
|
+
always_print_fields_with_no_presence=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
logger.debug(f"Retrieved user profile for mission_id: {self.mission_id}")
|
|
69
|
+
return user_profile_dict
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""This module contains the abstract base class for UserProfile strategies."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from digitalkin.services.base_strategy import BaseStrategy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UserProfileServiceError(Exception):
|
|
10
|
+
"""Base exception for UserProfile service errors."""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UserProfileStrategy(BaseStrategy, ABC):
|
|
14
|
+
"""Abstract base class for UserProfile strategies."""
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def get_user_profile(self) -> dict[str, Any]:
|
|
18
|
+
"""Get user profile data.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
dict[str, Any]: User profile data
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
UserProfileServiceError: If the user profile cannot be retrieved
|
|
25
|
+
"""
|
digitalkin/utils/__init__.py
CHANGED
|
@@ -1 +1,29 @@
|
|
|
1
1
|
"""General utils folder."""
|
|
2
|
+
|
|
3
|
+
from digitalkin.utils.dynamic_schema import (
|
|
4
|
+
DEFAULT_TIMEOUT,
|
|
5
|
+
DynamicField,
|
|
6
|
+
Fetcher,
|
|
7
|
+
ResolveResult,
|
|
8
|
+
get_dynamic_metadata,
|
|
9
|
+
get_fetchers,
|
|
10
|
+
has_dynamic,
|
|
11
|
+
resolve,
|
|
12
|
+
resolve_safe,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# Alias for cleaner API: `Dynamic` is shorter than `DynamicField`
|
|
16
|
+
Dynamic = DynamicField
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"DEFAULT_TIMEOUT",
|
|
20
|
+
"Dynamic",
|
|
21
|
+
"DynamicField",
|
|
22
|
+
"Fetcher",
|
|
23
|
+
"ResolveResult",
|
|
24
|
+
"get_dynamic_metadata",
|
|
25
|
+
"get_fetchers",
|
|
26
|
+
"has_dynamic",
|
|
27
|
+
"resolve",
|
|
28
|
+
"resolve_safe",
|
|
29
|
+
]
|
digitalkin/utils/arg_parser.py
CHANGED
|
@@ -13,7 +13,7 @@ logger.setLevel(logging.INFO)
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class DevelopmentModeMappingAction(Action):
|
|
16
|
-
"""."""
|
|
16
|
+
"""ArgParse Action to map an environment variable to a ServicesMode enum."""
|
|
17
17
|
|
|
18
18
|
def __init__(
|
|
19
19
|
self,
|
|
@@ -22,7 +22,7 @@ class DevelopmentModeMappingAction(Action):
|
|
|
22
22
|
default: str | None = None,
|
|
23
23
|
**kwargs: dict[str, Any],
|
|
24
24
|
) -> None:
|
|
25
|
-
"""."""
|
|
25
|
+
"""Initialize the DevelopmentModeMappingAction."""
|
|
26
26
|
default = ServicesMode(os.environ.get(env_var, default))
|
|
27
27
|
|
|
28
28
|
if required and default:
|