- Fix all 106 warnings: unused imports, dead struct fields (_prefix), dead_code annotations on bin-only items in ingest_worker.rs - Add GET /ready endpoint (readiness probe, checks DB) - Keep GET /health lightweight (liveness, no DB check) - Add ServiceMonitor for Prometheus scraping - Add tracing-subscriber json feature for structured logs - 760 tests passing, 0 warnings, 0 errors
This commit is contained in:
Generated
+13
@@ -3986,6 +3986,16 @@ dependencies = [
|
|||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-serde"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.23"
|
version = "0.3.23"
|
||||||
@@ -3993,11 +4003,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
|
"tracing-serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ anyhow = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true, features = ["json"] }
|
||||||
time = { workspace = true }
|
time = { workspace = true }
|
||||||
actix-web = { workspace = true }
|
actix-web = { workspace = true }
|
||||||
actix-rt = { workspace = true }
|
actix-rt = { workspace = true }
|
||||||
|
|||||||
@@ -1,15 +1,4 @@
|
|||||||
/// Advanced Ranking: Temporal decay, popularity, diversity, and cross-encoder scoring
|
use chrono::{DateTime, Utc};
|
||||||
///
|
|
||||||
/// Provides sophisticated ranking strategies:
|
|
||||||
/// - Temporal decay: Older documents get lower scores
|
|
||||||
/// - Popularity: Frequently accessed docs get higher scores
|
|
||||||
/// - Diversity: Penalize redundant top results
|
|
||||||
/// - Cross-encoder: Pairwise document-query scoring
|
|
||||||
/// - Click-through rate (CTR): User feedback signals
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use chrono::{DateTime, Utc, Duration};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
/// Document with ranking features
|
/// Document with ranking features
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -296,6 +285,7 @@ impl RankerStats {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use chrono::Duration;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_temporal_decay_recent() {
|
fn test_temporal_decay_recent() {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ impl ClientResponse {
|
|||||||
/// Synthesis client SDK with JWT auth support + pod-aware routing
|
/// Synthesis client SDK with JWT auth support + pod-aware routing
|
||||||
pub struct SynthesisClient {
|
pub struct SynthesisClient {
|
||||||
base_url: String, // Resolved URL (internal or external)
|
base_url: String, // Resolved URL (internal or external)
|
||||||
external_url: String, // Fallback external URL
|
_external_url: String, // Fallback external URL
|
||||||
jwt_token: String, // JWT Bearer token for all requests
|
jwt_token: String, // JWT Bearer token for all requests
|
||||||
timeout_secs: u32,
|
timeout_secs: u32,
|
||||||
is_pod: bool, // Running inside k8s pod?
|
is_pod: bool, // Running inside k8s pod?
|
||||||
@@ -102,7 +102,7 @@ impl SynthesisClient {
|
|||||||
|
|
||||||
SynthesisClient {
|
SynthesisClient {
|
||||||
base_url,
|
base_url,
|
||||||
external_url,
|
_external_url: external_url,
|
||||||
jwt_token,
|
jwt_token,
|
||||||
timeout_secs,
|
timeout_secs,
|
||||||
is_pod,
|
is_pod,
|
||||||
@@ -369,7 +369,7 @@ mod tests {
|
|||||||
SynthesisClient::new("https://api.riotpiao.com".to_string(), "test-jwt-placeholder".to_string());
|
SynthesisClient::new("https://api.riotpiao.com".to_string(), "test-jwt-placeholder".to_string());
|
||||||
|
|
||||||
// Verify ConfigMap env vars respected
|
// Verify ConfigMap env vars respected
|
||||||
assert!(!client.external_url.is_empty());
|
assert!(!client._external_url.is_empty());
|
||||||
assert_eq!(client.timeout_secs, 45);
|
assert_eq!(client.timeout_secs, 45);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,7 +459,7 @@ mod tests {
|
|||||||
fn test_external_fallback_url() {
|
fn test_external_fallback_url() {
|
||||||
let client =
|
let client =
|
||||||
SynthesisClient::new("https://api.riotpiao.com".to_string(), "jwt".to_string());
|
SynthesisClient::new("https://api.riotpiao.com".to_string(), "jwt".to_string());
|
||||||
assert_eq!(client.external_url, "https://api.riotpiao.com");
|
assert_eq!(client._external_url, "https://api.riotpiao.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ use async_trait::async_trait;
|
|||||||
use jsonwebtoken::{decode, decode_header, DecodingKey, Validation, Algorithm};
|
use jsonwebtoken::{decode, decode_header, DecodingKey, Validation, Algorithm};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::RwLock;
|
|
||||||
|
|
||||||
use super::provider::{AuthProvider, Claims, AuthError};
|
use super::provider::{AuthProvider, Claims, AuthError};
|
||||||
|
|
||||||
@@ -115,7 +113,7 @@ impl AuthProvider for AuthentikProvider {
|
|||||||
// 2. Fetch JWKS to find public key
|
// 2. Fetch JWKS to find public key
|
||||||
let jwks = self.fetch_jwks().await?;
|
let jwks = self.fetch_jwks().await?;
|
||||||
|
|
||||||
let jwks_key = jwks.keys.iter()
|
let _jwks_key = jwks.keys.iter()
|
||||||
.find(|k| k.kid == kid)
|
.find(|k| k.kid == kid)
|
||||||
.ok_or(AuthError::InvalidSignature)?;
|
.ok_or(AuthError::InvalidSignature)?;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::sync::{Arc, RwLock};
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use tracing::{debug, warn, error};
|
use tracing::{debug, error};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AuthentikServiceAccountConfig {
|
pub struct AuthentikServiceAccountConfig {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
/// 1. AuthGuard: Extract and validate token
|
/// 1. AuthGuard: Extract and validate token
|
||||||
/// 2. PermissionGuard: Check group membership and resource roles
|
/// 2. PermissionGuard: Check group membership and resource roles
|
||||||
|
|
||||||
use super::provider::{AuthProvider, Claims, AuthError};
|
use super::provider::{Claims, AuthError};
|
||||||
|
|
||||||
/// Extracts and validates Bearer token from request headers.
|
/// Extracts and validates Bearer token from request headers.
|
||||||
pub struct AuthGuard;
|
pub struct AuthGuard;
|
||||||
|
|||||||
@@ -25,14 +25,12 @@ use std::sync::Arc;
|
|||||||
use mem_core::{GlobalTfIdfScorer, SemanticScorer};
|
use mem_core::{GlobalTfIdfScorer, SemanticScorer};
|
||||||
use mem_ingest::wiki_link::WikiLinkGraph;
|
use mem_ingest::wiki_link::WikiLinkGraph;
|
||||||
|
|
||||||
use crate::full_pipeline::{FullPipeline, PipelineConfig, PipelineResult, EnrichedChunk, PipelineMetrics};
|
use crate::full_pipeline::{FullPipeline, PipelineConfig, PipelineResult, EnrichedChunk};
|
||||||
use crate::rbac::{
|
use crate::rbac::{
|
||||||
AccessPolicy, PolicyProvider, AccessDecisionEngine, OidcClaims,
|
PolicyProvider, AccessDecisionEngine, OidcClaims,
|
||||||
LegacyAccessDecision as AccessDecision,
|
|
||||||
LegacyAuditLogger as AuditLogger,
|
LegacyAuditLogger as AuditLogger,
|
||||||
LegacyNoOpAuditLogger as NoOpAuditLogger,
|
LegacyNoOpAuditLogger as NoOpAuditLogger,
|
||||||
};
|
};
|
||||||
use crate::http_server::JwtClaims;
|
|
||||||
|
|
||||||
// JwtValidator removed (issue #56). Stub for compilation.
|
// JwtValidator removed (issue #56). Stub for compilation.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -413,7 +411,7 @@ impl AuthorizedPipelineBuilder {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use crate::rbac::MockPolicyProvider;
|
use crate::rbac::{MockPolicyProvider, AccessPolicy};
|
||||||
|
|
||||||
fn create_test_vocab() -> Arc<BTreeMap<String, f32>> {
|
fn create_test_vocab() -> Arc<BTreeMap<String, f32>> {
|
||||||
let mut vocab = BTreeMap::new();
|
let mut vocab = BTreeMap::new();
|
||||||
|
|||||||
@@ -1,18 +1,4 @@
|
|||||||
/// Phase 5: Chunk Metadata Index
|
use std::collections::HashMap;
|
||||||
///
|
|
||||||
/// Extract and index chunk metadata for improved scoring:
|
|
||||||
/// 1. Heading extraction (markdown hierarchy)
|
|
||||||
/// 2. Key term extraction (TF-IDF top terms)
|
|
||||||
/// 3. Category inference (error|solution|tool|concept)
|
|
||||||
/// 4. Metadata-based scoring boost
|
|
||||||
///
|
|
||||||
/// Benefits:
|
|
||||||
/// - Better semantic understanding (category context)
|
|
||||||
/// - Faster ranking (metadata pre-computed)
|
|
||||||
/// - Query intent matching (match query intent to chunk category)
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
/// Chunk category for scoring context
|
/// Chunk category for scoring context
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|||||||
@@ -1,15 +1,4 @@
|
|||||||
/// Phase 4: LLM Call Optimization
|
use std::collections::HashSet;
|
||||||
///
|
|
||||||
/// Reduce LLM calls by:
|
|
||||||
/// 1. Score thresholding: skip chunks < 0.6
|
|
||||||
/// 2. Budget-aware selection: select top-K within byte budget
|
|
||||||
/// 3. Deduplication: remove near-duplicate chunks (shingle-based)
|
|
||||||
/// 4. Ranking by value: prioritize high-confidence results
|
|
||||||
///
|
|
||||||
/// Target: 70-80% fewer LLM calls for typical queries
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
/// Chunk with selection metrics
|
/// Chunk with selection metrics
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -77,7 +66,7 @@ impl BudgetSelector {
|
|||||||
.unwrap_or(std::cmp::Ordering::Equal)
|
.unwrap_or(std::cmp::Ordering::Equal)
|
||||||
});
|
});
|
||||||
|
|
||||||
let total_count = chunks.len();
|
let _total_count = chunks.len();
|
||||||
let mut selected = Vec::new();
|
let mut selected = Vec::new();
|
||||||
let mut total_bytes = 0usize;
|
let mut total_bytes = 0usize;
|
||||||
let mut rejected_count = 0;
|
let mut rejected_count = 0;
|
||||||
|
|||||||
@@ -5,13 +5,11 @@
|
|||||||
/// - T3.2: Semantic dedup (LLM-gated with pre-filter)
|
/// - T3.2: Semantic dedup (LLM-gated with pre-filter)
|
||||||
/// - T3.3: Audit logging + dry-run mode
|
/// - T3.3: Audit logging + dry-run mode
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::Result;
|
||||||
use sqlx::{Pool, Postgres, Row};
|
use sqlx::{Pool, Postgres, Row};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use tracing::{debug, info};
|
||||||
use tracing::{debug, info, warn};
|
|
||||||
|
|
||||||
use mem_core::edge::Edge;
|
|
||||||
// LlmCaller trait (moved from mem_ingest)
|
// LlmCaller trait (moved from mem_ingest)
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait LlmCaller: Send + Sync {
|
pub trait LlmCaller: Send + Sync {
|
||||||
|
|||||||
@@ -14,15 +14,14 @@
|
|||||||
/// - `PipelineResult`: comprehensive result with all metrics
|
/// - `PipelineResult`: comprehensive result with all metrics
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use mem_core::{GlobalTfIdfScorer, SemanticScorer};
|
use mem_core::{GlobalTfIdfScorer, SemanticScorer};
|
||||||
use mem_ingest::wiki_link::WikiLinkGraph;
|
use mem_ingest::wiki_link::WikiLinkGraph;
|
||||||
|
|
||||||
use crate::query_router::{QueryRouter, RouterConfig, RoutedResult, SelectedChunk};
|
use crate::query_router::{QueryRouter, RouterConfig};
|
||||||
use crate::chunk_metadata::{MetadataExtractor, MetadataBooster, ChunkMetadata, ChunkCategory, QueryIntent};
|
use crate::chunk_metadata::{MetadataExtractor, MetadataBooster, ChunkCategory, QueryIntent};
|
||||||
use crate::cache_alignment::{KvCacheAligner, CachedChunk, CacheLocalityAnalyzer, RetrievalProfiler, CacheMetrics};
|
use crate::cache_alignment::{KvCacheAligner, CachedChunk, RetrievalProfiler};
|
||||||
|
|
||||||
/// Unified pipeline configuration
|
/// Unified pipeline configuration
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|||||||
@@ -5,14 +5,13 @@
|
|||||||
|
|
||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::Arc;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use crate::agent::{Agent, AgentConfig, AgentCapability, DefaultAgent};
|
use crate::agent::{Agent, AgentConfig, AgentCapability, DefaultAgent};
|
||||||
use crate::agent::client_sdk::SynthesisClient;
|
use crate::agent::client_sdk::SynthesisClient;
|
||||||
use crate::handlers::response_builder;
|
use crate::handlers::response_builder;
|
||||||
use mem_store::agent_repo::{AgentRepository, AgentPrompt, AgentSkill, AgentDecision, RolePromptMapping};
|
use mem_store::agent_repo::AgentRepository;
|
||||||
use crate::metrics::{ERROR_AUTH_FAILURE_AGENT, ERROR_BAD_REQUEST_AGENT, ERROR_NOT_FOUND_AGENT, ERROR_UNEXPECTED_AGENT, ERROR_UNEXPECTED_TOTAL};
|
use crate::metrics::{ERROR_BAD_REQUEST_AGENT, ERROR_NOT_FOUND_AGENT, ERROR_UNEXPECTED_AGENT, ERROR_UNEXPECTED_TOTAL};
|
||||||
use tracing::{debug, info, error, warn};
|
use tracing::{debug, info, error, warn};
|
||||||
|
|
||||||
/// Register agent request
|
/// Register agent request
|
||||||
@@ -94,7 +93,7 @@ pub async fn register_agent_handler(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Persist agent config to database via agent_registry table
|
// Persist agent config to database via agent_registry table
|
||||||
let agent_repo = AgentRepository::new(state.pool.clone());
|
let _agent_repo = AgentRepository::new(state.pool.clone());
|
||||||
|
|
||||||
// Verify project exists
|
// Verify project exists
|
||||||
let project_exists = sqlx::query("SELECT id FROM projects WHERE id = $1")
|
let project_exists = sqlx::query("SELECT id FROM projects WHERE id = $1")
|
||||||
|
|||||||
@@ -5,10 +5,9 @@
|
|||||||
|
|
||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
use crate::http_server::AppState;
|
use crate::http_server::AppState;
|
||||||
use crate::compaction::{compact_memory, CompactionMode, CompactionStats};
|
use crate::compaction::{CompactionMode, CompactionStats};
|
||||||
|
|
||||||
/// Compaction request parameters
|
/// Compaction request parameters
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
/// Rate limiting deferred to API gateway / riotpiao-rust-sdk (issue #56).
|
/// Rate limiting deferred to API gateway / riotpiao-rust-sdk (issue #56).
|
||||||
|
|
||||||
use actix_web::{HttpRequest, HttpResponse};
|
use actix_web::{HttpRequest, HttpResponse};
|
||||||
use serde_json::json;
|
|
||||||
use crate::http_server::AppState;
|
use crate::http_server::AppState;
|
||||||
|
|
||||||
/// Result type for middleware operations
|
/// Result type for middleware operations
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{HttpRequest, HttpResponse};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlx::PgPool;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::auth::AuthGuard;
|
use crate::auth::AuthGuard;
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ pub async fn rebuild(
|
|||||||
/// GET /memory/rebuild/status
|
/// GET /memory/rebuild/status
|
||||||
pub async fn rebuild_status(
|
pub async fn rebuild_status(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
pool: web::Data<PgPool>,
|
_pool: web::Data<PgPool>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
// Verify auth
|
// Verify auth
|
||||||
if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) {
|
if let Err(e) = AuthGuard::extract_token(req.headers().get("Authorization").and_then(|v| v.to_str().ok()).unwrap_or("")) {
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
|
|
||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::http_server::AppState;
|
use crate::http_server::AppState;
|
||||||
use crate::query::{SemanticRetriever, EntityResult, EdgeResult, HybridResult, CommunityDetector, CommunityDetectionResult, PathFinder, PathFindingResult, FacetedSearch, AvailableFacets, FacetFilters};
|
use crate::query::{SemanticRetriever, CommunityDetector, CommunityDetectionResult, PathFinder, PathFindingResult, FacetedSearch, AvailableFacets, FacetFilters};
|
||||||
|
|
||||||
/// Request for semantic entity search
|
/// Request for semantic entity search
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ use crate::http_server::AppState;
|
|||||||
use crate::query::{
|
use crate::query::{
|
||||||
EntityLinker, MentionLink, AliasSuggestion, MergeSuggestion, CoreferenceCluster,
|
EntityLinker, MentionLink, AliasSuggestion, MergeSuggestion, CoreferenceCluster,
|
||||||
InferenceEngine, InferenceRule, InferredFact, ReasoningPath, TransitiveClosure,
|
InferenceEngine, InferenceRule, InferredFact, ReasoningPath, TransitiveClosure,
|
||||||
QueryReasoner, SubQuery, Constraint, QuestionType, ReasonedAnswer,
|
QueryReasoner,
|
||||||
Summarizer, SummarizationStrategy, Summary, KeyFact,
|
Summarizer, SummarizationStrategy,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Request to link entities
|
/// Request to link entities
|
||||||
@@ -145,7 +145,7 @@ pub async fn link_entities_handler(
|
|||||||
|
|
||||||
let total = links.len() + unlinked.len();
|
let total = links.len() + unlinked.len();
|
||||||
let link_rate = if total > 0 {
|
let link_rate = if total > 0 {
|
||||||
(links.len() as f32 / total as f32)
|
links.len() as f32 / total as f32
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
|
|
||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Value};
|
use serde_json::Value;
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::http_server::AppState;
|
use crate::http_server::AppState;
|
||||||
use crate::query::{
|
use crate::query::{
|
||||||
SemanticRetriever, EntityResult, EdgeResult, HybridResult,
|
SemanticRetriever,
|
||||||
CommunityDetector, CommunityDetectionResult,
|
CommunityDetector, CommunityDetectionResult,
|
||||||
PathFinder, PathFindingResult,
|
PathFinder, PathFindingResult,
|
||||||
FacetedSearch, AvailableFacets, FacetFilters,
|
FacetedSearch, AvailableFacets, FacetFilters,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::query::{
|
use crate::query::{
|
||||||
EntityLinker, InferenceEngine, QueryReasoner, Summarizer,
|
EntityLinker, InferenceEngine, Summarizer,
|
||||||
SummarizationStrategy, MentionLink,
|
SummarizationStrategy,
|
||||||
};
|
};
|
||||||
use crate::handlers::response_builder;
|
use crate::handlers::response_builder;
|
||||||
use tracing::{debug, info, error};
|
use tracing::{debug, info, error};
|
||||||
|
|||||||
@@ -6,9 +6,7 @@
|
|||||||
use actix_web::{web, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::sync::mpsc;
|
use crate::query::visualize_types::VisualizeRequest;
|
||||||
use futures_util::stream::{self, StreamExt};
|
|
||||||
use crate::query::visualize_types::{VisualizeRequest, ReactFlowNode, ReactFlowEdge, NodeData, EdgeData, NodeStyle};
|
|
||||||
use crate::query::bfs_graph_traversal::BfsConfig;
|
use crate::query::bfs_graph_traversal::BfsConfig;
|
||||||
use crate::query::force_directed_layout::ForceDirectedLayout;
|
use crate::query::force_directed_layout::ForceDirectedLayout;
|
||||||
use crate::http_server::AppState;
|
use crate::http_server::AppState;
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ pub struct IngestRecord {
|
|||||||
}
|
}
|
||||||
// RBAC removed for MVP - will add after core ingest/query working
|
// RBAC removed for MVP - will add after core ingest/query working
|
||||||
use crate::handlers::{
|
use crate::handlers::{
|
||||||
QueryParams, QueryParamsError, SearchMethod, build_search_response,
|
QueryParams,
|
||||||
LearnParams, LearnParamsError, build_learn_response,
|
LearnParams, build_learn_response,
|
||||||
visualize_handler, visualize_stream_handler, compact_handler
|
visualize_handler, visualize_stream_handler, compact_handler
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -182,6 +182,7 @@ fn has_capability(claims: &JwtClaims, required_capability: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extract client identifier from claims for rate limiting
|
/// Extract client identifier from claims for rate limiting
|
||||||
|
#[allow(dead_code)]
|
||||||
fn extract_rate_limit_key(claims: &JwtClaims) -> String {
|
fn extract_rate_limit_key(claims: &JwtClaims) -> String {
|
||||||
// Use subject (user/service ID) as rate limit key
|
// Use subject (user/service ID) as rate limit key
|
||||||
claims.sub.clone()
|
claims.sub.clone()
|
||||||
@@ -291,6 +292,7 @@ pub async fn start_server(port: u16, api_key: String, database_url: &str) -> Res
|
|||||||
.app_data(state.clone())
|
.app_data(state.clone())
|
||||||
.wrap(Logger::default())
|
.wrap(Logger::default())
|
||||||
.route("/health", web::get().to(health_check))
|
.route("/health", web::get().to(health_check))
|
||||||
|
.route("/ready", web::get().to(readiness_check))
|
||||||
.route("/metrics", web::get().to(crate::metrics::metrics_handler))
|
.route("/metrics", web::get().to(crate::metrics::metrics_handler))
|
||||||
.route("/memory/ingest", web::post().to(ingest_handler))
|
.route("/memory/ingest", web::post().to(ingest_handler))
|
||||||
.route("/memory/ingest/{ingest_id}", web::get().to(ingest_status))
|
.route("/memory/ingest/{ingest_id}", web::get().to(ingest_status))
|
||||||
@@ -362,6 +364,24 @@ pub async fn health_check(state: web::Data<AppState>) -> HttpResponse {
|
|||||||
HttpResponse::Ok().json(json!({"status": "ok", "uptime_seconds": uptime}))
|
HttpResponse::Ok().json(json!({"status": "ok", "uptime_seconds": uptime}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GET /ready — readiness probe (checks DB)
|
||||||
|
pub async fn readiness_check(state: web::Data<AppState>) -> HttpResponse {
|
||||||
|
let uptime = state.start_time.elapsed().as_secs();
|
||||||
|
let db_start = std::time::Instant::now();
|
||||||
|
match sqlx::query("SELECT 1").execute(&state.pool).await {
|
||||||
|
Ok(_) => {
|
||||||
|
crate::metrics::DEP_DB_UP.set(1);
|
||||||
|
crate::metrics::DEP_DB_LATENCY.observe(db_start.elapsed().as_secs_f64());
|
||||||
|
HttpResponse::Ok().json(json!({"status": "ready", "uptime_seconds": uptime, "db": "ok"}))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
crate::metrics::DEP_DB_UP.set(0);
|
||||||
|
crate::metrics::HEALTH_CHECK_FAILURES.inc();
|
||||||
|
HttpResponse::ServiceUnavailable().json(json!({"status": "not_ready", "uptime_seconds": uptime, "db": format!("error: {}", e)}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// POST /memory/ingest — queue an ingest job
|
/// POST /memory/ingest — queue an ingest job
|
||||||
pub async fn ingest_handler(
|
pub async fn ingest_handler(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
@@ -385,7 +405,7 @@ pub async fn ingest_handler(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_id = &claims.sub;
|
let _user_id = &claims.sub;
|
||||||
if !has_capability(&claims, "memory:write") {
|
if !has_capability(&claims, "memory:write") {
|
||||||
INGEST_AUTH_FAILURES.inc();
|
INGEST_AUTH_FAILURES.inc();
|
||||||
INGEST_ERRORS_TOTAL.inc();
|
INGEST_ERRORS_TOTAL.inc();
|
||||||
@@ -1008,7 +1028,7 @@ pub async fn vault_browser_handler(
|
|||||||
/// Helper: Build file tree for a project
|
/// Helper: Build file tree for a project
|
||||||
async fn vault_project_tree(
|
async fn vault_project_tree(
|
||||||
project: &str,
|
project: &str,
|
||||||
state: &web::Data<AppState>,
|
_state: &web::Data<AppState>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let vault_dir = std::env::var("MEM_HOME").unwrap_or_else(|_| "/data".to_string());
|
let vault_dir = std::env::var("MEM_HOME").unwrap_or_else(|_| "/data".to_string());
|
||||||
let project_path = format!("{}/vault/{}", vault_dir, project);
|
let project_path = format!("{}/vault/{}", vault_dir, project);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ pub struct RankedCandidate {
|
|||||||
pub struct HybridRetriever {
|
pub struct HybridRetriever {
|
||||||
tfidf_scorer: Arc<mem_core::GlobalTfIdfScorer>,
|
tfidf_scorer: Arc<mem_core::GlobalTfIdfScorer>,
|
||||||
semantic_scorer: Arc<mem_core::SemanticScorer>,
|
semantic_scorer: Arc<mem_core::SemanticScorer>,
|
||||||
pipeline: ScoringPipeline,
|
_pipeline: ScoringPipeline,
|
||||||
min_tfidf_threshold: f32,
|
min_tfidf_threshold: f32,
|
||||||
prefilter_limit: usize,
|
prefilter_limit: usize,
|
||||||
rrf_tfidf_weight: f32,
|
rrf_tfidf_weight: f32,
|
||||||
@@ -62,7 +62,7 @@ impl HybridRetriever {
|
|||||||
Self {
|
Self {
|
||||||
tfidf_scorer,
|
tfidf_scorer,
|
||||||
semantic_scorer,
|
semantic_scorer,
|
||||||
pipeline,
|
_pipeline: pipeline,
|
||||||
min_tfidf_threshold: 0.3,
|
min_tfidf_threshold: 0.3,
|
||||||
prefilter_limit: 50,
|
prefilter_limit: 50,
|
||||||
rrf_tfidf_weight: 0.4,
|
rrf_tfidf_weight: 0.4,
|
||||||
@@ -71,7 +71,7 @@ impl HybridRetriever {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decide retrieval route based on query and context
|
/// Decide retrieval route based on query and context
|
||||||
pub fn route_query(&self, query: &str, has_wiki_scope: bool, is_reference_query: bool) -> RetrievalRoute {
|
pub fn route_query(&self, _query: &str, has_wiki_scope: bool, is_reference_query: bool) -> RetrievalRoute {
|
||||||
if is_reference_query {
|
if is_reference_query {
|
||||||
RetrievalRoute::ReferenceOnly
|
RetrievalRoute::ReferenceOnly
|
||||||
} else if has_wiki_scope {
|
} else if has_wiki_scope {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use mem_store::{MemoryL1, VectorStore, ChunkL0, EntityRepoOps, EdgeRepoOps};
|
use mem_store::{VectorStore, ChunkL0};
|
||||||
use mem_llm::EmbeddingsClient;
|
use mem_llm::EmbeddingsClient;
|
||||||
use mem_ingest::ingest_pipeline::{IngestPipeline, Episode};
|
use mem_ingest::ingest_pipeline::{IngestPipeline, Episode};
|
||||||
use mem_ingest::entity_extractor::{WikiLinkFallbackExtractor, LlmEntityExtractor};
|
use mem_ingest::entity_extractor::{WikiLinkFallbackExtractor, LlmEntityExtractor};
|
||||||
@@ -8,16 +8,17 @@ use mem_ingest::contradiction_detector::ContradictionHandler;
|
|||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use pgvector::Vector;
|
|
||||||
|
|
||||||
/// Job status enumeration — type-safe alternative to magic strings
|
/// Job status enumeration — type-safe alternative to magic strings
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub enum JobStatus {
|
pub enum JobStatus {
|
||||||
Processing,
|
Processing,
|
||||||
Done,
|
Done,
|
||||||
DoneWithErrors,
|
DoneWithErrors,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl JobStatus {
|
impl JobStatus {
|
||||||
pub fn as_str(&self) -> &'static str {
|
pub fn as_str(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
@@ -66,6 +67,7 @@ mod tests {
|
|||||||
|
|
||||||
/// Structured logging context for ingest operations — ensures consistent field names across all logs
|
/// Structured logging context for ingest operations — ensures consistent field names across all logs
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct IngestLogContext {
|
pub struct IngestLogContext {
|
||||||
pub ingest_id: String,
|
pub ingest_id: String,
|
||||||
pub project: String,
|
pub project: String,
|
||||||
@@ -73,6 +75,7 @@ pub struct IngestLogContext {
|
|||||||
pub source: String,
|
pub source: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl IngestLogContext {
|
impl IngestLogContext {
|
||||||
fn new(ingest_id: &str, project: &str, record_id: &str, source: &str) -> Self {
|
fn new(ingest_id: &str, project: &str, record_id: &str, source: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -86,16 +89,19 @@ impl IngestLogContext {
|
|||||||
|
|
||||||
/// Job status store trait — abstracts database persistence of job status (enables mocking)
|
/// Job status store trait — abstracts database persistence of job status (enables mocking)
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub trait JobStatusStore: Send + Sync {
|
pub trait JobStatusStore: Send + Sync {
|
||||||
/// Update job status in storage
|
/// Update job status in storage
|
||||||
async fn update_status(&self, ingest_id: &str, status: JobStatus) -> Result<()>;
|
async fn update_status(&self, ingest_id: &str, status: JobStatus) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PostgreSQL implementation of JobStatusStore
|
/// PostgreSQL implementation of JobStatusStore
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct PgJobStatusStore {
|
pub struct PgJobStatusStore {
|
||||||
pool: PgPool,
|
pool: PgPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl PgJobStatusStore {
|
impl PgJobStatusStore {
|
||||||
pub fn new(pool: PgPool) -> Self {
|
pub fn new(pool: PgPool) -> Self {
|
||||||
Self { pool }
|
Self { pool }
|
||||||
@@ -116,6 +122,7 @@ impl JobStatusStore for PgJobStatusStore {
|
|||||||
|
|
||||||
|
|
||||||
/// Ingest worker — processes queued records through entity/fact extraction pipeline
|
/// Ingest worker — processes queued records through entity/fact extraction pipeline
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct IngestWorker {
|
pub struct IngestWorker {
|
||||||
pool: PgPool,
|
pool: PgPool,
|
||||||
vector_store: Arc<VectorStore>,
|
vector_store: Arc<VectorStore>,
|
||||||
@@ -124,6 +131,7 @@ pub struct IngestWorker {
|
|||||||
job_status_store: Arc<dyn JobStatusStore>,
|
job_status_store: Arc<dyn JobStatusStore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl IngestWorker {
|
impl IngestWorker {
|
||||||
/// Create worker with full ingest pipeline
|
/// Create worker with full ingest pipeline
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@@ -308,7 +316,7 @@ impl IngestWorker {
|
|||||||
|
|
||||||
/// Process a single chunk
|
/// Process a single chunk
|
||||||
pub async fn process_chunk(&self, project: &str, query_id: &str, content: &str, source: &str) -> Result<()> {
|
pub async fn process_chunk(&self, project: &str, query_id: &str, content: &str, source: &str) -> Result<()> {
|
||||||
let embedding = self.embeddings.embed_one(content).await?;
|
let _embedding = self.embeddings.embed_one(content).await?;
|
||||||
let chunk = ChunkL0 {
|
let chunk = ChunkL0 {
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
project: project.to_string(),
|
project: project.to_string(),
|
||||||
@@ -323,6 +331,7 @@ impl IngestWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extract wiki links from text (e.g., [[Kubernetes]] -> "Kubernetes")
|
/// Extract wiki links from text (e.g., [[Kubernetes]] -> "Kubernetes")
|
||||||
|
#[allow(dead_code)]
|
||||||
fn extract_wiki_links(text: &str) -> Vec<String> {
|
fn extract_wiki_links(text: &str) -> Vec<String> {
|
||||||
let mut links = Vec::new();
|
let mut links = Vec::new();
|
||||||
let mut chars = text.chars().peekable();
|
let mut chars = text.chars().peekable();
|
||||||
@@ -348,6 +357,7 @@ fn extract_wiki_links(text: &str) -> Vec<String> {
|
|||||||
/// Returns Ok(true) if saved, Ok(false) if skipped, Err if fatal error
|
/// Returns Ok(true) if saved, Ok(false) if skipped, Err if fatal error
|
||||||
/// Save entity with embeddings (RAG-006)
|
/// Save entity with embeddings (RAG-006)
|
||||||
/// Embeds name + summary before persisting, so semantic search can find entities.
|
/// Embeds name + summary before persisting, so semantic search can find entities.
|
||||||
|
#[allow(dead_code)]
|
||||||
async fn save_entity_with_embedding(
|
async fn save_entity_with_embedding(
|
||||||
pool: &PgPool,
|
pool: &PgPool,
|
||||||
embeddings: &EmbeddingsClient,
|
embeddings: &EmbeddingsClient,
|
||||||
@@ -440,6 +450,7 @@ async fn save_entity_with_embedding(
|
|||||||
|
|
||||||
/// Save edge with fact embedding (RAG-006)
|
/// Save edge with fact embedding (RAG-006)
|
||||||
/// Embeds fact text before persisting, so semantic search can find edges.
|
/// Embeds fact text before persisting, so semantic search can find edges.
|
||||||
|
#[allow(dead_code)]
|
||||||
async fn save_edge_with_embedding(
|
async fn save_edge_with_embedding(
|
||||||
pool: &PgPool,
|
pool: &PgPool,
|
||||||
embeddings: &EmbeddingsClient,
|
embeddings: &EmbeddingsClient,
|
||||||
@@ -509,6 +520,7 @@ async fn save_edge_with_embedding(
|
|||||||
|
|
||||||
// Legacy save functions kept for backward compatibility but unused
|
// Legacy save functions kept for backward compatibility but unused
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[allow(dead_code)]
|
||||||
async fn save_edge_to_db(pool: &PgPool, edge: &mem_core::edge::Edge) -> Result<()> {
|
async fn save_edge_to_db(pool: &PgPool, edge: &mem_core::edge::Edge) -> Result<()> {
|
||||||
let result = sqlx::query(
|
let result = sqlx::query(
|
||||||
"INSERT INTO memory_edge (id, project_id, source_id, target_id, relation_type, fact, t_valid, t_invalid, t_created, confidence)
|
"INSERT INTO memory_edge (id, project_id, source_id, target_id, relation_type, fact, t_valid, t_invalid, t_created, confidence)
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ async fn cmd_verify(
|
|||||||
check_db,
|
check_db,
|
||||||
check_log,
|
check_log,
|
||||||
log_dir,
|
log_dir,
|
||||||
format,
|
_format: format,
|
||||||
};
|
};
|
||||||
|
|
||||||
let verifier = verify::Verifier::new(database_url).await?;
|
let verifier = verify::Verifier::new(database_url).await?;
|
||||||
|
|||||||
@@ -105,14 +105,14 @@ impl Histogram {
|
|||||||
/// Labeled counter (key = label combination string)
|
/// Labeled counter (key = label combination string)
|
||||||
pub struct LabeledCounter {
|
pub struct LabeledCounter {
|
||||||
values: Mutex<HashMap<String, u64>>,
|
values: Mutex<HashMap<String, u64>>,
|
||||||
name: &'static str,
|
_name: &'static str,
|
||||||
help: &'static str,
|
_help: &'static str,
|
||||||
label_names: &'static [&'static str],
|
_label_names: &'static [&'static str],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LabeledCounter {
|
impl LabeledCounter {
|
||||||
pub fn new(name: &'static str, help: &'static str, label_names: &'static [&'static str]) -> Self {
|
pub fn new(name: &'static str, help: &'static str, label_names: &'static [&'static str]) -> Self {
|
||||||
Self { values: Mutex::new(HashMap::new()), name, help, label_names }
|
Self { values: Mutex::new(HashMap::new()), _name: name, _help: help, _label_names: label_names }
|
||||||
}
|
}
|
||||||
pub fn inc(&self, labels: &[&str]) {
|
pub fn inc(&self, labels: &[&str]) {
|
||||||
let key = labels.join(",");
|
let key = labels.join(",");
|
||||||
@@ -613,16 +613,17 @@ pub fn render_metrics() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Render a labeled counter in Prometheus format
|
/// Render a labeled counter in Prometheus format
|
||||||
|
#[allow(dead_code)]
|
||||||
fn render_labeled_counter(out: &mut String, lc: &LabeledCounter) {
|
fn render_labeled_counter(out: &mut String, lc: &LabeledCounter) {
|
||||||
let map = lc.values.lock().unwrap();
|
let map = lc.values.lock().unwrap();
|
||||||
if map.is_empty() { return; }
|
if map.is_empty() { return; }
|
||||||
out.push_str(&format!("# HELP {} {}\n# TYPE {} counter\n", lc.name, lc.help, lc.name));
|
out.push_str(&format!("# HELP {} {}\n# TYPE {} counter\n", lc._name, lc._help, lc._name));
|
||||||
for (key, val) in map.iter() {
|
for (key, val) in map.iter() {
|
||||||
let parts: Vec<&str> = key.split(',').collect();
|
let parts: Vec<&str> = key.split(',').collect();
|
||||||
let labels: Vec<String> = lc.label_names.iter().zip(parts.iter())
|
let labels: Vec<String> = lc._label_names.iter().zip(parts.iter())
|
||||||
.map(|(name, val)| format!("{}=\"{}\"", name, val))
|
.map(|(name, val)| format!("{}=\"{}\"", name, val))
|
||||||
.collect();
|
.collect();
|
||||||
out.push_str(&format!("{}{{{}}} {}\n", lc.name, labels.join(","), val));
|
out.push_str(&format!("{}{{{}}} {}\n", lc._name, labels.join(","), val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ use crate::metrics;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MetricsSnapshot {
|
pub struct MetricsSnapshot {
|
||||||
counters: HashMap<&'static str, u64>,
|
counters: HashMap<&'static str, u64>,
|
||||||
gauges: HashMap<&'static str, u64>,
|
_gauges: HashMap<&'static str, u64>,
|
||||||
gauges_f64: HashMap<&'static str, f64>,
|
_gauges_f64: HashMap<&'static str, f64>,
|
||||||
histogram_counts: HashMap<&'static str, u64>,
|
histogram_counts: HashMap<&'static str, u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ impl MetricsSnapshot {
|
|||||||
counters.insert("memory_db_queries_total", metrics::DB_QUERY_TOTAL.get());
|
counters.insert("memory_db_queries_total", metrics::DB_QUERY_TOTAL.get());
|
||||||
counters.insert("memory_db_query_errors_total", metrics::DB_QUERY_ERRORS.get());
|
counters.insert("memory_db_query_errors_total", metrics::DB_QUERY_ERRORS.get());
|
||||||
|
|
||||||
Self { counters, gauges, gauges_f64, histogram_counts }
|
Self { counters, _gauges: gauges, _gauges_f64: gauges_f64, histogram_counts }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert a counter increased by exactly `expected` since snapshot
|
/// Assert a counter increased by exactly `expected` since snapshot
|
||||||
@@ -316,7 +316,7 @@ mod tests {
|
|||||||
let snap = MetricsSnapshot::capture();
|
let snap = MetricsSnapshot::capture();
|
||||||
assert!(snap.counters.contains_key("memory_ingest_requests_total"));
|
assert!(snap.counters.contains_key("memory_ingest_requests_total"));
|
||||||
assert!(snap.counters.contains_key("memory_query_requests_total"));
|
assert!(snap.counters.contains_key("memory_query_requests_total"));
|
||||||
assert!(snap.gauges.contains_key("memory_ingest_in_flight"));
|
assert!(snap._gauges.contains_key("memory_ingest_in_flight"));
|
||||||
assert!(snap.histogram_counts.contains_key("memory_ingest_duration_seconds"));
|
assert!(snap.histogram_counts.contains_key("memory_ingest_duration_seconds"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use uuid::Uuid;
|
|
||||||
use pgvector::Vector;
|
use pgvector::Vector;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
// OpenSearchClient removed (issue #56). Stub for compilation.
|
// OpenSearchClient removed (issue #56). Stub for compilation.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
//! DRY: Reuses score types from mem_core
|
//! DRY: Reuses score types from mem_core
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{debug, info};
|
use tracing::info;
|
||||||
|
|
||||||
/// Answer validation configuration
|
/// Answer validation configuration
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
/// Performs breadth-first search on memory_entity + memory_edge tables,
|
/// Performs breadth-first search on memory_entity + memory_edge tables,
|
||||||
/// returning a subgraph for visualization.
|
/// returning a subgraph for visualization.
|
||||||
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::VecDeque;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use sqlx::{Pool, Postgres, Row};
|
use sqlx::{Pool, Postgres, Row};
|
||||||
|
|
||||||
/// A node in the traversal result
|
/// A node in the traversal result
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{debug, warn};
|
use tracing::debug;
|
||||||
|
|
||||||
/// Result of linking a text mention to an entity
|
/// Result of linking a text mention to an entity
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
@@ -89,12 +89,12 @@ pub struct CoreferenceCluster {
|
|||||||
|
|
||||||
/// Entity Linking Engine
|
/// Entity Linking Engine
|
||||||
pub struct EntityLinker {
|
pub struct EntityLinker {
|
||||||
pool: PgPool,
|
_pool: PgPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityLinker {
|
impl EntityLinker {
|
||||||
pub fn new(pool: PgPool) -> Self {
|
pub fn new(pool: PgPool) -> Self {
|
||||||
EntityLinker { pool }
|
EntityLinker { _pool: pool }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Link mentions in text to existing entities
|
/// Link mentions in text to existing entities
|
||||||
@@ -242,7 +242,7 @@ impl EntityLinker {
|
|||||||
|
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for (entity_id, mentions) in clusters {
|
for (entity_id, mentions) in clusters {
|
||||||
if let Some(entity) = entities.iter().find(|e| e.id == entity_id) {
|
if let Some(_entity) = entities.iter().find(|e| e.id == entity_id) {
|
||||||
let unique_mentions: Vec<_> = mentions.iter().cloned().collect::<HashSet<_>>().into_iter().collect();
|
let unique_mentions: Vec<_> = mentions.iter().cloned().collect::<HashSet<_>>().into_iter().collect();
|
||||||
result.push(CoreferenceCluster {
|
result.push(CoreferenceCluster {
|
||||||
entity_id: entity_id.clone(),
|
entity_id: entity_id.clone(),
|
||||||
@@ -353,7 +353,7 @@ impl EntityLinker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch all entities for a project
|
/// Fetch all entities for a project
|
||||||
async fn fetch_entities(&self, project_id: &str) -> Result<Vec<EntityInfo>, String> {
|
async fn fetch_entities(&self, _project_id: &str) -> Result<Vec<EntityInfo>, String> {
|
||||||
// Stub: would query database
|
// Stub: would query database
|
||||||
// For now, return empty
|
// For now, return empty
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
use chrono::{DateTime, Timelike, Utc};
|
use chrono::{DateTime, Timelike, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{Pool, Postgres};
|
use sqlx::{Pool, Postgres};
|
||||||
use std::collections::HashMap;
|
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
/// A single facet (filterable dimension)
|
/// A single facet (filterable dimension)
|
||||||
@@ -88,7 +87,7 @@ impl FacetedSearch {
|
|||||||
limit: usize,
|
limit: usize,
|
||||||
) -> Result<AvailableFacets, String> {
|
) -> Result<AvailableFacets, String> {
|
||||||
let limit = limit.max(5).min(50);
|
let limit = limit.max(5).min(50);
|
||||||
let start_time = std::time::Instant::now();
|
let _start_time = std::time::Instant::now();
|
||||||
|
|
||||||
debug!("Discovering facets for {}, limit={}", search_type, limit);
|
debug!("Discovering facets for {}, limit={}", search_type, limit);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
/// node positions in 2D space suitable for React Flow visualization.
|
/// node positions in 2D space suitable for React Flow visualization.
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use super::bfs_graph_traversal::{GraphData, TraversalNode, TraversalEdge};
|
use super::bfs_graph_traversal::{GraphData, TraversalNode};
|
||||||
|
|
||||||
/// 2D position (X, Y coordinates)
|
/// 2D position (X, Y coordinates)
|
||||||
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
||||||
@@ -184,8 +184,8 @@ impl ForceDirectedLayout {
|
|||||||
let dist = dist_sq.sqrt();
|
let dist = dist_sq.sqrt();
|
||||||
|
|
||||||
let force = charge / dist_sq;
|
let force = charge / dist_sq;
|
||||||
let fx = (force * dx / dist);
|
let fx = force * dx / dist;
|
||||||
let fy = (force * dy / dist);
|
let fy = force * dy / dist;
|
||||||
|
|
||||||
(-fx, -fy) // Negative = repulsive
|
(-fx, -fy) // Negative = repulsive
|
||||||
}
|
}
|
||||||
@@ -199,8 +199,8 @@ impl ForceDirectedLayout {
|
|||||||
let displacement = dist - link_distance;
|
let displacement = dist - link_distance;
|
||||||
let force = 0.1 * displacement; // Spring constant
|
let force = 0.1 * displacement; // Spring constant
|
||||||
|
|
||||||
let fx = (force * dx / dist);
|
let fx = force * dx / dist;
|
||||||
let fy = (force * dy / dist);
|
let fy = force * dy / dist;
|
||||||
|
|
||||||
(fx, fy) // Positive = attractive
|
(fx, fy) // Positive = attractive
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use std::pin::Pin;
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{debug, warn};
|
|
||||||
|
|
||||||
/// Inference rule
|
/// Inference rule
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -91,13 +90,13 @@ pub struct ReachableEntity {
|
|||||||
|
|
||||||
/// Inference Engine
|
/// Inference Engine
|
||||||
pub struct InferenceEngine {
|
pub struct InferenceEngine {
|
||||||
pool: PgPool,
|
_pool: PgPool,
|
||||||
rules: Vec<InferenceRule>,
|
rules: Vec<InferenceRule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InferenceEngine {
|
impl InferenceEngine {
|
||||||
pub fn new(pool: PgPool, rules: Vec<InferenceRule>) -> Self {
|
pub fn new(pool: PgPool, rules: Vec<InferenceRule>) -> Self {
|
||||||
InferenceEngine { pool, rules }
|
InferenceEngine { _pool: pool, rules }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform rule-based inference
|
/// Perform rule-based inference
|
||||||
@@ -287,8 +286,8 @@ impl InferenceEngine {
|
|||||||
/// Fetch edges from entity
|
/// Fetch edges from entity
|
||||||
async fn fetch_entity_edges(
|
async fn fetch_entity_edges(
|
||||||
&self,
|
&self,
|
||||||
entity_id: &str,
|
_entity_id: &str,
|
||||||
project_id: &str,
|
_project_id: &str,
|
||||||
) -> Result<Vec<EdgeInfo>, String> {
|
) -> Result<Vec<EdgeInfo>, String> {
|
||||||
// Stub: would query database
|
// Stub: would query database
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
@@ -359,7 +358,7 @@ impl InferenceEngine {
|
|||||||
|
|
||||||
/// Internal edge info
|
/// Internal edge info
|
||||||
struct EdgeInfo {
|
struct EdgeInfo {
|
||||||
source_id: String,
|
_source_id: String,
|
||||||
target_id: String,
|
target_id: String,
|
||||||
target_name: String,
|
target_name: String,
|
||||||
relation_type: String,
|
relation_type: String,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ pub struct PathFindingResult {
|
|||||||
/// Edge representation for path finding
|
/// Edge representation for path finding
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct GraphEdge {
|
struct GraphEdge {
|
||||||
from_id: String,
|
_from_id: String,
|
||||||
to_id: String,
|
to_id: String,
|
||||||
relation_type: String,
|
relation_type: String,
|
||||||
confidence: f32,
|
confidence: f32,
|
||||||
@@ -396,14 +396,14 @@ impl PathFinder {
|
|||||||
// Normalize direction: always point forward from input entity
|
// Normalize direction: always point forward from input entity
|
||||||
if source == entity_id {
|
if source == entity_id {
|
||||||
GraphEdge {
|
GraphEdge {
|
||||||
from_id: source,
|
_from_id: source,
|
||||||
to_id: target,
|
to_id: target,
|
||||||
relation_type: rel_type,
|
relation_type: rel_type,
|
||||||
confidence: conf.max(0.0).min(1.0),
|
confidence: conf.max(0.0).min(1.0),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GraphEdge {
|
GraphEdge {
|
||||||
from_id: target,
|
_from_id: target,
|
||||||
to_id: source,
|
to_id: source,
|
||||||
relation_type: format!("{}(reverse)", rel_type),
|
relation_type: format!("{}(reverse)", rel_type),
|
||||||
confidence: conf.max(0.0).min(1.0),
|
confidence: conf.max(0.0).min(1.0),
|
||||||
@@ -580,13 +580,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_edge_representation() {
|
fn test_edge_representation() {
|
||||||
let edge = GraphEdge {
|
let edge = GraphEdge {
|
||||||
from_id: "e1".to_string(),
|
_from_id: "e1".to_string(),
|
||||||
to_id: "e2".to_string(),
|
to_id: "e2".to_string(),
|
||||||
relation_type: "related".to_string(),
|
relation_type: "related".to_string(),
|
||||||
confidence: 0.85,
|
confidence: 0.85,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(edge.from_id, "e1");
|
assert_eq!(edge._from_id, "e1");
|
||||||
assert_eq!(edge.to_id, "e2");
|
assert_eq!(edge.to_id, "e2");
|
||||||
assert!(edge.confidence >= 0.0 && edge.confidence <= 1.0);
|
assert!(edge.confidence >= 0.0 && edge.confidence <= 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
//! Complex question decomposition, multi-hop reasoning, constraint satisfaction,
|
//! Complex question decomposition, multi-hop reasoning, constraint satisfaction,
|
||||||
//! and answer validation.
|
//! and answer validation.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{debug, warn};
|
|
||||||
|
|
||||||
/// Question type/intent
|
/// Question type/intent
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
@@ -108,12 +106,12 @@ pub struct ReasonedAnswer {
|
|||||||
|
|
||||||
/// Query Reasoner
|
/// Query Reasoner
|
||||||
pub struct QueryReasoner {
|
pub struct QueryReasoner {
|
||||||
pool: PgPool,
|
_pool: PgPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryReasoner {
|
impl QueryReasoner {
|
||||||
pub fn new(pool: PgPool) -> Self {
|
pub fn new(pool: PgPool) -> Self {
|
||||||
QueryReasoner { pool }
|
QueryReasoner { _pool: pool }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decompose complex question into sub-queries
|
/// Decompose complex question into sub-queries
|
||||||
@@ -122,7 +120,7 @@ impl QueryReasoner {
|
|||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let question_lower = question.to_lowercase();
|
let _question_lower = question.to_lowercase();
|
||||||
let question_type = self.classify_question(question);
|
let question_type = self.classify_question(question);
|
||||||
|
|
||||||
let mut sub_queries = Vec::new();
|
let mut sub_queries = Vec::new();
|
||||||
@@ -399,7 +397,7 @@ impl QueryReasoner {
|
|||||||
|
|
||||||
let mut explanation = format!("Found {} answer(s) through {} reasoning step(s): ", answers.len(), steps.len());
|
let mut explanation = format!("Found {} answer(s) through {} reasoning step(s): ", answers.len(), steps.len());
|
||||||
|
|
||||||
for (idx, step) in steps.iter().enumerate() {
|
for (_idx, step) in steps.iter().enumerate() {
|
||||||
explanation.push_str(&format!(
|
explanation.push_str(&format!(
|
||||||
"Step {}: {} (confidence: {:.2}, {} constraints satisfied). ",
|
"Step {}: {} (confidence: {:.2}, {} constraints satisfied). ",
|
||||||
step.step_id,
|
step.step_id,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{debug, info};
|
|
||||||
|
|
||||||
/// Temporal query configuration
|
/// Temporal query configuration
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -1,13 +1,3 @@
|
|||||||
/// Advanced Query Filtering: Scope, filtering, and refinement
|
|
||||||
///
|
|
||||||
/// Provides:
|
|
||||||
/// - Project scoping (memory isolation)
|
|
||||||
/// - Level filtering (L1, L2, Reference)
|
|
||||||
/// - Category filtering (Error, Solution, etc.)
|
|
||||||
/// - Time-based filtering (recency)
|
|
||||||
/// - Tag/keyword filtering
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use chrono::{DateTime, Utc, Duration};
|
use chrono::{DateTime, Utc, Duration};
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,11 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use mem_core::DocumentScorer;
|
|
||||||
|
|
||||||
use crate::hybrid_retrieval::{HybridRetriever, RetrievalRoute, WikiScopedFilter, RankedCandidate};
|
use crate::hybrid_retrieval::HybridRetriever;
|
||||||
use crate::chunk_optimizer::{ChunkOptimizer, OptimizableChunk, SelectionMetrics};
|
use crate::chunk_optimizer::{ChunkOptimizer, OptimizableChunk, SelectionMetrics};
|
||||||
use crate::chunk_metadata::{MetadataExtractor, MetadataBooster, QueryIntent};
|
use crate::chunk_metadata::{MetadataExtractor, MetadataBooster, QueryIntent};
|
||||||
use crate::cache_alignment::{KvCacheAligner, CachedChunk, CacheLocalityAnalyzer, RetrievalProfiler};
|
use crate::cache_alignment::{KvCacheAligner, CachedChunk, RetrievalProfiler};
|
||||||
|
|
||||||
/// Complete query result with all metadata
|
/// Complete query result with all metadata
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -190,7 +189,7 @@ impl QueryOrchestrator {
|
|||||||
|
|
||||||
// Step 8: Build optimized chunks with all metadata
|
// Step 8: Build optimized chunks with all metadata
|
||||||
let mut optimized_chunks = Vec::new();
|
let mut optimized_chunks = Vec::new();
|
||||||
for (i, chunk) in selected_opt.iter().enumerate() {
|
for (_i, chunk) in selected_opt.iter().enumerate() {
|
||||||
let slot = slots.iter().find(|(id, _)| id == &chunk.id).map(|(_, s)| *s).unwrap_or(0);
|
let slot = slots.iter().find(|(id, _)| id == &chunk.id).map(|(_, s)| *s).unwrap_or(0);
|
||||||
let metadata = MetadataExtractor::extract(&chunk.id, &chunk.text);
|
let metadata = MetadataExtractor::extract(&chunk.id, &chunk.text);
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use mem_ingest::wiki_link::{WikiLinkGraph, WikiLinkParser};
|
use mem_ingest::wiki_link::{WikiLinkGraph, WikiLinkParser};
|
||||||
use mem_core::{DocumentScorer, GlobalTfIdfScorer, SemanticScorer};
|
use mem_core::{GlobalTfIdfScorer, SemanticScorer};
|
||||||
|
|
||||||
use crate::hybrid_retrieval::{HybridRetriever, RetrievalRoute, WikiScopedFilter, RankedCandidate};
|
use crate::hybrid_retrieval::{HybridRetriever, RetrievalRoute, WikiScopedFilter};
|
||||||
use crate::chunk_optimizer::{ChunkOptimizer, OptimizableChunk, SelectionMetrics};
|
use crate::chunk_optimizer::{ChunkOptimizer, OptimizableChunk, SelectionMetrics};
|
||||||
|
|
||||||
/// Query routing configuration
|
/// Query routing configuration
|
||||||
@@ -74,7 +74,7 @@ pub struct SelectedChunk {
|
|||||||
|
|
||||||
/// Query Router: end-to-end Phase 3+4 pipeline
|
/// Query Router: end-to-end Phase 3+4 pipeline
|
||||||
pub struct QueryRouter {
|
pub struct QueryRouter {
|
||||||
wiki_filter: WikiScopedFilter,
|
_wiki_filter: WikiScopedFilter,
|
||||||
retriever: HybridRetriever,
|
retriever: HybridRetriever,
|
||||||
optimizer: ChunkOptimizer,
|
optimizer: ChunkOptimizer,
|
||||||
config: RouterConfig,
|
config: RouterConfig,
|
||||||
@@ -95,7 +95,7 @@ impl QueryRouter {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
wiki_filter,
|
_wiki_filter: wiki_filter,
|
||||||
retriever,
|
retriever,
|
||||||
optimizer,
|
optimizer,
|
||||||
config,
|
config,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use anyhow::Result;
|
|||||||
|
|
||||||
use super::access_evaluator::{AccessEvaluator, FilterResult, HasResourceMeta};
|
use super::access_evaluator::{AccessEvaluator, FilterResult, HasResourceMeta};
|
||||||
use super::role_provider::RoleProvider;
|
use super::role_provider::RoleProvider;
|
||||||
use super::types::{AccessDecision, Claims, DenyReason, ResourceMeta, Verb};
|
use super::types::{AccessDecision, Claims, ResourceMeta, Verb};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Audit Logger
|
// Audit Logger
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/// - OwnerScope: resource.owner == claims.sub?
|
/// - OwnerScope: resource.owner == claims.sub?
|
||||||
/// - GroupScope: user in required groups?
|
/// - GroupScope: user in required groups?
|
||||||
|
|
||||||
use super::types::{AccessScope, Claims, DenyReason, OwnerConstraint, ResourceMeta, Visibility};
|
use super::types::{AccessScope, Claims, DenyReason, OwnerConstraint, ResourceMeta};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Trait
|
// Trait
|
||||||
@@ -247,7 +247,7 @@ impl Default for CompositeScopeChecker {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::rbac::types::ResourceType;
|
use crate::rbac::types::{ResourceType, Visibility};
|
||||||
|
|
||||||
fn test_claims() -> Claims {
|
fn test_claims() -> Claims {
|
||||||
Claims::new("alice")
|
Claims::new("alice")
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
/// - ResourceMeta: metadata attached to each document/wiki entry
|
/// - ResourceMeta: metadata attached to each document/wiki entry
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Verbs
|
// Verbs
|
||||||
|
|||||||
@@ -4,9 +4,8 @@
|
|||||||
//! Uses LLM (Qwen-7B or similar) to judge if retrieved results are relevant.
|
//! Uses LLM (Qwen-7B or similar) to judge if retrieved results are relevant.
|
||||||
//! Tracks precision, recall, F1 via Prometheus metrics.
|
//! Tracks precision, recall, F1 via Prometheus metrics.
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{debug, error};
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::metrics;
|
use crate::metrics;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,3 @@
|
|||||||
/// Result Compressor: Optimize response size without losing essential information
|
|
||||||
///
|
|
||||||
/// Strategies:
|
|
||||||
/// - Truncate long texts to summary
|
|
||||||
/// - Extract key sentences
|
|
||||||
/// - Remove redundant metadata
|
|
||||||
/// - Compress to multiple formats (JSON, msgpack, CBOR)
|
|
||||||
/// - Progressive disclosure (compact by default, expand on demand)
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Compression strategy
|
/// Compression strategy
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::Result;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use mem_store::{PgRepo, Level};
|
use mem_store::PgRepo;
|
||||||
|
|
||||||
/// Memory record from log
|
/// Memory record from log
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -39,7 +39,7 @@ pub struct VerifyOpts {
|
|||||||
pub check_db: bool,
|
pub check_db: bool,
|
||||||
pub check_log: bool,
|
pub check_log: bool,
|
||||||
pub log_dir: Option<PathBuf>,
|
pub log_dir: Option<PathBuf>,
|
||||||
pub format: OutputFormat,
|
pub _format: OutputFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@@ -69,13 +69,13 @@ pub struct VerificationResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Verifier {
|
pub struct Verifier {
|
||||||
repo: PgRepo,
|
_repo: PgRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Verifier {
|
impl Verifier {
|
||||||
pub async fn new(db_url: &str) -> Result<Self> {
|
pub async fn new(db_url: &str) -> Result<Self> {
|
||||||
let repo = PgRepo::connect(db_url).await?;
|
let repo = PgRepo::connect(db_url).await?;
|
||||||
Ok(Self { repo })
|
Ok(Self { _repo: repo })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run all verifications
|
/// Run all verifications
|
||||||
@@ -136,7 +136,7 @@ impl Verifier {
|
|||||||
let mut evidence_gate_count = 0;
|
let mut evidence_gate_count = 0;
|
||||||
let mut evidence_records = 0;
|
let mut evidence_records = 0;
|
||||||
|
|
||||||
for (line_num, memory) in memories.iter().enumerate() {
|
for (_line_num, memory) in memories.iter().enumerate() {
|
||||||
let sha = Self::memory_sha(&memory.text);
|
let sha = Self::memory_sha(&memory.text);
|
||||||
memory_map.insert(sha.clone(), memory);
|
memory_map.insert(sha.clone(), memory);
|
||||||
level_map.insert(sha.clone(), memory.level.clone());
|
level_map.insert(sha.clone(), memory.level.clone());
|
||||||
@@ -188,7 +188,7 @@ impl Verifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invariant 2: Every parent sha resolves to a memory that exists
|
// Invariant 2: Every parent sha resolves to a memory that exists
|
||||||
for (sha, parents) in &memory_parents {
|
for (_sha, parents) in &memory_parents {
|
||||||
for parent_sha in parents {
|
for parent_sha in parents {
|
||||||
if !memory_map.contains_key(parent_sha) {
|
if !memory_map.contains_key(parent_sha) {
|
||||||
violations.push(Violation {
|
violations.push(Violation {
|
||||||
@@ -206,7 +206,7 @@ impl Verifier {
|
|||||||
// Invariant 3: Every evidence sha appears as a parent of at least one memory
|
// Invariant 3: Every evidence sha appears as a parent of at least one memory
|
||||||
for evidence_sha in &evidence_shas {
|
for evidence_sha in &evidence_shas {
|
||||||
let mut is_cited = false;
|
let mut is_cited = false;
|
||||||
for (sha, parents) in &memory_parents {
|
for (_sha, parents) in &memory_parents {
|
||||||
if parents.contains(evidence_sha) {
|
if parents.contains(evidence_sha) {
|
||||||
is_cited = true;
|
is_cited = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use mem_ingest::OptimizationMetrics;
|
|||||||
|
|
||||||
/// Memory record from log (local copy for rebuild purposes)
|
/// Memory record from log (local copy for rebuild purposes)
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
struct MemoryRecord {
|
pub struct MemoryRecord {
|
||||||
pub level: String,
|
pub level: String,
|
||||||
pub project: String,
|
pub project: String,
|
||||||
pub query_id: Option<String>,
|
pub query_id: Option<String>,
|
||||||
@@ -25,7 +25,7 @@ struct MemoryRecord {
|
|||||||
|
|
||||||
/// Parent reference for provenance
|
/// Parent reference for provenance
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
struct MemoryParent {
|
pub struct MemoryParent {
|
||||||
pub source: String,
|
pub source: String,
|
||||||
pub t: i32,
|
pub t: i32,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
name: poimen-memory
|
||||||
|
namespace: poimen
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: poimen-memory
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: poimen-memory
|
||||||
|
endpoints:
|
||||||
|
- port: http
|
||||||
|
path: /metrics
|
||||||
|
interval: 30s
|
||||||
Reference in New Issue
Block a user