omnibase_infra 0.2.1__py3-none-any.whl → 0.2.2__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 +446 -0
- omnibase_infra/cli/commands.py +1 -1
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +4 -1
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +4 -1
- 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/handlers/handler_db.py +2 -1
- omnibase_infra/handlers/handler_graph.py +10 -5
- omnibase_infra/handlers/handler_mcp.py +736 -63
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
- omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +301 -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 +24 -7
- omnibase_infra/mixins/mixin_retry_execution.py +1 -1
- omnibase_infra/models/handlers/__init__.py +10 -0
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +15 -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/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/registry/registry_infra_node_registration_orchestrator.py +9 -8
- 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/registry/registry_infra_registration_storage.py +46 -25
- 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 +24 -19
- 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/protocol_event_projector.py +1 -1
- omnibase_infra/runtime/__init__.py +51 -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 +514 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +289 -167
- omnibase_infra/runtime/handler_plugin_loader.py +4 -2
- 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/protocols/__init__.py +10 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +3 -2
- omnibase_infra/runtime/registry_policy.py +9 -326
- omnibase_infra/runtime/secret_resolver.py +4 -2
- omnibase_infra/runtime/service_kernel.py +10 -2
- omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
- omnibase_infra/runtime/service_runtime_host_process.py +225 -15
- 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 +5 -1
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +443 -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 +243 -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 +846 -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 +13 -2
- omnibase_infra/utils/util_dsn_validation.py +1 -1
- 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 +113 -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.2.dist-info}/METADATA +2 -2
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/RECORD +116 -74
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/licenses/LICENSE +0 -0
omnibase_infra/__init__.py
CHANGED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""ONEX Tool Execution Adapter - Bridges MCP tool calls to ONEX orchestrator execution.
|
|
4
|
+
|
|
5
|
+
This adapter handles the execution of MCP tool invocations by:
|
|
6
|
+
1. Validating input arguments against the tool's input schema
|
|
7
|
+
2. Building an ONEX envelope with the input payload
|
|
8
|
+
3. Dispatching to the orchestrator endpoint via HTTP
|
|
9
|
+
4. Transforming the response to MCP format
|
|
10
|
+
|
|
11
|
+
Routing:
|
|
12
|
+
The adapter uses the tool definition's endpoint or service_id to locate
|
|
13
|
+
the target orchestrator. It supports both direct HTTP dispatch and
|
|
14
|
+
service discovery via Consul.
|
|
15
|
+
|
|
16
|
+
Timeout Handling:
|
|
17
|
+
Each tool definition includes a timeout_seconds value. The adapter
|
|
18
|
+
enforces this timeout when dispatching to the orchestrator, raising
|
|
19
|
+
InfraTimeoutError if exceeded.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import asyncio
|
|
25
|
+
import logging
|
|
26
|
+
from typing import TYPE_CHECKING
|
|
27
|
+
from uuid import UUID, uuid4
|
|
28
|
+
|
|
29
|
+
import httpx
|
|
30
|
+
|
|
31
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
32
|
+
from omnibase_infra.errors import (
|
|
33
|
+
InfraConnectionError,
|
|
34
|
+
InfraTimeoutError,
|
|
35
|
+
InfraUnavailableError,
|
|
36
|
+
ModelInfraErrorContext,
|
|
37
|
+
ModelTimeoutErrorContext,
|
|
38
|
+
)
|
|
39
|
+
from omnibase_infra.mixins import MixinAsyncCircuitBreaker
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from omnibase_infra.models.mcp.model_mcp_tool_definition import (
|
|
43
|
+
ModelMCPToolDefinition,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
logger = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class AdapterONEXToolExecution(MixinAsyncCircuitBreaker):
|
|
50
|
+
"""Bridges MCP tool calls to ONEX orchestrator execution.
|
|
51
|
+
|
|
52
|
+
This adapter handles the dispatch of MCP tool invocations to the
|
|
53
|
+
appropriate ONEX orchestrator node. It supports:
|
|
54
|
+
- Direct HTTP dispatch to orchestrator endpoint
|
|
55
|
+
- Input validation against JSON Schema
|
|
56
|
+
- Timeout enforcement
|
|
57
|
+
- Error transformation to MCP format
|
|
58
|
+
- Circuit breaker protection for external HTTP calls
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
_http_client: HTTP client for orchestrator dispatch.
|
|
62
|
+
_default_timeout: Default timeout if tool definition doesn't specify one.
|
|
63
|
+
|
|
64
|
+
Example:
|
|
65
|
+
>>> adapter = AdapterONEXToolExecution()
|
|
66
|
+
>>> result = await adapter.execute(
|
|
67
|
+
... tool=tool_definition,
|
|
68
|
+
... arguments={"input_data": "test"},
|
|
69
|
+
... correlation_id=uuid4(),
|
|
70
|
+
... )
|
|
71
|
+
>>> print(result["success"])
|
|
72
|
+
True
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def __init__(
|
|
76
|
+
self,
|
|
77
|
+
http_client: httpx.AsyncClient | None = None,
|
|
78
|
+
default_timeout: float = 30.0,
|
|
79
|
+
circuit_breaker_threshold: int = 5,
|
|
80
|
+
circuit_breaker_reset_timeout: float = 60.0,
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Initialize the execution adapter.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
http_client: Optional HTTP client. If not provided, one will be
|
|
86
|
+
created during execute() calls.
|
|
87
|
+
default_timeout: Default timeout in seconds for orchestrator calls.
|
|
88
|
+
circuit_breaker_threshold: Max failures before opening circuit (default: 5).
|
|
89
|
+
circuit_breaker_reset_timeout: Seconds before automatic reset (default: 60.0).
|
|
90
|
+
"""
|
|
91
|
+
self._http_client = http_client
|
|
92
|
+
self._default_timeout = default_timeout
|
|
93
|
+
self._owns_client = http_client is None
|
|
94
|
+
|
|
95
|
+
# Initialize circuit breaker for HTTP dispatch resilience
|
|
96
|
+
self._init_circuit_breaker(
|
|
97
|
+
threshold=circuit_breaker_threshold,
|
|
98
|
+
reset_timeout=circuit_breaker_reset_timeout,
|
|
99
|
+
service_name="onex-tool-execution",
|
|
100
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
logger.debug(
|
|
104
|
+
"AdapterONEXToolExecution initialized",
|
|
105
|
+
extra={
|
|
106
|
+
"default_timeout": default_timeout,
|
|
107
|
+
"circuit_breaker_threshold": circuit_breaker_threshold,
|
|
108
|
+
"circuit_breaker_reset_timeout": circuit_breaker_reset_timeout,
|
|
109
|
+
},
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
async def execute(
|
|
113
|
+
self,
|
|
114
|
+
tool: ModelMCPToolDefinition,
|
|
115
|
+
arguments: dict[str, object],
|
|
116
|
+
correlation_id: UUID,
|
|
117
|
+
) -> dict[str, object]:
|
|
118
|
+
"""Execute an MCP tool call by dispatching to the ONEX orchestrator.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
tool: Tool definition containing endpoint, timeout, and metadata.
|
|
122
|
+
arguments: Input arguments from the MCP tool call.
|
|
123
|
+
correlation_id: Correlation ID for tracing.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Dictionary with execution result:
|
|
127
|
+
- success: True if execution succeeded
|
|
128
|
+
- result: Orchestrator response (if successful)
|
|
129
|
+
- error: Error message (if failed)
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
InfraUnavailableError: If tool endpoint is not configured.
|
|
133
|
+
InfraTimeoutError: If execution times out.
|
|
134
|
+
InfraConnectionError: If connection to orchestrator fails.
|
|
135
|
+
"""
|
|
136
|
+
logger.info(
|
|
137
|
+
"Executing MCP tool",
|
|
138
|
+
extra={
|
|
139
|
+
"tool_name": tool.name,
|
|
140
|
+
"correlation_id": str(correlation_id),
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Validate endpoint
|
|
145
|
+
endpoint = tool.endpoint
|
|
146
|
+
if not endpoint:
|
|
147
|
+
ctx = ModelInfraErrorContext.with_correlation(
|
|
148
|
+
correlation_id=correlation_id,
|
|
149
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
150
|
+
operation="execute_tool",
|
|
151
|
+
target_name=tool.name,
|
|
152
|
+
)
|
|
153
|
+
raise InfraUnavailableError(
|
|
154
|
+
f"Tool '{tool.name}' has no endpoint configured",
|
|
155
|
+
context=ctx,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Build envelope payload
|
|
159
|
+
envelope = self._build_envelope(tool, arguments, correlation_id)
|
|
160
|
+
|
|
161
|
+
# Determine timeout
|
|
162
|
+
timeout = tool.timeout_seconds or self._default_timeout
|
|
163
|
+
|
|
164
|
+
# Check circuit breaker before dispatch
|
|
165
|
+
try:
|
|
166
|
+
async with self._circuit_breaker_lock:
|
|
167
|
+
await self._check_circuit_breaker(
|
|
168
|
+
operation="execute_tool",
|
|
169
|
+
correlation_id=correlation_id,
|
|
170
|
+
)
|
|
171
|
+
except InfraUnavailableError:
|
|
172
|
+
logger.warning(
|
|
173
|
+
"MCP tool execution blocked - circuit breaker open",
|
|
174
|
+
extra={
|
|
175
|
+
"tool_name": tool.name,
|
|
176
|
+
"correlation_id": str(correlation_id),
|
|
177
|
+
},
|
|
178
|
+
)
|
|
179
|
+
return {
|
|
180
|
+
"success": False,
|
|
181
|
+
"error": "Service temporarily unavailable - circuit breaker open",
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# Dispatch to orchestrator
|
|
185
|
+
try:
|
|
186
|
+
result = await self._http_dispatch(
|
|
187
|
+
endpoint=endpoint,
|
|
188
|
+
envelope=envelope,
|
|
189
|
+
timeout=timeout,
|
|
190
|
+
correlation_id=correlation_id,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Record success to reset circuit breaker
|
|
194
|
+
async with self._circuit_breaker_lock:
|
|
195
|
+
await self._reset_circuit_breaker()
|
|
196
|
+
|
|
197
|
+
logger.info(
|
|
198
|
+
"MCP tool execution succeeded",
|
|
199
|
+
extra={
|
|
200
|
+
"tool_name": tool.name,
|
|
201
|
+
"correlation_id": str(correlation_id),
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
"success": True,
|
|
207
|
+
"result": result,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
except InfraTimeoutError:
|
|
211
|
+
# Record failure to potentially open circuit breaker
|
|
212
|
+
async with self._circuit_breaker_lock:
|
|
213
|
+
await self._record_circuit_failure(
|
|
214
|
+
operation="execute_tool",
|
|
215
|
+
correlation_id=correlation_id,
|
|
216
|
+
)
|
|
217
|
+
logger.warning(
|
|
218
|
+
"MCP tool execution timed out",
|
|
219
|
+
extra={
|
|
220
|
+
"tool_name": tool.name,
|
|
221
|
+
"timeout": timeout,
|
|
222
|
+
"correlation_id": str(correlation_id),
|
|
223
|
+
},
|
|
224
|
+
)
|
|
225
|
+
return {
|
|
226
|
+
"success": False,
|
|
227
|
+
"error": f"Tool execution timed out after {timeout} seconds",
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
except InfraConnectionError as e:
|
|
231
|
+
# Record failure to potentially open circuit breaker
|
|
232
|
+
async with self._circuit_breaker_lock:
|
|
233
|
+
await self._record_circuit_failure(
|
|
234
|
+
operation="execute_tool",
|
|
235
|
+
correlation_id=correlation_id,
|
|
236
|
+
)
|
|
237
|
+
logger.warning(
|
|
238
|
+
"MCP tool execution failed - connection error",
|
|
239
|
+
extra={
|
|
240
|
+
"tool_name": tool.name,
|
|
241
|
+
"error": str(e),
|
|
242
|
+
"correlation_id": str(correlation_id),
|
|
243
|
+
},
|
|
244
|
+
)
|
|
245
|
+
return {
|
|
246
|
+
"success": False,
|
|
247
|
+
"error": f"Connection error: {e}",
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
except Exception as e:
|
|
251
|
+
# Record failure to potentially open circuit breaker
|
|
252
|
+
async with self._circuit_breaker_lock:
|
|
253
|
+
await self._record_circuit_failure(
|
|
254
|
+
operation="execute_tool",
|
|
255
|
+
correlation_id=correlation_id,
|
|
256
|
+
)
|
|
257
|
+
logger.exception(
|
|
258
|
+
"MCP tool execution failed - unexpected error",
|
|
259
|
+
extra={
|
|
260
|
+
"tool_name": tool.name,
|
|
261
|
+
"error": str(e),
|
|
262
|
+
"correlation_id": str(correlation_id),
|
|
263
|
+
},
|
|
264
|
+
)
|
|
265
|
+
return {
|
|
266
|
+
"success": False,
|
|
267
|
+
"error": f"Unexpected error: {e}",
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
def _build_envelope(
|
|
271
|
+
self,
|
|
272
|
+
tool: ModelMCPToolDefinition,
|
|
273
|
+
arguments: dict[str, object],
|
|
274
|
+
correlation_id: UUID,
|
|
275
|
+
) -> dict[str, object]:
|
|
276
|
+
"""Build an ONEX envelope for the orchestrator.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
tool: Tool definition.
|
|
280
|
+
arguments: Input arguments from MCP.
|
|
281
|
+
correlation_id: Correlation ID.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
Envelope dict for the orchestrator.
|
|
285
|
+
"""
|
|
286
|
+
return {
|
|
287
|
+
"envelope_id": str(uuid4()),
|
|
288
|
+
"correlation_id": str(correlation_id),
|
|
289
|
+
"source": "mcp-adapter",
|
|
290
|
+
"payload": arguments,
|
|
291
|
+
"metadata": {
|
|
292
|
+
"tool_name": tool.name,
|
|
293
|
+
"tool_version": tool.version,
|
|
294
|
+
},
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async def _http_dispatch(
|
|
298
|
+
self,
|
|
299
|
+
endpoint: str,
|
|
300
|
+
envelope: dict[str, object],
|
|
301
|
+
timeout: float,
|
|
302
|
+
correlation_id: UUID,
|
|
303
|
+
) -> dict[str, object]:
|
|
304
|
+
"""Dispatch envelope to orchestrator endpoint via HTTP.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
endpoint: Target endpoint URL.
|
|
308
|
+
envelope: Request envelope.
|
|
309
|
+
timeout: Request timeout in seconds.
|
|
310
|
+
correlation_id: Correlation ID.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Response from orchestrator.
|
|
314
|
+
|
|
315
|
+
Raises:
|
|
316
|
+
InfraTimeoutError: If request times out.
|
|
317
|
+
InfraConnectionError: If connection fails.
|
|
318
|
+
"""
|
|
319
|
+
# Use provided client or create one
|
|
320
|
+
if self._http_client is not None:
|
|
321
|
+
return await self._dispatch_with_client(
|
|
322
|
+
self._http_client,
|
|
323
|
+
endpoint,
|
|
324
|
+
envelope,
|
|
325
|
+
timeout,
|
|
326
|
+
correlation_id,
|
|
327
|
+
)
|
|
328
|
+
else:
|
|
329
|
+
# Create temporary client
|
|
330
|
+
async with httpx.AsyncClient() as client:
|
|
331
|
+
return await self._dispatch_with_client(
|
|
332
|
+
client,
|
|
333
|
+
endpoint,
|
|
334
|
+
envelope,
|
|
335
|
+
timeout,
|
|
336
|
+
correlation_id,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
async def _dispatch_with_client(
|
|
340
|
+
self,
|
|
341
|
+
client: httpx.AsyncClient,
|
|
342
|
+
endpoint: str,
|
|
343
|
+
envelope: dict[str, object],
|
|
344
|
+
timeout: float,
|
|
345
|
+
correlation_id: UUID,
|
|
346
|
+
) -> dict[str, object]:
|
|
347
|
+
"""Dispatch using the provided HTTP client.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
client: HTTP client.
|
|
351
|
+
endpoint: Target endpoint URL.
|
|
352
|
+
envelope: Request envelope.
|
|
353
|
+
timeout: Request timeout in seconds.
|
|
354
|
+
correlation_id: Correlation ID.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
Response from orchestrator.
|
|
358
|
+
|
|
359
|
+
Raises:
|
|
360
|
+
InfraTimeoutError: If request times out.
|
|
361
|
+
InfraConnectionError: If connection fails.
|
|
362
|
+
"""
|
|
363
|
+
try:
|
|
364
|
+
response = await asyncio.wait_for(
|
|
365
|
+
client.post(
|
|
366
|
+
endpoint,
|
|
367
|
+
json=envelope,
|
|
368
|
+
headers={
|
|
369
|
+
"X-Correlation-ID": str(correlation_id),
|
|
370
|
+
"Content-Type": "application/json",
|
|
371
|
+
},
|
|
372
|
+
timeout=timeout,
|
|
373
|
+
),
|
|
374
|
+
timeout=timeout,
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
response.raise_for_status()
|
|
378
|
+
result: dict[str, object] = response.json()
|
|
379
|
+
return result
|
|
380
|
+
|
|
381
|
+
except TimeoutError as e:
|
|
382
|
+
timeout_ctx = ModelTimeoutErrorContext(
|
|
383
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
384
|
+
operation="http_dispatch",
|
|
385
|
+
target_name=endpoint,
|
|
386
|
+
correlation_id=correlation_id,
|
|
387
|
+
timeout_seconds=timeout,
|
|
388
|
+
)
|
|
389
|
+
raise InfraTimeoutError(
|
|
390
|
+
f"Timeout dispatching to {endpoint} after {timeout}s",
|
|
391
|
+
context=timeout_ctx,
|
|
392
|
+
) from e
|
|
393
|
+
|
|
394
|
+
except httpx.ConnectError as e:
|
|
395
|
+
ctx = ModelInfraErrorContext.with_correlation(
|
|
396
|
+
correlation_id=correlation_id,
|
|
397
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
398
|
+
operation="http_dispatch",
|
|
399
|
+
target_name=endpoint,
|
|
400
|
+
)
|
|
401
|
+
raise InfraConnectionError(
|
|
402
|
+
f"Connection failed to {endpoint}: {e}",
|
|
403
|
+
context=ctx,
|
|
404
|
+
) from e
|
|
405
|
+
|
|
406
|
+
except httpx.HTTPStatusError as e:
|
|
407
|
+
ctx = ModelInfraErrorContext.with_correlation(
|
|
408
|
+
correlation_id=correlation_id,
|
|
409
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
410
|
+
operation="http_dispatch",
|
|
411
|
+
target_name=endpoint,
|
|
412
|
+
)
|
|
413
|
+
raise InfraConnectionError(
|
|
414
|
+
f"HTTP error from {endpoint}: {e.response.status_code}",
|
|
415
|
+
context=ctx,
|
|
416
|
+
) from e
|
|
417
|
+
|
|
418
|
+
except Exception as e:
|
|
419
|
+
ctx = ModelInfraErrorContext.with_correlation(
|
|
420
|
+
correlation_id=correlation_id,
|
|
421
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
422
|
+
operation="http_dispatch",
|
|
423
|
+
target_name=endpoint,
|
|
424
|
+
)
|
|
425
|
+
raise InfraConnectionError(
|
|
426
|
+
f"Request to {endpoint} failed: {e}",
|
|
427
|
+
context=ctx,
|
|
428
|
+
) from e
|
|
429
|
+
|
|
430
|
+
async def close(self) -> None:
|
|
431
|
+
"""Close the HTTP client if owned by this adapter."""
|
|
432
|
+
if self._owns_client and self._http_client is not None:
|
|
433
|
+
await self._http_client.aclose()
|
|
434
|
+
self._http_client = None
|
|
435
|
+
|
|
436
|
+
def describe(self) -> dict[str, object]:
|
|
437
|
+
"""Return adapter metadata for observability."""
|
|
438
|
+
return {
|
|
439
|
+
"adapter_name": "AdapterONEXToolExecution",
|
|
440
|
+
"default_timeout": self._default_timeout,
|
|
441
|
+
"owns_client": self._owns_client,
|
|
442
|
+
"circuit_breaker": self._get_circuit_breaker_state(),
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
__all__ = ["AdapterONEXToolExecution"]
|
omnibase_infra/cli/commands.py
CHANGED
|
@@ -127,7 +127,7 @@ def validate_imports_cmd(directory: str) -> None:
|
|
|
127
127
|
console.print(f"[bold blue]Checking circular imports in {directory}...[/bold blue]")
|
|
128
128
|
result = validate_infra_circular_imports(directory)
|
|
129
129
|
|
|
130
|
-
#
|
|
130
|
+
# ModelImportValidationResult uses has_circular_imports property (plural)
|
|
131
131
|
if not result.has_circular_imports:
|
|
132
132
|
console.print("[bold green]Circular Imports: PASS[/bold green]")
|
|
133
133
|
raise SystemExit(0)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
#
|
|
4
|
+
# Widget Mapping Configuration for ONEX Registry Dashboard
|
|
5
|
+
#
|
|
6
|
+
# This file defines the mapping from node capabilities and semantic roles
|
|
7
|
+
# to dashboard widget types. Used by the Registry API to inform dashboards
|
|
8
|
+
# which widget to render for each node.
|
|
9
|
+
#
|
|
10
|
+
# Related Tickets:
|
|
11
|
+
# - OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
12
|
+
#
|
|
13
|
+
# Widget Types:
|
|
14
|
+
# - status_indicator: Shows health/state with colored indicator
|
|
15
|
+
# - event_feed: Scrolling list of recent events
|
|
16
|
+
# - metric_card: Single metric with value and optional trend
|
|
17
|
+
# - info_card: General information display
|
|
18
|
+
# - status_grid: Grid of status indicators
|
|
19
|
+
# - timeline: Time-based visualization
|
|
20
|
+
# - gauge: Circular progress/threshold indicator
|
|
21
|
+
# - table: Tabular data display
|
|
22
|
+
#
|
|
23
|
+
# Configuration Sections:
|
|
24
|
+
# - version: Schema version for compatibility checking
|
|
25
|
+
# - capability_mappings: Maps capability tags to widget configs
|
|
26
|
+
# - semantic_mappings: Maps semantic roles to widget configs
|
|
27
|
+
# - fallback: Default config when no mapping matches
|
|
28
|
+
version: "1.0.0"
|
|
29
|
+
# Capability Mappings
|
|
30
|
+
# Map specific capability tags to widget configurations.
|
|
31
|
+
# These take precedence over semantic mappings.
|
|
32
|
+
capability_mappings:
|
|
33
|
+
# Health and monitoring capabilities
|
|
34
|
+
health.check:
|
|
35
|
+
widget_type: status_indicator
|
|
36
|
+
defaults:
|
|
37
|
+
show_timestamp: true
|
|
38
|
+
refresh_interval_seconds: 10
|
|
39
|
+
health.heartbeat:
|
|
40
|
+
widget_type: status_indicator
|
|
41
|
+
defaults:
|
|
42
|
+
show_timestamp: true
|
|
43
|
+
show_last_seen: true
|
|
44
|
+
# Event-related capabilities
|
|
45
|
+
event.emit:
|
|
46
|
+
widget_type: event_feed
|
|
47
|
+
defaults:
|
|
48
|
+
max_items: 50
|
|
49
|
+
show_timestamp: true
|
|
50
|
+
auto_scroll: true
|
|
51
|
+
event.consume:
|
|
52
|
+
widget_type: event_feed
|
|
53
|
+
defaults:
|
|
54
|
+
max_items: 50
|
|
55
|
+
show_source: true
|
|
56
|
+
event.transform:
|
|
57
|
+
widget_type: timeline
|
|
58
|
+
defaults:
|
|
59
|
+
show_duration: true
|
|
60
|
+
# Kafka/messaging capabilities
|
|
61
|
+
kafka.consumer:
|
|
62
|
+
widget_type: metric_card
|
|
63
|
+
defaults:
|
|
64
|
+
refresh_interval_seconds: 5
|
|
65
|
+
show_lag: true
|
|
66
|
+
kafka.producer:
|
|
67
|
+
widget_type: metric_card
|
|
68
|
+
defaults:
|
|
69
|
+
refresh_interval_seconds: 5
|
|
70
|
+
show_throughput: true
|
|
71
|
+
kafka.stream:
|
|
72
|
+
widget_type: timeline
|
|
73
|
+
defaults:
|
|
74
|
+
show_offset: true
|
|
75
|
+
# Database capabilities
|
|
76
|
+
postgres.storage:
|
|
77
|
+
widget_type: metric_card
|
|
78
|
+
defaults:
|
|
79
|
+
show_connection_count: true
|
|
80
|
+
refresh_interval_seconds: 10
|
|
81
|
+
postgres.query:
|
|
82
|
+
widget_type: table
|
|
83
|
+
defaults:
|
|
84
|
+
show_query_time: true
|
|
85
|
+
# Service discovery
|
|
86
|
+
consul.register:
|
|
87
|
+
widget_type: status_indicator
|
|
88
|
+
defaults:
|
|
89
|
+
show_service_id: true
|
|
90
|
+
consul.discover:
|
|
91
|
+
widget_type: status_grid
|
|
92
|
+
defaults:
|
|
93
|
+
show_health: true
|
|
94
|
+
group_by: service_name
|
|
95
|
+
# Workflow capabilities
|
|
96
|
+
workflow.orchestrate:
|
|
97
|
+
widget_type: timeline
|
|
98
|
+
defaults:
|
|
99
|
+
show_steps: true
|
|
100
|
+
show_duration: true
|
|
101
|
+
workflow.reduce:
|
|
102
|
+
widget_type: gauge
|
|
103
|
+
defaults:
|
|
104
|
+
show_progress: true
|
|
105
|
+
# Compute capabilities
|
|
106
|
+
compute.transform:
|
|
107
|
+
widget_type: metric_card
|
|
108
|
+
defaults:
|
|
109
|
+
show_throughput: true
|
|
110
|
+
show_latency: true
|
|
111
|
+
compute.validate:
|
|
112
|
+
widget_type: status_indicator
|
|
113
|
+
defaults:
|
|
114
|
+
show_pass_rate: true
|
|
115
|
+
# Effect capabilities
|
|
116
|
+
effect.http:
|
|
117
|
+
widget_type: metric_card
|
|
118
|
+
defaults:
|
|
119
|
+
show_latency: true
|
|
120
|
+
show_error_rate: true
|
|
121
|
+
effect.grpc:
|
|
122
|
+
widget_type: metric_card
|
|
123
|
+
defaults:
|
|
124
|
+
show_latency: true
|
|
125
|
+
show_error_rate: true
|
|
126
|
+
# Semantic Mappings
|
|
127
|
+
# Map semantic roles/contexts to widget configurations.
|
|
128
|
+
# Used when capability_mappings don't match.
|
|
129
|
+
semantic_mappings:
|
|
130
|
+
# Node overview in dashboard
|
|
131
|
+
node_overview:
|
|
132
|
+
widget_type: info_card
|
|
133
|
+
defaults:
|
|
134
|
+
show_version: true
|
|
135
|
+
show_capabilities: true
|
|
136
|
+
show_state: true
|
|
137
|
+
# Instance health grid
|
|
138
|
+
instance_health:
|
|
139
|
+
widget_type: status_grid
|
|
140
|
+
defaults:
|
|
141
|
+
group_by: service_name
|
|
142
|
+
show_address: true
|
|
143
|
+
show_port: true
|
|
144
|
+
# Registration timeline
|
|
145
|
+
registration_timeline:
|
|
146
|
+
widget_type: timeline
|
|
147
|
+
defaults:
|
|
148
|
+
show_state_transitions: true
|
|
149
|
+
show_timestamps: true
|
|
150
|
+
# Capability matrix
|
|
151
|
+
capability_matrix:
|
|
152
|
+
widget_type: table
|
|
153
|
+
defaults:
|
|
154
|
+
group_by: node_type
|
|
155
|
+
show_capability_tags: true
|
|
156
|
+
# Summary statistics
|
|
157
|
+
summary_stats:
|
|
158
|
+
widget_type: metric_card
|
|
159
|
+
defaults:
|
|
160
|
+
show_trend: true
|
|
161
|
+
compare_to_previous: true
|
|
162
|
+
# Error monitoring
|
|
163
|
+
error_monitoring:
|
|
164
|
+
widget_type: event_feed
|
|
165
|
+
defaults:
|
|
166
|
+
filter_level: error
|
|
167
|
+
max_items: 100
|
|
168
|
+
highlight_critical: true
|
|
169
|
+
# Fallback Configuration
|
|
170
|
+
# Used when no capability or semantic mapping matches.
|
|
171
|
+
fallback:
|
|
172
|
+
widget_type: info_card
|
|
173
|
+
defaults:
|
|
174
|
+
show_name: true
|
|
175
|
+
show_state: true
|
|
176
|
+
show_type: true
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# Handler ID follows convention: {node_type}.{domain}.handler
|
|
2
2
|
handler_id: effect.filesystem.handler
|
|
3
3
|
name: FileSystem Handler
|
|
4
|
-
|
|
4
|
+
contract_version:
|
|
5
|
+
major: 1
|
|
6
|
+
minor: 0
|
|
7
|
+
patch: 0
|
|
5
8
|
description: >
|
|
6
9
|
Effect handler for filesystem operations including read, write, list, delete, and directory management.
|
|
7
10
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# Handler ID follows convention: {node_type}.{domain}.handler
|
|
2
2
|
handler_id: effect.mcp.handler
|
|
3
3
|
name: MCP Handler
|
|
4
|
-
|
|
4
|
+
contract_version:
|
|
5
|
+
major: 1
|
|
6
|
+
minor: 0
|
|
7
|
+
patch: 0
|
|
5
8
|
description: >
|
|
6
9
|
Effect handler for Model Context Protocol (MCP) integration. Exposes ONEX nodes as MCP tools for AI agent integration via streamable HTTP transport.
|
|
7
10
|
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
This module defines the ComputeRegistryError for compute registry operations.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from typing import Any, cast
|
|
9
|
+
|
|
8
10
|
from omnibase_infra.errors.error_infra import RuntimeHostError
|
|
9
11
|
from omnibase_infra.models.errors.model_infra_error_context import (
|
|
10
12
|
ModelInfraErrorContext,
|
|
@@ -82,10 +84,11 @@ class ComputeRegistryError(RuntimeHostError):
|
|
|
82
84
|
if registered_plugins is not None:
|
|
83
85
|
extra_context["registered_plugins"] = registered_plugins
|
|
84
86
|
|
|
87
|
+
# NOTE: Cast required for mypy - **dict[str, object] doesn't satisfy **context: Any
|
|
85
88
|
super().__init__(
|
|
86
89
|
message=message,
|
|
87
90
|
context=context,
|
|
88
|
-
**extra_context,
|
|
91
|
+
**cast("dict[str, Any]", extra_context),
|
|
89
92
|
)
|
|
90
93
|
|
|
91
94
|
|