digitalkin 0.1.1__py3-none-any.whl → 0.2.0__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.
- base_server/__init__.py +1 -0
- base_server/mock/__init__.py +5 -0
- base_server/mock/mock_pb2.py +39 -0
- base_server/mock/mock_pb2_grpc.py +102 -0
- base_server/server_async_insecure.py +124 -0
- base_server/server_async_secure.py +142 -0
- base_server/server_sync_insecure.py +102 -0
- base_server/server_sync_secure.py +121 -0
- digitalkin/__init__.py +1 -11
- digitalkin/__version__.py +1 -4
- digitalkin/{grpc → grpc_servers}/__init__.py +1 -13
- digitalkin/{grpc → grpc_servers}/_base_server.py +3 -3
- digitalkin/{grpc → grpc_servers}/module_server.py +30 -12
- digitalkin/{grpc → grpc_servers}/module_servicer.py +30 -14
- digitalkin/{grpc → grpc_servers}/registry_server.py +6 -4
- digitalkin/{grpc → grpc_servers}/registry_servicer.py +8 -2
- digitalkin/{grpc → grpc_servers}/utils/factory.py +6 -4
- digitalkin/grpc_servers/utils/grpc_client_wrapper.py +68 -0
- digitalkin/{grpc → grpc_servers}/utils/models.py +1 -1
- digitalkin/models/__init__.py +1 -4
- digitalkin/models/module/__init__.py +8 -2
- digitalkin/models/module/module_types.py +10 -0
- digitalkin/models/services/__init__.py +0 -5
- digitalkin/modules/__init__.py +3 -3
- digitalkin/modules/_base_module.py +64 -27
- digitalkin/modules/archetype_module.py +2 -6
- digitalkin/modules/job_manager.py +46 -28
- digitalkin/modules/tool_module.py +3 -7
- digitalkin/modules/trigger_module.py +2 -7
- digitalkin/services/__init__.py +7 -9
- digitalkin/services/agent/__init__.py +2 -2
- digitalkin/services/agent/agent_strategy.py +3 -6
- digitalkin/services/agent/default_agent.py +1 -4
- digitalkin/services/base_strategy.py +18 -0
- digitalkin/services/cost/__init__.py +4 -3
- digitalkin/services/cost/cost_strategy.py +35 -5
- digitalkin/services/cost/default_cost.py +22 -5
- digitalkin/services/cost/grpc_cost.py +81 -0
- digitalkin/services/filesystem/__init__.py +4 -3
- digitalkin/services/filesystem/default_filesystem.py +197 -17
- digitalkin/services/filesystem/filesystem_strategy.py +54 -15
- digitalkin/services/filesystem/grpc_filesystem.py +209 -0
- digitalkin/services/identity/__init__.py +2 -2
- digitalkin/services/identity/default_identity.py +1 -1
- digitalkin/services/identity/identity_strategy.py +3 -1
- digitalkin/services/registry/__init__.py +2 -2
- digitalkin/services/registry/default_registry.py +1 -4
- digitalkin/services/registry/registry_strategy.py +3 -6
- digitalkin/services/services_config.py +176 -0
- digitalkin/services/services_models.py +61 -0
- digitalkin/services/setup/default_setup.py +222 -0
- digitalkin/services/setup/grpc_setup.py +307 -0
- digitalkin/services/setup/setup_strategy.py +145 -0
- digitalkin/services/snapshot/__init__.py +2 -2
- digitalkin/services/snapshot/default_snapshot.py +1 -1
- digitalkin/services/snapshot/snapshot_strategy.py +3 -4
- digitalkin/services/storage/__init__.py +4 -3
- digitalkin/services/storage/default_storage.py +184 -57
- digitalkin/services/storage/grpc_storage.py +76 -170
- digitalkin/services/storage/storage_strategy.py +195 -24
- digitalkin/utils/arg_parser.py +16 -17
- {digitalkin-0.1.1.dist-info → digitalkin-0.2.0.dist-info}/METADATA +8 -7
- digitalkin-0.2.0.dist-info/RECORD +78 -0
- {digitalkin-0.1.1.dist-info → digitalkin-0.2.0.dist-info}/WHEEL +1 -1
- digitalkin-0.2.0.dist-info/top_level.txt +3 -0
- modules/__init__.py +0 -0
- modules/minimal_llm_module.py +162 -0
- modules/storage_module.py +187 -0
- modules/text_transform_module.py +201 -0
- digitalkin/services/default_service.py +0 -13
- digitalkin/services/development_service.py +0 -10
- digitalkin/services/service_provider.py +0 -27
- digitalkin-0.1.1.dist-info/RECORD +0 -59
- digitalkin-0.1.1.dist-info/top_level.txt +0 -1
- /digitalkin/{grpc → grpc_servers}/utils/exceptions.py +0 -0
- /digitalkin/{grpc → grpc_servers}/utils/types.py +0 -0
- {digitalkin-0.1.1.dist-info → digitalkin-0.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,42 +1,213 @@
|
|
|
1
1
|
"""This module contains the abstract base class for storage strategies."""
|
|
2
2
|
|
|
3
|
+
import datetime
|
|
3
4
|
from abc import ABC, abstractmethod
|
|
4
|
-
from
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Any, Literal, TypeGuard
|
|
5
7
|
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
"""Abstract base class for storage strategies."""
|
|
10
|
+
from digitalkin.services.base_strategy import BaseStrategy
|
|
9
11
|
|
|
10
|
-
def __init__(self) -> None:
|
|
11
|
-
"""Initialize the storage strategy."""
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
class StorageServiceError(Exception):
|
|
14
|
+
"""Base exception for Setup service errors."""
|
|
15
15
|
|
|
16
|
-
@abstractmethod
|
|
17
|
-
def connect(self) -> bool:
|
|
18
|
-
"""Establish connection to the database."""
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"""Close connection to the database."""
|
|
17
|
+
class DataType(Enum):
|
|
18
|
+
"""Enum defining the types of data that can be stored."""
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
OUTPUT = "OUTPUT"
|
|
21
|
+
VIEW = "VIEW"
|
|
22
|
+
LOGS = "LOGS"
|
|
23
|
+
OTHER = "OTHER"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class StorageRecord(BaseModel):
|
|
27
|
+
"""Container for stored records with metadata."""
|
|
28
|
+
|
|
29
|
+
# Metadata
|
|
30
|
+
mission_id: str = Field(description="The ID of the mission this record is associated with")
|
|
31
|
+
name: str = Field(description="The name of the record")
|
|
32
|
+
creation_date: datetime.datetime | None = Field(default=None, description="The date the record was created")
|
|
33
|
+
update_date: datetime.datetime | None = Field(default=None, description="The date the record was last updated")
|
|
34
|
+
data_type: DataType = Field(default=DataType.OUTPUT, description="The type of data stored")
|
|
35
|
+
# Actual data payload
|
|
36
|
+
data: BaseModel = Field(description="The data stored in the record")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class StorageStrategy(BaseStrategy, ABC):
|
|
40
|
+
"""Abstract base class for storage strategies.
|
|
41
|
+
|
|
42
|
+
This strategy defines how data is stored and retrieved, with
|
|
43
|
+
type validation through registered Pydantic models.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, mission_id: str, config: dict[str, type[BaseModel]]) -> None:
|
|
47
|
+
"""Initialize the storage strategy.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
mission_id: The ID of the mission this strategy is associated with
|
|
51
|
+
config: A dictionary mapping names to Pydantic model classes
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(mission_id)
|
|
54
|
+
# Schema configuration mapping keys to model classes
|
|
55
|
+
self.config: dict[str, type[BaseModel]] = config
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def _is_valid_data_type_name(value: str) -> TypeGuard[str]:
|
|
59
|
+
return value in DataType.__members__
|
|
27
60
|
|
|
28
61
|
@abstractmethod
|
|
29
|
-
def
|
|
30
|
-
"""
|
|
62
|
+
def _store(self, record: StorageRecord) -> StorageRecord:
|
|
63
|
+
"""Store a new record in the storage.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
record: The record to store
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
The ID of the created record
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def store(
|
|
73
|
+
self,
|
|
74
|
+
name: str,
|
|
75
|
+
data: dict[str, Any],
|
|
76
|
+
data_type: Literal["OUTPUT", "VIEW", "LOGS", "OTHER"] = "OUTPUT",
|
|
77
|
+
) -> StorageRecord:
|
|
78
|
+
"""Store a new record in the storage.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
name: The unique name to store the data under
|
|
82
|
+
data: The data to store
|
|
83
|
+
data_type: The type of data being stored (default: OUTPUT)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
The ID of the created record
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
ValueError: If the data type is invalid or if validation fails
|
|
90
|
+
"""
|
|
91
|
+
if not self._is_valid_data_type_name(data_type):
|
|
92
|
+
msg = f"Invalid data type '{data_type}'. Must be one of {list(DataType.__members__.keys())}"
|
|
93
|
+
raise ValueError(msg)
|
|
94
|
+
data_type_enum = DataType[data_type]
|
|
95
|
+
validated_data = self._validate_data(name, {**data, "mission_id": self.mission_id})
|
|
96
|
+
record = self._create_storage_record(name, validated_data, data_type_enum)
|
|
97
|
+
return self._store(record)
|
|
31
98
|
|
|
32
99
|
@abstractmethod
|
|
33
|
-
def
|
|
34
|
-
"""
|
|
100
|
+
def _read(self, name: str) -> StorageRecord | None:
|
|
101
|
+
"""Get records from storage by key.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
name: The unique name to retrieve data for
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
A storage record with validated data
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def read(self, name: str) -> StorageRecord | None:
|
|
111
|
+
"""Get records from storage by key.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
name: The unique name to retrieve data for
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
A storage record with validated data
|
|
118
|
+
"""
|
|
119
|
+
return self._read(name)
|
|
35
120
|
|
|
36
121
|
@abstractmethod
|
|
37
|
-
def
|
|
38
|
-
"""
|
|
122
|
+
def _modify(self, name: str, data: BaseModel) -> StorageRecord | None:
|
|
123
|
+
"""Update a record in the storage.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
name: The unique name for the record type
|
|
127
|
+
data: The new data to store
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
StorageRecord: The modified record
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def modify(self, name: str, data: dict[str, Any]) -> StorageRecord | None:
|
|
134
|
+
"""Update a record in the storage (overwrite all the data).
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
name: The unique name for the record type
|
|
138
|
+
data: The new data to store
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
StorageRecord: The modified record
|
|
142
|
+
"""
|
|
143
|
+
validated_data = self._validate_data(name, data)
|
|
144
|
+
return self._modify(name, validated_data)
|
|
39
145
|
|
|
40
146
|
@abstractmethod
|
|
41
|
-
def
|
|
42
|
-
"""
|
|
147
|
+
def _remove(self, name: str) -> bool:
|
|
148
|
+
"""Delete a record from the storage.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
name: The unique name for the record type
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
True if the deletion was successful, False otherwise
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
def remove(self, name: str) -> bool:
|
|
158
|
+
"""Delete a record from the storage.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
name: The unique name for the record type
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
True if the deletion was successful, False otherwise
|
|
165
|
+
"""
|
|
166
|
+
return self._remove(name)
|
|
167
|
+
|
|
168
|
+
def _validate_data(self, name: str, data: dict[str, Any]) -> BaseModel:
|
|
169
|
+
"""Validate data against the model schema for the given key.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
name: The unique name to get the model type for
|
|
173
|
+
data: The data to validate
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
A validated model instance
|
|
177
|
+
|
|
178
|
+
Raises:
|
|
179
|
+
ValueError: If the key has no associated model or validation fails
|
|
180
|
+
"""
|
|
181
|
+
model_cls = self.config.get(name)
|
|
182
|
+
if not model_cls:
|
|
183
|
+
msg = f"No model schema defined for name: {name}"
|
|
184
|
+
raise ValueError(msg)
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
return model_cls.model_validate(data)
|
|
188
|
+
except Exception as e:
|
|
189
|
+
msg = f"Data validation failed for key '{name}': {e!s}"
|
|
190
|
+
raise ValueError(msg) from e
|
|
191
|
+
|
|
192
|
+
def _create_storage_record(
|
|
193
|
+
self,
|
|
194
|
+
name: str,
|
|
195
|
+
validated_data: BaseModel,
|
|
196
|
+
data_type: DataType,
|
|
197
|
+
) -> StorageRecord:
|
|
198
|
+
"""Create a storage record with metadata.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
name: The unique name for the record
|
|
202
|
+
validated_data: The validated data model
|
|
203
|
+
data_type: The type of data
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
A complete storage record with metadata
|
|
207
|
+
"""
|
|
208
|
+
return StorageRecord(
|
|
209
|
+
mission_id=self.mission_id,
|
|
210
|
+
name=name,
|
|
211
|
+
data=validated_data,
|
|
212
|
+
data_type=data_type,
|
|
213
|
+
)
|
digitalkin/utils/arg_parser.py
CHANGED
|
@@ -6,7 +6,7 @@ from argparse import Action, ArgumentParser, Namespace, _HelpAction, _SubParsers
|
|
|
6
6
|
from collections.abc import Sequence
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from digitalkin.services.
|
|
9
|
+
from digitalkin.services.services_models import ServicesMode
|
|
10
10
|
|
|
11
11
|
logging.getLogger().setLevel(logging.INFO)
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
@@ -99,38 +99,37 @@ class ArgParser:
|
|
|
99
99
|
class DevelopmentModeMappingAction(Action):
|
|
100
100
|
"""."""
|
|
101
101
|
|
|
102
|
-
default: ServiceProvider | None
|
|
103
|
-
class_mapping: dict[str, ServiceProvider]
|
|
104
|
-
|
|
105
102
|
def __init__(
|
|
106
103
|
self,
|
|
107
104
|
env_var: str,
|
|
108
|
-
class_mapping: dict[str, ServiceProvider],
|
|
109
105
|
required: bool = True, # noqa: FBT001, FBT002
|
|
110
106
|
default: str | None = None,
|
|
111
107
|
**kwargs: dict[str, Any],
|
|
112
108
|
) -> None:
|
|
113
109
|
"""."""
|
|
114
|
-
default =
|
|
115
|
-
if default is None:
|
|
116
|
-
logger.error("Invalid default value: %s, for the Service Provider in the module", default)
|
|
110
|
+
default = ServicesMode(os.environ.get(env_var, default))
|
|
117
111
|
|
|
118
112
|
if required and default:
|
|
119
113
|
required = False
|
|
120
|
-
self.class_mapping = class_mapping
|
|
121
114
|
super().__init__(default=default, required=required, **kwargs) # type: ignore
|
|
122
115
|
|
|
123
116
|
def __call__(
|
|
124
117
|
self,
|
|
125
|
-
parser: ArgumentParser,
|
|
118
|
+
parser: ArgumentParser, # noqa: ARG002
|
|
126
119
|
namespace: Namespace,
|
|
127
120
|
values: str | Sequence[Any] | None,
|
|
128
121
|
option_string: str | None = None, # noqa: ARG002
|
|
129
122
|
) -> None:
|
|
130
|
-
"""Set the attribute to the corresponding class.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
123
|
+
"""Set the attribute to the corresponding class.
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
TypeError: if the value is not a string.
|
|
127
|
+
"""
|
|
128
|
+
# Check if the value is a string and convert it to lowercase
|
|
129
|
+
if isinstance(values, str):
|
|
130
|
+
values = values.lower()
|
|
131
|
+
else:
|
|
132
|
+
msg = "values must be a string"
|
|
133
|
+
raise TypeError(msg)
|
|
134
|
+
mode = ServicesMode(values)
|
|
135
|
+
setattr(namespace, self.dest, mode)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: digitalkin
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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,25 +452,26 @@ 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.
|
|
455
|
+
Requires-Dist: digitalkin-proto>=0.1.5
|
|
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
|
-
Requires-Dist: pydantic>=2.
|
|
459
|
+
Requires-Dist: pydantic>=2.11.3
|
|
460
460
|
Provides-Extra: dev
|
|
461
461
|
Requires-Dist: pytest>=8.3.4; extra == "dev"
|
|
462
|
-
Requires-Dist: pytest-asyncio>=0.
|
|
463
|
-
Requires-Dist: pytest-cov>=6.
|
|
464
|
-
Requires-Dist: typos>=1.
|
|
462
|
+
Requires-Dist: pytest-asyncio>=0.26.0; extra == "dev"
|
|
463
|
+
Requires-Dist: pytest-cov>=6.1.0; extra == "dev"
|
|
464
|
+
Requires-Dist: typos>=1.31.1; extra == "dev"
|
|
465
465
|
Requires-Dist: ruff>=0.11.2; extra == "dev"
|
|
466
466
|
Requires-Dist: mypy>=1.15.0; extra == "dev"
|
|
467
|
-
Requires-Dist: pyright>=1.1.
|
|
467
|
+
Requires-Dist: pyright>=1.1.398; extra == "dev"
|
|
468
468
|
Requires-Dist: pre-commit>=4.2.0; extra == "dev"
|
|
469
469
|
Requires-Dist: bump2version>=1.0.1; extra == "dev"
|
|
470
470
|
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
471
471
|
Requires-Dist: twine>=6.1.0; extra == "dev"
|
|
472
472
|
Requires-Dist: cryptography>=44.0.2; extra == "dev"
|
|
473
473
|
Requires-Dist: grpcio-testing>=1.71.0; extra == "dev"
|
|
474
|
+
Requires-Dist: freezegun>=1.5.1; extra == "dev"
|
|
474
475
|
Provides-Extra: examples
|
|
475
476
|
Requires-Dist: openai>=1.66.3; extra == "examples"
|
|
476
477
|
Dynamic: license-file
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
base_server/__init__.py,sha256=gs8t9Dg0dNVHRdYYbEQY8bn8tzEUv2zE6eBhKNPG3kU,88
|
|
2
|
+
base_server/server_async_insecure.py,sha256=Rvj5Xj8tDMglAj6aOGlQdMeD-FL97_OBEhHYHxxQrVo,3887
|
|
3
|
+
base_server/server_async_secure.py,sha256=SV_CqEmD6YNHHP2Y369T2PLPJ-9JG3bvXytchX_Ensk,4684
|
|
4
|
+
base_server/server_sync_insecure.py,sha256=VgSH8YghagK3fiwHhc7d6__zjN6lj_FgBUponFbOoxM,3127
|
|
5
|
+
base_server/server_sync_secure.py,sha256=MMkq67vAZNiDLJSySjoXtHIEIK1pAlRz57n75Egnndk,3939
|
|
6
|
+
base_server/mock/__init__.py,sha256=YZFT-F1l_TpvJYuIPX-7kTeE1CfOjhx9YmNRXVoi-jQ,143
|
|
7
|
+
base_server/mock/mock_pb2.py,sha256=sETakcS3PAAm4E-hTCV1jIVaQTPEAIoVVHupB8Z_k7Y,1843
|
|
8
|
+
base_server/mock/mock_pb2_grpc.py,sha256=BbOT70H6q3laKgkHfOx1QdfmCS_HxCY4wCOX84YAdG4,3180
|
|
9
|
+
digitalkin/__init__.py,sha256=7LLBAba0th-3SGqcpqFO-lopWdUkVLKzLZiMtB-mW3M,162
|
|
10
|
+
digitalkin/__version__.py,sha256=c4f1Pc-TEf7O1UkIJonXwVhP7WicVMKecmjTFvgmDLQ,190
|
|
11
|
+
digitalkin/logger.py,sha256=9cDgyJV2QXXT8F--xRODFlZyDgjuTTXNdpCU3GdqCsk,382
|
|
12
|
+
digitalkin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
digitalkin/grpc_servers/__init__.py,sha256=0cJBlwipSmFdXkyH3T0i6OJ1WpAtNsZgYX7JaSnkbtg,804
|
|
14
|
+
digitalkin/grpc_servers/_base_server.py,sha256=ec4xmgAuOMVg45a63O_PEa2T7mI4tJ6boxcXauFyZ5g,18649
|
|
15
|
+
digitalkin/grpc_servers/module_server.py,sha256=0HVOygMGP82WDU8I_04ZrFQ1Tqme0bM5nyqMVmoOL1Y,9072
|
|
16
|
+
digitalkin/grpc_servers/module_servicer.py,sha256=togOyvogAYkBv353S-9X_pP5yI8MvxupOIBSvq39jA4,11816
|
|
17
|
+
digitalkin/grpc_servers/registry_server.py,sha256=AjN-OXLGsJtvddqLKeHosJVdSDqvjfpkQM3JcPl5PSQ,2120
|
|
18
|
+
digitalkin/grpc_servers/registry_servicer.py,sha256=mCAjNhdMq5DozZMEPsJK__DIxePEYxSWV-gAq-Xctk4,16469
|
|
19
|
+
digitalkin/grpc_servers/utils/exceptions.py,sha256=I00OM8p8up20He4dU1fiHsvdLj1DymjR_UmoeUm2MSA,785
|
|
20
|
+
digitalkin/grpc_servers/utils/factory.py,sha256=jm6rFjiqmtSv7BIHNAOxsG9xXtSvWpx9TfzSQiX97MQ,5899
|
|
21
|
+
digitalkin/grpc_servers/utils/grpc_client_wrapper.py,sha256=y9zGzmeESAhrzzQcekA8rE_P9gyPvOjxWwnZAc3fpx4,2435
|
|
22
|
+
digitalkin/grpc_servers/utils/models.py,sha256=AXv4FQ3RRmcr5sZaaZc72ED1LtGJEaxmFIZP0Xlo-PY,5483
|
|
23
|
+
digitalkin/grpc_servers/utils/types.py,sha256=rQ78s4nAet2jy-NIDj_PUWriT0kuGHr_w6ELjmjgBao,539
|
|
24
|
+
digitalkin/models/__init__.py,sha256=hDHtUfswaNh8wo4NZaBItg9JqC0uNSRqXArNWSrGynY,163
|
|
25
|
+
digitalkin/models/module/__init__.py,sha256=ihvRlemJuFvU4armZIL-Vq-zaJx9UrjDoJAVPbEG8jw,345
|
|
26
|
+
digitalkin/models/module/module.py,sha256=vlIeWmH61NVEiJpRx0Crk4iB8hAUV4mG30likSyRFP4,686
|
|
27
|
+
digitalkin/models/module/module_types.py,sha256=SxwzfDDnkyuQe50glVrxN6VPuJCkbB313FRyVZugIMw,312
|
|
28
|
+
digitalkin/models/services/__init__.py,sha256=HsW7MUGFPvH7Ri28WN4BHHBfEQk5dzU_9FOWAc-0lSE,56
|
|
29
|
+
digitalkin/models/services/cost.py,sha256=QTEuFD6xz62nob0z4ksE-INJWcZ-iFiuNW5mvXhpFes,1599
|
|
30
|
+
digitalkin/models/services/storage.py,sha256=cYTVIriGKiprF9OerhSxmc_jM6fUTVwmeon1yQCinkE,143
|
|
31
|
+
digitalkin/modules/__init__.py,sha256=ppYARmhvdVi55ofC0QZerIempSlcJYDeCXhcl4qXObw,278
|
|
32
|
+
digitalkin/modules/_base_module.py,sha256=f4AEZFyl0meT_V6esnEFyUtuN7ZXvhHgIYa1ZOMe7tM,7651
|
|
33
|
+
digitalkin/modules/archetype_module.py,sha256=T2Ehj7EpAC2MO9WQbJv39hqRw7rh3exhVZTEL3JPM8U,421
|
|
34
|
+
digitalkin/modules/job_manager.py,sha256=q48ZJwWmOZ4xJKV2QApI6x_Nfgviej-AoIV8BJQ9B-o,6110
|
|
35
|
+
digitalkin/modules/tool_module.py,sha256=86g0M1wHZ1ReIc7AkKfyjnlGN2QYJBGxrEQpKVlyrZI,421
|
|
36
|
+
digitalkin/modules/trigger_module.py,sha256=kVoI4Gdkw7WWUP5T6hSCNqw5FxibTxL6Tpq9KP7gg78,379
|
|
37
|
+
digitalkin/services/__init__.py,sha256=LqGk_5DJy8Bzz62ajIq9jCeYNKQUIgtSCpafZk15FLc,910
|
|
38
|
+
digitalkin/services/base_strategy.py,sha256=U7J09LkNvTaj4bkX-gF86iU_FcUeHK6AKp4zyUPx6eI,470
|
|
39
|
+
digitalkin/services/services_config.py,sha256=6mNYtw07ZNZbk2b4e3xKEpYfozD_NUZyUY3iiein_10,7256
|
|
40
|
+
digitalkin/services/services_models.py,sha256=5zXkWcfKnXGwQi9sN4OAL3XrgqOcmsTl8ai5Mi4RPsw,1668
|
|
41
|
+
digitalkin/services/agent/__init__.py,sha256=vJc8JN0pdtA8ecypLBeHrwAUIW6H2C8NyW-dk24rTpk,244
|
|
42
|
+
digitalkin/services/agent/agent_strategy.py,sha256=42Q9RciHX6tg3CgDQkbrlIx4h_TX0WIuSpLmCjitVmA,492
|
|
43
|
+
digitalkin/services/agent/default_agent.py,sha256=4N_E_eQxJGOx1KVUUg5jNOje-3ncMxF3ePB-uDuGrJc,345
|
|
44
|
+
digitalkin/services/cost/__init__.py,sha256=Wi9ZB4LSXFsUYgkX-V1UJQkVXYDNDpp8q2dXccR2uRM,303
|
|
45
|
+
digitalkin/services/cost/cost_strategy.py,sha256=KkVLT8X2EY58ul-27Gj6lFx7dsk1SZgg-UunBC0D8Ks,986
|
|
46
|
+
digitalkin/services/cost/default_cost.py,sha256=LaTOBIdGOwh4-9vDlnefm8eKDvSWglJOS7BFLOT_G9Q,811
|
|
47
|
+
digitalkin/services/cost/grpc_cost.py,sha256=k0Df_41dwrowBjtz11eqYQyWCMIjY-wEPEytbo2j4gE,3215
|
|
48
|
+
digitalkin/services/filesystem/__init__.py,sha256=BhwMl_BUvM0d65fmglkp0SVwn3RfYiUOKJgIMnOCaGM,381
|
|
49
|
+
digitalkin/services/filesystem/default_filesystem.py,sha256=tTOsBt0MSjexKgWm657y8BLppMYJtmJIVdqzsSRRaYk,7264
|
|
50
|
+
digitalkin/services/filesystem/filesystem_strategy.py,sha256=VH93jkijFtyVA6XaH_rsfdSyeEpkqea54NAvHFLJDjM,2216
|
|
51
|
+
digitalkin/services/filesystem/grpc_filesystem.py,sha256=rtVfutPoggB1AG6vcxrSMnUOu20h9tlWFfwoY1PMliw,8180
|
|
52
|
+
digitalkin/services/identity/__init__.py,sha256=InkeyLgFYYwItx8mePA8HpfacOMWZwwuc0G4pWtKq9s,270
|
|
53
|
+
digitalkin/services/identity/default_identity.py,sha256=Y2auZHrGSZTIN5D8HyjLvLcNbYFM1CNUE23x7p5VIGw,386
|
|
54
|
+
digitalkin/services/identity/identity_strategy.py,sha256=skappBbds1_qa0Gr24FGrNX1N0_OYhYT1Lh7dUaAirE,429
|
|
55
|
+
digitalkin/services/registry/__init__.py,sha256=Zl4QAkCe9tOmmKGBWVuLQVFepdZiL0ec3VDj27IeyYM,270
|
|
56
|
+
digitalkin/services/registry/default_registry.py,sha256=VnWkF6nHpFxUKuUbZLPqzXqdA6oXmyV_ySpeuOCf_ko,277
|
|
57
|
+
digitalkin/services/registry/registry_strategy.py,sha256=uBXgZIv25jeXbeVO8vWvlNPxxNYu7_KiCw2PoE6AWr8,423
|
|
58
|
+
digitalkin/services/setup/default_setup.py,sha256=x1J6trXhyLC7V2OTe5pRY5mIFkQ4oyi3-aG50a1G1U4,8253
|
|
59
|
+
digitalkin/services/setup/grpc_setup.py,sha256=Bo84gLZSK8DKqHAVSVFOQdtZQkfpp78eNgjJnGhXQfU,12449
|
|
60
|
+
digitalkin/services/setup/setup_strategy.py,sha256=ZnJ_HwWCkHCPrqKekSD5L9y3p8wMwfjQ8sj2hLZq6go,4004
|
|
61
|
+
digitalkin/services/snapshot/__init__.py,sha256=Uzlnzo0CYlSpVsdiI37hW7xQk8hu3YA1fOI6O6MSzB0,270
|
|
62
|
+
digitalkin/services/snapshot/default_snapshot.py,sha256=Mb8QwWRsHh9I_tN0ln_ZiFa1QCZxOVWmuVLemQOTWpc,1058
|
|
63
|
+
digitalkin/services/snapshot/snapshot_strategy.py,sha256=B1TU3V_k9A-OdqBkdyc41-ihnrW5Btcwd1KyQdHT46A,898
|
|
64
|
+
digitalkin/services/storage/__init__.py,sha256=T-ocYLLphudkQgzvG47jBOm5GQsRFRIGA88y7Ur4akg,341
|
|
65
|
+
digitalkin/services/storage/default_storage.py,sha256=bHNPm8nLvytKqKP2ntLkikvqH1qDKOwofrStVJH6PJg,7765
|
|
66
|
+
digitalkin/services/storage/grpc_storage.py,sha256=b9z-2Q7mui8H0yn9GNb_RLu5RoLNFc55Dw2Xe_YklvY,4042
|
|
67
|
+
digitalkin/services/storage/storage_strategy.py,sha256=vGo4aYkEp_GZV11m7vd-xY_Z3gVa5K0gMTzbj2Au_3o,6600
|
|
68
|
+
digitalkin/utils/__init__.py,sha256=sJnY-ZUgsjMfojAjONC1VN14mhgIDnzyOlGkw21rRnM,28
|
|
69
|
+
digitalkin/utils/arg_parser.py,sha256=3YyI6oZhhrlTmPTrzlwpQzbCNWDFAT3pggcLxNtJoc0,4388
|
|
70
|
+
digitalkin-0.2.0.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
|
|
71
|
+
modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
|
+
modules/minimal_llm_module.py,sha256=JrRPTx7DCYrbmnfkE98xWBU_6x5lr7i8MFP16ATKkfo,5531
|
|
73
|
+
modules/storage_module.py,sha256=HktIy4j8-0w7ugMA7HqcNZymZIGruhchsWKXje9qR4o,6264
|
|
74
|
+
modules/text_transform_module.py,sha256=fAC6r_Ujca1Tz1qdWL4hTPZFn3gFWIVNj5-rytQMObE,7191
|
|
75
|
+
digitalkin-0.2.0.dist-info/METADATA,sha256=692wgNWfg0bqDK5y2cA-UxS3QvpYUEAtBP1XeTno3QE,29095
|
|
76
|
+
digitalkin-0.2.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
77
|
+
digitalkin-0.2.0.dist-info/top_level.txt,sha256=5_5e35inSM5YfWNZE21p5wGBojiVtQQML_WzbEk4BRU,31
|
|
78
|
+
digitalkin-0.2.0.dist-info/RECORD,,
|
modules/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Simple module calling an LLM."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from typing import Any, ClassVar
|
|
6
|
+
|
|
7
|
+
import grpc
|
|
8
|
+
import openai
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from digitalkin.grpc_servers.utils.models import SecurityMode, ServerConfig, ServerMode
|
|
12
|
+
from digitalkin.modules._base_module import BaseModule
|
|
13
|
+
from digitalkin.services.setup.setup_strategy import SetupData
|
|
14
|
+
|
|
15
|
+
# Configure logging with clear formatting
|
|
16
|
+
logging.basicConfig(
|
|
17
|
+
level=logging.INFO,
|
|
18
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
19
|
+
)
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Define schema models using Pydantic
|
|
24
|
+
class OpenAIToolInput(BaseModel):
|
|
25
|
+
"""Input model defining what data the module expects."""
|
|
26
|
+
|
|
27
|
+
prompt: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class OpenAIToolOutput(BaseModel):
|
|
31
|
+
"""Output model defining what data the module produces."""
|
|
32
|
+
|
|
33
|
+
response: str
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OpenAIToolSetup(BaseModel):
|
|
37
|
+
"""Setup model defining module configuration parameters."""
|
|
38
|
+
|
|
39
|
+
openai_key: str
|
|
40
|
+
model_name: str
|
|
41
|
+
dev_prompt: str
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class OpenAIToolSecret(BaseModel):
|
|
45
|
+
"""Secret model defining module configuration parameters."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
server_config = ServerConfig(
|
|
49
|
+
host="[::]",
|
|
50
|
+
port=50151,
|
|
51
|
+
mode=ServerMode.ASYNC,
|
|
52
|
+
security=SecurityMode.INSECURE,
|
|
53
|
+
max_workers=10,
|
|
54
|
+
credentials=None,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class OpenAIToolModule(BaseModule[OpenAIToolInput, OpenAIToolOutput, OpenAIToolSetup, OpenAIToolSecret]):
|
|
59
|
+
"""A openAI endpoint tool module module."""
|
|
60
|
+
|
|
61
|
+
name = "OpenAIToolModule"
|
|
62
|
+
description = "A module that interacts with OpenAI API to process text"
|
|
63
|
+
|
|
64
|
+
# Define the schema formats for the module
|
|
65
|
+
input_format = OpenAIToolInput
|
|
66
|
+
output_format = OpenAIToolOutput
|
|
67
|
+
setup_format = OpenAIToolSetup
|
|
68
|
+
secret_format = OpenAIToolSecret
|
|
69
|
+
|
|
70
|
+
openai_client: openai.OpenAI
|
|
71
|
+
|
|
72
|
+
# Define module metadata for discovery
|
|
73
|
+
metadata: ClassVar[dict[str, Any]] = {
|
|
74
|
+
"name": "Minimal_LLM_Tool",
|
|
75
|
+
"description": "Transforms input text using a streaming LLM response.",
|
|
76
|
+
"version": "1.0.0",
|
|
77
|
+
"tags": ["text", "transformation", "encryption", "streaming"],
|
|
78
|
+
}
|
|
79
|
+
# Define services_config_params with default values
|
|
80
|
+
services_config_strategies = {}
|
|
81
|
+
services_config_params = {
|
|
82
|
+
"storage": {
|
|
83
|
+
"config": {"setups": OpenAIToolSetup},
|
|
84
|
+
"server_config": server_config,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async def initialize(self, setup_data: SetupData) -> None:
|
|
89
|
+
"""Initialize the module capabilities.
|
|
90
|
+
|
|
91
|
+
This method is called when the module is loaded by the server.
|
|
92
|
+
Use it to set up module-specific resources or configurations.
|
|
93
|
+
"""
|
|
94
|
+
self.openai_client = openai.OpenAI(api_key=setup_data.current_setup_version.content["openai_key"])
|
|
95
|
+
# Define what capabilities this module provides
|
|
96
|
+
self.capabilities = ["text-processing", "streaming", "transformation"]
|
|
97
|
+
logger.info(
|
|
98
|
+
"Module %s initialized with capabilities: %s",
|
|
99
|
+
self.metadata["name"],
|
|
100
|
+
self.capabilities,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def run(
|
|
104
|
+
self,
|
|
105
|
+
input_data: dict[str, Any],
|
|
106
|
+
setup_data: SetupData,
|
|
107
|
+
callback: Callable,
|
|
108
|
+
) -> None:
|
|
109
|
+
"""Process input text and stream LLM responses.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
input_data: Contains the text to process.
|
|
113
|
+
setup_data: Contains model configuration and development prompt.
|
|
114
|
+
callback: Function to send output data back to the client.
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
grpc.RpcError: If gRPC communication fails.
|
|
118
|
+
openai.AuthenticationError: If authentication with OpenAI fails.
|
|
119
|
+
openai.APIConnectionError: If an API connection error occurs.
|
|
120
|
+
Exception: For any unexpected runtime errors.
|
|
121
|
+
"""
|
|
122
|
+
logger.info(
|
|
123
|
+
"Running job %s with prompt: '%s' on model: %s",
|
|
124
|
+
self.job_id,
|
|
125
|
+
input_data["prompt"],
|
|
126
|
+
setup_data.current_setup_version.content["model_name"],
|
|
127
|
+
)
|
|
128
|
+
try:
|
|
129
|
+
response = self.openai_client.responses.create(
|
|
130
|
+
model=setup_data.current_setup_version.content["model_name"],
|
|
131
|
+
tools=[{"type": "web_search_preview"}],
|
|
132
|
+
instructions=setup_data.current_setup_version.content["dev_prompt"],
|
|
133
|
+
input=input_data["prompt"],
|
|
134
|
+
)
|
|
135
|
+
if not response.output_text:
|
|
136
|
+
raise openai.APIConnectionError
|
|
137
|
+
output_data = OpenAIToolOutput(response=response.output_text).model_dump()
|
|
138
|
+
|
|
139
|
+
except openai.AuthenticationError as _:
|
|
140
|
+
message = "Authentication Error, OPENAI auth token was never set."
|
|
141
|
+
logger.exception(message)
|
|
142
|
+
output_data = {
|
|
143
|
+
"error": {
|
|
144
|
+
"code": grpc.StatusCode.UNAUTHENTICATED,
|
|
145
|
+
"error_message": message,
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
except openai.APIConnectionError as _:
|
|
149
|
+
message = "API Error, please try again."
|
|
150
|
+
logger.exception(message)
|
|
151
|
+
output_data = {"error": {"code": grpc.StatusCode.UNAVAILABLE, "error_message": message}}
|
|
152
|
+
await callback(job_id=self.job_id, output_data=output_data)
|
|
153
|
+
logger.info("Job %s completed", self.job_id)
|
|
154
|
+
|
|
155
|
+
async def cleanup(self) -> None:
|
|
156
|
+
"""Clean up any resources when the module is stopped.
|
|
157
|
+
|
|
158
|
+
This method is called when the module is being shut down.
|
|
159
|
+
Use it to close connections, free resources, etc.
|
|
160
|
+
"""
|
|
161
|
+
logger.info("Cleaning up module %s", self.metadata["name"])
|
|
162
|
+
# Release any resources here if needed.
|