ouroboros-ai 0.1.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.
Potentially problematic release.
This version of ouroboros-ai might be problematic. Click here for more details.
- ouroboros/__init__.py +15 -0
- ouroboros/__main__.py +9 -0
- ouroboros/bigbang/__init__.py +39 -0
- ouroboros/bigbang/ambiguity.py +464 -0
- ouroboros/bigbang/interview.py +530 -0
- ouroboros/bigbang/seed_generator.py +610 -0
- ouroboros/cli/__init__.py +9 -0
- ouroboros/cli/commands/__init__.py +7 -0
- ouroboros/cli/commands/config.py +79 -0
- ouroboros/cli/commands/init.py +425 -0
- ouroboros/cli/commands/run.py +201 -0
- ouroboros/cli/commands/status.py +85 -0
- ouroboros/cli/formatters/__init__.py +31 -0
- ouroboros/cli/formatters/panels.py +157 -0
- ouroboros/cli/formatters/progress.py +112 -0
- ouroboros/cli/formatters/tables.py +166 -0
- ouroboros/cli/main.py +60 -0
- ouroboros/config/__init__.py +81 -0
- ouroboros/config/loader.py +292 -0
- ouroboros/config/models.py +332 -0
- ouroboros/core/__init__.py +62 -0
- ouroboros/core/ac_tree.py +401 -0
- ouroboros/core/context.py +472 -0
- ouroboros/core/errors.py +246 -0
- ouroboros/core/seed.py +212 -0
- ouroboros/core/types.py +205 -0
- ouroboros/evaluation/__init__.py +110 -0
- ouroboros/evaluation/consensus.py +350 -0
- ouroboros/evaluation/mechanical.py +351 -0
- ouroboros/evaluation/models.py +235 -0
- ouroboros/evaluation/pipeline.py +286 -0
- ouroboros/evaluation/semantic.py +302 -0
- ouroboros/evaluation/trigger.py +278 -0
- ouroboros/events/__init__.py +5 -0
- ouroboros/events/base.py +80 -0
- ouroboros/events/decomposition.py +153 -0
- ouroboros/events/evaluation.py +248 -0
- ouroboros/execution/__init__.py +44 -0
- ouroboros/execution/atomicity.py +451 -0
- ouroboros/execution/decomposition.py +481 -0
- ouroboros/execution/double_diamond.py +1386 -0
- ouroboros/execution/subagent.py +275 -0
- ouroboros/observability/__init__.py +63 -0
- ouroboros/observability/drift.py +383 -0
- ouroboros/observability/logging.py +504 -0
- ouroboros/observability/retrospective.py +338 -0
- ouroboros/orchestrator/__init__.py +78 -0
- ouroboros/orchestrator/adapter.py +391 -0
- ouroboros/orchestrator/events.py +278 -0
- ouroboros/orchestrator/runner.py +597 -0
- ouroboros/orchestrator/session.py +486 -0
- ouroboros/persistence/__init__.py +23 -0
- ouroboros/persistence/checkpoint.py +511 -0
- ouroboros/persistence/event_store.py +183 -0
- ouroboros/persistence/migrations/__init__.py +1 -0
- ouroboros/persistence/migrations/runner.py +100 -0
- ouroboros/persistence/migrations/scripts/001_initial.sql +20 -0
- ouroboros/persistence/schema.py +56 -0
- ouroboros/persistence/uow.py +230 -0
- ouroboros/providers/__init__.py +28 -0
- ouroboros/providers/base.py +133 -0
- ouroboros/providers/claude_code_adapter.py +212 -0
- ouroboros/providers/litellm_adapter.py +316 -0
- ouroboros/py.typed +0 -0
- ouroboros/resilience/__init__.py +67 -0
- ouroboros/resilience/lateral.py +595 -0
- ouroboros/resilience/stagnation.py +727 -0
- ouroboros/routing/__init__.py +60 -0
- ouroboros/routing/complexity.py +272 -0
- ouroboros/routing/downgrade.py +664 -0
- ouroboros/routing/escalation.py +340 -0
- ouroboros/routing/router.py +204 -0
- ouroboros/routing/tiers.py +247 -0
- ouroboros/secondary/__init__.py +40 -0
- ouroboros/secondary/scheduler.py +467 -0
- ouroboros/secondary/todo_registry.py +483 -0
- ouroboros_ai-0.1.0.dist-info/METADATA +607 -0
- ouroboros_ai-0.1.0.dist-info/RECORD +81 -0
- ouroboros_ai-0.1.0.dist-info/WHEEL +4 -0
- ouroboros_ai-0.1.0.dist-info/entry_points.txt +2 -0
- ouroboros_ai-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""SubAgent isolation and lifecycle management.
|
|
2
|
+
|
|
3
|
+
This module provides:
|
|
4
|
+
- SubAgent result validation
|
|
5
|
+
- SubAgent lifecycle events (started, completed, failed)
|
|
6
|
+
- Error handling that doesn't propagate to parent execution
|
|
7
|
+
|
|
8
|
+
Story 3.4: SubAgent Isolation
|
|
9
|
+
- AC 1, 2: SubAgents receive filtered context
|
|
10
|
+
- AC 3: Main context not modified by SubAgent
|
|
11
|
+
- AC 4: SubAgent results validated before integration
|
|
12
|
+
- AC 5: Failed SubAgent doesn't crash main execution
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import TYPE_CHECKING, Any
|
|
18
|
+
|
|
19
|
+
from ouroboros.core.errors import OuroborosError
|
|
20
|
+
from ouroboros.core.types import Result
|
|
21
|
+
from ouroboros.events.base import BaseEvent
|
|
22
|
+
from ouroboros.observability.logging import get_logger
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from ouroboros.execution.double_diamond import CycleResult
|
|
26
|
+
|
|
27
|
+
log = get_logger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# =============================================================================
|
|
31
|
+
# Errors
|
|
32
|
+
# =============================================================================
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class SubAgentError(OuroborosError):
|
|
36
|
+
"""Error during SubAgent execution.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
subagent_id: The SubAgent execution ID.
|
|
40
|
+
parent_id: The parent execution ID.
|
|
41
|
+
is_retriable: Whether the error is potentially retriable.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
message: str,
|
|
47
|
+
*,
|
|
48
|
+
subagent_id: str | None = None,
|
|
49
|
+
parent_id: str | None = None,
|
|
50
|
+
is_retriable: bool = False,
|
|
51
|
+
details: dict[str, Any] | None = None,
|
|
52
|
+
) -> None:
|
|
53
|
+
super().__init__(message, details)
|
|
54
|
+
self.subagent_id = subagent_id
|
|
55
|
+
self.parent_id = parent_id
|
|
56
|
+
self.is_retriable = is_retriable
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ValidationError(SubAgentError):
|
|
60
|
+
"""Error during SubAgent result validation."""
|
|
61
|
+
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# =============================================================================
|
|
66
|
+
# Result Validation (AC 4)
|
|
67
|
+
# =============================================================================
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def validate_child_result(
|
|
71
|
+
child_result: CycleResult,
|
|
72
|
+
expected_ac: str, # noqa: ARG001 - reserved for future semantic validation
|
|
73
|
+
) -> Result[CycleResult, ValidationError]:
|
|
74
|
+
"""Validate a child SubAgent result before integration.
|
|
75
|
+
|
|
76
|
+
This function performs structural validation:
|
|
77
|
+
- Success status check
|
|
78
|
+
- Required phases present (for non-decomposed results)
|
|
79
|
+
- AC content matches expected
|
|
80
|
+
|
|
81
|
+
Semantic validation (goal alignment, drift) is deferred to Epic 5 Stage 2.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
child_result: The CycleResult from child SubAgent execution.
|
|
85
|
+
expected_ac: The expected acceptance criterion content.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Result containing the validated CycleResult or ValidationError.
|
|
89
|
+
"""
|
|
90
|
+
from ouroboros.execution.double_diamond import Phase
|
|
91
|
+
|
|
92
|
+
# Check success status
|
|
93
|
+
if not child_result.success:
|
|
94
|
+
log.warning(
|
|
95
|
+
"subagent.validation.unsuccessful",
|
|
96
|
+
execution_id=child_result.execution_id,
|
|
97
|
+
current_ac=child_result.current_ac[:50],
|
|
98
|
+
)
|
|
99
|
+
return Result.err(
|
|
100
|
+
ValidationError(
|
|
101
|
+
f"Child result unsuccessful: {child_result.execution_id}",
|
|
102
|
+
subagent_id=child_result.execution_id,
|
|
103
|
+
is_retriable=False,
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# For non-decomposed results, check required phases
|
|
108
|
+
if not child_result.is_decomposed:
|
|
109
|
+
required_phases = {Phase.DISCOVER, Phase.DEFINE, Phase.DESIGN, Phase.DELIVER}
|
|
110
|
+
present_phases = set(child_result.phase_results.keys())
|
|
111
|
+
missing_phases = required_phases - present_phases
|
|
112
|
+
|
|
113
|
+
if missing_phases:
|
|
114
|
+
log.warning(
|
|
115
|
+
"subagent.validation.missing_phases",
|
|
116
|
+
execution_id=child_result.execution_id,
|
|
117
|
+
missing=[p.value for p in missing_phases],
|
|
118
|
+
)
|
|
119
|
+
return Result.err(
|
|
120
|
+
ValidationError(
|
|
121
|
+
f"Missing required phases: {[p.value for p in missing_phases]}",
|
|
122
|
+
subagent_id=child_result.execution_id,
|
|
123
|
+
is_retriable=False,
|
|
124
|
+
details={"missing_phases": [p.value for p in missing_phases]},
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
# Decomposed results only need DISCOVER and DEFINE phases
|
|
129
|
+
required_phases = {Phase.DISCOVER, Phase.DEFINE}
|
|
130
|
+
present_phases = set(child_result.phase_results.keys())
|
|
131
|
+
missing_phases = required_phases - present_phases
|
|
132
|
+
|
|
133
|
+
if missing_phases:
|
|
134
|
+
log.warning(
|
|
135
|
+
"subagent.validation.missing_phases_decomposed",
|
|
136
|
+
execution_id=child_result.execution_id,
|
|
137
|
+
missing=[p.value for p in missing_phases],
|
|
138
|
+
)
|
|
139
|
+
return Result.err(
|
|
140
|
+
ValidationError(
|
|
141
|
+
f"Decomposed result missing phases: {[p.value for p in missing_phases]}",
|
|
142
|
+
subagent_id=child_result.execution_id,
|
|
143
|
+
is_retriable=False,
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
log.info(
|
|
148
|
+
"subagent.validation.passed",
|
|
149
|
+
execution_id=child_result.execution_id,
|
|
150
|
+
is_decomposed=child_result.is_decomposed,
|
|
151
|
+
phase_count=len(child_result.phase_results),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return Result.ok(child_result)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# =============================================================================
|
|
158
|
+
# Lifecycle Events
|
|
159
|
+
# =============================================================================
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def create_subagent_started_event(
|
|
163
|
+
subagent_id: str,
|
|
164
|
+
parent_execution_id: str,
|
|
165
|
+
child_ac: str,
|
|
166
|
+
depth: int,
|
|
167
|
+
) -> BaseEvent:
|
|
168
|
+
"""Create event for SubAgent execution start.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
subagent_id: The SubAgent execution ID.
|
|
172
|
+
parent_execution_id: The parent execution ID.
|
|
173
|
+
child_ac: The acceptance criterion for this SubAgent.
|
|
174
|
+
depth: Current depth in AC decomposition tree.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
BaseEvent with type 'execution.subagent.started'.
|
|
178
|
+
"""
|
|
179
|
+
return BaseEvent(
|
|
180
|
+
type="execution.subagent.started",
|
|
181
|
+
aggregate_type="execution",
|
|
182
|
+
aggregate_id=subagent_id,
|
|
183
|
+
data={
|
|
184
|
+
"parent_execution_id": parent_execution_id,
|
|
185
|
+
"child_ac": child_ac[:200], # Truncate for storage
|
|
186
|
+
"depth": depth,
|
|
187
|
+
},
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def create_subagent_completed_event(
|
|
192
|
+
subagent_id: str,
|
|
193
|
+
parent_execution_id: str,
|
|
194
|
+
success: bool,
|
|
195
|
+
child_count: int = 0,
|
|
196
|
+
) -> BaseEvent:
|
|
197
|
+
"""Create event for SubAgent execution completion.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
subagent_id: The SubAgent execution ID.
|
|
201
|
+
parent_execution_id: The parent execution ID.
|
|
202
|
+
success: Whether the SubAgent completed successfully.
|
|
203
|
+
child_count: Number of child SubAgents spawned (if decomposed).
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
BaseEvent with type 'execution.subagent.completed'.
|
|
207
|
+
"""
|
|
208
|
+
return BaseEvent(
|
|
209
|
+
type="execution.subagent.completed",
|
|
210
|
+
aggregate_type="execution",
|
|
211
|
+
aggregate_id=subagent_id,
|
|
212
|
+
data={
|
|
213
|
+
"parent_execution_id": parent_execution_id,
|
|
214
|
+
"success": success,
|
|
215
|
+
"child_count": child_count,
|
|
216
|
+
},
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def create_subagent_failed_event(
|
|
221
|
+
subagent_id: str,
|
|
222
|
+
parent_execution_id: str,
|
|
223
|
+
error_message: str,
|
|
224
|
+
is_retriable: bool = False,
|
|
225
|
+
) -> BaseEvent:
|
|
226
|
+
"""Create event for SubAgent execution failure.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
subagent_id: The SubAgent execution ID.
|
|
230
|
+
parent_execution_id: The parent execution ID.
|
|
231
|
+
error_message: Description of the failure.
|
|
232
|
+
is_retriable: Whether the failure might be resolved by retry.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
BaseEvent with type 'execution.subagent.failed'.
|
|
236
|
+
"""
|
|
237
|
+
return BaseEvent(
|
|
238
|
+
type="execution.subagent.failed",
|
|
239
|
+
aggregate_type="execution",
|
|
240
|
+
aggregate_id=subagent_id,
|
|
241
|
+
data={
|
|
242
|
+
"parent_execution_id": parent_execution_id,
|
|
243
|
+
"error_message": error_message[:500], # Truncate for storage
|
|
244
|
+
"is_retriable": is_retriable,
|
|
245
|
+
},
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def create_subagent_validated_event(
|
|
250
|
+
subagent_id: str,
|
|
251
|
+
parent_execution_id: str,
|
|
252
|
+
validation_passed: bool,
|
|
253
|
+
validation_message: str = "",
|
|
254
|
+
) -> BaseEvent:
|
|
255
|
+
"""Create event for SubAgent result validation.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
subagent_id: The SubAgent execution ID.
|
|
259
|
+
parent_execution_id: The parent execution ID.
|
|
260
|
+
validation_passed: Whether validation passed.
|
|
261
|
+
validation_message: Additional validation details.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
BaseEvent with type 'execution.subagent.validated'.
|
|
265
|
+
"""
|
|
266
|
+
return BaseEvent(
|
|
267
|
+
type="execution.subagent.validated",
|
|
268
|
+
aggregate_type="execution",
|
|
269
|
+
aggregate_id=subagent_id,
|
|
270
|
+
data={
|
|
271
|
+
"parent_execution_id": parent_execution_id,
|
|
272
|
+
"validation_passed": validation_passed,
|
|
273
|
+
"validation_message": validation_message[:200],
|
|
274
|
+
},
|
|
275
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Observability module for Ouroboros.
|
|
2
|
+
|
|
3
|
+
This module provides structured logging, drift measurement, and retrospective
|
|
4
|
+
analysis for observability across the application.
|
|
5
|
+
|
|
6
|
+
Main components:
|
|
7
|
+
- Logging: configure_logging, get_logger, bind_context, unbind_context
|
|
8
|
+
- Drift: DriftMeasurement, DriftMetrics for goal alignment tracking
|
|
9
|
+
- Retrospective: RetrospectiveAnalyzer for periodic self-assessment
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from ouroboros.observability.drift import (
|
|
13
|
+
DRIFT_THRESHOLD,
|
|
14
|
+
DriftMeasuredEvent,
|
|
15
|
+
DriftMeasurement,
|
|
16
|
+
DriftMetrics,
|
|
17
|
+
DriftThresholdExceededEvent,
|
|
18
|
+
calculate_constraint_drift,
|
|
19
|
+
calculate_goal_drift,
|
|
20
|
+
calculate_ontology_drift,
|
|
21
|
+
)
|
|
22
|
+
from ouroboros.observability.logging import (
|
|
23
|
+
LoggingConfig,
|
|
24
|
+
LogMode,
|
|
25
|
+
bind_context,
|
|
26
|
+
configure_logging,
|
|
27
|
+
get_logger,
|
|
28
|
+
unbind_context,
|
|
29
|
+
)
|
|
30
|
+
from ouroboros.observability.retrospective import (
|
|
31
|
+
DEFAULT_RETROSPECTIVE_INTERVAL,
|
|
32
|
+
HumanAttentionRequiredEvent,
|
|
33
|
+
RetrospectiveAnalyzer,
|
|
34
|
+
RetrospectiveCompletedEvent,
|
|
35
|
+
RetrospectiveResult,
|
|
36
|
+
should_trigger_retrospective,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
# Logging
|
|
41
|
+
"LogMode",
|
|
42
|
+
"LoggingConfig",
|
|
43
|
+
"bind_context",
|
|
44
|
+
"configure_logging",
|
|
45
|
+
"get_logger",
|
|
46
|
+
"unbind_context",
|
|
47
|
+
# Drift
|
|
48
|
+
"DRIFT_THRESHOLD",
|
|
49
|
+
"DriftMeasuredEvent",
|
|
50
|
+
"DriftMeasurement",
|
|
51
|
+
"DriftMetrics",
|
|
52
|
+
"DriftThresholdExceededEvent",
|
|
53
|
+
"calculate_constraint_drift",
|
|
54
|
+
"calculate_goal_drift",
|
|
55
|
+
"calculate_ontology_drift",
|
|
56
|
+
# Retrospective
|
|
57
|
+
"DEFAULT_RETROSPECTIVE_INTERVAL",
|
|
58
|
+
"HumanAttentionRequiredEvent",
|
|
59
|
+
"RetrospectiveAnalyzer",
|
|
60
|
+
"RetrospectiveCompletedEvent",
|
|
61
|
+
"RetrospectiveResult",
|
|
62
|
+
"should_trigger_retrospective",
|
|
63
|
+
]
|