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
|
@@ -131,10 +131,10 @@ class ServiceCapabilityQuery(MixinAsyncCircuitBreaker):
|
|
|
131
131
|
Dependency Injection Pattern: This service is a leaf infrastructure
|
|
132
132
|
service that receives its dependencies directly via constructor
|
|
133
133
|
parameters rather than resolving them from a container. Unlike
|
|
134
|
-
orchestrators that use ``container.
|
|
135
|
-
dynamically, leaf services like this one are
|
|
136
|
-
concrete dependencies (projection_reader, node_selector)
|
|
137
|
-
themselves resolved by higher-level components.
|
|
134
|
+
orchestrators that use ``container.service_registry.resolve_service()``
|
|
135
|
+
to obtain services dynamically, leaf services like this one are
|
|
136
|
+
instantiated with concrete dependencies (projection_reader, node_selector)
|
|
137
|
+
and are themselves resolved by higher-level components.
|
|
138
138
|
"""
|
|
139
139
|
|
|
140
140
|
def __init__(
|
|
@@ -57,10 +57,11 @@ See Also:
|
|
|
57
57
|
from __future__ import annotations
|
|
58
58
|
|
|
59
59
|
import logging
|
|
60
|
-
from typing import TYPE_CHECKING, Literal
|
|
60
|
+
from typing import TYPE_CHECKING, Literal, cast
|
|
61
61
|
|
|
62
62
|
from aiohttp import web
|
|
63
63
|
|
|
64
|
+
from omnibase_core.types import JsonType
|
|
64
65
|
from omnibase_infra.enums import EnumInfraTransportType
|
|
65
66
|
from omnibase_infra.errors import (
|
|
66
67
|
ModelInfraErrorContext,
|
|
@@ -859,7 +860,7 @@ class ServiceHealth:
|
|
|
859
860
|
response = ModelHealthCheckResponse.success(
|
|
860
861
|
status=status,
|
|
861
862
|
version=self._version,
|
|
862
|
-
details=health_details,
|
|
863
|
+
details=cast("dict[str, JsonType]", health_details),
|
|
863
864
|
)
|
|
864
865
|
|
|
865
866
|
return web.Response(
|
|
@@ -36,6 +36,8 @@ from uuid import UUID
|
|
|
36
36
|
|
|
37
37
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
38
38
|
|
|
39
|
+
from omnibase_core.container import ModelONEXContainer
|
|
40
|
+
from omnibase_core.models.events.model_event_envelope import ModelEventEnvelope
|
|
39
41
|
from omnibase_infra.enums import EnumInfraTransportType
|
|
40
42
|
from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationError
|
|
41
43
|
from omnibase_infra.models.projection import ModelRegistrationProjection
|
|
@@ -216,6 +218,7 @@ class ServiceTimeoutEmitter:
|
|
|
216
218
|
|
|
217
219
|
Usage:
|
|
218
220
|
>>> emitter = ServiceTimeoutEmitter(
|
|
221
|
+
... container=container,
|
|
219
222
|
... timeout_query=timeout_scanner,
|
|
220
223
|
... event_bus=event_bus,
|
|
221
224
|
... projector=projector,
|
|
@@ -261,6 +264,7 @@ class ServiceTimeoutEmitter:
|
|
|
261
264
|
|
|
262
265
|
def __init__(
|
|
263
266
|
self,
|
|
267
|
+
container: ModelONEXContainer,
|
|
264
268
|
timeout_query: ServiceTimeoutScanner,
|
|
265
269
|
event_bus: ProtocolEventBus,
|
|
266
270
|
projector: ProjectorShell,
|
|
@@ -269,6 +273,7 @@ class ServiceTimeoutEmitter:
|
|
|
269
273
|
"""Initialize with required dependencies.
|
|
270
274
|
|
|
271
275
|
Args:
|
|
276
|
+
container: ONEX container for dependency injection.
|
|
272
277
|
timeout_query: Scanner for querying overdue entities.
|
|
273
278
|
Must be initialized with a ProjectionReaderRegistration.
|
|
274
279
|
event_bus: Event bus for publishing timeout events.
|
|
@@ -280,16 +285,18 @@ class ServiceTimeoutEmitter:
|
|
|
280
285
|
|
|
281
286
|
Example:
|
|
282
287
|
>>> reader = ProjectionReaderRegistration(pool)
|
|
283
|
-
>>> timeout_query = ServiceTimeoutScanner(reader)
|
|
288
|
+
>>> timeout_query = ServiceTimeoutScanner(container, reader)
|
|
284
289
|
>>> bus = EventBusKafka.default()
|
|
285
290
|
>>> projector = projector_loader.load("registration_projector")
|
|
286
291
|
>>> emitter = ServiceTimeoutEmitter(
|
|
292
|
+
... container=container,
|
|
287
293
|
... timeout_query=timeout_query,
|
|
288
294
|
... event_bus=bus,
|
|
289
295
|
... projector=projector,
|
|
290
296
|
... config=ModelTimeoutEmissionConfig(environment="dev"),
|
|
291
297
|
... )
|
|
292
298
|
"""
|
|
299
|
+
self._container = container
|
|
293
300
|
self._timeout_query = timeout_query
|
|
294
301
|
self._event_bus = event_bus
|
|
295
302
|
self._projector = projector
|
|
@@ -568,8 +575,13 @@ class ServiceTimeoutEmitter:
|
|
|
568
575
|
},
|
|
569
576
|
)
|
|
570
577
|
|
|
578
|
+
# Wrap event in ModelEventEnvelope for protocol compliance
|
|
579
|
+
envelope: ModelEventEnvelope[object] = ModelEventEnvelope(
|
|
580
|
+
payload=event,
|
|
581
|
+
correlation_id=correlation_id,
|
|
582
|
+
)
|
|
571
583
|
await self._event_bus.publish_envelope(
|
|
572
|
-
envelope=
|
|
584
|
+
envelope=envelope, # type: ignore[arg-type]
|
|
573
585
|
topic=topic,
|
|
574
586
|
)
|
|
575
587
|
|
|
@@ -657,8 +669,13 @@ class ServiceTimeoutEmitter:
|
|
|
657
669
|
},
|
|
658
670
|
)
|
|
659
671
|
|
|
672
|
+
# Wrap event in ModelEventEnvelope for protocol compliance
|
|
673
|
+
envelope: ModelEventEnvelope[object] = ModelEventEnvelope(
|
|
674
|
+
payload=event,
|
|
675
|
+
correlation_id=correlation_id,
|
|
676
|
+
)
|
|
660
677
|
await self._event_bus.publish_envelope(
|
|
661
|
-
envelope=
|
|
678
|
+
envelope=envelope, # type: ignore[arg-type]
|
|
662
679
|
topic=topic,
|
|
663
680
|
)
|
|
664
681
|
|
|
@@ -31,6 +31,7 @@ from uuid import UUID, uuid4
|
|
|
31
31
|
|
|
32
32
|
from pydantic import BaseModel, ConfigDict, Field
|
|
33
33
|
|
|
34
|
+
from omnibase_core.container import ModelONEXContainer
|
|
34
35
|
from omnibase_infra.models.projection import ModelRegistrationProjection
|
|
35
36
|
from omnibase_infra.projectors.projection_reader_registration import (
|
|
36
37
|
ProjectionReaderRegistration,
|
|
@@ -126,7 +127,7 @@ class ServiceTimeoutScanner:
|
|
|
126
127
|
|
|
127
128
|
Usage:
|
|
128
129
|
>>> reader = ProjectionReaderRegistration(pool)
|
|
129
|
-
>>> scanner = ServiceTimeoutScanner(reader)
|
|
130
|
+
>>> scanner = ServiceTimeoutScanner(container, reader)
|
|
130
131
|
>>> result = await scanner.find_overdue_entities(now=tick.now)
|
|
131
132
|
>>>
|
|
132
133
|
>>> for projection in result.ack_timeouts:
|
|
@@ -152,12 +153,14 @@ class ServiceTimeoutScanner:
|
|
|
152
153
|
|
|
153
154
|
def __init__(
|
|
154
155
|
self,
|
|
156
|
+
container: ModelONEXContainer,
|
|
155
157
|
projection_reader: ProjectionReaderRegistration,
|
|
156
158
|
batch_size: int | None = None,
|
|
157
159
|
) -> None:
|
|
158
|
-
"""Initialize
|
|
160
|
+
"""Initialize the timeout scanner service.
|
|
159
161
|
|
|
160
162
|
Args:
|
|
163
|
+
container: ONEX container for dependency injection.
|
|
161
164
|
projection_reader: The projection reader for database queries.
|
|
162
165
|
Must be initialized with an asyncpg connection pool.
|
|
163
166
|
batch_size: Maximum entities to return per query type.
|
|
@@ -166,8 +169,9 @@ class ServiceTimeoutScanner:
|
|
|
166
169
|
Example:
|
|
167
170
|
>>> pool = await asyncpg.create_pool(dsn)
|
|
168
171
|
>>> reader = ProjectionReaderRegistration(pool)
|
|
169
|
-
>>> scanner = ServiceTimeoutScanner(reader)
|
|
172
|
+
>>> scanner = ServiceTimeoutScanner(container, reader)
|
|
170
173
|
"""
|
|
174
|
+
self._container = container
|
|
171
175
|
self._reader = projection_reader
|
|
172
176
|
self._batch_size = batch_size or self.DEFAULT_BATCH_SIZE
|
|
173
177
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Session storage and event consumer services.
|
|
4
|
+
|
|
5
|
+
This module provides infrastructure for persisting Claude Code session
|
|
6
|
+
snapshots and consuming session events from Kafka.
|
|
7
|
+
|
|
8
|
+
Moved from omniclaude as part of OMN-1526 architectural cleanup.
|
|
9
|
+
|
|
10
|
+
Components:
|
|
11
|
+
- SessionSnapshotStore: PostgreSQL storage for session snapshots
|
|
12
|
+
- SessionEventConsumer: Kafka consumer for session events
|
|
13
|
+
- ConfigSessionStorage: Storage configuration
|
|
14
|
+
- ConfigSessionConsumer: Consumer configuration
|
|
15
|
+
- ConsumerMetrics: Metrics for consumer observability
|
|
16
|
+
- EnumCircuitState: Circuit breaker states
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
>>> from omnibase_infra.services.session import (
|
|
20
|
+
... SessionSnapshotStore,
|
|
21
|
+
... ConfigSessionStorage,
|
|
22
|
+
... )
|
|
23
|
+
>>> from pydantic import SecretStr
|
|
24
|
+
>>>
|
|
25
|
+
>>> config = ConfigSessionStorage(postgres_password=SecretStr("secret"))
|
|
26
|
+
>>> store = SessionSnapshotStore(config)
|
|
27
|
+
>>> await store.initialize()
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from omnibase_infra.services.session.config_consumer import ConfigSessionConsumer
|
|
31
|
+
from omnibase_infra.services.session.config_store import ConfigSessionStorage
|
|
32
|
+
from omnibase_infra.services.session.consumer import (
|
|
33
|
+
ConsumerMetrics,
|
|
34
|
+
EnumCircuitState,
|
|
35
|
+
SessionEventConsumer,
|
|
36
|
+
)
|
|
37
|
+
from omnibase_infra.services.session.protocol_session_aggregator import (
|
|
38
|
+
ProtocolSessionAggregator,
|
|
39
|
+
)
|
|
40
|
+
from omnibase_infra.services.session.store import (
|
|
41
|
+
SessionSnapshotStore,
|
|
42
|
+
SessionStoreNotInitializedError,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
# Storage
|
|
47
|
+
"SessionSnapshotStore",
|
|
48
|
+
"SessionStoreNotInitializedError",
|
|
49
|
+
"ConfigSessionStorage",
|
|
50
|
+
# Consumer
|
|
51
|
+
"SessionEventConsumer",
|
|
52
|
+
"ConfigSessionConsumer",
|
|
53
|
+
"ConsumerMetrics",
|
|
54
|
+
"EnumCircuitState",
|
|
55
|
+
"ProtocolSessionAggregator",
|
|
56
|
+
]
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""Configuration for session event consumers.
|
|
2
|
+
|
|
3
|
+
Loads from environment variables with OMNIBASE_INFRA_SESSION_CONSUMER_ prefix.
|
|
4
|
+
|
|
5
|
+
Moved from omniclaude as part of OMN-1526 architectural cleanup.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
from pydantic import Field, model_validator
|
|
13
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ConfigSessionConsumer(BaseSettings):
|
|
19
|
+
"""Configuration for the Claude session event Kafka consumer.
|
|
20
|
+
|
|
21
|
+
Environment variables use the OMNIBASE_INFRA_SESSION_CONSUMER_ prefix.
|
|
22
|
+
Example: OMNIBASE_INFRA_SESSION_CONSUMER_BOOTSTRAP_SERVERS=kafka.example.com:9092
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
model_config = SettingsConfigDict(
|
|
26
|
+
env_prefix="OMNIBASE_INFRA_SESSION_CONSUMER_",
|
|
27
|
+
env_file=".env",
|
|
28
|
+
env_file_encoding="utf-8",
|
|
29
|
+
case_sensitive=False,
|
|
30
|
+
extra="ignore",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Kafka connection
|
|
34
|
+
bootstrap_servers: str = Field(
|
|
35
|
+
default="localhost:9092",
|
|
36
|
+
description="Kafka bootstrap servers. Set via OMNIBASE_INFRA_SESSION_CONSUMER_BOOTSTRAP_SERVERS env var for production.",
|
|
37
|
+
)
|
|
38
|
+
group_id: str = Field(
|
|
39
|
+
default="omnibase-infra-session-consumer",
|
|
40
|
+
description="Consumer group ID",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Topics to subscribe
|
|
44
|
+
topics: list[str] = Field(
|
|
45
|
+
default=[
|
|
46
|
+
"dev.omniclaude.session.started.v1",
|
|
47
|
+
"dev.omniclaude.session.ended.v1",
|
|
48
|
+
"dev.omniclaude.prompt.submitted.v1",
|
|
49
|
+
"dev.omniclaude.tool.executed.v1",
|
|
50
|
+
],
|
|
51
|
+
description="Kafka topics to consume",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Consumer behavior
|
|
55
|
+
auto_offset_reset: str = Field(
|
|
56
|
+
default="earliest",
|
|
57
|
+
description="Where to start consuming if no offset exists",
|
|
58
|
+
)
|
|
59
|
+
enable_auto_commit: bool = Field(
|
|
60
|
+
default=False,
|
|
61
|
+
description="Disable auto-commit for at-least-once delivery",
|
|
62
|
+
)
|
|
63
|
+
max_poll_records: int = Field(
|
|
64
|
+
default=100,
|
|
65
|
+
ge=1,
|
|
66
|
+
le=10000,
|
|
67
|
+
description="Maximum records per poll",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Processing
|
|
71
|
+
batch_timeout_ms: int = Field(
|
|
72
|
+
default=5000,
|
|
73
|
+
ge=100,
|
|
74
|
+
le=60000,
|
|
75
|
+
description="Timeout for batch processing in milliseconds",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Circuit breaker
|
|
79
|
+
circuit_breaker_threshold: int = Field(
|
|
80
|
+
default=5,
|
|
81
|
+
ge=1,
|
|
82
|
+
le=100,
|
|
83
|
+
description="Failures before circuit opens",
|
|
84
|
+
)
|
|
85
|
+
circuit_breaker_timeout_seconds: int = Field(
|
|
86
|
+
default=60,
|
|
87
|
+
ge=1,
|
|
88
|
+
le=3600,
|
|
89
|
+
description="Time before circuit half-opens",
|
|
90
|
+
)
|
|
91
|
+
circuit_breaker_half_open_successes: int = Field(
|
|
92
|
+
default=1,
|
|
93
|
+
ge=1,
|
|
94
|
+
le=10,
|
|
95
|
+
description="Number of successful requests required to close circuit from half-open state",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
@model_validator(mode="after")
|
|
99
|
+
def validate_timing_relationships(self) -> ConfigSessionConsumer:
|
|
100
|
+
"""Validate timing relationships between configuration values.
|
|
101
|
+
|
|
102
|
+
Warns if circuit breaker timeout is very short relative to batch processing,
|
|
103
|
+
which could cause premature circuit opens during normal batch operations.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Self if validation passes.
|
|
107
|
+
"""
|
|
108
|
+
batch_timeout_seconds = self.batch_timeout_ms / 1000
|
|
109
|
+
min_recommended_circuit_timeout = batch_timeout_seconds * 2
|
|
110
|
+
|
|
111
|
+
if self.circuit_breaker_timeout_seconds < min_recommended_circuit_timeout:
|
|
112
|
+
logger.warning(
|
|
113
|
+
"Circuit breaker timeout (%ds) is less than 2x batch timeout (%.1fs). "
|
|
114
|
+
"This may cause premature circuit opens during normal batch processing. "
|
|
115
|
+
"Recommended minimum: %ds",
|
|
116
|
+
self.circuit_breaker_timeout_seconds,
|
|
117
|
+
batch_timeout_seconds,
|
|
118
|
+
int(min_recommended_circuit_timeout),
|
|
119
|
+
)
|
|
120
|
+
return self
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Configuration for session snapshot storage.
|
|
2
|
+
|
|
3
|
+
Loads from environment variables with OMNIBASE_INFRA_SESSION_STORAGE_ prefix.
|
|
4
|
+
|
|
5
|
+
Moved from omniclaude as part of OMN-1526 architectural cleanup.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pydantic import Field, SecretStr, model_validator
|
|
11
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ConfigSessionStorage(BaseSettings):
|
|
15
|
+
"""Configuration for session snapshot PostgreSQL storage.
|
|
16
|
+
|
|
17
|
+
Environment variables use the OMNIBASE_INFRA_SESSION_STORAGE_ prefix.
|
|
18
|
+
Example: OMNIBASE_INFRA_SESSION_STORAGE_POSTGRES_HOST=192.168.86.200
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
model_config = SettingsConfigDict(
|
|
22
|
+
env_prefix="OMNIBASE_INFRA_SESSION_STORAGE_",
|
|
23
|
+
env_file=".env",
|
|
24
|
+
env_file_encoding="utf-8",
|
|
25
|
+
case_sensitive=False,
|
|
26
|
+
extra="ignore",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# PostgreSQL connection
|
|
30
|
+
postgres_host: str = Field(
|
|
31
|
+
default="192.168.86.200",
|
|
32
|
+
description="PostgreSQL host",
|
|
33
|
+
)
|
|
34
|
+
postgres_port: int = Field(
|
|
35
|
+
default=5436,
|
|
36
|
+
ge=1,
|
|
37
|
+
le=65535,
|
|
38
|
+
description="PostgreSQL port",
|
|
39
|
+
)
|
|
40
|
+
postgres_database: str = Field(
|
|
41
|
+
default="omninode_bridge",
|
|
42
|
+
description="PostgreSQL database name",
|
|
43
|
+
)
|
|
44
|
+
postgres_user: str = Field(
|
|
45
|
+
default="postgres",
|
|
46
|
+
description="PostgreSQL user",
|
|
47
|
+
)
|
|
48
|
+
postgres_password: SecretStr = Field(
|
|
49
|
+
..., # Required
|
|
50
|
+
description="PostgreSQL password - set via OMNIBASE_INFRA_SESSION_STORAGE_POSTGRES_PASSWORD env var",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Connection pool
|
|
54
|
+
pool_min_size: int = Field(
|
|
55
|
+
default=2,
|
|
56
|
+
ge=1,
|
|
57
|
+
le=100,
|
|
58
|
+
description="Minimum connection pool size",
|
|
59
|
+
)
|
|
60
|
+
pool_max_size: int = Field(
|
|
61
|
+
default=10,
|
|
62
|
+
ge=1,
|
|
63
|
+
le=100,
|
|
64
|
+
description="Maximum connection pool size",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Query timeouts
|
|
68
|
+
query_timeout_seconds: int = Field(
|
|
69
|
+
default=30,
|
|
70
|
+
ge=1,
|
|
71
|
+
le=300,
|
|
72
|
+
description="Query timeout in seconds",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@model_validator(mode="after")
|
|
76
|
+
def validate_pool_sizes(self) -> ConfigSessionStorage:
|
|
77
|
+
"""Validate that pool_min_size <= pool_max_size.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Self if validation passes.
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
ValueError: If pool_min_size > pool_max_size.
|
|
84
|
+
"""
|
|
85
|
+
if self.pool_min_size > self.pool_max_size:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
f"pool_min_size ({self.pool_min_size}) must be <= "
|
|
88
|
+
f"pool_max_size ({self.pool_max_size})"
|
|
89
|
+
)
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def dsn(self) -> str:
|
|
94
|
+
"""Build PostgreSQL DSN from components.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
PostgreSQL connection string.
|
|
98
|
+
"""
|
|
99
|
+
password = self.postgres_password.get_secret_value()
|
|
100
|
+
return (
|
|
101
|
+
f"postgresql://{self.postgres_user}:{password}"
|
|
102
|
+
f"@{self.postgres_host}:{self.postgres_port}"
|
|
103
|
+
f"/{self.postgres_database}"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def dsn_async(self) -> str:
|
|
108
|
+
"""Build async PostgreSQL DSN for asyncpg.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
PostgreSQL connection string with postgresql+asyncpg scheme.
|
|
112
|
+
"""
|
|
113
|
+
password = self.postgres_password.get_secret_value()
|
|
114
|
+
return (
|
|
115
|
+
f"postgresql+asyncpg://{self.postgres_user}:{password}"
|
|
116
|
+
f"@{self.postgres_host}:{self.postgres_port}"
|
|
117
|
+
f"/{self.postgres_database}"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def dsn_safe(self) -> str:
|
|
122
|
+
"""Build PostgreSQL DSN with password masked (safe for logging).
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
PostgreSQL connection string with password replaced by ***.
|
|
126
|
+
"""
|
|
127
|
+
return (
|
|
128
|
+
f"postgresql://{self.postgres_user}:***"
|
|
129
|
+
f"@{self.postgres_host}:{self.postgres_port}"
|
|
130
|
+
f"/{self.postgres_database}"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def __repr__(self) -> str:
|
|
134
|
+
"""Safe string representation that doesn't expose credentials.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
String representation with masked password.
|
|
138
|
+
"""
|
|
139
|
+
return f"ConfigSessionStorage(dsn={self.dsn_safe!r})"
|