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.
- omnibase_infra/__init__.py +1 -1
- omnibase_infra/adapters/adapter_onex_tool_execution.py +451 -0
- omnibase_infra/capabilities/__init__.py +15 -0
- omnibase_infra/capabilities/capability_inference_rules.py +211 -0
- omnibase_infra/capabilities/contract_capability_extractor.py +221 -0
- omnibase_infra/capabilities/intent_type_extractor.py +160 -0
- omnibase_infra/cli/commands.py +1 -1
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +5 -2
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +5 -2
- omnibase_infra/enums/__init__.py +6 -0
- omnibase_infra/enums/enum_handler_error_type.py +10 -0
- omnibase_infra/enums/enum_handler_source_mode.py +72 -0
- omnibase_infra/enums/enum_kafka_acks.py +99 -0
- omnibase_infra/errors/error_compute_registry.py +4 -1
- omnibase_infra/errors/error_event_bus_registry.py +4 -1
- omnibase_infra/errors/error_infra.py +3 -1
- omnibase_infra/errors/error_policy_registry.py +4 -1
- omnibase_infra/event_bus/event_bus_kafka.py +1 -1
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +59 -10
- omnibase_infra/handlers/__init__.py +8 -1
- omnibase_infra/handlers/handler_consul.py +7 -1
- omnibase_infra/handlers/handler_db.py +10 -3
- omnibase_infra/handlers/handler_graph.py +10 -5
- omnibase_infra/handlers/handler_http.py +8 -2
- omnibase_infra/handlers/handler_intent.py +387 -0
- omnibase_infra/handlers/handler_mcp.py +745 -63
- omnibase_infra/handlers/handler_vault.py +11 -5
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
- omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +7 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +308 -4
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
- omnibase_infra/mixins/mixin_node_introspection.py +42 -7
- omnibase_infra/mixins/mixin_retry_execution.py +1 -1
- omnibase_infra/models/discovery/model_introspection_config.py +11 -0
- omnibase_infra/models/handlers/__init__.py +48 -5
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_contract_discovery_result.py +6 -4
- omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
- omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
- omnibase_infra/models/mcp/__init__.py +15 -0
- omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
- omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
- omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
- omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
- omnibase_infra/models/registration/model_node_capabilities.py +11 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +9 -0
- omnibase_infra/models/runtime/model_handler_contract.py +25 -9
- omnibase_infra/models/runtime/model_loaded_handler.py +9 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
- omnibase_infra/nodes/effects/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
- omnibase_infra/nodes/node_registration_orchestrator/plugin.py +1 -1
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +4 -3
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_storage_effect/node.py +4 -1
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +47 -26
- omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +28 -20
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
- omnibase_infra/plugins/plugin_compute_base.py +16 -2
- omnibase_infra/protocols/__init__.py +2 -0
- omnibase_infra/protocols/protocol_container_aware.py +200 -0
- omnibase_infra/protocols/protocol_event_projector.py +1 -1
- omnibase_infra/runtime/__init__.py +90 -1
- omnibase_infra/runtime/binding_config_resolver.py +102 -37
- omnibase_infra/runtime/constants_notification.py +75 -0
- omnibase_infra/runtime/contract_handler_discovery.py +6 -1
- omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +267 -186
- omnibase_infra/runtime/handler_identity.py +81 -0
- omnibase_infra/runtime/handler_plugin_loader.py +19 -2
- omnibase_infra/runtime/handler_registry.py +11 -3
- omnibase_infra/runtime/handler_source_resolver.py +326 -0
- omnibase_infra/runtime/mixin_semver_cache.py +25 -1
- omnibase_infra/runtime/mixins/__init__.py +7 -0
- omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
- omnibase_infra/runtime/models/__init__.py +24 -0
- omnibase_infra/runtime/models/model_health_check_result.py +2 -1
- omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
- omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1 -1
- omnibase_infra/runtime/projector_shell.py +229 -1
- omnibase_infra/runtime/protocol_lifecycle_executor.py +6 -6
- omnibase_infra/runtime/protocols/__init__.py +10 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +16 -15
- omnibase_infra/runtime/registry_contract_source.py +693 -0
- omnibase_infra/runtime/registry_policy.py +9 -326
- omnibase_infra/runtime/secret_resolver.py +4 -2
- omnibase_infra/runtime/service_kernel.py +11 -3
- omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
- omnibase_infra/runtime/service_runtime_host_process.py +589 -106
- omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
- omnibase_infra/runtime/transition_notification_publisher.py +764 -0
- omnibase_infra/runtime/util_container_wiring.py +6 -5
- omnibase_infra/runtime/util_wiring.py +17 -4
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/__init__.py +21 -0
- omnibase_infra/services/corpus_capture.py +7 -1
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
- omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
- omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
- omnibase_infra/services/registry_api/__init__.py +40 -0
- omnibase_infra/services/registry_api/main.py +261 -0
- omnibase_infra/services/registry_api/models/__init__.py +66 -0
- omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
- omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
- omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
- omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
- omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
- omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
- omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
- omnibase_infra/services/registry_api/models/model_warning.py +49 -0
- omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
- omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
- omnibase_infra/services/registry_api/routes.py +371 -0
- omnibase_infra/services/registry_api/service.py +837 -0
- omnibase_infra/services/service_capability_query.py +4 -4
- omnibase_infra/services/service_health.py +3 -2
- omnibase_infra/services/service_timeout_emitter.py +20 -3
- omnibase_infra/services/service_timeout_scanner.py +7 -3
- omnibase_infra/services/session/__init__.py +56 -0
- omnibase_infra/services/session/config_consumer.py +120 -0
- omnibase_infra/services/session/config_store.py +139 -0
- omnibase_infra/services/session/consumer.py +1007 -0
- omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
- omnibase_infra/services/session/store.py +997 -0
- omnibase_infra/utils/__init__.py +19 -0
- omnibase_infra/utils/util_atomic_file.py +261 -0
- omnibase_infra/utils/util_db_transaction.py +239 -0
- omnibase_infra/utils/util_dsn_validation.py +1 -1
- omnibase_infra/utils/util_retry_optimistic.py +281 -0
- omnibase_infra/validation/__init__.py +3 -19
- omnibase_infra/validation/contracts/security.validation.yaml +114 -0
- omnibase_infra/validation/infra_validators.py +35 -24
- omnibase_infra/validation/validation_exemptions.yaml +140 -9
- omnibase_infra/validation/validator_chain_propagation.py +2 -2
- omnibase_infra/validation/validator_runtime_shape.py +1 -1
- omnibase_infra/validation/validator_security.py +473 -370
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/METADATA +3 -3
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/RECORD +161 -98
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/licenses/LICENSE +0 -0
omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py
CHANGED
|
@@ -39,7 +39,7 @@ class RegistryInfraArchitectureValidator:
|
|
|
39
39
|
|
|
40
40
|
This registry provides a static method to register the NodeArchitectureValidator
|
|
41
41
|
with the ONEX dependency injection container. The validator is registered as
|
|
42
|
-
|
|
42
|
+
an instance after being created with the container reference.
|
|
43
43
|
|
|
44
44
|
Thread Safety:
|
|
45
45
|
Registration is typically done at startup before the container is frozen.
|
|
@@ -53,17 +53,17 @@ class RegistryInfraArchitectureValidator:
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
container = ModelONEXContainer()
|
|
56
|
-
RegistryInfraArchitectureValidator.register(container)
|
|
56
|
+
await RegistryInfraArchitectureValidator.register(container)
|
|
57
57
|
```
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
60
|
@staticmethod
|
|
61
|
-
def register(container: ModelONEXContainer) -> None:
|
|
61
|
+
async def register(container: ModelONEXContainer) -> None:
|
|
62
62
|
"""Register architecture validator with container.
|
|
63
63
|
|
|
64
64
|
Registers the NodeArchitectureValidator as a service in the ONEX
|
|
65
|
-
dependency injection container. The validator is
|
|
66
|
-
|
|
65
|
+
dependency injection container. The validator is created immediately
|
|
66
|
+
and registered as a singleton instance.
|
|
67
67
|
|
|
68
68
|
Args:
|
|
69
69
|
container: The DI container to register with.
|
|
@@ -77,22 +77,29 @@ class RegistryInfraArchitectureValidator:
|
|
|
77
77
|
Example:
|
|
78
78
|
```python
|
|
79
79
|
container = ModelONEXContainer()
|
|
80
|
-
RegistryInfraArchitectureValidator.register(container)
|
|
80
|
+
await RegistryInfraArchitectureValidator.register(container)
|
|
81
81
|
|
|
82
82
|
# Resolve when needed
|
|
83
|
-
validator = container.
|
|
83
|
+
validator = await container.service_registry.resolve_service(
|
|
84
|
+
NodeArchitectureValidator
|
|
85
|
+
)
|
|
84
86
|
result = await validator.compute(request)
|
|
85
87
|
```
|
|
86
88
|
"""
|
|
89
|
+
from omnibase_core.enums import EnumInjectionScope
|
|
90
|
+
|
|
87
91
|
# Check if service_registry is available
|
|
88
92
|
if container.service_registry is None:
|
|
89
93
|
# Container doesn't have full DI support - skip registration
|
|
90
94
|
# This allows the code to work with minimal container configurations
|
|
91
95
|
return
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
# Create instance and register (factory registration not supported in v1.0)
|
|
98
|
+
validator_instance = NodeArchitectureValidator(container)
|
|
99
|
+
await container.service_registry.register_instance(
|
|
100
|
+
interface=NodeArchitectureValidator,
|
|
101
|
+
instance=validator_instance,
|
|
102
|
+
scope=EnumInjectionScope.GLOBAL,
|
|
96
103
|
)
|
|
97
104
|
|
|
98
105
|
|
|
@@ -36,6 +36,13 @@ node_version: "1.0.0"
|
|
|
36
36
|
name: "node_registration_orchestrator"
|
|
37
37
|
node_type: "ORCHESTRATOR_GENERIC"
|
|
38
38
|
description: "Registration workflow orchestrator that coordinates node lifecycle by calling reducer for intents and effect for execution."
|
|
39
|
+
# MCP (Model Context Protocol) Configuration
|
|
40
|
+
# Exposes this orchestrator as an AI-invocable tool via MCP server
|
|
41
|
+
mcp:
|
|
42
|
+
expose: true
|
|
43
|
+
tool_name: "register_node"
|
|
44
|
+
description: "Register a new ONEX node with the cluster. Handles Consul service registration and PostgreSQL metadata storage. Returns registration status and assigned service ID."
|
|
45
|
+
timeout_seconds: 30
|
|
39
46
|
input_model:
|
|
40
47
|
name: "ModelOrchestratorInput"
|
|
41
48
|
module: "omnibase_infra.nodes.node_registration_orchestrator.models"
|
|
@@ -53,6 +53,7 @@ Related Tickets:
|
|
|
53
53
|
from __future__ import annotations
|
|
54
54
|
|
|
55
55
|
import logging
|
|
56
|
+
import re
|
|
56
57
|
import time
|
|
57
58
|
from datetime import datetime, timedelta
|
|
58
59
|
from typing import TYPE_CHECKING
|
|
@@ -237,6 +238,39 @@ class HandlerNodeIntrospected:
|
|
|
237
238
|
"""Check if HandlerConsul is configured for Consul registration."""
|
|
238
239
|
return self._consul_handler is not None
|
|
239
240
|
|
|
241
|
+
def _sanitize_tool_name(self, name: str) -> str:
|
|
242
|
+
"""Sanitize tool name for use in Consul tags.
|
|
243
|
+
|
|
244
|
+
Converts free-form text (like descriptions) into stable, Consul-safe
|
|
245
|
+
identifiers. This ensures consistent service discovery matching.
|
|
246
|
+
|
|
247
|
+
Transformation rules:
|
|
248
|
+
1. Convert to lowercase
|
|
249
|
+
2. Replace non-alphanumeric characters with dashes
|
|
250
|
+
3. Collapse multiple consecutive dashes into one
|
|
251
|
+
4. Remove leading/trailing dashes
|
|
252
|
+
5. Truncate to 63 characters (Consul tag limit)
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
name: Raw tool name or description text.
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
Sanitized string suitable for Consul tags (lowercase, alphanumeric
|
|
259
|
+
with dashes, max 63 chars).
|
|
260
|
+
|
|
261
|
+
Example:
|
|
262
|
+
>>> handler._sanitize_tool_name("My Cool Tool (v2.0)")
|
|
263
|
+
'my-cool-tool-v2-0'
|
|
264
|
+
>>> handler._sanitize_tool_name(" Spaces & Special!Chars ")
|
|
265
|
+
'spaces-special-chars'
|
|
266
|
+
"""
|
|
267
|
+
# Replace non-alphanumeric with dash, lowercase
|
|
268
|
+
sanitized = re.sub(r"[^a-zA-Z0-9]+", "-", name.lower())
|
|
269
|
+
# Remove leading/trailing dashes
|
|
270
|
+
sanitized = sanitized.strip("-")
|
|
271
|
+
# Truncate to Consul tag limit (63 chars is common limit for DNS labels)
|
|
272
|
+
return sanitized[:63]
|
|
273
|
+
|
|
240
274
|
async def handle(
|
|
241
275
|
self,
|
|
242
276
|
envelope: ModelEventEnvelope[ModelNodeIntrospectionEvent],
|
|
@@ -422,11 +456,19 @@ class HandlerNodeIntrospected:
|
|
|
422
456
|
|
|
423
457
|
# Register with Consul for service discovery (dual registration)
|
|
424
458
|
# This happens AFTER PostgreSQL persistence (source of truth)
|
|
459
|
+
# Pass MCP config from capabilities (if present) for MCP tag generation
|
|
460
|
+
mcp_config = (
|
|
461
|
+
event.declared_capabilities.mcp
|
|
462
|
+
if event.declared_capabilities is not None
|
|
463
|
+
else None
|
|
464
|
+
)
|
|
425
465
|
await self._register_with_consul(
|
|
426
466
|
node_id=node_id,
|
|
427
467
|
node_type=event.node_type.value,
|
|
428
468
|
endpoints=event.endpoints,
|
|
429
469
|
correlation_id=correlation_id,
|
|
470
|
+
mcp_config=mcp_config,
|
|
471
|
+
node_name=event.metadata.description if event.metadata else None,
|
|
430
472
|
)
|
|
431
473
|
|
|
432
474
|
logger.info(
|
|
@@ -458,6 +500,8 @@ class HandlerNodeIntrospected:
|
|
|
458
500
|
node_type: str,
|
|
459
501
|
endpoints: dict[str, str] | None,
|
|
460
502
|
correlation_id: UUID,
|
|
503
|
+
mcp_config: object | None = None,
|
|
504
|
+
node_name: str | None = None,
|
|
461
505
|
) -> None:
|
|
462
506
|
"""Register node with Consul for service discovery.
|
|
463
507
|
|
|
@@ -465,8 +509,16 @@ class HandlerNodeIntrospected:
|
|
|
465
509
|
- service_name: `onex-{node_type}` (ONEX convention for service discovery)
|
|
466
510
|
- service_id: `onex-{node_type}-{node_id}` (unique identifier)
|
|
467
511
|
- tags: [`onex`, `node-type:{node_type}`]
|
|
512
|
+
- MCP tags (orchestrators only): [`mcp-enabled`, `mcp-tool:{tool_name}`]
|
|
468
513
|
- address/port: Extracted from endpoints if available
|
|
469
514
|
|
|
515
|
+
MCP Tags:
|
|
516
|
+
MCP tags are added ONLY when:
|
|
517
|
+
1. node_type is "orchestrator"
|
|
518
|
+
2. mcp_config is provided with expose=True
|
|
519
|
+
|
|
520
|
+
This ensures only orchestrators can be exposed as MCP tools.
|
|
521
|
+
|
|
470
522
|
This method is idempotent - re-registering the same service_id updates it.
|
|
471
523
|
Errors are logged but not propagated (PostgreSQL is source of truth).
|
|
472
524
|
|
|
@@ -475,6 +527,8 @@ class HandlerNodeIntrospected:
|
|
|
475
527
|
node_type: ONEX node type (effect, compute, reducer, orchestrator).
|
|
476
528
|
endpoints: Optional dict of endpoint URLs from introspection event.
|
|
477
529
|
correlation_id: Correlation ID for tracing.
|
|
530
|
+
mcp_config: Optional MCP configuration from capabilities.
|
|
531
|
+
node_name: Optional node name for MCP tool naming.
|
|
478
532
|
"""
|
|
479
533
|
if self._consul_handler is None:
|
|
480
534
|
logger.debug(
|
|
@@ -554,11 +608,42 @@ class HandlerNodeIntrospected:
|
|
|
554
608
|
},
|
|
555
609
|
)
|
|
556
610
|
|
|
611
|
+
# Build base tags
|
|
612
|
+
tags: list[str] = ["onex", f"node-type:{node_type}"]
|
|
613
|
+
|
|
614
|
+
# Add MCP tags for orchestrators with MCP config enabled
|
|
615
|
+
# MCP tags are ONLY added when:
|
|
616
|
+
# 1. node_type is "orchestrator" (enforces orchestrator-only rule)
|
|
617
|
+
# 2. mcp_config exists with expose=True
|
|
618
|
+
if node_type == "orchestrator" and mcp_config is not None:
|
|
619
|
+
# Check if mcp_config has expose attribute and it's True
|
|
620
|
+
mcp_expose = getattr(mcp_config, "expose", False)
|
|
621
|
+
if mcp_expose:
|
|
622
|
+
# Get tool name from mcp_config or fall back to node_name
|
|
623
|
+
mcp_tool_name_raw = getattr(mcp_config, "tool_name", None)
|
|
624
|
+
if not mcp_tool_name_raw:
|
|
625
|
+
# Fall back to node_name (description), then service_name
|
|
626
|
+
mcp_tool_name_raw = node_name or service_name
|
|
627
|
+
# Sanitize tool name for Consul tag safety
|
|
628
|
+
# node_name comes from metadata.description which can be free-form text
|
|
629
|
+
mcp_tool_name = self._sanitize_tool_name(mcp_tool_name_raw)
|
|
630
|
+
tags.extend(["mcp-enabled", f"mcp-tool:{mcp_tool_name}"])
|
|
631
|
+
|
|
632
|
+
logger.info(
|
|
633
|
+
"Adding MCP tags to Consul registration",
|
|
634
|
+
extra={
|
|
635
|
+
"node_id": str(node_id),
|
|
636
|
+
"tool_name": mcp_tool_name,
|
|
637
|
+
"tool_name_raw": mcp_tool_name_raw,
|
|
638
|
+
"correlation_id": str(correlation_id),
|
|
639
|
+
},
|
|
640
|
+
)
|
|
641
|
+
|
|
557
642
|
# Build Consul registration payload
|
|
558
643
|
consul_payload: dict[str, object] = {
|
|
559
644
|
"name": service_name,
|
|
560
645
|
"service_id": service_id,
|
|
561
|
-
"tags":
|
|
646
|
+
"tags": tags,
|
|
562
647
|
}
|
|
563
648
|
if address:
|
|
564
649
|
consul_payload["address"] = address
|
|
@@ -392,7 +392,7 @@ class IntrospectionEventRouter:
|
|
|
392
392
|
correlation_id=raw_envelope.correlation_id or callback_correlation_id,
|
|
393
393
|
source_tool=raw_envelope.source_tool,
|
|
394
394
|
target_tool=raw_envelope.target_tool,
|
|
395
|
-
metadata=_normalize_metadata(raw_envelope.metadata),
|
|
395
|
+
metadata=_normalize_metadata(raw_envelope.metadata), # type: ignore[arg-type]
|
|
396
396
|
priority=raw_envelope.priority,
|
|
397
397
|
timeout_seconds=raw_envelope.timeout_seconds,
|
|
398
398
|
trace_id=raw_envelope.trace_id,
|
|
@@ -419,7 +419,7 @@ class IntrospectionEventRouter:
|
|
|
419
419
|
},
|
|
420
420
|
)
|
|
421
421
|
dispatcher_start_time = time.time()
|
|
422
|
-
result = await self._dispatcher.handle(event_envelope)
|
|
422
|
+
result = await self._dispatcher.handle(event_envelope) # type: ignore[arg-type]
|
|
423
423
|
dispatcher_duration = time.time() - dispatcher_start_time
|
|
424
424
|
|
|
425
425
|
if result.is_successful():
|
|
@@ -441,7 +441,7 @@ class IntrospectionEventRouter:
|
|
|
441
441
|
if result.output_events:
|
|
442
442
|
for output_event in result.output_events:
|
|
443
443
|
# Wrap output event in envelope
|
|
444
|
-
output_envelope = ModelEventEnvelope(
|
|
444
|
+
output_envelope = ModelEventEnvelope( # type: ignore[var-annotated]
|
|
445
445
|
payload=output_event,
|
|
446
446
|
correlation_id=event_envelope.correlation_id,
|
|
447
447
|
envelope_timestamp=datetime.now(UTC),
|
|
@@ -515,7 +515,7 @@ class PluginRegistration:
|
|
|
515
515
|
# Deferred import: Only load HandlerConsul when Consul is configured
|
|
516
516
|
from omnibase_infra.handlers import HandlerConsul
|
|
517
517
|
|
|
518
|
-
self._consul_handler = HandlerConsul()
|
|
518
|
+
self._consul_handler = HandlerConsul(config.container)
|
|
519
519
|
await self._consul_handler.initialize(
|
|
520
520
|
{"host": consul_host, "port": consul_port}
|
|
521
521
|
)
|
|
@@ -13,7 +13,7 @@ Handler Wiring (from contract.yaml):
|
|
|
13
13
|
- ModelNodeHeartbeatEvent -> HandlerNodeHeartbeat
|
|
14
14
|
|
|
15
15
|
Handler Implementation:
|
|
16
|
-
All handlers implement
|
|
16
|
+
All handlers implement ProtocolContainerAware directly with:
|
|
17
17
|
- handler_id, category, message_types, node_kind properties
|
|
18
18
|
- handle(envelope) -> ModelHandlerOutput signature
|
|
19
19
|
|
|
@@ -88,11 +88,12 @@ from __future__ import annotations
|
|
|
88
88
|
import importlib
|
|
89
89
|
import logging
|
|
90
90
|
from pathlib import Path
|
|
91
|
-
from typing import TYPE_CHECKING
|
|
91
|
+
from typing import TYPE_CHECKING, cast
|
|
92
92
|
|
|
93
93
|
from omnibase_core.services.service_handler_registry import ServiceHandlerRegistry
|
|
94
94
|
from omnibase_infra.enums import EnumInfraTransportType
|
|
95
95
|
from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationError
|
|
96
|
+
from omnibase_infra.protocols import ProtocolContainerAware
|
|
96
97
|
from omnibase_infra.runtime.contract_loaders import (
|
|
97
98
|
load_handler_class_info_from_contract,
|
|
98
99
|
)
|
|
@@ -110,14 +111,14 @@ ALLOWED_NAMESPACES: tuple[str, ...] = (
|
|
|
110
111
|
|
|
111
112
|
|
|
112
113
|
def _validate_handler_protocol(handler: object) -> tuple[bool, list[str]]:
|
|
113
|
-
"""Validate handler implements
|
|
114
|
+
"""Validate handler implements ProtocolContainerAware via duck typing.
|
|
114
115
|
|
|
115
116
|
Uses duck typing to verify the handler has the required properties and
|
|
116
|
-
methods for
|
|
117
|
+
methods for ProtocolContainerAware compliance. Per ONEX conventions,
|
|
117
118
|
protocol compliance is verified via structural typing rather than
|
|
118
119
|
isinstance checks.
|
|
119
120
|
|
|
120
|
-
Protocol Requirements (
|
|
121
|
+
Protocol Requirements (ProtocolContainerAware):
|
|
121
122
|
- handler_id (property): Unique identifier string
|
|
122
123
|
- category (property): EnumMessageCategory value
|
|
123
124
|
- message_types (property): set[str] of message type names
|
|
@@ -492,7 +493,7 @@ class RegistryInfraNodeRegistrationOrchestrator:
|
|
|
492
493
|
context=ctx,
|
|
493
494
|
) from e
|
|
494
495
|
|
|
495
|
-
# Validate handler implements
|
|
496
|
+
# Validate handler implements ProtocolContainerAware
|
|
496
497
|
is_valid, missing = _validate_handler_protocol(handler_instance)
|
|
497
498
|
if not is_valid:
|
|
498
499
|
ctx = ModelInfraErrorContext.with_correlation(
|
|
@@ -501,7 +502,7 @@ class RegistryInfraNodeRegistrationOrchestrator:
|
|
|
501
502
|
target_name=handler_class_name,
|
|
502
503
|
)
|
|
503
504
|
raise ProtocolConfigurationError(
|
|
504
|
-
f"Handler '{handler_class_name}' does not implement
|
|
505
|
+
f"Handler '{handler_class_name}' does not implement ProtocolContainerAware. "
|
|
505
506
|
f"Missing required members: {', '.join(missing)}. "
|
|
506
507
|
f"Handlers must have: handler_id, category, message_types, node_kind properties "
|
|
507
508
|
f"and handle(envelope) method. "
|
|
@@ -510,7 +511,7 @@ class RegistryInfraNodeRegistrationOrchestrator:
|
|
|
510
511
|
)
|
|
511
512
|
|
|
512
513
|
# Register handler
|
|
513
|
-
registry.register_handler(handler_instance)
|
|
514
|
+
registry.register_handler(handler_instance) # type: ignore[arg-type]
|
|
514
515
|
logger.debug(
|
|
515
516
|
"Registered handler from contract: %s",
|
|
516
517
|
handler_class_name,
|
|
@@ -203,8 +203,9 @@ class TimeoutCoordinator:
|
|
|
203
203
|
|
|
204
204
|
Usage in orchestrator:
|
|
205
205
|
>>> # Wire dependencies
|
|
206
|
-
>>> timeout_query = ServiceTimeoutScanner(projection_reader)
|
|
206
|
+
>>> timeout_query = ServiceTimeoutScanner(container, projection_reader)
|
|
207
207
|
>>> timeout_emission = ServiceTimeoutEmitter(
|
|
208
|
+
... container=container,
|
|
208
209
|
... timeout_query=timeout_query,
|
|
209
210
|
... event_bus=event_bus,
|
|
210
211
|
... projector=projector,
|
|
@@ -235,8 +236,8 @@ class TimeoutCoordinator:
|
|
|
235
236
|
|
|
236
237
|
Example:
|
|
237
238
|
>>> reader = ProjectionReaderRegistration(pool)
|
|
238
|
-
>>> query = ServiceTimeoutScanner(reader)
|
|
239
|
-
>>> emission = ServiceTimeoutEmitter(query, event_bus, projector)
|
|
239
|
+
>>> query = ServiceTimeoutScanner(container, reader)
|
|
240
|
+
>>> emission = ServiceTimeoutEmitter(container, query, event_bus, projector)
|
|
240
241
|
>>> coordinator = TimeoutCoordinator(query, emission)
|
|
241
242
|
"""
|
|
242
243
|
self._timeout_query = timeout_query
|
|
@@ -44,6 +44,7 @@ import logging
|
|
|
44
44
|
from typing import TYPE_CHECKING, TypedDict, cast
|
|
45
45
|
from uuid import UUID
|
|
46
46
|
|
|
47
|
+
from omnibase_core.enums import EnumInjectionScope
|
|
47
48
|
from omnibase_infra.enums import EnumInfraTransportType
|
|
48
49
|
from omnibase_infra.errors import (
|
|
49
50
|
ContainerValidationError,
|
|
@@ -269,12 +270,14 @@ async def wire_registration_dispatchers(
|
|
|
269
270
|
# because MessageDispatchEngine.register_dispatcher() takes a callable
|
|
270
271
|
|
|
271
272
|
# 3a. Register DispatcherNodeIntrospected
|
|
273
|
+
# Note: node_kind is NOT passed to register_dispatcher because the dispatcher's
|
|
274
|
+
# handle() method doesn't accept ModelDispatchContext - it handles time injection
|
|
275
|
+
# internally. The node_kind property is informational only.
|
|
272
276
|
engine.register_dispatcher(
|
|
273
277
|
dispatcher_id=dispatcher_introspected.dispatcher_id,
|
|
274
278
|
dispatcher=dispatcher_introspected.handle,
|
|
275
279
|
category=dispatcher_introspected.category,
|
|
276
280
|
message_types=dispatcher_introspected.message_types,
|
|
277
|
-
node_kind=dispatcher_introspected.node_kind,
|
|
278
281
|
)
|
|
279
282
|
dispatchers_registered.append(dispatcher_introspected.dispatcher_id)
|
|
280
283
|
|
|
@@ -284,7 +287,6 @@ async def wire_registration_dispatchers(
|
|
|
284
287
|
dispatcher=dispatcher_runtime_tick.handle,
|
|
285
288
|
category=dispatcher_runtime_tick.category,
|
|
286
289
|
message_types=dispatcher_runtime_tick.message_types,
|
|
287
|
-
node_kind=dispatcher_runtime_tick.node_kind,
|
|
288
290
|
)
|
|
289
291
|
dispatchers_registered.append(dispatcher_runtime_tick.dispatcher_id)
|
|
290
292
|
|
|
@@ -294,7 +296,6 @@ async def wire_registration_dispatchers(
|
|
|
294
296
|
dispatcher=dispatcher_acked.handle,
|
|
295
297
|
category=dispatcher_acked.category,
|
|
296
298
|
message_types=dispatcher_acked.message_types,
|
|
297
|
-
node_kind=dispatcher_acked.node_kind,
|
|
298
299
|
)
|
|
299
300
|
dispatchers_registered.append(dispatcher_acked.dispatcher_id)
|
|
300
301
|
|
|
@@ -409,7 +410,7 @@ async def wire_registration_handlers(
|
|
|
409
410
|
ContainerWiringError: If service registration fails.
|
|
410
411
|
|
|
411
412
|
Note:
|
|
412
|
-
Services are registered with scope=
|
|
413
|
+
Services are registered with scope=EnumInjectionScope.GLOBAL and may conflict if multiple
|
|
413
414
|
plugins register the same interface type. This is acceptable for the
|
|
414
415
|
Registration domain as these handlers are singletons by design. If you
|
|
415
416
|
need to register multiple implementations of the same interface, use
|
|
@@ -440,7 +441,7 @@ async def wire_registration_handlers(
|
|
|
440
441
|
await container.service_registry.register_instance(
|
|
441
442
|
interface=ProjectionReaderRegistration,
|
|
442
443
|
instance=projection_reader,
|
|
443
|
-
scope=
|
|
444
|
+
scope=EnumInjectionScope.GLOBAL,
|
|
444
445
|
metadata={
|
|
445
446
|
"description": "Registration projection reader",
|
|
446
447
|
"version": str(semver_default),
|
|
@@ -453,7 +454,7 @@ async def wire_registration_handlers(
|
|
|
453
454
|
await container.service_registry.register_instance(
|
|
454
455
|
interface=ProjectorShell,
|
|
455
456
|
instance=projector,
|
|
456
|
-
scope=
|
|
457
|
+
scope=EnumInjectionScope.GLOBAL,
|
|
457
458
|
metadata={
|
|
458
459
|
"description": "Registration projector",
|
|
459
460
|
"version": str(semver_default),
|
|
@@ -470,7 +471,7 @@ async def wire_registration_handlers(
|
|
|
470
471
|
await container.service_registry.register_instance(
|
|
471
472
|
interface=HandlerNodeIntrospected,
|
|
472
473
|
instance=handler_introspected,
|
|
473
|
-
scope=
|
|
474
|
+
scope=EnumInjectionScope.GLOBAL,
|
|
474
475
|
metadata={
|
|
475
476
|
"description": "Handler for NodeIntrospectionEvent",
|
|
476
477
|
"version": str(semver_default),
|
|
@@ -485,7 +486,7 @@ async def wire_registration_handlers(
|
|
|
485
486
|
await container.service_registry.register_instance(
|
|
486
487
|
interface=HandlerRuntimeTick,
|
|
487
488
|
instance=handler_runtime_tick,
|
|
488
|
-
scope=
|
|
489
|
+
scope=EnumInjectionScope.GLOBAL,
|
|
489
490
|
metadata={
|
|
490
491
|
"description": "Handler for RuntimeTick",
|
|
491
492
|
"version": str(semver_default),
|
|
@@ -501,7 +502,7 @@ async def wire_registration_handlers(
|
|
|
501
502
|
await container.service_registry.register_instance(
|
|
502
503
|
interface=HandlerNodeRegistrationAcked,
|
|
503
504
|
instance=handler_acked,
|
|
504
|
-
scope=
|
|
505
|
+
scope=EnumInjectionScope.GLOBAL,
|
|
505
506
|
metadata={
|
|
506
507
|
"description": "Handler for NodeRegistrationAcked",
|
|
507
508
|
"version": str(semver_default),
|
|
@@ -579,7 +580,7 @@ async def get_projection_reader_from_container(
|
|
|
579
580
|
_validate_service_registry(container, "resolve ProjectionReaderRegistration")
|
|
580
581
|
try:
|
|
581
582
|
return cast(
|
|
582
|
-
ProjectionReaderRegistration,
|
|
583
|
+
"ProjectionReaderRegistration",
|
|
583
584
|
await container.service_registry.resolve_service(
|
|
584
585
|
ProjectionReaderRegistration
|
|
585
586
|
),
|
|
@@ -622,7 +623,7 @@ async def get_handler_node_introspected_from_container(
|
|
|
622
623
|
_validate_service_registry(container, "resolve HandlerNodeIntrospected")
|
|
623
624
|
try:
|
|
624
625
|
return cast(
|
|
625
|
-
HandlerNodeIntrospected,
|
|
626
|
+
"HandlerNodeIntrospected",
|
|
626
627
|
await container.service_registry.resolve_service(HandlerNodeIntrospected),
|
|
627
628
|
)
|
|
628
629
|
except Exception as e:
|
|
@@ -663,7 +664,7 @@ async def get_handler_runtime_tick_from_container(
|
|
|
663
664
|
_validate_service_registry(container, "resolve HandlerRuntimeTick")
|
|
664
665
|
try:
|
|
665
666
|
return cast(
|
|
666
|
-
HandlerRuntimeTick,
|
|
667
|
+
"HandlerRuntimeTick",
|
|
667
668
|
await container.service_registry.resolve_service(HandlerRuntimeTick),
|
|
668
669
|
)
|
|
669
670
|
except Exception as e:
|
|
@@ -704,7 +705,7 @@ async def get_handler_node_registration_acked_from_container(
|
|
|
704
705
|
_validate_service_registry(container, "resolve HandlerNodeRegistrationAcked")
|
|
705
706
|
try:
|
|
706
707
|
return cast(
|
|
707
|
-
HandlerNodeRegistrationAcked,
|
|
708
|
+
"HandlerNodeRegistrationAcked",
|
|
708
709
|
await container.service_registry.resolve_service(
|
|
709
710
|
HandlerNodeRegistrationAcked
|
|
710
711
|
),
|
|
@@ -15,11 +15,6 @@
|
|
|
15
15
|
name: "node_registration_storage_effect"
|
|
16
16
|
contract_name: "node_registration_storage_effect"
|
|
17
17
|
node_name: "node_registration_storage_effect"
|
|
18
|
-
# Version (semantic versioning)
|
|
19
|
-
version:
|
|
20
|
-
major: 1
|
|
21
|
-
minor: 0
|
|
22
|
-
patch: 0
|
|
23
18
|
contract_version:
|
|
24
19
|
major: 1
|
|
25
20
|
minor: 0
|
|
@@ -44,7 +44,10 @@ Pluggable Backends:
|
|
|
44
44
|
|
|
45
45
|
# Create container and register handler
|
|
46
46
|
container = ModelONEXContainer()
|
|
47
|
-
handler = HandlerRegistrationStoragePostgres(
|
|
47
|
+
handler = HandlerRegistrationStoragePostgres(
|
|
48
|
+
container=container,
|
|
49
|
+
dsn="postgresql://...",
|
|
50
|
+
)
|
|
48
51
|
RegistryInfraRegistrationStorage.register(container)
|
|
49
52
|
RegistryInfraRegistrationStorage.register_handler(container, handler)
|
|
50
53
|
|