ouroboros-ai 0.2.3__py3-none-any.whl → 0.4.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 +1 -1
- ouroboros/bigbang/__init__.py +9 -0
- ouroboros/bigbang/interview.py +16 -18
- ouroboros/bigbang/ontology.py +180 -0
- ouroboros/cli/commands/__init__.py +2 -0
- ouroboros/cli/commands/init.py +162 -97
- ouroboros/cli/commands/mcp.py +161 -0
- ouroboros/cli/commands/run.py +165 -27
- ouroboros/cli/main.py +2 -1
- ouroboros/core/ontology_aspect.py +455 -0
- ouroboros/core/ontology_questions.py +462 -0
- ouroboros/evaluation/__init__.py +16 -1
- ouroboros/evaluation/consensus.py +569 -11
- ouroboros/evaluation/models.py +81 -0
- ouroboros/events/ontology.py +135 -0
- ouroboros/mcp/__init__.py +83 -0
- ouroboros/mcp/client/__init__.py +20 -0
- ouroboros/mcp/client/adapter.py +632 -0
- ouroboros/mcp/client/manager.py +600 -0
- ouroboros/mcp/client/protocol.py +161 -0
- ouroboros/mcp/errors.py +377 -0
- ouroboros/mcp/resources/__init__.py +22 -0
- ouroboros/mcp/resources/handlers.py +328 -0
- ouroboros/mcp/server/__init__.py +21 -0
- ouroboros/mcp/server/adapter.py +408 -0
- ouroboros/mcp/server/protocol.py +291 -0
- ouroboros/mcp/server/security.py +636 -0
- ouroboros/mcp/tools/__init__.py +24 -0
- ouroboros/mcp/tools/definitions.py +351 -0
- ouroboros/mcp/tools/registry.py +269 -0
- ouroboros/mcp/types.py +333 -0
- ouroboros/orchestrator/__init__.py +31 -0
- ouroboros/orchestrator/events.py +40 -0
- ouroboros/orchestrator/mcp_config.py +419 -0
- ouroboros/orchestrator/mcp_tools.py +483 -0
- ouroboros/orchestrator/runner.py +119 -2
- ouroboros/providers/claude_code_adapter.py +75 -0
- ouroboros/strategies/__init__.py +23 -0
- ouroboros/strategies/devil_advocate.py +197 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/METADATA +73 -17
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/RECORD +44 -19
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/WHEEL +0 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/entry_points.txt +0 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
"""AOP Framework for Ontological Analysis.
|
|
2
|
+
|
|
3
|
+
This module provides Aspect-Oriented Programming capabilities for
|
|
4
|
+
applying ontological analysis as a cross-cutting concern across
|
|
5
|
+
Interview, Consensus, and Resilience phases.
|
|
6
|
+
|
|
7
|
+
Pattern: Protocol + Strategy + Dependency Injection
|
|
8
|
+
- OntologicalAspect: Central weaver (Around Advice)
|
|
9
|
+
- OntologyStrategy: Protocol for join-point-specific analysis
|
|
10
|
+
- TTLCache: Performance optimization for LLM calls
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
# Create aspect with strategy
|
|
14
|
+
aspect = OntologicalAspect(
|
|
15
|
+
strategy=DevilAdvocateStrategy(llm_adapter),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Execute with ontological analysis
|
|
19
|
+
result = await aspect.execute(
|
|
20
|
+
context=consensus_context,
|
|
21
|
+
core_operation=lambda ctx: consensus.deliberate(ctx),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
Design Reference: docs/ontological-framework/aop-design.md
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from collections.abc import Awaitable, Callable
|
|
30
|
+
from dataclasses import dataclass, field
|
|
31
|
+
from enum import StrEnum
|
|
32
|
+
import logging
|
|
33
|
+
from typing import TYPE_CHECKING, Any, Generic, Protocol, TypeVar
|
|
34
|
+
|
|
35
|
+
from cachetools import TTLCache
|
|
36
|
+
|
|
37
|
+
from ouroboros.core.errors import OuroborosError
|
|
38
|
+
from ouroboros.core.types import Result
|
|
39
|
+
|
|
40
|
+
if TYPE_CHECKING:
|
|
41
|
+
from ouroboros.events.base import BaseEvent
|
|
42
|
+
|
|
43
|
+
log = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# =============================================================================
|
|
47
|
+
# Core Types
|
|
48
|
+
# =============================================================================
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class OntologicalJoinPoint(StrEnum):
|
|
52
|
+
"""Join points where ontological analysis is applied.
|
|
53
|
+
|
|
54
|
+
These correspond to Ouroboros phases where cross-cutting
|
|
55
|
+
ontological concerns are relevant.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
INTERVIEW = "interview"
|
|
59
|
+
"""Phase 0: Requirement clarification - ensures user asks about root problem."""
|
|
60
|
+
|
|
61
|
+
RESILIENCE = "resilience"
|
|
62
|
+
"""Phase 3: Stagnation recovery - CONTRARIAN challenges assumptions."""
|
|
63
|
+
|
|
64
|
+
CONSENSUS = "consensus"
|
|
65
|
+
"""Phase 4: Result evaluation - Devil's Advocate checks root vs symptom."""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True, slots=True)
|
|
69
|
+
class AnalysisResult:
|
|
70
|
+
"""Result of ontological analysis by a Strategy.
|
|
71
|
+
|
|
72
|
+
This represents the AOP verdict (valid/invalid) rather than
|
|
73
|
+
the full ontological insight content.
|
|
74
|
+
|
|
75
|
+
Attributes:
|
|
76
|
+
is_valid: Whether the subject passes ontological scrutiny.
|
|
77
|
+
confidence: Analysis confidence (0.0-1.0).
|
|
78
|
+
reasoning: Explanation of the verdict.
|
|
79
|
+
suggestions: Refinement suggestions if invalid.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
is_valid: bool
|
|
83
|
+
confidence: float
|
|
84
|
+
reasoning: tuple[str, ...]
|
|
85
|
+
suggestions: tuple[str, ...]
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def needs_refinement(self) -> bool:
|
|
89
|
+
"""True if invalid and has actionable suggestions."""
|
|
90
|
+
return not self.is_valid and len(self.suggestions) > 0
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def valid(
|
|
94
|
+
cls,
|
|
95
|
+
confidence: float = 1.0,
|
|
96
|
+
reasoning: tuple[str, ...] | list[str] = (),
|
|
97
|
+
) -> AnalysisResult:
|
|
98
|
+
"""Create a passing result."""
|
|
99
|
+
return cls(
|
|
100
|
+
is_valid=True,
|
|
101
|
+
confidence=confidence,
|
|
102
|
+
reasoning=tuple(reasoning) if isinstance(reasoning, list) else reasoning,
|
|
103
|
+
suggestions=(),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def invalid(
|
|
108
|
+
cls,
|
|
109
|
+
reasoning: tuple[str, ...] | list[str],
|
|
110
|
+
suggestions: tuple[str, ...] | list[str] = (),
|
|
111
|
+
confidence: float = 0.8,
|
|
112
|
+
) -> AnalysisResult:
|
|
113
|
+
"""Create a failing result."""
|
|
114
|
+
return cls(
|
|
115
|
+
is_valid=False,
|
|
116
|
+
confidence=confidence,
|
|
117
|
+
reasoning=tuple(reasoning) if isinstance(reasoning, list) else reasoning,
|
|
118
|
+
suggestions=tuple(suggestions) if isinstance(suggestions, list) else suggestions,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class OntologicalViolationError(OuroborosError):
|
|
123
|
+
"""Error raised when ontological analysis blocks execution.
|
|
124
|
+
|
|
125
|
+
This error contains the analysis result explaining why
|
|
126
|
+
the operation was halted.
|
|
127
|
+
|
|
128
|
+
Attributes:
|
|
129
|
+
result: The AnalysisResult that caused the violation.
|
|
130
|
+
join_point: Which phase triggered the violation.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def __init__(
|
|
134
|
+
self,
|
|
135
|
+
result: AnalysisResult,
|
|
136
|
+
*,
|
|
137
|
+
join_point: OntologicalJoinPoint | None = None,
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Initialize violation error.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
result: The analysis result that caused the violation.
|
|
143
|
+
join_point: Which phase triggered this error.
|
|
144
|
+
"""
|
|
145
|
+
self.result = result
|
|
146
|
+
self.join_point = join_point
|
|
147
|
+
super().__init__(
|
|
148
|
+
message="Ontological violation: analysis blocked execution",
|
|
149
|
+
details={
|
|
150
|
+
"is_valid": result.is_valid,
|
|
151
|
+
"confidence": result.confidence,
|
|
152
|
+
"reasoning": result.reasoning,
|
|
153
|
+
"suggestions": result.suggestions,
|
|
154
|
+
"join_point": join_point.value if join_point else None,
|
|
155
|
+
},
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# =============================================================================
|
|
160
|
+
# Strategy Protocol
|
|
161
|
+
# =============================================================================
|
|
162
|
+
|
|
163
|
+
C = TypeVar("C", contravariant=True) # Context type (input)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class OntologyStrategy(Protocol[C]):
|
|
167
|
+
"""Protocol for join-point-specific ontological analysis.
|
|
168
|
+
|
|
169
|
+
Each Strategy implements phase-specific logic:
|
|
170
|
+
- InterviewOntologyStrategy: Checks if user asks about root problem
|
|
171
|
+
- DevilAdvocateStrategy: Validates solution addresses root cause
|
|
172
|
+
- ContrarianStrategy: Challenges assumptions when stuck
|
|
173
|
+
|
|
174
|
+
Key Design Decision:
|
|
175
|
+
Strategy provides get_cache_key(), not Aspect.
|
|
176
|
+
This allows fine-grained control over what matters for caching.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def join_point(self) -> OntologicalJoinPoint:
|
|
181
|
+
"""Which phase this strategy is for."""
|
|
182
|
+
...
|
|
183
|
+
|
|
184
|
+
def get_cache_key(self, context: C) -> str:
|
|
185
|
+
"""Return cache key for this context.
|
|
186
|
+
|
|
187
|
+
Strategy decides which parts of context are relevant for caching.
|
|
188
|
+
Example: Consensus only cares about artifact hash, not full state.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
context: The analysis context.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
A string cache key.
|
|
195
|
+
"""
|
|
196
|
+
...
|
|
197
|
+
|
|
198
|
+
async def analyze(self, context: C) -> AnalysisResult:
|
|
199
|
+
"""Perform ontological analysis on the given context.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
context: Phase-specific context.
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
AnalysisResult with validity, confidence, and reasoning.
|
|
206
|
+
"""
|
|
207
|
+
...
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# =============================================================================
|
|
211
|
+
# Ontological Aspect (Weaver)
|
|
212
|
+
# =============================================================================
|
|
213
|
+
|
|
214
|
+
T = TypeVar("T") # Result type (output)
|
|
215
|
+
E = TypeVar("E", bound=OuroborosError) # Error type
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@dataclass
|
|
219
|
+
class OntologicalAspect(Generic[C, T, E]):
|
|
220
|
+
"""Central AOP Weaver for Ontological Analysis.
|
|
221
|
+
|
|
222
|
+
Implements the "Around Advice" pattern:
|
|
223
|
+
1. Pre-execution: Run ontological analysis
|
|
224
|
+
2. Decision: Proceed or halt based on analysis
|
|
225
|
+
3. Execution: Run core operation if valid
|
|
226
|
+
4. Post-execution: Emit events
|
|
227
|
+
|
|
228
|
+
Type Parameters:
|
|
229
|
+
C: Context type passed to strategy
|
|
230
|
+
T: Success type from core operation
|
|
231
|
+
E: Error type from core operation (must extend OuroborosError)
|
|
232
|
+
|
|
233
|
+
Configuration:
|
|
234
|
+
halt_on_violation: Return error on ontological failure (default: True)
|
|
235
|
+
strict_mode: Fail closed on LLM errors (default: True)
|
|
236
|
+
cache_ttl: Cache TTL in seconds (default: 300)
|
|
237
|
+
cache_maxsize: Max cached entries (default: 100)
|
|
238
|
+
|
|
239
|
+
Example:
|
|
240
|
+
aspect = OntologicalAspect(
|
|
241
|
+
strategy=DevilAdvocateStrategy(llm),
|
|
242
|
+
event_emitter=event_store.emit,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
result = await aspect.execute(
|
|
246
|
+
context=consensus_context,
|
|
247
|
+
core_operation=lambda ctx: consensus.deliberate(ctx),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if result.is_err:
|
|
251
|
+
if isinstance(result.error, OntologicalViolationError):
|
|
252
|
+
# Handle ontological violation
|
|
253
|
+
print(result.error.result.suggestions)
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
strategy: OntologyStrategy[C]
|
|
257
|
+
event_emitter: Callable[[BaseEvent], Awaitable[None]] | None = None
|
|
258
|
+
halt_on_violation: bool = True
|
|
259
|
+
strict_mode: bool = True # fail_closed by default
|
|
260
|
+
cache_ttl: int = 300 # 5 minutes
|
|
261
|
+
cache_maxsize: int = 100
|
|
262
|
+
_cache: TTLCache[str, AnalysisResult] = field(
|
|
263
|
+
default_factory=lambda: TTLCache(maxsize=100, ttl=300),
|
|
264
|
+
repr=False,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def __post_init__(self) -> None:
|
|
268
|
+
"""Initialize cache with configured TTL and maxsize."""
|
|
269
|
+
# Recreate cache with actual config values if they differ from defaults
|
|
270
|
+
if self.cache_ttl != 300 or self.cache_maxsize != 100:
|
|
271
|
+
object.__setattr__(
|
|
272
|
+
self,
|
|
273
|
+
"_cache",
|
|
274
|
+
TTLCache(maxsize=self.cache_maxsize, ttl=self.cache_ttl),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
async def execute(
|
|
278
|
+
self,
|
|
279
|
+
context: C,
|
|
280
|
+
core_operation: Callable[[C], Awaitable[Result[T, E]]],
|
|
281
|
+
*,
|
|
282
|
+
skip_analysis: bool = False,
|
|
283
|
+
) -> Result[T, OntologicalViolationError | E]:
|
|
284
|
+
"""Execute with ontological analysis (Around Advice).
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
context: Phase-specific context passed to strategy.
|
|
288
|
+
core_operation: The operation returning Result[T, E].
|
|
289
|
+
skip_analysis: Skip ontological check (for known-safe hot paths).
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
Result with union error type:
|
|
293
|
+
- Ok(T) if analysis passes and operation succeeds
|
|
294
|
+
- Err(OntologicalViolationError) if analysis fails and halt_on_violation
|
|
295
|
+
- Err(E) if core operation fails
|
|
296
|
+
"""
|
|
297
|
+
# Escape hatch for hot paths
|
|
298
|
+
if skip_analysis:
|
|
299
|
+
return await core_operation(context)
|
|
300
|
+
|
|
301
|
+
# Get cache key from Strategy (not self-computed)
|
|
302
|
+
cache_key = self.strategy.get_cache_key(context)
|
|
303
|
+
|
|
304
|
+
# Check cache
|
|
305
|
+
if cache_key in self._cache:
|
|
306
|
+
analysis = self._cache[cache_key]
|
|
307
|
+
log.debug(
|
|
308
|
+
"ontology.analysis.cache_hit",
|
|
309
|
+
extra={
|
|
310
|
+
"join_point": self.strategy.join_point,
|
|
311
|
+
"cache_key": cache_key[:16],
|
|
312
|
+
},
|
|
313
|
+
)
|
|
314
|
+
else:
|
|
315
|
+
try:
|
|
316
|
+
analysis = await self.strategy.analyze(context)
|
|
317
|
+
self._cache[cache_key] = analysis
|
|
318
|
+
log.debug(
|
|
319
|
+
"ontology.analysis.completed",
|
|
320
|
+
extra={
|
|
321
|
+
"join_point": self.strategy.join_point,
|
|
322
|
+
"is_valid": analysis.is_valid,
|
|
323
|
+
"confidence": analysis.confidence,
|
|
324
|
+
},
|
|
325
|
+
)
|
|
326
|
+
except Exception as e:
|
|
327
|
+
# LLM provider failure
|
|
328
|
+
if self.strict_mode:
|
|
329
|
+
# fail_closed: propagate error
|
|
330
|
+
log.error(
|
|
331
|
+
"ontology.analysis.failed_closed",
|
|
332
|
+
extra={
|
|
333
|
+
"join_point": self.strategy.join_point,
|
|
334
|
+
"error": str(e),
|
|
335
|
+
},
|
|
336
|
+
)
|
|
337
|
+
raise
|
|
338
|
+
else:
|
|
339
|
+
# fail_open: log warning, proceed without analysis
|
|
340
|
+
log.warning(
|
|
341
|
+
"ontology.analysis.failed_open",
|
|
342
|
+
extra={
|
|
343
|
+
"join_point": self.strategy.join_point,
|
|
344
|
+
"error": str(e),
|
|
345
|
+
},
|
|
346
|
+
)
|
|
347
|
+
return await core_operation(context)
|
|
348
|
+
|
|
349
|
+
# Handle violation
|
|
350
|
+
if not analysis.is_valid:
|
|
351
|
+
await self._emit_violation_event(analysis)
|
|
352
|
+
|
|
353
|
+
if self.halt_on_violation:
|
|
354
|
+
return Result.err(
|
|
355
|
+
OntologicalViolationError(
|
|
356
|
+
analysis,
|
|
357
|
+
join_point=self.strategy.join_point,
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
# else: log and continue (non-halting mode)
|
|
361
|
+
log.warning(
|
|
362
|
+
"ontology.analysis.violation_ignored",
|
|
363
|
+
extra={
|
|
364
|
+
"join_point": self.strategy.join_point,
|
|
365
|
+
"reasoning": analysis.reasoning,
|
|
366
|
+
},
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# Handle valid
|
|
370
|
+
if analysis.is_valid:
|
|
371
|
+
await self._emit_passed_event(analysis)
|
|
372
|
+
|
|
373
|
+
# Execute core operation (returns Result[T, E])
|
|
374
|
+
return await core_operation(context)
|
|
375
|
+
|
|
376
|
+
async def _emit_violation_event(self, analysis: AnalysisResult) -> None:
|
|
377
|
+
"""Emit ontological violation event."""
|
|
378
|
+
if self.event_emitter:
|
|
379
|
+
from ouroboros.events.ontology import OntologicalViolationEvent
|
|
380
|
+
|
|
381
|
+
event = OntologicalViolationEvent(
|
|
382
|
+
join_point=self.strategy.join_point,
|
|
383
|
+
confidence=analysis.confidence,
|
|
384
|
+
reasoning=analysis.reasoning,
|
|
385
|
+
suggestions=analysis.suggestions,
|
|
386
|
+
)
|
|
387
|
+
await self.event_emitter(event)
|
|
388
|
+
|
|
389
|
+
async def _emit_passed_event(self, analysis: AnalysisResult) -> None:
|
|
390
|
+
"""Emit ontological passed event."""
|
|
391
|
+
if self.event_emitter:
|
|
392
|
+
from ouroboros.events.ontology import OntologicalPassedEvent
|
|
393
|
+
|
|
394
|
+
event = OntologicalPassedEvent(
|
|
395
|
+
join_point=self.strategy.join_point,
|
|
396
|
+
confidence=analysis.confidence,
|
|
397
|
+
)
|
|
398
|
+
await self.event_emitter(event)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
# =============================================================================
|
|
402
|
+
# Factory Function
|
|
403
|
+
# =============================================================================
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def create_ontology_aspect(
|
|
407
|
+
strategy: OntologyStrategy[Any],
|
|
408
|
+
event_emitter: Callable[[BaseEvent], Awaitable[None]] | None = None,
|
|
409
|
+
*,
|
|
410
|
+
halt_on_violation: bool = True,
|
|
411
|
+
strict_mode: bool = True,
|
|
412
|
+
cache_ttl: int = 300,
|
|
413
|
+
cache_maxsize: int = 100,
|
|
414
|
+
) -> OntologicalAspect[Any, Any, Any]:
|
|
415
|
+
"""Factory to create configured ontological aspect.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
strategy: The OntologyStrategy to use.
|
|
419
|
+
event_emitter: Optional event emission callback.
|
|
420
|
+
halt_on_violation: Return error on violation (default: True).
|
|
421
|
+
strict_mode: Fail closed on LLM errors (default: True).
|
|
422
|
+
cache_ttl: Cache TTL in seconds (default: 300).
|
|
423
|
+
cache_maxsize: Max cached entries (default: 100).
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
Configured OntologicalAspect instance.
|
|
427
|
+
|
|
428
|
+
Example:
|
|
429
|
+
aspect = create_ontology_aspect(
|
|
430
|
+
strategy=DevilAdvocateStrategy(llm_adapter),
|
|
431
|
+
event_emitter=event_store.emit,
|
|
432
|
+
)
|
|
433
|
+
"""
|
|
434
|
+
return OntologicalAspect(
|
|
435
|
+
strategy=strategy,
|
|
436
|
+
event_emitter=event_emitter,
|
|
437
|
+
halt_on_violation=halt_on_violation,
|
|
438
|
+
strict_mode=strict_mode,
|
|
439
|
+
cache_ttl=cache_ttl,
|
|
440
|
+
cache_maxsize=cache_maxsize,
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
__all__ = [
|
|
445
|
+
# Types
|
|
446
|
+
"OntologicalJoinPoint",
|
|
447
|
+
"AnalysisResult",
|
|
448
|
+
"OntologicalViolationError",
|
|
449
|
+
# Protocol
|
|
450
|
+
"OntologyStrategy",
|
|
451
|
+
# Weaver
|
|
452
|
+
"OntologicalAspect",
|
|
453
|
+
# Factory
|
|
454
|
+
"create_ontology_aspect",
|
|
455
|
+
]
|