krons 0.1.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.
Files changed (101) hide show
  1. kronos/__init__.py +0 -0
  2. kronos/core/__init__.py +145 -0
  3. kronos/core/broadcaster.py +116 -0
  4. kronos/core/element.py +225 -0
  5. kronos/core/event.py +316 -0
  6. kronos/core/eventbus.py +116 -0
  7. kronos/core/flow.py +356 -0
  8. kronos/core/graph.py +442 -0
  9. kronos/core/node.py +982 -0
  10. kronos/core/pile.py +575 -0
  11. kronos/core/processor.py +494 -0
  12. kronos/core/progression.py +296 -0
  13. kronos/enforcement/__init__.py +57 -0
  14. kronos/enforcement/common/__init__.py +34 -0
  15. kronos/enforcement/common/boolean.py +85 -0
  16. kronos/enforcement/common/choice.py +97 -0
  17. kronos/enforcement/common/mapping.py +118 -0
  18. kronos/enforcement/common/model.py +102 -0
  19. kronos/enforcement/common/number.py +98 -0
  20. kronos/enforcement/common/string.py +140 -0
  21. kronos/enforcement/context.py +129 -0
  22. kronos/enforcement/policy.py +80 -0
  23. kronos/enforcement/registry.py +153 -0
  24. kronos/enforcement/rule.py +312 -0
  25. kronos/enforcement/service.py +370 -0
  26. kronos/enforcement/validator.py +198 -0
  27. kronos/errors.py +146 -0
  28. kronos/operations/__init__.py +32 -0
  29. kronos/operations/builder.py +228 -0
  30. kronos/operations/flow.py +398 -0
  31. kronos/operations/node.py +101 -0
  32. kronos/operations/registry.py +92 -0
  33. kronos/protocols.py +414 -0
  34. kronos/py.typed +0 -0
  35. kronos/services/__init__.py +81 -0
  36. kronos/services/backend.py +286 -0
  37. kronos/services/endpoint.py +608 -0
  38. kronos/services/hook.py +471 -0
  39. kronos/services/imodel.py +465 -0
  40. kronos/services/registry.py +115 -0
  41. kronos/services/utilities/__init__.py +36 -0
  42. kronos/services/utilities/header_factory.py +87 -0
  43. kronos/services/utilities/rate_limited_executor.py +271 -0
  44. kronos/services/utilities/rate_limiter.py +180 -0
  45. kronos/services/utilities/resilience.py +414 -0
  46. kronos/session/__init__.py +41 -0
  47. kronos/session/exchange.py +258 -0
  48. kronos/session/message.py +60 -0
  49. kronos/session/session.py +411 -0
  50. kronos/specs/__init__.py +25 -0
  51. kronos/specs/adapters/__init__.py +0 -0
  52. kronos/specs/adapters/_utils.py +45 -0
  53. kronos/specs/adapters/dataclass_field.py +246 -0
  54. kronos/specs/adapters/factory.py +56 -0
  55. kronos/specs/adapters/pydantic_adapter.py +309 -0
  56. kronos/specs/adapters/sql_ddl.py +946 -0
  57. kronos/specs/catalog/__init__.py +36 -0
  58. kronos/specs/catalog/_audit.py +39 -0
  59. kronos/specs/catalog/_common.py +43 -0
  60. kronos/specs/catalog/_content.py +59 -0
  61. kronos/specs/catalog/_enforcement.py +70 -0
  62. kronos/specs/factory.py +120 -0
  63. kronos/specs/operable.py +314 -0
  64. kronos/specs/phrase.py +405 -0
  65. kronos/specs/protocol.py +140 -0
  66. kronos/specs/spec.py +506 -0
  67. kronos/types/__init__.py +60 -0
  68. kronos/types/_sentinel.py +311 -0
  69. kronos/types/base.py +369 -0
  70. kronos/types/db_types.py +260 -0
  71. kronos/types/identity.py +66 -0
  72. kronos/utils/__init__.py +40 -0
  73. kronos/utils/_hash.py +234 -0
  74. kronos/utils/_json_dump.py +392 -0
  75. kronos/utils/_lazy_init.py +63 -0
  76. kronos/utils/_to_list.py +165 -0
  77. kronos/utils/_to_num.py +85 -0
  78. kronos/utils/_utils.py +375 -0
  79. kronos/utils/concurrency/__init__.py +205 -0
  80. kronos/utils/concurrency/_async_call.py +333 -0
  81. kronos/utils/concurrency/_cancel.py +122 -0
  82. kronos/utils/concurrency/_errors.py +96 -0
  83. kronos/utils/concurrency/_patterns.py +363 -0
  84. kronos/utils/concurrency/_primitives.py +328 -0
  85. kronos/utils/concurrency/_priority_queue.py +135 -0
  86. kronos/utils/concurrency/_resource_tracker.py +110 -0
  87. kronos/utils/concurrency/_run_async.py +67 -0
  88. kronos/utils/concurrency/_task.py +95 -0
  89. kronos/utils/concurrency/_utils.py +79 -0
  90. kronos/utils/fuzzy/__init__.py +14 -0
  91. kronos/utils/fuzzy/_extract_json.py +90 -0
  92. kronos/utils/fuzzy/_fuzzy_json.py +288 -0
  93. kronos/utils/fuzzy/_fuzzy_match.py +149 -0
  94. kronos/utils/fuzzy/_string_similarity.py +187 -0
  95. kronos/utils/fuzzy/_to_dict.py +396 -0
  96. kronos/utils/sql/__init__.py +13 -0
  97. kronos/utils/sql/_sql_validation.py +142 -0
  98. krons-0.1.0.dist-info/METADATA +70 -0
  99. krons-0.1.0.dist-info/RECORD +101 -0
  100. krons-0.1.0.dist-info/WHEEL +4 -0
  101. krons-0.1.0.dist-info/licenses/LICENSE +201 -0
kronos/protocols.py ADDED
@@ -0,0 +1,414 @@
1
+ # Copyright (c) 2025 - 2026, HaiyangLi <quantocean.li at gmail dot com>
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ """Runtime-checkable protocols and @implements decorator.
5
+
6
+ Protocols define structural interfaces (duck typing) with isinstance() support.
7
+ Use @implements(Protocol) to declare and validate protocol implementations.
8
+
9
+ Example:
10
+ @implements(Serializable, Invocable)
11
+ class MyClass:
12
+ def to_dict(self, **kwargs): ...
13
+ async def invoke(self): ...
14
+ """
15
+
16
+ import inspect
17
+ import warnings
18
+ from typing import Any, Literal, Protocol, runtime_checkable
19
+ from uuid import UUID
20
+
21
+ __all__ = (
22
+ "Allowable",
23
+ "Communicatable",
24
+ "Containable",
25
+ "Deserializable",
26
+ "Hashable",
27
+ "Invocable",
28
+ "Observable",
29
+ "Serializable",
30
+ "SignatureMismatchError",
31
+ "implements",
32
+ )
33
+
34
+
35
+ class SignatureMismatchError(TypeError):
36
+ """@implements detected incompatible method signature."""
37
+
38
+ pass
39
+
40
+
41
+ @runtime_checkable
42
+ class ObservableProto(Protocol):
43
+ """Has unique UUID identity. Check: isinstance(obj, Observable)."""
44
+
45
+ @property
46
+ def id(self) -> UUID:
47
+ """Unique identifier for this instance."""
48
+ ...
49
+
50
+
51
+ @runtime_checkable
52
+ class Serializable(Protocol):
53
+ """Can serialize to dict. Implement to_dict(**kwargs) -> dict."""
54
+
55
+ def to_dict(self, **kwargs: Any) -> dict[str, Any]:
56
+ """Serialize to dict. kwargs: mode, format, etc."""
57
+ ...
58
+
59
+
60
+ @runtime_checkable
61
+ class Deserializable(Protocol):
62
+ """Can deserialize from dict. Implement classmethod from_dict(data, **kwargs)."""
63
+
64
+ @classmethod
65
+ def from_dict(cls, data: dict[str, Any], **kwargs: Any) -> Any:
66
+ """Create instance from dict."""
67
+ ...
68
+
69
+
70
+ @runtime_checkable
71
+ class Containable(Protocol):
72
+ """Supports 'in' operator. Implement __contains__(item) -> bool."""
73
+
74
+ def __contains__(self, item: Any) -> bool:
75
+ """Check membership (by UUID or instance)."""
76
+ ...
77
+
78
+
79
+ @runtime_checkable
80
+ class Invocable(Protocol):
81
+ """Async executable. Implement async invoke() -> Any."""
82
+
83
+ async def invoke(self) -> Any:
84
+ """Execute and return result."""
85
+ ...
86
+
87
+
88
+ @runtime_checkable
89
+ class Hashable(Protocol):
90
+ """Hashable for sets/dicts. Implement __hash__() -> int."""
91
+
92
+ def __hash__(self) -> int:
93
+ """Hash value (typically based on immutable id)."""
94
+ ...
95
+
96
+
97
+ @runtime_checkable
98
+ class Allowable(Protocol):
99
+ """Has defined allowed values. Implement allowed() -> set[str]."""
100
+
101
+ def allowed(self) -> set[str]:
102
+ """Set of allowed keys/values."""
103
+ ...
104
+
105
+
106
+ @runtime_checkable
107
+ class Communicatable(Protocol):
108
+ """Entity with mailbox for message exchange.
109
+
110
+ Enables multi-agent communication. Higher layers define Agent, Branch, etc.
111
+ """
112
+
113
+ @property
114
+ def id(self) -> UUID:
115
+ """Entity identifier for routing."""
116
+ ...
117
+
118
+ @property
119
+ def mailbox(self) -> Any:
120
+ """Mailbox for send/receive operations."""
121
+ ...
122
+
123
+
124
+ Observable = ObservableProto
125
+ """Alias: Observable = ObservableProto."""
126
+
127
+
128
+ def _get_signature_params(func: Any) -> dict[str, inspect.Parameter] | None:
129
+ """Extract params from callable, excluding self/cls. Returns None if not introspectable."""
130
+ if isinstance(func, (classmethod, staticmethod)):
131
+ func = func.__func__
132
+
133
+ if isinstance(func, property):
134
+ return None
135
+
136
+ if not callable(func):
137
+ return None
138
+
139
+ try:
140
+ sig = inspect.signature(func)
141
+ except (ValueError, TypeError):
142
+ return None
143
+
144
+ params = {}
145
+ for name, param in sig.parameters.items():
146
+ if name in ("self", "cls"):
147
+ continue
148
+ params[name] = param
149
+
150
+ return params
151
+
152
+
153
+ def _check_signature_compatibility(
154
+ protocol_params: dict[str, inspect.Parameter],
155
+ impl_params: dict[str, inspect.Parameter],
156
+ ) -> list[str]:
157
+ """Check impl signature compatibility with protocol. Returns error messages.
158
+
159
+ Rules: impl must accept required protocol params; may have extra optionals;
160
+ *args/**kwargs can satisfy protocol params; if protocol has **kwargs, impl must too.
161
+ """
162
+ errors = []
163
+
164
+ impl_has_var_positional = any(
165
+ p.kind == inspect.Parameter.VAR_POSITIONAL for p in impl_params.values()
166
+ )
167
+ impl_has_var_keyword = any(
168
+ p.kind == inspect.Parameter.VAR_KEYWORD for p in impl_params.values()
169
+ )
170
+
171
+ # Check if protocol has *args or **kwargs
172
+ proto_has_var_positional = any(
173
+ p.kind == inspect.Parameter.VAR_POSITIONAL for p in protocol_params.values()
174
+ )
175
+ proto_has_var_keyword = any(
176
+ p.kind == inspect.Parameter.VAR_KEYWORD for p in protocol_params.values()
177
+ )
178
+
179
+ # If protocol accepts **kwargs, implementation must also accept them
180
+ # Otherwise callers passing kwargs (allowed by protocol) will fail
181
+ if proto_has_var_keyword and not impl_has_var_keyword:
182
+ errors.append(" - 'kwargs': protocol accepts **kwargs but implementation doesn't")
183
+
184
+ # If protocol accepts *args, implementation must also accept them
185
+ if proto_has_var_positional and not impl_has_var_positional:
186
+ errors.append(" - 'args': protocol accepts *args but implementation doesn't")
187
+
188
+ # For each protocol parameter, verify implementation can accept it
189
+ for param_name, proto_param in protocol_params.items():
190
+ # Skip VAR_POSITIONAL and VAR_KEYWORD in protocol (handled above)
191
+ if proto_param.kind in (
192
+ inspect.Parameter.VAR_POSITIONAL,
193
+ inspect.Parameter.VAR_KEYWORD,
194
+ ):
195
+ continue
196
+
197
+ # Check if implementation has this parameter
198
+ if param_name in impl_params:
199
+ impl_param = impl_params[param_name]
200
+
201
+ # Check parameter kind compatibility
202
+ # Implementation can be more flexible (e.g., POSITIONAL_OR_KEYWORD
203
+ # can accept POSITIONAL_ONLY)
204
+ proto_kind = proto_param.kind
205
+ impl_kind = impl_param.kind
206
+
207
+ # VAR_POSITIONAL/VAR_KEYWORD in impl can accept anything
208
+ if impl_kind in (
209
+ inspect.Parameter.VAR_POSITIONAL,
210
+ inspect.Parameter.VAR_KEYWORD,
211
+ ):
212
+ continue
213
+
214
+ # Required in protocol but has default in impl is OK
215
+ # (implementation is more lenient)
216
+
217
+ # If protocol param is required, impl param should not require
218
+ # something the protocol doesn't provide
219
+ if proto_param.default is inspect.Parameter.empty:
220
+ # Protocol requires this param
221
+ # Implementation can either:
222
+ # 1. Also require it (empty default)
223
+ # 2. Make it optional (has default) - this is fine
224
+
225
+ # Check if impl param is keyword-only but protocol is positional
226
+ if impl_kind == inspect.Parameter.KEYWORD_ONLY and proto_kind in (
227
+ inspect.Parameter.POSITIONAL_ONLY,
228
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
229
+ ):
230
+ errors.append(
231
+ f" - '{param_name}': protocol allows positional, "
232
+ f"but implementation requires keyword-only"
233
+ )
234
+ else:
235
+ # Protocol param is optional (has default)
236
+ # Implementation should NOT make it required (tightening contract)
237
+ if impl_param.default is inspect.Parameter.empty:
238
+ errors.append(
239
+ f" - '{param_name}': protocol makes this optional, "
240
+ f"but implementation requires it"
241
+ )
242
+
243
+ else:
244
+ # Parameter not in implementation by name
245
+ # Check if it can be satisfied by *args or **kwargs
246
+ proto_kind = proto_param.kind
247
+
248
+ if proto_kind in (
249
+ inspect.Parameter.POSITIONAL_ONLY,
250
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
251
+ ):
252
+ # Can be satisfied by *args or **kwargs
253
+ if not (impl_has_var_positional or impl_has_var_keyword):
254
+ errors.append(
255
+ f" - '{param_name}': required by protocol but not in implementation"
256
+ )
257
+ elif proto_kind == inspect.Parameter.KEYWORD_ONLY: # noqa: SIM102
258
+ # Can only be satisfied by **kwargs
259
+ if not impl_has_var_keyword:
260
+ errors.append(
261
+ f" - '{param_name}': keyword-only param required by protocol "
262
+ f"but not in implementation"
263
+ )
264
+
265
+ # Check if implementation has required parameters that protocol doesn't provide
266
+ for param_name, impl_param in impl_params.items():
267
+ # Skip *args and **kwargs
268
+ if impl_param.kind in (
269
+ inspect.Parameter.VAR_POSITIONAL,
270
+ inspect.Parameter.VAR_KEYWORD,
271
+ ):
272
+ continue
273
+
274
+ # If implementation requires a parameter (no default)
275
+ if impl_param.default is inspect.Parameter.empty: # noqa: SIM102
276
+ # Protocol must also have this parameter
277
+ if param_name not in protocol_params:
278
+ # Check if protocol has *args or **kwargs that could provide it
279
+ proto_has_var_positional = any(
280
+ p.kind == inspect.Parameter.VAR_POSITIONAL for p in protocol_params.values()
281
+ )
282
+ proto_has_var_keyword = any(
283
+ p.kind == inspect.Parameter.VAR_KEYWORD for p in protocol_params.values()
284
+ )
285
+
286
+ can_satisfy = False
287
+ if impl_param.kind in (
288
+ inspect.Parameter.POSITIONAL_ONLY,
289
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
290
+ ):
291
+ can_satisfy = proto_has_var_positional or proto_has_var_keyword
292
+ elif impl_param.kind == inspect.Parameter.KEYWORD_ONLY:
293
+ can_satisfy = proto_has_var_keyword
294
+
295
+ if not can_satisfy:
296
+ errors.append(
297
+ f" - '{param_name}': implementation requires this param "
298
+ f"but protocol doesn't provide it"
299
+ )
300
+
301
+ return errors
302
+
303
+
304
+ def implements(
305
+ *protocols: type,
306
+ signature_check: Literal["error", "warn", "skip"] = "warn",
307
+ allow_inherited: bool = False,
308
+ ):
309
+ """Decorator to declare and validate protocol implementations.
310
+
311
+ Validates members exist (in class body by default) and optionally checks
312
+ signature compatibility. Stores validated protocols in cls.__protocols__.
313
+
314
+ Args:
315
+ *protocols: Protocol classes to implement.
316
+ signature_check: "error"=raise, "warn"=warning, "skip"=no check.
317
+ allow_inherited: Accept inherited implementations (default: require in class body).
318
+
319
+ Raises:
320
+ TypeError: Required member missing.
321
+ SignatureMismatchError: If signature_check="error" and mismatch.
322
+
323
+ Example:
324
+ @implements(Serializable, signature_check="error")
325
+ class MyModel:
326
+ def to_dict(self, **kwargs): return {"id": self.id}
327
+ """
328
+
329
+ def decorator(cls):
330
+ all_signature_errors = []
331
+
332
+ # Validate that all protocol members are defined in class body
333
+ for protocol in protocols:
334
+ # Get protocol members from protocol class annotations
335
+ protocol_members = {}
336
+ for name, obj in inspect.getmembers(protocol):
337
+ if name.startswith("_"):
338
+ continue
339
+ # Include methods, properties, classmethods
340
+ if callable(obj) or isinstance(obj, (property, classmethod)):
341
+ protocol_members[name] = obj
342
+
343
+ # Check each required member exists
344
+ for member_name, protocol_member in protocol_members.items():
345
+ # Check if member is in class body or inherited (based on allow_inherited)
346
+ # For Pydantic models, also check __annotations__ for fields
347
+ in_class_body = member_name in cls.__dict__
348
+
349
+ # For Pydantic models, check if it's a field annotation
350
+ if not in_class_body and hasattr(cls, "__annotations__"):
351
+ in_class_body = member_name in cls.__annotations__
352
+
353
+ # Check if member exists anywhere (including inherited)
354
+ has_member = hasattr(cls, member_name)
355
+
356
+ if allow_inherited:
357
+ # When inheritance is allowed, just check the member exists
358
+ if not has_member:
359
+ protocol_name = protocol.__name__
360
+ raise TypeError(
361
+ f"{cls.__name__} declares @implements({protocol_name}) but "
362
+ f"'{member_name}' is not defined or inherited"
363
+ )
364
+ else:
365
+ # Strict mode: require member in class body
366
+ if not in_class_body:
367
+ protocol_name = protocol.__name__
368
+ raise TypeError(
369
+ f"{cls.__name__} declares @implements({protocol_name}) but does not "
370
+ f"define '{member_name}' in its class body. "
371
+ f"Use allow_inherited=True to accept inherited implementations."
372
+ )
373
+
374
+ # Signature checking (if enabled and member exists)
375
+ if signature_check != "skip":
376
+ # Get the actual implementation (from class body or inherited)
377
+ if in_class_body:
378
+ impl_member = cls.__dict__.get(member_name)
379
+ else:
380
+ impl_member = getattr(cls, member_name, None)
381
+
382
+ if impl_member is None and hasattr(cls, "__annotations__"):
383
+ # Pydantic field - skip signature check (it's a field, not method)
384
+ continue
385
+
386
+ # Get signatures for comparison
387
+ proto_params = _get_signature_params(protocol_member)
388
+ impl_params = _get_signature_params(impl_member)
389
+
390
+ # Only check if both have extractable signatures
391
+ if proto_params is not None and impl_params is not None:
392
+ errors = _check_signature_compatibility(
393
+ proto_params,
394
+ impl_params,
395
+ )
396
+ if errors:
397
+ error_msg = (
398
+ f"{cls.__name__}.{member_name} signature incompatible "
399
+ f"with {protocol.__name__}.{member_name}:\n" + "\n".join(errors)
400
+ )
401
+ all_signature_errors.append(error_msg)
402
+
403
+ # Handle signature errors based on signature_check mode
404
+ if all_signature_errors:
405
+ full_message = "\n\n".join(all_signature_errors)
406
+ if signature_check == "error":
407
+ raise SignatureMismatchError(full_message)
408
+ elif signature_check == "warn":
409
+ warnings.warn(full_message, stacklevel=2)
410
+
411
+ cls.__protocols__ = protocols
412
+ return cls
413
+
414
+ return decorator
kronos/py.typed ADDED
File without changes
@@ -0,0 +1,81 @@
1
+ # Copyright (c) 2025 - 2026, HaiyangLi <quantocean.li at gmail dot com>
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ """Services module: iModel, ServiceBackend, hooks, and registry.
5
+
6
+ Core exports:
7
+ - iModel: Unified service interface with rate limiting and hooks
8
+ - ServiceBackend/Endpoint: Backend abstractions for API calls
9
+ - HookRegistry/HookEvent/HookPhase: Lifecycle hook system
10
+ - ServiceRegistry: O(1) name-based service lookup
11
+
12
+ Uses lazy loading for fast import.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import TYPE_CHECKING
18
+
19
+ # Lazy import mapping
20
+ _LAZY_IMPORTS: dict[str, tuple[str, str]] = {
21
+ "Calling": ("kronos.services.backend", "Calling"),
22
+ "NormalizedResponse": ("kronos.services.backend", "NormalizedResponse"),
23
+ "ServiceBackend": ("kronos.services.backend", "ServiceBackend"),
24
+ "ServiceConfig": ("kronos.services.backend", "ServiceConfig"),
25
+ "ServiceRegistry": ("kronos.services.registry", "ServiceRegistry"),
26
+ "iModel": ("kronos.services.imodel", "iModel"),
27
+ "Endpoint": ("kronos.services.endpoint", "Endpoint"),
28
+ "EndpointConfig": ("kronos.services.endpoint", "EndpointConfig"),
29
+ "APICalling": ("kronos.services.endpoint", "APICalling"),
30
+ "HookRegistry": ("kronos.services.hook", "HookRegistry"),
31
+ "HookEvent": ("kronos.services.hook", "HookEvent"),
32
+ "HookPhase": ("kronos.services.hook", "HookPhase"),
33
+ }
34
+
35
+ _LOADED: dict[str, object] = {}
36
+
37
+
38
+ def __getattr__(name: str) -> object:
39
+ """Lazy import attributes on first access."""
40
+ if name in _LOADED:
41
+ return _LOADED[name]
42
+
43
+ if name in _LAZY_IMPORTS:
44
+ from importlib import import_module
45
+
46
+ module_name, attr_name = _LAZY_IMPORTS[name]
47
+ module = import_module(module_name)
48
+ value = getattr(module, attr_name)
49
+ _LOADED[name] = value
50
+ return value
51
+
52
+ raise AttributeError(f"module 'kronos.services' has no attribute {name!r}")
53
+
54
+
55
+ def __dir__() -> list[str]:
56
+ """Return all available attributes for autocomplete."""
57
+ return list(__all__)
58
+
59
+
60
+ # TYPE_CHECKING block for static analysis
61
+ if TYPE_CHECKING:
62
+ from .backend import Calling, NormalizedResponse, ServiceBackend, ServiceConfig
63
+ from .endpoint import APICalling, Endpoint, EndpointConfig
64
+ from .hook import HookEvent, HookPhase, HookRegistry
65
+ from .imodel import iModel
66
+ from .registry import ServiceRegistry
67
+
68
+ __all__ = (
69
+ "APICalling",
70
+ "Calling",
71
+ "Endpoint",
72
+ "EndpointConfig",
73
+ "HookEvent",
74
+ "HookPhase",
75
+ "HookRegistry",
76
+ "NormalizedResponse",
77
+ "ServiceBackend",
78
+ "ServiceConfig",
79
+ "ServiceRegistry",
80
+ "iModel",
81
+ )