use crate::capabilities::{
RuvectorCapabilities, ATTENTION_AVAILABLE, GNN_AVAILABLE, GRAPH_AVAILABLE, HNSW_AVAILABLE,
SONA_AVAILABLE,
};
use crate::claude_flow::{AgentRouter, AgentType};
use crate::error::{Result, RuvLLMError};
use crate::sona::{RoutingRecommendation, SonaConfig, SonaIntegration, SonaStats, Trajectory};
use parking_lot::RwLock;
use ruvector_core::index::hnsw::HnswIndex;
use ruvector_core::index::VectorIndex;
use ruvector_core::types::{DistanceMetric, HnswConfig, VectorId};
use ruvector_sona::{LearnedPattern, PatternConfig, ReasoningBank};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrationConfig {
pub embedding_dim: usize,
pub hnsw_config: HnswConfig,
pub sona_config: SonaConfig,
pub distance_metric: DistanceMetric,
pub enable_attention: bool,
pub enable_graph: bool,
pub enable_gnn: bool,
pub routing_confidence_threshold: f32,
pub max_pattern_search: usize,
pub learning_rate: f32,
pub ewc_lambda: f32,
}
impl Default for IntegrationConfig {
fn default() -> Self {
let caps = RuvectorCapabilities::detect();
let (m, ef_construction, ef_search) = caps.recommended_hnsw_params();
Self {
embedding_dim: 768,
hnsw_config: HnswConfig {
m,
ef_construction,
ef_search,
max_elements: 100_000,
},
sona_config: SonaConfig::default(),
distance_metric: DistanceMetric::Cosine,
enable_attention: ATTENTION_AVAILABLE,
enable_graph: GRAPH_AVAILABLE,
enable_gnn: GNN_AVAILABLE,
routing_confidence_threshold: 0.6,
max_pattern_search: 10,
learning_rate: 0.01,
ewc_lambda: 0.1,
}
}
}
pub struct UnifiedIndex {
hnsw: Arc<RwLock<HnswIndex>>,
reasoning_bank: Arc<RwLock<ReasoningBank>>,
metadata: Arc<RwLock<HashMap<VectorId, VectorMetadata>>>,
config: IntegrationConfig,
stats: UnifiedIndexStats,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VectorMetadata {
pub source: String,
pub task_type: Option<String>,
pub agent_type: Option<AgentType>,
pub quality_score: f32,
pub access_count: u64,
pub created_at: chrono::DateTime<chrono::Utc>,
pub last_accessed: chrono::DateTime<chrono::Utc>,
pub tags: Vec<String>,
}
impl Default for VectorMetadata {
fn default() -> Self {
let now = chrono::Utc::now();
Self {
source: "unknown".to_string(),
task_type: None,
agent_type: None,
quality_score: 0.0,
access_count: 0,
created_at: now,
last_accessed: now,
tags: Vec::new(),
}
}
}
#[derive(Debug, Default)]
pub struct UnifiedIndexStats {
pub total_vectors: AtomicU64,
pub total_searches: AtomicU64,
pub successful_matches: AtomicU64,
pub avg_search_latency_us: AtomicU64,
pub patterns_learned: AtomicU64,
}
impl Clone for UnifiedIndexStats {
fn clone(&self) -> Self {
Self {
total_vectors: AtomicU64::new(self.total_vectors.load(Ordering::Relaxed)),
total_searches: AtomicU64::new(self.total_searches.load(Ordering::Relaxed)),
successful_matches: AtomicU64::new(self.successful_matches.load(Ordering::Relaxed)),
avg_search_latency_us: AtomicU64::new(
self.avg_search_latency_us.load(Ordering::Relaxed),
),
patterns_learned: AtomicU64::new(self.patterns_learned.load(Ordering::Relaxed)),
}
}
}
impl UnifiedIndex {
pub fn new(config: IntegrationConfig) -> Result<Self> {
let hnsw = HnswIndex::new(
config.embedding_dim,
config.distance_metric,
config.hnsw_config.clone(),
)
.map_err(|e| RuvLLMError::Ruvector(e.to_string()))?;
let pattern_config = PatternConfig {
k_clusters: 100,
embedding_dim: config.embedding_dim.min(256),
max_trajectories: 10000,
quality_threshold: config.routing_confidence_threshold,
..Default::default()
};
let reasoning_bank = ReasoningBank::new(pattern_config);
Ok(Self {
hnsw: Arc::new(RwLock::new(hnsw)),
reasoning_bank: Arc::new(RwLock::new(reasoning_bank)),
metadata: Arc::new(RwLock::new(HashMap::new())),
config,
stats: UnifiedIndexStats::default(),
})
}
pub fn add(&self, id: VectorId, vector: Vec<f32>, metadata: VectorMetadata) -> Result<()> {
{
let mut hnsw = self.hnsw.write();
hnsw.add(id.clone(), vector)?;
}
{
let mut meta = self.metadata.write();
meta.insert(id, metadata);
}
self.stats.total_vectors.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn add_batch(&self, entries: Vec<(VectorId, Vec<f32>, VectorMetadata)>) -> Result<()> {
let vectors: Vec<(VectorId, Vec<f32>)> = entries
.iter()
.map(|(id, vec, _)| (id.clone(), vec.clone()))
.collect();
{
let mut hnsw = self.hnsw.write();
hnsw.add_batch(vectors)?;
}
{
let mut meta = self.metadata.write();
for (id, _, metadata) in entries.iter() {
meta.insert(id.clone(), metadata.clone());
}
}
self.stats
.total_vectors
.fetch_add(entries.len() as u64, Ordering::SeqCst);
Ok(())
}
pub fn search(&self, query: &[f32], k: usize) -> Result<Vec<SearchResultWithMetadata>> {
let start = std::time::Instant::now();
let results = {
let hnsw = self.hnsw.read();
hnsw.search(query, k)?
};
let metadata = self.metadata.read();
let enriched: Vec<SearchResultWithMetadata> = results
.into_iter()
.map(|r| {
let meta = metadata.get(&r.id).cloned();
SearchResultWithMetadata {
id: r.id,
score: r.score,
metadata: meta,
}
})
.collect();
let latency = start.elapsed().as_micros() as u64;
self.stats.total_searches.fetch_add(1, Ordering::SeqCst);
let current_avg = self.stats.avg_search_latency_us.load(Ordering::SeqCst);
let searches = self.stats.total_searches.load(Ordering::SeqCst);
let new_avg = (current_avg * (searches - 1) + latency) / searches;
self.stats
.avg_search_latency_us
.store(new_avg, Ordering::SeqCst);
if !enriched.is_empty() {
self.stats.successful_matches.fetch_add(1, Ordering::SeqCst);
}
Ok(enriched)
}
#[cfg(feature = "attention")]
pub fn search_with_attention(
&self,
query: &[f32],
k: usize,
attention_context: Option<&[f32]>,
) -> Result<Vec<SearchResultWithMetadata>> {
let effective_query = if let Some(ctx) = attention_context {
let alpha = 0.7; query
.iter()
.zip(ctx.iter())
.map(|(q, c)| alpha * q + (1.0 - alpha) * c)
.collect::<Vec<_>>()
} else {
query.to_vec()
};
self.search(&effective_query, k)
}
#[cfg(not(feature = "attention"))]
pub fn search_with_attention(
&self,
query: &[f32],
k: usize,
_attention_context: Option<&[f32]>,
) -> Result<Vec<SearchResultWithMetadata>> {
self.search(query, k)
}
pub fn stats(&self) -> IndexStats {
IndexStats {
total_vectors: self.stats.total_vectors.load(Ordering::SeqCst),
total_searches: self.stats.total_searches.load(Ordering::SeqCst),
successful_matches: self.stats.successful_matches.load(Ordering::SeqCst),
avg_search_latency_us: self.stats.avg_search_latency_us.load(Ordering::SeqCst),
patterns_learned: self.stats.patterns_learned.load(Ordering::SeqCst),
hnsw_config: self.config.hnsw_config.clone(),
}
}
pub fn reasoning_bank(&self) -> &Arc<RwLock<ReasoningBank>> {
&self.reasoning_bank
}
}
#[derive(Debug, Clone)]
pub struct SearchResultWithMetadata {
pub id: VectorId,
pub score: f32,
pub metadata: Option<VectorMetadata>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexStats {
pub total_vectors: u64,
pub total_searches: u64,
pub successful_matches: u64,
pub avg_search_latency_us: u64,
pub patterns_learned: u64,
pub hnsw_config: HnswConfig,
}
pub struct IntelligenceLayer {
sona: Arc<RwLock<SonaIntegration>>,
router: Arc<RwLock<AgentRouter>>,
index: Arc<UnifiedIndex>,
config: IntegrationConfig,
stats: IntelligenceStats,
}
#[derive(Debug, Default)]
pub struct IntelligenceStats {
pub routing_decisions: AtomicU64,
pub successful_routings: AtomicU64,
pub pattern_based_routings: AtomicU64,
pub learning_updates: AtomicU64,
pub ewc_consolidations: AtomicU64,
}
impl Clone for IntelligenceStats {
fn clone(&self) -> Self {
Self {
routing_decisions: AtomicU64::new(self.routing_decisions.load(Ordering::Relaxed)),
successful_routings: AtomicU64::new(self.successful_routings.load(Ordering::Relaxed)),
pattern_based_routings: AtomicU64::new(
self.pattern_based_routings.load(Ordering::Relaxed),
),
learning_updates: AtomicU64::new(self.learning_updates.load(Ordering::Relaxed)),
ewc_consolidations: AtomicU64::new(self.ewc_consolidations.load(Ordering::Relaxed)),
}
}
}
#[derive(Debug, Clone)]
pub struct IntelligentRoutingDecision {
pub agent: AgentType,
pub confidence: f32,
pub alternatives: Vec<(AgentType, f32)>,
pub reasoning: Vec<String>,
pub influencing_patterns: Vec<LearnedPattern>,
pub pattern_based: bool,
pub model_tier: usize,
}
impl IntelligenceLayer {
pub fn new(config: IntegrationConfig) -> Result<Self> {
let sona = SonaIntegration::new(config.sona_config.clone());
let router = AgentRouter::new(config.sona_config.clone());
let index = UnifiedIndex::new(config.clone())?;
Ok(Self {
sona: Arc::new(RwLock::new(sona)),
router: Arc::new(RwLock::new(router)),
index: Arc::new(index),
config,
stats: IntelligenceStats::default(),
})
}
pub fn route(&self, task_description: &str, embedding: &[f32]) -> IntelligentRoutingDecision {
self.stats.routing_decisions.fetch_add(1, Ordering::SeqCst);
let mut reasoning = Vec::new();
let sona_rec = {
let sona = self.sona.read();
sona.get_routing_recommendation(embedding)
};
let similar_results = self
.index
.search(embedding, self.config.max_pattern_search)
.unwrap_or_default();
let keyword_decision = {
let mut router = self.router.write();
router.route(task_description, Some(embedding))
};
let mut influencing_patterns: Vec<LearnedPattern> = Vec::new();
{
let rb = self.index.reasoning_bank().read();
let patterns = rb.find_similar(embedding, 5);
influencing_patterns = patterns.into_iter().cloned().collect();
}
reasoning.push(format!(
"Task analyzed: '{}'",
task_description.chars().take(50).collect::<String>()
));
let (agent, confidence, pattern_based) = if sona_rec.based_on_patterns > 0
&& sona_rec.confidence > self.config.routing_confidence_threshold
{
self.stats
.pattern_based_routings
.fetch_add(1, Ordering::SeqCst);
reasoning.push(format!(
"SONA pattern match: {} patterns, avg quality {:.2}",
sona_rec.based_on_patterns, sona_rec.average_quality
));
let agent = Self::model_index_to_agent(sona_rec.suggested_model);
(agent, sona_rec.confidence, true)
} else if !similar_results.is_empty() && similar_results[0].score < 0.3 {
self.stats
.pattern_based_routings
.fetch_add(1, Ordering::SeqCst);
let best = &similar_results[0];
let agent = best
.metadata
.as_ref()
.and_then(|m| m.agent_type)
.unwrap_or(keyword_decision.primary_agent);
reasoning.push(format!(
"Vector similarity match: score={:.3}, source={}",
best.score,
best.metadata
.as_ref()
.map(|m| m.source.as_str())
.unwrap_or("unknown")
));
(agent, 0.8 * (1.0 - best.score), true)
} else {
reasoning.push(format!(
"Keyword routing: matched {} keywords, confidence={:.2}",
keyword_decision.learned_patterns, keyword_decision.confidence
));
(
keyword_decision.primary_agent,
keyword_decision.confidence,
false,
)
};
let model_tier = Self::determine_model_tier(task_description, confidence);
reasoning.push(format!(
"Model tier selected: {} ({})",
model_tier,
match model_tier {
0 => "haiku/fast",
1 => "sonnet/balanced",
_ => "opus/powerful",
}
));
let alternatives = keyword_decision.alternatives;
IntelligentRoutingDecision {
agent,
confidence,
alternatives,
reasoning,
influencing_patterns,
pattern_based,
model_tier,
}
}
pub fn learn_from_outcome(
&self,
task_description: &str,
embedding: &[f32],
agent_used: AgentType,
success: bool,
quality_score: f32,
) -> Result<()> {
self.stats.learning_updates.fetch_add(1, Ordering::SeqCst);
let trajectory = Trajectory {
request_id: uuid::Uuid::new_v4().to_string(),
session_id: "ruvector-integration".to_string(),
query_embedding: embedding.to_vec(),
response_embedding: embedding.to_vec(),
quality_score,
routing_features: vec![
agent_used as u8 as f32 / 10.0,
if success { 1.0 } else { 0.0 },
quality_score,
],
model_index: agent_used as usize,
timestamp: chrono::Utc::now(),
};
{
let sona = self.sona.read();
sona.record_trajectory(trajectory)?;
}
{
let mut router = self.router.write();
router.record_feedback(task_description, embedding, agent_used, success);
}
if success && quality_score > self.config.routing_confidence_threshold {
let metadata = VectorMetadata {
source: "learning".to_string(),
task_type: Some(task_description.chars().take(50).collect()),
agent_type: Some(agent_used),
quality_score,
..Default::default()
};
let id = format!("pattern-{}", uuid::Uuid::new_v4());
self.index.add(id, embedding.to_vec(), metadata)?;
self.stats
.successful_routings
.fetch_add(1, Ordering::SeqCst);
}
Ok(())
}
pub fn trigger_background_learning(&self) -> Result<()> {
let sona = self.sona.read();
sona.trigger_background_loop()?;
self.stats.ewc_consolidations.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn trigger_deep_learning(&self) -> Result<()> {
let sona = self.sona.read();
sona.trigger_deep_loop()?;
Ok(())
}
pub fn sona_stats(&self) -> SonaStats {
self.sona.read().stats()
}
pub fn stats(&self) -> IntelligenceLayerStats {
IntelligenceLayerStats {
routing_decisions: self.stats.routing_decisions.load(Ordering::SeqCst),
successful_routings: self.stats.successful_routings.load(Ordering::SeqCst),
pattern_based_routings: self.stats.pattern_based_routings.load(Ordering::SeqCst),
learning_updates: self.stats.learning_updates.load(Ordering::SeqCst),
ewc_consolidations: self.stats.ewc_consolidations.load(Ordering::SeqCst),
sona_stats: self.sona_stats(),
index_stats: self.index.stats(),
router_accuracy: self.router.read().accuracy(),
}
}
fn model_index_to_agent(index: usize) -> AgentType {
match index {
0 => AgentType::Coder,
1 => AgentType::Researcher,
2 => AgentType::Tester,
3 => AgentType::Reviewer,
4 => AgentType::Architect,
5 => AgentType::Security,
6 => AgentType::Performance,
_ => AgentType::Coder,
}
}
fn determine_model_tier(task: &str, confidence: f32) -> usize {
let lower = task.to_lowercase();
if lower.contains("architect")
|| lower.contains("design")
|| lower.contains("security")
|| lower.contains("complex")
|| lower.contains("refactor")
{
return 2;
}
if confidence > 0.8
&& (lower.contains("simple")
|| lower.contains("fix")
|| lower.contains("typo")
|| lower.contains("format")
|| lower.len() < 50)
{
return 0;
}
1
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntelligenceLayerStats {
pub routing_decisions: u64,
pub successful_routings: u64,
pub pattern_based_routings: u64,
pub learning_updates: u64,
pub ewc_consolidations: u64,
pub sona_stats: SonaStats,
pub index_stats: IndexStats,
pub router_accuracy: f32,
}
pub struct RuvectorIntegration {
capabilities: RuvectorCapabilities,
config: IntegrationConfig,
intelligence: IntelligenceLayer,
unified_index: Arc<UnifiedIndex>,
}
impl RuvectorIntegration {
pub fn new(config: IntegrationConfig) -> Result<Self> {
let capabilities = RuvectorCapabilities::detect();
let intelligence = IntelligenceLayer::new(config.clone())?;
let unified_index = Arc::new(UnifiedIndex::new(config.clone())?);
tracing::info!(
"RuvectorIntegration initialized: {}",
capabilities.summary()
);
Ok(Self {
capabilities,
config,
intelligence,
unified_index,
})
}
pub fn capabilities(&self) -> &RuvectorCapabilities {
&self.capabilities
}
pub fn capabilities_summary(&self) -> String {
self.capabilities.summary()
}
pub fn create_unified_index(&self) -> Result<UnifiedIndex> {
UnifiedIndex::new(self.config.clone())
}
pub fn unified_index(&self) -> &Arc<UnifiedIndex> {
&self.unified_index
}
pub fn route_with_intelligence(
&self,
task: &str,
embedding: &[f32],
) -> IntelligentRoutingDecision {
self.intelligence.route(task, embedding)
}
pub fn learn_from_outcome(
&self,
task: &str,
embedding: &[f32],
agent: AgentType,
success: bool,
quality: f32,
) -> Result<()> {
self.intelligence
.learn_from_outcome(task, embedding, agent, success, quality)
}
pub fn trigger_background_learning(&self) -> Result<()> {
self.intelligence.trigger_background_learning()
}
pub fn trigger_deep_learning(&self) -> Result<()> {
self.intelligence.trigger_deep_learning()
}
pub fn stats(&self) -> IntegrationStats {
IntegrationStats {
capabilities: self.capabilities,
intelligence: self.intelligence.stats(),
index: self.unified_index.stats(),
}
}
pub fn search(&self, query: &[f32], k: usize) -> Result<Vec<SearchResultWithMetadata>> {
self.unified_index.search(query, k)
}
pub fn add_vector(
&self,
id: VectorId,
vector: Vec<f32>,
metadata: VectorMetadata,
) -> Result<()> {
self.unified_index.add(id, vector, metadata)
}
pub fn has_feature(&self, feature: &str) -> bool {
match feature.to_lowercase().as_str() {
"hnsw" => self.capabilities.hnsw,
"attention" | "flash" => self.capabilities.attention,
"graph" => self.capabilities.graph,
"gnn" => self.capabilities.gnn,
"sona" => self.capabilities.sona,
"simd" => self.capabilities.simd,
"parallel" => self.capabilities.parallel,
_ => false,
}
}
#[cfg(feature = "attention")]
pub fn compute_attention(&self, query: &[f32], keys: &[&[f32]], values: &[&[f32]]) -> Vec<f32> {
use ruvector_attention::{traits::Attention, ScaledDotProductAttention};
let attention = ScaledDotProductAttention::new(query.len());
attention.compute(query, keys, values).unwrap_or_default()
}
#[cfg(not(feature = "attention"))]
pub fn compute_attention(
&self,
query: &[f32],
_keys: &[&[f32]],
values: &[&[f32]],
) -> Vec<f32> {
if values.is_empty() {
return query.to_vec();
}
let dim = query.len();
let mut result = vec![0.0; dim];
for v in values {
for (i, val) in v.iter().take(dim).enumerate() {
result[i] += val;
}
}
for r in &mut result {
*r /= values.len() as f32;
}
result
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrationStats {
pub capabilities: RuvectorCapabilities,
pub intelligence: IntelligenceLayerStats,
pub index: IndexStats,
}
#[cfg(test)]
mod tests {
use super::*;
fn test_embedding() -> Vec<f32> {
vec![0.1; 768]
}
#[test]
fn test_integration_config_default() {
let config = IntegrationConfig::default();
assert_eq!(config.embedding_dim, 768);
assert!(config.routing_confidence_threshold > 0.0);
}
#[test]
fn test_unified_index_creation() {
let config = IntegrationConfig::default();
let index = UnifiedIndex::new(config).unwrap();
assert_eq!(index.stats().total_vectors, 0);
}
#[test]
fn test_unified_index_add_and_search() {
let config = IntegrationConfig {
embedding_dim: 128,
..Default::default()
};
let index = UnifiedIndex::new(config).unwrap();
let embedding = vec![0.1; 128];
let metadata = VectorMetadata {
source: "test".to_string(),
..Default::default()
};
index
.add("test-1".to_string(), embedding.clone(), metadata)
.unwrap();
let results = index.search(&embedding, 5).unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].id, "test-1");
}
#[test]
fn test_intelligence_layer_routing() {
let config = IntegrationConfig {
embedding_dim: 128,
..Default::default()
};
let intelligence = IntelligenceLayer::new(config).unwrap();
let embedding = vec![0.1; 128];
let decision = intelligence.route("implement a REST API", &embedding);
assert!(decision.confidence > 0.0);
assert!(!decision.reasoning.is_empty());
}
#[test]
fn test_ruvector_integration() {
let config = IntegrationConfig {
embedding_dim: 128,
..Default::default()
};
let integration = RuvectorIntegration::new(config).unwrap();
assert!(integration.capabilities().hnsw);
assert!(integration.capabilities().sona);
let summary = integration.capabilities_summary();
assert!(summary.contains("HNSW"));
assert!(summary.contains("SONA"));
}
#[test]
fn test_route_with_intelligence() {
let config = IntegrationConfig {
embedding_dim: 128,
..Default::default()
};
let integration = RuvectorIntegration::new(config).unwrap();
let embedding = vec![0.1; 128];
let decision = integration.route_with_intelligence("write unit tests", &embedding);
assert!(decision.confidence > 0.0);
assert!(decision.model_tier <= 2);
}
#[test]
fn test_learn_from_outcome() {
let config = IntegrationConfig {
embedding_dim: 128,
..Default::default()
};
let integration = RuvectorIntegration::new(config).unwrap();
let embedding = vec![0.1; 128];
integration
.learn_from_outcome("test task", &embedding, AgentType::Tester, true, 0.9)
.unwrap();
let stats = integration.stats();
assert_eq!(stats.intelligence.learning_updates, 1);
}
#[test]
fn test_model_tier_determination() {
assert_eq!(
IntelligenceLayer::determine_model_tier("architect a microservices system", 0.5),
2
);
assert_eq!(IntelligenceLayer::determine_model_tier("fix typo", 0.9), 0);
assert_eq!(
IntelligenceLayer::determine_model_tier("implement feature", 0.7),
1
);
}
#[test]
fn test_has_feature() {
let config = IntegrationConfig::default();
let integration = RuvectorIntegration::new(config).unwrap();
assert!(integration.has_feature("hnsw"));
assert!(integration.has_feature("sona"));
assert!(!integration.has_feature("unknown_feature"));
}
}