open-standards/eoc/eoc-rs/crates/eoc-memory/src/memory.rs
Transaction Science 68b8a2dbee ingest wave F: 3 crates · op-crypto-extra + smart-byte-acdc + eoc-memory
OpenPay (1 crate, 3751 LOC, 83 tests)
  op-crypto-extra      Extended crypto rails. Stablecoin catalog (USDC, USDT,
                       PYUSD, DAI, RLUSD, EURC, FDUSD — 26 deployments). L2
                       catalog (12 chains incl. Optimism, Arbitrum, Base,
                       zkSync Era, Polygon zkEVM, Linea, Scroll, Starknet).
                       CCTP v2 BurnMessage encode/decode + domain ids +
                       attestation. ERC-4337 UserOperation v0.7 +
                       PackedUserOperation. EIP-7702 set-EOA-code with RLP
                       signing preimage. Uniswap Permit2 single + batch
                       transfer EIP-712 hashes. EIP-2612 ERC-20 permit.
                       BOLT-11 bech32 invoices + LNURL decode. Bitcoin
                       PSBT v2 (BIP-370). Atomic-swap HTLC. Solana SPL /
                       Aleo / Aztec confidential-transfer sketches.

Smart Byte (1 crate, 2304 LOC, 30 tests)
  smart-byte-acdc      Authentic Chained Data Containers (KERI ecosystem).
                       Acdc + AcdcBuilder (targeted + untargeted) with SAID
                       derivation. JSON Schema 2020-12 validator with
                       oneOf partial-disclosure. TEL (RIP/VRT/ISS/REV)
                       with hash-chained verification. IPEX (apply/offer/
                       agree/grant/admit/spurn) chained by SAID. Edge
                       records (I2I/NI2I/DI2I) + EdgeGraph BFS traversal
                       with cycle detection. Selective disclosure with
                       full/none/subset plans + compact packing.
                       CredentialRegistry trait + InMemoryRegistry over
                       TEL. Composes with smart-byte-core + smart-byte-keri-witness.

EOC (1 crate, 1764 LOC, 16 tests)
  eoc-memory           Long-term memory primitives. Memory trait + MemoryKind +
                       EpisodeId. Episodic event log with TimeIndex range
                       queries. RDF-style Triple store with S/P/O indices.
                       Bounded attention-budget Scratchpad with
                       salience-weighted eviction. Rolling SummaryBuffer +
                       FIFO SlidingWindow. Dream-cycle consolidate()
                       (episodic → semantic). Ebbinghaus forgetting curve
                       with reinforcement. Retriever blending cosine
                       similarity + recency + saturating frequency.
                       MemGpt three-tier shape (Main/Recall/Archival).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-24 17:28:24 -04:00

118 lines
3.7 KiB
Rust

//! Base [`Memory`] trait and shared identifier / item types.
use serde::{Deserialize, Serialize};
use crate::error::MemoryResult;
/// Stable identifier for a single episodic event.
///
/// Constructed from a BLAKE3 digest over `(timestamp_ms, payload)`
/// so identical events at identical timestamps collapse to the same
/// id — preserving determinism.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct EpisodeId(pub [u8; 16]);
impl EpisodeId {
/// Build an [`EpisodeId`] from a timestamp + payload bytes.
#[must_use]
pub fn from_event(timestamp_ms: u64, payload: &[u8]) -> Self {
let mut hasher = blake3::Hasher::new();
hasher.update(&timestamp_ms.to_le_bytes());
hasher.update(payload);
let h = hasher.finalize();
let mut out = [0u8; 16];
out.copy_from_slice(&h.as_bytes()[..16]);
Self(out)
}
/// Lowercase hex form of the id (32 chars).
#[must_use]
pub fn to_hex(&self) -> String {
let mut s = String::with_capacity(32);
for b in &self.0 {
s.push_str(&format!("{b:02x}"));
}
s
}
}
/// Taxonomy of memory subsystems implemented by this crate.
///
/// The classification roughly follows Tulving (1972) — episodic vs
/// semantic — plus working / procedural / summary as engineering
/// niceties for LLM agents.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum MemoryKind {
/// Time-stamped events (conversations, observations).
Episodic,
/// Distilled facts as entity-relation triples.
Semantic,
/// Volatile scratchpad held inside the model's attention budget.
Working,
/// Rolling natural-language summary of older context.
Summary,
/// Sliding window of recent turns.
Window,
}
/// A reference to a single memory record, used by retrieval and
/// injection routines.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct MemoryRef {
/// Which subsystem produced this item.
pub kind: MemoryKind,
/// Stable opaque id (BLAKE3-16 hex) of the underlying record.
pub id: String,
}
/// A retrieved memory item carrying enough text to be injected into
/// a prompt.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct MemoryItem {
/// Stable reference to the source record.
pub reference: MemoryRef,
/// Rendered natural-language text.
pub text: String,
/// Approximate token count (`text.split_whitespace().count()`).
pub tokens: u32,
/// Monotonic timestamp of the underlying event in ms.
pub timestamp_ms: u64,
}
impl MemoryItem {
/// Construct a new item; tokens are computed by whitespace count.
#[must_use]
pub fn new(reference: MemoryRef, text: String, timestamp_ms: u64) -> Self {
let tokens = u32::try_from(text.split_whitespace().count()).unwrap_or(u32::MAX);
Self {
reference,
text,
tokens,
timestamp_ms,
}
}
}
/// Common contract for every memory subsystem.
///
/// Implementations must be deterministic given a fixed clock; that
/// is, calling [`Memory::recent`] with the same arguments after the
/// same sequence of writes must yield the same items in the same
/// order.
pub trait Memory {
/// Identify which subsystem this implementation is.
fn kind(&self) -> MemoryKind;
/// Total number of records currently held.
fn len(&self) -> usize;
/// True iff `len() == 0`.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Most-recent `n` items (newest first).
///
/// Returns an error only if the store itself is broken.
fn recent(&self, n: usize) -> MemoryResult<Vec<MemoryItem>>;
}