Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
cd6a4b6
fix: add thread safety to Membrane rate limiting
coredipper Dec 26, 2025
b5d941d
fix: add expression length limit to Mitochondria (DoS protection)
coredipper Dec 26, 2025
aae8d3c
fix: add proper error logging to Lysosome (no silent failures)
coredipper Dec 26, 2025
42178eb
fix: add error context to Mitochondria exceptions
coredipper Dec 26, 2025
c90e86a
test: add comprehensive Ribosome tests (42 test cases)
coredipper Dec 26, 2025
9d7df4a
test: add comprehensive Lysosome tests (30 test cases)
coredipper Dec 26, 2025
fe3dda4
test: expand Nucleus tests (25 test cases)
coredipper Dec 26, 2025
c9d6894
test: expand WAgent tests (33 test cases)
coredipper Dec 26, 2025
72d8708
test: add Oscillator topology tests
coredipper Dec 26, 2025
27a056d
style: add missing return type hints to Ribosome
coredipper Dec 26, 2025
522ea42
style: standardize to Python 3.10+ union syntax in types.py
coredipper Dec 26, 2025
8fe47f6
docs: add docstrings to Ribosome private methods
coredipper Dec 26, 2025
aa8e0bd
fix: respect silent flag in Lysosome auto_digest
coredipper Dec 26, 2025
d1d84ad
test: add multi-organelle integration tests
coredipper Dec 26, 2025
0457631
docs: fix Oscillator example with undefined functions
coredipper Dec 26, 2025
2c7dbca
docs: fix Chaperone example to use FoldingStrategy import
coredipper Dec 26, 2025
2bb19b7
docs: fix Membrane example with undefined other_membrane
coredipper Dec 26, 2025
c7dc190
docs: fix Ribosome example to use mRNA import
coredipper Dec 26, 2025
e8e3877
docs: fix more README examples with undefined variables
coredipper Dec 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ print(result.threat_level) # ThreatLevel.CRITICAL
membrane.learn_threat("BACKDOOR_PROTOCOL", level=ThreatLevel.CRITICAL)

# Share immunity between agents
other_membrane = Membrane() # Another agent's membrane
antibodies = membrane.export_antibodies()
other_membrane.import_antibodies(antibodies)
```
Expand Down Expand Up @@ -142,10 +143,13 @@ result = chap.fold(raw, User)
print(result.valid) # True
print(result.structure.age) # 30 (coerced to int)

# Enhanced folding with confidence
# Control which strategies are tried (default: STRICT → EXTRACTION → LENIENT → REPAIR)
result = chap.fold(raw, User, strategies=[FoldingStrategy.STRICT, FoldingStrategy.REPAIR])

# Enhanced folding with confidence scoring
result = chap.fold_enhanced(raw, User)
print(result.confidence) # 0.65 (lower due to repairs)
print(result.coercions_applied) # ["fixed_single_quotes", "removed_trailing_comma"]
print(result.strategy_used) # FoldingStrategy.REPAIR
```

### 🧬 Ribosome (Prompt Template Engine)
Expand Down Expand Up @@ -185,6 +189,10 @@ protein = ribosome.translate(
query="How do I sort a list?"
)
print(protein.sequence)

# Or create mRNA directly for inspection
template = mRNA(sequence="Hello {{name}}")
print(template.get_required_variables()) # ["name"]
```

### 🗑️ Lysosome (Cleanup & Recycling)
Expand All @@ -199,13 +207,13 @@ Handles failure states, expired data, and sensitive material—digesting waste w
- **Toxic Disposal**: Secure handling of sensitive data

```python
from operon_ai import Lysosome, Waste, WasteType
from operon_ai import Lysosome, WasteType

lysosome = Lysosome(auto_digest_threshold=100)

# Capture failures
try:
risky_operation()
result = 1 / 0 # Example risky operation
except Exception as e:
lysosome.ingest_error(e, source="risky_op", context={"step": 3})

Expand Down Expand Up @@ -323,7 +331,8 @@ metabolism.consume(20, "tool_use", EnergyType.GTP)
metabolism.convert_nadh_to_atp(15)

# Transfer energy between agents
metabolism.transfer_to(other_agent.metabolism, 10)
other_metabolism = ATP_Store(budget=50)
metabolism.transfer_to(other_metabolism, 10)
```

### 🧬 Genome (Immutable Configuration)
Expand Down Expand Up @@ -363,10 +372,10 @@ telomere = Telomere(
)

# Each operation shortens telomeres
while telomere.tick(): # Returns False when senescent
do_operation()
if telomere.record_error():
handle_error()
for i in range(10):
if not telomere.tick(): # Returns False when senescent
break
print(f"Operation {i}: {telomere.remaining} remaining")

# Renew agent (like telomerase)
if telomere.get_phase() == LifecyclePhase.SENESCENT:
Expand Down Expand Up @@ -437,8 +446,10 @@ Multi-agent consensus with voting strategies and reliability tracking.
Note: quorum only helps if voters are not strongly correlated (use diverse models, tool checks, and/or data partitioning).

```python
from operon_ai import ATP_Store
from operon_ai.topology import QuorumSensing, VotingStrategy

budget = ATP_Store(budget=100)
quorum = QuorumSensing(
n_agents=5,
budget=budget,
Expand All @@ -464,17 +475,17 @@ cascade = Cascade(name="DataPipeline")

cascade.add_stage(CascadeStage(
name="validate",
processor=lambda x: x if valid(x) else None,
processor=lambda x: x if x > 0 else None, # Only positive values
checkpoint=lambda x: x is not None, # Gate
))

cascade.add_stage(CascadeStage(
name="transform",
processor=lambda x: process(x),
processor=lambda x: x * 2, # Double the value
amplification=2.0, # Signal amplification
))

result = cascade.run(input_data)
result = cascade.run(10) # Input value
print(f"Amplification: {result.total_amplification}x")

# Or use pre-built MAPK cascade
Expand All @@ -488,10 +499,20 @@ Biological rhythms for scheduled operations.
```python
from operon_ai.topology import Oscillator, HeartbeatOscillator, OscillatorPhase

# Heartbeat for health checks
# Define your periodic actions
def health_check():
print("💓 Health check: OK")

def do_work():
print("⚙️ Working...")

def do_rest():
print("😴 Resting...")

# Heartbeat for health checks (1 beat per second)
heartbeat = HeartbeatOscillator(
beats_per_minute=60,
on_beat=lambda: health_check(),
on_beat=health_check,
)
heartbeat.start()

Expand All @@ -500,6 +521,10 @@ osc = Oscillator(frequency_hz=0.1) # 10 second period
osc.add_phase(OscillatorPhase(name="work", duration_seconds=7, action=do_work))
osc.add_phase(OscillatorPhase(name="rest", duration_seconds=3, action=do_rest))
osc.start()

# Stop when done (oscillators run in background threads)
# heartbeat.stop()
# osc.stop()
```

---
Expand Down
22 changes: 11 additions & 11 deletions operon_ai/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""

from dataclasses import dataclass, field
from typing import Dict, Optional, Generic, TypeVar, Any, List
from typing import Generic, TypeVar, Any
from enum import Enum, IntEnum
from datetime import datetime

Expand Down Expand Up @@ -61,8 +61,8 @@ class Signal:
signal_type: SignalType = SignalType.EXTERNAL
strength: SignalStrength = SignalStrength.MODERATE
timestamp: datetime = field(default_factory=datetime.now)
metadata: Dict[str, Any] = field(default_factory=dict)
trace_id: Optional[str] = None
metadata: dict[str, Any] = field(default_factory=dict)
trace_id: str | None = None

def with_metadata(self, **kwargs) -> 'Signal':
"""Create a new signal with additional metadata."""
Expand Down Expand Up @@ -178,7 +178,7 @@ class ApprovalToken:
confidence: float = 1.0
integrity: IntegrityLabel = IntegrityLabel.TRUSTED
timestamp: datetime = field(default_factory=datetime.now)
metadata: Dict[str, Any] = field(default_factory=dict)
metadata: dict[str, Any] = field(default_factory=dict)


@dataclass
Expand All @@ -201,9 +201,9 @@ class ActionProtein:
action_type: str # Keep as str for backward compatibility
payload: Any
confidence: float
source_agent: Optional[str] = None
source_agent: str | None = None
timestamp: datetime = field(default_factory=datetime.now)
metadata: Dict[str, Any] = field(default_factory=dict)
metadata: dict[str, Any] = field(default_factory=dict)

def is_success(self) -> bool:
"""Check if this represents a successful action."""
Expand Down Expand Up @@ -242,9 +242,9 @@ class FoldedProtein(Generic[T]):
folding_attempts: Number of attempts needed
"""
valid: bool
structure: Optional[T] = None
structure: T | None = None
raw_peptide_chain: str = ""
error_trace: Optional[str] = None
error_trace: str | None = None
folding_attempts: int = 1

def map(self, func) -> 'FoldedProtein':
Expand Down Expand Up @@ -322,9 +322,9 @@ class Pathway:
signals: Signals that have traveled this path
"""
name: str
stages: List[str] = field(default_factory=list)
stages: list[str] = field(default_factory=list)
current_stage: int = 0
signals: List[Signal] = field(default_factory=list)
signals: list[Signal] = field(default_factory=list)

def advance(self) -> bool:
"""Move to next stage. Returns False if at end."""
Expand All @@ -333,7 +333,7 @@ def advance(self) -> bool:
return True
return False

def current_stage_name(self) -> Optional[str]:
def current_stage_name(self) -> str | None:
"""Get name of current stage."""
if 0 <= self.current_stage < len(self.stages):
return self.stages[self.current_stage]
Expand Down
15 changes: 11 additions & 4 deletions operon_ai/organelles/lysosome.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
import weakref
import threading
import time
import logging


_logger = logging.getLogger(__name__)


class WasteType(Enum):
Expand Down Expand Up @@ -350,8 +354,8 @@ def _digest_orphaned(self, waste: Waste) -> dict:
if hasattr(content, 'cleanup'):
try:
content.cleanup()
except Exception:
pass
except Exception as e:
_logger.warning(f"Cleanup failed for {waste.waste_type.value}: {e}")

return {}

Expand Down Expand Up @@ -383,15 +387,18 @@ def _emergency_digest(self):
digester = self._digesters.get(waste.waste_type, self._digest_default)
digester(waste)
self._total_digested += 1
except Exception:
pass
except Exception as e:
_logger.warning(f"Emergency digest failed for item: {e}")
continue # Continue processing other items
self._queue = self._queue[items_to_process:]

if not self.silent:
print(f"⚠️ [Lysosome] Emergency digest: processed {items_to_process} items")

def _auto_digest(self):
"""Auto-triggered digest when threshold reached."""
if not self.silent:
print(f"[Lysosome] Auto-digesting {len(self._queue)} items")
# Process half the queue
self.digest(max_items=len(self._queue) // 2)

Expand Down
44 changes: 30 additions & 14 deletions operon_ai/organelles/membrane.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import re
import hashlib
import time
import threading

from ..core.types import Signal

Expand Down Expand Up @@ -252,6 +253,7 @@ def __init__(
self._learned_patterns: dict[str, ThreatSignature] = {}
self._request_times: list[float] = []
self._blocked_hashes: set[str] = set()
self._rate_lock = threading.Lock()

# Audit log
self._audit_log: list[FilterResult] = []
Expand Down Expand Up @@ -281,20 +283,16 @@ def filter(self, signal: Signal) -> FilterResult:
self._total_filtered += 1

# Rate limiting check
if self.rate_limit:
now = time.time()
self._request_times = [t for t in self._request_times if now - t < 60]
if len(self._request_times) >= self.rate_limit:
result = FilterResult(
allowed=False,
threat_level=ThreatLevel.CRITICAL,
matched_signatures=[],
audit_hash=content_hash,
processing_time_ms=(time.time() - start_time) * 1000
)
self._log_result(result, "Rate limit exceeded")
return result
self._request_times.append(now)
if self._check_rate_limit():
result = FilterResult(
allowed=False,
threat_level=ThreatLevel.CRITICAL,
matched_signatures=[],
audit_hash=content_hash,
processing_time_ms=(time.time() - start_time) * 1000
)
self._log_result(result, "Rate limit exceeded")
return result

# Check if previously blocked (immune memory)
if content_hash in self._blocked_hashes:
Expand Down Expand Up @@ -359,6 +357,24 @@ def _log_result(self, result: FilterResult, reason: str):
if not self.silent:
print(f"🛡️ [Membrane] BLOCKED: {reason}")

def _check_rate_limit(self) -> bool:
"""Check if request should be rate-limited. Thread-safe."""
if self.rate_limit is None:
return False

with self._rate_lock:
now = time.time()
cutoff = now - 60 # 60 second window

# Remove old entries
self._request_times = [t for t in self._request_times if t > cutoff]

if len(self._request_times) >= self.rate_limit:
return True

self._request_times.append(now)
return False

def learn_threat(
self,
pattern: str,
Expand Down
Loading