digitalkin 0.2.18__py3-none-any.whl → 0.2.20__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. digitalkin/__version__.py +1 -1
  2. digitalkin/grpc_servers/module_servicer.py +9 -7
  3. digitalkin/models/module/__init__.py +6 -6
  4. digitalkin/models/module/module_types.py +76 -14
  5. digitalkin/modules/_base_module.py +71 -46
  6. digitalkin/modules/archetype_module.py +0 -2
  7. digitalkin/modules/job_manager/base_job_manager.py +8 -7
  8. digitalkin/modules/job_manager/single_job_manager.py +19 -10
  9. digitalkin/modules/job_manager/taskiq_broker.py +6 -4
  10. digitalkin/modules/job_manager/taskiq_job_manager.py +9 -5
  11. digitalkin/modules/tool_module.py +1 -2
  12. digitalkin/services/base_strategy.py +3 -1
  13. digitalkin/services/cost/cost_strategy.py +9 -2
  14. digitalkin/services/cost/default_cost.py +3 -2
  15. digitalkin/services/cost/grpc_cost.py +2 -1
  16. digitalkin/services/filesystem/default_filesystem.py +9 -7
  17. digitalkin/services/filesystem/filesystem_strategy.py +10 -3
  18. digitalkin/services/filesystem/grpc_filesystem.py +10 -8
  19. digitalkin/services/services_config.py +3 -2
  20. digitalkin/services/storage/default_storage.py +2 -1
  21. digitalkin/services/storage/grpc_storage.py +6 -5
  22. digitalkin/services/storage/storage_strategy.py +9 -2
  23. digitalkin/utils/package_discover.py +2 -2
  24. {digitalkin-0.2.18.dist-info → digitalkin-0.2.20.dist-info}/METADATA +13 -13
  25. {digitalkin-0.2.18.dist-info → digitalkin-0.2.20.dist-info}/RECORD +28 -28
  26. {digitalkin-0.2.18.dist-info → digitalkin-0.2.20.dist-info}/WHEEL +0 -0
  27. {digitalkin-0.2.18.dist-info → digitalkin-0.2.20.dist-info}/licenses/LICENSE +0 -0
  28. {digitalkin-0.2.18.dist-info → digitalkin-0.2.20.dist-info}/top_level.txt +0 -0
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.18"
8
+ __version__ = "0.2.20"
@@ -105,7 +105,8 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
105
105
  setup_version = request.setup_version
106
106
  config_setup_data = self.module_class.create_config_setup_model(json_format.MessageToDict(request.content))
107
107
  setup_version_data = self.module_class.create_setup_model(
108
- json_format.MessageToDict(request.setup_version.content)
108
+ json_format.MessageToDict(request.setup_version.content),
109
+ config_fields=True,
109
110
  )
110
111
 
111
112
  if not setup_version_data:
@@ -119,8 +120,8 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
119
120
  # create a task to run the module in background
120
121
  job_id = await self.job_manager.create_config_setup_instance_job(
121
122
  config_setup_data,
122
- setup_version_data,
123
123
  request.mission_id,
124
+ setup_version.setup_id,
124
125
  setup_version.id,
125
126
  )
126
127
 
@@ -177,6 +178,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
177
178
  input_data,
178
179
  setup_data,
179
180
  mission_id=request.mission_id,
181
+ setup_id=setup_data_class.current_setup_version.setup_id,
180
182
  setup_version_id=setup_data_class.current_setup_version.id,
181
183
  )
182
184
 
@@ -333,7 +335,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
333
335
  except NotImplementedError as e:
334
336
  logger.warning(e)
335
337
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
336
- context.set_details(e)
338
+ context.set_details(str(e))
337
339
  return information_pb2.GetModuleInputResponse()
338
340
 
339
341
  return information_pb2.GetModuleInputResponse(
@@ -369,7 +371,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
369
371
  except NotImplementedError as e:
370
372
  logger.warning(e)
371
373
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
372
- context.set_details(e)
374
+ context.set_details(str(e))
373
375
  return information_pb2.GetModuleOutputResponse()
374
376
 
375
377
  return information_pb2.GetModuleOutputResponse(
@@ -405,7 +407,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
405
407
  except NotImplementedError as e:
406
408
  logger.warning(e)
407
409
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
408
- context.set_details(e)
410
+ context.set_details(str(e))
409
411
  return information_pb2.GetModuleSetupResponse()
410
412
 
411
413
  return information_pb2.GetModuleSetupResponse(
@@ -441,7 +443,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
441
443
  except NotImplementedError as e:
442
444
  logger.warning(e)
443
445
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
444
- context.set_details(e)
446
+ context.set_details(str(e))
445
447
  return information_pb2.GetModuleSecretResponse()
446
448
 
447
449
  return information_pb2.GetModuleSecretResponse(
@@ -477,7 +479,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
477
479
  except NotImplementedError as e:
478
480
  logger.warning(e)
479
481
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
480
- context.set_details(e)
482
+ context.set_details(str(e))
481
483
  return information_pb2.GetConfigSetupModuleResponse()
482
484
 
483
485
  return information_pb2.GetConfigSetupModuleResponse(
@@ -3,24 +3,24 @@
3
3
  from digitalkin.models.module.module import Module, ModuleStatus
4
4
  from digitalkin.models.module.module_context import ModuleContext
5
5
  from digitalkin.models.module.module_types import (
6
- ConfigSetupModelT,
7
- InputModel,
6
+ DataModel,
7
+ DataTrigger,
8
8
  InputModelT,
9
- InputTrigger,
10
9
  OutputModelT,
11
10
  SecretModelT,
11
+ SetupModel,
12
12
  SetupModelT,
13
13
  )
14
14
 
15
15
  __all__ = [
16
- "ConfigSetupModelT",
17
- "InputModel",
16
+ "DataModel",
17
+ "DataTrigger",
18
18
  "InputModelT",
19
- "InputTrigger",
20
19
  "Module",
21
20
  "ModuleContext",
22
21
  "ModuleStatus",
23
22
  "OutputModelT",
24
23
  "SecretModelT",
24
+ "SetupModel",
25
25
  "SetupModelT",
26
26
  ]
@@ -1,43 +1,105 @@
1
1
  """Types for module models."""
2
2
 
3
- from typing import TypeVar
3
+ from datetime import datetime, timezone
4
+ from typing import Any, ClassVar, Generic, TypeVar, cast
4
5
 
5
- from pydantic import BaseModel
6
+ from pydantic import BaseModel, ConfigDict, Field, create_model
6
7
 
8
+ from digitalkin.logger import logger
7
9
 
8
- class InputTrigger(BaseModel):
10
+
11
+ class DataTrigger(BaseModel):
9
12
  """Defines the root input model exposing the protocol.
10
13
 
11
14
  The mandatory protocol is important to define the module beahvior following the user or agent input.
12
15
 
13
16
  Example:
14
- class MyInput(InputModel):
15
- root: InputTrigger
17
+ class MyInput(DataModel):
18
+ root: DataTrigger
16
19
  user_define_data: Any
17
20
 
18
21
  # Usage
19
- my_input = MyInput(root=InputTrigger(protocol="message"))
22
+ my_input = MyInput(root=DataTrigger(protocol="message"))
20
23
  print(my_input.root.protocol) # Output: message
21
24
  """
22
25
 
23
- protocol: str
26
+ protocol: ClassVar[str]
27
+ created_at: str = datetime.now(tz=timezone.utc).isoformat()
28
+
29
+
30
+ DataTriggerT = TypeVar("DataTriggerT", bound=DataTrigger)
24
31
 
25
32
 
26
- class InputModel(BaseModel):
33
+ class DataModel(BaseModel, Generic[DataTriggerT]):
27
34
  """Base definition of input model showing mandatory root fields.
28
35
 
29
36
  The Model define the Module Input, usually referring to multiple input type defined by an union.
30
37
 
31
38
  Example:
32
- class ModuleInput(InputModel):
39
+ class ModuleInput(DataModel):
33
40
  root: FileInput | MessageInput
34
41
  """
35
42
 
36
- root: InputTrigger
43
+ root: DataTriggerT
44
+ annotations: dict[str, str] = Field(
45
+ default={},
46
+ title="Annotations",
47
+ description="Additional metadata or annotations related to the output. ex {'role': 'user'}",
48
+ )
37
49
 
38
50
 
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)
51
+ InputModelT = TypeVar("InputModelT", bound=DataModel)
52
+ OutputModelT = TypeVar("OutputModelT", bound=DataModel)
43
53
  SecretModelT = TypeVar("SecretModelT", bound=BaseModel)
54
+ SetupModelT = TypeVar("SetupModelT", bound="SetupModel")
55
+
56
+
57
+ class SetupModel(BaseModel):
58
+ """Base definition of setup model showing mandatory root fields.
59
+
60
+ Optionally, the setup model can define a config option in json_schema_extra to be used to initialize the Kin.
61
+
62
+ Example:
63
+ class MySetup(SetupModel):
64
+ name: str = Field()
65
+ number: int = Field(..., json_schema_extra={"config": True})
66
+ """
67
+
68
+ @classmethod
69
+ def get_clean_model(cls, *, config_fields: bool, hidden_fields: bool) -> type[SetupModelT]: # type: ignore
70
+ """Dynamically builds and returns a new BaseModel subclass.
71
+
72
+ containing only those fields where json_schema_extra["config"] == True.
73
+
74
+ Returns:
75
+ Type[BaseModel]: A new BaseModel subclass with the filtered fields.
76
+
77
+ Raises:
78
+ ValueError: If both config_fields and hidden_fields are set to True.
79
+ """
80
+ clean_fields: dict[str, Any] = {}
81
+ for name, field_info in cls.model_fields.items():
82
+ extra = getattr(field_info, "json_schema_extra", {}) or {}
83
+ is_config = bool(extra.get("config", False))
84
+ is_hidden = bool(extra.get("hidden", False))
85
+
86
+ # Skip config unless explicitly included
87
+ if is_config and not config_fields:
88
+ logger.debug("Skipping '%s' (config-only)", name)
89
+ continue
90
+
91
+ # Skip hidden unless explicitly included
92
+ if is_hidden and not hidden_fields:
93
+ logger.debug("Skipping '%s' (hidden-only)", name)
94
+ continue
95
+
96
+ clean_fields[name] = (field_info.annotation, field_info)
97
+
98
+ # Dynamically create a model e.g. "SetupModel"
99
+ m = create_model(
100
+ f"{cls.__name__}",
101
+ __base__=BaseModel,
102
+ __config__=ConfigDict(arbitrary_types_allowed=True),
103
+ **clean_fields,
104
+ )
105
+ return cast("type[SetupModelT]", m)
@@ -9,10 +9,8 @@ from typing import Any, ClassVar, Generic
9
9
 
10
10
  from pydantic import BaseModel
11
11
 
12
- from digitalkin.grpc_servers.utils.exceptions import OptionalFeatureNotImplementedError
13
12
  from digitalkin.logger import logger
14
13
  from digitalkin.models.module import (
15
- ConfigSetupModelT,
16
14
  InputModelT,
17
15
  ModuleStatus,
18
16
  OutputModelT,
@@ -33,11 +31,11 @@ from digitalkin.utils.llm_ready_schema import llm_ready_schema
33
31
  from digitalkin.utils.package_discover import ModuleDiscoverer
34
32
 
35
33
 
36
- class ModuleErrorModel(BaseModel):
34
+ class ModuleCodeModel(BaseModel):
37
35
  """typed error/code model."""
38
36
 
39
37
  code: str
40
- exception: str
38
+ message: str
41
39
  short_description: str
42
40
 
43
41
 
@@ -48,7 +46,6 @@ class BaseModule( # noqa: PLR0904
48
46
  OutputModelT,
49
47
  SetupModelT,
50
48
  SecretModelT,
51
- ConfigSetupModelT,
52
49
  ],
53
50
  ):
54
51
  """BaseModule is the abstract base for all modules in the DigitalKin SDK."""
@@ -56,10 +53,9 @@ class BaseModule( # noqa: PLR0904
56
53
  name: str
57
54
  description: str
58
55
 
59
- config_setup_format: type[ConfigSetupModelT]
56
+ setup_format: type[SetupModelT]
60
57
  input_format: type[InputModelT]
61
58
  output_format: type[OutputModelT]
62
- setup_format: type[SetupModelT]
63
59
  secret_format: type[SecretModelT]
64
60
  metadata: ClassVar[dict[str, Any]]
65
61
 
@@ -80,21 +76,38 @@ class BaseModule( # noqa: PLR0904
80
76
  snapshot: SnapshotStrategy
81
77
  storage: StorageStrategy
82
78
 
79
+ # runtime params
80
+ job_id: str
81
+ mission_id: str
82
+ setup_id: str
83
+ setup_version_id: str
84
+ _status: ModuleStatus
85
+ _task: asyncio.Task | None
86
+
83
87
  def _init_strategies(self) -> None:
84
88
  """Initialize the services configuration."""
85
89
  for service_name in self.services_config.valid_strategy_names():
86
- service = self.services_config.init_strategy(service_name, self.mission_id, self.setup_version_id)
90
+ service = self.services_config.init_strategy(
91
+ service_name,
92
+ self.mission_id,
93
+ self.setup_id,
94
+ self.setup_version_id,
95
+ )
87
96
  setattr(self, service_name, service)
88
97
 
89
98
  def __init__(
90
99
  self,
91
100
  job_id: str,
92
101
  mission_id: str,
102
+ setup_id: str,
93
103
  setup_version_id: str,
94
104
  ) -> None:
95
105
  """Initialize the module."""
96
106
  self.job_id: str = job_id
97
107
  self.mission_id: str = mission_id
108
+ # Setup reference needed for the overall Kin scope as the filesystem context
109
+ self.setup_id: str = setup_id
110
+ # SetupVersion reference needed for the precise Kin scope as the cost
98
111
  self.setup_version_id: str = setup_version_id
99
112
  self._status = ModuleStatus.CREATED
100
113
  self._task: asyncio.Task | None = None
@@ -172,20 +185,22 @@ class BaseModule( # noqa: PLR0904
172
185
  def get_config_setup_format(cls, *, llm_format: bool) -> str:
173
186
  """Gets the JSON schema of the config setup format model.
174
187
 
188
+ The config setup format is used only to initialize the module with configuration data.
189
+ The setup format is used to initialize an run the module with setup data.
190
+
175
191
  Raises:
176
- OptionalFeatureNotImplementedError: If the `config_setup_format` is not defined.
192
+ NotImplementedError: If the `setup_format` is not defined.
177
193
 
178
194
  Returns:
179
195
  The JSON schema of the config setup format as a string.
180
196
  """
181
- config_setup_format = getattr(cls, "config_setup_format", None)
182
-
183
- if config_setup_format is not None:
197
+ if cls.setup_format is not None:
198
+ setup_format = cls.setup_format.get_clean_model(config_fields=True, hidden_fields=False)
184
199
  if llm_format:
185
- return json.dumps(llm_ready_schema(config_setup_format), indent=2)
186
- return json.dumps(config_setup_format.model_json_schema(), indent=2)
200
+ return json.dumps(llm_ready_schema(setup_format), indent=2)
201
+ return json.dumps(setup_format.model_json_schema(), indent=2)
187
202
  msg = "'%s' class does not define an 'config_setup_format'."
188
- raise OptionalFeatureNotImplementedError(msg)
203
+ raise NotImplementedError(msg)
189
204
 
190
205
  @classmethod
191
206
  def get_setup_format(cls, *, llm_format: bool) -> str:
@@ -198,14 +213,15 @@ class BaseModule( # noqa: PLR0904
198
213
  The JSON schema of the setup format as a string.
199
214
  """
200
215
  if cls.setup_format is not None:
216
+ setup_format = cls.setup_format.get_clean_model(config_fields=False, hidden_fields=True)
201
217
  if llm_format:
202
- return json.dumps(llm_ready_schema(cls.setup_format), indent=2)
203
- return json.dumps(cls.setup_format.model_json_schema(), indent=2)
218
+ return json.dumps(llm_ready_schema(setup_format), indent=2)
219
+ return json.dumps(setup_format.model_json_schema(), indent=2)
204
220
  msg = "'%s' class does not define an 'setup_format'."
205
221
  raise NotImplementedError(msg)
206
222
 
207
223
  @classmethod
208
- def create_config_setup_model(cls, config_setup_data: dict[str, Any]) -> ConfigSetupModelT:
224
+ def create_config_setup_model(cls, config_setup_data: dict[str, Any]) -> SetupModelT:
209
225
  """Create the setup model from the setup data.
210
226
 
211
227
  Args:
@@ -214,7 +230,7 @@ class BaseModule( # noqa: PLR0904
214
230
  Returns:
215
231
  The setup model.
216
232
  """
217
- return cls.config_setup_format(**config_setup_data)
233
+ return cls.setup_format(**config_setup_data)
218
234
 
219
235
  @classmethod
220
236
  def create_input_model(cls, input_data: dict[str, Any]) -> InputModelT:
@@ -229,16 +245,17 @@ class BaseModule( # noqa: PLR0904
229
245
  return cls.input_format(**input_data)
230
246
 
231
247
  @classmethod
232
- def create_setup_model(cls, setup_data: dict[str, Any]) -> SetupModelT:
248
+ def create_setup_model(cls, setup_data: dict[str, Any], *, config_fields: bool = False) -> SetupModelT:
233
249
  """Create the setup model from the setup data.
234
250
 
235
251
  Args:
236
252
  setup_data: The setup data to create the model from.
253
+ config_fields: If True, include only fields with json_schema_extra["config"] == True.
237
254
 
238
255
  Returns:
239
256
  The setup model.
240
257
  """
241
- return cls.setup_format(**setup_data)
258
+ return cls.setup_format.get_clean_model(config_fields=config_fields, hidden_fields=True)(**setup_data)
242
259
 
243
260
  @classmethod
244
261
  def create_secret_model(cls, secret_data: dict[str, Any]) -> SecretModelT:
@@ -290,20 +307,20 @@ class BaseModule( # noqa: PLR0904
290
307
  """
291
308
  return cls.triggers_discoverer.register_trigger(handler_cls)
292
309
 
293
- @abstractmethod
294
- async def run_config_setup(
295
- self,
296
- config_setup_data: ConfigSetupModelT,
297
- setup_data: SetupModelT,
298
- callback: Callable,
299
- ) -> None:
310
+ async def run_config_setup(self, config_setup_data: SetupModelT) -> SetupModelT: # noqa: PLR6301
300
311
  """Run config setup the module.
301
312
 
302
- Raises:
303
- OptionalFeatureNotImplementedError: If the config setup feature is not implemented.
313
+ The config setup is used to initialize the setup with configuration data.
314
+ This method is typically used to set up the module with necessary configuration before running it,
315
+ especially for processing data like files.
316
+ The function needs to save the setup in the storage.
317
+ The module will be initialize with the setup and not the config setup.
318
+ This method is optional, the config setup and setup can be the same.
319
+
320
+ Returns:
321
+ The updated setup model after running the config setup.
304
322
  """
305
- msg = f"'{self}' class does not define an optional 'run_config_setup' attribute."
306
- raise OptionalFeatureNotImplementedError(msg)
323
+ return config_setup_data
307
324
 
308
325
  @abstractmethod
309
326
  async def initialize(self, setup_data: SetupModelT) -> None:
@@ -364,9 +381,9 @@ class BaseModule( # noqa: PLR0904
364
381
  asyncio.CancelledError: If the module is cancelled
365
382
  """
366
383
  try:
367
- logger.warning("Starting module %s", self.name)
384
+ logger.info("Starting module %s", self.name)
368
385
  await self.run(input_data, setup_data, callback)
369
- logger.warning("Module %s finished", self.name)
386
+ logger.info("Module %s finished", self.name)
370
387
  except asyncio.CancelledError:
371
388
  self._status = ModuleStatus.CANCELLED
372
389
  logger.error(f"Module {self.name} cancelled")
@@ -374,7 +391,7 @@ class BaseModule( # noqa: PLR0904
374
391
  self._status = ModuleStatus.FAILED
375
392
  logger.exception("Error inside module %s", self.name)
376
393
  else:
377
- self._status = ModuleStatus.STOPPED
394
+ self._status = ModuleStatus.STOPPING
378
395
  finally:
379
396
  await self.stop()
380
397
 
@@ -382,22 +399,22 @@ class BaseModule( # noqa: PLR0904
382
399
  self,
383
400
  input_data: InputModelT,
384
401
  setup_data: SetupModelT,
385
- callback: Callable[[OutputModelT | ModuleErrorModel], Coroutine[Any, Any, None]],
402
+ callback: Callable[[OutputModelT | ModuleCodeModel], Coroutine[Any, Any, None]],
386
403
  done_callback: Callable | None = None,
387
404
  ) -> None:
388
405
  """Start the module."""
389
406
  try:
390
- logger.info("Inititalize module")
407
+ logger.debug("Inititalize module")
391
408
  await self.initialize(setup_data=setup_data)
392
409
  except Exception as e:
393
410
  self._status = ModuleStatus.FAILED
394
411
  short_description = "Error initializing module"
395
412
  logger.exception("%s: %s", short_description, e)
396
413
  await callback(
397
- ModuleErrorModel(
414
+ ModuleCodeModel(
398
415
  code=str(self._status),
399
416
  short_description=short_description,
400
- exception=str(e),
417
+ message=str(e),
401
418
  )
402
419
  )
403
420
  if done_callback is not None:
@@ -406,9 +423,9 @@ class BaseModule( # noqa: PLR0904
406
423
  return
407
424
 
408
425
  try:
409
- logger.info("Init the discod input handlers.")
426
+ logger.debug("Init the discovered input handlers.")
410
427
  self.triggers_discoverer.init_handlers(self.context)
411
- logger.info("Run lifecycle")
428
+ logger.debug("Run lifecycle")
412
429
  self._status = ModuleStatus.RUNNING
413
430
  self._task = asyncio.create_task(
414
431
  self._run_lifecycle(input_data, setup_data, callback),
@@ -422,7 +439,8 @@ class BaseModule( # noqa: PLR0904
422
439
 
423
440
  async def stop(self) -> None:
424
441
  """Stop the module."""
425
- if self._status != ModuleStatus.RUNNING:
442
+ logger.info("Stopping module %s with status %s", self.name, self._status)
443
+ if self._status not in {ModuleStatus.RUNNING, ModuleStatus.STOPPING}:
426
444
  return
427
445
 
428
446
  try:
@@ -431,22 +449,29 @@ class BaseModule( # noqa: PLR0904
431
449
  self._task.cancel()
432
450
  with contextlib.suppress(asyncio.CancelledError):
433
451
  await self._task
452
+ logger.debug("Module %s stopped", self.name)
434
453
  await self.cleanup()
454
+ self._status = ModuleStatus.STOPPED
455
+ logger.debug("Module %s cleaned", self.name)
435
456
  except Exception:
436
457
  self._status = ModuleStatus.FAILED
437
458
  logger.exception("Error stopping module")
438
459
 
439
460
  async def start_config_setup(
440
461
  self,
441
- config_setup_data: ConfigSetupModelT,
442
- setup_data: SetupModelT,
443
- callback: Callable[[OutputModelT | ModuleErrorModel], Coroutine[Any, Any, None]],
462
+ config_setup_data: SetupModelT,
463
+ callback: Callable[[SetupModelT | ModuleCodeModel], Coroutine[Any, Any, None]],
444
464
  ) -> None:
445
465
  """Start the module."""
446
466
  try:
447
467
  logger.info("Run Config Setup lifecycle")
448
468
  self._status = ModuleStatus.RUNNING
449
- await self.run_config_setup(config_setup_data, setup_data, callback)
469
+ content = await self.run_config_setup(config_setup_data)
470
+
471
+ wrapper = config_setup_data.model_dump()
472
+ wrapper["content"] = content.model_dump()
473
+ await callback(self.create_setup_model(wrapper))
474
+ self._status = ModuleStatus.STOPPING
450
475
  except Exception:
451
476
  self._status = ModuleStatus.FAILED
452
477
  logger.exception("Error during module lifecyle")
@@ -3,7 +3,6 @@
3
3
  from abc import ABC
4
4
 
5
5
  from digitalkin.models.module import InputModelT, OutputModelT, SecretModelT, SetupModelT
6
- from digitalkin.models.module.module_types import ConfigSetupModelT
7
6
  from digitalkin.modules._base_module import BaseModule
8
7
 
9
8
 
@@ -13,7 +12,6 @@ class ArchetypeModule(
13
12
  OutputModelT,
14
13
  SetupModelT,
15
14
  SecretModelT,
16
- ConfigSetupModelT,
17
15
  ],
18
16
  ABC,
19
17
  ):
@@ -7,13 +7,12 @@ from typing import Any, Generic
7
7
 
8
8
  from digitalkin.models import ModuleStatus
9
9
  from digitalkin.models.module import InputModelT, OutputModelT, SetupModelT
10
- from digitalkin.models.module.module_types import ConfigSetupModelT
11
10
  from digitalkin.modules._base_module import BaseModule
12
11
  from digitalkin.services.services_config import ServicesConfig
13
12
  from digitalkin.services.services_models import ServicesMode
14
13
 
15
14
 
16
- class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT, ConfigSetupModelT]):
15
+ class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT]):
17
16
  """Abstract base class for managing background module jobs."""
18
17
 
19
18
  async def _start(self) -> None:
@@ -88,6 +87,7 @@ class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT, ConfigSetupModel
88
87
  input_data: InputModelT,
89
88
  setup_data: SetupModelT,
90
89
  mission_id: str,
90
+ setup_id: str,
91
91
  setup_version_id: str,
92
92
  ) -> str:
93
93
  """Create and start a new job for the module's instance.
@@ -96,7 +96,8 @@ class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT, ConfigSetupModel
96
96
  input_data: The input data required to start the job.
97
97
  setup_data: The setup configuration for the module.
98
98
  mission_id: The mission ID associated with the job.
99
- setup_version_id: The setup ID associated with the module.
99
+ setup_id: The setup ID.
100
+ setup_version_id: The setup version ID associated with the module.
100
101
 
101
102
  Returns:
102
103
  str: The unique identifier (job ID) of the created job.
@@ -120,9 +121,9 @@ class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT, ConfigSetupModel
120
121
  @abc.abstractmethod
121
122
  async def create_config_setup_instance_job(
122
123
  self,
123
- config_setup_data: ConfigSetupModelT,
124
- setup_data: SetupModelT,
124
+ config_setup_data: SetupModelT,
125
125
  mission_id: str,
126
+ setup_id: str,
126
127
  setup_version_id: str,
127
128
  ) -> str:
128
129
  """Create and start a new module job.
@@ -132,9 +133,9 @@ class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT, ConfigSetupModel
132
133
 
133
134
  Args:
134
135
  config_setup_data: The input data required to start the job.
135
- setup_data: The setup configuration for the module.
136
136
  mission_id: The mission ID associated with the job.
137
- setup_version_id: The setup ID.
137
+ setup_id: The setup ID.
138
+ setup_version_id: The setup version ID.
138
139
 
139
140
  Returns:
140
141
  str: The unique identifier (job ID) of the created job.