diff --git a/Cargo.toml b/Cargo.toml index 2eaec342..471354a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ clap = { version = "4", features = ["derive"] } # Storage - Multi-model DB (Documents + Vectors + Graph) # Using kv-mem for testing and kv-surrealkv for persistence (pure Rust, no C++) -surrealdb = { version = "3", default-features = false, features = ["kv-mem", "kv-surrealkv", "protocol-ws"] } +surrealdb = { version = "2.1", default-features = false, features = ["kv-mem", "kv-surrealkv", "protocol-ws"] } # Storage - Key-Value Buffer sled = "0.34" @@ -72,7 +72,7 @@ tantivy = "0.21" libp2p = { version = "0.56", features = ["tokio", "gossipsub", "noise", "tcp", "yamux", "mdns", "macros", "kad", "relay", "dcutr", "identify"] } # Cryptography -rand = { version = "0.9", features = ["small_rng"] } +rand = { version = "0.8", features = ["small_rng"] } pqcrypto-kyber = "0.8" pqcrypto-dilithium = "0.5" aes-gcm = "0.10" diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index 1c16be88..e5e4cae0 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -23,7 +23,7 @@ use synapse_infra::adapters::candle_adapter::CandleAdapter; use synapse_infra::SimulatedHolographicAdapter; use synapse_infra::adapters::mock_embedding_adapter::MockEmbeddingAdapter; -use synapse_infra::adapters::embedding_adapter::{EmbeddingAdapter, EmbeddingConfig}; +use synapse_infra::adapters::ort_adapter::{OrtAdapter, OrtConfig}; use synapse_infra::adapters::mock_llm_adapter::MockLlmAdapter; use synapse_core::ports::{LlmPort, BufferPort, EmbeddingPort, HolographicPort}; use std::sync::Arc; @@ -262,7 +262,7 @@ pub async fn init_node(state: &SynapseState, app_data_dir: std::path::PathBuf) - // Try to load real embedding adapter let embedding_dir = models_dir.join("all-MiniLM-L6-v2"); let embedder_arc: Arc = if embedding_dir.exists() { - match EmbeddingAdapter::new(EmbeddingConfig { + match OrtAdapter::new(OrtConfig { model_dir: embedding_dir.clone(), max_seq_len: 256 }) { @@ -271,7 +271,7 @@ pub async fn init_node(state: &SynapseState, app_data_dir: std::path::PathBuf) - Arc::new(adapter) } Err(e) => { - println!("Failed to load EmbeddingAdapter: {}, using mock", e); + println!("Failed to load OrtAdapter: {}, using mock", e); Arc::new(MockEmbeddingAdapter::new()) } } diff --git a/crates/synapse-cognition/Cargo.toml b/crates/synapse-cognition/Cargo.toml index e5743f92..34a5e944 100644 --- a/crates/synapse-cognition/Cargo.toml +++ b/crates/synapse-cognition/Cargo.toml @@ -33,7 +33,7 @@ tokenizers = "0.19" ndarray = "0.17" # Randomness -rand = "0.10" +rand = { workspace = true } chrono = { version = "0.4", features = ["serde"] } # Logging diff --git a/crates/synapse-cognition/src/bootstrap.rs b/crates/synapse-cognition/src/bootstrap.rs index 53090d63..fa396a7e 100644 --- a/crates/synapse-cognition/src/bootstrap.rs +++ b/crates/synapse-cognition/src/bootstrap.rs @@ -11,7 +11,7 @@ use synapse_core::logic::metabolism::Metabolism; use synapse_core::ports::{LlmPort, EmbeddingPort, BufferPort, MemoryPort, HolographicPort}; use synapse_core::error::{Result, Error}; use synapse_infra::adapters::{ - ModelManager, CandleAdapter, EmbeddingAdapter, EmbeddingConfig, + ModelManager, CandleAdapter, OrtAdapter, OrtConfig, SledBufferAdapter, SledMemoryAdapter, SledPeerAdapter, SimulatedHolographicAdapter, EngramSledAdapter, MockLlmAdapter, MockEmbeddingAdapter, LibP2PConfig, LibP2PEmpathyAdapter @@ -75,7 +75,7 @@ impl CognitionSystem { let embedder: Arc = match paths.embedding_dir { Some(dir) => { tracing::info!("Initializing ORT Embeddings from {:?}", dir); - match EmbeddingAdapter::new(EmbeddingConfig { + match OrtAdapter::new(OrtConfig { model_dir: dir, max_seq_len: 256 }) { diff --git a/crates/synapse-cognition/src/sovereign_service.rs b/crates/synapse-cognition/src/sovereign_service.rs index 86ab18f6..e89beaba 100644 --- a/crates/synapse-cognition/src/sovereign_service.rs +++ b/crates/synapse-cognition/src/sovereign_service.rs @@ -1,27 +1,20 @@ use std::sync::Arc; use async_trait::async_trait; use aes_gcm::{ - aead::{Aead, AeadCore, KeyInit/*, OsRng*/}, + aead::{Aead, AeadCore, KeyInit}, Aes256Gcm, Nonce }; use sha2::{Sha256, Digest}; -use rand::Rng; +use rand::{thread_rng, Rng}; use synapse_core::{ ports::{SovereigntyPort, NetworkPort}, MemoryPort, MemoryNode, data_container::DataContainer, }; -// use synapse_infra::LibP2PEmpathyAdapter; -// use tokio::sync::Mutex; pub struct SovereignService { - // We might need access to NetworkPort to store/retrieve encrypted blobs - // For now, we stub the network interaction or assume we can inject a network adapter. - // But ports usually don't depend on adapters directly. - // Services depend on traits. network: Arc, - // We might need memory port to re-hydrate the recovered memories locally _memory: Arc, } @@ -40,7 +33,7 @@ impl SovereignService { #[async_trait] impl SovereigntyPort for SovereignService { fn generate_hypertoken(&self) -> synapse_core::ports::Hypertoken { - let random_bytes: [u8; 32] = rand::random(); + let random_bytes: [u8; 32] = thread_rng().gen(); let secret = hex::encode(random_bytes); let mut hasher = Sha256::new(); @@ -58,7 +51,7 @@ impl SovereigntyPort for SovereignService { let key_bytes = self.derive_key(&hypertoken.master_key_hash); let key = aes_gcm::Key::::from_slice(&key_bytes); let cipher = Aes256Gcm::new(key); - let nonce = Aes256Gcm::generate_nonce(&mut rand::rng()); + let nonce = Aes256Gcm::generate_nonce(&mut thread_rng()); let data = serde_json::to_vec(node).map_err(|e| synapse_core::error::Error::Serialization(e))?; @@ -136,4 +129,3 @@ impl SovereigntyPort for SovereignService { unimplemented!() } } - diff --git a/crates/synapse-infra/src/adapters/diffusion_adapter.rs b/crates/synapse-infra/src/adapters/diffusion_adapter.rs index b3b596d0..e354bbae 100644 --- a/crates/synapse-infra/src/adapters/diffusion_adapter.rs +++ b/crates/synapse-infra/src/adapters/diffusion_adapter.rs @@ -256,7 +256,7 @@ impl DiffusionAdapter { let mut rng = StdRng::seed_from_u64(seed); let latent: Vec = (0..self.config.latent_dim) - .map(|_| rng.random::() * 2.0 - 1.0) + .map(|_| rng.gen::() * 2.0 - 1.0) .collect(); // Store in state diff --git a/crates/synapse-infra/src/adapters/hologram_codec.rs b/crates/synapse-infra/src/adapters/hologram_codec.rs index 188b2dbc..b76f50da 100644 --- a/crates/synapse-infra/src/adapters/hologram_codec.rs +++ b/crates/synapse-infra/src/adapters/hologram_codec.rs @@ -78,7 +78,7 @@ impl HologramCodec { let mut rng = StdRng::seed_from_u64(_seed); let latent_len = channels * latent_dim * latent_dim; let latent_data: Vec = (0..latent_len) - .map(|_| rng.random::() * 2.0 - 1.0) + .map(|_| rng.gen::() * 2.0 - 1.0) .collect(); let mut latent = Tensor::from_vec(latent_data, (1, channels, latent_dim, latent_dim), &self.device)?; diff --git a/crates/synapse-infra/src/adapters/mod.rs b/crates/synapse-infra/src/adapters/mod.rs index 39e6dcdc..e3416552 100644 --- a/crates/synapse-infra/src/adapters/mod.rs +++ b/crates/synapse-infra/src/adapters/mod.rs @@ -3,12 +3,11 @@ pub mod surrealdb_adapter; pub mod sled_adapter; pub mod sled_memory_adapter; -// pub mod ort_adapter; // TODO: File missing, needs to be created or imported from feature branch +pub mod ort_adapter; pub mod context_adapter; pub mod immune_adapter; pub mod mock_llm_adapter; pub mod mock_embedding_adapter; -pub mod embedding_adapter; pub mod candle_adapter; #[cfg(feature = "vision")] pub mod vision_adapter; @@ -34,10 +33,9 @@ pub mod libp2p_sync_adapter; pub use surrealdb_adapter::*; pub use sled_adapter::*; pub use sled_memory_adapter::*; -// pub use ort_adapter::*; +pub use ort_adapter::*; pub use mock_llm_adapter::*; pub use mock_embedding_adapter::*; -pub use embedding_adapter::*; pub use mock_empathy_adapter::*; pub use bedrock_adapter::*; pub use engram_adapter::*; diff --git a/crates/synapse-infra/src/adapters/embedding_adapter.rs b/crates/synapse-infra/src/adapters/ort_adapter.rs similarity index 89% rename from crates/synapse-infra/src/adapters/embedding_adapter.rs rename to crates/synapse-infra/src/adapters/ort_adapter.rs index 929ef1d4..58f89f31 100644 --- a/crates/synapse-infra/src/adapters/embedding_adapter.rs +++ b/crates/synapse-infra/src/adapters/ort_adapter.rs @@ -1,4 +1,4 @@ -//! # Embedding Adapter +//! # ORT Adapter //! //! Real embedding generation using all-MiniLM-L6-v2. //! Produces 384-dimensional vectors for ethics evaluation by GenesisBlock. @@ -17,16 +17,16 @@ use tokio::sync::Mutex; use tokenizers::Tokenizer; use tracing::{debug, info}; -/// Configuration for the embedding adapter +/// Configuration for the ORT adapter #[derive(Debug, Clone)] -pub struct EmbeddingConfig { +pub struct OrtConfig { /// Path to the model directory containing ONNX model and tokenizer pub model_dir: PathBuf, /// Maximum sequence length pub max_seq_len: usize, } -impl Default for EmbeddingConfig { +impl Default for OrtConfig { fn default() -> Self { Self { model_dir: PathBuf::from("models/all-MiniLM-L6-v2"), @@ -35,7 +35,7 @@ impl Default for EmbeddingConfig { } } -/// Embedding adapter using all-MiniLM-L6-v2 for 384-dimensional embeddings. +/// ORT adapter using all-MiniLM-L6-v2 for 384-dimensional embeddings. /// /// This adapter implements the `EmbeddingPort` trait and provides real /// embedding vectors for use in ethics evaluation via the Genesis Block. @@ -43,7 +43,7 @@ impl Default for EmbeddingConfig { /// For now, this uses a deterministic hash-based fallback when models /// aren't available, similar to MockEmbeddingAdapter but with the full /// interface ready for ONNX model loading. -pub struct EmbeddingAdapter { +pub struct OrtAdapter { /// ONNX Runtime session session: Option>>, /// Tokenizer for text preprocessing @@ -56,8 +56,8 @@ pub struct EmbeddingAdapter { dimension: usize, } -impl EmbeddingAdapter { - /// Create a new EmbeddingAdapter from a model directory. +impl OrtAdapter { + /// Create a new OrtAdapter from a model directory. /// /// The directory should contain: /// - model.onnx or model.safetensors @@ -66,8 +66,8 @@ impl EmbeddingAdapter { /// /// If the model files aren't found, operates in fallback mode with /// deterministic hash-based embeddings. - pub fn new(config: EmbeddingConfig) -> Result { - info!("Initializing embedding adapter from {:?}", config.model_dir); + pub fn new(config: OrtConfig) -> Result { + info!("Initializing ORT adapter from {:?}", config.model_dir); let model_path = config.model_dir.join("model.onnx"); let tokenizer_path = config.model_dir.join("tokenizer.json"); @@ -105,12 +105,12 @@ impl EmbeddingAdapter { }) } - /// Create an EmbeddingAdapter in fallback mode (no model required). + /// Create an OrtAdapter in fallback mode (no model required). /// /// Uses deterministic hash-based embeddings that are consistent /// for the same input text. pub fn fallback() -> Self { - info!("Creating embedding adapter in fallback mode"); + info!("Creating ORT adapter in fallback mode"); Self { session: None, tokenizer: None, @@ -160,7 +160,7 @@ impl EmbeddingAdapter { } #[async_trait] -impl EmbeddingPort for EmbeddingAdapter { +impl EmbeddingPort for OrtAdapter { /// Generate a 384-dimensional embedding for the given text. async fn embed(&self, text: &str) -> Result, Error> { if let (Some(session_arc), Some(tokenizer)) = (&self.session, &self.tokenizer) { @@ -261,21 +261,21 @@ mod tests { #[test] fn test_fallback_creation() { - let adapter = EmbeddingAdapter::fallback(); + let adapter = OrtAdapter::fallback(); assert_eq!(adapter.dimension(), 384); assert!(!adapter.has_model()); } #[tokio::test] async fn test_embed_produces_correct_dimension() { - let adapter = EmbeddingAdapter::fallback(); + let adapter = OrtAdapter::fallback(); let embedding = adapter.embed("Hello world").await.unwrap(); assert_eq!(embedding.len(), 384); } #[tokio::test] async fn test_embed_is_deterministic() { - let adapter = EmbeddingAdapter::fallback(); + let adapter = OrtAdapter::fallback(); let e1 = adapter.embed("Same text").await.unwrap(); let e2 = adapter.embed("Same text").await.unwrap(); assert_eq!(e1, e2); @@ -283,7 +283,7 @@ mod tests { #[tokio::test] async fn test_embed_different_texts_produce_different_embeddings() { - let adapter = EmbeddingAdapter::fallback(); + let adapter = OrtAdapter::fallback(); let e1 = adapter.embed("First text").await.unwrap(); let e2 = adapter.embed("Second text").await.unwrap(); assert_ne!(e1, e2); @@ -291,7 +291,7 @@ mod tests { #[tokio::test] async fn test_embedding_is_normalized() { - let adapter = EmbeddingAdapter::fallback(); + let adapter = OrtAdapter::fallback(); let embedding = adapter.embed("Test").await.unwrap(); let norm: f32 = embedding.iter().map(|x| x * x).sum::().sqrt(); @@ -304,41 +304,41 @@ mod tests { #[test] fn test_config_default() { - let config = EmbeddingConfig::default(); + let config = OrtConfig::default(); assert_eq!(config.max_seq_len, 256); } #[test] fn test_model_loading() { - let config = EmbeddingConfig::default(); + let config = OrtConfig::default(); if !config.model_dir.exists() { println!("Skipping model loading test: model dir not found"); return; } - let adapter = EmbeddingAdapter::new(config).unwrap(); + let adapter = OrtAdapter::new(config).unwrap(); assert!(adapter.has_model()); } #[tokio::test] async fn test_ort_embed_produces_correct_dimension() { - let config = EmbeddingConfig::default(); + let config = OrtConfig::default(); if !config.model_dir.exists() { println!("Skipping ORT embedding test: model dir not found"); return; } - let adapter = EmbeddingAdapter::new(config).unwrap(); + let adapter = OrtAdapter::new(config).unwrap(); let embedding = adapter.embed("Hello world").await.unwrap(); assert_eq!(embedding.len(), 384); } #[tokio::test] async fn test_ort_embedding_is_normalized() { - let config = EmbeddingConfig::default(); + let config = OrtConfig::default(); if !config.model_dir.exists() { println!("Skipping ORT normalization test: model dir not found"); return; } - let adapter = EmbeddingAdapter::new(config).unwrap(); + let adapter = OrtAdapter::new(config).unwrap(); let embedding = adapter.embed("Test").await.unwrap(); let norm: f32 = embedding.iter().map(|x| x * x).sum::().sqrt(); diff --git a/crates/synapse-infra/src/adapters/surrealdb_adapter.rs b/crates/synapse-infra/src/adapters/surrealdb_adapter.rs index 72753ecb..9831a76e 100644 --- a/crates/synapse-infra/src/adapters/surrealdb_adapter.rs +++ b/crates/synapse-infra/src/adapters/surrealdb_adapter.rs @@ -480,9 +480,6 @@ impl MemoryPort for SurrealDbAdapter { } async fn add_relationship(&self, from_id: &str, relation: &str, to_id: &str) -> Result<()> { - // Use backtick-escaped record IDs for UUIDs with hyphens - // SurrealDB syntax: RELATE memory_node:⟨uuid⟩->relation->memory_node:⟨uuid⟩ - // Note: UUIDs starting with numbers need careful escaping in SurrealDB let query = format!( "RELATE memory_node:⟨{}⟩->{}->memory_node:⟨{}⟩", from_id, relation, to_id @@ -688,7 +685,6 @@ mod tests { async fn test_vector_search() { let adapter = SurrealDbAdapter::new_memory().await.unwrap(); - // Store nodes with different embeddings let node1 = MemoryNode::new("Close vector".to_string()) .with_embedding(vec![0.1, 0.2, 0.3]); let node2 = MemoryNode::new("Far vector".to_string()) @@ -697,12 +693,10 @@ mod tests { adapter.store(node1).await.unwrap(); adapter.store(node2).await.unwrap(); - // Search for vectors close to [0.1, 0.2, 0.3] let query = vec![0.1, 0.2, 0.3]; let results = adapter.search(&query, 2).await.unwrap(); assert_eq!(results.len(), 2); - // First result should be closer assert!(results[0].distance < results[1].distance); } @@ -718,7 +712,6 @@ mod tests { adapter.store(fact).await.unwrap(); adapter.store(summary).await.unwrap(); - // Search only layer 0 let results = adapter.search_layer(&[0.1, 0.2, 0.3], 0, 10).await.unwrap(); assert_eq!(results.len(), 1); assert_eq!(results[0].node.layer, 0); @@ -738,7 +731,6 @@ mod tests { adapter.store(personal).await.unwrap(); adapter.store(medical).await.unwrap(); - // Search only personal namespace let results = adapter .search_namespace(&[0.1, 0.2, 0.3], "personal", 10) .await @@ -757,7 +749,6 @@ mod tests { let fact_id = adapter.store(fact).await.unwrap(); let summary_id = adapter.store(summary).await.unwrap(); - // Create relationship: Summary -> summarizes -> Fact adapter .add_relationship(&summary_id, "summarizes", &fact_id) .await @@ -768,11 +759,9 @@ mod tests { async fn test_count_by_layer() { let adapter = SurrealDbAdapter::new_memory().await.unwrap(); - // Initially no nodes assert_eq!(adapter.count_by_layer(0).await.unwrap(), 0); assert_eq!(adapter.count_by_layer(1).await.unwrap(), 0); - // Add Layer 0 nodes let fact1 = MemoryNode::with_layer("Fact 1".to_string(), 0) .with_embedding(vec![0.1, 0.2, 0.3]); let fact2 = MemoryNode::with_layer("Fact 2".to_string(), 0) @@ -780,12 +769,10 @@ mod tests { adapter.store(fact1).await.unwrap(); adapter.store(fact2).await.unwrap(); - // Add Layer 1 node let summary = MemoryNode::with_layer("Summary".to_string(), 1) .with_embedding(vec![0.1, 0.2, 0.3]); adapter.store(summary).await.unwrap(); - // Verify counts assert_eq!(adapter.count_by_layer(0).await.unwrap(), 2); assert_eq!(adapter.count_by_layer(1).await.unwrap(), 1); assert_eq!(adapter.count_by_layer(2).await.unwrap(), 0); diff --git a/crates/synapse-infra/src/adapters/tokenomics_adapter.rs b/crates/synapse-infra/src/adapters/tokenomics_adapter.rs index 9a98909f..5e5843a7 100644 --- a/crates/synapse-infra/src/adapters/tokenomics_adapter.rs +++ b/crates/synapse-infra/src/adapters/tokenomics_adapter.rs @@ -1,5 +1,5 @@ use async_trait::async_trait; -use serde::Deserialize; // Serialize is unused +use serde::Deserialize; use std::sync::Arc; use surrealdb::engine::local::{Db, Mem, SurrealKv}; use surrealdb::Surreal; @@ -89,9 +89,6 @@ impl SurrealTokenomicsRepository { #[async_trait] impl TokenomicsRepository for SurrealTokenomicsRepository { async fn get_user_profile(&self, wallet: &str) -> SynapseResult> { - // We query by wallet_address since that's the lookup key in the function signature, - // even though ID might be different. - // We'll Select * from user_profile where wallet_address = $wallet let mut response = self .db .query("SELECT * FROM user_profile WHERE wallet_address = $wallet LIMIT 1") @@ -107,27 +104,9 @@ impl TokenomicsRepository for SurrealTokenomicsRepository { } async fn save_user_profile(&self, profile: &UserProfile) -> SynapseResult<()> { - // Upsert based on wallet (which we marked unique) - // Or we can use the specific record ID if we mapped it. - // Let's assume we want to store it. - // We need to check if it exists or define a specific ID strategy. - // We'll query first or just use CREATE/UPDATE. - // SurrealDB `INSERT` with `ON DUPLICATE KEY UPDATE` is supported via `UPSERT` or similar logic. - // Since we have an index on wallet, we can try to update where wallet matches, or create. - - // Simpler: Use wallet as the ID part: `user_profile:wallet_address` - // But wallet addresses might have chars invalid for simple IDs without escaping. - // Let's use `SELECT` to see if exists, then UPDATE or CREATE. - let existing = self.get_user_profile(&profile.wallet_address).await?; if existing.is_some() { - // UPDATE - // We need the Record ID of the existing one? - // Actually, `get_user_profile` returns the Struct, which doesn't carry the Record ID (Thing). - // We might need to change the query to get ID. - // Or we just strictly use `UPDATE user_profile SET ... WHERE wallet_address = $w` - let _ = self.db .query("UPDATE user_profile SET karma_score = $k, is_human_verified = $h, balance = $b WHERE wallet_address = $w") .bind(("k", profile.karma_score)) @@ -137,7 +116,6 @@ impl TokenomicsRepository for SurrealTokenomicsRepository { .await .map_err(|e| Error::System(format!("Failed to update profile: {}", e)))?; } else { - // CREATE let _: Option = self .db .create("user_profile") @@ -198,19 +176,15 @@ mod tests { last_action_timestamp: 0, }; - // Save repo.save_user_profile(&profile).await.unwrap(); - // Get let loaded = repo.get_user_profile(&wallet).await.unwrap().expect("Should exist"); assert_eq!(loaded.wallet_address, wallet); assert!((loaded.karma_score - 50.0).abs() < 1e-6); - // Update profile.karma_score = 75.0; repo.save_user_profile(&profile).await.unwrap(); - // Get Updated let loaded_v2 = repo.get_user_profile(&wallet).await.unwrap().expect("Should exist"); assert!((loaded_v2.karma_score - 75.0).abs() < 1e-6); } diff --git a/crates/synapse-infra/src/security/encryption_adapter.rs b/crates/synapse-infra/src/security/encryption_adapter.rs index 626badd3..1a4b0aaa 100644 --- a/crates/synapse-infra/src/security/encryption_adapter.rs +++ b/crates/synapse-infra/src/security/encryption_adapter.rs @@ -4,7 +4,7 @@ use aes_gcm::{ Aes256Gcm, Nonce }; use synapse_core::{error::Error as SynapseError, error::Result, ports::EncryptionPort}; -use rand::Rng; +use rand::{Rng, thread_rng}; /// AES-GCM Implementation of EncryptionPort pub struct AesGcmAdapter { @@ -20,7 +20,7 @@ impl AesGcmAdapter { /// Generate a random key for the adapter pub fn generate_key() -> [u8; 32] { let mut key = [0u8; 32]; - rand::rng().fill(&mut key); + thread_rng().fill(&mut key); key } } @@ -33,7 +33,7 @@ impl EncryptionPort for AesGcmAdapter { // Generate a random 12-byte nonce let mut nonce_bytes = [0u8; 12]; - rand::rng().fill(&mut nonce_bytes); + thread_rng().fill(&mut nonce_bytes); let nonce = Nonce::from_slice(&nonce_bytes); let ciphertext = cipher.encrypt(nonce, data)