digitalkin 0.2.17__py3-none-any.whl → 0.2.19__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.17"
8
+ __version__ = "0.2.19"
@@ -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,7 +120,6 @@ 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
124
  setup_version.id,
125
125
  )
@@ -333,7 +333,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
333
333
  except NotImplementedError as e:
334
334
  logger.warning(e)
335
335
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
336
- context.set_details(e)
336
+ context.set_details(str(e))
337
337
  return information_pb2.GetModuleInputResponse()
338
338
 
339
339
  return information_pb2.GetModuleInputResponse(
@@ -369,7 +369,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
369
369
  except NotImplementedError as e:
370
370
  logger.warning(e)
371
371
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
372
- context.set_details(e)
372
+ context.set_details(str(e))
373
373
  return information_pb2.GetModuleOutputResponse()
374
374
 
375
375
  return information_pb2.GetModuleOutputResponse(
@@ -405,7 +405,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
405
405
  except NotImplementedError as e:
406
406
  logger.warning(e)
407
407
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
408
- context.set_details(e)
408
+ context.set_details(str(e))
409
409
  return information_pb2.GetModuleSetupResponse()
410
410
 
411
411
  return information_pb2.GetModuleSetupResponse(
@@ -441,7 +441,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
441
441
  except NotImplementedError as e:
442
442
  logger.warning(e)
443
443
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
444
- context.set_details(e)
444
+ context.set_details(str(e))
445
445
  return information_pb2.GetModuleSecretResponse()
446
446
 
447
447
  return information_pb2.GetModuleSecretResponse(
@@ -477,7 +477,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
477
477
  except NotImplementedError as e:
478
478
  logger.warning(e)
479
479
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
480
- context.set_details(e)
480
+ context.set_details(str(e))
481
481
  return information_pb2.GetConfigSetupModuleResponse()
482
482
 
483
483
  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,10 @@ 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]
57
+
60
58
  input_format: type[InputModelT]
61
59
  output_format: type[OutputModelT]
62
- setup_format: type[SetupModelT]
63
60
  secret_format: type[SecretModelT]
64
61
  metadata: ClassVar[dict[str, Any]]
65
62
 
@@ -172,20 +169,22 @@ class BaseModule( # noqa: PLR0904
172
169
  def get_config_setup_format(cls, *, llm_format: bool) -> str:
173
170
  """Gets the JSON schema of the config setup format model.
174
171
 
172
+ The config setup format is used only to initialize the module with configuration data.
173
+ The setup format is used to initialize an run the module with setup data.
174
+
175
175
  Raises:
176
- OptionalFeatureNotImplementedError: If the `config_setup_format` is not defined.
176
+ NotImplementedError: If the `setup_format` is not defined.
177
177
 
178
178
  Returns:
179
179
  The JSON schema of the config setup format as a string.
180
180
  """
181
- config_setup_format = getattr(cls, "config_setup_format", None)
182
-
183
- if config_setup_format is not None:
181
+ if cls.setup_format is not None:
182
+ setup_format = cls.setup_format.get_clean_model(config_fields=True, hidden_fields=False)
184
183
  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)
184
+ return json.dumps(llm_ready_schema(setup_format), indent=2)
185
+ return json.dumps(setup_format.model_json_schema(), indent=2)
187
186
  msg = "'%s' class does not define an 'config_setup_format'."
188
- raise OptionalFeatureNotImplementedError(msg)
187
+ raise NotImplementedError(msg)
189
188
 
190
189
  @classmethod
191
190
  def get_setup_format(cls, *, llm_format: bool) -> str:
@@ -198,14 +197,15 @@ class BaseModule( # noqa: PLR0904
198
197
  The JSON schema of the setup format as a string.
199
198
  """
200
199
  if cls.setup_format is not None:
200
+ setup_format = cls.setup_format.get_clean_model(config_fields=False, hidden_fields=True)
201
201
  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)
202
+ return json.dumps(llm_ready_schema(setup_format), indent=2)
203
+ return json.dumps(setup_format.model_json_schema(), indent=2)
204
204
  msg = "'%s' class does not define an 'setup_format'."
205
205
  raise NotImplementedError(msg)
206
206
 
207
207
  @classmethod
208
- def create_config_setup_model(cls, config_setup_data: dict[str, Any]) -> ConfigSetupModelT:
208
+ def create_config_setup_model(cls, config_setup_data: dict[str, Any]) -> SetupModelT:
209
209
  """Create the setup model from the setup data.
210
210
 
211
211
  Args:
@@ -214,7 +214,7 @@ class BaseModule( # noqa: PLR0904
214
214
  Returns:
215
215
  The setup model.
216
216
  """
217
- return cls.config_setup_format(**config_setup_data)
217
+ return cls.setup_format(**config_setup_data)
218
218
 
219
219
  @classmethod
220
220
  def create_input_model(cls, input_data: dict[str, Any]) -> InputModelT:
@@ -229,16 +229,17 @@ class BaseModule( # noqa: PLR0904
229
229
  return cls.input_format(**input_data)
230
230
 
231
231
  @classmethod
232
- def create_setup_model(cls, setup_data: dict[str, Any]) -> SetupModelT:
232
+ def create_setup_model(cls, setup_data: dict[str, Any], *, config_fields: bool = False) -> SetupModelT:
233
233
  """Create the setup model from the setup data.
234
234
 
235
235
  Args:
236
236
  setup_data: The setup data to create the model from.
237
+ config_fields: If True, include only fields with json_schema_extra["config"] == True.
237
238
 
238
239
  Returns:
239
240
  The setup model.
240
241
  """
241
- return cls.setup_format(**setup_data)
242
+ return cls.setup_format.get_clean_model(config_fields=config_fields, hidden_fields=True)(**setup_data)
242
243
 
243
244
  @classmethod
244
245
  def create_secret_model(cls, secret_data: dict[str, Any]) -> SecretModelT:
@@ -290,20 +291,20 @@ class BaseModule( # noqa: PLR0904
290
291
  """
291
292
  return cls.triggers_discoverer.register_trigger(handler_cls)
292
293
 
293
- @abstractmethod
294
- async def run_config_setup(
295
- self,
296
- config_setup_data: ConfigSetupModelT,
297
- setup_data: SetupModelT,
298
- callback: Callable,
299
- ) -> None:
294
+ async def run_config_setup(self, config_setup_data: SetupModelT) -> SetupModelT: # noqa: PLR6301
300
295
  """Run config setup the module.
301
296
 
302
- Raises:
303
- OptionalFeatureNotImplementedError: If the config setup feature is not implemented.
297
+ The config setup is used to initialize the setup with configuration data.
298
+ This method is typically used to set up the module with necessary configuration before running it,
299
+ especially for processing data like files.
300
+ The function needs to save the setup in the storage.
301
+ The module will be initialize with the setup and not the config setup.
302
+ This method is optional, the config setup and setup can be the same.
303
+
304
+ Returns:
305
+ The updated setup model after running the config setup.
304
306
  """
305
- msg = f"'{self}' class does not define an optional 'run_config_setup' attribute."
306
- raise OptionalFeatureNotImplementedError(msg)
307
+ return config_setup_data
307
308
 
308
309
  @abstractmethod
309
310
  async def initialize(self, setup_data: SetupModelT) -> None:
@@ -364,9 +365,9 @@ class BaseModule( # noqa: PLR0904
364
365
  asyncio.CancelledError: If the module is cancelled
365
366
  """
366
367
  try:
367
- logger.warning("Starting module %s", self.name)
368
+ logger.info("Starting module %s", self.name)
368
369
  await self.run(input_data, setup_data, callback)
369
- logger.warning("Module %s finished", self.name)
370
+ logger.info("Module %s finished", self.name)
370
371
  except asyncio.CancelledError:
371
372
  self._status = ModuleStatus.CANCELLED
372
373
  logger.error(f"Module {self.name} cancelled")
@@ -374,7 +375,7 @@ class BaseModule( # noqa: PLR0904
374
375
  self._status = ModuleStatus.FAILED
375
376
  logger.exception("Error inside module %s", self.name)
376
377
  else:
377
- self._status = ModuleStatus.STOPPED
378
+ self._status = ModuleStatus.STOPPING
378
379
  finally:
379
380
  await self.stop()
380
381
 
@@ -382,22 +383,22 @@ class BaseModule( # noqa: PLR0904
382
383
  self,
383
384
  input_data: InputModelT,
384
385
  setup_data: SetupModelT,
385
- callback: Callable[[OutputModelT | ModuleErrorModel], Coroutine[Any, Any, None]],
386
+ callback: Callable[[OutputModelT | ModuleCodeModel], Coroutine[Any, Any, None]],
386
387
  done_callback: Callable | None = None,
387
388
  ) -> None:
388
389
  """Start the module."""
389
390
  try:
390
- logger.info("Inititalize module")
391
+ logger.debug("Inititalize module")
391
392
  await self.initialize(setup_data=setup_data)
392
393
  except Exception as e:
393
394
  self._status = ModuleStatus.FAILED
394
395
  short_description = "Error initializing module"
395
396
  logger.exception("%s: %s", short_description, e)
396
397
  await callback(
397
- ModuleErrorModel(
398
+ ModuleCodeModel(
398
399
  code=str(self._status),
399
400
  short_description=short_description,
400
- exception=str(e),
401
+ message=str(e),
401
402
  )
402
403
  )
403
404
  if done_callback is not None:
@@ -406,9 +407,9 @@ class BaseModule( # noqa: PLR0904
406
407
  return
407
408
 
408
409
  try:
409
- logger.info("Init the discod input handlers.")
410
+ logger.debug("Init the discovered input handlers.")
410
411
  self.triggers_discoverer.init_handlers(self.context)
411
- logger.info("Run lifecycle")
412
+ logger.debug("Run lifecycle")
412
413
  self._status = ModuleStatus.RUNNING
413
414
  self._task = asyncio.create_task(
414
415
  self._run_lifecycle(input_data, setup_data, callback),
@@ -422,7 +423,8 @@ class BaseModule( # noqa: PLR0904
422
423
 
423
424
  async def stop(self) -> None:
424
425
  """Stop the module."""
425
- if self._status != ModuleStatus.RUNNING:
426
+ logger.info("Stopping module %s with status %s", self.name, self._status)
427
+ if self._status not in {ModuleStatus.RUNNING, ModuleStatus.STOPPING}:
426
428
  return
427
429
 
428
430
  try:
@@ -431,22 +433,29 @@ class BaseModule( # noqa: PLR0904
431
433
  self._task.cancel()
432
434
  with contextlib.suppress(asyncio.CancelledError):
433
435
  await self._task
436
+ logger.debug("Module %s stopped", self.name)
434
437
  await self.cleanup()
438
+ self._status = ModuleStatus.STOPPED
439
+ logger.debug("Module %s cleaned", self.name)
435
440
  except Exception:
436
441
  self._status = ModuleStatus.FAILED
437
442
  logger.exception("Error stopping module")
438
443
 
439
444
  async def start_config_setup(
440
445
  self,
441
- config_setup_data: ConfigSetupModelT,
442
- setup_data: SetupModelT,
443
- callback: Callable[[OutputModelT | ModuleErrorModel], Coroutine[Any, Any, None]],
446
+ config_setup_data: SetupModelT,
447
+ callback: Callable[[SetupModelT | ModuleCodeModel], Coroutine[Any, Any, None]],
444
448
  ) -> None:
445
449
  """Start the module."""
446
450
  try:
447
451
  logger.info("Run Config Setup lifecycle")
448
452
  self._status = ModuleStatus.RUNNING
449
- await self.run_config_setup(config_setup_data, setup_data, callback)
453
+ content = await self.run_config_setup(config_setup_data)
454
+
455
+ wrapper = config_setup_data.model_dump()
456
+ wrapper["content"] = content.model_dump()
457
+ await callback(self.create_setup_model(wrapper))
458
+ self._status = ModuleStatus.STOPPING
450
459
  except Exception:
451
460
  self._status = ModuleStatus.FAILED
452
461
  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:
@@ -120,8 +119,7 @@ class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT, ConfigSetupModel
120
119
  @abc.abstractmethod
121
120
  async def create_config_setup_instance_job(
122
121
  self,
123
- config_setup_data: ConfigSetupModelT,
124
- setup_data: SetupModelT,
122
+ config_setup_data: SetupModelT,
125
123
  mission_id: str,
126
124
  setup_version_id: str,
127
125
  ) -> str:
@@ -132,7 +130,6 @@ class BaseJobManager(abc.ABC, Generic[InputModelT, SetupModelT, ConfigSetupModel
132
130
 
133
131
  Args:
134
132
  config_setup_data: The input data required to start the job.
135
- setup_data: The setup configuration for the module.
136
133
  mission_id: The mission ID associated with the job.
137
134
  setup_version_id: The setup ID.
138
135
 
@@ -10,13 +10,14 @@ import grpc
10
10
 
11
11
  from digitalkin.logger import logger
12
12
  from digitalkin.models import ModuleStatus
13
- from digitalkin.models.module import ConfigSetupModelT, InputModelT, OutputModelT, SetupModelT
13
+ from digitalkin.models.module import InputModelT, OutputModelT, SetupModelT
14
14
  from digitalkin.modules._base_module import BaseModule
15
15
  from digitalkin.modules.job_manager.base_job_manager import BaseJobManager
16
+ from digitalkin.modules.job_manager.job_manager_models import StreamCodeModel
16
17
  from digitalkin.services.services_models import ServicesMode
17
18
 
18
19
 
19
- class SingleJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigSetupModelT]):
20
+ class SingleJobManager(BaseJobManager, Generic[InputModelT, SetupModelT]):
20
21
  """Manages a single instance of a module job.
21
22
 
22
23
  This class ensures that only one instance of a module job is active at a time.
@@ -68,8 +69,7 @@ class SingleJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigS
68
69
 
69
70
  async def create_config_setup_instance_job(
70
71
  self,
71
- config_setup_data: ConfigSetupModelT,
72
- setup_data: SetupModelT,
72
+ config_setup_data: SetupModelT,
73
73
  mission_id: str,
74
74
  setup_version_id: str,
75
75
  ) -> str:
@@ -99,7 +99,6 @@ class SingleJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigS
99
99
  try:
100
100
  await module.start_config_setup(
101
101
  config_setup_data,
102
- setup_data,
103
102
  await self.job_specific_callback(self.add_to_queue, job_id),
104
103
  )
105
104
  logger.debug("Module %s (%s) started successfully", job_id, module.name)
@@ -166,7 +165,6 @@ class SingleJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigS
166
165
  ):
167
166
  logger.info(f"{job_id=}: {module.status=}")
168
167
  yield await self.queues[job_id].get()
169
- logger.info(f"{job_id=}: {module.status=} | {self.queues[job_id].empty()}")
170
168
 
171
169
  finally:
172
170
  del self.queues[job_id]
@@ -202,12 +200,14 @@ class SingleJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigS
202
200
  module = self.module_class(job_id, mission_id=mission_id, setup_version_id=setup_version_id)
203
201
  self.modules[job_id] = module
204
202
  self.queues[job_id] = asyncio.Queue()
203
+ callback = await self.job_specific_callback(self.add_to_queue, job_id)
205
204
 
206
205
  try:
207
206
  await module.start(
208
207
  input_data,
209
208
  setup_data,
210
- await self.job_specific_callback(self.add_to_queue, job_id),
209
+ callback,
210
+ done_callback=lambda _: asyncio.create_task(callback(StreamCodeModel(code="__END_OF_STREAM__"))),
211
211
  )
212
212
  logger.debug("Module %s (%s) started successfully", job_id, module.name)
213
213
  except Exception:
@@ -180,7 +180,6 @@ async def run_config_module(
180
180
  module_class: type[BaseModule],
181
181
  services_mode: ServicesMode,
182
182
  config_setup_data: dict,
183
- setup_data: dict,
184
183
  context: Context = TaskiqDepends(),
185
184
  ) -> None:
186
185
  """TaskIQ task allowing a module to compute in the background asynchronously.
@@ -209,6 +208,5 @@ async def run_config_module(
209
208
 
210
209
  await module.start_config_setup(
211
210
  module_class.create_config_setup_model(config_setup_data),
212
- module_class.create_setup_model(setup_data),
213
211
  callback,
214
212
  )
@@ -18,7 +18,7 @@ from typing import TYPE_CHECKING, Any, Generic
18
18
  from rstream import Consumer, ConsumerOffsetSpecification, MessageContext, OffsetType
19
19
 
20
20
  from digitalkin.logger import logger
21
- from digitalkin.models.module import ConfigSetupModelT, InputModelT, SetupModelT
21
+ from digitalkin.models.module import InputModelT, SetupModelT
22
22
  from digitalkin.models.module.module import ModuleStatus
23
23
  from digitalkin.modules._base_module import BaseModule
24
24
  from digitalkin.modules.job_manager.base_job_manager import BaseJobManager
@@ -29,7 +29,7 @@ if TYPE_CHECKING:
29
29
  from taskiq.task import AsyncTaskiqTask
30
30
 
31
31
 
32
- class TaskiqJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigSetupModelT]):
32
+ class TaskiqJobManager(BaseJobManager, Generic[InputModelT, SetupModelT]):
33
33
  """Taskiq job manager for running modules in Taskiq tasks."""
34
34
 
35
35
  services_mode: ServicesMode
@@ -134,8 +134,7 @@ class TaskiqJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigS
134
134
 
135
135
  async def create_config_setup_instance_job(
136
136
  self,
137
- config_setup_data: ConfigSetupModelT,
138
- setup_data: SetupModelT,
137
+ config_setup_data: SetupModelT,
139
138
  mission_id: str,
140
139
  setup_version_id: str,
141
140
  ) -> str:
@@ -173,7 +172,6 @@ class TaskiqJobManager(BaseJobManager, Generic[InputModelT, SetupModelT, ConfigS
173
172
  self.module_class,
174
173
  self.services_mode,
175
174
  config_setup_data.model_dump(), # type: ignore
176
- setup_data.model_dump(),
177
175
  )
178
176
 
179
177
  job_id = running_task.task_id
@@ -3,9 +3,8 @@
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 # type: ignore
8
7
 
9
8
 
10
- class ToolModule(BaseModule[InputModelT, OutputModelT, SetupModelT, SecretModelT,ConfigSetupModelT,], ABC):
9
+ class ToolModule(BaseModule[InputModelT, OutputModelT, SetupModelT, SecretModelT,], ABC):
11
10
  """ToolModule extends BaseModule to implement specific module types."""
@@ -126,7 +126,7 @@ class DefaultFilesystem(FilesystemStrategy):
126
126
  raise FilesystemServiceError(msg) # noqa: TRY301
127
127
 
128
128
  Path(file_path).write_bytes(file.content)
129
- storage_url = str(Path(file_path).resolve())
129
+ storage_uri = str(Path(file_path).resolve())
130
130
  file_data = FilesystemRecord(
131
131
  id=str(uuid.uuid4()),
132
132
  context=self.mission_id,
@@ -136,7 +136,8 @@ class DefaultFilesystem(FilesystemStrategy):
136
136
  size_bytes=len(file.content),
137
137
  checksum=self._calculate_checksum(file.content),
138
138
  metadata=file.metadata,
139
- storage_url=storage_url,
139
+ storage_uri=storage_uri,
140
+ file_url=storage_uri,
140
141
  status=file.status if hasattr(file, "status") and file.status else "ACTIVE",
141
142
  )
142
143
 
@@ -200,7 +201,7 @@ class DefaultFilesystem(FilesystemStrategy):
200
201
 
201
202
  if include_content:
202
203
  for file in paginated_files:
203
- file.content = Path(file.storage_url).read_bytes()
204
+ file.content = Path(file.storage_uri).read_bytes()
204
205
 
205
206
  except Exception as e:
206
207
  msg = f"Error listing files: {e!s}"
@@ -243,7 +244,7 @@ class DefaultFilesystem(FilesystemStrategy):
243
244
  raise FilesystemServiceError(msg) # noqa: TRY301
244
245
 
245
246
  if include_content:
246
- file_path = file_data.storage_url
247
+ file_path = file_data.storage_uri
247
248
  if os.path.exists(file_path):
248
249
  content = Path(file_path).read_bytes()
249
250
  file_data.content = content
@@ -330,7 +331,7 @@ class DefaultFilesystem(FilesystemStrategy):
330
331
  new_path = os.path.join(context_dir, new_name)
331
332
  os.rename(file_path, new_path)
332
333
  existing_file.name = new_name
333
- existing_file.storage_url = str(Path(new_path).resolve())
334
+ existing_file.storage_uri = str(Path(new_path).resolve())
334
335
 
335
336
  self.db[file_id] = existing_file
336
337
 
@@ -388,7 +389,7 @@ class DefaultFilesystem(FilesystemStrategy):
388
389
  continue
389
390
 
390
391
  try:
391
- file_path = file_data.storage_url
392
+ file_path = file_data.storage_uri
392
393
  if os.path.exists(file_path):
393
394
  if permanent:
394
395
  os.remove(file_path)
@@ -24,7 +24,8 @@ class FilesystemRecord(BaseModel):
24
24
  size_bytes: int = Field(default=0, description="Size of the file in bytes")
25
25
  checksum: str = Field(default="", description="SHA-256 checksum of the file content")
26
26
  metadata: dict[str, Any] | None = Field(default=None, description="Additional metadata for the file")
27
- storage_url: str = Field(description="Internal URL for accessing the file content")
27
+ storage_uri: str = Field(description="Internal URI for accessing the file content")
28
+ file_url: str = Field(description="Public URL for accessing the file content")
28
29
  status: str = Field(default="UNSPECIFIED", description="Current status of the file")
29
30
  content: bytes | None = Field(default=None, description="The content of the file")
30
31
 
@@ -121,7 +121,8 @@ class GrpcFilesystem(FilesystemStrategy, GrpcClientWrapper):
121
121
  size_bytes=file.size_bytes,
122
122
  checksum=file.checksum,
123
123
  metadata=MessageToDict(file.metadata),
124
- storage_url=file.storage_url,
124
+ storage_uri=file.storage_uri,
125
+ file_url=file.file_url,
125
126
  status=filesystem_pb2.FileStatus.Name(file.status),
126
127
  content=file.content,
127
128
  )
@@ -97,7 +97,7 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
97
97
  resp = self.exec_grpc_query("ReadRecord", req)
98
98
  return self._build_record_from_proto(resp.stored_data)
99
99
  except Exception:
100
- logger.exception("gRPC ReadRecord failed for %s:%s", collection, record_id)
100
+ logger.warning("gRPC ReadRecord failed for %s:%s", collection, record_id)
101
101
  return None
102
102
 
103
103
  def _update(
@@ -149,7 +149,7 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
149
149
  )
150
150
  self.exec_grpc_query("RemoveRecord", req)
151
151
  except Exception:
152
- logger.exception(
152
+ logger.warning(
153
153
  "gRPC RemoveRecord failed for %s:%s",
154
154
  collection,
155
155
  record_id,
@@ -174,7 +174,7 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
174
174
  resp = self.exec_grpc_query("ListRecords", req)
175
175
  return [self._build_record_from_proto(r) for r in resp.records]
176
176
  except Exception:
177
- logger.exception("gRPC ListRecords failed for %s", collection)
177
+ logger.warning("gRPC ListRecords failed for %s", collection)
178
178
  return []
179
179
 
180
180
  def _remove_collection(self, collection: str) -> bool:
@@ -193,7 +193,7 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
193
193
  )
194
194
  self.exec_grpc_query("RemoveCollection", req)
195
195
  except Exception:
196
- logger.exception("gRPC RemoveCollection failed for %s", collection)
196
+ logger.warning("gRPC RemoveCollection failed for %s", collection)
197
197
  return False
198
198
  return True
199
199
 
@@ -10,7 +10,7 @@ from pathlib import Path
10
10
  from typing import ClassVar
11
11
 
12
12
  from digitalkin.models.module.module_context import ModuleContext
13
- from digitalkin.models.module.module_types import InputTrigger
13
+ from digitalkin.models.module.module_types import DataTrigger
14
14
  from digitalkin.modules.trigger_handler import TriggerHandler
15
15
 
16
16
  logger = logging.getLogger(__name__)
@@ -329,7 +329,7 @@ class ModuleDiscoverer:
329
329
  for protocol, handlers_cls in self._trigger_handlers_cls.items():
330
330
  self.trigger_handlers[protocol] = tuple(handler_cls(context) for handler_cls in set(handlers_cls))
331
331
 
332
- def get_trigger(self, protocol: str, input_instance: InputTrigger) -> TriggerHandler:
332
+ def get_trigger(self, protocol: str, input_instance: DataTrigger) -> TriggerHandler:
333
333
  """Retrieve a trigger handler instance based on the provided protocol and input instance type.
334
334
 
335
335
  Args:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.2.17
3
+ Version: 0.2.19
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,36 +452,36 @@ 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.15
455
+ Requires-Dist: digitalkin-proto>=0.1.16
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
459
459
  Requires-Dist: pydantic>=2.11.5
460
460
  Provides-Extra: dev
461
- Requires-Dist: typos>=1.33.1; extra == "dev"
462
- Requires-Dist: ruff>=0.11.13; extra == "dev"
463
- Requires-Dist: mypy>=1.16.0; extra == "dev"
464
- Requires-Dist: pyright>=1.1.401; extra == "dev"
461
+ Requires-Dist: typos>=1.34.0; extra == "dev"
462
+ Requires-Dist: ruff>=0.12.5; extra == "dev"
463
+ Requires-Dist: mypy>=1.17.0; extra == "dev"
464
+ Requires-Dist: pyright>=1.1.403; extra == "dev"
465
465
  Requires-Dist: pre-commit>=4.2.0; extra == "dev"
466
466
  Requires-Dist: bump2version>=1.0.1; extra == "dev"
467
467
  Requires-Dist: build>=1.2.2; extra == "dev"
468
468
  Requires-Dist: twine>=6.1.0; extra == "dev"
469
- Requires-Dist: cryptography>=45.0.4; extra == "dev"
469
+ Requires-Dist: cryptography>=45.0.5; extra == "dev"
470
470
  Provides-Extra: examples
471
471
  Requires-Dist: openai>=1.75.0; extra == "examples"
472
472
  Provides-Extra: tests
473
- Requires-Dist: freezegun>=1.5.2; extra == "tests"
473
+ Requires-Dist: freezegun>=1.5.3; extra == "tests"
474
474
  Requires-Dist: hdrhistogram>=0.10.3; extra == "tests"
475
475
  Requires-Dist: grpcio-testing>=1.71.0; extra == "tests"
476
476
  Requires-Dist: psutil>=7.0.0; extra == "tests"
477
477
  Requires-Dist: pytest>=8.4.0; extra == "tests"
478
- Requires-Dist: pytest-asyncio>=1.0.0; extra == "tests"
478
+ Requires-Dist: pytest-asyncio>=1.1.0; extra == "tests"
479
479
  Requires-Dist: pytest-cov>=6.1.0; extra == "tests"
480
480
  Provides-Extra: taskiq
481
481
  Requires-Dist: rstream>=0.30.0; extra == "taskiq"
482
- Requires-Dist: taskiq-aio-pika>=0.4.2; extra == "taskiq"
483
- Requires-Dist: taskiq-redis>=1.0.9; extra == "taskiq"
484
- Requires-Dist: taskiq[reload]>=0.11.17; extra == "taskiq"
482
+ Requires-Dist: taskiq-aio-pika>=0.4.3; extra == "taskiq"
483
+ Requires-Dist: taskiq-redis>=1.1.0; extra == "taskiq"
484
+ Requires-Dist: taskiq[reload]>=0.11.18; extra == "taskiq"
485
485
  Dynamic: license-file
486
486
 
487
487
  # DigitalKin Python SDK
@@ -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=PXwJ6gG-NzAdC32zDCvvLWJOjTWYVS771y5C2GkuohE,191
10
+ digitalkin/__version__.py,sha256=LHM4OqKaSNrr7rgQKMrzY_uftKOe1OypsBhuoDm0K6Q,191
11
11
  digitalkin/logger.py,sha256=cFbIAZHOFx3nddOssRNYLXyqUPzR4CgDR_c-5wmB-og,1685
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=NXnnZPjJqUDWoumhEbb7EOEWB7d8XYwpQs-l97NTe4k,18647
15
15
  digitalkin/grpc_servers/module_server.py,sha256=hOvoY2XFjxmgkbAsMex5a-m7OPyljnz0Gh9BJxtDtJo,10259
16
- digitalkin/grpc_servers/module_servicer.py,sha256=yHlzMBBdjdEirx6otG0u3fNy-nZgFkK2HAWQJ6LA7jQ,18415
16
+ digitalkin/grpc_servers/module_servicer.py,sha256=FSPcGHoEH_hfuGNDpNNN-bifSsxRnY-vOUBRZlE8hb4,18441
17
17
  digitalkin/grpc_servers/registry_server.py,sha256=StY18DKYoPKQIU1SIzgito6D4_QA1aMVddZ8O2WGlHY,2223
18
18
  digitalkin/grpc_servers/registry_servicer.py,sha256=dqsKGHZ0LnaIvGt4ipaAuigd37sbJBndT4MAT029GsY,16471
19
19
  digitalkin/grpc_servers/utils/exceptions.py,sha256=SyOgvjggaUECYmSiqy8KJLHwHVt5IClSTxslHM-IZzI,931
@@ -22,23 +22,23 @@ digitalkin/grpc_servers/utils/grpc_client_wrapper.py,sha256=GXRqCTCufwWd8sVMoCln
22
22
  digitalkin/grpc_servers/utils/models.py,sha256=80F5oHiv8MOqMoDZJBXmJSRoVYJRyhaVcijQ2LinAig,8428
23
23
  digitalkin/grpc_servers/utils/types.py,sha256=rQ78s4nAet2jy-NIDj_PUWriT0kuGHr_w6ELjmjgBao,539
24
24
  digitalkin/models/__init__.py,sha256=hDHtUfswaNh8wo4NZaBItg9JqC0uNSRqXArNWSrGynY,163
25
- digitalkin/models/module/__init__.py,sha256=CSnXBcuE8omdbQllfPQGMHaWsfiN7FJyigEv1eZeO4M,579
25
+ digitalkin/models/module/__init__.py,sha256=fgTVbsNmLZgM43Vy-Ea5-g0EG3pncmAmJl9nk-OQdzo,561
26
26
  digitalkin/models/module/module.py,sha256=NWOwCeD_NH0NL89AF_NJ0SwE7G1n-HTcRalodLCDmpM,749
27
27
  digitalkin/models/module/module_context.py,sha256=AL6bzwjYfYPLHb1Hu5kKBjaIOxCpBCPMvxEnapdyrX4,1003
28
- digitalkin/models/module/module_types.py,sha256=HWp-CRG0AB7ve9CRqOegbcwqDgXZ0hmS-QxDpgbdMmI,1196
28
+ digitalkin/models/module/module_types.py,sha256=IygT4MnS-ihI3s0oaPf4DibWcKlq7hvQCjgPc9JAH6g,3511
29
29
  digitalkin/models/services/__init__.py,sha256=HsW7MUGFPvH7Ri28WN4BHHBfEQk5dzU_9FOWAc-0lSE,56
30
30
  digitalkin/models/services/cost.py,sha256=QTEuFD6xz62nob0z4ksE-INJWcZ-iFiuNW5mvXhpFes,1599
31
31
  digitalkin/models/services/storage.py,sha256=cYTVIriGKiprF9OerhSxmc_jM6fUTVwmeon1yQCinkE,143
32
32
  digitalkin/modules/__init__.py,sha256=VwVbKok81NGyPIBZgEj_SR-59G8tTlSb4eBJI9W6Vx4,281
33
- digitalkin/modules/_base_module.py,sha256=tYFWMB09jO0VLOYA3pUSHeI7ujdwnsIqmgPDJE2WtSU,15981
34
- digitalkin/modules/archetype_module.py,sha256=7rleVOkZfFR7TQeaq6oZXLBuRWixKsUJMOr9HfDV0T8,566
35
- digitalkin/modules/tool_module.py,sha256=7eWem70dEJiyoCtkGIJP4Ak2G8MzSruOjrByQMqW9-I,508
33
+ digitalkin/modules/_base_module.py,sha256=JxiInXqnSltdiUjZMkRejURCBJ5MCBXz6SCsYKx-c0Q,16889
34
+ digitalkin/modules/archetype_module.py,sha256=lOe3yYufwfylZR_VGy1w-zqdqVaMI_JANfKkbH9eODE,471
35
+ digitalkin/modules/tool_module.py,sha256=h9oo2vrFJdiBLW2qL_m79a9hEzfXV0L6bZd4KD5OSQs,422
36
36
  digitalkin/modules/trigger_handler.py,sha256=TpxFc_xkYia9B9rAvHkj02e818W08JOfIqssQqbsCpM,1785
37
- digitalkin/modules/job_manager/base_job_manager.py,sha256=Ku_MT7Cuf1R_qJU7SV-yHkzUhhMtmDOa8t5DyetvMxw,6177
37
+ digitalkin/modules/job_manager/base_job_manager.py,sha256=3t2OPqlsFGKsKAEUsPS0hPin1uZGmeSUhK8prWwaoKI,5987
38
38
  digitalkin/modules/job_manager/job_manager_models.py,sha256=onHy-DfInLZQveniMIWIKwTKSQjojz500JvHB54x93c,1129
39
- digitalkin/modules/job_manager/single_job_manager.py,sha256=DkQV3-E9XqgmuC6hoYKolTX2iv9lUJ8BSCde3zk1OU8,10264
40
- digitalkin/modules/job_manager/taskiq_broker.py,sha256=sMXIgheOBshMiBUWUKph_5rxBHkip4rKusrrxFoa7uY,7379
41
- digitalkin/modules/job_manager/taskiq_job_manager.py,sha256=evcE3o51DPWzW2y4ri6DFQZNZbFJXyvFb65SibExJH8,10152
39
+ digitalkin/modules/job_manager/single_job_manager.py,sha256=Yx8uk97GPauZWnMOPtu3HAQ110-tsfOsMiTPosJ2AV8,10287
40
+ digitalkin/modules/job_manager/taskiq_broker.py,sha256=rj7jXp-5K9345HY-ECueu5BPBFRP9Os_BiM-EgVjK_c,7304
41
+ digitalkin/modules/job_manager/taskiq_job_manager.py,sha256=9rQBqmidamkblvZLzDdz8C1TVVIxQ-vZfxZXUR-NRw8,10038
42
42
  digitalkin/services/__init__.py,sha256=LqGk_5DJy8Bzz62ajIq9jCeYNKQUIgtSCpafZk15FLc,910
43
43
  digitalkin/services/base_strategy.py,sha256=QAQnJw1BbqcYMSzwlFyhHP5juBH2WKrZzWxqDr_sDHI,638
44
44
  digitalkin/services/services_config.py,sha256=4hc7-rHgSigoS3SuV0V9FReD2Dz7XoMXcD6iMBP2KKM,7391
@@ -51,9 +51,9 @@ digitalkin/services/cost/cost_strategy.py,sha256=VhHeqi9WnE1yoDBBVp5qmqwIt5tTZHU
51
51
  digitalkin/services/cost/default_cost.py,sha256=mEd0VL_tMcGU41q0f9MFeBYeKZBenv0mIHuwgXlQ7uQ,3869
52
52
  digitalkin/services/cost/grpc_cost.py,sha256=p_5mG72N7e4bxwBOD9DNokvLtinBILiqCfllmkqpmhw,6253
53
53
  digitalkin/services/filesystem/__init__.py,sha256=BhwMl_BUvM0d65fmglkp0SVwn3RfYiUOKJgIMnOCaGM,381
54
- digitalkin/services/filesystem/default_filesystem.py,sha256=kyNoxnzIAQ-hrBgushwV6GUqtcpno77wUI3qaP7Ge1c,14981
55
- digitalkin/services/filesystem/filesystem_strategy.py,sha256=-0oad7P0wqL47DJY30snlnGh7RrruFTZT-G9iFmbAk4,9047
56
- digitalkin/services/filesystem/grpc_filesystem.py,sha256=0U9n4CjTkzscwvFLKYdA0StyHRuV9lCjGbwr7OFrRxI,12453
54
+ digitalkin/services/filesystem/default_filesystem.py,sha256=pQI7Sc9WNJrxxwd21iIviWcrKKuxuj3BdoAT-rghYGk,15023
55
+ digitalkin/services/filesystem/filesystem_strategy.py,sha256=MlSgEDjjCy1GjtpdO_rKiF2NtfP4DpSU_VF2UtwQ7Ug,9130
56
+ digitalkin/services/filesystem/grpc_filesystem.py,sha256=W-TYe76Zbf2KS0Z4NMVUjRdP6m2IzU7-VXiBdecOjpk,12489
57
57
  digitalkin/services/identity/__init__.py,sha256=InkeyLgFYYwItx8mePA8HpfacOMWZwwuc0G4pWtKq9s,270
58
58
  digitalkin/services/identity/default_identity.py,sha256=Y2auZHrGSZTIN5D8HyjLvLcNbYFM1CNUE23x7p5VIGw,386
59
59
  digitalkin/services/identity/identity_strategy.py,sha256=skappBbds1_qa0Gr24FGrNX1N0_OYhYT1Lh7dUaAirE,429
@@ -69,21 +69,21 @@ digitalkin/services/snapshot/default_snapshot.py,sha256=Mb8QwWRsHh9I_tN0ln_ZiFa1
69
69
  digitalkin/services/snapshot/snapshot_strategy.py,sha256=B1TU3V_k9A-OdqBkdyc41-ihnrW5Btcwd1KyQdHT46A,898
70
70
  digitalkin/services/storage/__init__.py,sha256=T-ocYLLphudkQgzvG47jBOm5GQsRFRIGA88y7Ur4akg,341
71
71
  digitalkin/services/storage/default_storage.py,sha256=m53sLOx0JVbua4weD_4GQBKK3c0UDf9HC5BnvSJAkvg,7933
72
- digitalkin/services/storage/grpc_storage.py,sha256=EU2gcT2bOCSqOsnLwQcu3VOeOvdBlP1g0ALfBb07JxY,7172
72
+ digitalkin/services/storage/grpc_storage.py,sha256=TWllxZGYse6f6AZp3YmYbskojOFTO1VkGSVde1zdQ6Q,7164
73
73
  digitalkin/services/storage/storage_strategy.py,sha256=vZWPk49AyJs7RwhSfUwDiTG1A7C4Ccd8y-VVPslyf0w,8734
74
74
  digitalkin/utils/__init__.py,sha256=sJnY-ZUgsjMfojAjONC1VN14mhgIDnzyOlGkw21rRnM,28
75
75
  digitalkin/utils/arg_parser.py,sha256=nvjI1pKDY1HfS0oGcMQPtdTQcggXLtpxXMbnMxNEKRU,3109
76
76
  digitalkin/utils/development_mode_action.py,sha256=TqRuAF_A7bDD4twRB4PnZcRoNeaiAnEdxM5kvy4aoaA,1511
77
77
  digitalkin/utils/llm_ready_schema.py,sha256=JjMug_lrQllqFoanaC091VgOqwAd-_YzcpqFlS7p778,2375
78
- digitalkin/utils/package_discover.py,sha256=aASTSloPVTp6MAaj5T7ToIeC6NHKajPDjWa1LoGjj3g,13473
79
- digitalkin-0.2.17.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
78
+ digitalkin/utils/package_discover.py,sha256=3e9-6Vf3yAAv2VkHHVK4QVqHJBxQqg3d8uuDTsXph24,13471
79
+ digitalkin-0.2.19.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
80
80
  modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
81
  modules/cpu_intensive_module.py,sha256=ejB9XPnFfA0uCuFUQbM3fy5UYfqqAlF36rv_P5Ri8ho,8363
82
82
  modules/minimal_llm_module.py,sha256=Ijld__ZnhzfLwpXD1XVkLZ7jyKZKyOFZczOpiPttJZc,11216
83
83
  modules/text_transform_module.py,sha256=bwPSnEUthZQyfLwcTLo52iAxItAoknkLh8Y3m5aywaY,7251
84
84
  services/filesystem_module.py,sha256=71Mcja8jCQqiqFHPdsIXplFIHTvgkxRhp0TRXuCfgkk,7430
85
85
  services/storage_module.py,sha256=ybTMqmvGaTrR8PqJ4FU0cwxaDjT36TskVrGoetTGmno,6955
86
- digitalkin-0.2.17.dist-info/METADATA,sha256=MNbrMKu92MTMh39heiB4hzNkEMiemE5eTi-ebRxybgc,30580
87
- digitalkin-0.2.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
88
- digitalkin-0.2.17.dist-info/top_level.txt,sha256=gcjqlyrZuLjIyxrOIavCQM_olpr6ND5kPKkZd2j0xGo,40
89
- digitalkin-0.2.17.dist-info/RECORD,,
86
+ digitalkin-0.2.19.dist-info/METADATA,sha256=9gzMCkxF-zbZRMDfEzcTTrD6kde7pgMdyM-ckPv_wR0,30579
87
+ digitalkin-0.2.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
88
+ digitalkin-0.2.19.dist-info/top_level.txt,sha256=gcjqlyrZuLjIyxrOIavCQM_olpr6ND5kPKkZd2j0xGo,40
89
+ digitalkin-0.2.19.dist-info/RECORD,,