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
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Handler Source Configuration Model.
|
|
4
|
+
|
|
5
|
+
This module provides ModelHandlerSourceConfig, a Pydantic model for
|
|
6
|
+
configuring handler source mode selection at runtime.
|
|
7
|
+
|
|
8
|
+
The configuration controls how handlers are discovered and loaded:
|
|
9
|
+
- BOOTSTRAP: Hardcoded handlers from _KNOWN_HANDLERS dict (MVP mode)
|
|
10
|
+
- CONTRACT: YAML contracts from handler_contract.yaml files (production)
|
|
11
|
+
- HYBRID: Contract-first with bootstrap fallback per-handler identity
|
|
12
|
+
|
|
13
|
+
Production hardening features:
|
|
14
|
+
- Bootstrap expiry enforcement: If bootstrap_expires_at is set and now > expires_at,
|
|
15
|
+
the runtime will refuse to start in BOOTSTRAP mode (or force CONTRACT mode)
|
|
16
|
+
- Structured logging of expiry status at startup
|
|
17
|
+
- Override control for hybrid mode handler resolution
|
|
18
|
+
|
|
19
|
+
.. versionadded:: 0.7.0
|
|
20
|
+
Created as part of OMN-1095 handler source mode configuration.
|
|
21
|
+
|
|
22
|
+
See Also:
|
|
23
|
+
- HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md: Full architecture documentation
|
|
24
|
+
- EnumHandlerSourceMode: Enum defining valid source modes
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from datetime import UTC, datetime, timezone
|
|
30
|
+
|
|
31
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
32
|
+
|
|
33
|
+
from omnibase_infra.enums.enum_handler_source_mode import EnumHandlerSourceMode
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ModelHandlerSourceConfig(BaseModel):
|
|
37
|
+
"""Configuration for handler source mode selection.
|
|
38
|
+
|
|
39
|
+
Controls how handlers are discovered and loaded at runtime. This model
|
|
40
|
+
is used by RuntimeHostProcess and related components to determine the
|
|
41
|
+
handler loading strategy.
|
|
42
|
+
|
|
43
|
+
Configuration Options:
|
|
44
|
+
- handler_source_mode: Selects the loading strategy (BOOTSTRAP, CONTRACT, HYBRID)
|
|
45
|
+
- allow_bootstrap_override: Controls handler resolution in HYBRID mode
|
|
46
|
+
- bootstrap_expires_at: Production safety - forces CONTRACT after expiry
|
|
47
|
+
|
|
48
|
+
Production Hardening:
|
|
49
|
+
When bootstrap_expires_at is set and the current time exceeds it:
|
|
50
|
+
- BOOTSTRAP mode: Runtime refuses to start (safety mechanism)
|
|
51
|
+
- HYBRID mode: Bootstrap fallback disabled, contract-only resolution
|
|
52
|
+
- CONTRACT mode: No effect (already contract-only)
|
|
53
|
+
|
|
54
|
+
This prevents accidental deployment with hardcoded handlers in production.
|
|
55
|
+
|
|
56
|
+
Attributes:
|
|
57
|
+
handler_source_mode: Handler loading source mode.
|
|
58
|
+
- BOOTSTRAP: Load from hardcoded _KNOWN_HANDLERS dict (MVP)
|
|
59
|
+
- CONTRACT: Load from handler_contract.yaml files (production)
|
|
60
|
+
- HYBRID: Contract-first with bootstrap fallback per-handler identity
|
|
61
|
+
Defaults to HYBRID as recommended for gradual migration.
|
|
62
|
+
|
|
63
|
+
allow_bootstrap_override: If True, bootstrap handlers can override
|
|
64
|
+
contract handlers in HYBRID mode. Default is False, meaning
|
|
65
|
+
contract handlers take precedence (inverse of naive HYBRID).
|
|
66
|
+
Has no effect in BOOTSTRAP or CONTRACT modes.
|
|
67
|
+
When parsing from environment or config, string values "true",
|
|
68
|
+
"yes", "1", "on" (case-insensitive) are accepted as truthy.
|
|
69
|
+
|
|
70
|
+
bootstrap_expires_at: If set and expired, refuse BOOTSTRAP mode and
|
|
71
|
+
force CONTRACT. This is a production safety mechanism to ensure
|
|
72
|
+
hardcoded handlers are not accidentally deployed to production
|
|
73
|
+
after a migration deadline. Set to None to disable expiry checking.
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
>>> from datetime import datetime, timezone
|
|
77
|
+
>>> from omnibase_infra.models.handlers import ModelHandlerSourceConfig
|
|
78
|
+
>>> from omnibase_infra.enums import EnumHandlerSourceMode
|
|
79
|
+
>>>
|
|
80
|
+
>>> # Production configuration (recommended)
|
|
81
|
+
>>> config = ModelHandlerSourceConfig(
|
|
82
|
+
... handler_source_mode=EnumHandlerSourceMode.CONTRACT,
|
|
83
|
+
... )
|
|
84
|
+
>>>
|
|
85
|
+
>>> # Migration configuration with safety expiry (must be timezone-aware)
|
|
86
|
+
>>> config = ModelHandlerSourceConfig(
|
|
87
|
+
... handler_source_mode=EnumHandlerSourceMode.HYBRID,
|
|
88
|
+
... bootstrap_expires_at=datetime(2025, 3, 1, 0, 0, 0, tzinfo=timezone.utc),
|
|
89
|
+
... )
|
|
90
|
+
>>>
|
|
91
|
+
>>> # Check if bootstrap is expired
|
|
92
|
+
>>> if config.is_bootstrap_expired:
|
|
93
|
+
... print("Bootstrap mode has expired - must use CONTRACT")
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
model_config = ConfigDict(
|
|
97
|
+
strict=True,
|
|
98
|
+
frozen=True,
|
|
99
|
+
extra="forbid",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
handler_source_mode: EnumHandlerSourceMode = Field(
|
|
103
|
+
default=EnumHandlerSourceMode.HYBRID,
|
|
104
|
+
description="Handler loading source mode: BOOTSTRAP, CONTRACT, or HYBRID. "
|
|
105
|
+
"Defaults to HYBRID (contract-first with bootstrap fallback).",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
allow_bootstrap_override: bool = Field(
|
|
109
|
+
default=False,
|
|
110
|
+
description=(
|
|
111
|
+
"If True, bootstrap handlers can override contract handlers in HYBRID mode. "
|
|
112
|
+
"Default is False (contract handlers take precedence). "
|
|
113
|
+
"When parsing from config, string values 'true', 'yes', '1', 'on' "
|
|
114
|
+
"(case-insensitive) are accepted as truthy."
|
|
115
|
+
),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
bootstrap_expires_at: datetime | None = Field(
|
|
119
|
+
default=None,
|
|
120
|
+
description=(
|
|
121
|
+
"If set and expired, refuse BOOTSTRAP mode and force CONTRACT. "
|
|
122
|
+
"Production safety mechanism for migration deadlines. "
|
|
123
|
+
"Must be timezone-aware (UTC recommended); naive datetimes are rejected."
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
@field_validator("allow_bootstrap_override", mode="before")
|
|
128
|
+
@classmethod
|
|
129
|
+
def _coerce_allow_bootstrap_override(cls, value: object) -> bool:
|
|
130
|
+
"""Coerce string and numeric values to boolean for config file compatibility.
|
|
131
|
+
|
|
132
|
+
Environment variables and YAML/JSON config files often represent booleans
|
|
133
|
+
as strings. This validator handles common truthy string representations
|
|
134
|
+
before Pydantic's strict type validation.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
value: The raw value to coerce (may be str, bool, int, float, None, or other).
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
True if value is a truthy string ("true", "yes", "1", "on") or
|
|
141
|
+
a truthy boolean, False otherwise.
|
|
142
|
+
|
|
143
|
+
Type Handling:
|
|
144
|
+
- bool: Passed through unchanged.
|
|
145
|
+
- str: Case-insensitive check for "true", "yes", "1", "on".
|
|
146
|
+
- int/float: 0 and 0.0 are False, all other numbers are True.
|
|
147
|
+
- None: Returns False.
|
|
148
|
+
- Unknown types: Default to False for safety.
|
|
149
|
+
"""
|
|
150
|
+
if isinstance(value, bool):
|
|
151
|
+
return value
|
|
152
|
+
if isinstance(value, str):
|
|
153
|
+
return value.lower() in ("true", "yes", "1", "on")
|
|
154
|
+
if isinstance(value, (int, float)):
|
|
155
|
+
# Explicit: 0/0.0 = False, any other number = True
|
|
156
|
+
return bool(value)
|
|
157
|
+
# Unknown types default to False for safety
|
|
158
|
+
return False
|
|
159
|
+
|
|
160
|
+
@field_validator("bootstrap_expires_at")
|
|
161
|
+
@classmethod
|
|
162
|
+
def _validate_expires_at_timezone(cls, value: datetime | None) -> datetime | None:
|
|
163
|
+
"""Validate and normalize bootstrap_expires_at to UTC.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
value: The datetime value to validate.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
None if value is None, otherwise the datetime normalized to UTC.
|
|
170
|
+
|
|
171
|
+
Raises:
|
|
172
|
+
ValueError: If the datetime is naive (no timezone info).
|
|
173
|
+
"""
|
|
174
|
+
if value is None:
|
|
175
|
+
return None
|
|
176
|
+
if value.tzinfo is None:
|
|
177
|
+
raise ValueError(
|
|
178
|
+
"bootstrap_expires_at must be timezone-aware (UTC recommended). "
|
|
179
|
+
"Use datetime.now(timezone.utc) or datetime(..., tzinfo=timezone.utc)."
|
|
180
|
+
)
|
|
181
|
+
return value.astimezone(UTC)
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def is_bootstrap_expired(self) -> bool:
|
|
185
|
+
"""Check if bootstrap mode has expired.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
True if bootstrap_expires_at is set and current time exceeds it,
|
|
189
|
+
False otherwise.
|
|
190
|
+
|
|
191
|
+
Note:
|
|
192
|
+
Uses UTC-aware comparison. The bootstrap_expires_at field is
|
|
193
|
+
validated and normalized to UTC at construction time.
|
|
194
|
+
"""
|
|
195
|
+
if self.bootstrap_expires_at is None:
|
|
196
|
+
return False
|
|
197
|
+
return datetime.now(UTC) > self.bootstrap_expires_at
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def effective_mode(self) -> EnumHandlerSourceMode:
|
|
201
|
+
"""Get the effective handler source mode after expiry check.
|
|
202
|
+
|
|
203
|
+
If bootstrap_expires_at is set and expired, returns CONTRACT
|
|
204
|
+
regardless of the configured handler_source_mode. Otherwise
|
|
205
|
+
returns the configured mode.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
The effective handler source mode to use at runtime.
|
|
209
|
+
|
|
210
|
+
Note:
|
|
211
|
+
This property should be used by runtime components instead of
|
|
212
|
+
directly accessing handler_source_mode to ensure expiry
|
|
213
|
+
enforcement is applied.
|
|
214
|
+
"""
|
|
215
|
+
if self.is_bootstrap_expired:
|
|
216
|
+
return EnumHandlerSourceMode.CONTRACT
|
|
217
|
+
return self.handler_source_mode
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
__all__ = ["ModelHandlerSourceConfig"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP models for Model Context Protocol integration."""
|
|
4
|
+
|
|
5
|
+
from omnibase_infra.models.mcp.model_mcp_contract_config import ModelMCPContractConfig
|
|
6
|
+
from omnibase_infra.models.mcp.model_mcp_server_config import ModelMCPServerConfig
|
|
7
|
+
from omnibase_infra.models.mcp.model_mcp_tool_definition import ModelMCPToolDefinition
|
|
8
|
+
from omnibase_infra.models.mcp.model_mcp_tool_parameter import ModelMCPToolParameter
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"ModelMCPContractConfig",
|
|
12
|
+
"ModelMCPServerConfig",
|
|
13
|
+
"ModelMCPToolDefinition",
|
|
14
|
+
"ModelMCPToolParameter",
|
|
15
|
+
]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP contract configuration model for enabling nodes as MCP tools.
|
|
4
|
+
|
|
5
|
+
This model defines the `mcp` field that can be added to ONEX contracts to expose
|
|
6
|
+
orchestrator nodes as MCP tools for AI agent integration.
|
|
7
|
+
|
|
8
|
+
Example contract.yaml:
|
|
9
|
+
node_type: ORCHESTRATOR_GENERIC
|
|
10
|
+
mcp:
|
|
11
|
+
expose: true
|
|
12
|
+
tool_name: "workflow_execute"
|
|
13
|
+
description: "Execute a workflow"
|
|
14
|
+
timeout_seconds: 30
|
|
15
|
+
|
|
16
|
+
Enforcement Rule:
|
|
17
|
+
The `mcp.expose` field is ONLY valid for ORCHESTRATOR_GENERIC nodes.
|
|
18
|
+
Non-orchestrator nodes with `mcp.expose: true` will be ignored during
|
|
19
|
+
registration - the MCP tags will not be added to Consul.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from pydantic import BaseModel, Field
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ModelMCPContractConfig(BaseModel):
|
|
28
|
+
"""MCP configuration for exposing a node as an MCP tool.
|
|
29
|
+
|
|
30
|
+
This configuration is embedded in a node's contract.yaml to enable
|
|
31
|
+
AI agents to discover and invoke the node as an MCP tool.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
expose: Whether to expose this node as an MCP tool. When True and
|
|
35
|
+
the node is an orchestrator, it will be registered with Consul
|
|
36
|
+
using MCP-specific tags for tool discovery.
|
|
37
|
+
tool_name: Optional stable name for the MCP tool. If not provided,
|
|
38
|
+
defaults to the node's name. Use this to provide a consistent
|
|
39
|
+
tool name across node version changes.
|
|
40
|
+
description: Optional AI-friendly description of what this tool does.
|
|
41
|
+
If not provided, the node's description from the contract is used.
|
|
42
|
+
timeout_seconds: Optional execution timeout in seconds. Defaults to 30.
|
|
43
|
+
This is enforced when AI agents invoke the tool.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
>>> config = ModelMCPContractConfig(
|
|
47
|
+
... expose=True,
|
|
48
|
+
... tool_name="my_workflow",
|
|
49
|
+
... description="Execute my custom workflow",
|
|
50
|
+
... timeout_seconds=60,
|
|
51
|
+
... )
|
|
52
|
+
>>> config.expose
|
|
53
|
+
True
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
expose: bool = Field(
|
|
57
|
+
default=False,
|
|
58
|
+
description="Whether to expose this node as an MCP tool. "
|
|
59
|
+
"Only valid for ORCHESTRATOR_GENERIC nodes.",
|
|
60
|
+
)
|
|
61
|
+
tool_name: str | None = Field(
|
|
62
|
+
default=None,
|
|
63
|
+
description="Optional stable name for the MCP tool. "
|
|
64
|
+
"Defaults to the node's name if not specified.",
|
|
65
|
+
)
|
|
66
|
+
description: str | None = Field(
|
|
67
|
+
default=None,
|
|
68
|
+
description="Optional AI-friendly description of what this tool does. "
|
|
69
|
+
"If not provided, the node's description from the contract is used.",
|
|
70
|
+
)
|
|
71
|
+
timeout_seconds: int = Field(
|
|
72
|
+
default=30,
|
|
73
|
+
ge=1,
|
|
74
|
+
le=300,
|
|
75
|
+
description="Execution timeout in seconds for tool invocations. "
|
|
76
|
+
"Minimum: 1, Maximum: 300 (5 minutes).",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
__all__ = ["ModelMCPContractConfig"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP server configuration model.
|
|
4
|
+
|
|
5
|
+
This model defines the configuration for the MCP server lifecycle,
|
|
6
|
+
including Consul discovery, Kafka hot reload, and HTTP server settings.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ModelMCPServerConfig(BaseModel):
|
|
15
|
+
"""Configuration for the MCP server lifecycle.
|
|
16
|
+
|
|
17
|
+
This model captures all configuration needed for the MCP server:
|
|
18
|
+
- Consul connection settings for service discovery
|
|
19
|
+
- Kafka settings for hot reload
|
|
20
|
+
- HTTP server binding
|
|
21
|
+
- Execution defaults
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
consul_host: Consul server hostname for service discovery.
|
|
25
|
+
consul_port: Consul server port.
|
|
26
|
+
consul_scheme: HTTP scheme for Consul (http/https).
|
|
27
|
+
consul_token: Optional ACL token for Consul authentication.
|
|
28
|
+
kafka_enabled: Whether to enable Kafka for hot reload.
|
|
29
|
+
http_host: Host to bind the MCP HTTP server.
|
|
30
|
+
http_port: Port for the MCP HTTP server.
|
|
31
|
+
default_timeout: Default execution timeout for tools.
|
|
32
|
+
dev_mode: Whether to run in development mode (local contracts).
|
|
33
|
+
contracts_dir: Directory for contract scanning in dev mode.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
consul_host: str = Field(default="localhost", description="Consul server hostname")
|
|
37
|
+
consul_port: int = Field(
|
|
38
|
+
default=8500, ge=1, le=65535, description="Consul server port"
|
|
39
|
+
)
|
|
40
|
+
consul_scheme: str = Field(
|
|
41
|
+
default="http", pattern="^https?$", description="HTTP scheme for Consul"
|
|
42
|
+
)
|
|
43
|
+
consul_token: str | None = Field(
|
|
44
|
+
default=None, description="Optional ACL token for Consul authentication"
|
|
45
|
+
)
|
|
46
|
+
kafka_enabled: bool = Field(
|
|
47
|
+
default=True, description="Whether to enable Kafka for hot reload"
|
|
48
|
+
)
|
|
49
|
+
http_host: str = Field(
|
|
50
|
+
default="0.0.0.0", # noqa: S104 - Intentional bind-all for server
|
|
51
|
+
description="Host to bind the MCP HTTP server",
|
|
52
|
+
)
|
|
53
|
+
http_port: int = Field(
|
|
54
|
+
default=8090, ge=1, le=65535, description="Port for the MCP HTTP server"
|
|
55
|
+
)
|
|
56
|
+
default_timeout: float = Field(
|
|
57
|
+
default=30.0, gt=0, le=300, description="Default execution timeout for tools"
|
|
58
|
+
)
|
|
59
|
+
dev_mode: bool = Field(
|
|
60
|
+
default=False, description="Whether to run in development mode"
|
|
61
|
+
)
|
|
62
|
+
contracts_dir: str | None = Field(
|
|
63
|
+
default=None, description="Directory for contract scanning in dev mode"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
__all__ = ["ModelMCPServerConfig"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP tool definition model for representing ONEX nodes as MCP tools.
|
|
4
|
+
|
|
5
|
+
This model is used by the MCP adapter layer to:
|
|
6
|
+
1. Cache discovered tools in the registry
|
|
7
|
+
2. Generate MCP tool schemas for AI agents
|
|
8
|
+
3. Route tool invocations to ONEX orchestrators
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, Field
|
|
14
|
+
|
|
15
|
+
from omnibase_infra.models.mcp.model_mcp_tool_parameter import ModelMCPToolParameter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelMCPToolDefinition(BaseModel):
|
|
19
|
+
"""Complete MCP tool definition derived from an ONEX orchestrator node.
|
|
20
|
+
|
|
21
|
+
This model captures all information needed to:
|
|
22
|
+
- Expose the tool to AI agents via MCP protocol
|
|
23
|
+
- Route invocations to the correct ONEX orchestrator
|
|
24
|
+
- Enforce execution constraints (timeout, etc.)
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
name: Stable tool name for AI agent invocation. This is derived from
|
|
28
|
+
contract.mcp.tool_name or falls back to the node name.
|
|
29
|
+
description: AI-friendly description of tool functionality.
|
|
30
|
+
version: Tool version from the node contract.
|
|
31
|
+
parameters: List of input parameters with type information.
|
|
32
|
+
input_schema: JSON Schema for input validation.
|
|
33
|
+
orchestrator_node_id: UUID of the ONEX orchestrator node.
|
|
34
|
+
orchestrator_service_id: Consul service ID for routing.
|
|
35
|
+
endpoint: HTTP endpoint for direct invocation (if available).
|
|
36
|
+
timeout_seconds: Execution timeout for tool invocations.
|
|
37
|
+
metadata: Additional metadata for routing and observability.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
name: str = Field(description="Stable tool name for MCP invocation")
|
|
41
|
+
description: str = Field(description="AI-friendly tool description")
|
|
42
|
+
version: str = Field(default="1.0.0", description="Tool version")
|
|
43
|
+
parameters: list[ModelMCPToolParameter] = Field(
|
|
44
|
+
default_factory=list, description="Input parameters"
|
|
45
|
+
)
|
|
46
|
+
input_schema: dict[str, object] = Field(
|
|
47
|
+
default_factory=lambda: dict[str, object]({"type": "object", "properties": {}}),
|
|
48
|
+
description="JSON Schema for input validation",
|
|
49
|
+
)
|
|
50
|
+
orchestrator_node_id: str | None = Field(
|
|
51
|
+
default=None, description="UUID of the source orchestrator node"
|
|
52
|
+
)
|
|
53
|
+
orchestrator_service_id: str | None = Field(
|
|
54
|
+
default=None, description="Consul service ID for routing"
|
|
55
|
+
)
|
|
56
|
+
endpoint: str | None = Field(
|
|
57
|
+
default=None, description="HTTP endpoint for direct invocation"
|
|
58
|
+
)
|
|
59
|
+
timeout_seconds: int = Field(
|
|
60
|
+
default=30, ge=1, le=300, description="Execution timeout in seconds"
|
|
61
|
+
)
|
|
62
|
+
metadata: dict[str, object] = Field(
|
|
63
|
+
default_factory=dict,
|
|
64
|
+
description="Additional metadata (tags, input_model module, etc.)",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def tool_type(self) -> str:
|
|
69
|
+
"""Return the MCP tool type. Always 'function' for ONEX nodes."""
|
|
70
|
+
return "function"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
__all__ = ["ModelMCPToolDefinition"]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP tool parameter model for representing tool input parameters."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ModelMCPToolParameter(BaseModel):
|
|
11
|
+
"""Parameter definition for an MCP tool.
|
|
12
|
+
|
|
13
|
+
Represents a single parameter that can be passed to an MCP tool,
|
|
14
|
+
including its type, validation constraints, and documentation.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
name: str = Field(description="Parameter name")
|
|
18
|
+
parameter_type: str = Field(
|
|
19
|
+
default="string",
|
|
20
|
+
description="JSON Schema type: string, number, boolean, array, object",
|
|
21
|
+
)
|
|
22
|
+
description: str = Field(default="", description="Human-readable description")
|
|
23
|
+
required: bool = Field(
|
|
24
|
+
default=True, description="Whether this parameter is required"
|
|
25
|
+
)
|
|
26
|
+
default_value: object | None = Field(
|
|
27
|
+
default=None, description="Default value if not provided"
|
|
28
|
+
)
|
|
29
|
+
json_schema: dict[str, object] | None = Field(
|
|
30
|
+
default=None,
|
|
31
|
+
description="Additional JSON Schema constraints (enum, format, etc.)",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
__all__ = ["ModelMCPToolParameter"]
|
|
@@ -12,9 +12,12 @@ Note:
|
|
|
12
12
|
would not correctly handle this distinction.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
from pydantic import BaseModel, ConfigDict, Field
|
|
16
18
|
|
|
17
19
|
from omnibase_core.types import JsonType
|
|
20
|
+
from omnibase_infra.models.mcp.model_mcp_contract_config import ModelMCPContractConfig
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
class ModelNodeCapabilities(BaseModel):
|
|
@@ -94,6 +97,14 @@ class ModelNodeCapabilities(BaseModel):
|
|
|
94
97
|
description="Nested configuration (JSON-serializable values)",
|
|
95
98
|
)
|
|
96
99
|
|
|
100
|
+
# MCP configuration for exposing node as AI agent tool
|
|
101
|
+
# Only valid for ORCHESTRATOR nodes - ignored for other node types
|
|
102
|
+
mcp: ModelMCPContractConfig | None = Field(
|
|
103
|
+
default=None,
|
|
104
|
+
description="MCP configuration for exposing node as AI agent tool. "
|
|
105
|
+
"Only valid for ORCHESTRATOR_GENERIC nodes.",
|
|
106
|
+
)
|
|
107
|
+
|
|
97
108
|
def __getitem__(self, key: str) -> object:
|
|
98
109
|
"""Enable dict-like access to capabilities.
|
|
99
110
|
|
|
@@ -14,6 +14,7 @@ from uuid import UUID
|
|
|
14
14
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
15
15
|
|
|
16
16
|
from omnibase_core.enums import EnumNodeKind
|
|
17
|
+
from omnibase_core.models.capabilities import ModelContractCapabilities
|
|
17
18
|
from omnibase_core.models.primitives.model_semver import ModelSemVer
|
|
18
19
|
from omnibase_infra.enums import EnumIntrospectionReason
|
|
19
20
|
from omnibase_infra.models.discovery.model_discovered_capabilities import (
|
|
@@ -49,6 +50,8 @@ class ModelNodeIntrospectionEvent(BaseModel):
|
|
|
49
50
|
node_version: Semantic version of the node.
|
|
50
51
|
declared_capabilities: Contract-declared capabilities (feature flags).
|
|
51
52
|
discovered_capabilities: Runtime-discovered capabilities (reflection).
|
|
53
|
+
contract_capabilities: Contract-derived capabilities (design-time truth).
|
|
54
|
+
Populated from the node's contract when available, None otherwise.
|
|
52
55
|
endpoints: Dictionary of exposed endpoints (name -> URL).
|
|
53
56
|
current_state: Current FSM state if the node has state management.
|
|
54
57
|
reason: Why this introspection event was emitted.
|
|
@@ -98,6 +101,12 @@ class ModelNodeIntrospectionEvent(BaseModel):
|
|
|
98
101
|
default_factory=ModelDiscoveredCapabilities,
|
|
99
102
|
description="Capabilities discovered via runtime reflection",
|
|
100
103
|
)
|
|
104
|
+
contract_capabilities: ModelContractCapabilities | None = Field(
|
|
105
|
+
default=None,
|
|
106
|
+
description="Contract-derived capabilities (design-time truth, deterministic). "
|
|
107
|
+
"Populated by ContractCapabilityExtractor from the node's contract. "
|
|
108
|
+
"None when contract is not available or extraction fails.",
|
|
109
|
+
)
|
|
101
110
|
|
|
102
111
|
# Endpoints and state
|
|
103
112
|
endpoints: dict[str, str] = Field(
|
|
@@ -27,6 +27,7 @@ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_valida
|
|
|
27
27
|
|
|
28
28
|
logger = logging.getLogger(__name__)
|
|
29
29
|
|
|
30
|
+
from omnibase_core.models.primitives import ModelSemVer
|
|
30
31
|
from omnibase_infra.enums.enum_handler_type_category import EnumHandlerTypeCategory
|
|
31
32
|
from omnibase_infra.errors import ProtocolConfigurationError
|
|
32
33
|
from omnibase_infra.models.runtime.model_contract_security_config import (
|
|
@@ -131,6 +132,10 @@ class ModelHandlerContract(BaseModel):
|
|
|
131
132
|
default=None,
|
|
132
133
|
description="Optional security configuration for the handler",
|
|
133
134
|
)
|
|
135
|
+
handler_version: ModelSemVer | None = Field(
|
|
136
|
+
default=None,
|
|
137
|
+
description="Handler version in semantic versioning format. If not provided, defaults to 1.0.0",
|
|
138
|
+
)
|
|
134
139
|
|
|
135
140
|
@field_validator("handler_type", mode="before")
|
|
136
141
|
@classmethod
|
|
@@ -207,18 +212,22 @@ class ModelHandlerContract(BaseModel):
|
|
|
207
212
|
return []
|
|
208
213
|
|
|
209
214
|
@model_validator(mode="after")
|
|
210
|
-
def
|
|
211
|
-
"""Set
|
|
215
|
+
def set_defaults(self) -> ModelHandlerContract:
|
|
216
|
+
"""Set default values for protocol_type and handler_version.
|
|
212
217
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
218
|
+
Protocol Type:
|
|
219
|
+
If protocol_type is None, derives it from handler_name by stripping
|
|
220
|
+
the 'handler-' prefix. If handler_name doesn't have that prefix,
|
|
221
|
+
uses the full handler_name as protocol_type.
|
|
216
222
|
|
|
217
|
-
|
|
218
|
-
|
|
223
|
+
Guards against empty derived protocol_type which would produce
|
|
224
|
+
invalid registry keys.
|
|
225
|
+
|
|
226
|
+
Handler Version:
|
|
227
|
+
If handler_version is None, sets it to the default version 1.0.0.
|
|
219
228
|
|
|
220
229
|
Returns:
|
|
221
|
-
Self with protocol_type populated.
|
|
230
|
+
Self with protocol_type and handler_version populated.
|
|
222
231
|
|
|
223
232
|
Raises:
|
|
224
233
|
ValueError: If derived protocol_type would be empty (e.g., handler_name
|
|
@@ -232,6 +241,8 @@ class ModelHandlerContract(BaseModel):
|
|
|
232
241
|
... )
|
|
233
242
|
>>> contract.protocol_type
|
|
234
243
|
'db'
|
|
244
|
+
>>> contract.handler_version
|
|
245
|
+
ModelSemVer(major=1, minor=0, patch=0)
|
|
235
246
|
|
|
236
247
|
>>> contract = ModelHandlerContract(
|
|
237
248
|
... handler_name="custom-handler",
|
|
@@ -241,6 +252,10 @@ class ModelHandlerContract(BaseModel):
|
|
|
241
252
|
>>> contract.protocol_type
|
|
242
253
|
'custom-handler'
|
|
243
254
|
"""
|
|
255
|
+
# Set default handler_version if not provided
|
|
256
|
+
if self.handler_version is None:
|
|
257
|
+
self.handler_version = ModelSemVer(major=1, minor=0, patch=0)
|
|
258
|
+
|
|
244
259
|
if self.protocol_type is None:
|
|
245
260
|
prefix = "handler-"
|
|
246
261
|
if self.handler_name.startswith(prefix):
|
|
@@ -263,7 +278,7 @@ class ModelHandlerContract(BaseModel):
|
|
|
263
278
|
f"Provide a non-empty protocol_type or handler_name."
|
|
264
279
|
)
|
|
265
280
|
|
|
266
|
-
# Log successful
|
|
281
|
+
# Log successful contract validation for debugging
|
|
267
282
|
logger.debug(
|
|
268
283
|
"Handler contract validated successfully",
|
|
269
284
|
extra={
|
|
@@ -271,6 +286,7 @@ class ModelHandlerContract(BaseModel):
|
|
|
271
286
|
"handler_class": self.handler_class,
|
|
272
287
|
"protocol_type": self.protocol_type,
|
|
273
288
|
"handler_type": self.handler_type.value,
|
|
289
|
+
"handler_version": str(self.handler_version),
|
|
274
290
|
},
|
|
275
291
|
)
|
|
276
292
|
|
|
@@ -24,6 +24,7 @@ from pathlib import Path
|
|
|
24
24
|
|
|
25
25
|
from pydantic import BaseModel, ConfigDict, Field
|
|
26
26
|
|
|
27
|
+
from omnibase_core.models.primitives import ModelSemVer
|
|
27
28
|
from omnibase_infra.enums.enum_handler_type_category import EnumHandlerTypeCategory
|
|
28
29
|
|
|
29
30
|
|
|
@@ -53,10 +54,13 @@ class ModelLoadedHandler(BaseModel):
|
|
|
53
54
|
Examples: ['auth', 'validation', 'http-client'].
|
|
54
55
|
loaded_at: Timestamp when the handler was successfully loaded.
|
|
55
56
|
Used for diagnostics and cache invalidation.
|
|
57
|
+
handler_version: Semantic version of the handler from the contract.
|
|
58
|
+
Used for version tracking and compatibility checks.
|
|
56
59
|
|
|
57
60
|
Example:
|
|
58
61
|
>>> from datetime import datetime, UTC
|
|
59
62
|
>>> from pathlib import Path
|
|
63
|
+
>>> from omnibase_core.models.primitives import ModelSemVer
|
|
60
64
|
>>> from omnibase_infra.enums import EnumHandlerTypeCategory
|
|
61
65
|
>>> handler = ModelLoadedHandler(
|
|
62
66
|
... handler_name="auth.validate_token",
|
|
@@ -65,6 +69,7 @@ class ModelLoadedHandler(BaseModel):
|
|
|
65
69
|
... contract_path=Path("/app/handlers/auth/handler_contract.yaml"),
|
|
66
70
|
... capability_tags=["auth", "validation", "jwt"],
|
|
67
71
|
... loaded_at=datetime.now(UTC),
|
|
72
|
+
... handler_version=ModelSemVer(major=1, minor=0, patch=0),
|
|
68
73
|
... )
|
|
69
74
|
>>> handler.handler_name
|
|
70
75
|
'auth.validate_token'
|
|
@@ -115,6 +120,10 @@ class ModelLoadedHandler(BaseModel):
|
|
|
115
120
|
...,
|
|
116
121
|
description="Timestamp when the handler was successfully loaded",
|
|
117
122
|
)
|
|
123
|
+
handler_version: ModelSemVer = Field(
|
|
124
|
+
...,
|
|
125
|
+
description="Handler semantic version from contract",
|
|
126
|
+
)
|
|
118
127
|
|
|
119
128
|
|
|
120
129
|
__all__ = ["ModelLoadedHandler"]
|