From cc4ba87e2d18674fe89dc06e43a5ffd2fcda22a2 Mon Sep 17 00:00:00 2001 From: rock Date: Mon, 7 Sep 2026 17:54:29 -0700 Subject: [PATCH] fix: resolve all 75 mem-cli compilation errors across 25 files - embed_text -> embed_one + Vector to Vec conversion (semantic.rs, unified_query.rs) - DefaultAgent: remove shadowing type alias, re-export concrete struct - Position: add Default derive for unwrap_or_default() - streaming_body -> streaming + yield Result for SSE - borrow-after-move: compute len before move in 6 places - add missing imports: sqlx::Row, chrono::Timelike, std::pin::Pin - add missing derives: Serialize on CompactionStats, FacetFilters - extract_token: extract Authorization header from HttpRequest first - AuthError variants: match actual enum (TokenExpired, not ExpiredToken) - validate_bearer_token -> extract_bearer_token (sync check) - check_limit -> check with correct args - link_entities -> link_mentions (async, correct signature) - InferenceEngine::new + infer_facts: match actual 2-arg/3-arg API - RoutedResult: add missing confidence_score + is_valid fields - client_sdk: fix ownership (remove borrow, save status before .text()) - index_chunk -> index_document (match OpenSearchClient API) - recursive async dfs_paths: Box::pin for infinite future size - log -> tracing crate in authentik_service_account - CI: add SQLX_OFFLINE=true env var for offline builds --- .gitea/workflows/build.yaml | 1 + crates/mem-cli/src/agent/client_sdk.rs | 5 ++-- crates/mem-cli/src/agent/mod.rs | 4 +-- .../src/auth/authentik_service_account.rs | 2 +- crates/mem-cli/src/auth_middleware.rs | 8 +++--- crates/mem-cli/src/compaction.rs | 2 +- crates/mem-cli/src/handlers/middleware.rs | 6 ++--- .../mem-cli/src/handlers/ranking_handler.rs | 2 +- .../mem-cli/src/handlers/rebuild_handler.rs | 4 +-- crates/mem-cli/src/handlers/semantic.rs | 12 ++++----- crates/mem-cli/src/handlers/synthesis.rs | 3 ++- crates/mem-cli/src/handlers/unified_query.rs | 4 +-- .../mem-cli/src/handlers/unified_synthesis.rs | 16 ++++++------ .../src/handlers/versioning_handler.rs | 12 ++++----- crates/mem-cli/src/handlers/visualize_sse.rs | 8 +++--- crates/mem-cli/src/parallel_dual_write.rs | 10 +++---- .../mem-cli/src/query/bfs_graph_traversal.rs | 5 ++-- .../mem-cli/src/query/community_detector.rs | 10 +++---- crates/mem-cli/src/query/faceted_search.rs | 4 +-- .../src/query/force_directed_layout.rs | 2 +- crates/mem-cli/src/query/inference_engine.rs | 26 +++++++++++-------- crates/mem-cli/src/query/path_finder.rs | 24 ++++++++++------- .../mem-cli/src/query/semantic_retriever.rs | 4 +-- crates/mem-cli/src/query/summarizer.rs | 4 +-- crates/mem-cli/src/query_router.rs | 2 ++ 25 files changed, 99 insertions(+), 81 deletions(-) diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 18c6fda..0f1e31c 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -11,6 +11,7 @@ env: REGISTRY: forgejo.riotpiao.com IMAGE: forgejo.riotpiao.com/rock/poimen-memory DOCKER_HOST: tcp://localhost:2375 + SQLX_OFFLINE: "true" jobs: ci: diff --git a/crates/mem-cli/src/agent/client_sdk.rs b/crates/mem-cli/src/agent/client_sdk.rs index e4262c7..2b87bc9 100644 --- a/crates/mem-cli/src/agent/client_sdk.rs +++ b/crates/mem-cli/src/agent/client_sdk.rs @@ -227,7 +227,7 @@ impl SynthesisClient { ) -> Vec> { let mut results = Vec::new(); for req in requests { - results.push(self.execute(&req).await); + results.push(self.execute(req).await); } results } @@ -280,11 +280,12 @@ impl SynthesisClient { tracing::debug!("Workflow executed in {}ms", elapsed_ms); Ok(body) } else { + let status = response.status(); let error_text = response .text() .await .unwrap_or_else(|_| "unknown error".to_string()); - Err(format!("Workflow failed ({}): {}", response.status(), error_text)) + Err(format!("Workflow failed ({}): {}", status, error_text)) } } } diff --git a/crates/mem-cli/src/agent/mod.rs b/crates/mem-cli/src/agent/mod.rs index 990af38..36e1145 100644 --- a/crates/mem-cli/src/agent/mod.rs +++ b/crates/mem-cli/src/agent/mod.rs @@ -11,6 +11,4 @@ pub use agent_interface::{Agent, AgentConfig, AgentCapability}; pub use webhook_handler::{WebhookEvent, WebhookPayload}; pub use observability::{AgentMetrics, MetricsCollector}; pub use client_sdk::{SynthesisClient, ClientRequest, ClientResponse}; - -/// Default agent implementation (type alias for Agent) -pub type DefaultAgent = Agent; +pub use agent_interface::DefaultAgent; diff --git a/crates/mem-cli/src/auth/authentik_service_account.rs b/crates/mem-cli/src/auth/authentik_service_account.rs index 419e232..7c58a2c 100644 --- a/crates/mem-cli/src/auth/authentik_service_account.rs +++ b/crates/mem-cli/src/auth/authentik_service_account.rs @@ -5,7 +5,7 @@ use std::sync::{Arc, RwLock}; use std::time::{Duration, Instant}; use serde::{Deserialize, Serialize}; use reqwest::Client; -use log::{debug, warn, error}; +use tracing::{debug, warn, error}; #[derive(Clone, Debug)] pub struct AuthentikServiceAccountConfig { diff --git a/crates/mem-cli/src/auth_middleware.rs b/crates/mem-cli/src/auth_middleware.rs index 5c18d09..6628cb8 100644 --- a/crates/mem-cli/src/auth_middleware.rs +++ b/crates/mem-cli/src/auth_middleware.rs @@ -59,15 +59,17 @@ pub fn auth_error_response(error: &AuthError) -> HttpResponse { let (status, message) = match error { AuthError::MissingToken => ("Unauthorized", "Missing or invalid Authorization header"), AuthError::InvalidSignature => ("Unauthorized", "Invalid token signature"), - AuthError::ExpiredToken => ("Unauthorized", "Token has expired"), + AuthError::TokenExpired => ("Unauthorized", "Token has expired"), AuthError::InvalidIssuer => ("Unauthorized", "Invalid token issuer"), - AuthError::AccessDenied => ("Forbidden", "Access denied for this resource"), - AuthError::InvalidClaims => ("Unauthorized", "Invalid or missing required claims"), + AuthError::InvalidAudience => ("Unauthorized", "Invalid token audience"), + AuthError::ProviderUnavailable(_) => ("ServiceUnavailable", "Auth provider unavailable"), + AuthError::Other(_) => ("Unauthorized", "Authentication error"), }; HttpResponse::build(match status { "Unauthorized" => actix_web::http::StatusCode::UNAUTHORIZED, "Forbidden" => actix_web::http::StatusCode::FORBIDDEN, + "ServiceUnavailable" => actix_web::http::StatusCode::SERVICE_UNAVAILABLE, _ => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR, }) .json(json!({ diff --git a/crates/mem-cli/src/compaction.rs b/crates/mem-cli/src/compaction.rs index 4b889d4..552d54f 100644 --- a/crates/mem-cli/src/compaction.rs +++ b/crates/mem-cli/src/compaction.rs @@ -19,7 +19,7 @@ pub trait LlmCaller: Send + Sync { } /// Compaction statistics -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, serde::Serialize)] pub struct CompactionStats { pub duplicate_edges_deleted: usize, pub stale_facts_deleted: usize, diff --git a/crates/mem-cli/src/handlers/middleware.rs b/crates/mem-cli/src/handlers/middleware.rs index 59f2a72..7103ecb 100644 --- a/crates/mem-cli/src/handlers/middleware.rs +++ b/crates/mem-cli/src/handlers/middleware.rs @@ -41,7 +41,7 @@ pub fn validate_and_rate_limit( })) })?; - jwt_validator.validate_bearer_token(auth_header).map_err(|e| { + crate::jwt_validator::JwtValidator::extract_bearer_token(auth_header).map_err(|e| { HttpResponse::Unauthorized().json(json!({ "error": format!("JWT validation failed: {}", e) })) @@ -51,10 +51,10 @@ pub fn validate_and_rate_limit( // 2. Rate limiting (if enabled) state .rate_limiter - .check_limit(endpoint, rate_limit) + .check("default", endpoint) .map_err(|e| { HttpResponse::TooManyRequests().json(json!({ - "error": format!("Rate limit exceeded: {}", e) + "error": format!("Rate limit exceeded: {}", e.reason()) })) })?; diff --git a/crates/mem-cli/src/handlers/ranking_handler.rs b/crates/mem-cli/src/handlers/ranking_handler.rs index ff70cc8..030be7f 100644 --- a/crates/mem-cli/src/handlers/ranking_handler.rs +++ b/crates/mem-cli/src/handlers/ranking_handler.rs @@ -171,7 +171,7 @@ pub struct RankedResult { /// GET /memory/ranking/profiles pub async fn get_ranking_profiles(req: HttpRequest) -> HttpResponse { // Verify auth - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); diff --git a/crates/mem-cli/src/handlers/rebuild_handler.rs b/crates/mem-cli/src/handlers/rebuild_handler.rs index 22f754d..96fa834 100644 --- a/crates/mem-cli/src/handlers/rebuild_handler.rs +++ b/crates/mem-cli/src/handlers/rebuild_handler.rs @@ -54,7 +54,7 @@ pub async fn rebuild( pool: web::Data, ) -> HttpResponse { // Verify auth - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); @@ -155,7 +155,7 @@ pub async fn rebuild_status( pool: web::Data, ) -> HttpResponse { // Verify auth - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); diff --git a/crates/mem-cli/src/handlers/semantic.rs b/crates/mem-cli/src/handlers/semantic.rs index 8603e56..804e08e 100644 --- a/crates/mem-cli/src/handlers/semantic.rs +++ b/crates/mem-cli/src/handlers/semantic.rs @@ -142,8 +142,8 @@ pub async fn search_entities_handler( body.query, body.entity_type, body.start_time, body.end_time); // 3. Embed query - let query_embedding = match state.embeddings.embed_text(&body.query).await { - Ok(emb) => emb, + let query_embedding = match state.embeddings.embed_one(&body.query).await { + Ok(emb) => emb.to_vec(), Err(e) => { error!("Embedding failed: {}", e); return crate::handlers::response_builder::internal_error( @@ -278,8 +278,8 @@ pub async fn search_edges_handler( body.query, body.relation_type, body.start_time, body.end_time); // 3. Embed query - let query_embedding = match state.embeddings.embed_text(&body.query).await { - Ok(emb) => emb, + let query_embedding = match state.embeddings.embed_one(&body.query).await { + Ok(emb) => emb.to_vec(), Err(e) => { error!("Embedding failed: {}", e); return crate::handlers::response_builder::internal_error( @@ -361,8 +361,8 @@ pub async fn hybrid_search_handler( body.query, body.semantic_weight, body.lexical_weight); // 3. Embed query - let query_embedding = match state.embeddings.embed_text(&body.query).await { - Ok(emb) => emb, + let query_embedding = match state.embeddings.embed_one(&body.query).await { + Ok(emb) => emb.to_vec(), Err(e) => { error!("Embedding failed: {}", e); return crate::handlers::response_builder::internal_error( diff --git a/crates/mem-cli/src/handlers/synthesis.rs b/crates/mem-cli/src/handlers/synthesis.rs index fc30fc5..1a672f8 100644 --- a/crates/mem-cli/src/handlers/synthesis.rs +++ b/crates/mem-cli/src/handlers/synthesis.rs @@ -517,11 +517,12 @@ pub async fn reasoning_paths_handler( let elapsed = start_time.elapsed().as_millis(); info!("Paths: {} found in {}ms", paths.len(), elapsed); + let path_count = paths.len(); crate::handlers::response_builder::success_response(ReasoningPathsResponse { source_id: body.source_id.clone(), target_id: body.target_id.clone(), paths, - path_count: paths.len(), + path_count, process_time_ms: elapsed, }) } diff --git a/crates/mem-cli/src/handlers/unified_query.rs b/crates/mem-cli/src/handlers/unified_query.rs index 6bdf5b6..1d8415c 100644 --- a/crates/mem-cli/src/handlers/unified_query.rs +++ b/crates/mem-cli/src/handlers/unified_query.rs @@ -136,8 +136,8 @@ pub async fn unified_query_handler( body.search_type, body.query, body.entity_type, body.relation_type); // 3. Embed query once (reused for all search types) - let query_embedding = match state.embeddings.embed_text(&body.query).await { - Ok(emb) => emb, + let query_embedding = match state.embeddings.embed_one(&body.query).await { + Ok(emb) => emb.to_vec(), Err(e) => { error!("Embedding failed: {}", e); return crate::handlers::response_builder::internal_error( diff --git a/crates/mem-cli/src/handlers/unified_synthesis.rs b/crates/mem-cli/src/handlers/unified_synthesis.rs index 0a1ee7f..96940f9 100644 --- a/crates/mem-cli/src/handlers/unified_synthesis.rs +++ b/crates/mem-cli/src/handlers/unified_synthesis.rs @@ -158,12 +158,12 @@ pub async fn unified_synthesis_handler( // Entity Linking if body.link_entities { let linker = EntityLinker::new(state.pool.clone()); - match linker.link_entities(&body.content) { - Ok(links) => { + match linker.link_mentions(&body.content, &body.project).await { + Ok((links, _unlinked)) => { let alias_count = links.iter().filter(|l| l.confidence > 0.85).count(); entity_linking = Some(EntityLinkingResult { mention_links: links.iter().map(|l| MentionLinkResponse { - mention: l.mention.clone(), + mention: l.mention_text.clone(), entity_id: l.entity_id.clone(), confidence: l.confidence, }).collect(), @@ -179,14 +179,14 @@ pub async fn unified_synthesis_handler( // Inference if body.infer_facts { - let engine = InferenceEngine::new(state.pool.clone()); - match engine.infer_facts(&body.content, 5, 0.6, &body.project) { + let engine = InferenceEngine::new(state.pool.clone(), vec![]); + match engine.infer_facts(&body.project, &body.content, 5).await { Ok(facts) => { inference = Some(InferenceResult { inferred_facts: facts.iter().map(|f| InferredFactResponse { - source: f.source.clone(), - relation: f.relation.clone(), - target: f.target.clone(), + source: f.source_id.clone(), + relation: f.relation_type.clone(), + target: f.target_id.clone(), confidence: f.confidence, }).collect(), fact_count: facts.len(), diff --git a/crates/mem-cli/src/handlers/versioning_handler.rs b/crates/mem-cli/src/handlers/versioning_handler.rs index 2983aed..701d010 100644 --- a/crates/mem-cli/src/handlers/versioning_handler.rs +++ b/crates/mem-cli/src/handlers/versioning_handler.rs @@ -15,7 +15,7 @@ pub async fn get_entity_versions( pool: web::Data, ) -> HttpResponse { // Verify auth - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); @@ -46,7 +46,7 @@ pub async fn get_entity_version( path: web::Path<(String, i32)>, pool: web::Data, ) -> HttpResponse { - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); @@ -80,7 +80,7 @@ pub async fn get_entity_diff( query: web::Query, pool: web::Data, ) -> HttpResponse { - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); @@ -120,7 +120,7 @@ pub async fn get_entity_at_time( query: web::Query, pool: web::Data, ) -> HttpResponse { - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); @@ -164,7 +164,7 @@ pub async fn get_edge_versions( path: web::Path, pool: web::Data, ) -> HttpResponse { - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); @@ -196,7 +196,7 @@ pub async fn get_edge_diff( query: web::Query, pool: web::Data, ) -> HttpResponse { - if let Err(e) = AuthGuard::extract_token(&req) { + if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) { return HttpResponse::Unauthorized().json(json!({ "error": e.to_string() })); diff --git a/crates/mem-cli/src/handlers/visualize_sse.rs b/crates/mem-cli/src/handlers/visualize_sse.rs index bb52866..58d2cd0 100644 --- a/crates/mem-cli/src/handlers/visualize_sse.rs +++ b/crates/mem-cli/src/handlers/visualize_sse.rs @@ -145,13 +145,15 @@ pub async fn visualize_stream_handler( match execute_streaming_visualization(&state, req_body).await { Ok(events) => { for event in events { - yield format_sse_event(event); + let data = format_sse_event(event); + yield Ok::(actix_web::web::Bytes::from(data)); } } Err(e) => { - yield format_sse_event(VisualizeEvent::Error { + let data = format_sse_event(VisualizeEvent::Error { message: e, }); + yield Ok::(actix_web::web::Bytes::from(data)); } } }; @@ -161,7 +163,7 @@ pub async fn visualize_stream_handler( .insert_header(("Cache-Control", "no-cache")) .insert_header(("Connection", "keep-alive")) .insert_header(("Transfer-Encoding", "chunked")) - .streaming_body(Box::pin(stream)) + .streaming(Box::pin(stream)) } /// Execute streaming visualization (generates events) diff --git a/crates/mem-cli/src/parallel_dual_write.rs b/crates/mem-cli/src/parallel_dual_write.rs index 6b9791f..6d97eb0 100644 --- a/crates/mem-cli/src/parallel_dual_write.rs +++ b/crates/mem-cli/src/parallel_dual_write.rs @@ -116,13 +116,13 @@ impl ParallelDualWriteIndexer { // Spawn background task (non-blocking) tokio::spawn(async move { - let result = opensearch.index_chunk( + let result = opensearch.index_document( &chunk_id, &chunk.content, &chunk.source, - &chunk.project, &chunk.level, - &chunk.breadcrumb.join(" > "), + chunk.breadcrumb.clone(), + "", // jwt_token - not available in background task ).await; match result { @@ -139,8 +139,8 @@ impl ParallelDualWriteIndexer { &self, chunks: Vec<(&IndexableChunk, Vec)>, ) -> Vec { - let futures = chunks.into_iter().map(|(chunk, embedding)| { - self.index_parallel(chunk, &embedding) + let futures = chunks.into_iter().map(|(chunk, embedding)| async move { + self.index_parallel(chunk, &embedding).await }); futures::future::join_all(futures) diff --git a/crates/mem-cli/src/query/bfs_graph_traversal.rs b/crates/mem-cli/src/query/bfs_graph_traversal.rs index cd233cb..c7395e5 100644 --- a/crates/mem-cli/src/query/bfs_graph_traversal.rs +++ b/crates/mem-cli/src/query/bfs_graph_traversal.rs @@ -6,7 +6,7 @@ use std::collections::{HashMap, VecDeque}; use serde::{Deserialize, Serialize}; use chrono::{DateTime, Utc}; -use sqlx::{Pool, Postgres}; +use sqlx::{Pool, Postgres, Row}; /// A node in the traversal result #[derive(Debug, Clone, Serialize, Deserialize)] @@ -196,6 +196,7 @@ impl BfsGraphTraversal { }); } + let edge_count = edges.len(); Ok(GraphData { nodes, edges, @@ -203,7 +204,7 @@ impl BfsGraphTraversal { requested_depth: config.max_depth, max_depth_reached: max_depth, node_count: visited.len(), - edge_count: edges.len(), + edge_count, depth_breakdown, traversal_time_ms: start_time.elapsed().as_millis() as u64, }) diff --git a/crates/mem-cli/src/query/community_detector.rs b/crates/mem-cli/src/query/community_detector.rs index 6fb8209..60b06ef 100644 --- a/crates/mem-cli/src/query/community_detector.rs +++ b/crates/mem-cli/src/query/community_detector.rs @@ -185,9 +185,9 @@ impl CommunityDetector { communities_vec.push(Community { id: comm_id, + size: members.len(), entity_ids: members.into_iter().collect(), entity_names, - size: members.len(), modularity_contribution: modularity_contrib, average_strength: strength, density, @@ -196,9 +196,9 @@ impl CommunityDetector { } // 5. Calculate total modularity - let total_modularity = communities_vec + let total_modularity: f64 = communities_vec .iter() - .map(|c| c.modularity_contribution) + .map(|c| c.modularity_contribution as f64) .sum(); let average_community_size = if communities_vec.is_empty() { @@ -210,9 +210,9 @@ impl CommunityDetector { let result = CommunityDetectionResult { entity_count: entities.len(), edge_count: edges.len(), - communities: communities_vec, community_count: communities_vec.len(), - total_modularity: total_modularity.max(-1.0).min(1.0), + communities: communities_vec, + total_modularity: total_modularity.max(-1.0).min(1.0) as f32, average_community_size, }; diff --git a/crates/mem-cli/src/query/faceted_search.rs b/crates/mem-cli/src/query/faceted_search.rs index 34810f5..f76d88e 100644 --- a/crates/mem-cli/src/query/faceted_search.rs +++ b/crates/mem-cli/src/query/faceted_search.rs @@ -3,7 +3,7 @@ //! Enables multi-dimensional filtering across entities and edges. //! Supports entity types, relation types, date ranges, confidence levels, and more. -use chrono::{DateTime, Utc}; +use chrono::{DateTime, Timelike, Utc}; use serde::{Deserialize, Serialize}; use sqlx::{Pool, Postgres}; use std::collections::HashMap; @@ -42,7 +42,7 @@ pub struct AvailableFacets { } /// Facet filters for a query -#[derive(Debug, Clone, Default, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct FacetFilters { /// Filter by entity types (OR within facet, AND across facets) pub entity_types: Option>, diff --git a/crates/mem-cli/src/query/force_directed_layout.rs b/crates/mem-cli/src/query/force_directed_layout.rs index a637da5..53c80b1 100644 --- a/crates/mem-cli/src/query/force_directed_layout.rs +++ b/crates/mem-cli/src/query/force_directed_layout.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use super::bfs_graph_traversal::{GraphData, TraversalNode, TraversalEdge}; /// 2D position (X, Y coordinates) -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] pub struct Position { pub x: f32, pub y: f32, diff --git a/crates/mem-cli/src/query/inference_engine.rs b/crates/mem-cli/src/query/inference_engine.rs index cd38fb9..a080a25 100644 --- a/crates/mem-cli/src/query/inference_engine.rs +++ b/crates/mem-cli/src/query/inference_engine.rs @@ -4,6 +4,8 @@ //! confidence propagation through reasoning chains. use std::collections::{HashMap, HashSet, VecDeque}; +use std::pin::Pin; +use std::future::Future; use sqlx::PgPool; use serde::{Deserialize, Serialize}; use tracing::{debug, warn}; @@ -293,18 +295,19 @@ impl InferenceEngine { } /// DFS to find all paths - async fn dfs_paths( - &self, - current: &str, - target: &str, - project_id: &str, + fn dfs_paths<'a>( + &'a self, + current: &'a str, + target: &'a str, + project_id: &'a str, remaining_hops: usize, - path: &mut Vec, - relations: &mut Vec, - confidences: &mut Vec, - visited: &mut HashSet, - results: &mut Vec, - ) -> Result<(), String> { + path: &'a mut Vec, + relations: &'a mut Vec, + confidences: &'a mut Vec, + visited: &'a mut HashSet, + results: &'a mut Vec, + ) -> Pin> + Send + 'a>> { + Box::pin(async move { if remaining_hops == 0 { return Ok(()); } @@ -350,6 +353,7 @@ impl InferenceEngine { } Ok(()) + }) // Box::pin } } diff --git a/crates/mem-cli/src/query/path_finder.rs b/crates/mem-cli/src/query/path_finder.rs index c688f16..72edd53 100644 --- a/crates/mem-cli/src/query/path_finder.rs +++ b/crates/mem-cli/src/query/path_finder.rs @@ -6,6 +6,8 @@ use serde::{Deserialize, Serialize}; use sqlx::{Pool, Postgres}; use std::collections::{HashMap, HashSet, VecDeque}; +use std::pin::Pin; +use std::future::Future; use tracing::{debug, info}; /// A single path through the graph @@ -123,13 +125,14 @@ impl PathFinder { info!("Found shortest path: {} → {} (distance: {})", source_id, target_id, final_entities.len() - 1); + let distance = final_entities.len() - 1; return Ok(Some(Path { source_id: source_id.to_string(), target_id: target_id.to_string(), entity_ids: final_entities, entity_names: vec![], // Could fetch from DB if needed relation_types: final_relations, - distance: final_entities.len() - 1, + distance, total_confidence: final_confidence.max(0.0).min(1.0), })); } @@ -293,19 +296,20 @@ impl PathFinder { } /// DFS helper for finding all paths - async fn dfs_paths( - &self, - source_id: &str, - target_id: &str, + fn dfs_paths<'a>( + &'a self, + source_id: &'a str, + target_id: &'a str, current_path: Vec, relations_path: Vec, confidence: f32, depth: usize, max_depth: usize, - paths_found: &mut Vec, - visited: &mut HashSet, + paths_found: &'a mut Vec, + visited: &'a mut HashSet, max_paths: usize, - ) -> Result<(), String> { + ) -> Pin> + Send + 'a>> { + Box::pin(async move { if paths_found.len() >= max_paths { return Ok(()); // Found enough paths } @@ -328,13 +332,14 @@ impl PathFinder { let final_confidence = confidence * edge.confidence; + let distance = final_path.len() - 1; paths_found.push(Path { source_id: source_id.to_string(), target_id: target_id.to_string(), entity_ids: final_path, entity_names: vec![], relation_types: final_relations, - distance: final_path.len() - 1, + distance, total_confidence: final_confidence.max(0.0).min(1.0), }); @@ -370,6 +375,7 @@ impl PathFinder { } Ok(()) + }) // Box::pin } /// Fetch direct neighbors of an entity diff --git a/crates/mem-cli/src/query/semantic_retriever.rs b/crates/mem-cli/src/query/semantic_retriever.rs index 049c983..28c6b35 100644 --- a/crates/mem-cli/src/query/semantic_retriever.rs +++ b/crates/mem-cli/src/query/semantic_retriever.rs @@ -138,7 +138,7 @@ impl SemanticRetriever { .await .map_err(|e| format!("Database error: {}", e))?; - let entities = results + let entities: Vec<_> = results .into_iter() .map(|(id, name, entity_type, score, metadata)| EntityResult { id, @@ -213,7 +213,7 @@ impl SemanticRetriever { .await .map_err(|e| format!("Database error: {}", e))?; - let edges = results + let edges: Vec<_> = results .into_iter() .map(|(id, src_id, tgt_id, src_name, tgt_name, rel_type, fact, score, conf)| { EdgeResult { diff --git a/crates/mem-cli/src/query/summarizer.rs b/crates/mem-cli/src/query/summarizer.rs index 9acda52..9bd135e 100644 --- a/crates/mem-cli/src/query/summarizer.rs +++ b/crates/mem-cli/src/query/summarizer.rs @@ -261,7 +261,7 @@ impl Summarizer { } /// Split text into sentences - fn split_sentences(&self, text: &str) -> Vec<&str> { + fn split_sentences<'a>(&self, text: &'a str) -> Vec<&'a str> { text.split('.').map(|s| s.trim()).filter(|s| !s.is_empty()).collect() } @@ -331,7 +331,7 @@ impl Summarizer { let overlap = entities1 .iter() - .filter(|e| entities2.contains(e)) + .filter(|e| entities2.contains(*e)) .count(); coherence += overlap as f32 / (entities1.len().max(entities2.len()) as f32).max(1.0); } diff --git a/crates/mem-cli/src/query_router.rs b/crates/mem-cli/src/query_router.rs index 3f2258d..406c02b 100644 --- a/crates/mem-cli/src/query_router.rs +++ b/crates/mem-cli/src/query_router.rs @@ -245,6 +245,8 @@ impl QueryRouter { prefilter_size, metrics, latency_ms, + confidence_score: 1.0, + is_valid: true, }) }