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.
Files changed (116) hide show
  1. omnibase_infra/__init__.py +1 -1
  2. omnibase_infra/adapters/adapter_onex_tool_execution.py +446 -0
  3. omnibase_infra/cli/commands.py +1 -1
  4. omnibase_infra/configs/widget_mapping.yaml +176 -0
  5. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +4 -1
  6. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +4 -1
  7. omnibase_infra/errors/error_compute_registry.py +4 -1
  8. omnibase_infra/errors/error_event_bus_registry.py +4 -1
  9. omnibase_infra/errors/error_infra.py +3 -1
  10. omnibase_infra/errors/error_policy_registry.py +4 -1
  11. omnibase_infra/handlers/handler_db.py +2 -1
  12. omnibase_infra/handlers/handler_graph.py +10 -5
  13. omnibase_infra/handlers/handler_mcp.py +736 -63
  14. omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
  15. omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
  16. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +301 -4
  17. omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
  18. omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
  19. omnibase_infra/mixins/mixin_node_introspection.py +24 -7
  20. omnibase_infra/mixins/mixin_retry_execution.py +1 -1
  21. omnibase_infra/models/handlers/__init__.py +10 -0
  22. omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
  23. omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
  24. omnibase_infra/models/mcp/__init__.py +15 -0
  25. omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
  26. omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
  27. omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
  28. omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
  29. omnibase_infra/models/registration/model_node_capabilities.py +11 -0
  30. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
  31. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
  32. omnibase_infra/nodes/effects/contract.yaml +0 -5
  33. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
  34. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
  35. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
  36. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
  37. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
  38. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
  39. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +46 -25
  40. omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
  41. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
  42. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +24 -19
  43. omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
  44. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
  45. omnibase_infra/plugins/plugin_compute_base.py +16 -2
  46. omnibase_infra/protocols/protocol_event_projector.py +1 -1
  47. omnibase_infra/runtime/__init__.py +51 -1
  48. omnibase_infra/runtime/binding_config_resolver.py +102 -37
  49. omnibase_infra/runtime/constants_notification.py +75 -0
  50. omnibase_infra/runtime/contract_handler_discovery.py +6 -1
  51. omnibase_infra/runtime/handler_bootstrap_source.py +514 -0
  52. omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
  53. omnibase_infra/runtime/handler_contract_source.py +289 -167
  54. omnibase_infra/runtime/handler_plugin_loader.py +4 -2
  55. omnibase_infra/runtime/mixin_semver_cache.py +25 -1
  56. omnibase_infra/runtime/mixins/__init__.py +7 -0
  57. omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
  58. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
  59. omnibase_infra/runtime/models/__init__.py +24 -0
  60. omnibase_infra/runtime/models/model_health_check_result.py +2 -1
  61. omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
  62. omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
  63. omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
  64. omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
  65. omnibase_infra/runtime/projector_plugin_loader.py +1 -1
  66. omnibase_infra/runtime/projector_shell.py +229 -1
  67. omnibase_infra/runtime/protocols/__init__.py +10 -0
  68. omnibase_infra/runtime/registry/registry_protocol_binding.py +3 -2
  69. omnibase_infra/runtime/registry_policy.py +9 -326
  70. omnibase_infra/runtime/secret_resolver.py +4 -2
  71. omnibase_infra/runtime/service_kernel.py +10 -2
  72. omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
  73. omnibase_infra/runtime/service_runtime_host_process.py +225 -15
  74. omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
  75. omnibase_infra/runtime/transition_notification_publisher.py +764 -0
  76. omnibase_infra/runtime/util_container_wiring.py +6 -5
  77. omnibase_infra/runtime/util_wiring.py +5 -1
  78. omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
  79. omnibase_infra/services/mcp/__init__.py +31 -0
  80. omnibase_infra/services/mcp/mcp_server_lifecycle.py +443 -0
  81. omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
  82. omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
  83. omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
  84. omnibase_infra/services/registry_api/__init__.py +40 -0
  85. omnibase_infra/services/registry_api/main.py +243 -0
  86. omnibase_infra/services/registry_api/models/__init__.py +66 -0
  87. omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
  88. omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
  89. omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
  90. omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
  91. omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
  92. omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
  93. omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
  94. omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
  95. omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
  96. omnibase_infra/services/registry_api/models/model_warning.py +49 -0
  97. omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
  98. omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
  99. omnibase_infra/services/registry_api/routes.py +371 -0
  100. omnibase_infra/services/registry_api/service.py +846 -0
  101. omnibase_infra/services/service_capability_query.py +4 -4
  102. omnibase_infra/services/service_health.py +3 -2
  103. omnibase_infra/services/service_timeout_emitter.py +13 -2
  104. omnibase_infra/utils/util_dsn_validation.py +1 -1
  105. omnibase_infra/validation/__init__.py +3 -19
  106. omnibase_infra/validation/contracts/security.validation.yaml +114 -0
  107. omnibase_infra/validation/infra_validators.py +35 -24
  108. omnibase_infra/validation/validation_exemptions.yaml +113 -9
  109. omnibase_infra/validation/validator_chain_propagation.py +2 -2
  110. omnibase_infra/validation/validator_runtime_shape.py +1 -1
  111. omnibase_infra/validation/validator_security.py +473 -370
  112. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/METADATA +2 -2
  113. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/RECORD +116 -74
  114. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/WHEEL +0 -0
  115. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/entry_points.txt +0 -0
  116. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,243 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Registry API FastAPI Application.
4
+
5
+ Creates and configures the FastAPI application for the Registry API.
6
+ Provides factory function for flexible instantiation with different
7
+ backend configurations.
8
+
9
+ Usage:
10
+ # Create app with default settings (no backends)
11
+ app = create_app()
12
+
13
+ # Create app with full backends
14
+ app = create_app(
15
+ projection_reader=reader,
16
+ consul_handler=handler,
17
+ )
18
+
19
+ # Run with uvicorn
20
+ uvicorn.run(app, host="0.0.0.0", port=8000)
21
+
22
+ Related Tickets:
23
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import logging
29
+ import os
30
+ from collections.abc import AsyncIterator
31
+ from contextlib import asynccontextmanager
32
+ from pathlib import Path
33
+ from typing import TYPE_CHECKING
34
+
35
+ from fastapi import FastAPI
36
+ from fastapi.middleware.cors import CORSMiddleware
37
+
38
+ from omnibase_infra.enums import EnumInfraTransportType
39
+ from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationError
40
+ from omnibase_infra.services.registry_api.routes import router
41
+ from omnibase_infra.services.registry_api.service import ServiceRegistryDiscovery
42
+
43
+ if TYPE_CHECKING:
44
+ from omnibase_infra.handlers.service_discovery import HandlerServiceDiscoveryConsul
45
+ from omnibase_infra.projectors import ProjectionReaderRegistration
46
+
47
+ logger = logging.getLogger(__name__)
48
+
49
+ # API metadata
50
+ API_TITLE = "ONEX Registry API"
51
+ API_DESCRIPTION = """
52
+ Registry Discovery API for ONEX Dashboard Integration.
53
+
54
+ This API provides access to node registrations and live service instances
55
+ for dashboard consumption. It combines data from:
56
+
57
+ - **PostgreSQL Projections**: Node registration state, capabilities, and metadata
58
+ - **Consul Service Discovery**: Live service instances with health status
59
+
60
+ ## Key Features
61
+
62
+ - **Full Dashboard Payload**: Single endpoint for all dashboard data
63
+ - **Partial Success**: Returns data even when one backend fails
64
+ - **Widget Mapping**: Configuration for capability-to-widget rendering
65
+ - **Health Monitoring**: Component-level health status
66
+
67
+ ## Related Tickets
68
+
69
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
70
+ """
71
+ API_VERSION = "1.0.0"
72
+
73
+
74
+ @asynccontextmanager
75
+ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
76
+ """Application lifespan handler for startup/shutdown.
77
+
78
+ Initializes backend connections on startup and cleans up on shutdown.
79
+
80
+ Args:
81
+ app: FastAPI application instance.
82
+
83
+ Yields:
84
+ None (context manager pattern).
85
+ """
86
+ logger.info("Registry API starting up")
87
+
88
+ # Log configuration
89
+ service: ServiceRegistryDiscovery | None = getattr(
90
+ app.state, "registry_service", None
91
+ )
92
+ if service is not None:
93
+ logger.info(
94
+ "Registry service configured",
95
+ extra={
96
+ "has_projection_reader": service.has_projection_reader,
97
+ "has_consul_handler": service.has_consul_handler,
98
+ },
99
+ )
100
+ else:
101
+ logger.warning("Registry service not configured - API will return limited data")
102
+
103
+ yield
104
+
105
+ logger.info("Registry API shutting down")
106
+
107
+ # Cleanup Consul handler if we own it
108
+ if service is not None and service.consul_handler is not None:
109
+ try:
110
+ await service.consul_handler.shutdown()
111
+ logger.info("Consul handler shutdown complete")
112
+ except Exception as e:
113
+ logger.exception(
114
+ "Error during Consul handler shutdown",
115
+ extra={"error_type": type(e).__name__},
116
+ )
117
+
118
+
119
+ def create_app(
120
+ projection_reader: ProjectionReaderRegistration | None = None,
121
+ consul_handler: HandlerServiceDiscoveryConsul | None = None,
122
+ widget_mapping_path: Path | None = None,
123
+ cors_origins: list[str] | None = None,
124
+ ) -> FastAPI:
125
+ """Create and configure the Registry API FastAPI application.
126
+
127
+ Factory function that creates a FastAPI app with the specified
128
+ backend configurations. All backends are optional - the API will
129
+ return partial data with warnings when backends are unavailable.
130
+
131
+ Args:
132
+ projection_reader: Optional projection reader for node registrations.
133
+ consul_handler: Optional Consul handler for live instances.
134
+ widget_mapping_path: Optional path to widget mapping YAML.
135
+ cors_origins: Optional list of allowed CORS origins.
136
+ If not provided, reads from CORS_ORIGINS environment variable.
137
+ Raises ProtocolConfigurationError if neither is configured (fail-fast).
138
+
139
+ Returns:
140
+ Configured FastAPI application.
141
+
142
+ Raises:
143
+ ProtocolConfigurationError: If CORS origins not configured via parameter
144
+ or CORS_ORIGINS environment variable.
145
+
146
+ Example:
147
+ >>> from omnibase_infra.services.registry_api import create_app
148
+ >>> app = create_app()
149
+ >>> # Run with: uvicorn module:app --host 0.0.0.0 --port 8000
150
+ """
151
+ app = FastAPI(
152
+ title=API_TITLE,
153
+ description=API_DESCRIPTION,
154
+ version=API_VERSION,
155
+ lifespan=lifespan,
156
+ docs_url="/docs",
157
+ redoc_url="/redoc",
158
+ openapi_url="/openapi.json",
159
+ )
160
+
161
+ # Configure CORS - fail-fast if not configured
162
+ if cors_origins is not None:
163
+ origins = cors_origins
164
+ else:
165
+ env_origins = os.environ.get("CORS_ORIGINS")
166
+ if env_origins is None:
167
+ context = ModelInfraErrorContext.with_correlation(
168
+ transport_type=EnumInfraTransportType.HTTP,
169
+ operation="configure_cors",
170
+ )
171
+ raise ProtocolConfigurationError(
172
+ "CORS_ORIGINS must be configured. "
173
+ "Set the CORS_ORIGINS environment variable (comma-separated list of allowed origins) "
174
+ "or pass cors_origins parameter to create_app(). "
175
+ "Example: CORS_ORIGINS=http://localhost:3000,https://dashboard.example.com",
176
+ context=context,
177
+ )
178
+ origins = env_origins.split(",")
179
+
180
+ # Warn about wildcard CORS - only when explicitly configured
181
+ if "*" in origins:
182
+ logger.warning(
183
+ "CORS explicitly configured with wildcard origin '*'. "
184
+ "This is acceptable for development but should be restricted in production.",
185
+ extra={"origins": origins},
186
+ )
187
+
188
+ app.add_middleware(
189
+ CORSMiddleware,
190
+ allow_origins=origins,
191
+ allow_credentials=True,
192
+ allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
193
+ allow_headers=["*"],
194
+ )
195
+
196
+ # Create and attach service
197
+ service = ServiceRegistryDiscovery(
198
+ projection_reader=projection_reader,
199
+ consul_handler=consul_handler,
200
+ widget_mapping_path=widget_mapping_path,
201
+ )
202
+ app.state.registry_service = service
203
+
204
+ # Include routes
205
+ app.include_router(router)
206
+
207
+ # Root endpoint
208
+ @app.get("/", include_in_schema=False)
209
+ async def root() -> dict[str, str]:
210
+ """Root endpoint with API info."""
211
+ return {
212
+ "service": API_TITLE,
213
+ "version": API_VERSION,
214
+ "docs": "/docs",
215
+ "health": "/registry/health",
216
+ }
217
+
218
+ logger.info(
219
+ "Registry API created",
220
+ extra={
221
+ "version": API_VERSION,
222
+ "cors_origins": origins,
223
+ },
224
+ )
225
+
226
+ return app
227
+
228
+
229
+ # Default app instance for direct uvicorn usage
230
+ # Example: uvicorn omnibase_infra.services.registry_api.main:app --host 0.0.0.0 --port 8000
231
+ # Note: This creates an app with no backends configured. For production,
232
+ # use create_app() directly with proper backend configuration (projection_reader,
233
+ # consul_handler). Tests should also use create_app() for controlled app creation.
234
+ #
235
+ # IMPORTANT: CORS_ORIGINS environment variable MUST be set for module-level app creation.
236
+ # If CORS_ORIGINS is not set, the module can still be imported but `app` will be None.
237
+ # Use create_app(cors_origins=["..."]) directly for programmatic usage.
238
+ app: FastAPI | None = None
239
+ if os.environ.get("CORS_ORIGINS") is not None:
240
+ app = create_app()
241
+
242
+
243
+ __all__ = ["app", "create_app"]
@@ -0,0 +1,66 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Registry API Response Models.
4
+
5
+ Pydantic models for the Registry API HTTP responses. These models define
6
+ the JSON shape returned by each endpoint for dashboard consumption.
7
+
8
+ Design Principles:
9
+ - Flat, dashboard-friendly structures (no deep nesting)
10
+ - Explicit field descriptions for API documentation
11
+ - Immutable (frozen) for thread safety
12
+ - Strict validation (extra="forbid")
13
+
14
+ Related Tickets:
15
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
16
+ """
17
+
18
+ from omnibase_infra.services.registry_api.models.model_capability_widget_mapping import (
19
+ ModelCapabilityWidgetMapping,
20
+ )
21
+ from omnibase_infra.services.registry_api.models.model_pagination_info import (
22
+ ModelPaginationInfo,
23
+ )
24
+ from omnibase_infra.services.registry_api.models.model_registry_discovery_response import (
25
+ ModelRegistryDiscoveryResponse,
26
+ )
27
+ from omnibase_infra.services.registry_api.models.model_registry_health_response import (
28
+ ModelRegistryHealthResponse,
29
+ )
30
+ from omnibase_infra.services.registry_api.models.model_registry_instance_view import (
31
+ ModelRegistryInstanceView,
32
+ )
33
+ from omnibase_infra.services.registry_api.models.model_registry_node_view import (
34
+ ModelRegistryNodeView,
35
+ )
36
+ from omnibase_infra.services.registry_api.models.model_registry_summary import (
37
+ ModelRegistrySummary,
38
+ )
39
+ from omnibase_infra.services.registry_api.models.model_response_list_instances import (
40
+ ModelResponseListInstances,
41
+ )
42
+ from omnibase_infra.services.registry_api.models.model_response_list_nodes import (
43
+ ModelResponseListNodes,
44
+ )
45
+ from omnibase_infra.services.registry_api.models.model_warning import ModelWarning
46
+ from omnibase_infra.services.registry_api.models.model_widget_defaults import (
47
+ ModelWidgetDefaults,
48
+ )
49
+ from omnibase_infra.services.registry_api.models.model_widget_mapping import (
50
+ ModelWidgetMapping,
51
+ )
52
+
53
+ __all__ = [
54
+ "ModelCapabilityWidgetMapping",
55
+ "ModelPaginationInfo",
56
+ "ModelRegistryDiscoveryResponse",
57
+ "ModelRegistryHealthResponse",
58
+ "ModelRegistryInstanceView",
59
+ "ModelRegistryNodeView",
60
+ "ModelRegistrySummary",
61
+ "ModelResponseListInstances",
62
+ "ModelResponseListNodes",
63
+ "ModelWarning",
64
+ "ModelWidgetDefaults",
65
+ "ModelWidgetMapping",
66
+ ]
@@ -0,0 +1,38 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Capability widget mapping model for dashboard configuration.
4
+
5
+ Related Tickets:
6
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from pydantic import BaseModel, ConfigDict, Field
12
+
13
+ from omnibase_infra.services.registry_api.models.model_widget_defaults import (
14
+ ModelWidgetDefaults,
15
+ )
16
+
17
+
18
+ class ModelCapabilityWidgetMapping(BaseModel):
19
+ """Mapping from a capability to its widget configuration.
20
+
21
+ Attributes:
22
+ widget_type: Type of widget to render
23
+ defaults: Default widget configuration
24
+ """
25
+
26
+ model_config = ConfigDict(frozen=True, extra="forbid")
27
+
28
+ widget_type: str = Field(
29
+ ...,
30
+ description="Type of widget to render",
31
+ )
32
+ defaults: ModelWidgetDefaults = Field(
33
+ default_factory=ModelWidgetDefaults,
34
+ description="Default widget configuration",
35
+ )
36
+
37
+
38
+ __all__ = ["ModelCapabilityWidgetMapping"]
@@ -0,0 +1,48 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Pagination info model for list endpoints.
4
+
5
+ Related Tickets:
6
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from pydantic import BaseModel, ConfigDict, Field
12
+
13
+
14
+ class ModelPaginationInfo(BaseModel):
15
+ """Pagination information for list endpoints.
16
+
17
+ Attributes:
18
+ total: Total number of items matching the query
19
+ limit: Maximum items per page
20
+ offset: Current offset (0-based)
21
+ has_more: Whether more items exist beyond current page
22
+ """
23
+
24
+ model_config = ConfigDict(frozen=True, extra="forbid")
25
+
26
+ total: int = Field(
27
+ ...,
28
+ ge=0,
29
+ description="Total number of items",
30
+ )
31
+ limit: int = Field(
32
+ ...,
33
+ ge=1,
34
+ le=1000,
35
+ description="Maximum items per page",
36
+ )
37
+ offset: int = Field(
38
+ ...,
39
+ ge=0,
40
+ description="Current offset (0-based)",
41
+ )
42
+ has_more: bool = Field(
43
+ ...,
44
+ description="Whether more items exist",
45
+ )
46
+
47
+
48
+ __all__ = ["ModelPaginationInfo"]
@@ -0,0 +1,73 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Registry discovery response model for dashboard payload.
4
+
5
+ Related Tickets:
6
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from datetime import datetime
12
+
13
+ from pydantic import BaseModel, ConfigDict, Field
14
+
15
+ from omnibase_infra.services.registry_api.models.model_pagination_info import (
16
+ ModelPaginationInfo,
17
+ )
18
+ from omnibase_infra.services.registry_api.models.model_registry_instance_view import (
19
+ ModelRegistryInstanceView,
20
+ )
21
+ from omnibase_infra.services.registry_api.models.model_registry_node_view import (
22
+ ModelRegistryNodeView,
23
+ )
24
+ from omnibase_infra.services.registry_api.models.model_registry_summary import (
25
+ ModelRegistrySummary,
26
+ )
27
+ from omnibase_infra.services.registry_api.models.model_warning import ModelWarning
28
+
29
+
30
+ class ModelRegistryDiscoveryResponse(BaseModel):
31
+ """Full dashboard payload combining nodes, instances, and summary.
32
+
33
+ The primary response model for the GET /registry/discovery endpoint,
34
+ providing everything a dashboard needs in a single request.
35
+
36
+ Attributes:
37
+ timestamp: When this response was generated
38
+ warnings: List of warnings for partial success scenarios
39
+ summary: Aggregate statistics
40
+ nodes: List of registered nodes
41
+ live_instances: List of live Consul instances
42
+ pagination: Pagination info for nodes list
43
+ """
44
+
45
+ model_config = ConfigDict(frozen=True, extra="forbid")
46
+
47
+ timestamp: datetime = Field(
48
+ ...,
49
+ description="When this response was generated",
50
+ )
51
+ warnings: list[ModelWarning] = Field(
52
+ default_factory=list,
53
+ description="Warnings for partial success scenarios",
54
+ )
55
+ summary: ModelRegistrySummary = Field(
56
+ ...,
57
+ description="Aggregate statistics",
58
+ )
59
+ nodes: list[ModelRegistryNodeView] = Field(
60
+ default_factory=list,
61
+ description="List of registered nodes",
62
+ )
63
+ live_instances: list[ModelRegistryInstanceView] = Field(
64
+ default_factory=list,
65
+ description="List of live Consul instances",
66
+ )
67
+ pagination: ModelPaginationInfo = Field(
68
+ ...,
69
+ description="Pagination info for nodes list",
70
+ )
71
+
72
+
73
+ __all__ = ["ModelRegistryDiscoveryResponse"]
@@ -0,0 +1,49 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Registry health response model for API health checks.
4
+
5
+ Related Tickets:
6
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from datetime import datetime
12
+ from typing import Literal
13
+
14
+ from pydantic import BaseModel, ConfigDict, Field
15
+
16
+ from omnibase_core.types import JsonType
17
+
18
+
19
+ class ModelRegistryHealthResponse(BaseModel):
20
+ """Health check response for the registry API.
21
+
22
+ Attributes:
23
+ status: Overall health status (healthy, degraded, unhealthy)
24
+ timestamp: When the health check was performed
25
+ components: Health status of individual components
26
+ version: API version string
27
+ """
28
+
29
+ model_config = ConfigDict(frozen=True, extra="forbid")
30
+
31
+ status: Literal["healthy", "degraded", "unhealthy"] = Field(
32
+ ...,
33
+ description="Overall health status",
34
+ )
35
+ timestamp: datetime = Field(
36
+ ...,
37
+ description="When the health check was performed",
38
+ )
39
+ components: dict[str, JsonType] = Field(
40
+ default_factory=dict,
41
+ description="Health status of individual components",
42
+ )
43
+ version: str = Field(
44
+ default="1.0.0",
45
+ description="API version string",
46
+ )
47
+
48
+
49
+ __all__ = ["ModelRegistryHealthResponse"]
@@ -0,0 +1,88 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Registry instance view model for dashboard display.
4
+
5
+ Related Tickets:
6
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from datetime import datetime
12
+ from typing import Literal
13
+ from uuid import UUID
14
+
15
+ from pydantic import BaseModel, ConfigDict, Field
16
+
17
+
18
+ class ModelRegistryInstanceView(BaseModel):
19
+ """Live service instance view for dashboard display.
20
+
21
+ Represents a live Consul service instance, providing real-time
22
+ health and connectivity information.
23
+
24
+ Attributes:
25
+ node_id: Node UUID (may be derived from service_id if not UUID)
26
+ service_name: Consul service name
27
+ service_id: Consul service instance ID
28
+ instance_id: Unique instance identifier (same as service_id)
29
+ address: Network address (IP or hostname)
30
+ port: Service port number
31
+ health_status: Health check status (passing, warning, critical, unknown)
32
+ health_output: Health check output message (nullable)
33
+ last_check_at: Timestamp of last health check (nullable)
34
+ tags: Consul service tags
35
+ meta: Consul service metadata
36
+ """
37
+
38
+ model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
39
+
40
+ node_id: UUID = Field(
41
+ ...,
42
+ description="Node UUID (may be derived from service_id)",
43
+ )
44
+ service_name: str = Field( # ONEX_EXCLUDE: pattern - Consul discovery identifier
45
+ ...,
46
+ description="Consul service name (external Consul identifier, not entity reference)",
47
+ )
48
+ service_id: UUID = Field(
49
+ ...,
50
+ description="Consul service instance ID",
51
+ )
52
+ instance_id: UUID = Field(
53
+ ...,
54
+ description="Unique instance identifier",
55
+ )
56
+ address: str = Field(
57
+ ...,
58
+ description="Network address (IP or hostname)",
59
+ )
60
+ port: int = Field(
61
+ ...,
62
+ ge=1,
63
+ le=65535,
64
+ description="Service port number",
65
+ )
66
+ health_status: Literal["passing", "warning", "critical", "unknown"] = Field(
67
+ ...,
68
+ description="Health check status",
69
+ )
70
+ health_output: str | None = Field(
71
+ default=None,
72
+ description="Health check output message",
73
+ )
74
+ last_check_at: datetime | None = Field(
75
+ default=None,
76
+ description="Timestamp of last health check",
77
+ )
78
+ tags: list[str] = Field(
79
+ default_factory=list,
80
+ description="Consul service tags",
81
+ )
82
+ meta: dict[str, str] = Field(
83
+ default_factory=dict,
84
+ description="Consul service metadata",
85
+ )
86
+
87
+
88
+ __all__ = ["ModelRegistryInstanceView"]
@@ -0,0 +1,88 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Registry node view model for dashboard display.
4
+
5
+ Related Tickets:
6
+ - OMN-1278: Contract-Driven Dashboard - Registry Discovery
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from datetime import datetime
12
+ from typing import Literal
13
+ from uuid import UUID
14
+
15
+ from pydantic import BaseModel, ConfigDict, Field
16
+
17
+ from omnibase_core.models.primitives.model_semver import ModelSemVer
18
+
19
+
20
+ class ModelRegistryNodeView(BaseModel):
21
+ """Node view for dashboard display.
22
+
23
+ Represents a registered ONEX node from the registration projection,
24
+ flattened for dashboard consumption.
25
+
26
+ Attributes:
27
+ node_id: Unique identifier (entity_id from projection)
28
+ name: Human-readable node name (from service_name or node_type)
29
+ service_name: Consul service name for discovery
30
+ namespace: Optional namespace for multi-tenant deployments
31
+ display_name: Optional human-friendly display name
32
+ node_type: ONEX node archetype (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR)
33
+ version: Semantic version (ModelSemVer instance)
34
+ state: Current FSM registration state
35
+ capabilities: List of capability tags
36
+ registered_at: Timestamp of initial registration
37
+ last_heartbeat_at: Timestamp of last heartbeat (nullable)
38
+ """
39
+
40
+ model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
41
+
42
+ node_id: UUID = Field(
43
+ ...,
44
+ description="Unique node identifier",
45
+ )
46
+ name: str = Field(
47
+ ...,
48
+ description="Node name (service_name or derived from node_type)",
49
+ )
50
+ service_name: str = Field( # ONEX_EXCLUDE: pattern - Consul discovery identifier
51
+ ...,
52
+ description="Consul service name (external Consul identifier, not entity reference)",
53
+ )
54
+ namespace: str | None = Field(
55
+ default=None,
56
+ description="Optional namespace for multi-tenant deployments",
57
+ )
58
+ display_name: str | None = Field(
59
+ default=None,
60
+ description="Optional human-friendly display name",
61
+ )
62
+ node_type: Literal["EFFECT", "COMPUTE", "REDUCER", "ORCHESTRATOR"] = Field(
63
+ ...,
64
+ description="ONEX node archetype",
65
+ )
66
+ version: ModelSemVer = Field(
67
+ ...,
68
+ description="Semantic version (ONEX standard)",
69
+ )
70
+ state: str = Field(
71
+ ...,
72
+ description="Current FSM registration state",
73
+ )
74
+ capabilities: list[str] = Field(
75
+ default_factory=list,
76
+ description="List of capability tags",
77
+ )
78
+ registered_at: datetime = Field(
79
+ ...,
80
+ description="Timestamp of initial registration",
81
+ )
82
+ last_heartbeat_at: datetime | None = Field(
83
+ default=None,
84
+ description="Timestamp of last heartbeat",
85
+ )
86
+
87
+
88
+ __all__ = ["ModelRegistryNodeView"]