omnibase_infra 0.2.1__py3-none-any.whl → 0.2.3__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 (161) hide show
  1. omnibase_infra/__init__.py +1 -1
  2. omnibase_infra/adapters/adapter_onex_tool_execution.py +451 -0
  3. omnibase_infra/capabilities/__init__.py +15 -0
  4. omnibase_infra/capabilities/capability_inference_rules.py +211 -0
  5. omnibase_infra/capabilities/contract_capability_extractor.py +221 -0
  6. omnibase_infra/capabilities/intent_type_extractor.py +160 -0
  7. omnibase_infra/cli/commands.py +1 -1
  8. omnibase_infra/configs/widget_mapping.yaml +176 -0
  9. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +5 -2
  10. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +5 -2
  11. omnibase_infra/enums/__init__.py +6 -0
  12. omnibase_infra/enums/enum_handler_error_type.py +10 -0
  13. omnibase_infra/enums/enum_handler_source_mode.py +72 -0
  14. omnibase_infra/enums/enum_kafka_acks.py +99 -0
  15. omnibase_infra/errors/error_compute_registry.py +4 -1
  16. omnibase_infra/errors/error_event_bus_registry.py +4 -1
  17. omnibase_infra/errors/error_infra.py +3 -1
  18. omnibase_infra/errors/error_policy_registry.py +4 -1
  19. omnibase_infra/event_bus/event_bus_kafka.py +1 -1
  20. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +59 -10
  21. omnibase_infra/handlers/__init__.py +8 -1
  22. omnibase_infra/handlers/handler_consul.py +7 -1
  23. omnibase_infra/handlers/handler_db.py +10 -3
  24. omnibase_infra/handlers/handler_graph.py +10 -5
  25. omnibase_infra/handlers/handler_http.py +8 -2
  26. omnibase_infra/handlers/handler_intent.py +387 -0
  27. omnibase_infra/handlers/handler_mcp.py +745 -63
  28. omnibase_infra/handlers/handler_vault.py +11 -5
  29. omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
  30. omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
  31. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +7 -0
  32. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +308 -4
  33. omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
  34. omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
  35. omnibase_infra/mixins/mixin_node_introspection.py +42 -7
  36. omnibase_infra/mixins/mixin_retry_execution.py +1 -1
  37. omnibase_infra/models/discovery/model_introspection_config.py +11 -0
  38. omnibase_infra/models/handlers/__init__.py +48 -5
  39. omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
  40. omnibase_infra/models/handlers/model_contract_discovery_result.py +6 -4
  41. omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
  42. omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
  43. omnibase_infra/models/mcp/__init__.py +15 -0
  44. omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
  45. omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
  46. omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
  47. omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
  48. omnibase_infra/models/registration/model_node_capabilities.py +11 -0
  49. omnibase_infra/models/registration/model_node_introspection_event.py +9 -0
  50. omnibase_infra/models/runtime/model_handler_contract.py +25 -9
  51. omnibase_infra/models/runtime/model_loaded_handler.py +9 -0
  52. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
  53. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
  54. omnibase_infra/nodes/effects/contract.yaml +0 -5
  55. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
  56. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
  57. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
  58. omnibase_infra/nodes/node_registration_orchestrator/plugin.py +1 -1
  59. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
  60. omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +4 -3
  61. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
  62. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
  63. omnibase_infra/nodes/node_registration_storage_effect/node.py +4 -1
  64. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +47 -26
  65. omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
  66. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
  67. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +28 -20
  68. omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
  69. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
  70. omnibase_infra/plugins/plugin_compute_base.py +16 -2
  71. omnibase_infra/protocols/__init__.py +2 -0
  72. omnibase_infra/protocols/protocol_container_aware.py +200 -0
  73. omnibase_infra/protocols/protocol_event_projector.py +1 -1
  74. omnibase_infra/runtime/__init__.py +90 -1
  75. omnibase_infra/runtime/binding_config_resolver.py +102 -37
  76. omnibase_infra/runtime/constants_notification.py +75 -0
  77. omnibase_infra/runtime/contract_handler_discovery.py +6 -1
  78. omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
  79. omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
  80. omnibase_infra/runtime/handler_contract_source.py +267 -186
  81. omnibase_infra/runtime/handler_identity.py +81 -0
  82. omnibase_infra/runtime/handler_plugin_loader.py +19 -2
  83. omnibase_infra/runtime/handler_registry.py +11 -3
  84. omnibase_infra/runtime/handler_source_resolver.py +326 -0
  85. omnibase_infra/runtime/mixin_semver_cache.py +25 -1
  86. omnibase_infra/runtime/mixins/__init__.py +7 -0
  87. omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
  88. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
  89. omnibase_infra/runtime/models/__init__.py +24 -0
  90. omnibase_infra/runtime/models/model_health_check_result.py +2 -1
  91. omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
  92. omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
  93. omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
  94. omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
  95. omnibase_infra/runtime/projector_plugin_loader.py +1 -1
  96. omnibase_infra/runtime/projector_shell.py +229 -1
  97. omnibase_infra/runtime/protocol_lifecycle_executor.py +6 -6
  98. omnibase_infra/runtime/protocols/__init__.py +10 -0
  99. omnibase_infra/runtime/registry/registry_protocol_binding.py +16 -15
  100. omnibase_infra/runtime/registry_contract_source.py +693 -0
  101. omnibase_infra/runtime/registry_policy.py +9 -326
  102. omnibase_infra/runtime/secret_resolver.py +4 -2
  103. omnibase_infra/runtime/service_kernel.py +11 -3
  104. omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
  105. omnibase_infra/runtime/service_runtime_host_process.py +589 -106
  106. omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
  107. omnibase_infra/runtime/transition_notification_publisher.py +764 -0
  108. omnibase_infra/runtime/util_container_wiring.py +6 -5
  109. omnibase_infra/runtime/util_wiring.py +17 -4
  110. omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
  111. omnibase_infra/services/__init__.py +21 -0
  112. omnibase_infra/services/corpus_capture.py +7 -1
  113. omnibase_infra/services/mcp/__init__.py +31 -0
  114. omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
  115. omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
  116. omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
  117. omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
  118. omnibase_infra/services/registry_api/__init__.py +40 -0
  119. omnibase_infra/services/registry_api/main.py +261 -0
  120. omnibase_infra/services/registry_api/models/__init__.py +66 -0
  121. omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
  122. omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
  123. omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
  124. omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
  125. omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
  126. omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
  127. omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
  128. omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
  129. omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
  130. omnibase_infra/services/registry_api/models/model_warning.py +49 -0
  131. omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
  132. omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
  133. omnibase_infra/services/registry_api/routes.py +371 -0
  134. omnibase_infra/services/registry_api/service.py +837 -0
  135. omnibase_infra/services/service_capability_query.py +4 -4
  136. omnibase_infra/services/service_health.py +3 -2
  137. omnibase_infra/services/service_timeout_emitter.py +20 -3
  138. omnibase_infra/services/service_timeout_scanner.py +7 -3
  139. omnibase_infra/services/session/__init__.py +56 -0
  140. omnibase_infra/services/session/config_consumer.py +120 -0
  141. omnibase_infra/services/session/config_store.py +139 -0
  142. omnibase_infra/services/session/consumer.py +1007 -0
  143. omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
  144. omnibase_infra/services/session/store.py +997 -0
  145. omnibase_infra/utils/__init__.py +19 -0
  146. omnibase_infra/utils/util_atomic_file.py +261 -0
  147. omnibase_infra/utils/util_db_transaction.py +239 -0
  148. omnibase_infra/utils/util_dsn_validation.py +1 -1
  149. omnibase_infra/utils/util_retry_optimistic.py +281 -0
  150. omnibase_infra/validation/__init__.py +3 -19
  151. omnibase_infra/validation/contracts/security.validation.yaml +114 -0
  152. omnibase_infra/validation/infra_validators.py +35 -24
  153. omnibase_infra/validation/validation_exemptions.yaml +140 -9
  154. omnibase_infra/validation/validator_chain_propagation.py +2 -2
  155. omnibase_infra/validation/validator_runtime_shape.py +1 -1
  156. omnibase_infra/validation/validator_security.py +473 -370
  157. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/METADATA +3 -3
  158. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/RECORD +161 -98
  159. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/WHEEL +0 -0
  160. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/entry_points.txt +0 -0
  161. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -17,6 +17,12 @@ Related:
17
17
  - NodeRegistrationStorageEffect: Effect node that uses these dependencies
18
18
  - ProtocolRegistrationPersistence: Protocol for storage backends
19
19
  - ModelONEXContainer: ONEX dependency injection container
20
+
21
+ Note:
22
+ This registry uses a module-level dict for handler storage because the
23
+ ServiceRegistry in omnibase_core v1.0 doesn't support dict-style access
24
+ or string-keyed multi-handler routing. The handlers are still validated
25
+ against the protocol but stored separately.
20
26
  """
21
27
 
22
28
  from __future__ import annotations
@@ -31,6 +37,12 @@ if TYPE_CHECKING:
31
37
 
32
38
  __all__ = ["RegistryInfraRegistrationStorage"]
33
39
 
40
+ # Module-level storage for handlers and metadata
41
+ # ServiceRegistry in v1.0 doesn't support dict-style access needed for
42
+ # multi-handler routing (e.g., "postgresql", "mock" handler types)
43
+ _HANDLER_STORAGE: dict[str, object] = {}
44
+ _PROTOCOL_METADATA: dict[str, dict[str, object]] = {}
45
+
34
46
 
35
47
  class RegistryInfraRegistrationStorage:
36
48
  """Registry for registration storage node dependencies.
@@ -72,14 +84,18 @@ class RegistryInfraRegistrationStorage:
72
84
  DEFAULT_HANDLER_TYPE = "postgresql"
73
85
 
74
86
  @staticmethod
75
- def register(container: ModelONEXContainer) -> None:
87
+ def register(_container: ModelONEXContainer) -> None:
76
88
  """Register registration storage dependencies with the container.
77
89
 
78
90
  Registers the protocol key for later handler binding. This method
79
91
  sets up the infrastructure but does not bind a specific handler.
80
92
 
81
93
  Args:
82
- container: ONEX dependency injection container.
94
+ _container: ONEX dependency injection container. Currently unused
95
+ because ServiceRegistry v1.0 doesn't support dict-style access
96
+ for multi-handler routing. The parameter is retained for API
97
+ consistency with other registry methods and future migration
98
+ when ServiceRegistry supports the required access patterns.
83
99
 
84
100
  Example:
85
101
  >>> from omnibase_core.models.container import ModelONEXContainer
@@ -88,20 +104,19 @@ class RegistryInfraRegistrationStorage:
88
104
  """
89
105
  # Register protocol metadata for discovery
90
106
  # Actual handler binding happens via register_handler()
91
- if container.service_registry is not None:
92
- container.service_registry[
93
- RegistryInfraRegistrationStorage.PROTOCOL_KEY
94
- ] = {
95
- "protocol": "ProtocolRegistrationPersistence",
96
- "module": "omnibase_infra.nodes.node_registration_storage_effect.protocols",
97
- "description": "Protocol for registration storage backends",
98
- "pluggable": True,
99
- "implementations": ["postgresql", "mock"],
100
- }
107
+ # Note: Uses module-level storage since ServiceRegistry v1.0 doesn't
108
+ # support dict-style access for multi-handler routing
109
+ _PROTOCOL_METADATA[RegistryInfraRegistrationStorage.PROTOCOL_KEY] = {
110
+ "protocol": "ProtocolRegistrationPersistence",
111
+ "module": "omnibase_infra.nodes.node_registration_storage_effect.protocols",
112
+ "description": "Protocol for registration storage backends",
113
+ "pluggable": True,
114
+ "implementations": ["postgresql", "mock"],
115
+ }
101
116
 
102
117
  @staticmethod
103
118
  def register_handler(
104
- container: ModelONEXContainer,
119
+ _container: ModelONEXContainer,
105
120
  handler: ProtocolRegistrationPersistence,
106
121
  ) -> None:
107
122
  """Register a specific storage handler with the container.
@@ -110,7 +125,11 @@ class RegistryInfraRegistrationStorage:
110
125
  The handler must implement ProtocolRegistrationPersistence.
111
126
 
112
127
  Args:
113
- container: ONEX dependency injection container.
128
+ _container: ONEX dependency injection container. Currently unused
129
+ because ServiceRegistry v1.0 doesn't support dict-style access
130
+ for multi-handler routing. The parameter is retained for API
131
+ consistency and future migration when ServiceRegistry supports
132
+ the required access patterns.
114
133
  handler: Handler implementation to register.
115
134
 
116
135
  Raises:
@@ -120,7 +139,7 @@ class RegistryInfraRegistrationStorage:
120
139
  >>> from omnibase_infra.handlers.registration_storage import (
121
140
  ... HandlerRegistrationStoragePostgres,
122
141
  ... )
123
- >>> handler = HandlerRegistrationStoragePostgres(pool, config)
142
+ >>> handler = HandlerRegistrationStoragePostgres(container, dsn="postgresql://...")
124
143
  >>> RegistryInfraRegistrationStorage.register_handler(container, handler)
125
144
  """
126
145
  # Import at runtime for isinstance check (protocol is @runtime_checkable)
@@ -143,32 +162,35 @@ class RegistryInfraRegistrationStorage:
143
162
  f"got {type(handler).__name__}"
144
163
  )
145
164
 
146
- if container.service_registry is None:
147
- return
148
-
165
+ # Note: Uses module-level storage since ServiceRegistry v1.0 doesn't
166
+ # support dict-style access for multi-handler routing
149
167
  handler_key = (
150
168
  f"{RegistryInfraRegistrationStorage.PROTOCOL_KEY}.{handler.handler_type}"
151
169
  )
152
- container.service_registry[handler_key] = handler
170
+ _HANDLER_STORAGE[handler_key] = handler
153
171
 
154
172
  # Also register as default if it matches the default type
155
173
  if (
156
174
  handler.handler_type
157
175
  == RegistryInfraRegistrationStorage.DEFAULT_HANDLER_TYPE
158
176
  ):
159
- container.service_registry[
177
+ _HANDLER_STORAGE[
160
178
  RegistryInfraRegistrationStorage.PROTOCOL_KEY + ".default"
161
179
  ] = handler
162
180
 
163
181
  @staticmethod
164
182
  def get_handler(
165
- container: ModelONEXContainer,
183
+ _container: ModelONEXContainer,
166
184
  handler_type: str | None = None,
167
185
  ) -> ProtocolRegistrationPersistence | None:
168
186
  """Retrieve a registered storage handler from the container.
169
187
 
170
188
  Args:
171
- container: ONEX dependency injection container.
189
+ _container: ONEX dependency injection container. Currently unused
190
+ because ServiceRegistry v1.0 doesn't support dict-style access
191
+ for multi-handler routing. The parameter is retained for API
192
+ consistency and future migration when ServiceRegistry supports
193
+ the required access patterns.
172
194
  handler_type: Specific handler type to retrieve. If None, returns default.
173
195
 
174
196
  Returns:
@@ -180,9 +202,8 @@ class RegistryInfraRegistrationStorage:
180
202
  ... handler_type="postgresql",
181
203
  ... )
182
204
  """
183
- if container.service_registry is None:
184
- return None
185
-
205
+ # Note: Uses module-level storage since ServiceRegistry v1.0 doesn't
206
+ # support dict-style access for multi-handler routing
186
207
  if handler_type is not None:
187
208
  handler_key = (
188
209
  f"{RegistryInfraRegistrationStorage.PROTOCOL_KEY}.{handler_type}"
@@ -190,5 +211,5 @@ class RegistryInfraRegistrationStorage:
190
211
  else:
191
212
  handler_key = RegistryInfraRegistrationStorage.PROTOCOL_KEY + ".default"
192
213
 
193
- result = container.service_registry.get(handler_key)
214
+ result = _HANDLER_STORAGE.get(handler_key)
194
215
  return cast("ProtocolRegistrationPersistence | None", result)
@@ -12,11 +12,6 @@
12
12
  name: "node_registry_effect"
13
13
  contract_name: "node_registry_effect"
14
14
  node_name: "node_registry_effect"
15
- # Version (semantic versioning)
16
- version:
17
- major: 1
18
- minor: 1
19
- patch: 0
20
15
  contract_version:
21
16
  major: 1
22
17
  minor: 1
@@ -41,6 +41,7 @@ import time
41
41
  from typing import TYPE_CHECKING, Protocol, runtime_checkable
42
42
  from uuid import UUID
43
43
 
44
+ from omnibase_core.models.primitives import ModelSemVer
44
45
  from omnibase_infra.enums import EnumBackendType
45
46
  from omnibase_infra.errors import (
46
47
  InfraAuthenticationError,
@@ -80,7 +81,7 @@ class ProtocolPartialRetryRequest(Protocol):
80
81
 
81
82
  node_id: UUID
82
83
  node_type: EnumNodeKind
83
- node_version: str
84
+ node_version: ModelSemVer
84
85
  target_backend: EnumBackendType
85
86
  idempotency_key: str | None
86
87
  service_name: str | None
@@ -40,6 +40,7 @@ Related:
40
40
 
41
41
  from __future__ import annotations
42
42
 
43
+ import logging
43
44
  from typing import TYPE_CHECKING
44
45
 
45
46
  from omnibase_infra.errors import ProtocolConfigurationError
@@ -50,6 +51,8 @@ if TYPE_CHECKING:
50
51
  ProtocolDiscoveryOperations,
51
52
  )
52
53
 
54
+ logger = logging.getLogger(__name__)
55
+
53
56
 
54
57
  class RegistryInfraServiceDiscovery:
55
58
  """Registry for service discovery node dependencies.
@@ -59,11 +62,11 @@ class RegistryInfraServiceDiscovery:
59
62
  registration and explicit handler configuration.
60
63
 
61
64
  API Pattern Note:
62
- This registry uses ``container.register_factory()`` and
63
- ``container.register_instance()`` for protocol-based type-safe DI
64
- resolution. This differs from RegistryInfraRegistrationStorage which
65
- uses ``container.service_registry[key]`` dict access for multi-handler
66
- routing by type string (e.g., "postgresql", "mock").
65
+ This registry uses ``container.service_registry.register_instance()``
66
+ for protocol-based type-safe DI resolution. This differs from
67
+ RegistryInfraRegistrationStorage which uses a module-level dict for
68
+ multi-handler routing by type string (e.g., "postgresql", "mock"),
69
+ as ServiceRegistry does not support dict-style indexed access.
67
70
 
68
71
  The different patterns serve different purposes:
69
72
  - Protocol-based registration: Single handler per protocol type
@@ -83,7 +86,10 @@ class RegistryInfraServiceDiscovery:
83
86
  RegistryInfraServiceDiscovery.register(container)
84
87
 
85
88
  # Explicit handler registration
86
- consul_handler = HandlerServiceDiscoveryConsul(config)
89
+ consul_handler = HandlerServiceDiscoveryConsul(
90
+ container=container,
91
+ consul_host="localhost",
92
+ )
87
93
  RegistryInfraServiceDiscovery.register_with_handler(
88
94
  container,
89
95
  handler=consul_handler,
@@ -113,21 +119,18 @@ class RegistryInfraServiceDiscovery:
113
119
  if container.service_registry is None:
114
120
  return
115
121
 
116
- # Import here to avoid circular imports
117
- from omnibase_infra.nodes.node_service_discovery_effect.protocols import (
118
- ProtocolDiscoveryOperations,
119
- )
120
-
121
- # Register protocol with lazy resolution
122
- # The actual implementation is determined at resolution time
123
- # based on configuration (CONSUL_AGENT_URL, K8S_NAMESPACE, etc.)
124
- container.register_factory(
125
- ProtocolDiscoveryOperations,
126
- RegistryInfraServiceDiscovery._create_handler_from_config,
122
+ # NOTE: Factory registration (register_factory) is not implemented in
123
+ # omnibase_core v1.0. This method provides no-op registration for forward
124
+ # compatibility. Use register_with_handler() to explicitly provide a
125
+ # pre-configured handler instance.
126
+ logger.debug(
127
+ "Service discovery factory registration skipped - "
128
+ "factory registration not implemented in v1.0. "
129
+ "Use register_with_handler() to register an explicit handler instance."
127
130
  )
128
131
 
129
132
  @staticmethod
130
- def register_with_handler(
133
+ async def register_with_handler(
131
134
  container: ModelONEXContainer,
132
135
  handler: ProtocolDiscoveryOperations,
133
136
  ) -> None:
@@ -146,12 +149,13 @@ class RegistryInfraServiceDiscovery:
146
149
  Example:
147
150
  >>> container = ModelONEXContainer()
148
151
  >>> handler = HandlerServiceDiscoveryConsul(config)
149
- >>> RegistryInfraServiceDiscovery.register_with_handler(
152
+ >>> await RegistryInfraServiceDiscovery.register_with_handler(
150
153
  ... container,
151
154
  ... handler=handler,
152
155
  ... )
153
156
  """
154
157
  # Import at runtime for isinstance check (protocol is @runtime_checkable)
158
+ from omnibase_core.enums import EnumInjectionScope
155
159
  from omnibase_infra.nodes.node_service_discovery_effect.protocols import (
156
160
  ProtocolDiscoveryOperations,
157
161
  )
@@ -174,7 +178,11 @@ class RegistryInfraServiceDiscovery:
174
178
  if container.service_registry is None:
175
179
  return
176
180
 
177
- container.register_instance(ProtocolDiscoveryOperations, handler)
181
+ await container.service_registry.register_instance(
182
+ interface=ProtocolDiscoveryOperations, # type: ignore[type-abstract]
183
+ instance=handler,
184
+ scope=EnumInjectionScope.GLOBAL,
185
+ )
178
186
 
179
187
  @staticmethod
180
188
  def _create_handler_from_config(
@@ -75,12 +75,12 @@ class PluginJsonNormalizer(PluginComputeBase):
75
75
  effective_max_depth = self.MAX_RECURSION_DEPTH
76
76
 
77
77
  try:
78
- json_data = cast(object, input_data.get("json", {}))
78
+ json_data = cast("object", input_data.get("json", {}))
79
79
  normalized: object = self._sort_keys_recursively(
80
80
  json_data, _max_depth=effective_max_depth
81
81
  )
82
82
  output: JsonNormalizerOutput = {"normalized": normalized}
83
- return cast(ModelPluginOutputData, output)
83
+ return cast("ModelPluginOutputData", output)
84
84
 
85
85
  except RecursionError as e:
86
86
  raise OnexError(
@@ -80,14 +80,14 @@ class PluginJsonNormalizerErrorHandling(PluginComputeBase):
80
80
 
81
81
  try:
82
82
  # Retrieve JSON data with safe default
83
- json_data = cast(object, input_data.get("json", {}))
83
+ json_data = cast("object", input_data.get("json", {}))
84
84
 
85
85
  # Perform pure deterministic computation
86
86
  normalized = self._sort_keys_recursively(json_data)
87
87
 
88
88
  # Return result with correlation_id for tracing
89
89
  return cast(
90
- ModelPluginOutputData,
90
+ "ModelPluginOutputData",
91
91
  {
92
92
  "normalized": normalized,
93
93
  "correlation_id": correlation_id,
@@ -105,9 +105,15 @@ ONEX 4-Node Architecture Integration:
105
105
 
106
106
  # Step 2: Integrate with NodeComputeService (I/O wrapper)
107
107
  class ValidationNode(NodeComputeService):
108
- def __init__(self, container: ONEXContainer):
108
+ def __init__(self, container: ONEXContainer, plugin: ProtocolPluginCompute):
109
109
  super().__init__(container)
110
- self.plugin = container.resolve(ProtocolPluginCompute)
110
+ # Plugin is injected via constructor (sync-friendly)
111
+ # Resolution from container happens at initialization time:
112
+ # plugin = await container.service_registry.resolve_service(
113
+ # ProtocolPluginCompute
114
+ # )
115
+ # node = ValidationNode(container, plugin)
116
+ self.plugin = plugin
111
117
 
112
118
  async def execute(self, input_model: ModelInput) -> ModelOutput:
113
119
  # Node handles I/O and state management
@@ -119,6 +125,14 @@ ONEX 4-Node Architecture Integration:
119
125
 
120
126
  # Node handles output persistence (if needed)
121
127
  return ModelOutput(**result)
128
+
129
+ # Complete initialization example:
130
+ async def create_validation_node(container: ONEXContainer) -> ValidationNode:
131
+ '''Factory function for creating ValidationNode with resolved plugin.'''
132
+ plugin = await container.service_registry.resolve_service(
133
+ ProtocolPluginCompute
134
+ )
135
+ return ValidationNode(container, plugin)
122
136
  ```
123
137
 
124
138
  When to Use Plugin vs Direct Node Implementation:
@@ -62,6 +62,7 @@ from omnibase_infra.protocols.protocol_capability_projection import (
62
62
  ProtocolCapabilityProjection,
63
63
  )
64
64
  from omnibase_infra.protocols.protocol_capability_query import ProtocolCapabilityQuery
65
+ from omnibase_infra.protocols.protocol_container_aware import ProtocolContainerAware
65
66
  from omnibase_infra.protocols.protocol_event_bus_like import ProtocolEventBusLike
66
67
  from omnibase_infra.protocols.protocol_event_projector import ProtocolEventProjector
67
68
  from omnibase_infra.protocols.protocol_idempotency_store import (
@@ -88,6 +89,7 @@ __all__: list[str] = [
88
89
  "ProtocolCapabilityQuery",
89
90
  "ProtocolEventBusLike",
90
91
  "ProtocolEventProjector",
92
+ "ProtocolContainerAware",
91
93
  "ProtocolIdempotencyStore",
92
94
  "ProtocolMessageDispatcher",
93
95
  "ProtocolMessageTypeRegistry",
@@ -0,0 +1,200 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Protocol extension for Infrastructure Handlers with Container DI.
4
+
5
+ This module defines the ProtocolContainerAware interface, which extends the base
6
+ ProtocolHandler from omnibase_spi to add container-based dependency injection
7
+ requirements. All infrastructure handlers in omnibase_infra must implement this
8
+ extended protocol.
9
+
10
+ Why This Protocol Exists:
11
+ The base ProtocolHandler in omnibase_spi is intentionally minimal and doesn't
12
+ mandate a specific constructor signature. This keeps the SPI layer decoupled
13
+ from implementation details.
14
+
15
+ However, omnibase_infra handlers require ModelONEXContainer for:
16
+ - Dependency injection of shared services (connection pools, clients)
17
+ - Configuration access without global state
18
+ - Testability through container mocking
19
+
20
+ This protocol adds the __init__ signature requirement while inheriting all
21
+ method requirements from the base protocol.
22
+
23
+ Protocol Hierarchy:
24
+ omnibase_spi.ProtocolHandler (base)
25
+ - handler_type property
26
+ - initialize()
27
+ - shutdown()
28
+ - execute()
29
+ - describe()
30
+ - health_check()
31
+
32
+ omnibase_infra.ProtocolContainerAware (extension)
33
+ - All methods from ProtocolHandler
34
+ - __init__(container: ModelONEXContainer) requirement
35
+
36
+ Usage:
37
+ Infrastructure handlers should implement this extended protocol:
38
+
39
+ ```python
40
+ from omnibase_core.container import ModelONEXContainer
41
+ from omnibase_infra.protocols import ProtocolContainerAware
42
+
43
+ class HandlerDatabase:
44
+ '''Database handler implementing the infra protocol.'''
45
+
46
+ def __init__(self, container: ModelONEXContainer) -> None:
47
+ self._container = container
48
+ # Access shared resources via container
49
+
50
+ @property
51
+ def handler_type(self) -> str:
52
+ return "db"
53
+
54
+ # ... implement remaining protocol methods ...
55
+ ```
56
+
57
+ The RuntimeHostProcess uses this protocol for type-safe handler instantiation:
58
+
59
+ ```python
60
+ handler_cls: type[ProtocolContainerAware] = handler_registry.get(handler_type)
61
+ handler_instance = handler_cls(container=container) # Type-safe
62
+ ```
63
+
64
+ Thread Safety:
65
+ Handler implementations must be thread-safe. The container provides access
66
+ to shared resources that may be used concurrently.
67
+
68
+ See Also:
69
+ - omnibase_spi.protocols.handlers.protocol_handler.ProtocolHandler
70
+ - omnibase_core.container.ModelONEXContainer
71
+ - CLAUDE.md section "Container-Based Dependency Injection"
72
+ - PR #186: Container DI refactoring for handlers
73
+
74
+ .. versionadded:: 0.7.1
75
+ Created as part of OMN-1434 container DI standardization.
76
+ """
77
+
78
+ from __future__ import annotations
79
+
80
+ from typing import TYPE_CHECKING, Protocol, runtime_checkable
81
+
82
+ from omnibase_spi.protocols.handlers.protocol_handler import (
83
+ ProtocolHandler as ProtocolHandlerBase,
84
+ )
85
+
86
+ if TYPE_CHECKING:
87
+ from omnibase_core.container import ModelONEXContainer
88
+
89
+ __all__ = [
90
+ "ProtocolContainerAware",
91
+ ]
92
+
93
+
94
+ @runtime_checkable
95
+ class ProtocolContainerAware(ProtocolHandlerBase, Protocol):
96
+ """Extended protocol for infrastructure handlers with container DI.
97
+
98
+ This protocol extends the base ProtocolHandler from omnibase_spi to require
99
+ a constructor that accepts ModelONEXContainer for dependency injection.
100
+
101
+ All infrastructure handlers in omnibase_infra must implement this protocol.
102
+ The container provides access to:
103
+ - Database connection pools
104
+ - HTTP clients
105
+ - Service discovery clients
106
+ - Configuration values
107
+ - Logging context
108
+
109
+ Methods inherited from ProtocolHandler:
110
+ handler_type: Property returning the handler type identifier.
111
+ initialize: Initialize clients and connection pools.
112
+ shutdown: Release resources and close connections.
113
+ execute: Execute protocol-specific operations.
114
+ describe: Return handler metadata and capabilities.
115
+ health_check: Check handler health and connectivity.
116
+
117
+ Constructor Requirement (added by this protocol):
118
+ __init__: Must accept container: ModelONEXContainer as first positional argument.
119
+
120
+ Example:
121
+ ```python
122
+ from omnibase_core.container import ModelONEXContainer
123
+
124
+ class HandlerConsul:
125
+ def __init__(self, container: ModelONEXContainer) -> None:
126
+ self._container = container
127
+ self._consul_url = container.config.get("consul_url")
128
+
129
+ @property
130
+ def handler_type(self) -> str:
131
+ return "consul"
132
+
133
+ async def initialize(self, config):
134
+ # Use container for shared resources
135
+ ...
136
+
137
+ # ... implement remaining methods ...
138
+ ```
139
+
140
+ Protocol Verification:
141
+ Per ONEX conventions, verify protocol compliance via duck typing:
142
+
143
+ ```python
144
+ handler_cls = handler_registry.get("http")
145
+
146
+ # Verify constructor signature accepts container
147
+ import inspect
148
+ sig = inspect.signature(handler_cls.__init__)
149
+ params = list(sig.parameters.keys())
150
+ assert "container" in params or len(params) > 1 # self + container
151
+
152
+ # Verify protocol methods exist
153
+ assert hasattr(handler_cls, "handler_type")
154
+ assert hasattr(handler_cls, "initialize") and callable(getattr(handler_cls, "initialize"))
155
+ ```
156
+
157
+ Note:
158
+ Method bodies in this Protocol use ``...`` (Ellipsis) rather than
159
+ ``raise NotImplementedError()``. This is the standard Python convention
160
+ for ``typing.Protocol`` classes per PEP 544.
161
+ """
162
+
163
+ def __init__(self, container: ModelONEXContainer) -> None:
164
+ """Initialize the handler with a dependency injection container.
165
+
166
+ All infrastructure handlers receive their dependencies through the
167
+ container rather than as individual constructor arguments. This enables:
168
+
169
+ - Consistent initialization across all handlers
170
+ - Easy testing through container mocking
171
+ - Runtime configuration without code changes
172
+ - Shared resource management (connection pools, clients)
173
+
174
+ Args:
175
+ container: ONEX dependency injection container providing access to:
176
+ - Configuration values (container.config)
177
+ - Shared services (database pools, HTTP clients)
178
+ - Logging context
179
+ - Runtime metadata
180
+
181
+ Note:
182
+ Handlers should store the container reference and access dependencies
183
+ lazily when needed, rather than extracting all values in __init__.
184
+ This improves startup time and allows for late-bound configuration.
185
+
186
+ Example:
187
+ ```python
188
+ def __init__(self, container: ModelONEXContainer) -> None:
189
+ self._container = container
190
+ self._client: httpx.AsyncClient | None = None # Lazy init
191
+
192
+ async def initialize(self, config):
193
+ # Create client during initialize(), not __init__()
194
+ self._client = httpx.AsyncClient(
195
+ base_url=self._container.config.get("base_url"),
196
+ timeout=config.get("timeout", 30.0),
197
+ )
198
+ ```
199
+ """
200
+ ...
@@ -14,7 +14,7 @@ from typing import TYPE_CHECKING, Protocol, runtime_checkable
14
14
  from uuid import UUID
15
15
 
16
16
  if TYPE_CHECKING:
17
- from omnibase_core.models.events import ModelEventEnvelope
17
+ from omnibase_core.models.events.model_event_envelope import ModelEventEnvelope
18
18
  from omnibase_core.models.projectors import ModelProjectionResult
19
19
 
20
20