pub struct HoraCore { /* private fields */ }Expand description
The main entry point for hora-graph-core.
use hora_graph_core::{HoraCore, HoraConfig};
let mut hora = HoraCore::new(HoraConfig::default()).unwrap();
let id = hora.add_entity("project", "hora", None, None).unwrap();
let entity = hora.get_entity(id).unwrap().unwrap();
assert_eq!(entity.name, "hora");Implementations§
Source§impl HoraCore
impl HoraCore
Sourcepub fn new(config: HoraConfig) -> Result<Self>
pub fn new(config: HoraConfig) -> Result<Self>
Create a new in-memory HoraCore instance (no persistence).
Sourcepub fn open(path: impl AsRef<Path>, config: HoraConfig) -> Result<Self>
pub fn open(path: impl AsRef<Path>, config: HoraConfig) -> Result<Self>
Open a file-backed HoraCore instance.
If the file exists, loads data from it. If it does not exist, creates
a new empty instance that will write to the given path on flush().
Sourcepub fn flush(&self) -> Result<()>
pub fn flush(&self) -> Result<()>
Flush all data to the backing file.
Writes to a temporary file first, then renames for crash safety. Returns an error if this is an in-memory-only instance.
Sourcepub fn snapshot(&self, dest: impl AsRef<Path>) -> Result<()>
pub fn snapshot(&self, dest: impl AsRef<Path>) -> Result<()>
Copy the current state to a snapshot file.
Flushes first if file-backed, then copies. For in-memory instances, writes directly to the given path.
Sourcepub fn add_entity(
&mut self,
entity_type: &str,
name: &str,
properties: Option<Properties>,
embedding: Option<&[f32]>,
) -> Result<EntityId>
pub fn add_entity( &mut self, entity_type: &str, name: &str, properties: Option<Properties>, embedding: Option<&[f32]>, ) -> Result<EntityId>
Add a new entity to the knowledge graph.
If deduplication is enabled and a duplicate is detected among entities of the same type, returns the existing entity’s ID instead of creating a new one. Detection uses: normalized name exact match, cosine embedding similarity, and Jaccard token overlap (in that priority order).
Sourcepub fn get_entity(&mut self, id: EntityId) -> Result<Option<Entity>>
pub fn get_entity(&mut self, id: EntityId) -> Result<Option<Entity>>
Get an entity by ID. Returns None if not found.
Side-effect: buffers an access event for ACT-R activation tracking. The actual activation computation is deferred until needed.
Sourcepub fn update_entity(
&mut self,
id: EntityId,
update: EntityUpdate,
) -> Result<()>
pub fn update_entity( &mut self, id: EntityId, update: EntityUpdate, ) -> Result<()>
Update an entity. Only fields set to Some in the update are changed.
Sourcepub fn delete_entity(&mut self, id: EntityId) -> Result<()>
pub fn delete_entity(&mut self, id: EntityId) -> Result<()>
Delete an entity and all its associated edges (cascade).
Sourcepub fn add_fact(
&mut self,
source: EntityId,
target: EntityId,
relation: &str,
description: &str,
confidence: Option<f32>,
) -> Result<EdgeId>
pub fn add_fact( &mut self, source: EntityId, target: EntityId, relation: &str, description: &str, confidence: Option<f32>, ) -> Result<EdgeId>
Add a new fact (directed edge) between two entities.
Returns the ID of the newly created fact. Both source and target entities must exist.
Sourcepub fn get_fact(&self, id: EdgeId) -> Result<Option<Edge>>
pub fn get_fact(&self, id: EdgeId) -> Result<Option<Edge>>
Get a fact by ID. Returns None if not found.
Sourcepub fn update_fact(&mut self, id: EdgeId, update: FactUpdate) -> Result<()>
pub fn update_fact(&mut self, id: EdgeId, update: FactUpdate) -> Result<()>
Update a fact. Only fields set to Some in the update are changed.
Sourcepub fn invalidate_fact(&mut self, id: EdgeId) -> Result<()>
pub fn invalidate_fact(&mut self, id: EdgeId) -> Result<()>
Mark a fact as invalid (bi-temporal). The fact is NOT deleted — it remains queryable with its validity window.
Sourcepub fn delete_fact(&mut self, id: EdgeId) -> Result<()>
pub fn delete_fact(&mut self, id: EdgeId) -> Result<()>
Physically delete a fact. Use invalidate_fact for bi-temporal soft-delete.
Sourcepub fn get_entity_facts(&self, entity_id: EntityId) -> Result<Vec<Edge>>
pub fn get_entity_facts(&self, entity_id: EntityId) -> Result<Vec<Edge>>
Get all facts where the given entity is source or target.
Sourcepub fn traverse(
&self,
start: EntityId,
opts: TraverseOpts,
) -> Result<TraverseResult>
pub fn traverse( &self, start: EntityId, opts: TraverseOpts, ) -> Result<TraverseResult>
BFS traversal from a start entity up to the given depth.
Returns IDs of all discovered entities and edges. Depth 0 returns only the start entity (no edges).
Sourcepub fn neighbors(&self, entity_id: EntityId) -> Result<Vec<EntityId>>
pub fn neighbors(&self, entity_id: EntityId) -> Result<Vec<EntityId>>
Get all direct neighbor entity IDs (connected via any edge).
Sourcepub fn timeline(&self, entity_id: EntityId) -> Result<Vec<Edge>>
pub fn timeline(&self, entity_id: EntityId) -> Result<Vec<Edge>>
Timeline of all facts involving an entity, sorted by valid_at.
Sourcepub fn facts_at(&self, t: i64) -> Result<Vec<Edge>>
pub fn facts_at(&self, t: i64) -> Result<Vec<Edge>>
All facts valid at a given point in time.
A fact is valid at time t if valid_at <= t and
(invalid_at == 0 or invalid_at > t).
Sourcepub fn vector_search(&self, query: &[f32], k: usize) -> Result<Vec<SearchHit>>
pub fn vector_search(&self, query: &[f32], k: usize) -> Result<Vec<SearchHit>>
Brute-force vector search: find the k most similar entities by cosine similarity.
Requires embedding_dims > 0 in the config. Entities without embeddings
are silently skipped. The query embedding must match embedding_dims in length.
Sourcepub fn text_search(&mut self, query: &str, k: usize) -> Result<Vec<SearchHit>>
pub fn text_search(&mut self, query: &str, k: usize) -> Result<Vec<SearchHit>>
Full-text search using BM25+ scoring over entity names and string properties.
Returns the top k matching entities. Entities without indexable text
are invisible to BM25.
Sourcepub fn search(
&mut self,
query_text: Option<&str>,
query_embedding: Option<&[f32]>,
opts: SearchOpts,
) -> Result<Vec<SearchHit>>
pub fn search( &mut self, query_text: Option<&str>, query_embedding: Option<&[f32]>, opts: SearchOpts, ) -> Result<Vec<SearchHit>>
Hybrid search combining vector similarity and BM25 full-text via RRF fusion.
Provide query_text for BM25, query_embedding for vector search, or both.
When both are provided, results are fused using Reciprocal Rank Fusion.
When only one is provided, that leg runs alone.
Returns empty if neither is provided.
Sourcepub fn get_activation(&mut self, id: EntityId) -> Option<f64>
pub fn get_activation(&mut self, id: EntityId) -> Option<f64>
Get the current ACT-R base-level activation for an entity.
Returns f64::NEG_INFINITY if the entity has never been accessed,
or None if the entity doesn’t exist.
Sourcepub fn record_access(&mut self, id: EntityId)
pub fn record_access(&mut self, id: EntityId)
Record an access on an entity for ACT-R activation tracking.
Called automatically by get_entity() and search(). Can also be
called directly for external access events.
Sourcepub fn get_memory_phase(&mut self, id: EntityId) -> Option<&MemoryPhase>
pub fn get_memory_phase(&mut self, id: EntityId) -> Option<&MemoryPhase>
Get the current reconsolidation phase for an entity.
Resolves any pending time-based transitions before returning.
Returns None if the entity doesn’t exist.
Sourcepub fn get_stability_multiplier(&mut self, id: EntityId) -> Option<f64>
pub fn get_stability_multiplier(&mut self, id: EntityId) -> Option<f64>
Get the cumulative stability multiplier for an entity.
Starts at 1.0, increases by restabilization_boost (default 1.2×)
each time the entity completes a reconsolidation cycle.
Sourcepub fn get_retrievability(&self, id: EntityId) -> Option<f64>
pub fn get_retrievability(&self, id: EntityId) -> Option<f64>
Get the current retrievability for an entity (0.0 to 1.0).
R = 1.0 immediately after review, R → 0.0 as time passes.
Returns None if the entity doesn’t exist.
Sourcepub fn get_next_review_days(&self, id: EntityId) -> Option<f64>
pub fn get_next_review_days(&self, id: EntityId) -> Option<f64>
Get the optimal next review interval in days for an entity.
Uses the configured desired_retention (default 0.9).
Returns None if the entity doesn’t exist.
Sourcepub fn get_fsrs_stability(&self, id: EntityId) -> Option<f64>
pub fn get_fsrs_stability(&self, id: EntityId) -> Option<f64>
Get the current FSRS stability in days for an entity.
Returns None if the entity doesn’t exist.
Sourcepub fn dark_node_pass(&mut self) -> usize
pub fn dark_node_pass(&mut self) -> usize
Scan all entities and mark those below activation threshold as Dark.
An entity becomes Dark when:
- Its activation is below
silencing_threshold(default -2.0) - Its last access was more than
silencing_delay_secsago (default 7 days) - It is currently in Stable state (not Labile/Restabilizing/already Dark)
Returns the number of entities newly marked as Dark.
Sourcepub fn attempt_recovery(&mut self, id: EntityId) -> bool
pub fn attempt_recovery(&mut self, id: EntityId) -> bool
Attempt to recover a Dark entity via strong external reactivation.
If the entity is Dark, it transitions to Labile (for re-encoding)
and a record_access is applied. Returns true if recovery occurred.
Sourcepub fn dark_nodes(&mut self) -> Vec<EntityId>
pub fn dark_nodes(&mut self) -> Vec<EntityId>
List all entity IDs currently in Dark state.
Sourcepub fn gc_candidates(&mut self) -> Vec<EntityId>
pub fn gc_candidates(&mut self) -> Vec<EntityId>
List dark entities eligible for garbage collection (dark > gc_eligible_after_secs).
Sourcepub fn shy_downscaling(&mut self, factor: f64) -> usize
pub fn shy_downscaling(&mut self, factor: f64) -> usize
Apply SHY homeostatic downscaling to all entity activations.
Multiplies every entity’s activation score by factor (default 0.78).
This is cumulative and idempotent-safe: two calls produce factor².
Affects both positive and negative activations (amplitude reduction).
Returns the number of entities downscaled.
Sourcepub fn interleaved_replay(&mut self) -> Result<ReplayStats>
pub fn interleaved_replay(&mut self) -> Result<ReplayStats>
Interleaved replay: re-activate entities from a mix of recent and old episodes.
Selects up to max_replay_items episodes, split by recent_ratio (default 70%
recent, 30% older). For each selected episode, calls record_access() on every
referenced entity that still exists.
Episodes are split at the median created_at timestamp: those above median are
“recent”, the rest are “older”. This is deterministic (no RNG required).
Sourcepub fn cls_transfer(&mut self) -> Result<ClsStats>
pub fn cls_transfer(&mut self) -> Result<ClsStats>
CLS transfer: extract recurring episodic patterns into semantic facts.
Scans episodes with consolidation_count >= cls_threshold. For each,
collects the referenced facts and groups them by (source, relation, target).
Triplets seen in >= cls_threshold distinct episodes become semantic facts
(or get their confidence reinforced if already existing).
Each processed episode gets its consolidation_count incremented.
Sourcepub fn memory_linking(&mut self) -> Result<LinkingStats>
pub fn memory_linking(&mut self) -> Result<LinkingStats>
Memory linking: create temporal links between entities co-created within a time window.
Scans all entities sorted by created_at. For each pair within linking_window_ms
(default 6h), creates bidirectional “temporally_linked” edges (A→B and B→A).
If the link already exists, reinforces its confidence (+0.1, capped at 1.0).
Sourcepub fn dream_cycle(
&mut self,
config: &DreamCycleConfig,
) -> Result<DreamCycleStats>
pub fn dream_cycle( &mut self, config: &DreamCycleConfig, ) -> Result<DreamCycleStats>
Run a full dream cycle: the 6-step consolidation pipeline.
Steps (in order):
- SHY downscaling — reduce all activation scores
- Interleaved replay — reactivate entities from mixed episodes
- CLS transfer — extract recurring patterns into semantic facts
- Memory linking — create temporal co-creation edges
- Dark check — silence low-activation entities
- GC (optional) — delete GC-eligible dark entities
Each step can be enabled/disabled via DreamCycleConfig.
Sourcepub fn spread_activation(
&self,
sources: &[(EntityId, f64)],
params: &SpreadingParams,
) -> Result<HashMap<EntityId, f64>>
pub fn spread_activation( &self, sources: &[(EntityId, f64)], params: &SpreadingParams, ) -> Result<HashMap<EntityId, f64>>
Spread activation from source entities through the knowledge graph.
Uses ACT-R fan effect: S_ji = S_max - ln(fan). High-fan nodes
inhibit spreading (negative activation when fan > e^S_max ≈ 5).
Returns accumulated activation per entity (can be negative for inhibition).
Sourcepub fn add_episode(
&mut self,
source: EpisodeSource,
session_id: &str,
entity_ids: &[EntityId],
fact_ids: &[EdgeId],
) -> Result<u64>
pub fn add_episode( &mut self, source: EpisodeSource, session_id: &str, entity_ids: &[EntityId], fact_ids: &[EdgeId], ) -> Result<u64>
Record an episode (interaction snapshot).
Sourcepub fn get_episodes(
&self,
session_id: Option<&str>,
source: Option<EpisodeSource>,
since: Option<i64>,
until: Option<i64>,
) -> Result<Vec<Episode>>
pub fn get_episodes( &self, session_id: Option<&str>, source: Option<EpisodeSource>, since: Option<i64>, until: Option<i64>, ) -> Result<Vec<Episode>>
Get all episodes, optionally filtered.
Filters:
session_id: only episodes from this sessionsource: only episodes from this source typesince/until: epoch millis time range oncreated_at
Sourcepub fn increment_consolidation(&mut self, episode_id: u64) -> Result<bool>
pub fn increment_consolidation(&mut self, episode_id: u64) -> Result<bool>
Increment the consolidation count for an episode.
Sourcepub fn stats(&self) -> Result<StorageStats>
pub fn stats(&self) -> Result<StorageStats>
Get summary statistics about the knowledge graph.