digitalkin 0.2.13__py3-none-any.whl → 0.2.15__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.2.13
3
+ Version: 0.2.15
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.10
455
+ Requires-Dist: digitalkin-proto>=0.1.15
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.11.4
459
+ Requires-Dist: pydantic>=2.11.5
460
460
  Provides-Extra: dev
461
- Requires-Dist: typos>=1.32.0; extra == "dev"
462
- Requires-Dist: ruff>=0.11.9; extra == "dev"
463
- Requires-Dist: mypy>=1.15.0; extra == "dev"
464
- Requires-Dist: pyright>=1.1.400; 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"
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>=44.0.3; extra == "dev"
470
- Requires-Dist: taskiq[reload]>=0.11.17; extra == "dev"
469
+ Requires-Dist: cryptography>=45.0.4; extra == "dev"
471
470
  Provides-Extra: examples
472
471
  Requires-Dist: openai>=1.75.0; extra == "examples"
473
472
  Provides-Extra: tests
474
- Requires-Dist: freezegun>=1.5.1; extra == "tests"
473
+ Requires-Dist: freezegun>=1.5.2; extra == "tests"
475
474
  Requires-Dist: hdrhistogram>=0.10.3; extra == "tests"
476
475
  Requires-Dist: grpcio-testing>=1.71.0; extra == "tests"
477
476
  Requires-Dist: psutil>=7.0.0; extra == "tests"
478
- Requires-Dist: pytest>=8.3.4; extra == "tests"
479
- Requires-Dist: pytest-asyncio>=0.26.0; extra == "tests"
477
+ Requires-Dist: pytest>=8.4.0; extra == "tests"
478
+ Requires-Dist: pytest-asyncio>=1.0.0; extra == "tests"
480
479
  Requires-Dist: pytest-cov>=6.1.0; extra == "tests"
481
480
  Provides-Extra: taskiq
482
- Requires-Dist: rstream>=0.20.9; extra == "taskiq"
481
+ Requires-Dist: rstream>=0.30.0; extra == "taskiq"
483
482
  Requires-Dist: taskiq-aio-pika>=0.4.2; extra == "taskiq"
484
- Requires-Dist: taskiq-redis>=1.0.8; extra == "taskiq"
483
+ Requires-Dist: taskiq-redis>=1.0.9; extra == "taskiq"
484
+ Requires-Dist: taskiq[reload]>=0.11.17; extra == "taskiq"
485
485
  Dynamic: license-file
486
486
 
487
487
  # DigitalKin Python SDK
@@ -7,37 +7,37 @@ 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=FYm4fUSZE0epsu7qiHq0IkVIvAs5ZzTEDWDQWZeryGs,191
10
+ digitalkin/__version__.py,sha256=GxhXo6zJ5Xxw-pyzgpQ5JGuE2pD4yvOoWCyz8hiyjwU,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=tc4n8fu7bcMkwCI3CKkAKR4cZqyP_JTEW0lGtqsc5hs,10283
16
- digitalkin/grpc_servers/module_servicer.py,sha256=I6S8qDhKOwDD1tofoUhAfhN8VH6A7hAM5UAlwu91_Is,14747
16
+ digitalkin/grpc_servers/module_servicer.py,sha256=DZ1c_3XAXt-m5I6-CGqmrQ8TAFrYCUQj8R5rqMDKeQc,18383
17
17
  digitalkin/grpc_servers/registry_server.py,sha256=StY18DKYoPKQIU1SIzgito6D4_QA1aMVddZ8O2WGlHY,2223
18
18
  digitalkin/grpc_servers/registry_servicer.py,sha256=dqsKGHZ0LnaIvGt4ipaAuigd37sbJBndT4MAT029GsY,16471
19
- digitalkin/grpc_servers/utils/exceptions.py,sha256=I00OM8p8up20He4dU1fiHsvdLj1DymjR_UmoeUm2MSA,785
19
+ digitalkin/grpc_servers/utils/exceptions.py,sha256=SyOgvjggaUECYmSiqy8KJLHwHVt5IClSTxslHM-IZzI,931
20
20
  digitalkin/grpc_servers/utils/factory.py,sha256=jm6rFjiqmtSv7BIHNAOxsG9xXtSvWpx9TfzSQiX97MQ,5899
21
21
  digitalkin/grpc_servers/utils/grpc_client_wrapper.py,sha256=GXRqCTCufwWd8sVMoClnl-JpeBjgmdlSCD0a3YMU9D0,2594
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=ihvRlemJuFvU4armZIL-Vq-zaJx9UrjDoJAVPbEG8jw,345
25
+ digitalkin/models/module/__init__.py,sha256=iQJgq3OVvxoY6gkNCVdVz5bSGgLCy0TMY5H1FFxs-0Q,389
26
26
  digitalkin/models/module/module.py,sha256=NWOwCeD_NH0NL89AF_NJ0SwE7G1n-HTcRalodLCDmpM,749
27
- digitalkin/models/module/module_types.py,sha256=SxwzfDDnkyuQe50glVrxN6VPuJCkbB313FRyVZugIMw,312
27
+ digitalkin/models/module/module_types.py,sha256=rlT6prjBN-h1sLKstSwjxWXiyFgtxEn1mjOSLgfI6uA,385
28
28
  digitalkin/models/services/__init__.py,sha256=HsW7MUGFPvH7Ri28WN4BHHBfEQk5dzU_9FOWAc-0lSE,56
29
29
  digitalkin/models/services/cost.py,sha256=QTEuFD6xz62nob0z4ksE-INJWcZ-iFiuNW5mvXhpFes,1599
30
30
  digitalkin/models/services/storage.py,sha256=cYTVIriGKiprF9OerhSxmc_jM6fUTVwmeon1yQCinkE,143
31
31
  digitalkin/modules/__init__.py,sha256=ppYARmhvdVi55ofC0QZerIempSlcJYDeCXhcl4qXObw,278
32
- digitalkin/modules/_base_module.py,sha256=EwfCCIy3N1eBdBUj6KAdx0WzNRFJsyQDVCdA8Lwvtn4,10463
33
- digitalkin/modules/archetype_module.py,sha256=T2Ehj7EpAC2MO9WQbJv39hqRw7rh3exhVZTEL3JPM8U,421
34
- digitalkin/modules/tool_module.py,sha256=86g0M1wHZ1ReIc7AkKfyjnlGN2QYJBGxrEQpKVlyrZI,421
35
- digitalkin/modules/trigger_module.py,sha256=kVoI4Gdkw7WWUP5T6hSCNqw5FxibTxL6Tpq9KP7gg78,379
36
- digitalkin/modules/job_manager/base_job_manager.py,sha256=I3bduyGDjCJ6RsbwQvLp_NA6ucP8MJJVoIKpEbaP9ss,4706
32
+ digitalkin/modules/_base_module.py,sha256=wFnGGN97RNu3TJMdgMktOKdYPWmJL9WnwR120bPRXQg,12922
33
+ digitalkin/modules/archetype_module.py,sha256=7rleVOkZfFR7TQeaq6oZXLBuRWixKsUJMOr9HfDV0T8,566
34
+ digitalkin/modules/tool_module.py,sha256=7eWem70dEJiyoCtkGIJP4Ak2G8MzSruOjrByQMqW9-I,508
35
+ digitalkin/modules/trigger_module.py,sha256=FNiJmG3nTG1nDqKC1XdJI8PmFNZNPs1_QrH6RX7ev2Y,475
36
+ digitalkin/modules/job_manager/base_job_manager.py,sha256=Ku_MT7Cuf1R_qJU7SV-yHkzUhhMtmDOa8t5DyetvMxw,6177
37
37
  digitalkin/modules/job_manager/job_manager_models.py,sha256=onHy-DfInLZQveniMIWIKwTKSQjojz500JvHB54x93c,1129
38
- digitalkin/modules/job_manager/single_job_manager.py,sha256=Dekcnn8wb4epqGrWFAZ86YvvII553Hw0xjipgAINl4A,7745
39
- digitalkin/modules/job_manager/taskiq_broker.py,sha256=OnHZy-hAtVDU5FU4W9folZZKCrDrUk16VfHlfoECuiQ,5930
40
- digitalkin/modules/job_manager/taskiq_job_manager.py,sha256=ODqC7Snf-Flo0ugotqicrTgjFu4wgll6bUu7CM3l7ZE,7459
38
+ digitalkin/modules/job_manager/single_job_manager.py,sha256=DkQV3-E9XqgmuC6hoYKolTX2iv9lUJ8BSCde3zk1OU8,10264
39
+ digitalkin/modules/job_manager/taskiq_broker.py,sha256=sMXIgheOBshMiBUWUKph_5rxBHkip4rKusrrxFoa7uY,7379
40
+ digitalkin/modules/job_manager/taskiq_job_manager.py,sha256=evcE3o51DPWzW2y4ri6DFQZNZbFJXyvFb65SibExJH8,10152
41
41
  digitalkin/services/__init__.py,sha256=LqGk_5DJy8Bzz62ajIq9jCeYNKQUIgtSCpafZk15FLc,910
42
42
  digitalkin/services/base_strategy.py,sha256=QAQnJw1BbqcYMSzwlFyhHP5juBH2WKrZzWxqDr_sDHI,638
43
43
  digitalkin/services/services_config.py,sha256=4hc7-rHgSigoS3SuV0V9FReD2Dz7XoMXcD6iMBP2KKM,7391
@@ -50,9 +50,9 @@ digitalkin/services/cost/cost_strategy.py,sha256=VhHeqi9WnE1yoDBBVp5qmqwIt5tTZHU
50
50
  digitalkin/services/cost/default_cost.py,sha256=mEd0VL_tMcGU41q0f9MFeBYeKZBenv0mIHuwgXlQ7uQ,3869
51
51
  digitalkin/services/cost/grpc_cost.py,sha256=p_5mG72N7e4bxwBOD9DNokvLtinBILiqCfllmkqpmhw,6253
52
52
  digitalkin/services/filesystem/__init__.py,sha256=BhwMl_BUvM0d65fmglkp0SVwn3RfYiUOKJgIMnOCaGM,381
53
- digitalkin/services/filesystem/default_filesystem.py,sha256=8pRO80GtJ3n7StNllvwsgM6vMurJso1Xj4bWBt_zbjw,7381
54
- digitalkin/services/filesystem/filesystem_strategy.py,sha256=g5duep7Trc_NWq9WNtCrnheVxfMUvX6vJyx4W0hwwiY,2348
55
- digitalkin/services/filesystem/grpc_filesystem.py,sha256=IN2HX05lzUzsE9BZdp_nhEKYV2GNLJRQLduzFh1JN-w,8326
53
+ digitalkin/services/filesystem/default_filesystem.py,sha256=RATQqhdlujaTZNGbYtIstUSVSoahioghdzXFvv1X11Y,14771
54
+ digitalkin/services/filesystem/filesystem_strategy.py,sha256=CJTjCz0eDikeTSFlL_YMwdHpIPxBSO9Yx3fDTgfYSTM,8405
55
+ digitalkin/services/filesystem/grpc_filesystem.py,sha256=9Zw6SUbQNDV7B4rwgU5qG0b1v-2qBFElfLnjnpZ8qhA,12331
56
56
  digitalkin/services/identity/__init__.py,sha256=InkeyLgFYYwItx8mePA8HpfacOMWZwwuc0G4pWtKq9s,270
57
57
  digitalkin/services/identity/default_identity.py,sha256=Y2auZHrGSZTIN5D8HyjLvLcNbYFM1CNUE23x7p5VIGw,386
58
58
  digitalkin/services/identity/identity_strategy.py,sha256=skappBbds1_qa0Gr24FGrNX1N0_OYhYT1Lh7dUaAirE,429
@@ -61,7 +61,7 @@ digitalkin/services/registry/default_registry.py,sha256=VnWkF6nHpFxUKuUbZLPqzXqd
61
61
  digitalkin/services/registry/registry_strategy.py,sha256=uBXgZIv25jeXbeVO8vWvlNPxxNYu7_KiCw2PoE6AWr8,423
62
62
  digitalkin/services/setup/__init__.py,sha256=t6xcvEWqTbcRZstBFK9cESEqaZKvpW14VtYygxIqfYQ,65
63
63
  digitalkin/services/setup/default_setup.py,sha256=9VM3KwsuQcFQQ08RoOHWOE_-9BsRW0YGRtDWYTbQGdA,8246
64
- digitalkin/services/setup/grpc_setup.py,sha256=jLw9tfHMFhdVYXCIGC2ffx2HUgyNpgMi9G265nvkvMg,12440
64
+ digitalkin/services/setup/grpc_setup.py,sha256=qjdED3HYZtpgeYYpiIwBWwPgB1NtoAuKmB5unNNRnVQ,12480
65
65
  digitalkin/services/setup/setup_strategy.py,sha256=ZnJ_HwWCkHCPrqKekSD5L9y3p8wMwfjQ8sj2hLZq6go,4004
66
66
  digitalkin/services/snapshot/__init__.py,sha256=Uzlnzo0CYlSpVsdiI37hW7xQk8hu3YA1fOI6O6MSzB0,270
67
67
  digitalkin/services/snapshot/default_snapshot.py,sha256=Mb8QwWRsHh9I_tN0ln_ZiFa1QCZxOVWmuVLemQOTWpc,1058
@@ -74,13 +74,14 @@ digitalkin/utils/__init__.py,sha256=sJnY-ZUgsjMfojAjONC1VN14mhgIDnzyOlGkw21rRnM,
74
74
  digitalkin/utils/arg_parser.py,sha256=nvjI1pKDY1HfS0oGcMQPtdTQcggXLtpxXMbnMxNEKRU,3109
75
75
  digitalkin/utils/development_mode_action.py,sha256=TqRuAF_A7bDD4twRB4PnZcRoNeaiAnEdxM5kvy4aoaA,1511
76
76
  digitalkin/utils/llm_ready_schema.py,sha256=JjMug_lrQllqFoanaC091VgOqwAd-_YzcpqFlS7p778,2375
77
- digitalkin-0.2.13.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
77
+ digitalkin-0.2.15.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
78
78
  modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- modules/cpu_intensive_module.py,sha256=LUfgd1qFJ0HfsWMapSXUivgf5KGDpANKPORbcQBUjc4,8089
80
- modules/minimal_llm_module.py,sha256=6cygPliUb4mroOrUo5YirZfQQ1IeOT3xUHzPpDC_0Tc,10045
81
- modules/storage_module.py,sha256=KJA75oxXDUxZrLfoY5KxeyI8Gm1b3DxFuFj7LGOkeaQ,6389
82
- modules/text_transform_module.py,sha256=Db_WbJi7_gWyoNvQEVhHQf5VurDsU-jd9LMAalG0oZY,7277
83
- digitalkin-0.2.13.dist-info/METADATA,sha256=CUpDclUxsamv7icPsWN-ImippAec3_EQZUGm1cQGHFQ,30577
84
- digitalkin-0.2.13.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
85
- digitalkin-0.2.13.dist-info/top_level.txt,sha256=5_5e35inSM5YfWNZE21p5wGBojiVtQQML_WzbEk4BRU,31
86
- digitalkin-0.2.13.dist-info/RECORD,,
79
+ modules/cpu_intensive_module.py,sha256=ejB9XPnFfA0uCuFUQbM3fy5UYfqqAlF36rv_P5Ri8ho,8363
80
+ modules/minimal_llm_module.py,sha256=Ijld__ZnhzfLwpXD1XVkLZ7jyKZKyOFZczOpiPttJZc,11216
81
+ modules/text_transform_module.py,sha256=bwPSnEUthZQyfLwcTLo52iAxItAoknkLh8Y3m5aywaY,7251
82
+ services/filesystem_module.py,sha256=71Mcja8jCQqiqFHPdsIXplFIHTvgkxRhp0TRXuCfgkk,7430
83
+ services/storage_module.py,sha256=ybTMqmvGaTrR8PqJ4FU0cwxaDjT36TskVrGoetTGmno,6955
84
+ digitalkin-0.2.15.dist-info/METADATA,sha256=c9lkB9hRvwrBAGVvaQ-n7EQME-w-qt21ER2lutKgWbg,30580
85
+ digitalkin-0.2.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
86
+ digitalkin-0.2.15.dist-info/top_level.txt,sha256=gcjqlyrZuLjIyxrOIavCQM_olpr6ND5kPKkZd2j0xGo,40
87
+ digitalkin-0.2.15.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,3 +1,4 @@
1
1
  base_server
2
2
  digitalkin
3
3
  modules
4
+ services
@@ -127,6 +127,16 @@ class CPUOutput(BaseModel):
127
127
  )
128
128
 
129
129
 
130
+ class CPUConfigSetup(BaseModel):
131
+ """Config Setup model definining data that will be pre-computed for each setup and module instance."""
132
+
133
+ files: list[str] = Field(
134
+ ...,
135
+ title="Files to embed",
136
+ description="List of files to embed in the setup lifecycle.",
137
+ )
138
+
139
+
130
140
  class CPUSetup(BaseModel):
131
141
  """Setup model defining module configuration parameters."""
132
142
 
@@ -175,7 +185,7 @@ client_config = ClientConfig(
175
185
  )
176
186
 
177
187
 
178
- class CPUIntensiveModule(BaseModule[CPUInput, CPUOutput, CPUSetup, CPUToolSecret]):
188
+ class CPUIntensiveModule(BaseModule[CPUInput, CPUOutput, CPUSetup, CPUToolSecret, None]):
179
189
  """A CPU endpoint tool module module."""
180
190
 
181
191
  name = "CPUIntensiveModule"
@@ -202,7 +212,6 @@ class CPUIntensiveModule(BaseModule[CPUInput, CPUOutput, CPUSetup, CPUToolSecret
202
212
  "client_config": client_config,
203
213
  },
204
214
  "filesystem": {
205
- "config": {},
206
215
  "client_config": client_config,
207
216
  },
208
217
  "cost": {
@@ -11,7 +11,6 @@ from pydantic import BaseModel, Field
11
11
  from digitalkin.grpc_servers.utils.models import ClientConfig, SecurityMode, ServerMode
12
12
  from digitalkin.modules._base_module import BaseModule
13
13
  from digitalkin.services.services_models import ServicesStrategy
14
- from digitalkin.services.setup.setup_strategy import SetupData
15
14
 
16
15
  # Configure logging with clear formatting
17
16
  logging.basicConfig(
@@ -154,6 +153,16 @@ class OpenAISetup(BaseModel):
154
153
  )
155
154
 
156
155
 
156
+ class OpenAIConfigSetup(BaseModel):
157
+ """Setup model defining module configuration parameters."""
158
+
159
+ rag_files: list[bytes] = Field(
160
+ ...,
161
+ title="RAG Files",
162
+ description="Files used for retrieval-augmented generation (RAG) with the OpenAI module.",
163
+ )
164
+
165
+
157
166
  class OpenAIToolSecret(BaseModel):
158
167
  """Secret model defining module configuration parameters."""
159
168
 
@@ -167,13 +176,22 @@ client_config = ClientConfig(
167
176
  )
168
177
 
169
178
 
170
- class OpenAIToolModule(BaseModule[OpenAIInput, OpenAIOutput, OpenAISetup, OpenAIToolSecret]):
179
+ class OpenAIToolModule(
180
+ BaseModule[
181
+ OpenAIInput,
182
+ OpenAIOutput,
183
+ OpenAISetup,
184
+ OpenAIToolSecret,
185
+ OpenAIConfigSetup,
186
+ ]
187
+ ):
171
188
  """A openAI endpoint tool module module."""
172
189
 
173
190
  name = "OpenAIToolModule"
174
191
  description = "A module that interacts with OpenAI API to process text"
175
192
 
176
193
  # Define the schema formats for the module
194
+ config_setup_format = OpenAIConfigSetup
177
195
  input_format = OpenAIInput
178
196
  output_format = OpenAIOutput
179
197
  setup_format = OpenAISetup
@@ -205,7 +223,27 @@ class OpenAIToolModule(BaseModule[OpenAIInput, OpenAIOutput, OpenAISetup, OpenAI
205
223
  },
206
224
  }
207
225
 
208
- async def initialize(self, setup_data: SetupData) -> None:
226
+ async def run_config_setup(
227
+ self,
228
+ config_setup_data: OpenAIConfigSetup,
229
+ setup_data: OpenAISetup,
230
+ callback: Callable,
231
+ ) -> None:
232
+ """Configure the module with additional setup data.
233
+
234
+ Args:
235
+ config_setup_data: Additional configuration content.
236
+ setup_data: Initial setup data for the module.
237
+ callback: Function to send output data back to the client.
238
+ """
239
+ logger.info("Configuring OpenAIToolModule with additional setup data. %s", config_setup_data)
240
+
241
+ # Here you can process config_content and update setup_data as needed
242
+ # For now, we just return the original setup_data
243
+ setup_data.developer_prompt = "| + |".join(f.decode("utf-8") for f in config_setup_data.rag_files)
244
+ await callback(setup_data)
245
+
246
+ async def initialize(self, setup_data: OpenAISetup) -> None:
209
247
  """Initialize the module capabilities.
210
248
 
211
249
  This method is called when the module is loaded by the server.
@@ -93,7 +93,6 @@ class TextTransformModule(BaseModule[TextTransformInput, TextTransformOutput, Te
93
93
  "client_config": client_config,
94
94
  },
95
95
  "filesystem": {
96
- "config": {},
97
96
  "client_config": client_config,
98
97
  },
99
98
  }
@@ -0,0 +1,198 @@
1
+ """Example module implementation to test ArchetypeModule functionality."""
2
+
3
+ import asyncio
4
+ import datetime
5
+ from collections.abc import Callable
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+ from digitalkin.logger import logger
11
+ from digitalkin.models.module import ModuleStatus
12
+ from digitalkin.modules.archetype_module import ArchetypeModule
13
+ from digitalkin.services.services_config import ServicesConfig
14
+ from digitalkin.services.services_models import ServicesMode
15
+ from digitalkin.services.filesystem.filesystem_strategy import FilesystemRecord, FileFilter, UploadFileData
16
+
17
+
18
+ class ExampleInput(BaseModel):
19
+ """Input model for example module."""
20
+
21
+ message: str = Field(description="Message to process")
22
+ number: int = Field(description="Number to process")
23
+
24
+
25
+ class ExampleOutput(BaseModel):
26
+ """Output model for example module."""
27
+
28
+ processed_message: str = Field(description="The processed message")
29
+ processed_number: int = Field(description="The processed number")
30
+ timestamp: datetime.datetime = Field(description="When the processing was done")
31
+
32
+
33
+ class ExampleSetup(BaseModel):
34
+ """Setup model for example module."""
35
+
36
+ processing_mode: str = Field(description="Mode to process data in", default="default")
37
+ multiply_factor: int = Field(description="Factor to multiply number by", default=1)
38
+
39
+
40
+ class ExampleSecret(BaseModel):
41
+ """Secret model for example module."""
42
+
43
+ api_key: str = Field(description="API key for external service")
44
+
45
+
46
+ class ExampleStorage(BaseModel):
47
+ """Secret model for example module."""
48
+
49
+ test_key: str = Field(description="Test value for storage")
50
+
51
+
52
+ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, ExampleSecret, None]):
53
+ """Example module that demonstrates ArchetypeModule functionality."""
54
+
55
+ name = "ExampleModule"
56
+ description = "An example module for testing purposes"
57
+ input_format = ExampleInput
58
+ output_format = ExampleOutput
59
+ setup_format = ExampleSetup
60
+ secret_format = ExampleSecret
61
+ metadata = {"name": "ExampleModule", "description": "A module for testing ArchetypeModule functionality"}
62
+
63
+ # Define services_config_params with default values
64
+ services_config_strategies = {}
65
+ services_config_params = {"cost": {"config": {}}, "storage": {"config": {}}} # Filesystem has no config but it's enabled
66
+
67
+ def __init__(self, job_id: str, mission_id: str, setup_version_id: str) -> None:
68
+ """Initialize the example module.
69
+
70
+ Args:
71
+ job_id: Unique identifier for the job
72
+ name: Optional name for the module
73
+ """
74
+ # Initialize services configuration using the class attribute before the instance is created
75
+ self.services_config = ServicesConfig(
76
+ services_config_strategies=self.services_config_strategies,
77
+ services_config_params=self.services_config_params,
78
+ mode=ServicesMode.LOCAL,
79
+ )
80
+
81
+ super().__init__(job_id, mission_id, setup_version_id)
82
+
83
+ async def initialize(self, setup_data: ExampleSetup) -> None:
84
+ """Initialize the module.
85
+
86
+ Args:
87
+ setup_data: Setup data for the module
88
+ """
89
+ logger.info("Initializing ExampleModule with setup data: %s", setup_data)
90
+ self.setup = self.setup_format.model_validate(setup_data)
91
+ logger.info("Initialization complete, using processing mode: [%s]", self.setup.processing_mode)
92
+
93
+ async def run(
94
+ self,
95
+ input_data: dict[str, Any],
96
+ setup_data: ExampleSetup,
97
+ callback: Callable,
98
+ ) -> None:
99
+ """Run the module.
100
+
101
+ Args:
102
+ input_data: Input data for the module
103
+ setup_data: Setup data for the module
104
+ callback: Callback function to report progress
105
+ """
106
+ # Validate the input data
107
+ input_model = self.input_format.model_validate(input_data)
108
+ logger.info("Running with input data: %s", input_model)
109
+
110
+ # Process the data
111
+ processed_message = f"Processed: {input_model.message}"
112
+ processed_number = input_model.number * self.setup.multiply_factor
113
+
114
+ # Create output model
115
+ file = UploadFileData(
116
+ content=b"%s\n%s" % (processed_message.encode(), str(processed_number).encode()),
117
+ name="example_output.txt",
118
+ file_type="text/plain",
119
+ content_type="text/plain",
120
+ metadata={"example_key": "example_value"},
121
+ replace_if_exists=True,
122
+ )
123
+
124
+ records, uploaded, failed = self.filesystem.upload_files(files=[file])
125
+ for record in records:
126
+ logger.info("Uploaded file: %s, uploaded: %d, failed: %d", record, uploaded, failed)
127
+ logger.info("Stored file with ID: %s", record.id)
128
+ callback(record.model_dump())
129
+ # Call the callback with the output data
130
+
131
+
132
+ # Wait a bit to simulate processing time
133
+ await asyncio.sleep(1)
134
+
135
+ async def run_config_setup(
136
+ self,
137
+ setup_data: ExampleSetup,
138
+ ) -> None:
139
+ """Run the configuration setup for the module.
140
+
141
+ Args:
142
+ setup_data: Setup data for the module
143
+ """
144
+ logger.info("Running config setup with data: %s", setup_data)
145
+ # Here we could implement any additional configuration logic if needed
146
+
147
+ async def cleanup(self) -> None:
148
+ """Clean up the module."""
149
+ logger.info("Cleaning up ExampleModule")
150
+ # Nothing to clean up in this example
151
+
152
+
153
+ async def test_module() -> None:
154
+ """Test the example module."""
155
+ # Create the module
156
+ module = ExampleModule(job_id="test-job-123", mission_id="test-mission-123", setup_version_id="test-setup-123")
157
+
158
+ # Define input and setup data
159
+ input_data = ExampleInput(message="Hello, world!", number=42)
160
+
161
+ setup_data = ExampleSetup(processing_mode="test", multiply_factor=10)
162
+
163
+ # Define a callback function
164
+ def callback(result) -> None:
165
+ logger.info(f"callback {result}")
166
+
167
+ # Start the module
168
+ await module.start(input_data, setup_data, callback)
169
+
170
+ # Wait for the module to complete
171
+ while module.status not in {ModuleStatus.STOPPED, ModuleStatus.FAILED}:
172
+ await asyncio.sleep(0.5)
173
+
174
+ # Check the storage
175
+ if module.status == ModuleStatus.STOPPED:
176
+ files, nb_results = module.filesystem.get_files(
177
+ filters=FileFilter(name="example_output.txt", context="test-mission-123"),
178
+ )
179
+ for file in files:
180
+ module.filesystem.update_file(file.id, file_type="updated")
181
+ # module.filesystem.delete_files(filters=FileFilter(name="example_output.txt", context="test-mission-123"), permanent=True)
182
+
183
+ logger.info("Retrieved file: %s with ID: %s", file.name, file.id)
184
+ try:
185
+ file_record = module.filesystem.get_file(file_id=file.id, include_content=True)
186
+ if file_record:
187
+ logger.info("File ID: %s", file_record.id)
188
+ logger.info("File name: %s", file_record.name)
189
+ logger.info("File type: %s", file_record.file_type)
190
+ logger.info("File status: %s", file_record.status)
191
+ logger.info("File content: %s", file_record.content.decode())
192
+ except Exception:
193
+ logger.error("No file retrieved")
194
+
195
+
196
+ if __name__ == "__main__":
197
+ # Run the module test
198
+ asyncio.run(test_module())
@@ -51,7 +51,7 @@ class ExampleStorage(BaseModel):
51
51
  test_key: str = Field(description="Test value for storage")
52
52
 
53
53
 
54
- class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, ExampleSecret]):
54
+ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, ExampleSecret, None]):
55
55
  """Example module that demonstrates ArchetypeModule functionality."""
56
56
 
57
57
  name = "ExampleModule"
@@ -64,14 +64,15 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
64
64
 
65
65
  # Define services_config_params with default values
66
66
  services_config_strategies = {}
67
- services_config_params = {"storage": {"config": {"example": ExampleOutput}}, "filesystem": {"config": {}}}
67
+ services_config_params = {"storage": {"config": {"example": ExampleOutput}},"cost": {"config":{}}}
68
68
 
69
- def __init__(self, job_id: str, mission_id: str) -> None:
69
+ def __init__(self, job_id: str, mission_id: str, setup_version_id: str) -> None:
70
70
  """Initialize the example module.
71
71
 
72
72
  Args:
73
73
  job_id: Unique identifier for the job
74
- name: Optional name for the module
74
+ mission_id: Unique identifier for the mission
75
+ setup_version_id: Unique identifier for the setup version
75
76
  """
76
77
  # Initialize services configuration using the class attribute before the instance is created
77
78
  self.services_config = ServicesConfig(
@@ -80,7 +81,7 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
80
81
  mode=ServicesMode.LOCAL,
81
82
  )
82
83
 
83
- super().__init__(job_id, mission_id)
84
+ super().__init__(job_id, mission_id, setup_version_id)
84
85
 
85
86
  async def initialize(self, setup_data: ExampleSetup) -> None:
86
87
  """Initialize the module.
@@ -92,6 +93,18 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
92
93
  self.setup = self.setup_format.model_validate(setup_data)
93
94
  logger.info("Initialization complete, using processing mode: [%s]", self.setup.processing_mode)
94
95
 
96
+ async def run_config_setup(
97
+ self,
98
+ setup_data: ExampleSetup,
99
+ ) -> None:
100
+ """Run the configuration setup for the module.
101
+
102
+ Args:
103
+ setup_data: Setup data for the module
104
+ """
105
+ logger.info("Running config setup with data: %s", setup_data)
106
+ # Here we could implement any additional configuration logic if needed
107
+
95
108
  async def run(
96
109
  self,
97
110
  input_data: dict[str, Any],
@@ -142,7 +155,7 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
142
155
  async def test_module() -> None:
143
156
  """Test the example module."""
144
157
  # Create the module
145
- module = ExampleModule(job_id="test-job-123", mission_id="test-mission-123")
158
+ module = ExampleModule(job_id="test-job-123", mission_id="test-mission-123", setup_version_id="test-setup-123")
146
159
 
147
160
  # Define input and setup data
148
161
  input_data = ExampleInput(message="Hello, world!", number=42)
@@ -171,7 +184,7 @@ async def test_module() -> None:
171
184
  def test_storage_directly() -> None:
172
185
  """Test the storage service directly."""
173
186
  # Initialize storage service
174
- storage = ServicesConfig().storage(mission_id="test-mission", config={"example": ExampleStorage})
187
+ storage = ServicesConfig().storage(mission_id="test-mission",setup_version_id="test-setup-123", config={"example": ExampleStorage})
175
188
 
176
189
  # Create a test record
177
190
  storage.store("example", "test_table", {"test_key": "test_value"}, "OUTPUT")