| | from __future__ import annotations
|
| |
|
| | from dataclasses import dataclass, field
|
| | from datetime import datetime, timezone
|
| | from typing import TYPE_CHECKING, Dict, Any, Optional
|
| | import math
|
| |
|
| | from .binary_hdv import BinaryHDV
|
| | from .config import get_config
|
| |
|
| | if TYPE_CHECKING:
|
| | from .provenance import ProvenanceRecord
|
| |
|
| |
|
| | @dataclass
|
| | class MemoryNode:
|
| | """
|
| | Holographic memory neuron (Phase 3.0+).
|
| | Uses BinaryHDV for efficient storage and computation.
|
| |
|
| | Phase 4.3: Temporal Recall - supports episodic chaining and time-based indexing.
|
| | """
|
| |
|
| | id: str
|
| | hdv: BinaryHDV
|
| | content: str
|
| | metadata: Dict[str, Any] = field(default_factory=dict)
|
| | created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
| | last_accessed: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
| |
|
| |
|
| | tier: str = "hot"
|
| | access_count: int = 1
|
| | ltp_strength: float = 0.5
|
| |
|
| |
|
| | epistemic_value: float = 0.0
|
| | pragmatic_value: float = 0.0
|
| |
|
| |
|
| | previous_id: Optional[str] = None
|
| |
|
| |
|
| | provenance: Optional["ProvenanceRecord"] = field(default=None, repr=False)
|
| |
|
| |
|
| |
|
| |
|
| | stability: float = 1.0
|
| | review_candidate: bool = False
|
| |
|
| | def access(self, update_weights: bool = True):
|
| | """Retrieve memory (reconsolidation)"""
|
| | now = datetime.now(timezone.utc)
|
| | self.last_accessed = now
|
| |
|
| | if update_weights:
|
| | self.access_count += 1
|
| |
|
| |
|
| | self.calculate_ltp()
|
| |
|
| |
|
| |
|
| | import math as _math
|
| | self.stability = max(1.0, 1.0 + _math.log1p(self.access_count) * 0.5)
|
| |
|
| |
|
| | self.epistemic_value *= 1.01
|
| | self.epistemic_value = min(self.epistemic_value, 1.0)
|
| |
|
| | def calculate_ltp(self) -> float:
|
| | """
|
| | Calculate Long-Term Potentiation (LTP) strength.
|
| | Formula: S = I * log(1 + A) * e^(-lambda * T)
|
| | """
|
| | config = get_config()
|
| |
|
| |
|
| | importance = max(
|
| | config.ltp.initial_importance,
|
| | (self.epistemic_value + self.pragmatic_value) / 2
|
| | )
|
| |
|
| |
|
| | access_factor = math.log1p(self.access_count)
|
| |
|
| |
|
| | age = self.age_days()
|
| |
|
| |
|
| | decay = math.exp(-config.ltp.decay_lambda * age)
|
| |
|
| | self.ltp_strength = importance * access_factor * decay
|
| |
|
| |
|
| |
|
| | if self.ltp_strength > config.ltp.permanence_threshold:
|
| |
|
| |
|
| | pass
|
| |
|
| | return self.ltp_strength
|
| |
|
| | def get_free_energy_score(self) -> float:
|
| | """
|
| | Legacy score, now aliased to LTP strength for compatibility.
|
| | """
|
| |
|
| | return self.calculate_ltp()
|
| |
|
| | def age_days(self) -> float:
|
| | """Age of memory in days (for decay calculations)"""
|
| |
|
| | delta = datetime.now(timezone.utc) - self.created_at
|
| | return delta.total_seconds() / 86400.0
|
| |
|
| | @property
|
| | def unix_timestamp(self) -> int:
|
| | """Unix timestamp (seconds since epoch) for Qdrant indexing."""
|
| | return int(self.created_at.timestamp())
|
| |
|
| | @property
|
| | def iso_date(self) -> str:
|
| | """ISO 8601 date string for human-readable time metadata."""
|
| | return self.created_at.isoformat()
|
| |
|
| | def age_seconds(self) -> float:
|
| | """Age of memory in seconds (for fine-grained chrono-weighting)."""
|
| | delta = datetime.now(timezone.utc) - self.created_at
|
| | return delta.total_seconds()
|
| |
|
| | def __lt__(self, other):
|
| |
|
| |
|
| |
|
| | return self.id < other.id
|
| |
|