digitalkin 0.3.2.dev2__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 (131) hide show
  1. base_server/__init__.py +1 -0
  2. base_server/mock/__init__.py +5 -0
  3. base_server/mock/mock_pb2.py +39 -0
  4. base_server/mock/mock_pb2_grpc.py +102 -0
  5. base_server/server_async_insecure.py +125 -0
  6. base_server/server_async_secure.py +143 -0
  7. base_server/server_sync_insecure.py +103 -0
  8. base_server/server_sync_secure.py +122 -0
  9. digitalkin/__init__.py +8 -0
  10. digitalkin/__version__.py +8 -0
  11. digitalkin/core/__init__.py +1 -0
  12. digitalkin/core/common/__init__.py +9 -0
  13. digitalkin/core/common/factories.py +156 -0
  14. digitalkin/core/job_manager/__init__.py +1 -0
  15. digitalkin/core/job_manager/base_job_manager.py +288 -0
  16. digitalkin/core/job_manager/single_job_manager.py +354 -0
  17. digitalkin/core/job_manager/taskiq_broker.py +311 -0
  18. digitalkin/core/job_manager/taskiq_job_manager.py +541 -0
  19. digitalkin/core/task_manager/__init__.py +1 -0
  20. digitalkin/core/task_manager/base_task_manager.py +539 -0
  21. digitalkin/core/task_manager/local_task_manager.py +108 -0
  22. digitalkin/core/task_manager/remote_task_manager.py +87 -0
  23. digitalkin/core/task_manager/surrealdb_repository.py +266 -0
  24. digitalkin/core/task_manager/task_executor.py +249 -0
  25. digitalkin/core/task_manager/task_session.py +406 -0
  26. digitalkin/grpc_servers/__init__.py +1 -0
  27. digitalkin/grpc_servers/_base_server.py +486 -0
  28. digitalkin/grpc_servers/module_server.py +208 -0
  29. digitalkin/grpc_servers/module_servicer.py +516 -0
  30. digitalkin/grpc_servers/utils/__init__.py +1 -0
  31. digitalkin/grpc_servers/utils/exceptions.py +29 -0
  32. digitalkin/grpc_servers/utils/grpc_client_wrapper.py +88 -0
  33. digitalkin/grpc_servers/utils/grpc_error_handler.py +53 -0
  34. digitalkin/grpc_servers/utils/utility_schema_extender.py +97 -0
  35. digitalkin/logger.py +157 -0
  36. digitalkin/mixins/__init__.py +19 -0
  37. digitalkin/mixins/base_mixin.py +10 -0
  38. digitalkin/mixins/callback_mixin.py +24 -0
  39. digitalkin/mixins/chat_history_mixin.py +110 -0
  40. digitalkin/mixins/cost_mixin.py +76 -0
  41. digitalkin/mixins/file_history_mixin.py +93 -0
  42. digitalkin/mixins/filesystem_mixin.py +46 -0
  43. digitalkin/mixins/logger_mixin.py +51 -0
  44. digitalkin/mixins/storage_mixin.py +79 -0
  45. digitalkin/models/__init__.py +8 -0
  46. digitalkin/models/core/__init__.py +1 -0
  47. digitalkin/models/core/job_manager_models.py +36 -0
  48. digitalkin/models/core/task_monitor.py +70 -0
  49. digitalkin/models/grpc_servers/__init__.py +1 -0
  50. digitalkin/models/grpc_servers/models.py +275 -0
  51. digitalkin/models/grpc_servers/types.py +24 -0
  52. digitalkin/models/module/__init__.py +25 -0
  53. digitalkin/models/module/module.py +40 -0
  54. digitalkin/models/module/module_context.py +149 -0
  55. digitalkin/models/module/module_types.py +393 -0
  56. digitalkin/models/module/utility.py +146 -0
  57. digitalkin/models/services/__init__.py +10 -0
  58. digitalkin/models/services/cost.py +54 -0
  59. digitalkin/models/services/registry.py +42 -0
  60. digitalkin/models/services/storage.py +44 -0
  61. digitalkin/modules/__init__.py +11 -0
  62. digitalkin/modules/_base_module.py +517 -0
  63. digitalkin/modules/archetype_module.py +23 -0
  64. digitalkin/modules/tool_module.py +23 -0
  65. digitalkin/modules/trigger_handler.py +48 -0
  66. digitalkin/modules/triggers/__init__.py +12 -0
  67. digitalkin/modules/triggers/healthcheck_ping_trigger.py +45 -0
  68. digitalkin/modules/triggers/healthcheck_services_trigger.py +63 -0
  69. digitalkin/modules/triggers/healthcheck_status_trigger.py +52 -0
  70. digitalkin/py.typed +0 -0
  71. digitalkin/services/__init__.py +30 -0
  72. digitalkin/services/agent/__init__.py +6 -0
  73. digitalkin/services/agent/agent_strategy.py +19 -0
  74. digitalkin/services/agent/default_agent.py +13 -0
  75. digitalkin/services/base_strategy.py +22 -0
  76. digitalkin/services/communication/__init__.py +7 -0
  77. digitalkin/services/communication/communication_strategy.py +76 -0
  78. digitalkin/services/communication/default_communication.py +101 -0
  79. digitalkin/services/communication/grpc_communication.py +223 -0
  80. digitalkin/services/cost/__init__.py +14 -0
  81. digitalkin/services/cost/cost_strategy.py +100 -0
  82. digitalkin/services/cost/default_cost.py +114 -0
  83. digitalkin/services/cost/grpc_cost.py +138 -0
  84. digitalkin/services/filesystem/__init__.py +7 -0
  85. digitalkin/services/filesystem/default_filesystem.py +417 -0
  86. digitalkin/services/filesystem/filesystem_strategy.py +252 -0
  87. digitalkin/services/filesystem/grpc_filesystem.py +317 -0
  88. digitalkin/services/identity/__init__.py +6 -0
  89. digitalkin/services/identity/default_identity.py +15 -0
  90. digitalkin/services/identity/identity_strategy.py +14 -0
  91. digitalkin/services/registry/__init__.py +27 -0
  92. digitalkin/services/registry/default_registry.py +141 -0
  93. digitalkin/services/registry/exceptions.py +47 -0
  94. digitalkin/services/registry/grpc_registry.py +306 -0
  95. digitalkin/services/registry/registry_models.py +43 -0
  96. digitalkin/services/registry/registry_strategy.py +98 -0
  97. digitalkin/services/services_config.py +200 -0
  98. digitalkin/services/services_models.py +65 -0
  99. digitalkin/services/setup/__init__.py +1 -0
  100. digitalkin/services/setup/default_setup.py +219 -0
  101. digitalkin/services/setup/grpc_setup.py +343 -0
  102. digitalkin/services/setup/setup_strategy.py +145 -0
  103. digitalkin/services/snapshot/__init__.py +6 -0
  104. digitalkin/services/snapshot/default_snapshot.py +39 -0
  105. digitalkin/services/snapshot/snapshot_strategy.py +30 -0
  106. digitalkin/services/storage/__init__.py +7 -0
  107. digitalkin/services/storage/default_storage.py +228 -0
  108. digitalkin/services/storage/grpc_storage.py +214 -0
  109. digitalkin/services/storage/storage_strategy.py +273 -0
  110. digitalkin/services/user_profile/__init__.py +12 -0
  111. digitalkin/services/user_profile/default_user_profile.py +55 -0
  112. digitalkin/services/user_profile/grpc_user_profile.py +69 -0
  113. digitalkin/services/user_profile/user_profile_strategy.py +40 -0
  114. digitalkin/utils/__init__.py +29 -0
  115. digitalkin/utils/arg_parser.py +92 -0
  116. digitalkin/utils/development_mode_action.py +51 -0
  117. digitalkin/utils/dynamic_schema.py +483 -0
  118. digitalkin/utils/llm_ready_schema.py +75 -0
  119. digitalkin/utils/package_discover.py +357 -0
  120. digitalkin-0.3.2.dev2.dist-info/METADATA +602 -0
  121. digitalkin-0.3.2.dev2.dist-info/RECORD +131 -0
  122. digitalkin-0.3.2.dev2.dist-info/WHEEL +5 -0
  123. digitalkin-0.3.2.dev2.dist-info/licenses/LICENSE +430 -0
  124. digitalkin-0.3.2.dev2.dist-info/top_level.txt +4 -0
  125. modules/__init__.py +0 -0
  126. modules/cpu_intensive_module.py +280 -0
  127. modules/dynamic_setup_module.py +338 -0
  128. modules/minimal_llm_module.py +347 -0
  129. modules/text_transform_module.py +203 -0
  130. services/filesystem_module.py +200 -0
  131. services/storage_module.py +206 -0
@@ -0,0 +1,79 @@
1
+ """Storage Mixin to ease storage access in Triggers."""
2
+
3
+ from typing import Any, Literal
4
+
5
+ from digitalkin.models.module.module_context import ModuleContext
6
+ from digitalkin.services.storage.storage_strategy import StorageRecord
7
+
8
+
9
+ class StorageMixin:
10
+ """Mixin providing storage operations through the storage strategy.
11
+
12
+ This mixin wraps storage strategy calls to provide a cleaner API
13
+ for trigger handlers.
14
+ """
15
+
16
+ @staticmethod
17
+ def store_storage(
18
+ context: ModuleContext,
19
+ collection: str,
20
+ record_id: str | None,
21
+ data: dict[str, Any],
22
+ data_type: Literal["OUTPUT", "VIEW", "LOGS", "OTHER"] = "OUTPUT",
23
+ ) -> StorageRecord:
24
+ """Store data using the storage strategy.
25
+
26
+ Args:
27
+ context: Module context containing the storage strategy
28
+ collection: Collection name for the data
29
+ record_id: Optional record identifier
30
+ data: Data to store
31
+ data_type: Type of data being stored
32
+
33
+ Returns:
34
+ Result from the storage strategy
35
+
36
+ Raises:
37
+ StorageServiceError: If storage operation fails
38
+ """
39
+ return context.storage.store(collection, record_id, data, data_type=data_type)
40
+
41
+ @staticmethod
42
+ def read_storage(context: ModuleContext, collection: str, record_id: str) -> StorageRecord | None:
43
+ """Read data from storage.
44
+
45
+ Args:
46
+ context: Module context containing the storage strategy
47
+ collection: Collection name
48
+ record_id: Record identifier
49
+
50
+ Returns:
51
+ Retrieved data
52
+
53
+ Raises:
54
+ StorageServiceError: If read operation fails
55
+ """
56
+ return context.storage.read(collection, record_id)
57
+
58
+ @staticmethod
59
+ def update_storage(
60
+ context: ModuleContext,
61
+ collection: str,
62
+ record_id: str,
63
+ data: dict[str, Any],
64
+ ) -> StorageRecord | None:
65
+ """Update existing data in storage.
66
+
67
+ Args:
68
+ context: Module context containing the storage strategy
69
+ collection: Collection name
70
+ record_id: Record identifier
71
+ data: Updated data
72
+
73
+ Returns:
74
+ Result from the storage strategy
75
+
76
+ Raises:
77
+ StorageServiceError: If update operation fails
78
+ """
79
+ return context.storage.update(collection, record_id, data)
@@ -0,0 +1,8 @@
1
+ """This package contains the models for DigitalKin."""
2
+
3
+ from digitalkin.models.module.module import Module, ModuleStatus
4
+
5
+ __all__ = [
6
+ "Module",
7
+ "ModuleStatus",
8
+ ]
@@ -0,0 +1 @@
1
+ """Core models."""
@@ -0,0 +1,36 @@
1
+ """Job manager models."""
2
+
3
+ from enum import Enum
4
+
5
+ from digitalkin.core.job_manager.base_job_manager import BaseJobManager
6
+
7
+
8
+ class JobManagerMode(Enum):
9
+ """Job manager mode."""
10
+
11
+ SINGLE = "single"
12
+ TASKIQ = "taskiq"
13
+
14
+ def __str__(self) -> str:
15
+ """Get the string representation of the job manager mode.
16
+
17
+ Returns:
18
+ str: job manager mode name.
19
+ """
20
+ return self.value
21
+
22
+ def get_manager_class(self) -> type[BaseJobManager]:
23
+ """Get the job manager class based on the mode.
24
+
25
+ Returns:
26
+ type: The job manager class.
27
+ """
28
+ match self:
29
+ case JobManagerMode.SINGLE:
30
+ from digitalkin.core.job_manager.single_job_manager import SingleJobManager # noqa: PLC0415
31
+
32
+ return SingleJobManager
33
+ case JobManagerMode.TASKIQ:
34
+ from digitalkin.core.job_manager.taskiq_job_manager import TaskiqJobManager # noqa: PLC0415
35
+
36
+ return TaskiqJobManager
@@ -0,0 +1,70 @@
1
+ """Task monitoring models for signaling and heartbeat messages."""
2
+
3
+ from datetime import datetime, timezone
4
+ from enum import Enum
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class TaskStatus(Enum):
11
+ """Task status enumeration."""
12
+
13
+ PENDING = "pending"
14
+ RUNNING = "running"
15
+ CANCELLED = "cancelled"
16
+ COMPLETED = "completed"
17
+ FAILED = "failed"
18
+
19
+
20
+ class CancellationReason(Enum):
21
+ """Reason for task cancellation - helps distinguish cleanup vs real cancellation."""
22
+
23
+ # Cleanup cancellations (not errors)
24
+ SUCCESS_CLEANUP = "success_cleanup" # Main task completed, cleaning up helper tasks
25
+ FAILURE_CLEANUP = "failure_cleanup" # Main task failed, cleaning up helper tasks
26
+
27
+ # Real cancellations
28
+ SIGNAL = "signal" # External signal requested cancellation
29
+ HEARTBEAT_FAILURE = "heartbeat_failure" # Heartbeat stopped working
30
+ TIMEOUT = "timeout" # Task timed out
31
+ SHUTDOWN = "shutdown" # Manager is shutting down
32
+
33
+ # Unknown/unset
34
+ UNKNOWN = "unknown" # Reason not determined
35
+
36
+
37
+ class SignalType(Enum):
38
+ """Signal type enumeration."""
39
+
40
+ START = "start"
41
+ STOP = "stop"
42
+ CANCEL = "cancel"
43
+ PAUSE = "pause"
44
+ RESUME = "resume"
45
+ STATUS = "status"
46
+
47
+ ACK_CANCEL = "ack_cancel"
48
+ ACK_PAUSE = "ack_pause"
49
+ ACK_RESUME = "ack_resume"
50
+ ACK_STATUS = "ack_status"
51
+
52
+
53
+ class SignalMessage(BaseModel):
54
+ """Signal message model for task monitoring."""
55
+
56
+ task_id: str = Field(..., description="Unique identifier for the task")
57
+ mission_id: str = Field(..., description="Identifier for the mission")
58
+ status: TaskStatus = Field(..., description="Current status of the task")
59
+ action: SignalType = Field(..., description="Type of signal action")
60
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
61
+ payload: dict[str, Any] = Field(default={}, description="Optional payload for the signal")
62
+ model_config = {"use_enum_values": True}
63
+
64
+
65
+ class HeartbeatMessage(BaseModel):
66
+ """Heartbeat message model for task monitoring."""
67
+
68
+ task_id: str = Field(..., description="Unique identifier for the task")
69
+ mission_id: str = Field(..., description="Identifier for the mission")
70
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
@@ -0,0 +1 @@
1
+ """Base gRPC server and client models."""
@@ -0,0 +1,275 @@
1
+ """Data models for gRPC server configurations."""
2
+
3
+ from enum import Enum
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, Field, ValidationInfo, field_validator
8
+
9
+ from digitalkin.grpc_servers.utils.exceptions import ConfigurationError, SecurityError
10
+
11
+
12
+ class ServerMode(str, Enum):
13
+ """Enum for server operation mode."""
14
+
15
+ SYNC = "sync"
16
+ ASYNC = "async"
17
+
18
+
19
+ class SecurityMode(str, Enum):
20
+ """Enum for server security mode."""
21
+
22
+ SECURE = "secure"
23
+ INSECURE = "insecure"
24
+
25
+
26
+ class ServerCredentials(BaseModel):
27
+ """Model for server credentials in secure mode.
28
+
29
+ Attributes:
30
+ server_key_path: Path to the server private key
31
+ server_cert_path: Path to the server certificate
32
+ root_cert_path: Optional path to the root certificate
33
+ """
34
+
35
+ server_key_path: Path = Field(..., description="Path to the server private key")
36
+ server_cert_path: Path = Field(..., description="Path to the server certificate")
37
+ root_cert_path: Path | None = Field(None, description="Path to the root certificate")
38
+
39
+ # Enable __slots__ for memory efficiency
40
+ model_config = {
41
+ "extra": "forbid",
42
+ "arbitrary_types_allowed": True,
43
+ "validate_assignment": True,
44
+ "use_enum_values": True,
45
+ "frozen": True, # Make immutable
46
+ }
47
+
48
+ @field_validator("server_key_path", "server_cert_path", "root_cert_path")
49
+ @classmethod
50
+ def check_path_exists(cls, v: Path | None) -> Path | None:
51
+ """Validate that the file path exists.
52
+
53
+ Args:
54
+ v: Path to validate
55
+
56
+ Returns:
57
+ The validated path
58
+
59
+ Raises:
60
+ SecurityError: If the path does not exist
61
+ """
62
+ if v is not None and not v.exists():
63
+ msg = f"File not found: {v}"
64
+ raise SecurityError(msg)
65
+ return v
66
+
67
+
68
+ class ClientCredentials(BaseModel):
69
+ """Model for client credentials in secure mode.
70
+
71
+ Attributes:
72
+ root_cert_path: path to the root certificate
73
+ client_key_path: Path to the client private key
74
+ client_cert_path: Path to the client certificate
75
+ """
76
+
77
+ root_cert_path: Path = Field(..., description="Path to the root certificate")
78
+ client_key_path: Path | None = Field(None, description="Path to the client private key | mTLS enable")
79
+ client_cert_path: Path | None = Field(None, description="Path to the client certificate | mTLS enable")
80
+
81
+ # Enable __slots__ for memory efficiency
82
+ model_config = {
83
+ "extra": "forbid",
84
+ "arbitrary_types_allowed": True,
85
+ "validate_assignment": True,
86
+ "use_enum_values": True,
87
+ "frozen": True, # Make immutable
88
+ }
89
+
90
+ @field_validator("client_key_path", "client_cert_path", "root_cert_path")
91
+ @classmethod
92
+ def check_path_exists(cls, v: Path | None) -> Path | None:
93
+ """Validate that the file path exists.
94
+
95
+ Args:
96
+ v: Path to validate
97
+
98
+ Returns:
99
+ The validated path
100
+
101
+ Raises:
102
+ SecurityError: If the path does not exist
103
+ """
104
+ if v is not None and not v.exists():
105
+ msg = f"File not found: {v}"
106
+ raise SecurityError(msg)
107
+ return v
108
+
109
+
110
+ class ChannelConfig(BaseModel):
111
+ """Base configuration for gRPC channels.
112
+
113
+ Attributes:
114
+ host: Host address
115
+ port: Port to listen on
116
+ mode: communication operation mode (sync/async)
117
+ security: Security mode (secure/insecure)
118
+ credentials: Client credentials for secure mode
119
+ """
120
+
121
+ host: str = Field("0.0.0.0", description="Host address to bind the client to") # noqa: S104
122
+ port: int = Field(50051, description="Port to listen on")
123
+ mode: ServerMode = Field(ServerMode.SYNC, description="Client operation mode (sync/async)")
124
+ security: SecurityMode = Field(SecurityMode.INSECURE, description="Security mode (secure/insecure)")
125
+
126
+ # Enable __slots__ for memory efficiency
127
+ model_config = {
128
+ "extra": "forbid",
129
+ "arbitrary_types_allowed": True,
130
+ "validate_assignment": True,
131
+ "use_enum_values": True,
132
+ }
133
+
134
+ @field_validator("port")
135
+ @classmethod
136
+ def validate_port(cls, v: int) -> int:
137
+ """Validate that the port is in a valid range.
138
+
139
+ Args:
140
+ v: Port number to validate
141
+
142
+ Returns:
143
+ The validated port number
144
+
145
+ Raises:
146
+ ConfigurationError: If port is outside valid range
147
+ """
148
+ if not 0 < v < 65536: # noqa: PLR2004
149
+ msg = f"Port must be between 1 and 65535, got {v}"
150
+ raise ConfigurationError(msg)
151
+ return v
152
+
153
+ @property
154
+ def address(self) -> str:
155
+ """Get the server address.
156
+
157
+ Returns:
158
+ The formatted address string
159
+ """
160
+ return f"{self.host}:{self.port}"
161
+
162
+
163
+ class ClientConfig(ChannelConfig):
164
+ """Base configuration for gRPC clients.
165
+
166
+ Attributes:
167
+ host: Host address to bind the client to
168
+ port: Port to listen on
169
+ mode: Client operation mode (sync/async)
170
+ security: Security mode (secure/insecure)
171
+ credentials: Client credentials for secure mode
172
+ channel_options: Additional channel options
173
+ """
174
+
175
+ credentials: ClientCredentials | None = Field(None, description="Client credentials for secure mode")
176
+ channel_options: list[tuple[str, Any]] = Field(
177
+ default_factory=lambda: [
178
+ ("grpc.max_receive_message_length", 100 * 1024 * 1024), # 100MB
179
+ ("grpc.max_send_message_length", 100 * 1024 * 1024), # 100MB
180
+ ],
181
+ description="Additional channel options",
182
+ )
183
+
184
+ @field_validator("credentials")
185
+ @classmethod
186
+ def validate_credentials(cls, v: ClientCredentials | None, info: ValidationInfo) -> ClientCredentials | None:
187
+ """Validate that credentials are provided when in secure mode.
188
+
189
+ Args:
190
+ v: The credentials value
191
+ info: ValidationInfo containing other field values
192
+
193
+ Returns:
194
+ The validated credentials
195
+
196
+ Raises:
197
+ ConfigurationError: If credentials are missing in secure mode
198
+ """
199
+ # Access security mode from the info.data dictionary
200
+ security = info.data.get("security")
201
+
202
+ if security == SecurityMode.SECURE and v is None:
203
+ msg = "Credentials must be provided when using secure mode"
204
+ raise ConfigurationError(msg)
205
+ return v
206
+
207
+
208
+ class ServerConfig(ChannelConfig):
209
+ """Base configuration for gRPC servers.
210
+
211
+ Attributes:
212
+ host: Host address to bind the server to
213
+ port: Port to listen on
214
+ max_workers: Maximum number of workers for sync mode
215
+ mode: Server operation mode (sync/async)
216
+ security: Security mode (secure/insecure)
217
+ credentials: Server credentials for secure mode
218
+ server_options: Additional server options
219
+ enable_reflection: Enable reflection for the server
220
+ """
221
+
222
+ max_workers: int = Field(10, description="Maximum number of workers for sync mode")
223
+ credentials: ServerCredentials | None = Field(None, description="Server credentials for secure mode")
224
+ server_options: list[tuple[str, Any]] = Field(
225
+ default_factory=lambda: [
226
+ ("grpc.max_receive_message_length", 100 * 1024 * 1024), # 100MB
227
+ ("grpc.max_send_message_length", 100 * 1024 * 1024), # 100MB
228
+ ],
229
+ description="Additional server options",
230
+ )
231
+ enable_reflection: bool = Field(default=True, description="Enable reflection for the server")
232
+ enable_health_check: bool = Field(default=True, description="Enable health check service")
233
+
234
+ @field_validator("credentials")
235
+ @classmethod
236
+ def validate_credentials(cls, v: ServerCredentials | None, info: ValidationInfo) -> ServerCredentials | None:
237
+ """Validate that credentials are provided when in secure mode.
238
+
239
+ Args:
240
+ v: The credentials value
241
+ info: ValidationInfo containing other field values
242
+
243
+ Returns:
244
+ The validated credentials
245
+
246
+ Raises:
247
+ ConfigurationError: If credentials are missing in secure mode
248
+ """
249
+ # Access security mode from the info.data dictionary
250
+ security = info.data.get("security")
251
+
252
+ if security == SecurityMode.SECURE and v is None:
253
+ msg = "Credentials must be provided when using secure mode"
254
+ raise ConfigurationError(msg)
255
+ return v
256
+
257
+
258
+ class ModuleServerConfig(ServerConfig):
259
+ """Configuration for Module gRPC server.
260
+
261
+ Attributes:
262
+ registry_address: Address of the registry server
263
+ """
264
+
265
+ registry_address: str = Field(..., description="Address of the registry server")
266
+
267
+
268
+ class RegistryServerConfig(ServerConfig):
269
+ """Configuration for Registry gRPC server.
270
+
271
+ Attributes:
272
+ database_url: Database URL for registry data storage
273
+ """
274
+
275
+ database_url: str | None = Field(None, description="Database URL for registry data storage")
@@ -0,0 +1,24 @@
1
+ """Type definitions for gRPC utilities."""
2
+
3
+ from typing import Protocol, TypeVar
4
+
5
+ import grpc
6
+ from grpc import aio as grpc_aio
7
+
8
+ GrpcServer = grpc.Server | grpc_aio.Server
9
+
10
+ # Create a type variable for servicer implementations
11
+ T = TypeVar("T")
12
+
13
+
14
+ class ServiceObject(Protocol):
15
+ """Protocol for individual services in a gRPC descriptor."""
16
+
17
+ full_name: str
18
+
19
+
20
+ # Create a protocol for service descriptors
21
+ class ServiceDescriptor(Protocol):
22
+ """Protocol for gRPC service descriptors."""
23
+
24
+ services_by_name: dict[str, ServiceObject]
@@ -0,0 +1,25 @@
1
+ """This module contains the models for the modules."""
2
+
3
+ from digitalkin.models.module.module_context import ModuleContext
4
+ from digitalkin.models.module.module_types import (
5
+ DataModel,
6
+ DataTrigger,
7
+ SetupModel,
8
+ )
9
+ from digitalkin.models.module.utility import (
10
+ EndOfStreamOutput,
11
+ UtilityProtocol,
12
+ UtilityRegistry,
13
+ )
14
+
15
+ __all__ = [
16
+ # Core types (used by all SDK users)
17
+ "DataModel",
18
+ "DataTrigger",
19
+ # Utility (commonly used)
20
+ "EndOfStreamOutput",
21
+ "ModuleContext",
22
+ "SetupModel",
23
+ "UtilityProtocol",
24
+ "UtilityRegistry",
25
+ ]
@@ -0,0 +1,40 @@
1
+ """Module model."""
2
+
3
+ from enum import Enum, auto
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class ModuleCodeModel(BaseModel):
9
+ """typed error/code model."""
10
+
11
+ code: str = Field(...)
12
+ message: str | None = Field(default=None)
13
+ short_description: str | None = Field(default=None)
14
+
15
+
16
+ class ModuleStatus(Enum):
17
+ """Possible module's state."""
18
+
19
+ CREATED = auto() # Module created but not started
20
+ STARTING = auto() # Module is starting
21
+ RUNNING = auto() # Module do run
22
+ STOPPING = auto() # Module is stopping
23
+ STOPPED = auto() # Module stop successfuly
24
+ FAILED = auto() # Module stopped due to internal error
25
+ CANCELLED = auto() # Module stopped due to internal error
26
+ NOT_FOUND = auto()
27
+
28
+
29
+ class Module(BaseModel):
30
+ """Module model."""
31
+
32
+ name: str
33
+ cost_schema: str
34
+ input_schema: str
35
+ output_schema: str
36
+ setup_schema: str
37
+ secret_schema: str
38
+ type: str
39
+ version: str
40
+ description: str