digitalkin 0.2.15__tar.gz → 0.2.17__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.2.15 → digitalkin-0.2.17}/PKG-INFO +1 -1
- {digitalkin-0.2.15 → digitalkin-0.2.17}/pyproject.toml +2 -2
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/__version__.py +1 -1
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/module_server.py +6 -6
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/module_servicer.py +1 -0
- digitalkin-0.2.17/src/digitalkin/models/module/__init__.py +26 -0
- digitalkin-0.2.17/src/digitalkin/models/module/module_context.py +24 -0
- digitalkin-0.2.17/src/digitalkin/models/module/module_types.py +43 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/__init__.py +2 -2
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/_base_module.py +78 -8
- digitalkin-0.2.17/src/digitalkin/modules/trigger_handler.py +47 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/filesystem/default_filesystem.py +12 -2
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/filesystem/filesystem_strategy.py +37 -4
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/filesystem/grpc_filesystem.py +15 -6
- digitalkin-0.2.17/src/digitalkin/utils/package_discover.py +358 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin.egg-info/PKG-INFO +1 -1
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin.egg-info/SOURCES.txt +4 -2
- digitalkin-0.2.15/src/digitalkin/models/module/__init__.py +0 -12
- digitalkin-0.2.15/src/digitalkin/models/module/module_types.py +0 -11
- digitalkin-0.2.15/src/digitalkin/modules/trigger_module.py +0 -11
- {digitalkin-0.2.15 → digitalkin-0.2.17}/LICENSE +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/README.md +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/mock/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/mock/mock_pb2.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/server_async_insecure.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/server_async_secure.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/server_sync_insecure.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/base_server/server_sync_secure.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/modules/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/modules/cpu_intensive_module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/modules/minimal_llm_module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/modules/text_transform_module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/services/filesystem_module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/examples/services/storage_module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/setup.cfg +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/_base_server.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/registry_server.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/registry_servicer.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/utils/factory.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/utils/models.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/grpc_servers/utils/types.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/logger.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/models/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/models/module/module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/models/services/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/models/services/cost.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/models/services/storage.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/archetype_module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/job_manager/base_job_manager.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/job_manager/job_manager_models.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/job_manager/single_job_manager.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/job_manager/taskiq_broker.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/job_manager/taskiq_job_manager.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/modules/tool_module.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/py.typed +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/agent/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/agent/agent_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/agent/default_agent.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/base_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/cost/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/cost/cost_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/cost/default_cost.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/cost/grpc_cost.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/filesystem/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/identity/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/identity/default_identity.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/identity/identity_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/registry/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/registry/default_registry.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/registry/registry_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/services_config.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/services_models.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/setup/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/setup/default_setup.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/setup/grpc_setup.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/setup/setup_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/snapshot/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/storage/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/storage/default_storage.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/storage/grpc_storage.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/storage/storage_strategy.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/utils/__init__.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/utils/arg_parser.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/utils/development_mode_action.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/utils/llm_ready_schema.py +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin.egg-info/dependency_links.txt +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin.egg-info/requires.txt +0 -0
- {digitalkin-0.2.15 → digitalkin-0.2.17}/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
|
# Version of the package automatically updated by bump2version (that is why it is separated)
|
|
15
|
-
version = "0.2.
|
|
15
|
+
version = "0.2.17"
|
|
16
16
|
|
|
17
17
|
classifiers = [
|
|
18
18
|
"Development Status :: 3 - Alpha",
|
|
@@ -212,7 +212,7 @@
|
|
|
212
212
|
"ANN401",
|
|
213
213
|
"PLR0912",
|
|
214
214
|
"ANN201",
|
|
215
|
-
"D100"
|
|
215
|
+
"D100",
|
|
216
216
|
]
|
|
217
217
|
|
|
218
218
|
[tool.ruff.lint.pylint]
|
|
@@ -79,10 +79,10 @@ class ModuleServer(BaseServer):
|
|
|
79
79
|
|
|
80
80
|
def start(self) -> None:
|
|
81
81
|
"""Start the module server and register with the registry if configured."""
|
|
82
|
-
logger.
|
|
82
|
+
logger.info(self.server_config)
|
|
83
83
|
super().start()
|
|
84
84
|
|
|
85
|
-
logger.
|
|
85
|
+
logger.info(self.server_config)
|
|
86
86
|
# If a registry address is provided, register the module
|
|
87
87
|
if self.server_config.registry_address:
|
|
88
88
|
try:
|
|
@@ -91,17 +91,17 @@ class ModuleServer(BaseServer):
|
|
|
91
91
|
logger.exception("Failed to register with registry")
|
|
92
92
|
|
|
93
93
|
if self.module_servicer is not None:
|
|
94
|
-
logger.
|
|
94
|
+
logger.info(
|
|
95
95
|
"Setup post init started with config: %s", self.client_config
|
|
96
96
|
)
|
|
97
97
|
self.module_servicer.setup.__post_init__(self.client_config)
|
|
98
98
|
|
|
99
99
|
async def start_async(self) -> None:
|
|
100
100
|
"""Start the module server and register with the registry if configured."""
|
|
101
|
-
logger.
|
|
101
|
+
logger.info(self.server_config)
|
|
102
102
|
await super().start_async()
|
|
103
103
|
|
|
104
|
-
logger.
|
|
104
|
+
logger.info(self.server_config)
|
|
105
105
|
# If a registry address is provided, register the module
|
|
106
106
|
if self.server_config.registry_address:
|
|
107
107
|
try:
|
|
@@ -110,7 +110,7 @@ class ModuleServer(BaseServer):
|
|
|
110
110
|
logger.exception("Failed to register with registry")
|
|
111
111
|
|
|
112
112
|
if self.module_servicer is not None:
|
|
113
|
-
logger.
|
|
113
|
+
logger.info(
|
|
114
114
|
"Setup post init started with config: %s", self.client_config
|
|
115
115
|
)
|
|
116
116
|
await self.module_servicer.job_manager._start()
|
|
@@ -70,6 +70,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
|
|
|
70
70
|
module_class: The module type to serve.
|
|
71
71
|
"""
|
|
72
72
|
super().__init__()
|
|
73
|
+
module_class.discover()
|
|
73
74
|
self.module_class = module_class
|
|
74
75
|
job_manager_class = self.args.job_manager_mode.get_manager_class()
|
|
75
76
|
self.job_manager = job_manager_class(module_class, self.args.services_mode)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""This module contains the models for the modules."""
|
|
2
|
+
|
|
3
|
+
from digitalkin.models.module.module import Module, ModuleStatus
|
|
4
|
+
from digitalkin.models.module.module_context import ModuleContext
|
|
5
|
+
from digitalkin.models.module.module_types import (
|
|
6
|
+
ConfigSetupModelT,
|
|
7
|
+
InputModel,
|
|
8
|
+
InputModelT,
|
|
9
|
+
InputTrigger,
|
|
10
|
+
OutputModelT,
|
|
11
|
+
SecretModelT,
|
|
12
|
+
SetupModelT,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"ConfigSetupModelT",
|
|
17
|
+
"InputModel",
|
|
18
|
+
"InputModelT",
|
|
19
|
+
"InputTrigger",
|
|
20
|
+
"Module",
|
|
21
|
+
"ModuleContext",
|
|
22
|
+
"ModuleStatus",
|
|
23
|
+
"OutputModelT",
|
|
24
|
+
"SecretModelT",
|
|
25
|
+
"SetupModelT",
|
|
26
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Define the module context used in the triggers."""
|
|
2
|
+
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
|
|
5
|
+
from digitalkin.services.cost.cost_strategy import CostStrategy
|
|
6
|
+
from digitalkin.services.filesystem.filesystem_strategy import FilesystemStrategy
|
|
7
|
+
from digitalkin.services.storage.storage_strategy import StorageStrategy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ModuleContext(SimpleNamespace):
|
|
11
|
+
"""ModuleContext provides a container for strategies and resources used by a module.
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
cost (CostStrategy): The strategy used to calculate or manage costs within the module.
|
|
15
|
+
filesystem (FilesystemStrategy): The strategy for interacting with the filesystem.
|
|
16
|
+
storage (StorageStrategy): The strategy for handling storage operations.
|
|
17
|
+
|
|
18
|
+
This context object is designed to be passed to module components, providing them with
|
|
19
|
+
access to shared strategies and resources. Additional attributes may be set dynamically.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
cost: CostStrategy
|
|
23
|
+
filesystem: FilesystemStrategy
|
|
24
|
+
storage: StorageStrategy
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Types for module models."""
|
|
2
|
+
|
|
3
|
+
from typing import TypeVar
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class InputTrigger(BaseModel):
|
|
9
|
+
"""Defines the root input model exposing the protocol.
|
|
10
|
+
|
|
11
|
+
The mandatory protocol is important to define the module beahvior following the user or agent input.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
class MyInput(InputModel):
|
|
15
|
+
root: InputTrigger
|
|
16
|
+
user_define_data: Any
|
|
17
|
+
|
|
18
|
+
# Usage
|
|
19
|
+
my_input = MyInput(root=InputTrigger(protocol="message"))
|
|
20
|
+
print(my_input.root.protocol) # Output: message
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
protocol: str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class InputModel(BaseModel):
|
|
27
|
+
"""Base definition of input model showing mandatory root fields.
|
|
28
|
+
|
|
29
|
+
The Model define the Module Input, usually referring to multiple input type defined by an union.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
class ModuleInput(InputModel):
|
|
33
|
+
root: FileInput | MessageInput
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
root: InputTrigger
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
ConfigSetupModelT = TypeVar("ConfigSetupModelT", bound=BaseModel | None)
|
|
40
|
+
InputModelT = TypeVar("InputModelT", bound=InputModel)
|
|
41
|
+
OutputModelT = TypeVar("OutputModelT", bound=BaseModel)
|
|
42
|
+
SetupModelT = TypeVar("SetupModelT", bound=BaseModel)
|
|
43
|
+
SecretModelT = TypeVar("SecretModelT", bound=BaseModel)
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from digitalkin.modules.archetype_module import ArchetypeModule
|
|
4
4
|
from digitalkin.modules.tool_module import ToolModule
|
|
5
|
-
from digitalkin.modules.
|
|
5
|
+
from digitalkin.modules.trigger_handler import TriggerHandler
|
|
6
6
|
|
|
7
|
-
__all__ = ["ArchetypeModule", "ToolModule", "
|
|
7
|
+
__all__ = ["ArchetypeModule", "ToolModule", "TriggerHandler"]
|
|
@@ -19,6 +19,8 @@ from digitalkin.models.module import (
|
|
|
19
19
|
SecretModelT,
|
|
20
20
|
SetupModelT,
|
|
21
21
|
)
|
|
22
|
+
from digitalkin.models.module.module_context import ModuleContext
|
|
23
|
+
from digitalkin.modules.trigger_handler import TriggerHandler
|
|
22
24
|
from digitalkin.services.agent.agent_strategy import AgentStrategy
|
|
23
25
|
from digitalkin.services.cost.cost_strategy import CostStrategy
|
|
24
26
|
from digitalkin.services.filesystem.filesystem_strategy import FilesystemStrategy
|
|
@@ -28,17 +30,18 @@ from digitalkin.services.services_config import ServicesConfig, ServicesStrategy
|
|
|
28
30
|
from digitalkin.services.snapshot.snapshot_strategy import SnapshotStrategy
|
|
29
31
|
from digitalkin.services.storage.storage_strategy import StorageStrategy
|
|
30
32
|
from digitalkin.utils.llm_ready_schema import llm_ready_schema
|
|
33
|
+
from digitalkin.utils.package_discover import ModuleDiscoverer
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
class ModuleErrorModel(BaseModel):
|
|
34
|
-
"""
|
|
37
|
+
"""typed error/code model."""
|
|
35
38
|
|
|
36
39
|
code: str
|
|
37
40
|
exception: str
|
|
38
41
|
short_description: str
|
|
39
42
|
|
|
40
43
|
|
|
41
|
-
class BaseModule(
|
|
44
|
+
class BaseModule( # noqa: PLR0904
|
|
42
45
|
ABC,
|
|
43
46
|
Generic[
|
|
44
47
|
InputModelT,
|
|
@@ -60,6 +63,9 @@ class BaseModule(
|
|
|
60
63
|
secret_format: type[SecretModelT]
|
|
61
64
|
metadata: ClassVar[dict[str, Any]]
|
|
62
65
|
|
|
66
|
+
context: ModuleContext
|
|
67
|
+
triggers_discoverer: ClassVar[ModuleDiscoverer]
|
|
68
|
+
|
|
63
69
|
# service config params
|
|
64
70
|
services_config_strategies: ClassVar[dict[str, ServicesStrategy | None]]
|
|
65
71
|
services_config_params: ClassVar[dict[str, dict[str, Any | None] | None]]
|
|
@@ -95,6 +101,13 @@ class BaseModule(
|
|
|
95
101
|
# Initialize services configuration
|
|
96
102
|
self._init_strategies()
|
|
97
103
|
|
|
104
|
+
# Initialize minimum context
|
|
105
|
+
self.context = ModuleContext(
|
|
106
|
+
storage=self.storage,
|
|
107
|
+
cost=self.cost,
|
|
108
|
+
filesystem=self.filesystem,
|
|
109
|
+
)
|
|
110
|
+
|
|
98
111
|
@property
|
|
99
112
|
def status(self) -> ModuleStatus:
|
|
100
113
|
"""Get the module status.
|
|
@@ -165,10 +178,12 @@ class BaseModule(
|
|
|
165
178
|
Returns:
|
|
166
179
|
The JSON schema of the config setup format as a string.
|
|
167
180
|
"""
|
|
168
|
-
|
|
181
|
+
config_setup_format = getattr(cls, "config_setup_format", None)
|
|
182
|
+
|
|
183
|
+
if config_setup_format is not None:
|
|
169
184
|
if llm_format:
|
|
170
|
-
return json.dumps(llm_ready_schema(
|
|
171
|
-
return json.dumps(
|
|
185
|
+
return json.dumps(llm_ready_schema(config_setup_format), indent=2)
|
|
186
|
+
return json.dumps(config_setup_format.model_json_schema(), indent=2)
|
|
172
187
|
msg = "'%s' class does not define an 'config_setup_format'."
|
|
173
188
|
raise OptionalFeatureNotImplementedError(msg)
|
|
174
189
|
|
|
@@ -249,6 +264,32 @@ class BaseModule(
|
|
|
249
264
|
"""
|
|
250
265
|
return cls.output_format(**output_data)
|
|
251
266
|
|
|
267
|
+
@classmethod
|
|
268
|
+
def discover(cls) -> None:
|
|
269
|
+
"""Discover and register all TriggerHandler subclasses in the specified package or current directory.
|
|
270
|
+
|
|
271
|
+
Dynamically import all Python modules in the specified package or current directory,
|
|
272
|
+
triggering class registrations for subclasses of TriggerHandler whose names end with 'Trigger'.
|
|
273
|
+
|
|
274
|
+
If a package is provided, all .py files within its path are imported; otherwise, the current
|
|
275
|
+
working directory is searched. For each imported module, any class matching the criteria is
|
|
276
|
+
registered via cls.register(). Errors during import are logged at debug level.
|
|
277
|
+
"""
|
|
278
|
+
cls.triggers_discoverer.discover_modules()
|
|
279
|
+
logger.debug("discovered: %s", cls.triggers_discoverer)
|
|
280
|
+
|
|
281
|
+
@classmethod
|
|
282
|
+
def register(cls, handler_cls: type[TriggerHandler]) -> type[TriggerHandler]:
|
|
283
|
+
"""Dynamically register the trigger class.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
handler_cls: type of the trigger handler to register.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
type of the trigger handler.
|
|
290
|
+
"""
|
|
291
|
+
return cls.triggers_discoverer.register_trigger(handler_cls)
|
|
292
|
+
|
|
252
293
|
@abstractmethod
|
|
253
294
|
async def run_config_setup(
|
|
254
295
|
self,
|
|
@@ -269,15 +310,42 @@ class BaseModule(
|
|
|
269
310
|
"""Initialize the module."""
|
|
270
311
|
raise NotImplementedError
|
|
271
312
|
|
|
272
|
-
@abstractmethod
|
|
273
313
|
async def run(
|
|
274
314
|
self,
|
|
275
315
|
input_data: InputModelT,
|
|
276
316
|
setup_data: SetupModelT,
|
|
277
317
|
callback: Callable[[OutputModelT], Coroutine[Any, Any, None]],
|
|
278
318
|
) -> None:
|
|
279
|
-
"""Run the module.
|
|
280
|
-
|
|
319
|
+
"""Run the module with the given input and setup data.
|
|
320
|
+
|
|
321
|
+
This method validates the input data, determines the protocol from the input,
|
|
322
|
+
and dispatches the request to the corresponding trigger handler. The trigger handler
|
|
323
|
+
is responsible for processing the input and invoking the callback with the result.
|
|
324
|
+
|
|
325
|
+
Triggers:
|
|
326
|
+
- The method is triggered when a module run is requested with specific input and setup data.
|
|
327
|
+
- The protocol specified in the input determines which trigger handler is invoked.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
input_data (InputModelT): The input data to be processed by the module.
|
|
331
|
+
setup_data (SetupModelT): The setup or configuration data required for the module.
|
|
332
|
+
callback (Callable[[OutputModelT], Coroutine[Any, Any, None]]): callback to be invoked to stream any result.
|
|
333
|
+
|
|
334
|
+
Raises:
|
|
335
|
+
ValueError: If no handler for the protocol is found.
|
|
336
|
+
"""
|
|
337
|
+
input_instance = self.input_format.model_validate(input_data)
|
|
338
|
+
handler_instance = self.triggers_discoverer.get_trigger(
|
|
339
|
+
input_instance.root.protocol,
|
|
340
|
+
input_instance.root,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
await handler_instance.handle(
|
|
344
|
+
input_instance.root,
|
|
345
|
+
setup_data,
|
|
346
|
+
callback,
|
|
347
|
+
self.context,
|
|
348
|
+
)
|
|
281
349
|
|
|
282
350
|
@abstractmethod
|
|
283
351
|
async def cleanup(self) -> None:
|
|
@@ -338,6 +406,8 @@ class BaseModule(
|
|
|
338
406
|
return
|
|
339
407
|
|
|
340
408
|
try:
|
|
409
|
+
logger.info("Init the discod input handlers.")
|
|
410
|
+
self.triggers_discoverer.init_handlers(self.context)
|
|
341
411
|
logger.info("Run lifecycle")
|
|
342
412
|
self._status = ModuleStatus.RUNNING
|
|
343
413
|
self._task = asyncio.create_task(
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Definition of the Trigger type."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Callable, Coroutine
|
|
5
|
+
from typing import Any, ClassVar, Generic
|
|
6
|
+
|
|
7
|
+
from digitalkin.models.module.module_types import InputModelT, OutputModelT, SetupModelT
|
|
8
|
+
from digitalkin.modules._base_module import ModuleContext
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TriggerHandler(ABC, Generic[InputModelT, SetupModelT, OutputModelT]):
|
|
12
|
+
"""Base class for all input-trigger handlers.
|
|
13
|
+
|
|
14
|
+
Each handler declares:
|
|
15
|
+
- protocol_key: the Literal value this handler processes
|
|
16
|
+
- handle(): logic to process the validated payload
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
protocol: ClassVar[str]
|
|
20
|
+
input_format: type[InputModelT]
|
|
21
|
+
output_format: type[OutputModelT]
|
|
22
|
+
|
|
23
|
+
def __init__(self, context: ModuleContext) -> None:
|
|
24
|
+
"""Initialize the TriggerHandler with the given context."""
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def handle(
|
|
28
|
+
self,
|
|
29
|
+
input_data: InputModelT,
|
|
30
|
+
setup_data: SetupModelT,
|
|
31
|
+
callback: Callable[[Any], Coroutine[Any, Any, None]],
|
|
32
|
+
context: ModuleContext,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Asynchronously processes the input data specific to Handler and streams results via the provided callback.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
input_data (InputModelT): The input data to be processed by the handler.
|
|
38
|
+
setup_data (SetupModelT): The setup or configuration data required for processing.
|
|
39
|
+
callback (Callable[[Any], Coroutine[Any, Any, None]]): callback that stream results.
|
|
40
|
+
context (ModuleContext): The context object containing module-specific information and resources.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Any: The result of the processing, if applicable.
|
|
44
|
+
|
|
45
|
+
Note:
|
|
46
|
+
The callback must be awaited to ensure results are streamed correctly during processing.
|
|
47
|
+
"""
|
{digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/filesystem/default_filesystem.py
RENAMED
|
@@ -5,7 +5,7 @@ import os
|
|
|
5
5
|
import tempfile
|
|
6
6
|
import uuid
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any
|
|
8
|
+
from typing import Any, Literal
|
|
9
9
|
|
|
10
10
|
from digitalkin.logger import logger
|
|
11
11
|
from digitalkin.services.filesystem.filesystem_strategy import (
|
|
@@ -259,7 +259,17 @@ class DefaultFilesystem(FilesystemStrategy):
|
|
|
259
259
|
self,
|
|
260
260
|
file_id: str,
|
|
261
261
|
content: bytes | None = None,
|
|
262
|
-
file_type:
|
|
262
|
+
file_type: Literal[
|
|
263
|
+
"UNSPECIFIED",
|
|
264
|
+
"DOCUMENT",
|
|
265
|
+
"IMAGE",
|
|
266
|
+
"VIDEO",
|
|
267
|
+
"AUDIO",
|
|
268
|
+
"ARCHIVE",
|
|
269
|
+
"CODE",
|
|
270
|
+
"OTHER",
|
|
271
|
+
]
|
|
272
|
+
| None = None,
|
|
263
273
|
content_type: str | None = None,
|
|
264
274
|
metadata: dict[str, Any] | None = None,
|
|
265
275
|
new_name: str | None = None,
|
{digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/filesystem/filesystem_strategy.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from datetime import datetime
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any, Literal
|
|
6
6
|
|
|
7
7
|
from pydantic import BaseModel, Field
|
|
8
8
|
|
|
@@ -34,7 +34,21 @@ class FileFilter(BaseModel):
|
|
|
34
34
|
|
|
35
35
|
names: list[str] | None = Field(default=None, description="Filter by file names (exact matches)")
|
|
36
36
|
file_ids: list[str] | None = Field(default=None, description="Filter by file IDs")
|
|
37
|
-
file_types:
|
|
37
|
+
file_types: (
|
|
38
|
+
list[
|
|
39
|
+
Literal[
|
|
40
|
+
"UNSPECIFIED",
|
|
41
|
+
"DOCUMENT",
|
|
42
|
+
"IMAGE",
|
|
43
|
+
"AUDIO",
|
|
44
|
+
"VIDEO",
|
|
45
|
+
"ARCHIVE",
|
|
46
|
+
"CODE",
|
|
47
|
+
"OTHER",
|
|
48
|
+
]
|
|
49
|
+
]
|
|
50
|
+
| None
|
|
51
|
+
) = Field(default=None, description="Filter by file types")
|
|
38
52
|
created_after: datetime | None = Field(default=None, description="Filter files created after this timestamp")
|
|
39
53
|
created_before: datetime | None = Field(default=None, description="Filter files created before this timestamp")
|
|
40
54
|
updated_after: datetime | None = Field(default=None, description="Filter files updated after this timestamp")
|
|
@@ -52,7 +66,16 @@ class UploadFileData(BaseModel):
|
|
|
52
66
|
|
|
53
67
|
content: bytes = Field(description="The content of the file")
|
|
54
68
|
name: str = Field(description="The name of the file")
|
|
55
|
-
file_type:
|
|
69
|
+
file_type: Literal[
|
|
70
|
+
"UNSPECIFIED",
|
|
71
|
+
"DOCUMENT",
|
|
72
|
+
"IMAGE",
|
|
73
|
+
"AUDIO",
|
|
74
|
+
"VIDEO",
|
|
75
|
+
"ARCHIVE",
|
|
76
|
+
"CODE",
|
|
77
|
+
"OTHER",
|
|
78
|
+
] = Field(description="The type of the file")
|
|
56
79
|
content_type: str | None = Field(default=None, description="The content type of the file")
|
|
57
80
|
metadata: dict[str, Any] | None = Field(default=None, description="The metadata of the file")
|
|
58
81
|
replace_if_exists: bool = Field(default=False, description="Whether to replace the file if it already exists")
|
|
@@ -153,7 +176,17 @@ class FilesystemStrategy(BaseStrategy, ABC):
|
|
|
153
176
|
self,
|
|
154
177
|
file_id: str,
|
|
155
178
|
content: bytes | None = None,
|
|
156
|
-
file_type:
|
|
179
|
+
file_type: Literal[
|
|
180
|
+
"UNSPECIFIED",
|
|
181
|
+
"DOCUMENT",
|
|
182
|
+
"IMAGE",
|
|
183
|
+
"VIDEO",
|
|
184
|
+
"AUDIO",
|
|
185
|
+
"ARCHIVE",
|
|
186
|
+
"CODE",
|
|
187
|
+
"OTHER",
|
|
188
|
+
]
|
|
189
|
+
| None = None,
|
|
157
190
|
content_type: str | None = None,
|
|
158
191
|
metadata: dict[str, Any] | None = None,
|
|
159
192
|
new_name: str | None = None,
|
{digitalkin-0.2.15 → digitalkin-0.2.17}/src/digitalkin/services/filesystem/grpc_filesystem.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Generator
|
|
4
4
|
from contextlib import contextmanager
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any, Literal
|
|
6
6
|
|
|
7
7
|
from digitalkin_proto.digitalkin.filesystem.v1 import filesystem_pb2, filesystem_service_pb2_grpc
|
|
8
8
|
from google.protobuf import struct_pb2
|
|
@@ -103,12 +103,11 @@ class GrpcFilesystem(FilesystemStrategy, GrpcClientWrapper):
|
|
|
103
103
|
status=self._file_status_to_enum(filters.status) if filters.status else None,
|
|
104
104
|
)
|
|
105
105
|
|
|
106
|
-
def _file_proto_to_data(self, file: filesystem_pb2.File
|
|
106
|
+
def _file_proto_to_data(self, file: filesystem_pb2.File) -> FilesystemRecord:
|
|
107
107
|
"""Convert a File proto message to FilesystemRecord.
|
|
108
108
|
|
|
109
109
|
Args:
|
|
110
110
|
file: The File proto message to convert
|
|
111
|
-
content: The content of the file
|
|
112
111
|
|
|
113
112
|
Returns:
|
|
114
113
|
FilesystemRecord: The converted data
|
|
@@ -124,7 +123,7 @@ class GrpcFilesystem(FilesystemStrategy, GrpcClientWrapper):
|
|
|
124
123
|
metadata=MessageToDict(file.metadata),
|
|
125
124
|
storage_url=file.storage_url,
|
|
126
125
|
status=filesystem_pb2.FileStatus.Name(file.status),
|
|
127
|
-
content=content,
|
|
126
|
+
content=file.content,
|
|
128
127
|
)
|
|
129
128
|
|
|
130
129
|
def __init__(
|
|
@@ -213,13 +212,23 @@ class GrpcFilesystem(FilesystemStrategy, GrpcClientWrapper):
|
|
|
213
212
|
|
|
214
213
|
response: filesystem_pb2.GetFileResponse = self.exec_grpc_query("GetFile", request)
|
|
215
214
|
|
|
216
|
-
return self._file_proto_to_data(response.file
|
|
215
|
+
return self._file_proto_to_data(response.file)
|
|
217
216
|
|
|
218
217
|
def update_file(
|
|
219
218
|
self,
|
|
220
219
|
file_id: str,
|
|
221
220
|
content: bytes | None = None,
|
|
222
|
-
file_type:
|
|
221
|
+
file_type: Literal[
|
|
222
|
+
"UNSPECIFIED",
|
|
223
|
+
"DOCUMENT",
|
|
224
|
+
"IMAGE",
|
|
225
|
+
"VIDEO",
|
|
226
|
+
"AUDIO",
|
|
227
|
+
"ARCHIVE",
|
|
228
|
+
"CODE",
|
|
229
|
+
"OTHER",
|
|
230
|
+
]
|
|
231
|
+
| None = None,
|
|
223
232
|
content_type: str | None = None,
|
|
224
233
|
metadata: dict[str, Any] | None = None,
|
|
225
234
|
new_name: str | None = None,
|