piphi-runtime-kit-python 0.4.2__py3-none-any.whl → 0.4.4__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.
@@ -8,7 +8,22 @@ from .runtime.auth import (
8
8
  format_runtime_auth_sync_log,
9
9
  mask_token,
10
10
  )
11
- from .runtime.config_sync import ConfigSyncCoordinator, build_sync_response, reconcile_config_ids
11
+ from .runtime.config_sync import (
12
+ CORE_BASE_URL_ENV_NAME,
13
+ DEFAULT_RUNTIME_CONFIG_SNAPSHOT_FILENAME,
14
+ DEFAULT_RUNTIME_VOLUME_DIR,
15
+ RUNTIME_CONFIG_SNAPSHOT_PATH_ENV_NAME,
16
+ ConfigSyncCoordinator,
17
+ RuntimeConfigRehydrateResult,
18
+ build_runtime_config_snapshot_from_core_rows,
19
+ build_sync_response,
20
+ fetch_core_runtime_config_snapshot,
21
+ load_runtime_config_snapshot,
22
+ reconcile_config_ids,
23
+ rehydrate_runtime_configs,
24
+ resolve_core_base_url,
25
+ resolve_runtime_config_snapshot_path,
26
+ )
12
27
  from .runtime.configuration import (
13
28
  build_config_apply_response,
14
29
  build_config_remove_response,
@@ -109,6 +124,10 @@ __all__ = [
109
124
  "CoreUnavailableError",
110
125
  "CoreUnexpectedResponseError",
111
126
  "DEFAULT_CORE_CLIENT_TIMEOUT_SECONDS",
127
+ "CORE_BASE_URL_ENV_NAME",
128
+ "DEFAULT_RUNTIME_CONFIG_SNAPSHOT_FILENAME",
129
+ "DEFAULT_RUNTIME_VOLUME_DIR",
130
+ "RUNTIME_CONFIG_SNAPSHOT_PATH_ENV_NAME",
112
131
  "DEFAULT_RUNTIME_CONTAINER_ID_ENV_NAME",
113
132
  "DEFAULT_RUNTIME_INTERNAL_TOKEN_ENV_NAME",
114
133
  "RUNTIME_CONTAINER_ID_HEADER_NAME",
@@ -127,6 +146,7 @@ __all__ = [
127
146
  "RuntimeConfig",
128
147
  "RuntimeConfigApplyResponse",
129
148
  "RuntimeConfigRemoveResponse",
149
+ "RuntimeConfigRehydrateResult",
130
150
  "RuntimeConfigSnapshot",
131
151
  "RuntimeConfigSyncResponse",
132
152
  "RuntimeContext",
@@ -143,6 +163,7 @@ __all__ = [
143
163
  "EventTransport",
144
164
  "IntegrationEventIngestResponse",
145
165
  "IntegrationEventListResponse",
166
+ "build_runtime_config_snapshot_from_core_rows",
146
167
  "build_discovery_response",
147
168
  "classify_core_delivery_error",
148
169
  "build_core_event_payload",
@@ -165,10 +186,12 @@ __all__ = [
165
186
  "dispatch_event_delivery",
166
187
  "dispatch_telemetry_delivery",
167
188
  "extract_runtime_auth_headers",
189
+ "fetch_core_runtime_config_snapshot",
168
190
  "format_config_apply_log",
169
191
  "format_discovery_attempt_log",
170
192
  "format_event_log",
171
193
  "format_runtime_auth_sync_log",
194
+ "load_runtime_config_snapshot",
172
195
  "mask_token",
173
196
  "MqttBrokerConfig",
174
197
  "MqttJsonClient",
@@ -176,6 +199,9 @@ __all__ = [
176
199
  "normalize_event_payload",
177
200
  "redact_config_secrets",
178
201
  "reconcile_config_ids",
202
+ "rehydrate_runtime_configs",
203
+ "resolve_core_base_url",
204
+ "resolve_runtime_config_snapshot_path",
179
205
  "runtime_lifespan",
180
206
  "schedule_event_delivery",
181
207
  "schedule_telemetry_delivery",
@@ -3,13 +3,318 @@ from __future__ import annotations
3
3
  """Helpers for basic config-sync orchestration and generation tracking."""
4
4
 
5
5
  from dataclasses import dataclass
6
- from typing import Awaitable, Callable, TypeVar
6
+ import json
7
+ import os
8
+ from pathlib import Path
9
+ from typing import Any, Awaitable, Callable, TypeVar
10
+
11
+ import httpx
7
12
 
8
13
  from ..schemas import RuntimeConfig, RuntimeConfigSnapshot, RuntimeConfigSyncResponse
14
+ from .auth import build_runtime_auth_headers
15
+ from .context import RuntimeContext
16
+ from .lifespan import DEFAULT_CORE_CLIENT_TIMEOUT_SECONDS
9
17
  from .state import RuntimeProcessState
10
18
 
11
19
  TConfig = TypeVar("TConfig", bound=RuntimeConfig)
12
20
 
21
+ CORE_BASE_URL_ENV_NAME = "PIPHI_CORE_BASE_URL"
22
+ RUNTIME_CONTAINER_ID_ENV_NAME = "PIPHI_CONTAINER_ID"
23
+ RUNTIME_CONFIG_SNAPSHOT_PATH_ENV_NAME = "PIPHI_CONFIG_SNAPSHOT_PATH"
24
+ DEFAULT_RUNTIME_VOLUME_DIR = "/.piphinetwork"
25
+ DEFAULT_RUNTIME_CONFIG_SNAPSHOT_FILENAME = "configs.json"
26
+ CORE_RUNTIME_CONFIG_FETCH_PATH = (
27
+ "/api/v2/integrations/config/fetch/all/by/container/internal"
28
+ )
29
+
30
+
31
+ SnapshotApplyCallable = Callable[[Any], Awaitable[Any]]
32
+
33
+
34
+ def resolve_core_base_url(default: str | None = None) -> str | None:
35
+ """Resolve Core's base URL from the managed-runtime environment."""
36
+ value = (os.getenv(CORE_BASE_URL_ENV_NAME) or "").strip().rstrip("/")
37
+ if value:
38
+ return value
39
+ return default.rstrip("/") if isinstance(default, str) and default.strip() else default
40
+
41
+
42
+ def resolve_runtime_config_snapshot_path(
43
+ *,
44
+ container_id: str | None = None,
45
+ volume_dir: str | Path = DEFAULT_RUNTIME_VOLUME_DIR,
46
+ ) -> Path:
47
+ """Resolve the local config snapshot path mounted by PiPhi Core."""
48
+ explicit_path = (os.getenv(RUNTIME_CONFIG_SNAPSHOT_PATH_ENV_NAME) or "").strip()
49
+ if explicit_path:
50
+ return Path(explicit_path)
51
+
52
+ resolved_container_id = (
53
+ str(container_id or "").strip()
54
+ or (os.getenv(RUNTIME_CONTAINER_ID_ENV_NAME) or "").strip()
55
+ )
56
+ if resolved_container_id:
57
+ return Path(volume_dir).joinpath(f"{resolved_container_id}.json")
58
+ return Path(volume_dir).joinpath(DEFAULT_RUNTIME_CONFIG_SNAPSHOT_FILENAME)
59
+
60
+
61
+ def load_runtime_config_snapshot(
62
+ *,
63
+ path: str | Path | None = None,
64
+ container_id: str | None = None,
65
+ volume_dir: str | Path = DEFAULT_RUNTIME_VOLUME_DIR,
66
+ ) -> RuntimeConfigSnapshot | None:
67
+ """Load Core's last known config snapshot from the mounted runtime volume.
68
+
69
+ Missing, unreadable, or invalid snapshots return ``None`` so integrations can
70
+ treat snapshot rehydration as a safe startup fallback rather than a crash
71
+ trigger.
72
+ """
73
+ snapshot_path = (
74
+ Path(path)
75
+ if path is not None
76
+ else resolve_runtime_config_snapshot_path(
77
+ container_id=container_id,
78
+ volume_dir=volume_dir,
79
+ )
80
+ )
81
+ try:
82
+ raw_payload = snapshot_path.read_text(encoding="utf-8")
83
+ except (FileNotFoundError, OSError):
84
+ return None
85
+
86
+ try:
87
+ payload = json.loads(raw_payload)
88
+ except json.JSONDecodeError:
89
+ return None
90
+ if not isinstance(payload, dict):
91
+ return None
92
+
93
+ try:
94
+ return RuntimeConfigSnapshot.model_validate(payload)
95
+ except ValueError:
96
+ return None
97
+
98
+
99
+ @dataclass(slots=True)
100
+ class RuntimeConfigRehydrateResult:
101
+ """Describe what happened during runtime startup config rehydration."""
102
+
103
+ snapshot_found: bool = False
104
+ snapshot_applied: bool = False
105
+ snapshot_config_count: int = 0
106
+ snapshot_generation: int | None = None
107
+ core_attempted: bool = False
108
+ core_applied: bool = False
109
+ core_config_count: int = 0
110
+ core_generation: int | None = None
111
+ core_error: str | None = None
112
+ missing_runtime_auth: bool = False
113
+
114
+ @property
115
+ def applied_any(self) -> bool:
116
+ """Return whether any startup source applied configs."""
117
+ return self.snapshot_applied or self.core_applied
118
+
119
+
120
+ def _model_validate_or_create(model_type: type[Any], payload: dict[str, Any]) -> Any:
121
+ validator = getattr(model_type, "model_validate", None)
122
+ if callable(validator):
123
+ return validator(payload)
124
+ return model_type(**payload)
125
+
126
+
127
+ def _snapshot_validate_or_create(model_type: type[Any], payload: dict[str, Any]) -> Any:
128
+ validator = getattr(model_type, "model_validate", None)
129
+ if callable(validator):
130
+ return validator(payload)
131
+ return model_type(**payload)
132
+
133
+
134
+ def _convert_snapshot_configs(
135
+ snapshot: RuntimeConfigSnapshot,
136
+ *,
137
+ config_model: type[TConfig],
138
+ snapshot_model: type[Any],
139
+ reason: str,
140
+ ) -> Any:
141
+ configs = [
142
+ _model_validate_or_create(config_model, config.model_dump())
143
+ for config in snapshot.configs
144
+ ]
145
+ return _snapshot_validate_or_create(
146
+ snapshot_model,
147
+ {
148
+ "schema_version": snapshot.schema_version,
149
+ "container_id": snapshot.container_id,
150
+ "integration_id": snapshot.integration_id,
151
+ "driver_pid": snapshot.driver_pid,
152
+ "reason": snapshot.reason or reason,
153
+ "generation": snapshot.generation,
154
+ "updated_at": snapshot.updated_at,
155
+ "configs": configs,
156
+ "deleted_config_ids": snapshot.deleted_config_ids,
157
+ "config_hash": snapshot.config_hash,
158
+ "internal_token": snapshot.internal_token,
159
+ },
160
+ )
161
+
162
+
163
+ def build_runtime_config_snapshot_from_core_rows(
164
+ rows: list[dict[str, Any]],
165
+ *,
166
+ container_id: str,
167
+ config_model: type[TConfig] = RuntimeConfig,
168
+ snapshot_model: type[Any] = RuntimeConfigSnapshot,
169
+ reason: str = "startup_rehydrate",
170
+ ) -> Any:
171
+ """Build a runtime config snapshot from Core's internal config rows.
172
+
173
+ Core returns database-shaped rows where the integration config lives under
174
+ ``config_data``. This helper turns those rows into the same snapshot shape
175
+ integrations receive from the normal config-sync endpoint.
176
+ """
177
+ configs: list[Any] = []
178
+ for row in rows:
179
+ if not isinstance(row, dict):
180
+ continue
181
+ config_data = row.get("config_data")
182
+ if not isinstance(config_data, dict):
183
+ continue
184
+ payload = {**config_data}
185
+ payload["container_id"] = payload.get("container_id") or container_id
186
+ configs.append(_model_validate_or_create(config_model, payload))
187
+
188
+ return _snapshot_validate_or_create(
189
+ snapshot_model,
190
+ {
191
+ "container_id": container_id,
192
+ "reason": reason,
193
+ "configs": configs,
194
+ },
195
+ )
196
+
197
+
198
+ async def fetch_core_runtime_config_snapshot(
199
+ *,
200
+ runtime_context: RuntimeContext,
201
+ client: httpx.AsyncClient,
202
+ core_base_url: str | None = None,
203
+ config_model: type[TConfig] = RuntimeConfig,
204
+ snapshot_model: type[Any] = RuntimeConfigSnapshot,
205
+ timeout_seconds: float = DEFAULT_CORE_CLIENT_TIMEOUT_SECONDS,
206
+ reason: str = "startup_rehydrate",
207
+ ) -> Any | None:
208
+ """Fetch the latest runtime configs from Core using managed-runtime auth."""
209
+ container_id, internal_token = runtime_context.auth.resolve()
210
+ if not container_id or not internal_token:
211
+ return None
212
+
213
+ base_url = resolve_core_base_url(core_base_url) or resolve_core_base_url(
214
+ "http://127.0.0.1:31419"
215
+ )
216
+ if not base_url:
217
+ return None
218
+
219
+ response = await client.get(
220
+ f"{base_url}{CORE_RUNTIME_CONFIG_FETCH_PATH}",
221
+ params={"container_id": container_id},
222
+ headers=build_runtime_auth_headers(
223
+ container_id=container_id,
224
+ internal_token=internal_token,
225
+ ),
226
+ timeout=timeout_seconds,
227
+ )
228
+ response.raise_for_status()
229
+
230
+ rows = response.json()
231
+ if not rows:
232
+ return None
233
+ if not isinstance(rows, list):
234
+ raise ValueError("Core runtime config response must be a list.")
235
+
236
+ return build_runtime_config_snapshot_from_core_rows(
237
+ rows,
238
+ container_id=container_id,
239
+ config_model=config_model,
240
+ snapshot_model=snapshot_model,
241
+ reason=reason,
242
+ )
243
+
244
+
245
+ async def rehydrate_runtime_configs(
246
+ *,
247
+ runtime_context: RuntimeContext,
248
+ client: httpx.AsyncClient,
249
+ apply_snapshot: SnapshotApplyCallable,
250
+ config_model: type[TConfig] = RuntimeConfig,
251
+ snapshot_model: type[Any] = RuntimeConfigSnapshot,
252
+ core_base_url: str | None = None,
253
+ timeout_seconds: float = DEFAULT_CORE_CLIENT_TIMEOUT_SECONDS,
254
+ snapshot_path: str | Path | None = None,
255
+ snapshot_volume_dir: str | Path = DEFAULT_RUNTIME_VOLUME_DIR,
256
+ snapshot_reason: str = "startup_snapshot_rehydrate",
257
+ core_reason: str = "startup_rehydrate",
258
+ raise_core_errors: bool = False,
259
+ ) -> RuntimeConfigRehydrateResult:
260
+ """Rehydrate runtime configs from the mounted snapshot and then Core.
261
+
262
+ Integration authors provide only their config model and apply callback. The
263
+ SDK handles startup ordering, managed-runtime auth, Core request headers,
264
+ local snapshot fallback, and safe offline behavior.
265
+ """
266
+ result = RuntimeConfigRehydrateResult()
267
+ container_id = runtime_context.auth.container_id
268
+
269
+ cached_snapshot = load_runtime_config_snapshot(
270
+ path=snapshot_path,
271
+ container_id=container_id,
272
+ volume_dir=snapshot_volume_dir,
273
+ )
274
+ if cached_snapshot is not None:
275
+ result.snapshot_found = True
276
+ snapshot = _convert_snapshot_configs(
277
+ cached_snapshot,
278
+ config_model=config_model,
279
+ snapshot_model=snapshot_model,
280
+ reason=snapshot_reason,
281
+ )
282
+ await apply_snapshot(snapshot)
283
+ result.snapshot_applied = True
284
+ result.snapshot_config_count = len(getattr(snapshot, "configs", []) or [])
285
+ result.snapshot_generation = getattr(snapshot, "generation", None)
286
+
287
+ resolved_container_id, resolved_internal_token = runtime_context.auth.resolve()
288
+ if not resolved_container_id or not resolved_internal_token:
289
+ result.missing_runtime_auth = True
290
+ return result
291
+
292
+ result.core_attempted = True
293
+ try:
294
+ core_snapshot = await fetch_core_runtime_config_snapshot(
295
+ runtime_context=runtime_context,
296
+ client=client,
297
+ core_base_url=core_base_url,
298
+ config_model=config_model,
299
+ snapshot_model=snapshot_model,
300
+ timeout_seconds=timeout_seconds,
301
+ reason=core_reason,
302
+ )
303
+ except Exception as exc:
304
+ result.core_error = f"{type(exc).__name__}: {exc}"
305
+ if raise_core_errors:
306
+ raise
307
+ return result
308
+
309
+ if core_snapshot is None:
310
+ return result
311
+
312
+ await apply_snapshot(core_snapshot)
313
+ result.core_applied = True
314
+ result.core_config_count = len(getattr(core_snapshot, "configs", []) or [])
315
+ result.core_generation = getattr(core_snapshot, "generation", None)
316
+ return result
317
+
13
318
 
14
319
  def reconcile_config_ids(
15
320
  *,
@@ -15,6 +15,7 @@ def _build_runtime_snapshot(runtime_context: RuntimeContext) -> dict[str, Any]:
15
15
  "core_auth_present": bool(runtime_context.auth.internal_token),
16
16
  "core_http_client_bound": process_state.core_http_client is not None,
17
17
  "current_generation": process_state.current_generation,
18
+ "config_generation": process_state.current_generation,
18
19
  "pending_task_count": len(
19
20
  [task for task in process_state.background_tasks if not task.done()]
20
21
  ),
@@ -35,12 +35,34 @@ class RuntimeConfig(BaseModel):
35
35
 
36
36
  class RuntimeConfigSnapshot(BaseModel):
37
37
  """Snapshot payload sent from PiPhi Core to an integration runtime."""
38
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
39
+
40
+ schema_version: int | None = Field(
41
+ default=None,
42
+ validation_alias=AliasChoices("schema_version", "schemaVersion"),
43
+ )
38
44
  container_id: str
39
45
  integration_id: str | None = None
40
46
  driver_pid: int | None = None
41
47
  reason: str | None = None
42
48
  generation: int | None = None
49
+ updated_at: str | None = Field(
50
+ default=None,
51
+ validation_alias=AliasChoices("updated_at", "updatedAt"),
52
+ )
43
53
  configs: list[RuntimeConfig] = Field(default_factory=list)
54
+ deleted_config_ids: list[str] = Field(
55
+ default_factory=list,
56
+ validation_alias=AliasChoices("deleted_config_ids", "deletedConfigIds"),
57
+ )
58
+ config_hash: str | None = Field(
59
+ default=None,
60
+ validation_alias=AliasChoices("config_hash", "configHash"),
61
+ )
62
+ internal_token: str | None = Field(
63
+ default=None,
64
+ validation_alias=AliasChoices("internal_token", "internalToken"),
65
+ )
44
66
 
45
67
 
46
68
  class RuntimeConfigSyncResponse(BaseModel):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: piphi-runtime-kit-python
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: PiPhi Network runtime integration helpers
5
5
  Keywords: piphi,runtime,integration,iot
6
6
  Author-Email: KelvinSan <support@piphi.network>
@@ -1,21 +1,21 @@
1
- piphi_runtime_kit_python-0.4.2.dist-info/METADATA,sha256=th_AhsVfZ_at7LDyKQv7ZA1EVxiasOUwoSdTxQvdulI,30849
2
- piphi_runtime_kit_python-0.4.2.dist-info/WHEEL,sha256=Z36eTX6lG3PITRleSd5hAZHCcz52yg3c0JQVxKBbLW0,90
3
- piphi_runtime_kit_python-0.4.2.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- piphi_runtime_kit_python-0.4.2.dist-info/licenses/LICENSE,sha256=pS6szQI4X7qAin1ODdoDp-XwZvsFy6ZZ28-JAwGHgzo,1070
5
- piphi_runtime_kit_python/__init__.py,sha256=P8yx6C1P88xuXWuf3D58d5zhUD-pprhBhbVeyNbDaJQ,6013
1
+ piphi_runtime_kit_python-0.4.4.dist-info/METADATA,sha256=itnYk2BZoSxO2w_x--KH4i937xkqhT4_HT5GZZKy-cA,30849
2
+ piphi_runtime_kit_python-0.4.4.dist-info/WHEEL,sha256=Z36eTX6lG3PITRleSd5hAZHCcz52yg3c0JQVxKBbLW0,90
3
+ piphi_runtime_kit_python-0.4.4.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ piphi_runtime_kit_python-0.4.4.dist-info/licenses/LICENSE,sha256=pS6szQI4X7qAin1ODdoDp-XwZvsFy6ZZ28-JAwGHgzo,1070
5
+ piphi_runtime_kit_python/__init__.py,sha256=nw9We1D1bN6aucvw2mlgux3rs4znSIH-RyagYSbDgWE,6866
6
6
  piphi_runtime_kit_python/adapters/__init__.py,sha256=3jBhPZSBN3Qo7MKHlxAol2jPU3cK23BXHR2oTlircsw,361
7
7
  piphi_runtime_kit_python/adapters/fastapi.py,sha256=1QcOBYprg6AmQVrkI8g61NIelBB_7BTbdvNaMvG2-s8,2098
8
8
  piphi_runtime_kit_python/fastapi.py,sha256=OZ-ds2-g32kB4YkF90D5bM4vVVjpOWPtrNC-WdhDNyo,361
9
9
  piphi_runtime_kit_python/runtime/__init__.py,sha256=0WxNbgGodqba-uiJILOAuU3EwZhBtXeDyw6sYhduWzg,3717
10
10
  piphi_runtime_kit_python/runtime/auth.py,sha256=hL90c3K5pJgEpPdNGJ7ds6mqeN4tmjC3I8igfNam_L4,4648
11
- piphi_runtime_kit_python/runtime/config_sync.py,sha256=IzsH5AGxnISISWx8OYfNMTk2O20kbW4fBvBEGwO_cYg,5625
11
+ piphi_runtime_kit_python/runtime/config_sync.py,sha256=FA9wcFpDpYWYBmmEXZRAhwRIuO-a-BHwlJTJzA748IA,15925
12
12
  piphi_runtime_kit_python/runtime/configuration.py,sha256=4kkoJeENOhJHeNvC9QDu81ejDJUQJG7S5GmQG1sv3YQ,3631
13
13
  piphi_runtime_kit_python/runtime/context.py,sha256=CwXgrivciBd7eTREn0u0zjqkDPy6VthASW-gsoZqCTg,1109
14
14
  piphi_runtime_kit_python/runtime/discovery.py,sha256=uH6rJ4BnLVukTCxu2QwvN8yJhsI_fcT29VEat62oBcY,2274
15
15
  piphi_runtime_kit_python/runtime/dispatch.py,sha256=QcbA9B5izyyg0znlKHq94dbr-oqHVxKW2LCjrQKYfkY,7341
16
16
  piphi_runtime_kit_python/runtime/errors.py,sha256=_mjqmJLsdM5NfrTwb6YFkhheqPfn6Df-QtAKgl9U6QU,4120
17
17
  piphi_runtime_kit_python/runtime/events.py,sha256=JcvrTZlJ-vgY237jTDVOAVTbSxbcuh9u2QCdOGyuduA,6543
18
- piphi_runtime_kit_python/runtime/health.py,sha256=9YO0K_UCJKTe6uSFLgb1kStr5dAgtIUc8Ha0dnRi2vA,1880
18
+ piphi_runtime_kit_python/runtime/health.py,sha256=3pds8SYSUql2w2ijegbszwm0HK69VzfIrwz42bN97yk,1943
19
19
  piphi_runtime_kit_python/runtime/identity.py,sha256=cth0_QHR9R5LTdp-6DPD1IhM8cYJT5HB1OUQYW7kLGs,2762
20
20
  piphi_runtime_kit_python/runtime/lifespan.py,sha256=mVSdZZAS66xlcnlzAwkztFjzw_l2pyLrJqULJsb0Ezk,2850
21
21
  piphi_runtime_kit_python/runtime/mqtt.py,sha256=JKMN5zxg1BcOidu7TaYnuRD3HuoAJ_WcvXMTTSlAteo,6069
@@ -24,5 +24,5 @@ piphi_runtime_kit_python/runtime/starter.py,sha256=j5C4GOOcRHNLJ-HYu8fmf3bE00baD
24
24
  piphi_runtime_kit_python/runtime/state.py,sha256=4xvQGTT59DF9rXHAtM3kDyV_UGg2a9tLPvGiCp_PFMc,674
25
25
  piphi_runtime_kit_python/runtime/tasks.py,sha256=gMd-2K96jMU8tCPvI12xdWxuyNt5gsLDss2QWOoM94k,1241
26
26
  piphi_runtime_kit_python/runtime/telemetry.py,sha256=RN6SFrhmAZ7aJLyioQMBzJEFsxQgOjjA1pV5qNeaR4E,4279
27
- piphi_runtime_kit_python/schemas.py,sha256=LGz53OHmWwUEQb_nHbVBgRDGVGowJPT53S2P7otP3lo,9073
28
- piphi_runtime_kit_python-0.4.2.dist-info/RECORD,,
27
+ piphi_runtime_kit_python/schemas.py,sha256=9jlsfmvz-O2YeoB0SVopXY7NhFlb1zgynez0NXEZkVE,9849
28
+ piphi_runtime_kit_python-0.4.4.dist-info/RECORD,,