diff --git a/src/basic/keywords/think_kb.rs b/src/basic/keywords/think_kb.rs index 7c02c319..da9ee728 100644 --- a/src/basic/keywords/think_kb.rs +++ b/src/basic/keywords/think_kb.rs @@ -184,7 +184,7 @@ async fn think_kb_search( /// Calculate confidence score based on multiple factors fn calculate_confidence(avg_relevance: f64, result_count: usize, source_count: usize) -> f64 { // Base confidence from average relevance (0.0 to 1.0) - let relevance_factor = avg_relevance.min(1.0).max(0.0); + let relevance_factor = avg_relevance.clamp(0.0, 1.0); // Boost confidence with more results (diminishing returns) let result_factor = (result_count as f64 / 10.0).min(1.0); diff --git a/src/core/bot/kb_context.rs b/src/core/bot/kb_context.rs index 3ef0273d..29092424 100644 --- a/src/core/bot/kb_context.rs +++ b/src/core/bot/kb_context.rs @@ -39,6 +39,15 @@ pub struct KbSearchResult { pub chunk_tokens: usize, } +pub struct KbInjectionContext<'a> { + pub session_id: Uuid, + pub bot_id: Uuid, + pub bot_name: &'a str, + pub user_query: &'a str, + pub messages: &'a mut serde_json::Value, + pub max_context_tokens: usize, +} + #[derive(Debug)] pub struct KbContextManager { kb_manager: Arc, @@ -479,28 +488,23 @@ fn estimate_tokens(text: &str) -> usize { pub async fn inject_kb_context( kb_manager: Arc, db_pool: DbPool, - session_id: Uuid, - bot_id: Uuid, - bot_name: &str, - user_query: &str, - messages: &mut serde_json::Value, - max_context_tokens: usize, + context: KbInjectionContext<'_>, ) -> Result<()> { let context_manager = KbContextManager::new(kb_manager.clone(), db_pool.clone()); let kb_contexts = context_manager - .search_active_kbs(session_id, bot_id, bot_name, user_query, 5, max_context_tokens / 2) + .search_active_kbs(context.session_id, context.bot_id, context.bot_name, context.user_query, 5, context.max_context_tokens / 2) .await?; let website_contexts = context_manager - .search_active_websites(session_id, user_query, 5, max_context_tokens / 2) + .search_active_websites(context.session_id, context.user_query, 5, context.max_context_tokens / 2) .await?; let mut all_contexts = kb_contexts; all_contexts.extend(website_contexts); if all_contexts.is_empty() { - debug!("No KB or website context found for session {}", session_id); + debug!("No KB or website context found for session {}", context.session_id); return Ok(()); } @@ -526,10 +530,10 @@ pub async fn inject_kb_context( info!( "Injecting {} characters of KB/website context into prompt for session {}", sanitized_context.len(), - session_id + context.session_id ); - if let Some(messages_array) = messages.as_array_mut() { + if let Some(messages_array) = context.messages.as_array_mut() { let system_msg_idx = messages_array.iter().position(|m| m["role"] == "system"); if let Some(idx) = system_msg_idx { diff --git a/src/core/bot/mod.rs b/src/core/bot/mod.rs index ea6489e3..93d04b63 100644 --- a/src/core/bot/mod.rs +++ b/src/core/bot/mod.rs @@ -676,15 +676,18 @@ impl BotOrchestrator { } if let Some(kb_manager) = self.state.kb_manager.as_ref() { + let context = crate::core::bot::kb_context::KbInjectionContext { + session_id, + bot_id: session.bot_id, + bot_name: &bot_name_for_context, + user_query: &message_content, + messages: &mut messages, + max_context_tokens: 8000, + }; if let Err(e) = inject_kb_context( kb_manager.clone(), self.state.conn.clone(), - session_id, - session.bot_id, - &bot_name_for_context, - &message_content, - &mut messages, - 8000, + context, ) .await { diff --git a/src/core/package_manager/alm_setup.rs b/src/core/package_manager/alm_setup.rs index 6551965c..12510d9e 100644 --- a/src/core/package_manager/alm_setup.rs +++ b/src/core/package_manager/alm_setup.rs @@ -71,14 +71,13 @@ INSTALL_LOCK = true // Try to create admin user and get runner token via HTTP API // Note: Forgejo CLI binary may segfault on some systems, so we use curl - let runner_token = match try_alm_api_setup(alm_url, &username, &password, data_path.to_str().unwrap_or(".")).await { + let runner_token = match try_alm_api_setup(alm_url, username, &password, data_path.to_str().unwrap_or(".")).await { Ok(token) => token, Err(e) => { warn!("ALM automated setup unavailable via API: {}", e); warn!("ALM will need manual configuration. Create admin user and runner token via web UI."); // Store placeholder credentials - let placeholder_token = generate_random_string(40); - placeholder_token + generate_random_string(40) } }; diff --git a/src/core/package_manager/installer.rs b/src/core/package_manager/installer.rs index 432aa4f8..303463bf 100644 --- a/src/core/package_manager/installer.rs +++ b/src/core/package_manager/installer.rs @@ -1548,7 +1548,7 @@ VAULT_CACERT={} } // Write default credentials to Vault for all components - self.seed_vault_defaults(&vault_addr, &root_token, &ca_cert, &vault_bin)?; + self.seed_vault_defaults(&vault_addr, root_token, &ca_cert, &vault_bin)?; Ok(()) } diff --git a/src/core/shared/utils.rs b/src/core/shared/utils.rs index 2c66d81c..36326fcf 100644 --- a/src/core/shared/utils.rs +++ b/src/core/shared/utils.rs @@ -40,8 +40,12 @@ pub async fn init_secrets_manager() -> Result<()> { } pub async fn get_database_url() -> Result { - let guard = SECRETS_MANAGER.read().map_err(|e| anyhow::anyhow!("Lock poisoned: {}", e))?; - if let Some(ref manager) = *guard { + let manager = { + let guard = SECRETS_MANAGER.read().map_err(|e| anyhow::anyhow!("Lock poisoned: {}", e))?; + (*guard).as_ref().map(|manager| manager.clone()) + }; + + if let Some(manager) = manager { return manager.get_database_url().await; } @@ -114,9 +118,17 @@ pub async fn create_s3_operator( }; let (access_key, secret_key) = if config.access_key.is_empty() || config.secret_key.is_empty() { - let guard = SECRETS_MANAGER.read().map_err(|e| format!("Lock poisoned: {}", e))?; - if let Some(ref manager) = *guard { - if manager.is_enabled() { + let (manager, is_vault_enabled) = { + let guard = SECRETS_MANAGER.read().map_err(|e| format!("Lock poisoned: {}", e))?; + if let Some(ref manager) = *guard { + (Some(manager.clone()), manager.is_enabled()) + } else { + (None, false) + } + }; + + match (manager, is_vault_enabled) { + (Some(manager), true) => { match manager.get_drive_credentials().await { Ok((ak, sk)) => (ak, sk), Err(e) => { @@ -124,11 +136,8 @@ pub async fn create_s3_operator( (config.access_key.clone(), config.secret_key.clone()) } } - } else { - (config.access_key.clone(), config.secret_key.clone()) } - } else { - (config.access_key.clone(), config.secret_key.clone()) + _ => (config.access_key.clone(), config.secret_key.clone()) } } else { (config.access_key.clone(), config.secret_key.clone()) diff --git a/src/drive/local_file_monitor.rs b/src/drive/local_file_monitor.rs index 3f883604..260bf417 100644 --- a/src/drive/local_file_monitor.rs +++ b/src/drive/local_file_monitor.rs @@ -333,16 +333,14 @@ impl LocalFileMonitor { let path = entry.path(); if path.is_dir() { stack.push(path); - } else { - if let Ok(meta) = tokio::fs::metadata(&path).await { - let mtime = meta.modified() - .map(|t| t.duration_since(SystemTime::UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0)) - .unwrap_or(0); - let size = meta.len(); - // Simple combinatorial hash - hash = hash.wrapping_mul(31).wrapping_add(mtime.wrapping_mul(37).wrapping_add(size)); - file_count += 1; - } + } else if let Ok(meta) = tokio::fs::metadata(&path).await { + let mtime = meta.modified() + .map(|t| t.duration_since(SystemTime::UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0)) + .unwrap_or(0); + let size = meta.len(); + // Simple combinatorial hash + hash = hash.wrapping_mul(31).wrapping_add(mtime.wrapping_mul(37).wrapping_add(size)); + file_count += 1; } } } diff --git a/src/main_module/bootstrap.rs b/src/main_module/bootstrap.rs index d7c32a33..9b631dd4 100644 --- a/src/main_module/bootstrap.rs +++ b/src/main_module/bootstrap.rs @@ -337,11 +337,11 @@ pub async fn init_redis() -> Option> { Ok(mut conn) => { match redis::cmd("PING").query::(&mut conn) { Ok(response) if response == "PONG" => { - log::info!("Cache initialized - Valkey connected via {}", cache_url.split('@').last().unwrap_or(&cache_url)); + log::info!("Cache initialized - Valkey connected via {}", cache_url.split('@').next_back().unwrap_or(&cache_url)); Ok(Some(Arc::new(client))) } Ok(response) => { - log::info!("Cache initialized - Valkey connected via {} (PING: {})", cache_url.split('@').last().unwrap_or(&cache_url), response); + log::info!("Cache initialized - Valkey connected via {} (PING: {})", cache_url.split('@').next_back().unwrap_or(&cache_url), response); Ok(Some(Arc::new(client))) } Err(e) => { diff --git a/src/security/integration.rs b/src/security/integration.rs index 9f875b6b..37539439 100644 --- a/src/security/integration.rs +++ b/src/security/integration.rs @@ -38,12 +38,12 @@ impl TlsIntegration { let qdrant_secure = qdrant_url.replace("http://", "https://"); let qdrant_port: u16 = qdrant_url .split(':') - .last() + .next_back() .and_then(|p| p.parse().ok()) .unwrap_or(6333); let qdrant_tls_port: u16 = qdrant_secure .split(':') - .last() + .next_back() .and_then(|p| p.parse().ok()) .unwrap_or(6334); @@ -62,12 +62,12 @@ impl TlsIntegration { let llm_secure = llm_url.replace("http://", "https://"); let llm_port: u16 = llm_url .split(':') - .last() + .next_back() .and_then(|p| p.parse().ok()) .unwrap_or(8081); let llm_tls_port: u16 = llm_secure .split(':') - .last() + .next_back() .and_then(|p| p.parse().ok()) .unwrap_or(8444); @@ -105,7 +105,7 @@ impl TlsIntegration { }; let drive_port: u16 = drive_host .split(':') - .last() + .next_back() .and_then(|p| p.parse().ok()) .unwrap_or(9100); @@ -123,12 +123,12 @@ impl TlsIntegration { let directory_secure = directory_url.replace("http://", "https://"); let directory_port: u16 = directory_url .split(':') - .last() + .next_back() .and_then(|p| p.parse().ok()) .unwrap_or(9000); let directory_tls_port: u16 = directory_secure .split(':') - .last() + .next_back() .and_then(|p| p.parse().ok()) .unwrap_or(8446);