| 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
|
|
|