digitalkin 0.2.3__py3-none-any.whl → 0.2.4__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.
digitalkin/__version__.py CHANGED
@@ -5,4 +5,4 @@ from importlib.metadata import PackageNotFoundError, version
5
5
  try:
6
6
  __version__ = version("digitalkin")
7
7
  except PackageNotFoundError:
8
- __version__ = "0.2.3"
8
+ __version__ = "0.2.4"
@@ -51,7 +51,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
51
51
  self.job_manager = JobManager(module_class)
52
52
  self.setup = GrpcSetup() if self.job_manager.args.services_mode == ServicesMode.REMOTE else DefaultSetup()
53
53
 
54
- async def add_to_queue(self, job_id: str, output_data: OutputModelT) -> None:
54
+ async def add_to_queue(self, job_id: str, output_data: OutputModelT) -> None: # type: ignore
55
55
  """Callback used to add the output data to the queue of messages."""
56
56
  logger.info("JOB: %s added an output_data: %s", job_id, output_data)
57
57
  await self.queue.put({job_id: output_data})
@@ -76,11 +76,11 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
76
76
  logger.info("StartModule called for module: '%s'", self.module_class.__name__)
77
77
  # Process the module input
78
78
  # TODO: Check failure of input data format
79
- input_data = self.module_class.input_format(**dict(request.input.items()))
79
+ input_data = self.module_class.create_input_model(dict(request.input.items()))
80
80
  setup_data_class = self.setup.get_setup(
81
81
  setup_dict={
82
82
  "setup_id": request.setup_id,
83
- "mission_id": "missions:test_demo",
83
+ "mission_id": request.mission_id,
84
84
  }
85
85
  )
86
86
 
@@ -88,31 +88,44 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
88
88
  msg = "No setup data returned."
89
89
  raise ServicerError(msg)
90
90
  # TODO: Check failure of setup data format
91
- setup_data = self.module_class.setup_format(**setup_data_class.current_setup_version.content)
91
+ setup_data = self.module_class.create_setup_model(setup_data_class.current_setup_version.content)
92
92
 
93
93
  # setup_id should be use to request a precise setup from the module
94
94
  # Create a job for this execution
95
- job_id, module = await self.job_manager.create_job(
95
+ result: tuple[str, BaseModule] = await self.job_manager.create_job(
96
96
  input_data,
97
97
  setup_data,
98
+ mission_id=request.mission_id,
98
99
  callback=self.add_to_queue,
99
100
  )
101
+ job_id, module = result
100
102
 
101
103
  while module.status == ModuleStatus.RUNNING or not self.queue.empty():
102
- output_data = await self.queue.get()
104
+ output_data: dict = await self.queue.get()
105
+ if job_id not in output_data or output_data[job_id] not in self.job_manager.modules:
106
+ message = f"Job {job_id} not found"
107
+ logger.warning(message)
108
+ context.set_code(grpc.StatusCode.NOT_FOUND)
109
+ context.set_details(message)
110
+ yield lifecycle_pb2.StartModuleResponse(success=False)
111
+ return
112
+
103
113
  if output_data[job_id].get("error", None) is not None:
104
114
  context.set_code(output_data[job_id]["error"]["code"])
105
115
  context.set_details(output_data[job_id]["error"]["error_message"])
106
116
  yield lifecycle_pb2.StartModuleResponse(success=False)
107
117
  return
108
- else:
109
- # TODO: add a check for the job_id / error handling
110
- output_proto = {key: str(value) for key, value in output_data[job_id].items()}
111
- yield lifecycle_pb2.StartModuleResponse(
112
- success=True,
113
- output=output_proto,
114
- job_id=job_id,
115
- )
118
+
119
+ output_proto = json_format.ParseDict(
120
+ output_data[job_id],
121
+ struct_pb2.Struct(),
122
+ ignore_unknown_fields=True,
123
+ )
124
+ yield lifecycle_pb2.StartModuleResponse(
125
+ success=True,
126
+ output=output_proto,
127
+ job_id=job_id,
128
+ )
116
129
 
117
130
  async def StopModule( # noqa: N802
118
131
  self,
@@ -140,6 +140,54 @@ class BaseModule(ABC, Generic[InputModelT, OutputModelT, SetupModelT, SecretMode
140
140
  msg = "'%s' class does not define an 'setup_format'."
141
141
  raise NotImplementedError(msg)
142
142
 
143
+ @classmethod
144
+ def create_input_model(cls, input_data: dict[str, Any]) -> InputModelT:
145
+ """Create the input model from the input data.
146
+
147
+ Args:
148
+ input_data: The input data to create the model from.
149
+
150
+ Returns:
151
+ The input model.
152
+ """
153
+ return cls.input_format(**input_data)
154
+
155
+ @classmethod
156
+ def create_setup_model(cls, setup_data: dict[str, Any]) -> SetupModelT:
157
+ """Create the setup model from the setup data.
158
+
159
+ Args:
160
+ setup_data: The setup data to create the model from.
161
+
162
+ Returns:
163
+ The setup model.
164
+ """
165
+ return cls.setup_format(**setup_data)
166
+
167
+ @classmethod
168
+ def create_secret_model(cls, secret_data: dict[str, Any]) -> SecretModelT:
169
+ """Create the secret model from the secret data.
170
+
171
+ Args:
172
+ secret_data: The secret data to create the model from.
173
+
174
+ Returns:
175
+ The secret model.
176
+ """
177
+ return cls.secret_format(**secret_data)
178
+
179
+ @classmethod
180
+ def create_output_model(cls, output_data: dict[str, Any]) -> OutputModelT:
181
+ """Create the output model from the output data.
182
+
183
+ Args:
184
+ output_data: The output data to create the model from.
185
+
186
+ Returns:
187
+ The output model.
188
+ """
189
+ return cls.output_format(**output_data)
190
+
143
191
  @abstractmethod
144
192
  async def initialize(self, setup_data: SetupModelT) -> None:
145
193
  """Initialize the module."""
@@ -8,7 +8,7 @@ from typing import Any
8
8
 
9
9
  from digitalkin.logger import logger
10
10
  from digitalkin.models import ModuleStatus
11
- from digitalkin.models.module import InputModelT, OutputModelT, SetupModelT
11
+ from digitalkin.models.module import InputModelT, OutputModelT, SecretModelT, SetupModelT
12
12
  from digitalkin.modules._base_module import BaseModule
13
13
  from digitalkin.services.services_config import ServicesConfig
14
14
  from digitalkin.services.services_models import ServicesMode
@@ -78,8 +78,9 @@ class JobManager(ArgParser):
78
78
  self,
79
79
  input_data: InputModelT,
80
80
  setup_data: SetupModelT,
81
+ mission_id: str,
81
82
  callback: Callable[[str, OutputModelT], Coroutine[Any, Any, None]],
82
- ) -> tuple[str, BaseModule]:
83
+ ) -> tuple[str, BaseModule[InputModelT, OutputModelT, SetupModelT, SecretModelT]]: # type: ignore
83
84
  """Start new module job in background (asyncio).
84
85
 
85
86
  Args:
@@ -91,7 +92,6 @@ class JobManager(ArgParser):
91
92
  str: job_id of the module entity
92
93
  """
93
94
  job_id = str(uuid.uuid4())
94
- mission_id = "missions:test_demo"
95
95
  """TODO: check uniqueness of the job_id"""
96
96
  # Création et démarrage du module
97
97
  module = self.module_class(job_id, mission_id=mission_id)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: SDK to build kin used in DigitalKin
5
5
  Author-email: "DigitalKin.ai" <contact@digitalkin.ai>
6
6
  License: Attribution-NonCommercial-ShareAlike 4.0 International
@@ -452,7 +452,7 @@ Classifier: License :: Other/Proprietary License
452
452
  Requires-Python: >=3.10
453
453
  Description-Content-Type: text/markdown
454
454
  License-File: LICENSE
455
- Requires-Dist: digitalkin-proto>=0.1.6
455
+ Requires-Dist: digitalkin-proto>=0.1.7
456
456
  Requires-Dist: grpcio-health-checking>=1.71.0
457
457
  Requires-Dist: grpcio-reflection>=1.71.0
458
458
  Requires-Dist: grpcio-status>=1.71.0
@@ -7,13 +7,13 @@ base_server/mock/__init__.py,sha256=YZFT-F1l_TpvJYuIPX-7kTeE1CfOjhx9YmNRXVoi-jQ,
7
7
  base_server/mock/mock_pb2.py,sha256=sETakcS3PAAm4E-hTCV1jIVaQTPEAIoVVHupB8Z_k7Y,1843
8
8
  base_server/mock/mock_pb2_grpc.py,sha256=BbOT70H6q3laKgkHfOx1QdfmCS_HxCY4wCOX84YAdG4,3180
9
9
  digitalkin/__init__.py,sha256=7LLBAba0th-3SGqcpqFO-lopWdUkVLKzLZiMtB-mW3M,162
10
- digitalkin/__version__.py,sha256=HxifwzaIVOH4OARz9iIyKg-4JvPFh73sakEoHGNycsA,190
10
+ digitalkin/__version__.py,sha256=mR_bGYOQA3eO6IjqeeDDhhBptzMqVTzT6k-jTNiddLY,190
11
11
  digitalkin/logger.py,sha256=9cDgyJV2QXXT8F--xRODFlZyDgjuTTXNdpCU3GdqCsk,382
12
12
  digitalkin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  digitalkin/grpc_servers/__init__.py,sha256=0cJBlwipSmFdXkyH3T0i6OJ1WpAtNsZgYX7JaSnkbtg,804
14
14
  digitalkin/grpc_servers/_base_server.py,sha256=ec4xmgAuOMVg45a63O_PEa2T7mI4tJ6boxcXauFyZ5g,18649
15
15
  digitalkin/grpc_servers/module_server.py,sha256=23Q6F9mSO9bCu2MmsLqM9WeviIzwfhDiBFrVspy0PCI,9065
16
- digitalkin/grpc_servers/module_servicer.py,sha256=togOyvogAYkBv353S-9X_pP5yI8MvxupOIBSvq39jA4,11816
16
+ digitalkin/grpc_servers/module_servicer.py,sha256=FMzB2E1dQZck34vGWf9OXNXEIfu_KhTdZ_Kn79XEowc,12306
17
17
  digitalkin/grpc_servers/registry_server.py,sha256=PmWaH4Xmg5Sj7NtFVLBNTOzkOfqo7dw_qyVBnaW4jy4,2238
18
18
  digitalkin/grpc_servers/registry_servicer.py,sha256=mCAjNhdMq5DozZMEPsJK__DIxePEYxSWV-gAq-Xctk4,16469
19
19
  digitalkin/grpc_servers/utils/exceptions.py,sha256=I00OM8p8up20He4dU1fiHsvdLj1DymjR_UmoeUm2MSA,785
@@ -29,9 +29,9 @@ digitalkin/models/services/__init__.py,sha256=HsW7MUGFPvH7Ri28WN4BHHBfEQk5dzU_9F
29
29
  digitalkin/models/services/cost.py,sha256=QTEuFD6xz62nob0z4ksE-INJWcZ-iFiuNW5mvXhpFes,1599
30
30
  digitalkin/models/services/storage.py,sha256=cYTVIriGKiprF9OerhSxmc_jM6fUTVwmeon1yQCinkE,143
31
31
  digitalkin/modules/__init__.py,sha256=ppYARmhvdVi55ofC0QZerIempSlcJYDeCXhcl4qXObw,278
32
- digitalkin/modules/_base_module.py,sha256=f4AEZFyl0meT_V6esnEFyUtuN7ZXvhHgIYa1ZOMe7tM,7651
32
+ digitalkin/modules/_base_module.py,sha256=iVPRlooAGIW4_3lN9loUPe1q6uf62-vSsEE5THvn8eU,9007
33
33
  digitalkin/modules/archetype_module.py,sha256=T2Ehj7EpAC2MO9WQbJv39hqRw7rh3exhVZTEL3JPM8U,421
34
- digitalkin/modules/job_manager.py,sha256=q48ZJwWmOZ4xJKV2QApI6x_Nfgviej-AoIV8BJQ9B-o,6110
34
+ digitalkin/modules/job_manager.py,sha256=QHcrm3F99I9tlNzXefkyhkkwPITf_H1bEb_obMDbUic,6177
35
35
  digitalkin/modules/tool_module.py,sha256=86g0M1wHZ1ReIc7AkKfyjnlGN2QYJBGxrEQpKVlyrZI,421
36
36
  digitalkin/modules/trigger_module.py,sha256=kVoI4Gdkw7WWUP5T6hSCNqw5FxibTxL6Tpq9KP7gg78,379
37
37
  digitalkin/services/__init__.py,sha256=LqGk_5DJy8Bzz62ajIq9jCeYNKQUIgtSCpafZk15FLc,910
@@ -67,12 +67,12 @@ digitalkin/services/storage/grpc_storage.py,sha256=BqWLK9w_03BEjlJCVbdrlbMvh2szG
67
67
  digitalkin/services/storage/storage_strategy.py,sha256=vGo4aYkEp_GZV11m7vd-xY_Z3gVa5K0gMTzbj2Au_3o,6600
68
68
  digitalkin/utils/__init__.py,sha256=sJnY-ZUgsjMfojAjONC1VN14mhgIDnzyOlGkw21rRnM,28
69
69
  digitalkin/utils/arg_parser.py,sha256=3YyI6oZhhrlTmPTrzlwpQzbCNWDFAT3pggcLxNtJoc0,4388
70
- digitalkin-0.2.3.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
70
+ digitalkin-0.2.4.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
71
71
  modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
- modules/minimal_llm_module.py,sha256=JrRPTx7DCYrbmnfkE98xWBU_6x5lr7i8MFP16ATKkfo,5531
73
- modules/storage_module.py,sha256=HktIy4j8-0w7ugMA7HqcNZymZIGruhchsWKXje9qR4o,6264
72
+ modules/minimal_llm_module.py,sha256=i9KTbv8w1ekzRYWDiRsxD6xLCoZ3uDjD_hWgfY2PRys,5637
73
+ modules/storage_module.py,sha256=bu52lW4RFcWB8VFDhrpBFfCaTSkVL6so3zrkfW4LO9E,6270
74
74
  modules/text_transform_module.py,sha256=fAC6r_Ujca1Tz1qdWL4hTPZFn3gFWIVNj5-rytQMObE,7191
75
- digitalkin-0.2.3.dist-info/METADATA,sha256=ckrSIFHPHRwPsf0W5wLoFue25_OSH4phzfRGiCIPoLk,29095
76
- digitalkin-0.2.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
77
- digitalkin-0.2.3.dist-info/top_level.txt,sha256=5_5e35inSM5YfWNZE21p5wGBojiVtQQML_WzbEk4BRU,31
78
- digitalkin-0.2.3.dist-info/RECORD,,
75
+ digitalkin-0.2.4.dist-info/METADATA,sha256=h_9hJnMdGTJZwkr0b5IZwSEO5l70sbtJmd5PNZhY0VI,29095
76
+ digitalkin-0.2.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
77
+ digitalkin-0.2.4.dist-info/top_level.txt,sha256=5_5e35inSM5YfWNZE21p5wGBojiVtQQML_WzbEk4BRU,31
78
+ digitalkin-0.2.4.dist-info/RECORD,,
@@ -82,7 +82,11 @@ class OpenAIToolModule(BaseModule[OpenAIToolInput, OpenAIToolOutput, OpenAIToolS
82
82
  "storage": {
83
83
  "config": {"setups": OpenAIToolSetup},
84
84
  "server_config": server_config,
85
- }
85
+ },
86
+ "filesystem": {
87
+ "config": {},
88
+ "server_config": server_config,
89
+ },
86
90
  }
87
91
 
88
92
  async def initialize(self, setup_data: SetupData) -> None:
modules/storage_module.py CHANGED
@@ -12,7 +12,7 @@ from digitalkin.models.module import ModuleStatus
12
12
  from digitalkin.modules.archetype_module import ArchetypeModule
13
13
  from digitalkin.services.services_config import ServicesConfig
14
14
  from digitalkin.services.services_models import ServicesMode
15
- from digitalkin.services.storage.storage_strategy import DataType, StorageRecord
15
+ from digitalkin.services.storage.storage_strategy import StorageRecord
16
16
 
17
17
 
18
18
  class ExampleInput(BaseModel):
@@ -62,7 +62,7 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
62
62
 
63
63
  # Define services_config_params with default values
64
64
  services_config_strategies = {}
65
- services_config_params = {"storage": {"config": {"example_outputs": ExampleOutput}}}
65
+ services_config_params = {"storage": {"config": {"example_outputs": ExampleOutput}}, "filesystem": {"config": {}}}
66
66
 
67
67
  def __init__(self, job_id: str, mission_id: str) -> None:
68
68
  """Initialize the example module.
@@ -119,7 +119,7 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
119
119
  )
120
120
 
121
121
  # Store the output data in storage
122
- storage_id = self.storage.store("example_outputs", output_data.model_dump(), data_type=DataType.OUTPUT)
122
+ storage_id = self.storage.store("example_outputs", output_data.model_dump(), data_type="OUTPUT")
123
123
 
124
124
  logger.info("Stored output data with ID: %s", storage_id)
125
125
 
@@ -170,7 +170,7 @@ def test_storage_directly() -> None:
170
170
  storage = ServicesConfig().storage(mission_id="test-mission", config={"test_table": ExampleStorage})
171
171
 
172
172
  # Create a test record
173
- storage.store("test_table", {"test_key": "test_value"}, DataType.OUTPUT)
173
+ storage.store("test_table", {"test_key": "test_value"}, "OUTPUT")
174
174
 
175
175
  # Retrieve the record
176
176
  retrieved = storage.read("test_table")