omnibase_infra 0.2.8__py3-none-any.whl → 0.3.0__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 (88) hide show
  1. omnibase_infra/__init__.py +1 -1
  2. omnibase_infra/enums/__init__.py +4 -0
  3. omnibase_infra/enums/enum_declarative_node_violation.py +102 -0
  4. omnibase_infra/errors/__init__.py +18 -0
  5. omnibase_infra/errors/repository/__init__.py +78 -0
  6. omnibase_infra/errors/repository/errors_repository.py +424 -0
  7. omnibase_infra/event_bus/adapters/__init__.py +31 -0
  8. omnibase_infra/event_bus/adapters/adapter_protocol_event_publisher_kafka.py +517 -0
  9. omnibase_infra/mixins/mixin_async_circuit_breaker.py +113 -1
  10. omnibase_infra/models/__init__.py +9 -0
  11. omnibase_infra/models/event_bus/__init__.py +22 -0
  12. omnibase_infra/models/event_bus/model_consumer_retry_config.py +367 -0
  13. omnibase_infra/models/event_bus/model_dlq_config.py +177 -0
  14. omnibase_infra/models/event_bus/model_idempotency_config.py +131 -0
  15. omnibase_infra/models/event_bus/model_offset_policy_config.py +107 -0
  16. omnibase_infra/models/resilience/model_circuit_breaker_config.py +15 -0
  17. omnibase_infra/models/validation/__init__.py +8 -0
  18. omnibase_infra/models/validation/model_declarative_node_validation_result.py +139 -0
  19. omnibase_infra/models/validation/model_declarative_node_violation.py +169 -0
  20. omnibase_infra/nodes/architecture_validator/__init__.py +28 -7
  21. omnibase_infra/nodes/architecture_validator/constants.py +36 -0
  22. omnibase_infra/nodes/architecture_validator/handlers/__init__.py +28 -0
  23. omnibase_infra/nodes/architecture_validator/handlers/contract.yaml +120 -0
  24. omnibase_infra/nodes/architecture_validator/handlers/handler_architecture_validation.py +359 -0
  25. omnibase_infra/nodes/architecture_validator/node.py +1 -0
  26. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +48 -336
  27. omnibase_infra/nodes/contract_registry_reducer/reducer.py +12 -2
  28. omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +16 -2
  29. omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +14 -4
  30. omnibase_infra/nodes/node_ledger_projection_compute/handlers/__init__.py +18 -0
  31. omnibase_infra/nodes/node_ledger_projection_compute/handlers/contract.yaml +53 -0
  32. omnibase_infra/nodes/node_ledger_projection_compute/handlers/handler_ledger_projection.py +354 -0
  33. omnibase_infra/nodes/node_ledger_projection_compute/node.py +20 -256
  34. omnibase_infra/nodes/node_registry_effect/node.py +20 -73
  35. omnibase_infra/protocols/protocol_dispatch_engine.py +90 -0
  36. omnibase_infra/runtime/__init__.py +11 -0
  37. omnibase_infra/runtime/baseline_subscriptions.py +150 -0
  38. omnibase_infra/runtime/db/__init__.py +73 -0
  39. omnibase_infra/runtime/db/models/__init__.py +41 -0
  40. omnibase_infra/runtime/db/models/model_repository_runtime_config.py +211 -0
  41. omnibase_infra/runtime/db/postgres_repository_runtime.py +545 -0
  42. omnibase_infra/runtime/event_bus_subcontract_wiring.py +455 -24
  43. omnibase_infra/runtime/kafka_contract_source.py +13 -5
  44. omnibase_infra/runtime/service_message_dispatch_engine.py +112 -0
  45. omnibase_infra/runtime/service_runtime_host_process.py +6 -11
  46. omnibase_infra/services/__init__.py +36 -0
  47. omnibase_infra/services/contract_publisher/__init__.py +95 -0
  48. omnibase_infra/services/contract_publisher/config.py +199 -0
  49. omnibase_infra/services/contract_publisher/errors.py +243 -0
  50. omnibase_infra/services/contract_publisher/models/__init__.py +28 -0
  51. omnibase_infra/services/contract_publisher/models/model_contract_error.py +67 -0
  52. omnibase_infra/services/contract_publisher/models/model_infra_error.py +62 -0
  53. omnibase_infra/services/contract_publisher/models/model_publish_result.py +112 -0
  54. omnibase_infra/services/contract_publisher/models/model_publish_stats.py +79 -0
  55. omnibase_infra/services/contract_publisher/service.py +617 -0
  56. omnibase_infra/services/contract_publisher/sources/__init__.py +52 -0
  57. omnibase_infra/services/contract_publisher/sources/model_discovered.py +155 -0
  58. omnibase_infra/services/contract_publisher/sources/protocol.py +101 -0
  59. omnibase_infra/services/contract_publisher/sources/source_composite.py +309 -0
  60. omnibase_infra/services/contract_publisher/sources/source_filesystem.py +174 -0
  61. omnibase_infra/services/contract_publisher/sources/source_package.py +221 -0
  62. omnibase_infra/services/observability/__init__.py +40 -0
  63. omnibase_infra/services/observability/agent_actions/__init__.py +64 -0
  64. omnibase_infra/services/observability/agent_actions/config.py +209 -0
  65. omnibase_infra/services/observability/agent_actions/consumer.py +1320 -0
  66. omnibase_infra/services/observability/agent_actions/models/__init__.py +87 -0
  67. omnibase_infra/services/observability/agent_actions/models/model_agent_action.py +142 -0
  68. omnibase_infra/services/observability/agent_actions/models/model_detection_failure.py +125 -0
  69. omnibase_infra/services/observability/agent_actions/models/model_envelope.py +85 -0
  70. omnibase_infra/services/observability/agent_actions/models/model_execution_log.py +159 -0
  71. omnibase_infra/services/observability/agent_actions/models/model_performance_metric.py +130 -0
  72. omnibase_infra/services/observability/agent_actions/models/model_routing_decision.py +138 -0
  73. omnibase_infra/services/observability/agent_actions/models/model_transformation_event.py +124 -0
  74. omnibase_infra/services/observability/agent_actions/tests/__init__.py +20 -0
  75. omnibase_infra/services/observability/agent_actions/tests/test_consumer.py +1154 -0
  76. omnibase_infra/services/observability/agent_actions/tests/test_models.py +645 -0
  77. omnibase_infra/services/observability/agent_actions/tests/test_writer.py +709 -0
  78. omnibase_infra/services/observability/agent_actions/writer_postgres.py +926 -0
  79. omnibase_infra/validation/__init__.py +12 -0
  80. omnibase_infra/validation/contracts/declarative_node.validation.yaml +143 -0
  81. omnibase_infra/validation/infra_validators.py +4 -1
  82. omnibase_infra/validation/validation_exemptions.yaml +111 -0
  83. omnibase_infra/validation/validator_declarative_node.py +850 -0
  84. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/METADATA +2 -2
  85. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/RECORD +88 -30
  86. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/WHEEL +0 -0
  87. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/entry_points.txt +0 -0
  88. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,87 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Observability Models for Agent Actions Consumer.
4
+
5
+ This package contains Pydantic models for the agent_actions observability
6
+ consumer. These models define the schema for events consumed from Kafka
7
+ and persisted to PostgreSQL.
8
+
9
+ Model Categories:
10
+ - Envelope (strict): ModelObservabilityEnvelope - common metadata fields
11
+ - Payload (flexible): All other models - required fields typed, extras allowed
12
+
13
+ Design Decisions:
14
+ - Envelope uses extra="forbid" for strict schema compliance
15
+ - Payload models use extra="allow" for Phase 1 flexibility
16
+ - All models have created_at for TTL readiness
17
+ - ModelExecutionLog has updated_at for lifecycle tracking
18
+ - Zero dict[str, Any] - use dict[str, object] when needed
19
+
20
+ Idempotency Keys (per table):
21
+ - agent_actions: id (UUID)
22
+ - agent_routing_decisions: id (UUID)
23
+ - agent_transformation_events: id (UUID)
24
+ - router_performance_metrics: id (UUID)
25
+ - agent_detection_failures: correlation_id (UUID)
26
+ - agent_execution_logs: execution_id (UUID)
27
+
28
+ Example:
29
+ >>> from omnibase_infra.services.observability.agent_actions.models import (
30
+ ... ModelObservabilityEnvelope,
31
+ ... ModelAgentAction,
32
+ ... ModelRoutingDecision,
33
+ ... )
34
+ >>> from datetime import datetime, UTC
35
+ >>> from uuid import uuid4
36
+ >>>
37
+ >>> # Strict envelope validation
38
+ >>> envelope = ModelObservabilityEnvelope(
39
+ ... event_id=uuid4(),
40
+ ... event_time=datetime.now(UTC),
41
+ ... producer_id="agent-observability-postgres",
42
+ ... schema_version="1.0.0",
43
+ ... )
44
+ >>>
45
+ >>> # Flexible payload - extras allowed
46
+ >>> action = ModelAgentAction(
47
+ ... id=uuid4(),
48
+ ... correlation_id=uuid4(),
49
+ ... agent_name="polymorphic-agent",
50
+ ... action_type="tool_call",
51
+ ... action_name="Read",
52
+ ... created_at=datetime.now(UTC),
53
+ ... custom_field="allowed in Phase 1", # extra field OK
54
+ ... )
55
+ """
56
+
57
+ from omnibase_infra.services.observability.agent_actions.models.model_agent_action import (
58
+ ModelAgentAction,
59
+ )
60
+ from omnibase_infra.services.observability.agent_actions.models.model_detection_failure import (
61
+ ModelDetectionFailure,
62
+ )
63
+ from omnibase_infra.services.observability.agent_actions.models.model_envelope import (
64
+ ModelObservabilityEnvelope,
65
+ )
66
+ from omnibase_infra.services.observability.agent_actions.models.model_execution_log import (
67
+ ModelExecutionLog,
68
+ )
69
+ from omnibase_infra.services.observability.agent_actions.models.model_performance_metric import (
70
+ ModelPerformanceMetric,
71
+ )
72
+ from omnibase_infra.services.observability.agent_actions.models.model_routing_decision import (
73
+ ModelRoutingDecision,
74
+ )
75
+ from omnibase_infra.services.observability.agent_actions.models.model_transformation_event import (
76
+ ModelTransformationEvent,
77
+ )
78
+
79
+ __all__ = [
80
+ "ModelAgentAction",
81
+ "ModelDetectionFailure",
82
+ "ModelExecutionLog",
83
+ "ModelObservabilityEnvelope",
84
+ "ModelPerformanceMetric",
85
+ "ModelRoutingDecision",
86
+ "ModelTransformationEvent",
87
+ ]
@@ -0,0 +1,142 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Agent Action Model.
4
+
5
+ This module defines the model for agent action events consumed from Kafka.
6
+ Agent actions represent individual tool calls, decisions, errors, and
7
+ successes recorded during agent execution.
8
+
9
+ Design Decisions:
10
+ - extra="allow": Phase 1 flexibility - required fields typed, extras preserved
11
+ - raw_payload: Optional field to preserve complete payload for schema tightening
12
+ - created_at: Required for TTL cleanup job (Phase 2)
13
+
14
+ Idempotency:
15
+ Table: agent_actions
16
+ Unique Key: id (UUID)
17
+ Conflict Action: DO NOTHING (append-only audit log)
18
+
19
+ Example:
20
+ >>> from datetime import datetime, UTC
21
+ >>> from uuid import uuid4
22
+ >>> action = ModelAgentAction(
23
+ ... id=uuid4(),
24
+ ... correlation_id=uuid4(),
25
+ ... agent_name="polymorphic-agent",
26
+ ... action_type="tool_call",
27
+ ... action_name="Bash",
28
+ ... created_at=datetime.now(UTC),
29
+ ... )
30
+ """
31
+
32
+ from datetime import datetime
33
+ from uuid import UUID
34
+
35
+ from pydantic import BaseModel, ConfigDict, Field
36
+
37
+ from omnibase_core.types import JsonType
38
+
39
+
40
+ class ModelAgentAction(BaseModel):
41
+ """Agent action event model.
42
+
43
+ Represents a single action performed by an agent, such as a tool call,
44
+ decision, error, or success. Uses extra="allow" for Phase 1 flexibility
45
+ while ensuring required fields are typed.
46
+
47
+ Attributes:
48
+ id: Unique identifier for this action (idempotency key).
49
+ correlation_id: Request correlation ID linking related actions.
50
+ agent_name: Name of the agent that performed this action.
51
+ action_type: Type of action (tool_call, decision, error, success).
52
+ action_name: Specific name of the action or tool.
53
+ created_at: Timestamp when the action was recorded (TTL key).
54
+ status: Optional status of the action (started, completed, failed).
55
+ duration_ms: Optional duration of the action in milliseconds.
56
+ result: Optional result summary or outcome.
57
+ error_message: Optional error message if action failed.
58
+ metadata: Optional additional metadata about the action.
59
+ raw_payload: Optional complete raw payload for Phase 2 schema tightening.
60
+
61
+ Example:
62
+ >>> action = ModelAgentAction(
63
+ ... id=uuid4(),
64
+ ... correlation_id=uuid4(),
65
+ ... agent_name="code-reviewer",
66
+ ... action_type="decision",
67
+ ... action_name="approve_pr",
68
+ ... created_at=datetime.now(UTC),
69
+ ... status="completed",
70
+ ... duration_ms=1234,
71
+ ... )
72
+ """
73
+
74
+ model_config = ConfigDict(
75
+ extra="allow",
76
+ from_attributes=True,
77
+ )
78
+
79
+ # ---- Required Fields ----
80
+ id: UUID = Field(
81
+ ...,
82
+ description="Unique identifier for this action (idempotency key).",
83
+ )
84
+ correlation_id: UUID = Field(
85
+ ...,
86
+ description="Request correlation ID linking related actions.",
87
+ )
88
+ agent_name: str = Field( # ONEX_EXCLUDE: entity_reference - external payload
89
+ ..., description="Name of the agent that performed this action."
90
+ )
91
+ action_type: str = Field(
92
+ ...,
93
+ description="Type of action (tool_call, decision, error, success).",
94
+ )
95
+ action_name: str = Field( # ONEX_EXCLUDE: entity_reference - external payload
96
+ ..., description="Specific name of the action or tool."
97
+ )
98
+ created_at: datetime = Field(
99
+ ...,
100
+ description="Timestamp when the action was recorded (TTL key).",
101
+ )
102
+
103
+ # ---- Optional Fields ----
104
+ status: str | None = Field(
105
+ default=None,
106
+ description="Status of the action (started, completed, failed).",
107
+ )
108
+ duration_ms: int | None = Field(
109
+ default=None,
110
+ description="Duration of the action in milliseconds.",
111
+ )
112
+ result: str | None = Field(
113
+ default=None,
114
+ description="Result summary or outcome of the action.",
115
+ )
116
+ error_message: str | None = Field(
117
+ default=None,
118
+ description="Error message if the action failed.",
119
+ )
120
+ metadata: dict[str, JsonType] | None = Field(
121
+ default=None,
122
+ description="Additional metadata about the action.",
123
+ )
124
+ raw_payload: dict[str, JsonType] | None = Field(
125
+ default=None,
126
+ description="Complete raw payload for Phase 2 schema tightening.",
127
+ )
128
+
129
+ def __str__(self) -> str:
130
+ """Return concise string representation for logging.
131
+
132
+ Includes key identifying fields but excludes metadata and raw_payload.
133
+ """
134
+ id_short = str(self.id)[:8]
135
+ status_part = f", status={self.status}" if self.status else ""
136
+ return (
137
+ f"AgentAction(id={id_short}, agent={self.agent_name}, "
138
+ f"type={self.action_type}, action={self.action_name}{status_part})"
139
+ )
140
+
141
+
142
+ __all__ = ["ModelAgentAction"]
@@ -0,0 +1,125 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Detection Failure Model.
4
+
5
+ This module defines the model for agent detection failure events consumed
6
+ from Kafka. Detection failures occur when the routing system cannot
7
+ determine an appropriate agent for a request.
8
+
9
+ Design Decisions:
10
+ - extra="allow": Phase 1 flexibility - required fields typed, extras preserved
11
+ - raw_payload: Optional field to preserve complete payload for schema tightening
12
+ - created_at: Required for TTL cleanup job (Phase 2)
13
+
14
+ Idempotency:
15
+ Table: agent_detection_failures
16
+ Unique Key: correlation_id (UUID) - one failure per correlation
17
+ Conflict Action: DO NOTHING
18
+
19
+ Example:
20
+ >>> from datetime import datetime, UTC
21
+ >>> from uuid import uuid4
22
+ >>> failure = ModelDetectionFailure(
23
+ ... correlation_id=uuid4(),
24
+ ... failure_reason="No matching agent pattern",
25
+ ... created_at=datetime.now(UTC),
26
+ ... )
27
+ """
28
+
29
+ from datetime import datetime
30
+ from uuid import UUID
31
+
32
+ from pydantic import BaseModel, ConfigDict, Field
33
+
34
+ from omnibase_core.types import JsonType
35
+
36
+
37
+ class ModelDetectionFailure(BaseModel):
38
+ """Agent detection failure event model.
39
+
40
+ Represents a failure to detect or route to an appropriate agent.
41
+ Used for analyzing routing coverage gaps and improving agent matching.
42
+
43
+ Attributes:
44
+ correlation_id: Request correlation ID (idempotency key - one per correlation).
45
+ failure_reason: Reason the detection failed.
46
+ created_at: Timestamp when the failure was recorded (TTL key).
47
+ request_summary: Optional summary of the request that failed routing.
48
+ attempted_patterns: Optional list of patterns attempted during detection.
49
+ fallback_used: Optional name of fallback agent if one was used.
50
+ error_code: Optional error code for categorization.
51
+ metadata: Optional additional metadata about the failure.
52
+ raw_payload: Optional complete raw payload for Phase 2 schema tightening.
53
+
54
+ Example:
55
+ >>> failure = ModelDetectionFailure(
56
+ ... correlation_id=uuid4(),
57
+ ... failure_reason="Confidence below threshold (0.3 < 0.5)",
58
+ ... created_at=datetime.now(UTC),
59
+ ... attempted_patterns=["code-review", "testing", "infrastructure"],
60
+ ... fallback_used="polymorphic-agent",
61
+ ... )
62
+ """
63
+
64
+ model_config = ConfigDict(
65
+ extra="allow",
66
+ from_attributes=True,
67
+ )
68
+
69
+ # ---- Required Fields ----
70
+ correlation_id: UUID = Field(
71
+ ...,
72
+ description="Request correlation ID (idempotency key - one per correlation).",
73
+ )
74
+ failure_reason: str = Field(
75
+ ...,
76
+ description="Reason the detection failed.",
77
+ )
78
+ created_at: datetime = Field(
79
+ ...,
80
+ description="Timestamp when the failure was recorded (TTL key).",
81
+ )
82
+
83
+ # ---- Optional Fields ----
84
+ request_summary: str | None = Field(
85
+ default=None,
86
+ description="Summary of the request that failed routing.",
87
+ )
88
+ attempted_patterns: list[str] | None = Field(
89
+ default=None,
90
+ description="List of patterns attempted during detection.",
91
+ )
92
+ fallback_used: str | None = Field(
93
+ default=None,
94
+ description="Name of fallback agent if one was used.",
95
+ )
96
+ error_code: str | None = Field(
97
+ default=None,
98
+ description="Error code for categorization.",
99
+ )
100
+ metadata: dict[str, JsonType] | None = Field(
101
+ default=None,
102
+ description="Additional metadata about the failure.",
103
+ )
104
+ raw_payload: dict[str, JsonType] | None = Field(
105
+ default=None,
106
+ description="Complete raw payload for Phase 2 schema tightening.",
107
+ )
108
+
109
+ def __str__(self) -> str:
110
+ """Return concise string representation for logging.
111
+
112
+ Includes key identifying fields but excludes metadata and raw_payload.
113
+ """
114
+ corr_short = str(self.correlation_id)[:8]
115
+ fallback_part = f", fallback={self.fallback_used}" if self.fallback_used else ""
116
+ # Truncate failure_reason to 50 chars for log readability
117
+ reason = (
118
+ self.failure_reason[:47] + "..."
119
+ if len(self.failure_reason) > 50
120
+ else self.failure_reason
121
+ )
122
+ return f"DetectionFailure(corr={corr_short}, reason={reason!r}{fallback_part})"
123
+
124
+
125
+ __all__ = ["ModelDetectionFailure"]
@@ -0,0 +1,85 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Observability Envelope Model.
4
+
5
+ This module defines the strict envelope model for all observability events.
6
+ The envelope contains common metadata fields that must be present on every
7
+ event consumed by the agent_actions observability consumer.
8
+
9
+ Design Decisions:
10
+ - extra="forbid": Strict validation ensures envelope schema compliance
11
+ - All fields are required or have explicit defaults
12
+ - correlation_id is optional (some events may not have request context)
13
+
14
+ Thread Safety:
15
+ ModelObservabilityEnvelope is immutable (frozen=True) after creation,
16
+ making it thread-safe for concurrent read access.
17
+
18
+ Example:
19
+ >>> from datetime import datetime, UTC
20
+ >>> from uuid import uuid4
21
+ >>> envelope = ModelObservabilityEnvelope(
22
+ ... event_id=uuid4(),
23
+ ... event_time=datetime.now(UTC),
24
+ ... producer_id="agent-observability-postgres",
25
+ ... schema_version="1.0.0",
26
+ ... correlation_id=uuid4(),
27
+ ... )
28
+ """
29
+
30
+ from datetime import datetime
31
+ from uuid import UUID
32
+
33
+ from pydantic import BaseModel, ConfigDict, Field
34
+
35
+
36
+ class ModelObservabilityEnvelope(BaseModel):
37
+ """Strict envelope for observability events.
38
+
39
+ All events must have these fields. The envelope is validated with
40
+ extra="forbid" to ensure no unexpected fields are present.
41
+
42
+ Attributes:
43
+ event_id: Unique identifier for this specific event instance.
44
+ event_time: Timestamp when the event was produced.
45
+ producer_id: Identifier of the service/component that produced the event.
46
+ schema_version: Version of the event schema for evolution tracking.
47
+ correlation_id: Optional request correlation ID for distributed tracing.
48
+
49
+ Example:
50
+ >>> envelope = ModelObservabilityEnvelope(
51
+ ... event_id=uuid4(),
52
+ ... event_time=datetime.now(UTC),
53
+ ... producer_id="claude-code-agent",
54
+ ... schema_version="1.0.0",
55
+ ... )
56
+ """
57
+
58
+ model_config = ConfigDict(
59
+ frozen=True,
60
+ extra="forbid",
61
+ from_attributes=True,
62
+ )
63
+
64
+ event_id: UUID = Field(
65
+ ...,
66
+ description="Unique identifier for this specific event instance.",
67
+ )
68
+ event_time: datetime = Field(
69
+ ...,
70
+ description="Timestamp when the event was produced.",
71
+ )
72
+ producer_id: str = Field( # ONEX_EXCLUDE: string_id - external service identifier
73
+ ..., description="Identifier of the service/component that produced the event."
74
+ )
75
+ schema_version: str = Field(
76
+ ...,
77
+ description="Version of the event schema for evolution tracking.",
78
+ )
79
+ correlation_id: UUID | None = Field(
80
+ default=None,
81
+ description="Optional request correlation ID for distributed tracing.",
82
+ )
83
+
84
+
85
+ __all__ = ["ModelObservabilityEnvelope"]
@@ -0,0 +1,159 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Execution Log Model.
4
+
5
+ This module defines the model for agent execution log events consumed
6
+ from Kafka. Execution logs track the full lifecycle of an agent execution,
7
+ from start to completion (or failure).
8
+
9
+ Design Decisions:
10
+ - extra="allow": Phase 1 flexibility - required fields typed, extras preserved
11
+ - raw_payload: Optional field to preserve complete payload for schema tightening
12
+ - created_at AND updated_at: Both required for lifecycle tracking and TTL
13
+ - TTL keys off updated_at (not created_at) to avoid deleting in-flight executions
14
+
15
+ Idempotency:
16
+ Table: agent_execution_logs
17
+ Unique Key: execution_id (UUID)
18
+ Conflict Action: DO UPDATE (lifecycle record - started -> completed)
19
+
20
+ Example:
21
+ >>> from datetime import datetime, UTC
22
+ >>> from uuid import uuid4
23
+ >>> log = ModelExecutionLog(
24
+ ... execution_id=uuid4(),
25
+ ... correlation_id=uuid4(),
26
+ ... agent_name="api-architect",
27
+ ... status="completed",
28
+ ... created_at=datetime.now(UTC),
29
+ ... updated_at=datetime.now(UTC),
30
+ ... )
31
+ """
32
+
33
+ from datetime import datetime
34
+ from uuid import UUID
35
+
36
+ from pydantic import BaseModel, ConfigDict, Field
37
+
38
+ from omnibase_core.types import JsonType
39
+
40
+
41
+ class ModelExecutionLog(BaseModel):
42
+ """Agent execution log event model.
43
+
44
+ Represents the lifecycle of an agent execution, from start to completion.
45
+ Unlike other observability models, this supports upsert semantics to track
46
+ status transitions (started -> running -> completed/failed).
47
+
48
+ Attributes:
49
+ execution_id: Unique identifier for this execution (idempotency key).
50
+ correlation_id: Request correlation ID linking related events.
51
+ agent_name: Name of the agent being executed.
52
+ status: Current status of the execution (started, running, completed, failed).
53
+ created_at: Timestamp when the execution started.
54
+ updated_at: Timestamp of last status update (TTL key for lifecycle records).
55
+ started_at: Optional explicit start timestamp.
56
+ completed_at: Optional completion timestamp.
57
+ duration_ms: Optional total duration in milliseconds.
58
+ exit_code: Optional exit code if execution completed.
59
+ error_message: Optional error message if execution failed.
60
+ input_summary: Optional summary of execution input.
61
+ output_summary: Optional summary of execution output.
62
+ metadata: Optional additional metadata about the execution.
63
+ raw_payload: Optional complete raw payload for Phase 2 schema tightening.
64
+
65
+ Example:
66
+ >>> log = ModelExecutionLog(
67
+ ... execution_id=uuid4(),
68
+ ... correlation_id=uuid4(),
69
+ ... agent_name="testing",
70
+ ... status="completed",
71
+ ... created_at=datetime.now(UTC),
72
+ ... updated_at=datetime.now(UTC),
73
+ ... duration_ms=5432,
74
+ ... exit_code=0,
75
+ ... )
76
+ """
77
+
78
+ model_config = ConfigDict(
79
+ extra="allow",
80
+ from_attributes=True,
81
+ )
82
+
83
+ # ---- Required Fields ----
84
+ execution_id: UUID = Field(
85
+ ...,
86
+ description="Unique identifier for this execution (idempotency key).",
87
+ )
88
+ correlation_id: UUID = Field(
89
+ ...,
90
+ description="Request correlation ID linking related events.",
91
+ )
92
+ agent_name: str = Field( # ONEX_EXCLUDE: entity_reference - external payload
93
+ ..., description="Name of the agent being executed."
94
+ )
95
+ status: str = Field( # ONEX_EXCLUDE: string_status - external payload
96
+ ..., description="Current status (started, running, completed, failed)."
97
+ )
98
+ created_at: datetime = Field(
99
+ ...,
100
+ description="Timestamp when the execution started.",
101
+ )
102
+ updated_at: datetime = Field(
103
+ ...,
104
+ description="Timestamp of last status update (TTL key for lifecycle records).",
105
+ )
106
+
107
+ # ---- Optional Fields ----
108
+ started_at: datetime | None = Field(
109
+ default=None,
110
+ description="Explicit start timestamp.",
111
+ )
112
+ completed_at: datetime | None = Field(
113
+ default=None,
114
+ description="Completion timestamp.",
115
+ )
116
+ duration_ms: int | None = Field(
117
+ default=None,
118
+ description="Total duration in milliseconds.",
119
+ )
120
+ exit_code: int | None = Field(
121
+ default=None,
122
+ description="Exit code if execution completed.",
123
+ )
124
+ error_message: str | None = Field(
125
+ default=None,
126
+ description="Error message if execution failed.",
127
+ )
128
+ input_summary: str | None = Field(
129
+ default=None,
130
+ description="Summary of execution input.",
131
+ )
132
+ output_summary: str | None = Field(
133
+ default=None,
134
+ description="Summary of execution output.",
135
+ )
136
+ metadata: dict[str, JsonType] | None = Field(
137
+ default=None,
138
+ description="Additional metadata about the execution.",
139
+ )
140
+ raw_payload: dict[str, JsonType] | None = Field(
141
+ default=None,
142
+ description="Complete raw payload for Phase 2 schema tightening.",
143
+ )
144
+
145
+ def __str__(self) -> str:
146
+ """Return concise string representation for logging.
147
+
148
+ Includes key identifying fields but excludes metadata and raw_payload.
149
+ """
150
+ exec_short = str(self.execution_id)[:8]
151
+ duration_part = f", duration={self.duration_ms}ms" if self.duration_ms else ""
152
+ exit_part = f", exit={self.exit_code}" if self.exit_code is not None else ""
153
+ return (
154
+ f"ExecutionLog(id={exec_short}, agent={self.agent_name}, "
155
+ f"status={self.status}{duration_part}{exit_part})"
156
+ )
157
+
158
+
159
+ __all__ = ["ModelExecutionLog"]