omnibase_infra 0.2.5__py3-none-any.whl → 0.2.7__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/constants_topic_patterns.py +26 -0
- omnibase_infra/enums/__init__.py +3 -0
- omnibase_infra/enums/enum_consumer_group_purpose.py +92 -0
- omnibase_infra/enums/enum_handler_source_mode.py +16 -2
- omnibase_infra/errors/__init__.py +4 -0
- omnibase_infra/errors/error_binding_resolution.py +128 -0
- omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +0 -2
- omnibase_infra/event_bus/event_bus_inmemory.py +64 -10
- omnibase_infra/event_bus/event_bus_kafka.py +105 -47
- omnibase_infra/event_bus/mixin_kafka_broadcast.py +3 -7
- omnibase_infra/event_bus/mixin_kafka_dlq.py +12 -6
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +0 -81
- omnibase_infra/event_bus/testing/__init__.py +26 -0
- omnibase_infra/event_bus/testing/adapter_protocol_event_publisher_inmemory.py +418 -0
- omnibase_infra/event_bus/testing/model_publisher_metrics.py +64 -0
- omnibase_infra/handlers/handler_consul.py +2 -0
- omnibase_infra/handlers/mixins/__init__.py +5 -0
- omnibase_infra/handlers/mixins/mixin_consul_service.py +274 -10
- omnibase_infra/handlers/mixins/mixin_consul_topic_index.py +585 -0
- omnibase_infra/handlers/models/model_filesystem_config.py +4 -4
- omnibase_infra/migrations/001_create_event_ledger.sql +166 -0
- omnibase_infra/migrations/001_drop_event_ledger.sql +18 -0
- omnibase_infra/mixins/mixin_node_introspection.py +189 -19
- omnibase_infra/models/__init__.py +8 -0
- omnibase_infra/models/bindings/__init__.py +59 -0
- omnibase_infra/models/bindings/constants.py +144 -0
- omnibase_infra/models/bindings/model_binding_resolution_result.py +103 -0
- omnibase_infra/models/bindings/model_operation_binding.py +44 -0
- omnibase_infra/models/bindings/model_operation_bindings_subcontract.py +152 -0
- omnibase_infra/models/bindings/model_parsed_binding.py +52 -0
- omnibase_infra/models/discovery/model_introspection_config.py +25 -17
- omnibase_infra/models/dispatch/__init__.py +8 -0
- omnibase_infra/models/dispatch/model_debug_trace_snapshot.py +114 -0
- omnibase_infra/models/dispatch/model_materialized_dispatch.py +141 -0
- omnibase_infra/models/handlers/model_handler_source_config.py +1 -1
- omnibase_infra/models/model_node_identity.py +126 -0
- omnibase_infra/models/projection/model_snapshot_topic_config.py +3 -2
- omnibase_infra/models/registration/__init__.py +9 -0
- omnibase_infra/models/registration/model_event_bus_topic_entry.py +59 -0
- omnibase_infra/models/registration/model_node_event_bus_config.py +99 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +11 -0
- omnibase_infra/models/runtime/__init__.py +9 -0
- omnibase_infra/models/validation/model_coverage_metrics.py +2 -2
- omnibase_infra/nodes/__init__.py +9 -0
- omnibase_infra/nodes/contract_registry_reducer/__init__.py +29 -0
- omnibase_infra/nodes/contract_registry_reducer/contract.yaml +255 -0
- omnibase_infra/nodes/contract_registry_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_contract_registry_state.py +266 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_cleanup_topic_references.py +55 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_deactivate_contract.py +58 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_mark_stale.py +49 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_heartbeat.py +71 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_topic.py +66 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_upsert_contract.py +92 -0
- omnibase_infra/nodes/contract_registry_reducer/node.py +121 -0
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +784 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/registry_infra_contract_registry_reducer.py +101 -0
- omnibase_infra/nodes/handlers/consul/contract.yaml +85 -0
- omnibase_infra/nodes/handlers/db/contract.yaml +72 -0
- omnibase_infra/nodes/handlers/graph/contract.yaml +127 -0
- omnibase_infra/nodes/handlers/http/contract.yaml +74 -0
- omnibase_infra/nodes/handlers/intent/contract.yaml +66 -0
- omnibase_infra/nodes/handlers/mcp/contract.yaml +69 -0
- omnibase_infra/nodes/handlers/vault/contract.yaml +91 -0
- omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +50 -0
- omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +104 -0
- omnibase_infra/nodes/node_ledger_projection_compute/node.py +284 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/__init__.py +29 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/registry_infra_ledger_projection.py +118 -0
- omnibase_infra/nodes/node_ledger_write_effect/__init__.py +82 -0
- omnibase_infra/nodes/node_ledger_write_effect/contract.yaml +200 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/__init__.py +22 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_append.py +372 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_query.py +597 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/__init__.py +31 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_append_result.py +54 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_entry.py +92 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query.py +53 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query_result.py +41 -0
- omnibase_infra/nodes/node_ledger_write_effect/node.py +89 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/__init__.py +13 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/protocol_ledger_persistence.py +127 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/registry_infra_ledger_write.py +121 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +7 -5
- omnibase_infra/nodes/reducers/models/__init__.py +7 -2
- omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +11 -0
- omnibase_infra/nodes/reducers/models/model_payload_ledger_append.py +133 -0
- omnibase_infra/nodes/reducers/registration_reducer.py +1 -0
- omnibase_infra/protocols/__init__.py +3 -0
- omnibase_infra/protocols/protocol_dispatch_engine.py +152 -0
- omnibase_infra/runtime/__init__.py +60 -0
- omnibase_infra/runtime/binding_resolver.py +753 -0
- omnibase_infra/runtime/constants_security.py +70 -0
- omnibase_infra/runtime/contract_loaders/__init__.py +9 -0
- omnibase_infra/runtime/contract_loaders/operation_bindings_loader.py +789 -0
- omnibase_infra/runtime/emit_daemon/__init__.py +97 -0
- omnibase_infra/runtime/emit_daemon/cli.py +844 -0
- omnibase_infra/runtime/emit_daemon/client.py +811 -0
- omnibase_infra/runtime/emit_daemon/config.py +535 -0
- omnibase_infra/runtime/emit_daemon/daemon.py +812 -0
- omnibase_infra/runtime/emit_daemon/event_registry.py +477 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_request.py +139 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_response.py +191 -0
- omnibase_infra/runtime/emit_daemon/queue.py +618 -0
- omnibase_infra/runtime/event_bus_subcontract_wiring.py +466 -0
- omnibase_infra/runtime/handler_source_resolver.py +43 -2
- omnibase_infra/runtime/kafka_contract_source.py +984 -0
- omnibase_infra/runtime/models/__init__.py +13 -0
- omnibase_infra/runtime/models/model_contract_load_result.py +224 -0
- omnibase_infra/runtime/models/model_runtime_contract_config.py +268 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_config.py +4 -3
- omnibase_infra/runtime/models/model_security_config.py +109 -0
- omnibase_infra/runtime/publisher_topic_scoped.py +294 -0
- omnibase_infra/runtime/runtime_contract_config_loader.py +406 -0
- omnibase_infra/runtime/service_kernel.py +76 -6
- omnibase_infra/runtime/service_message_dispatch_engine.py +558 -15
- omnibase_infra/runtime/service_runtime_host_process.py +770 -20
- omnibase_infra/runtime/transition_notification_publisher.py +3 -2
- omnibase_infra/runtime/util_wiring.py +206 -62
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +27 -9
- omnibase_infra/services/session/config_consumer.py +25 -8
- omnibase_infra/services/session/config_store.py +2 -2
- omnibase_infra/services/session/consumer.py +1 -1
- omnibase_infra/topics/__init__.py +45 -0
- omnibase_infra/topics/platform_topic_suffixes.py +140 -0
- omnibase_infra/topics/util_topic_composition.py +95 -0
- omnibase_infra/types/typed_dict/__init__.py +9 -1
- omnibase_infra/types/typed_dict/typed_dict_envelope_build_params.py +115 -0
- omnibase_infra/utils/__init__.py +9 -0
- omnibase_infra/utils/util_consumer_group.py +232 -0
- omnibase_infra/validation/infra_validators.py +18 -1
- omnibase_infra/validation/validation_exemptions.yaml +192 -0
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/METADATA +3 -3
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/RECORD +139 -52
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/entry_points.txt +1 -0
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Operation bindings models for declarative handler parameter mapping.
|
|
4
|
+
|
|
5
|
+
This module provides models for binding expressions used in declarative
|
|
6
|
+
handler parameter resolution from contract.yaml.
|
|
7
|
+
|
|
8
|
+
.. versionadded:: 0.2.6
|
|
9
|
+
Added ModelOperationBindingsSubcontract and ModelBindingResolutionResult
|
|
10
|
+
as part of OMN-1518 - Declarative operation bindings.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from omnibase_infra.models.bindings.constants import (
|
|
14
|
+
DEFAULT_JSON_RECURSION_DEPTH,
|
|
15
|
+
EXPRESSION_PATTERN,
|
|
16
|
+
MAX_EXPRESSION_LENGTH,
|
|
17
|
+
MAX_JSON_RECURSION_DEPTH,
|
|
18
|
+
MAX_PATH_SEGMENTS,
|
|
19
|
+
MIN_JSON_RECURSION_DEPTH,
|
|
20
|
+
VALID_CONTEXT_PATHS,
|
|
21
|
+
VALID_SOURCES,
|
|
22
|
+
)
|
|
23
|
+
from omnibase_infra.models.bindings.model_binding_resolution_result import (
|
|
24
|
+
ModelBindingResolutionResult,
|
|
25
|
+
)
|
|
26
|
+
from omnibase_infra.models.bindings.model_operation_binding import (
|
|
27
|
+
ModelOperationBinding,
|
|
28
|
+
)
|
|
29
|
+
from omnibase_infra.models.bindings.model_operation_bindings_subcontract import (
|
|
30
|
+
MAX_EXPRESSION_LENGTH_LIMIT,
|
|
31
|
+
MAX_PATH_SEGMENTS_LIMIT,
|
|
32
|
+
MIN_EXPRESSION_LENGTH,
|
|
33
|
+
MIN_PATH_SEGMENTS,
|
|
34
|
+
ModelOperationBindingsSubcontract,
|
|
35
|
+
)
|
|
36
|
+
from omnibase_infra.models.bindings.model_parsed_binding import (
|
|
37
|
+
ModelParsedBinding,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
__all__: list[str] = [
|
|
41
|
+
# Constants
|
|
42
|
+
"DEFAULT_JSON_RECURSION_DEPTH",
|
|
43
|
+
"EXPRESSION_PATTERN",
|
|
44
|
+
"MAX_EXPRESSION_LENGTH",
|
|
45
|
+
"MAX_EXPRESSION_LENGTH_LIMIT",
|
|
46
|
+
"MAX_JSON_RECURSION_DEPTH",
|
|
47
|
+
"MAX_PATH_SEGMENTS",
|
|
48
|
+
"MAX_PATH_SEGMENTS_LIMIT",
|
|
49
|
+
"MIN_EXPRESSION_LENGTH",
|
|
50
|
+
"MIN_JSON_RECURSION_DEPTH",
|
|
51
|
+
"MIN_PATH_SEGMENTS",
|
|
52
|
+
"VALID_CONTEXT_PATHS",
|
|
53
|
+
"VALID_SOURCES",
|
|
54
|
+
# Models
|
|
55
|
+
"ModelBindingResolutionResult",
|
|
56
|
+
"ModelOperationBinding",
|
|
57
|
+
"ModelOperationBindingsSubcontract",
|
|
58
|
+
"ModelParsedBinding",
|
|
59
|
+
]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Shared constants for binding expression parsing and validation.
|
|
4
|
+
|
|
5
|
+
This module contains guardrail constants and patterns used by both:
|
|
6
|
+
- :mod:`omnibase_infra.runtime.binding_resolver` (runtime resolution)
|
|
7
|
+
- :mod:`omnibase_infra.runtime.contract_loaders.operation_bindings_loader` (load-time validation)
|
|
8
|
+
|
|
9
|
+
These constants define the security and validation boundaries for binding expressions.
|
|
10
|
+
|
|
11
|
+
.. versionadded:: 0.2.6
|
|
12
|
+
Created as part of OMN-1518 - Declarative operation bindings.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import re
|
|
18
|
+
from typing import Final
|
|
19
|
+
|
|
20
|
+
# =============================================================================
|
|
21
|
+
# Guardrail Constants
|
|
22
|
+
# =============================================================================
|
|
23
|
+
|
|
24
|
+
MAX_EXPRESSION_LENGTH: Final[int] = 256
|
|
25
|
+
"""Maximum allowed length for binding expressions (characters).
|
|
26
|
+
|
|
27
|
+
Prevents denial-of-service via extremely long expressions that could
|
|
28
|
+
exhaust memory or CPU during regex matching.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
MAX_PATH_SEGMENTS: Final[int] = 20
|
|
32
|
+
"""Maximum allowed path depth (dot-separated segments).
|
|
33
|
+
|
|
34
|
+
Prevents deep nesting attacks and potential stack overflow during
|
|
35
|
+
path traversal. Also limits complexity of binding expressions.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
# =============================================================================
|
|
39
|
+
# JSON Recursion Depth Limits
|
|
40
|
+
# =============================================================================
|
|
41
|
+
|
|
42
|
+
DEFAULT_JSON_RECURSION_DEPTH: Final[int] = 100
|
|
43
|
+
"""Default maximum recursion depth for JSON compatibility validation.
|
|
44
|
+
|
|
45
|
+
This constant limits how deeply nested structures are validated in
|
|
46
|
+
``_is_json_compatible_recursive()``. It prevents stack overflow on
|
|
47
|
+
pathological inputs such as deeply nested dicts/lists or cyclic
|
|
48
|
+
references that somehow bypass Python's normal recursion limit.
|
|
49
|
+
|
|
50
|
+
The value of 100 is chosen to:
|
|
51
|
+
- Allow normal JSON structures (rarely exceed 10-20 levels)
|
|
52
|
+
- Prevent stack overflow on malicious or malformed inputs
|
|
53
|
+
- Align with common JSON parser depth limits
|
|
54
|
+
|
|
55
|
+
.. versionadded:: 0.2.6
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
MIN_JSON_RECURSION_DEPTH: Final[int] = 10
|
|
59
|
+
"""Minimum configurable JSON recursion depth.
|
|
60
|
+
|
|
61
|
+
Values below this threshold would be too restrictive for practical use,
|
|
62
|
+
as even simple nested structures (like user -> address -> country)
|
|
63
|
+
can easily reach 5+ levels.
|
|
64
|
+
|
|
65
|
+
.. versionadded:: 0.2.6
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
MAX_JSON_RECURSION_DEPTH: Final[int] = 1000
|
|
69
|
+
"""Maximum configurable JSON recursion depth.
|
|
70
|
+
|
|
71
|
+
Values above this threshold increase risk of stack overflow and would
|
|
72
|
+
exceed any reasonable JSON structure depth. Most JSON parsers use
|
|
73
|
+
similar limits (e.g., Python's json module has implicit limits).
|
|
74
|
+
|
|
75
|
+
.. versionadded:: 0.2.6
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
# =============================================================================
|
|
79
|
+
# Valid Sources and Context Paths
|
|
80
|
+
# =============================================================================
|
|
81
|
+
|
|
82
|
+
VALID_SOURCES: Final[frozenset[str]] = frozenset({"payload", "envelope", "context"})
|
|
83
|
+
"""Valid source names for binding expressions.
|
|
84
|
+
|
|
85
|
+
Binding expressions must start with one of these sources:
|
|
86
|
+
- ``payload``: Access fields from the event payload
|
|
87
|
+
- ``envelope``: Access fields from the event envelope (correlation_id, etc.)
|
|
88
|
+
- ``context``: Access runtime context values (now_iso, dispatcher_id, etc.)
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
VALID_CONTEXT_PATHS: Final[frozenset[str]] = frozenset(
|
|
92
|
+
{
|
|
93
|
+
"now_iso",
|
|
94
|
+
"dispatcher_id",
|
|
95
|
+
"correlation_id",
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
"""Exhaustive allowlist of valid context paths.
|
|
99
|
+
|
|
100
|
+
Context paths are special runtime-provided values injected by the
|
|
101
|
+
dispatch infrastructure. Adding new context paths requires:
|
|
102
|
+
|
|
103
|
+
1. Update this allowlist
|
|
104
|
+
2. Update the dispatch context provider to supply the value
|
|
105
|
+
3. Document the new context path in relevant docstrings
|
|
106
|
+
|
|
107
|
+
Current paths:
|
|
108
|
+
- ``now_iso``: Current timestamp in ISO 8601 format
|
|
109
|
+
- ``dispatcher_id``: Unique identifier of the dispatcher instance
|
|
110
|
+
- ``correlation_id``: Request correlation ID for distributed tracing
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
# =============================================================================
|
|
114
|
+
# Expression Pattern
|
|
115
|
+
# =============================================================================
|
|
116
|
+
|
|
117
|
+
EXPRESSION_PATTERN: Final[re.Pattern[str]] = re.compile(
|
|
118
|
+
r"^\$\{([a-z]+)\.([a-zA-Z0-9_.]+)\}$"
|
|
119
|
+
)
|
|
120
|
+
"""Compiled regex for parsing binding expressions.
|
|
121
|
+
|
|
122
|
+
Pattern breakdown:
|
|
123
|
+
- ``^\\$\\{``: Literal ``${`` at start
|
|
124
|
+
- ``([a-z]+)``: Group 1 - source (lowercase letters only)
|
|
125
|
+
- ``\\.``: Literal dot separator
|
|
126
|
+
- ``([a-zA-Z0-9_.]+)``: Group 2 - path (letters, numbers, underscores, dots)
|
|
127
|
+
- ``\\}$``: Literal ``}`` at end
|
|
128
|
+
|
|
129
|
+
Examples of valid expressions:
|
|
130
|
+
- ``${payload.user.id}`` -> source="payload", path="user.id"
|
|
131
|
+
- ``${envelope.correlation_id}`` -> source="envelope", path="correlation_id"
|
|
132
|
+
- ``${context.now_iso}`` -> source="context", path="now_iso"
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
__all__: list[str] = [
|
|
136
|
+
"DEFAULT_JSON_RECURSION_DEPTH",
|
|
137
|
+
"EXPRESSION_PATTERN",
|
|
138
|
+
"MAX_EXPRESSION_LENGTH",
|
|
139
|
+
"MAX_JSON_RECURSION_DEPTH",
|
|
140
|
+
"MAX_PATH_SEGMENTS",
|
|
141
|
+
"MIN_JSON_RECURSION_DEPTH",
|
|
142
|
+
"VALID_CONTEXT_PATHS",
|
|
143
|
+
"VALID_SOURCES",
|
|
144
|
+
]
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Binding resolution result model.
|
|
4
|
+
|
|
5
|
+
This model represents the outcome of resolving operation bindings, containing
|
|
6
|
+
the resolved parameters and debug information for troubleshooting.
|
|
7
|
+
|
|
8
|
+
.. versionadded:: 0.2.6
|
|
9
|
+
Created as part of OMN-1518 - Declarative operation bindings.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from pydantic import BaseModel, Field
|
|
15
|
+
|
|
16
|
+
from omnibase_core.types import JsonType
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ModelBindingResolutionResult(BaseModel):
|
|
20
|
+
"""Result of binding resolution - execution fact, never mutated.
|
|
21
|
+
|
|
22
|
+
Contains resolved parameters plus debug information for troubleshooting.
|
|
23
|
+
Once created, this is immutable - bindings become execution facts.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
operation_name: Operation that was resolved.
|
|
27
|
+
resolved_parameters: Mapping of parameter name to resolved value.
|
|
28
|
+
resolved_from: Mapping of parameter name to original expression (debug gold).
|
|
29
|
+
success: True if all required bindings resolved successfully.
|
|
30
|
+
error: Error message if success=False.
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> result = resolver.resolve(envelope, "db.query")
|
|
34
|
+
>>> if result:
|
|
35
|
+
... execute_query(result.resolved_parameters)
|
|
36
|
+
... else:
|
|
37
|
+
... log_error(result.error)
|
|
38
|
+
|
|
39
|
+
.. versionadded:: 0.2.6
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
operation_name: str = Field(
|
|
43
|
+
...,
|
|
44
|
+
description="Operation that was resolved",
|
|
45
|
+
)
|
|
46
|
+
resolved_parameters: dict[str, JsonType] = Field(
|
|
47
|
+
default_factory=dict,
|
|
48
|
+
description="Parameter name -> resolved value",
|
|
49
|
+
)
|
|
50
|
+
resolved_from: dict[str, str] = Field(
|
|
51
|
+
default_factory=dict,
|
|
52
|
+
description="Parameter name -> original expression (debug gold)",
|
|
53
|
+
)
|
|
54
|
+
success: bool = Field(
|
|
55
|
+
...,
|
|
56
|
+
description="True if all required bindings resolved successfully",
|
|
57
|
+
)
|
|
58
|
+
error: str | None = Field(
|
|
59
|
+
default=None,
|
|
60
|
+
description="Error message if success=False",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
model_config = {"frozen": True, "extra": "forbid"}
|
|
64
|
+
|
|
65
|
+
def __bool__(self) -> bool:
|
|
66
|
+
"""Return True if resolution succeeded.
|
|
67
|
+
|
|
68
|
+
Warning:
|
|
69
|
+
**Non-standard __bool__ behavior**: This model overrides ``__bool__`` to
|
|
70
|
+
return ``True`` only when ``success`` is True. This differs from typical
|
|
71
|
+
Pydantic model behavior where ``bool(model)`` always returns ``True`` for
|
|
72
|
+
any valid model instance.
|
|
73
|
+
|
|
74
|
+
This design enables idiomatic conditional checks for resolution results::
|
|
75
|
+
|
|
76
|
+
result = resolver.resolve(envelope, "db.query")
|
|
77
|
+
if result:
|
|
78
|
+
# Resolution succeeded - use parameters
|
|
79
|
+
execute_query(result.resolved_parameters)
|
|
80
|
+
else:
|
|
81
|
+
# Resolution failed - handle error
|
|
82
|
+
log_error(result.error)
|
|
83
|
+
|
|
84
|
+
If you need to check model existence instead, use explicit attribute access::
|
|
85
|
+
|
|
86
|
+
# Check for resolution success (uses __bool__)
|
|
87
|
+
if result:
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
# Check model is not None
|
|
91
|
+
if result is not None:
|
|
92
|
+
...
|
|
93
|
+
|
|
94
|
+
# Explicit success check (preferred for clarity)
|
|
95
|
+
if result.success:
|
|
96
|
+
...
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
True if resolution succeeded, False otherwise.
|
|
100
|
+
|
|
101
|
+
.. versionadded:: 0.2.6
|
|
102
|
+
"""
|
|
103
|
+
return self.success
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Operation binding model for contract.yaml entries."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
from omnibase_core.types import JsonType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ModelOperationBinding(BaseModel):
|
|
13
|
+
"""Single binding entry from contract.yaml.
|
|
14
|
+
|
|
15
|
+
Maps a handler parameter to an expression that extracts data from
|
|
16
|
+
envelope, payload, or context.
|
|
17
|
+
|
|
18
|
+
Example YAML:
|
|
19
|
+
- parameter_name: "correlation_id"
|
|
20
|
+
expression: "${envelope.correlation_id}"
|
|
21
|
+
required: true
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
parameter_name: str = Field(
|
|
25
|
+
...,
|
|
26
|
+
description="Target handler input field name",
|
|
27
|
+
)
|
|
28
|
+
expression: str = Field(
|
|
29
|
+
...,
|
|
30
|
+
description="Source expression in ${source.path} format",
|
|
31
|
+
)
|
|
32
|
+
required: bool = Field(
|
|
33
|
+
default=True,
|
|
34
|
+
description="If True, fail fast when field is missing",
|
|
35
|
+
)
|
|
36
|
+
default: JsonType | None = Field(
|
|
37
|
+
default=None,
|
|
38
|
+
description="Default value if not required and missing",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
model_config = {"frozen": True, "extra": "forbid"}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
__all__ = ["ModelOperationBinding"]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Operation bindings subcontract model for contract.yaml section.
|
|
4
|
+
|
|
5
|
+
This model represents the full operation_bindings section from a contract.yaml file,
|
|
6
|
+
containing pre-parsed bindings for all operations plus optional global bindings.
|
|
7
|
+
|
|
8
|
+
.. versionadded:: 0.2.6
|
|
9
|
+
Created as part of OMN-1518 - Declarative operation bindings.
|
|
10
|
+
|
|
11
|
+
.. versionchanged:: 0.2.7
|
|
12
|
+
Added max_expression_length and max_path_segments for per-contract guardrail overrides.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from pydantic import BaseModel, Field
|
|
18
|
+
|
|
19
|
+
from omnibase_core.models.primitives.model_semver import ModelSemVer
|
|
20
|
+
from omnibase_infra.models.bindings.constants import (
|
|
21
|
+
DEFAULT_JSON_RECURSION_DEPTH,
|
|
22
|
+
MAX_EXPRESSION_LENGTH,
|
|
23
|
+
MAX_JSON_RECURSION_DEPTH,
|
|
24
|
+
MAX_PATH_SEGMENTS,
|
|
25
|
+
MIN_JSON_RECURSION_DEPTH,
|
|
26
|
+
)
|
|
27
|
+
from omnibase_infra.models.bindings.model_parsed_binding import ModelParsedBinding
|
|
28
|
+
|
|
29
|
+
# =============================================================================
|
|
30
|
+
# Guardrail Bounds Constants
|
|
31
|
+
# =============================================================================
|
|
32
|
+
|
|
33
|
+
# Expression length bounds
|
|
34
|
+
MIN_EXPRESSION_LENGTH: int = 32
|
|
35
|
+
"""Minimum allowed value for max_expression_length override.
|
|
36
|
+
|
|
37
|
+
Prevents trivially small expressions that would be unusable for real bindings.
|
|
38
|
+
A minimal valid expression like ${payload.x} is 12 characters.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
MAX_EXPRESSION_LENGTH_LIMIT: int = 1024
|
|
42
|
+
"""Maximum allowed value for max_expression_length override.
|
|
43
|
+
|
|
44
|
+
Prevents DoS via excessively long expressions that could exhaust memory
|
|
45
|
+
or CPU during regex matching.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# Path segment bounds
|
|
49
|
+
MIN_PATH_SEGMENTS: int = 3
|
|
50
|
+
"""Minimum allowed value for max_path_segments override.
|
|
51
|
+
|
|
52
|
+
Need at least source.path.field (3 segments) for useful bindings.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
MAX_PATH_SEGMENTS_LIMIT: int = 50
|
|
56
|
+
"""Maximum allowed value for max_path_segments override.
|
|
57
|
+
|
|
58
|
+
Prevents absurdly deep paths that could cause stack issues or DoS.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ModelOperationBindingsSubcontract(BaseModel):
|
|
63
|
+
"""Full operation_bindings section from contract.yaml.
|
|
64
|
+
|
|
65
|
+
Contains pre-parsed bindings for all operations, plus optional
|
|
66
|
+
global bindings applied to every operation.
|
|
67
|
+
|
|
68
|
+
Example YAML:
|
|
69
|
+
operation_bindings:
|
|
70
|
+
version: { major: 1, minor: 0, patch: 0 }
|
|
71
|
+
max_expression_length: 512 # Override default (256)
|
|
72
|
+
max_path_segments: 30 # Override default (20)
|
|
73
|
+
max_json_recursion_depth: 50 # Override default (100)
|
|
74
|
+
additional_context_paths:
|
|
75
|
+
- "request_id" # Handler needs request ID
|
|
76
|
+
- "tenant_id" # Multi-tenant context
|
|
77
|
+
global_bindings:
|
|
78
|
+
- parameter_name: "correlation_id"
|
|
79
|
+
expression: "${envelope.correlation_id}"
|
|
80
|
+
bindings:
|
|
81
|
+
"db.query":
|
|
82
|
+
- parameter_name: "sql"
|
|
83
|
+
expression: "${payload.sql}"
|
|
84
|
+
- parameter_name: "tenant"
|
|
85
|
+
expression: "${context.tenant_id}"
|
|
86
|
+
required: true
|
|
87
|
+
|
|
88
|
+
Attributes:
|
|
89
|
+
version: Schema version for evolution tracking.
|
|
90
|
+
additional_context_paths: Additional context paths this handler can resolve
|
|
91
|
+
beyond the base set (now_iso, dispatcher_id, correlation_id).
|
|
92
|
+
When declared, the dispatch engine is CONTRACTED to provide these
|
|
93
|
+
values in the context dict. Pattern: ^[a-z][a-z0-9_]*$
|
|
94
|
+
bindings: Mapping of operation name to list of parsed bindings.
|
|
95
|
+
global_bindings: Optional bindings applied to all operations (can be overridden).
|
|
96
|
+
max_expression_length: Override default expression length limit (32-1024).
|
|
97
|
+
max_path_segments: Override default path segment limit (3-50).
|
|
98
|
+
max_json_recursion_depth: Maximum depth for JSON compatibility validation (10-1000).
|
|
99
|
+
Limits how deeply nested structures are validated to prevent stack overflow.
|
|
100
|
+
|
|
101
|
+
.. versionadded:: 0.2.6
|
|
102
|
+
.. versionchanged:: 0.2.7
|
|
103
|
+
Added max_expression_length, max_path_segments, and max_json_recursion_depth
|
|
104
|
+
for per-contract guardrail overrides.
|
|
105
|
+
Added additional_context_paths for extensible context resolution.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
version: ModelSemVer = Field(
|
|
109
|
+
default_factory=lambda: ModelSemVer(major=1, minor=0, patch=0),
|
|
110
|
+
description="Schema version for evolution tracking",
|
|
111
|
+
)
|
|
112
|
+
additional_context_paths: list[str] = Field(
|
|
113
|
+
default_factory=list,
|
|
114
|
+
description=(
|
|
115
|
+
"Additional context paths this handler can resolve beyond the base set "
|
|
116
|
+
"(now_iso, dispatcher_id, correlation_id). When declared, the dispatch "
|
|
117
|
+
"engine is CONTRACTED to provide these values. "
|
|
118
|
+
"Pattern: ^[a-z][a-z0-9_]*$ (lowercase letters, numbers, underscores)"
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
bindings: dict[str, list[ModelParsedBinding]] = Field(
|
|
122
|
+
default_factory=dict,
|
|
123
|
+
description="Operation name -> list of parsed bindings",
|
|
124
|
+
)
|
|
125
|
+
global_bindings: list[ModelParsedBinding] | None = Field(
|
|
126
|
+
default=None,
|
|
127
|
+
description="Bindings applied to all operations (can be overridden)",
|
|
128
|
+
)
|
|
129
|
+
max_expression_length: int = Field(
|
|
130
|
+
default=MAX_EXPRESSION_LENGTH,
|
|
131
|
+
ge=MIN_EXPRESSION_LENGTH,
|
|
132
|
+
le=MAX_EXPRESSION_LENGTH_LIMIT,
|
|
133
|
+
description="Override default expression length limit (32-1024)",
|
|
134
|
+
)
|
|
135
|
+
max_path_segments: int = Field(
|
|
136
|
+
default=MAX_PATH_SEGMENTS,
|
|
137
|
+
ge=MIN_PATH_SEGMENTS,
|
|
138
|
+
le=MAX_PATH_SEGMENTS_LIMIT,
|
|
139
|
+
description="Override default path segment limit (3-50)",
|
|
140
|
+
)
|
|
141
|
+
max_json_recursion_depth: int = Field(
|
|
142
|
+
default=DEFAULT_JSON_RECURSION_DEPTH,
|
|
143
|
+
ge=MIN_JSON_RECURSION_DEPTH,
|
|
144
|
+
le=MAX_JSON_RECURSION_DEPTH,
|
|
145
|
+
description=(
|
|
146
|
+
f"Maximum depth for JSON compatibility validation ({MIN_JSON_RECURSION_DEPTH}-"
|
|
147
|
+
f"{MAX_JSON_RECURSION_DEPTH}). Limits how deeply nested structures are "
|
|
148
|
+
"validated to prevent stack overflow on pathological inputs."
|
|
149
|
+
),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
model_config = {"frozen": True, "extra": "forbid"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Parsed binding model with pre-compiled expression components."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from omnibase_core.types import JsonType
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ModelParsedBinding(BaseModel):
|
|
15
|
+
"""Binding with pre-parsed expression for fast resolution.
|
|
16
|
+
|
|
17
|
+
The loader parses and validates expressions once at load time.
|
|
18
|
+
The resolver just executes path traversal without re-parsing.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
Original expression: "${payload.user.id}"
|
|
22
|
+
Parsed:
|
|
23
|
+
source: "payload"
|
|
24
|
+
path_segments: ("user", "id")
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
parameter_name: str = Field(
|
|
28
|
+
...,
|
|
29
|
+
description="Target handler input field name",
|
|
30
|
+
)
|
|
31
|
+
source: Literal["payload", "envelope", "context"] = Field(
|
|
32
|
+
...,
|
|
33
|
+
description="Data source for binding resolution",
|
|
34
|
+
)
|
|
35
|
+
path_segments: tuple[str, ...] = Field(
|
|
36
|
+
...,
|
|
37
|
+
description="Pre-parsed path segments for traversal",
|
|
38
|
+
)
|
|
39
|
+
required: bool = Field(
|
|
40
|
+
default=True,
|
|
41
|
+
description="If True, fail fast when field is missing",
|
|
42
|
+
)
|
|
43
|
+
default: JsonType | None = Field(
|
|
44
|
+
default=None,
|
|
45
|
+
description="Default value if not required and missing",
|
|
46
|
+
)
|
|
47
|
+
original_expression: str = Field(
|
|
48
|
+
...,
|
|
49
|
+
description="Original ${source.path} expression for error messages",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
model_config = {"frozen": True, "extra": "forbid"}
|
|
@@ -28,6 +28,11 @@ from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
|
28
28
|
|
|
29
29
|
from omnibase_core.enums import EnumNodeKind
|
|
30
30
|
from omnibase_core.models.contracts import ModelContractBase
|
|
31
|
+
from omnibase_infra.topics import (
|
|
32
|
+
SUFFIX_NODE_HEARTBEAT,
|
|
33
|
+
SUFFIX_NODE_INTROSPECTION,
|
|
34
|
+
SUFFIX_REQUEST_INTROSPECTION,
|
|
35
|
+
)
|
|
31
36
|
|
|
32
37
|
if TYPE_CHECKING:
|
|
33
38
|
from omnibase_core.protocols.event_bus.protocol_event_bus import ProtocolEventBus
|
|
@@ -42,11 +47,11 @@ else:
|
|
|
42
47
|
|
|
43
48
|
logger = logging.getLogger(__name__)
|
|
44
49
|
|
|
45
|
-
# Default topic constants
|
|
46
|
-
#
|
|
47
|
-
DEFAULT_INTROSPECTION_TOPIC =
|
|
48
|
-
DEFAULT_HEARTBEAT_TOPIC =
|
|
49
|
-
DEFAULT_REQUEST_INTROSPECTION_TOPIC =
|
|
50
|
+
# Default topic constants using ONEX platform suffix constants
|
|
51
|
+
# These are the canonical source for introspection-related topic defaults
|
|
52
|
+
DEFAULT_INTROSPECTION_TOPIC = SUFFIX_NODE_INTROSPECTION
|
|
53
|
+
DEFAULT_HEARTBEAT_TOPIC = SUFFIX_NODE_HEARTBEAT
|
|
54
|
+
DEFAULT_REQUEST_INTROSPECTION_TOPIC = SUFFIX_REQUEST_INTROSPECTION
|
|
50
55
|
|
|
51
56
|
# Topic validation patterns
|
|
52
57
|
# Matches valid topic characters: lowercase alphanumeric, dots, hyphens, underscores
|
|
@@ -79,14 +84,14 @@ class ModelIntrospectionConfig(BaseModel):
|
|
|
79
84
|
discovery. Methods starting with these prefixes are filtered out.
|
|
80
85
|
If None, uses MixinNodeIntrospection.DEFAULT_EXCLUDE_PREFIXES.
|
|
81
86
|
introspection_topic: Topic for publishing introspection events.
|
|
82
|
-
Defaults to
|
|
83
|
-
version suffix (.v1, .v2, etc.).
|
|
87
|
+
Defaults to SUFFIX_NODE_INTROSPECTION (onex.evt.platform.node-introspection.v1).
|
|
88
|
+
ONEX topics (onex.*) require version suffix (.v1, .v2, etc.).
|
|
84
89
|
heartbeat_topic: Topic for publishing heartbeat events.
|
|
85
|
-
Defaults to
|
|
86
|
-
version suffix (.v1, .v2, etc.).
|
|
90
|
+
Defaults to SUFFIX_NODE_HEARTBEAT (onex.evt.platform.node-heartbeat.v1).
|
|
91
|
+
ONEX topics (onex.*) require version suffix (.v1, .v2, etc.).
|
|
87
92
|
request_introspection_topic: Topic for receiving introspection requests.
|
|
88
|
-
Defaults to
|
|
89
|
-
require version suffix (.v1, .v2, etc.).
|
|
93
|
+
Defaults to SUFFIX_REQUEST_INTROSPECTION (onex.cmd.platform.request-introspection.v1).
|
|
94
|
+
ONEX topics (onex.*) require version suffix (.v1, .v2, etc.).
|
|
90
95
|
contract: Optional typed contract model for capability extraction.
|
|
91
96
|
When provided, MixinNodeIntrospection extracts contract_capabilities
|
|
92
97
|
using ContractCapabilityExtractor. None for legacy nodes.
|
|
@@ -282,6 +287,7 @@ class ModelIntrospectionConfig(BaseModel):
|
|
|
282
287
|
arbitrary_types_allowed=True, # Allow arbitrary types for event_bus
|
|
283
288
|
json_schema_extra={
|
|
284
289
|
"examples": [
|
|
290
|
+
# First example: Default topic configuration using suffix constants
|
|
285
291
|
{
|
|
286
292
|
"node_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
287
293
|
"node_type": "EFFECT",
|
|
@@ -290,10 +296,12 @@ class ModelIntrospectionConfig(BaseModel):
|
|
|
290
296
|
"cache_ttl": 300.0,
|
|
291
297
|
"operation_keywords": None,
|
|
292
298
|
"exclude_prefixes": None,
|
|
293
|
-
"introspection_topic": "node.
|
|
294
|
-
"heartbeat_topic": "node.
|
|
295
|
-
"request_introspection_topic": "
|
|
299
|
+
"introspection_topic": "onex.evt.platform.node-introspection.v1",
|
|
300
|
+
"heartbeat_topic": "onex.evt.platform.node-heartbeat.v1",
|
|
301
|
+
"request_introspection_topic": "onex.cmd.platform.request-introspection.v1",
|
|
296
302
|
},
|
|
303
|
+
# Second example: Custom prefixed topics for environment isolation
|
|
304
|
+
# Demonstrates adding env/namespace prefix to suffix constants
|
|
297
305
|
{
|
|
298
306
|
"node_id": "550e8400-e29b-41d4-a716-446655440001",
|
|
299
307
|
"node_type": "COMPUTE",
|
|
@@ -302,9 +310,9 @@ class ModelIntrospectionConfig(BaseModel):
|
|
|
302
310
|
"cache_ttl": 120.0,
|
|
303
311
|
"operation_keywords": ["process", "transform", "analyze"],
|
|
304
312
|
"exclude_prefixes": ["_internal", "_private"],
|
|
305
|
-
"introspection_topic": "onex.node
|
|
306
|
-
"heartbeat_topic": "onex.node
|
|
307
|
-
"request_introspection_topic": "onex.
|
|
313
|
+
"introspection_topic": "prod.myapp.onex.evt.platform.node-introspection.v1",
|
|
314
|
+
"heartbeat_topic": "prod.myapp.onex.evt.platform.node-heartbeat.v1",
|
|
315
|
+
"request_introspection_topic": "prod.myapp.onex.cmd.platform.request-introspection.v1",
|
|
308
316
|
},
|
|
309
317
|
]
|
|
310
318
|
},
|
|
@@ -95,6 +95,9 @@ See Also:
|
|
|
95
95
|
"""
|
|
96
96
|
|
|
97
97
|
from omnibase_infra.enums import EnumDispatchStatus, EnumTopicStandard
|
|
98
|
+
from omnibase_infra.models.dispatch.model_debug_trace_snapshot import (
|
|
99
|
+
ModelDebugTraceSnapshot,
|
|
100
|
+
)
|
|
98
101
|
from omnibase_infra.models.dispatch.model_dispatch_context import ModelDispatchContext
|
|
99
102
|
from omnibase_infra.models.dispatch.model_dispatch_error import ModelDispatchError
|
|
100
103
|
from omnibase_infra.models.dispatch.model_dispatch_log_context import (
|
|
@@ -112,6 +115,9 @@ from omnibase_infra.models.dispatch.model_dispatcher_metrics import (
|
|
|
112
115
|
from omnibase_infra.models.dispatch.model_dispatcher_registration import (
|
|
113
116
|
ModelDispatcherRegistration,
|
|
114
117
|
)
|
|
118
|
+
from omnibase_infra.models.dispatch.model_materialized_dispatch import (
|
|
119
|
+
ModelMaterializedDispatch,
|
|
120
|
+
)
|
|
115
121
|
from omnibase_infra.models.dispatch.model_parsed_topic import ModelParsedTopic
|
|
116
122
|
from omnibase_infra.models.dispatch.model_topic_parser import (
|
|
117
123
|
ModelTopicParser,
|
|
@@ -128,9 +134,11 @@ __all__ = [
|
|
|
128
134
|
"EnumDispatchStatus",
|
|
129
135
|
"EnumTopicStandard",
|
|
130
136
|
# Models
|
|
137
|
+
"ModelDebugTraceSnapshot",
|
|
131
138
|
"ModelDispatchContext",
|
|
132
139
|
"ModelDispatchError",
|
|
133
140
|
"ModelDispatchLogContext",
|
|
141
|
+
"ModelMaterializedDispatch",
|
|
134
142
|
"ModelDispatchMetadata",
|
|
135
143
|
"ModelDispatchMetrics",
|
|
136
144
|
"ModelDispatchOutcome",
|