digitalkin 0.3.2.dev2__tar.gz → 0.3.2.dev3__tar.gz
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.
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/PKG-INFO +1 -1
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/pyproject.toml +4 -4
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/__version__.py +1 -1
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/single_job_manager.py +14 -8
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/task_session.py +60 -98
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/module_servicer.py +31 -7
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/core/task_monitor.py +4 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/__init__.py +10 -2
- digitalkin-0.3.2.dev3/src/digitalkin/models/module/base_types.py +61 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/module_context.py +19 -1
- digitalkin-0.3.2.dev3/src/digitalkin/models/module/module_types.py +29 -0
- digitalkin-0.3.2.dev2/src/digitalkin/models/module/module_types.py → digitalkin-0.3.2.dev3/src/digitalkin/models/module/setup_types.py +131 -61
- digitalkin-0.3.2.dev3/src/digitalkin/models/module/tool_reference.py +105 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/utility.py +22 -1
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/_base_module.py +41 -3
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/__init__.py +0 -4
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/services_config.py +4 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -15
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/PKG-INFO +1 -1
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/SOURCES.txt +3 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/LICENSE +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/README.md +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/mock/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/mock/mock_pb2.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/server_async_insecure.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/server_async_secure.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/server_sync_insecure.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/base_server/server_sync_secure.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/modules/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/modules/cpu_intensive_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/modules/dynamic_setup_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/modules/minimal_llm_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/modules/text_transform_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/services/filesystem_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/examples/services/storage_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/setup.cfg +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/common/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/common/factories.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/taskiq_broker.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/taskiq_job_manager.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/surrealdb_repository.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/task_executor.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/_base_server.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/module_server.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/logger.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/base_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/callback_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/chat_history_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/cost_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/file_history_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/logger_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/storage_mixin.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/core/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/core/job_manager_models.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/grpc_servers/models.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/grpc_servers/types.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/services/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/services/cost.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/services/registry.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/services/storage.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/archetype_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/tool_module.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/trigger_handler.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/py.typed +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/agent/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/agent/agent_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/agent/default_agent.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/base_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/communication_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/default_communication.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/grpc_communication.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/cost_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/default_cost.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/grpc_cost.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/identity/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/identity/default_identity.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/identity/identity_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/default_registry.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/exceptions.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/grpc_registry.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/registry_models.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/registry_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/services_models.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/default_setup.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/grpc_setup.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/setup_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/snapshot/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/default_storage.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/grpc_storage.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/storage_strategy.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/__init__.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/arg_parser.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/development_mode_action.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/dynamic_schema.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/llm_ready_schema.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/package_discover.py +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/dependency_links.txt +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/requires.txt +0 -0
- {digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/top_level.txt +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
keywords = [ "digitalkin", "kin", "agent", "gprc", "sdk" ]
|
|
14
14
|
|
|
15
|
-
version = "0.3.2.
|
|
15
|
+
version = "0.3.2.dev3"
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Development Status :: 3 - Alpha",
|
|
18
18
|
"Intended Audience :: Developers",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
[dependency-groups]
|
|
57
57
|
dev = [
|
|
58
58
|
"typos>=1.40.0",
|
|
59
|
-
"ruff>=0.14.
|
|
60
|
-
"mypy>=1.19.
|
|
59
|
+
"ruff>=0.14.9",
|
|
60
|
+
"mypy>=1.19.1",
|
|
61
61
|
"pyright>=1.1.407",
|
|
62
62
|
"pre-commit>=4.5.0",
|
|
63
|
-
"bump-my-version>=1.2.
|
|
63
|
+
"bump-my-version>=1.2.5",
|
|
64
64
|
"build>=1.3.0",
|
|
65
65
|
"twine>=6.2.0",
|
|
66
66
|
"cryptography>=46.0.3",
|
|
@@ -15,8 +15,8 @@ from digitalkin.core.task_manager.local_task_manager import LocalTaskManager
|
|
|
15
15
|
from digitalkin.core.task_manager.task_session import TaskSession
|
|
16
16
|
from digitalkin.logger import logger
|
|
17
17
|
from digitalkin.models.core.task_monitor import TaskStatus
|
|
18
|
+
from digitalkin.models.module.base_types import InputModelT, OutputModelT, SetupModelT
|
|
18
19
|
from digitalkin.models.module.module import ModuleCodeModel
|
|
19
|
-
from digitalkin.models.module.module_types import InputModelT, OutputModelT, SetupModelT
|
|
20
20
|
from digitalkin.modules._base_module import BaseModule
|
|
21
21
|
from digitalkin.services.services_models import ServicesMode
|
|
22
22
|
|
|
@@ -86,7 +86,10 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
|
|
|
86
86
|
message=f"Module {job_id} did not respond within 30 seconds",
|
|
87
87
|
)
|
|
88
88
|
finally:
|
|
89
|
-
logger.
|
|
89
|
+
logger.debug(
|
|
90
|
+
"Config setup response retrieved",
|
|
91
|
+
extra={"job_id": job_id, "queue_empty": session.queue.empty()},
|
|
92
|
+
)
|
|
90
93
|
|
|
91
94
|
async def create_config_setup_instance_job(
|
|
92
95
|
self,
|
|
@@ -126,7 +129,7 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
|
|
|
126
129
|
except Exception:
|
|
127
130
|
# Remove the module from the manager in case of an error.
|
|
128
131
|
del self.tasks_sessions[job_id]
|
|
129
|
-
logger.exception("Failed to start module
|
|
132
|
+
logger.exception("Failed to start module", extra={"job_id": job_id})
|
|
130
133
|
raise
|
|
131
134
|
else:
|
|
132
135
|
return job_id
|
|
@@ -271,20 +274,23 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
|
|
|
271
274
|
Raises:
|
|
272
275
|
Exception: If an error occurs while stopping the module.
|
|
273
276
|
"""
|
|
274
|
-
logger.info(
|
|
277
|
+
logger.info("Stop module requested", extra={"job_id": job_id})
|
|
275
278
|
|
|
276
279
|
async with self._lock:
|
|
277
280
|
session = self.tasks_sessions.get(job_id)
|
|
278
281
|
|
|
279
282
|
if not session:
|
|
280
|
-
logger.warning(
|
|
283
|
+
logger.warning("Session not found", extra={"job_id": job_id})
|
|
281
284
|
return False
|
|
282
285
|
try:
|
|
283
286
|
await session.module.stop()
|
|
284
287
|
await self.cancel_task(job_id, session.mission_id)
|
|
285
|
-
logger.debug(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
+
logger.debug(
|
|
289
|
+
"Module stopped successfully",
|
|
290
|
+
extra={"job_id": job_id, "mission_id": session.mission_id, "module_name": session.module.name},
|
|
291
|
+
)
|
|
292
|
+
except Exception:
|
|
293
|
+
logger.exception("Error stopping module", extra={"job_id": job_id})
|
|
288
294
|
raise
|
|
289
295
|
else:
|
|
290
296
|
return True
|
{digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/task_session.py
RENAMED
|
@@ -84,9 +84,12 @@ class TaskSession:
|
|
|
84
84
|
self._heartbeat_interval = heartbeat_interval
|
|
85
85
|
|
|
86
86
|
logger.info(
|
|
87
|
-
"
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
"TaskSession initialized",
|
|
88
|
+
extra={
|
|
89
|
+
"task_id": task_id,
|
|
90
|
+
"mission_id": mission_id,
|
|
91
|
+
"heartbeat_interval": str(heartbeat_interval),
|
|
92
|
+
},
|
|
90
93
|
)
|
|
91
94
|
|
|
92
95
|
@property
|
|
@@ -99,6 +102,21 @@ class TaskSession:
|
|
|
99
102
|
"""Task paused status."""
|
|
100
103
|
return self._paused.is_set()
|
|
101
104
|
|
|
105
|
+
@property
|
|
106
|
+
def setup_id(self) -> str:
|
|
107
|
+
"""Get setup_id from module context."""
|
|
108
|
+
return self.module.context.session.setup_id
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def setup_version_id(self) -> str:
|
|
112
|
+
"""Get setup_version_id from module context."""
|
|
113
|
+
return self.module.context.session.setup_version_id
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def session_ids(self) -> dict[str, str]:
|
|
117
|
+
"""Get all session IDs from module context for structured logging."""
|
|
118
|
+
return self.module.context.session.current_ids()
|
|
119
|
+
|
|
102
120
|
async def send_heartbeat(self) -> bool:
|
|
103
121
|
"""Rate-limited heartbeat with connection resilience.
|
|
104
122
|
|
|
@@ -108,6 +126,8 @@ class TaskSession:
|
|
|
108
126
|
heartbeat = HeartbeatMessage(
|
|
109
127
|
task_id=self.task_id,
|
|
110
128
|
mission_id=self.mission_id,
|
|
129
|
+
setup_id=self.setup_id,
|
|
130
|
+
setup_version_id=self.setup_version_id,
|
|
111
131
|
timestamp=datetime.datetime.now(datetime.timezone.utc),
|
|
112
132
|
)
|
|
113
133
|
|
|
@@ -120,23 +140,17 @@ class TaskSession:
|
|
|
120
140
|
return True
|
|
121
141
|
except Exception as e:
|
|
122
142
|
logger.error(
|
|
123
|
-
"Heartbeat exception
|
|
124
|
-
self.
|
|
125
|
-
extra={"task_id": self.task_id, "error": str(e)},
|
|
143
|
+
"Heartbeat exception",
|
|
144
|
+
extra={**self.session_ids, "error": str(e)},
|
|
126
145
|
exc_info=True,
|
|
127
146
|
)
|
|
128
|
-
logger.error(
|
|
129
|
-
"Initial heartbeat failed for task: '%s'",
|
|
130
|
-
self.task_id,
|
|
131
|
-
extra={"task_id": self.task_id},
|
|
132
|
-
)
|
|
147
|
+
logger.error("Initial heartbeat failed", extra=self.session_ids)
|
|
133
148
|
return False
|
|
134
149
|
|
|
135
150
|
if (heartbeat.timestamp - self._last_heartbeat) < self._heartbeat_interval:
|
|
136
151
|
logger.debug(
|
|
137
|
-
"Heartbeat skipped due to rate limiting
|
|
138
|
-
self.
|
|
139
|
-
heartbeat.timestamp - self._last_heartbeat,
|
|
152
|
+
"Heartbeat skipped due to rate limiting",
|
|
153
|
+
extra={**self.session_ids, "delta": str(heartbeat.timestamp - self._last_heartbeat)},
|
|
140
154
|
)
|
|
141
155
|
return True
|
|
142
156
|
|
|
@@ -147,39 +161,24 @@ class TaskSession:
|
|
|
147
161
|
return True
|
|
148
162
|
except Exception as e:
|
|
149
163
|
logger.error(
|
|
150
|
-
"Heartbeat exception
|
|
151
|
-
self.
|
|
152
|
-
extra={"task_id": self.task_id, "error": str(e)},
|
|
164
|
+
"Heartbeat exception",
|
|
165
|
+
extra={**self.session_ids, "error": str(e)},
|
|
153
166
|
exc_info=True,
|
|
154
167
|
)
|
|
155
|
-
logger.warning(
|
|
156
|
-
"Heartbeat failed for task: '%s'",
|
|
157
|
-
self.task_id,
|
|
158
|
-
extra={"task_id": self.task_id},
|
|
159
|
-
)
|
|
168
|
+
logger.warning("Heartbeat failed", extra=self.session_ids)
|
|
160
169
|
return False
|
|
161
170
|
|
|
162
171
|
async def generate_heartbeats(self) -> None:
|
|
163
172
|
"""Periodic heartbeat generator with cancellation support."""
|
|
164
|
-
logger.debug(
|
|
165
|
-
"Heartbeat generator started for task: '%s'",
|
|
166
|
-
self.task_id,
|
|
167
|
-
extra={"task_id": self.task_id, "mission_id": self.mission_id},
|
|
168
|
-
)
|
|
173
|
+
logger.debug("Heartbeat generator started", extra=self.session_ids)
|
|
169
174
|
while not self.cancelled:
|
|
170
175
|
logger.debug(
|
|
171
|
-
"Heartbeat tick
|
|
172
|
-
self.
|
|
173
|
-
self.cancelled,
|
|
174
|
-
extra={"task_id": self.task_id, "mission_id": self.mission_id},
|
|
176
|
+
"Heartbeat tick",
|
|
177
|
+
extra={**self.session_ids, "cancelled": self.cancelled},
|
|
175
178
|
)
|
|
176
179
|
success = await self.send_heartbeat()
|
|
177
180
|
if not success:
|
|
178
|
-
logger.error(
|
|
179
|
-
"Heartbeat failed, cancelling task: '%s'",
|
|
180
|
-
self.task_id,
|
|
181
|
-
extra={"task_id": self.task_id, "mission_id": self.mission_id},
|
|
182
|
-
)
|
|
181
|
+
logger.error("Heartbeat failed, cancelling task", extra=self.session_ids)
|
|
183
182
|
await self._handle_cancel(CancellationReason.HEARTBEAT_FAILURE)
|
|
184
183
|
break
|
|
185
184
|
await asyncio.sleep(self._heartbeat_interval.total_seconds())
|
|
@@ -187,11 +186,7 @@ class TaskSession:
|
|
|
187
186
|
async def wait_if_paused(self) -> None:
|
|
188
187
|
"""Block execution if task is paused."""
|
|
189
188
|
if self._paused.is_set():
|
|
190
|
-
logger.info(
|
|
191
|
-
"Task paused, waiting for resume: '%s'",
|
|
192
|
-
self.task_id,
|
|
193
|
-
extra={"task_id": self.task_id},
|
|
194
|
-
)
|
|
189
|
+
logger.info("Task paused, waiting for resume", extra=self.session_ids)
|
|
195
190
|
await self._paused.wait()
|
|
196
191
|
|
|
197
192
|
async def listen_signals(self) -> None: # noqa: C901
|
|
@@ -200,18 +195,14 @@ class TaskSession:
|
|
|
200
195
|
Raises:
|
|
201
196
|
CancelledError: Asyncio when task cancelling
|
|
202
197
|
"""
|
|
203
|
-
logger.info(
|
|
204
|
-
"Signal listener started for task: '%s'",
|
|
205
|
-
self.task_id,
|
|
206
|
-
extra={"task_id": self.task_id},
|
|
207
|
-
)
|
|
198
|
+
logger.info("Signal listener started", extra=self.session_ids)
|
|
208
199
|
if self.signal_record_id is None:
|
|
209
200
|
self.signal_record_id = (await self.db.select_by_task_id("tasks", self.task_id)).get("id")
|
|
210
201
|
|
|
211
202
|
live_id, live_signals = await self.db.start_live("tasks")
|
|
212
203
|
try:
|
|
213
204
|
async for signal in live_signals:
|
|
214
|
-
logger.debug("Signal received
|
|
205
|
+
logger.debug("Signal received", extra={**self.session_ids, "signal": signal})
|
|
215
206
|
if self.cancelled:
|
|
216
207
|
break
|
|
217
208
|
|
|
@@ -228,26 +219,17 @@ class TaskSession:
|
|
|
228
219
|
await self._handle_status_request()
|
|
229
220
|
|
|
230
221
|
except asyncio.CancelledError:
|
|
231
|
-
logger.debug(
|
|
232
|
-
"Signal listener cancelled for task: '%s'",
|
|
233
|
-
self.task_id,
|
|
234
|
-
extra={"task_id": self.task_id},
|
|
235
|
-
)
|
|
222
|
+
logger.debug("Signal listener cancelled", extra=self.session_ids)
|
|
236
223
|
raise
|
|
237
224
|
except Exception as e:
|
|
238
225
|
logger.error(
|
|
239
|
-
"Signal listener fatal error
|
|
240
|
-
self.
|
|
241
|
-
extra={"task_id": self.task_id, "error": str(e)},
|
|
226
|
+
"Signal listener fatal error",
|
|
227
|
+
extra={**self.session_ids, "error": str(e)},
|
|
242
228
|
exc_info=True,
|
|
243
229
|
)
|
|
244
230
|
finally:
|
|
245
231
|
await self.db.stop_live(live_id)
|
|
246
|
-
logger.info(
|
|
247
|
-
"Signal listener stopped for task: '%s'",
|
|
248
|
-
self.task_id,
|
|
249
|
-
extra={"task_id": self.task_id},
|
|
250
|
-
)
|
|
232
|
+
logger.info("Signal listener stopped", extra=self.session_ids)
|
|
251
233
|
|
|
252
234
|
async def _handle_cancel(self, reason: CancellationReason = CancellationReason.UNKNOWN) -> None:
|
|
253
235
|
"""Idempotent cancellation with acknowledgment and reason tracking.
|
|
@@ -257,13 +239,9 @@ class TaskSession:
|
|
|
257
239
|
"""
|
|
258
240
|
if self.is_cancelled.is_set():
|
|
259
241
|
logger.debug(
|
|
260
|
-
"Cancel ignored -
|
|
261
|
-
self.task_id,
|
|
262
|
-
self.cancellation_reason.value,
|
|
263
|
-
reason.value,
|
|
242
|
+
"Cancel ignored - already cancelled",
|
|
264
243
|
extra={
|
|
265
|
-
|
|
266
|
-
"mission_id": self.mission_id,
|
|
244
|
+
**self.session_ids,
|
|
267
245
|
"existing_reason": self.cancellation_reason.value,
|
|
268
246
|
"new_reason": reason.value,
|
|
269
247
|
},
|
|
@@ -277,25 +255,13 @@ class TaskSession:
|
|
|
277
255
|
# Log with appropriate level based on reason
|
|
278
256
|
if reason in {CancellationReason.SUCCESS_CLEANUP, CancellationReason.FAILURE_CLEANUP}:
|
|
279
257
|
logger.debug(
|
|
280
|
-
"Task cancelled (cleanup)
|
|
281
|
-
self.
|
|
282
|
-
reason.value,
|
|
283
|
-
extra={
|
|
284
|
-
"task_id": self.task_id,
|
|
285
|
-
"mission_id": self.mission_id,
|
|
286
|
-
"cancellation_reason": reason.value,
|
|
287
|
-
},
|
|
258
|
+
"Task cancelled (cleanup)",
|
|
259
|
+
extra={**self.session_ids, "cancellation_reason": reason.value},
|
|
288
260
|
)
|
|
289
261
|
else:
|
|
290
262
|
logger.info(
|
|
291
|
-
"Task cancelled
|
|
292
|
-
self.
|
|
293
|
-
reason.value,
|
|
294
|
-
extra={
|
|
295
|
-
"task_id": self.task_id,
|
|
296
|
-
"mission_id": self.mission_id,
|
|
297
|
-
"cancellation_reason": reason.value,
|
|
298
|
-
},
|
|
263
|
+
"Task cancelled",
|
|
264
|
+
extra={**self.session_ids, "cancellation_reason": reason.value},
|
|
299
265
|
)
|
|
300
266
|
|
|
301
267
|
# Resume if paused so cancellation can proceed
|
|
@@ -308,6 +274,8 @@ class TaskSession:
|
|
|
308
274
|
SignalMessage(
|
|
309
275
|
task_id=self.task_id,
|
|
310
276
|
mission_id=self.mission_id,
|
|
277
|
+
setup_id=self.setup_id,
|
|
278
|
+
setup_version_id=self.setup_version_id,
|
|
311
279
|
action=SignalType.ACK_CANCEL,
|
|
312
280
|
status=self.status,
|
|
313
281
|
).model_dump(),
|
|
@@ -316,11 +284,7 @@ class TaskSession:
|
|
|
316
284
|
async def _handle_pause(self) -> None:
|
|
317
285
|
"""Pause task execution."""
|
|
318
286
|
if not self._paused.is_set():
|
|
319
|
-
logger.info(
|
|
320
|
-
"Pausing task: '%s'",
|
|
321
|
-
self.task_id,
|
|
322
|
-
extra={"task_id": self.task_id},
|
|
323
|
-
)
|
|
287
|
+
logger.info("Task paused", extra=self.session_ids)
|
|
324
288
|
self._paused.set()
|
|
325
289
|
|
|
326
290
|
await self.db.update(
|
|
@@ -329,6 +293,8 @@ class TaskSession:
|
|
|
329
293
|
SignalMessage(
|
|
330
294
|
task_id=self.task_id,
|
|
331
295
|
mission_id=self.mission_id,
|
|
296
|
+
setup_id=self.setup_id,
|
|
297
|
+
setup_version_id=self.setup_version_id,
|
|
332
298
|
action=SignalType.ACK_PAUSE,
|
|
333
299
|
status=self.status,
|
|
334
300
|
).model_dump(),
|
|
@@ -337,11 +303,7 @@ class TaskSession:
|
|
|
337
303
|
async def _handle_resume(self) -> None:
|
|
338
304
|
"""Resume paused task."""
|
|
339
305
|
if self._paused.is_set():
|
|
340
|
-
logger.info(
|
|
341
|
-
"Resuming task: '%s'",
|
|
342
|
-
self.task_id,
|
|
343
|
-
extra={"task_id": self.task_id},
|
|
344
|
-
)
|
|
306
|
+
logger.info("Task resumed", extra=self.session_ids)
|
|
345
307
|
self._paused.clear()
|
|
346
308
|
|
|
347
309
|
await self.db.update(
|
|
@@ -350,6 +312,8 @@ class TaskSession:
|
|
|
350
312
|
SignalMessage(
|
|
351
313
|
task_id=self.task_id,
|
|
352
314
|
mission_id=self.mission_id,
|
|
315
|
+
setup_id=self.setup_id,
|
|
316
|
+
setup_version_id=self.setup_version_id,
|
|
353
317
|
action=SignalType.ACK_RESUME,
|
|
354
318
|
status=self.status,
|
|
355
319
|
).model_dump(),
|
|
@@ -361,18 +325,16 @@ class TaskSession:
|
|
|
361
325
|
"tasks",
|
|
362
326
|
self.signal_record_id, # type: ignore
|
|
363
327
|
SignalMessage(
|
|
364
|
-
mission_id=self.mission_id,
|
|
365
328
|
task_id=self.task_id,
|
|
329
|
+
mission_id=self.mission_id,
|
|
330
|
+
setup_id=self.setup_id,
|
|
331
|
+
setup_version_id=self.setup_version_id,
|
|
366
332
|
status=self.status,
|
|
367
333
|
action=SignalType.ACK_STATUS,
|
|
368
334
|
).model_dump(),
|
|
369
335
|
)
|
|
370
336
|
|
|
371
|
-
logger.debug(
|
|
372
|
-
"Status report sent for task: '%s'",
|
|
373
|
-
self.task_id,
|
|
374
|
-
extra={"task_id": self.task_id},
|
|
375
|
-
)
|
|
337
|
+
logger.debug("Status report sent", extra=self.session_ids)
|
|
376
338
|
|
|
377
339
|
async def cleanup(self) -> None:
|
|
378
340
|
"""Clean up task session resources.
|
{digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/module_servicer.py
RENAMED
|
@@ -19,6 +19,7 @@ from digitalkin.logger import logger
|
|
|
19
19
|
from digitalkin.models.core.job_manager_models import JobManagerMode
|
|
20
20
|
from digitalkin.models.module.module import ModuleStatus
|
|
21
21
|
from digitalkin.modules._base_module import BaseModule
|
|
22
|
+
from digitalkin.services.registry import GrpcRegistry, RegistryStrategy
|
|
22
23
|
from digitalkin.services.services_models import ServicesMode
|
|
23
24
|
from digitalkin.services.setup.default_setup import DefaultSetup
|
|
24
25
|
from digitalkin.services.setup.grpc_setup import GrpcSetup
|
|
@@ -82,6 +83,22 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
|
|
|
82
83
|
)
|
|
83
84
|
self.setup = GrpcSetup() if self.args.services_mode == ServicesMode.REMOTE else DefaultSetup()
|
|
84
85
|
|
|
86
|
+
def _get_registry(self) -> RegistryStrategy | None:
|
|
87
|
+
"""Get a registry instance if configured.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
GrpcRegistry instance if registry config exists, None otherwise.
|
|
91
|
+
"""
|
|
92
|
+
registry_config = self.module_class.services_config_params.get("registry")
|
|
93
|
+
if not registry_config:
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
client_config = registry_config.get("client_config")
|
|
97
|
+
if not client_config:
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
return GrpcRegistry("", "", "", client_config)
|
|
101
|
+
|
|
85
102
|
async def ConfigSetupModule( # noqa: N802
|
|
86
103
|
self,
|
|
87
104
|
request: lifecycle_pb2.ConfigSetupModuleRequest,
|
|
@@ -125,6 +142,11 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
|
|
|
125
142
|
msg = "No config setup data returned."
|
|
126
143
|
raise ServicerError(msg)
|
|
127
144
|
|
|
145
|
+
# Resolve tool references in config_setup_data if registry is configured
|
|
146
|
+
registry = self._get_registry()
|
|
147
|
+
if registry:
|
|
148
|
+
config_setup_data.resolve_tool_references(registry)
|
|
149
|
+
|
|
128
150
|
# create a task to run the module in background
|
|
129
151
|
job_id = await self.job_manager.create_config_setup_instance_job(
|
|
130
152
|
config_setup_data,
|
|
@@ -139,8 +161,8 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
|
|
|
139
161
|
return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
|
|
140
162
|
|
|
141
163
|
updated_setup_data = await self.job_manager.generate_config_setup_module_response(job_id)
|
|
142
|
-
logger.info("Setup updated")
|
|
143
|
-
logger.debug(
|
|
164
|
+
logger.info("Setup updated", extra={"job_id": job_id})
|
|
165
|
+
logger.debug("Updated setup data", extra={"job_id": job_id, "setup_data": updated_setup_data})
|
|
144
166
|
setup_version.content = json_format.ParseDict(
|
|
145
167
|
updated_setup_data,
|
|
146
168
|
struct_pb2.Struct(),
|
|
@@ -249,17 +271,19 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
|
|
|
249
271
|
Returns:
|
|
250
272
|
A response indicating success or failure.
|
|
251
273
|
"""
|
|
252
|
-
logger.debug(
|
|
274
|
+
logger.debug(
|
|
275
|
+
"StopModule called",
|
|
276
|
+
extra={"module_class": self.module_class.__name__, "job_id": request.job_id},
|
|
277
|
+
)
|
|
253
278
|
|
|
254
279
|
response: bool = await self.job_manager.stop_module(request.job_id)
|
|
255
280
|
if not response:
|
|
256
|
-
|
|
257
|
-
logger.warning(message)
|
|
281
|
+
logger.warning("Job not found for stop request", extra={"job_id": request.job_id})
|
|
258
282
|
context.set_code(grpc.StatusCode.NOT_FOUND)
|
|
259
|
-
context.set_details(
|
|
283
|
+
context.set_details(f"Job {request.job_id} not found")
|
|
260
284
|
return lifecycle_pb2.StopModuleResponse(success=False)
|
|
261
285
|
|
|
262
|
-
logger.debug("Job
|
|
286
|
+
logger.debug("Job stopped successfully", extra={"job_id": request.job_id})
|
|
263
287
|
return lifecycle_pb2.StopModuleResponse(success=True)
|
|
264
288
|
|
|
265
289
|
async def GetModuleStatus( # noqa: N802
|
|
@@ -55,6 +55,8 @@ class SignalMessage(BaseModel):
|
|
|
55
55
|
|
|
56
56
|
task_id: str = Field(..., description="Unique identifier for the task")
|
|
57
57
|
mission_id: str = Field(..., description="Identifier for the mission")
|
|
58
|
+
setup_id: str = Field(default="", description="Identifier for the setup")
|
|
59
|
+
setup_version_id: str = Field(default="", description="Identifier for the setup version")
|
|
58
60
|
status: TaskStatus = Field(..., description="Current status of the task")
|
|
59
61
|
action: SignalType = Field(..., description="Type of signal action")
|
|
60
62
|
timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
@@ -67,4 +69,6 @@ class HeartbeatMessage(BaseModel):
|
|
|
67
69
|
|
|
68
70
|
task_id: str = Field(..., description="Unique identifier for the task")
|
|
69
71
|
mission_id: str = Field(..., description="Identifier for the mission")
|
|
72
|
+
setup_id: str = Field(default="", description="Identifier for the setup")
|
|
73
|
+
setup_version_id: str = Field(default="", description="Identifier for the setup version")
|
|
70
74
|
timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
@@ -6,20 +6,28 @@ from digitalkin.models.module.module_types import (
|
|
|
6
6
|
DataTrigger,
|
|
7
7
|
SetupModel,
|
|
8
8
|
)
|
|
9
|
+
from digitalkin.models.module.tool_reference import (
|
|
10
|
+
ToolReference,
|
|
11
|
+
ToolReferenceConfig,
|
|
12
|
+
ToolSelectionMode,
|
|
13
|
+
)
|
|
9
14
|
from digitalkin.models.module.utility import (
|
|
10
15
|
EndOfStreamOutput,
|
|
16
|
+
ModuleStartInfoOutput,
|
|
11
17
|
UtilityProtocol,
|
|
12
18
|
UtilityRegistry,
|
|
13
19
|
)
|
|
14
20
|
|
|
15
21
|
__all__ = [
|
|
16
|
-
# Core types (used by all SDK users)
|
|
17
22
|
"DataModel",
|
|
18
23
|
"DataTrigger",
|
|
19
|
-
# Utility (commonly used)
|
|
20
24
|
"EndOfStreamOutput",
|
|
21
25
|
"ModuleContext",
|
|
26
|
+
"ModuleStartInfoOutput",
|
|
22
27
|
"SetupModel",
|
|
28
|
+
"ToolReference",
|
|
29
|
+
"ToolReferenceConfig",
|
|
30
|
+
"ToolSelectionMode",
|
|
23
31
|
"UtilityProtocol",
|
|
24
32
|
"UtilityRegistry",
|
|
25
33
|
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Base types for module models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from typing import TYPE_CHECKING, ClassVar, Generic, TypeVar
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from digitalkin.models.module.setup_types import SetupModel
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DataTrigger(BaseModel):
|
|
15
|
+
"""Defines the root input/output model exposing the protocol.
|
|
16
|
+
|
|
17
|
+
The mandatory protocol is important to define the module beahvior following the user or agent input/output.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
class MyInput(DataModel):
|
|
21
|
+
root: DataTrigger
|
|
22
|
+
user_define_data: Any
|
|
23
|
+
|
|
24
|
+
# Usage
|
|
25
|
+
my_input = MyInput(root=DataTrigger(protocol="message"))
|
|
26
|
+
print(my_input.root.protocol) # Output: message
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
protocol: ClassVar[str]
|
|
30
|
+
created_at: str = Field(
|
|
31
|
+
default_factory=lambda: datetime.now(tz=timezone.utc).isoformat(),
|
|
32
|
+
title="Created At",
|
|
33
|
+
description="Timestamp when the payload was created.",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
DataTriggerT = TypeVar("DataTriggerT", bound=DataTrigger)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class DataModel(BaseModel, Generic[DataTriggerT]):
|
|
41
|
+
"""Base definition of input/output model showing mandatory root fields.
|
|
42
|
+
|
|
43
|
+
The Model define the Module Input/output, usually referring to multiple input/output type defined by an union.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
class ModuleInput(DataModel):
|
|
47
|
+
root: FileInput | MessageInput
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
root: DataTriggerT
|
|
51
|
+
annotations: dict[str, str] = Field(
|
|
52
|
+
default={},
|
|
53
|
+
title="Annotations",
|
|
54
|
+
description="Additional metadata or annotations related to the output. ex {'role': 'user'}",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
InputModelT = TypeVar("InputModelT", bound=DataModel)
|
|
59
|
+
OutputModelT = TypeVar("OutputModelT", bound=DataModel)
|
|
60
|
+
SecretModelT = TypeVar("SecretModelT", bound=BaseModel)
|
|
61
|
+
SetupModelT = TypeVar("SetupModelT", bound="SetupModel")
|
{digitalkin-0.3.2.dev2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/module_context.py
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import os
|
|
4
4
|
from datetime import tzinfo
|
|
5
5
|
from types import SimpleNamespace
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
7
|
from zoneinfo import ZoneInfo
|
|
8
8
|
|
|
9
9
|
from digitalkin.services.agent.agent_strategy import AgentStrategy
|
|
@@ -16,6 +16,9 @@ from digitalkin.services.snapshot.snapshot_strategy import SnapshotStrategy
|
|
|
16
16
|
from digitalkin.services.storage.storage_strategy import StorageStrategy
|
|
17
17
|
from digitalkin.services.user_profile.user_profile_strategy import UserProfileStrategy
|
|
18
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from digitalkin.models.services.registry import ModuleInfo
|
|
21
|
+
|
|
19
22
|
|
|
20
23
|
class Session(SimpleNamespace):
|
|
21
24
|
"""Session data container with mandatory setup_id and mission_id."""
|
|
@@ -98,6 +101,7 @@ class ModuleContext:
|
|
|
98
101
|
metadata: SimpleNamespace
|
|
99
102
|
helpers: SimpleNamespace
|
|
100
103
|
state: SimpleNamespace = SimpleNamespace()
|
|
104
|
+
tool_cache: dict[str, "ModuleInfo"]
|
|
101
105
|
|
|
102
106
|
def __init__( # noqa: PLR0913, PLR0917
|
|
103
107
|
self,
|
|
@@ -114,6 +118,7 @@ class ModuleContext:
|
|
|
114
118
|
metadata: dict[str, Any] = {},
|
|
115
119
|
helpers: dict[str, Any] = {},
|
|
116
120
|
callbacks: dict[str, Any] = {},
|
|
121
|
+
tool_cache: dict[str, "ModuleInfo"] | None = None,
|
|
117
122
|
) -> None:
|
|
118
123
|
"""Register mandatory services, session, metadata and callbacks.
|
|
119
124
|
|
|
@@ -131,6 +136,7 @@ class ModuleContext:
|
|
|
131
136
|
helpers: dict different user defined helpers.
|
|
132
137
|
session: dict referring the session IDs or informations.
|
|
133
138
|
callbacks: Functions allowing user to agent interaction.
|
|
139
|
+
tool_cache: Pre-resolved tool references from setup.
|
|
134
140
|
"""
|
|
135
141
|
# Core services
|
|
136
142
|
self.agent = agent
|
|
@@ -147,3 +153,15 @@ class ModuleContext:
|
|
|
147
153
|
self.session = Session(**session)
|
|
148
154
|
self.helpers = SimpleNamespace(**helpers)
|
|
149
155
|
self.callbacks = SimpleNamespace(**callbacks)
|
|
156
|
+
self.tool_cache = tool_cache or {}
|
|
157
|
+
|
|
158
|
+
def get_tool(self, field_name: str) -> "ModuleInfo | None":
|
|
159
|
+
"""Get resolved tool info by setup field name.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
field_name: The name of the ToolReference field in the setup model.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
ModuleInfo if found, None otherwise.
|
|
166
|
+
"""
|
|
167
|
+
return self.tool_cache.get(field_name)
|