mirror of
https://github.com/samvallad33/vestige.git
synced 2026-05-08 23:32:37 +02:00
chore: license AGPL-3.0, zero clippy warnings, CHANGELOG through v1.6.0
License: - Replace MIT/Apache-2.0 with AGPL-3.0-only across all crates and npm packages - Replace LICENSE file with official GNU AGPL-3.0 text - Remove LICENSE-MIT and LICENSE-APACHE Code quality: - Fix all 44 clippy warnings (zero remaining) - Collapsible if statements, redundant closures, manual Option::map - Remove duplicate #[allow(dead_code)] attributes in deprecated tool modules - Add Default impl for CognitiveEngine - Replace manual sort_by with sort_by_key Documentation: - Update CHANGELOG with v1.2.0, v1.3.0, v1.5.0, v1.6.0 entries - Update README with v1.6.0 highlights and accurate stats (52K lines, 1100+ tests) - Add fastembed-rs/ to .gitignore - Add fastembed-rs to workspace exclude 1115 tests passing, zero warnings, RUSTFLAGS="-Dwarnings" clean.
This commit is contained in:
parent
495a88331f
commit
ce520bb246
40 changed files with 953 additions and 424 deletions
|
|
@ -4,7 +4,7 @@ version = "1.6.0"
|
|||
edition = "2024"
|
||||
description = "Cognitive memory MCP server for Claude - FSRS-6, spreading activation, synaptic tagging, and 130 years of memory research"
|
||||
authors = ["samvallad33"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
license = "AGPL-3.0-only"
|
||||
keywords = ["mcp", "ai", "memory", "fsrs", "neuroscience", "cognitive-science", "spaced-repetition"]
|
||||
categories = ["command-line-utilities", "database"]
|
||||
repository = "https://github.com/samvallad33/vestige"
|
||||
|
|
|
|||
|
|
@ -561,11 +561,10 @@ fn run_backup(output: PathBuf) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
// Create parent directories if needed
|
||||
if let Some(parent) = output.parent() {
|
||||
if !parent.exists() {
|
||||
if let Some(parent) = output.parent()
|
||||
&& !parent.exists() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the database file
|
||||
println!("Copying database...");
|
||||
|
|
@ -638,11 +637,10 @@ fn run_export(
|
|||
.iter()
|
||||
.filter(|node| {
|
||||
// Date filter
|
||||
if let Some(ref since_dt) = since_date {
|
||||
if node.created_at < *since_dt {
|
||||
if let Some(ref since_dt) = since_date
|
||||
&& node.created_at < *since_dt {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Tag filter: node must contain ALL specified tags
|
||||
if !tag_filter.is_empty() {
|
||||
for tag in &tag_filter {
|
||||
|
|
@ -671,11 +669,10 @@ fn run_export(
|
|||
println!();
|
||||
|
||||
// Create parent directories if needed
|
||||
if let Some(parent) = output.parent() {
|
||||
if !parent.exists() {
|
||||
if let Some(parent) = output.parent()
|
||||
&& !parent.exists() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
}
|
||||
|
||||
let file = std::fs::File::create(&output)?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
|
|
|
|||
|
|
@ -61,10 +61,16 @@ pub struct CognitiveEngine {
|
|||
pub temporal_searcher: TemporalSearcher,
|
||||
}
|
||||
|
||||
impl Default for CognitiveEngine {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl CognitiveEngine {
|
||||
/// Initialize all cognitive modules with default configurations.
|
||||
pub fn new() -> Self {
|
||||
let engine = Self {
|
||||
Self {
|
||||
// Neuroscience
|
||||
activation_network: ActivationNetwork::new(),
|
||||
synaptic_tagging: SynapticTaggingSystem::new(),
|
||||
|
|
@ -98,8 +104,6 @@ impl CognitiveEngine {
|
|||
// Search
|
||||
reranker: Reranker::new(RerankerConfig::default()),
|
||||
temporal_searcher: TemporalSearcher::new(),
|
||||
};
|
||||
|
||||
engine
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ impl McpServer {
|
|||
|
||||
// Version negotiation: use client's version if older than server's
|
||||
// Claude Desktop rejects servers with newer protocol versions
|
||||
let negotiated_version = if request.protocol_version < MCP_VERSION.to_string() {
|
||||
let negotiated_version = if request.protocol_version.as_str() < MCP_VERSION {
|
||||
info!("Client requested older protocol version {}, using it", request.protocol_version);
|
||||
request.protocol_version.clone()
|
||||
} else {
|
||||
|
|
@ -593,7 +593,7 @@ impl McpServer {
|
|||
let should_consolidate = self.cognitive.try_lock()
|
||||
.ok()
|
||||
.map(|cog| cog.consolidation_scheduler.should_consolidate())
|
||||
.unwrap_or(count % 100 == 0); // Fallback to count-based if lock unavailable
|
||||
.unwrap_or(count.is_multiple_of(100)); // Fallback to count-based if lock unavailable
|
||||
|
||||
if should_consolidate {
|
||||
let storage_clone = Arc::clone(&self.storage);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Codebase Tools (Deprecated - use codebase_unified instead)
|
||||
//!
|
||||
//! Remember patterns, decisions, and context about codebases.
|
||||
|
|
@ -131,12 +130,12 @@ pub async fn execute_pattern(
|
|||
// Build content with structured format
|
||||
let mut content = format!("# Code Pattern: {}\n\n{}", args.name, args.description);
|
||||
|
||||
if let Some(ref files) = args.files {
|
||||
if !files.is_empty() {
|
||||
content.push_str("\n\n## Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
if let Some(ref files) = args.files
|
||||
&& !files.is_empty()
|
||||
{
|
||||
content.push_str("\n\n## Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -189,21 +188,21 @@ pub async fn execute_decision(
|
|||
args.decision
|
||||
);
|
||||
|
||||
if let Some(ref alternatives) = args.alternatives {
|
||||
if !alternatives.is_empty() {
|
||||
content.push_str("\n\n## Alternatives Considered:\n");
|
||||
for alt in alternatives {
|
||||
content.push_str(&format!("- {}\n", alt));
|
||||
}
|
||||
if let Some(ref alternatives) = args.alternatives
|
||||
&& !alternatives.is_empty()
|
||||
{
|
||||
content.push_str("\n\n## Alternatives Considered:\n");
|
||||
for alt in alternatives {
|
||||
content.push_str(&format!("- {}\n", alt));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref files) = args.files {
|
||||
if !files.is_empty() {
|
||||
content.push_str("\n\n## Affected Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
if let Some(ref files) = args.files
|
||||
&& !files.is_empty()
|
||||
{
|
||||
content.push_str("\n\n## Affected Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -239,7 +238,7 @@ pub async fn execute_context(
|
|||
args: Option<Value>,
|
||||
) -> Result<Value, String> {
|
||||
let args: ContextArgs = args
|
||||
.map(|v| serde_json::from_value(v))
|
||||
.map(serde_json::from_value)
|
||||
.transpose()
|
||||
.map_err(|e| format!("Invalid arguments: {}", e))?
|
||||
.unwrap_or(ContextArgs {
|
||||
|
|
|
|||
|
|
@ -127,12 +127,12 @@ async fn execute_remember_pattern(
|
|||
// Build content with structured format
|
||||
let mut content = format!("# Code Pattern: {}\n\n{}", name, description);
|
||||
|
||||
if let Some(ref files) = args.files {
|
||||
if !files.is_empty() {
|
||||
content.push_str("\n\n## Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
if let Some(ref files) = args.files
|
||||
&& !files.is_empty()
|
||||
{
|
||||
content.push_str("\n\n## Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,21 +211,21 @@ async fn execute_remember_decision(
|
|||
decision
|
||||
);
|
||||
|
||||
if let Some(ref alternatives) = args.alternatives {
|
||||
if !alternatives.is_empty() {
|
||||
content.push_str("\n\n## Alternatives Considered:\n");
|
||||
for alt in alternatives {
|
||||
content.push_str(&format!("- {}\n", alt));
|
||||
}
|
||||
if let Some(ref alternatives) = args.alternatives
|
||||
&& !alternatives.is_empty()
|
||||
{
|
||||
content.push_str("\n\n## Alternatives Considered:\n");
|
||||
for alt in alternatives {
|
||||
content.push_str(&format!("- {}\n", alt));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref files) = args.files {
|
||||
if !files.is_empty() {
|
||||
content.push_str("\n\n## Affected Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
if let Some(ref files) = args.files
|
||||
&& !files.is_empty()
|
||||
{
|
||||
content.push_str("\n\n## Affected Files:\n");
|
||||
for f in files {
|
||||
content.push_str(&format!("- {}\n", f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,23 +336,23 @@ async fn execute_get_context(
|
|||
// COGNITIVE: Cross-project knowledge discovery
|
||||
// ====================================================================
|
||||
let mut universal_patterns = Vec::new();
|
||||
if let Some(codebase_name) = &args.codebase {
|
||||
if let Ok(cog) = cognitive.try_lock() {
|
||||
let context = vestige_core::advanced::cross_project::ProjectContext {
|
||||
path: None,
|
||||
name: Some(codebase_name.clone()),
|
||||
languages: Vec::new(),
|
||||
frameworks: Vec::new(),
|
||||
file_types: std::collections::HashSet::new(),
|
||||
dependencies: Vec::new(),
|
||||
structure: Vec::new(),
|
||||
};
|
||||
let applicable = cog.cross_project.detect_applicable(&context);
|
||||
for knowledge in applicable {
|
||||
universal_patterns.push(serde_json::json!({
|
||||
"pattern": format!("{:?}", knowledge),
|
||||
}));
|
||||
}
|
||||
if let Some(codebase_name) = &args.codebase
|
||||
&& let Ok(cog) = cognitive.try_lock()
|
||||
{
|
||||
let context = vestige_core::advanced::cross_project::ProjectContext {
|
||||
path: None,
|
||||
name: Some(codebase_name.clone()),
|
||||
languages: Vec::new(),
|
||||
frameworks: Vec::new(),
|
||||
file_types: std::collections::HashSet::new(),
|
||||
dependencies: Vec::new(),
|
||||
structure: Vec::new(),
|
||||
};
|
||||
let applicable = cog.cross_project.detect_applicable(&context);
|
||||
for knowledge in applicable {
|
||||
universal_patterns.push(serde_json::json!({
|
||||
"pattern": format!("{:?}", knowledge),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Consolidation Tool (Deprecated)
|
||||
//!
|
||||
//! Run memory consolidation cycle with FSRS decay and embedding generation.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Context-Dependent Memory Tool (Deprecated)
|
||||
//!
|
||||
//! Retrieval based on encoding context match.
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ pub async fn execute(
|
|||
|
||||
for i in 0..n {
|
||||
for j in (i + 1)..n {
|
||||
let sim = cosine_similarity(&filtered_embeddings[i].2, &filtered_embeddings[j].2);
|
||||
let sim = cosine_similarity(filtered_embeddings[i].2, filtered_embeddings[j].2);
|
||||
if sim >= threshold {
|
||||
uf.union(i, j);
|
||||
similarities.push((i, j, sim));
|
||||
|
|
@ -195,7 +195,7 @@ pub async fn execute(
|
|||
.into_values()
|
||||
.filter(|c| c.len() > 1)
|
||||
.collect();
|
||||
clusters.sort_by(|a, b| b.len().cmp(&a.len()));
|
||||
clusters.sort_by_key(|b| std::cmp::Reverse(b.len()));
|
||||
clusters.truncate(limit);
|
||||
|
||||
// Build similarity lookup for formatting
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Feedback Tools
|
||||
//!
|
||||
//! Promote and demote memories based on outcome quality.
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ pub async fn execute(
|
|||
|
||||
run_post_ingest(cognitive, &node_id, &node_content, &node_type, importance_composite);
|
||||
|
||||
return Ok(serde_json::json!({
|
||||
Ok(serde_json::json!({
|
||||
"success": true,
|
||||
"nodeId": node_id,
|
||||
"decision": result.decision,
|
||||
|
|
@ -150,7 +150,7 @@ pub async fn execute(
|
|||
"reason": result.reason,
|
||||
"isNovel": is_novel,
|
||||
"embeddingStrategy": embedding_strategy,
|
||||
}));
|
||||
}))
|
||||
}
|
||||
Err(_) => {
|
||||
let node = storage_guard.ingest(fallback_input).map_err(|e| e.to_string())?;
|
||||
|
|
@ -162,7 +162,7 @@ pub async fn execute(
|
|||
|
||||
run_post_ingest(cognitive, &node_id, &node_content, &node_type, importance_composite);
|
||||
|
||||
return Ok(serde_json::json!({
|
||||
Ok(serde_json::json!({
|
||||
"success": true,
|
||||
"nodeId": node_id,
|
||||
"decision": "create",
|
||||
|
|
@ -170,7 +170,7 @@ pub async fn execute(
|
|||
"hasEmbedding": has_embedding,
|
||||
"isNovel": is_novel,
|
||||
"embeddingStrategy": embedding_strategy,
|
||||
}));
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,38 +257,38 @@ async fn execute_set(
|
|||
|
||||
if let Ok(cog) = cognitive.try_lock() {
|
||||
// 8A. Try NLP parsing when no explicit trigger is provided
|
||||
if args.trigger.is_none() {
|
||||
if let Ok(parsed) = cog.intention_parser.parse(description) {
|
||||
nlp_parsed = true;
|
||||
// Extract trigger info from parsed intention
|
||||
let (t_type, t_data) = match &parsed.trigger {
|
||||
ProspectiveTrigger::TimeBased { .. } => {
|
||||
("time".to_string(), serde_json::json!({"type": "time"}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::DurationBased { after, .. } => {
|
||||
let mins = after.num_minutes();
|
||||
("time".to_string(), serde_json::json!({"type": "time", "in_minutes": mins}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::EventBased { condition, .. } => {
|
||||
("event".to_string(), serde_json::json!({"type": "event", "condition": condition}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::ContextBased { context_match } => {
|
||||
("context".to_string(), serde_json::json!({"type": "context", "topic": format!("{:?}", context_match)}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::Recurring { .. } => {
|
||||
("recurring".to_string(), serde_json::json!({"type": "recurring"}).to_string())
|
||||
}
|
||||
_ => {
|
||||
("event".to_string(), serde_json::json!({"type": "event"}).to_string())
|
||||
}
|
||||
};
|
||||
nlp_trigger_type = Some(t_type);
|
||||
nlp_trigger_data = Some(t_data);
|
||||
|
||||
// Use NLP-detected priority if user didn't specify one
|
||||
if args.priority.is_none() {
|
||||
nlp_priority = Some(parsed.priority);
|
||||
if args.trigger.is_none()
|
||||
&& let Ok(parsed) = cog.intention_parser.parse(description)
|
||||
{
|
||||
nlp_parsed = true;
|
||||
// Extract trigger info from parsed intention
|
||||
let (t_type, t_data) = match &parsed.trigger {
|
||||
ProspectiveTrigger::TimeBased { .. } => {
|
||||
("time".to_string(), serde_json::json!({"type": "time"}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::DurationBased { after, .. } => {
|
||||
let mins = after.num_minutes();
|
||||
("time".to_string(), serde_json::json!({"type": "time", "in_minutes": mins}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::EventBased { condition, .. } => {
|
||||
("event".to_string(), serde_json::json!({"type": "event", "condition": condition}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::ContextBased { context_match } => {
|
||||
("context".to_string(), serde_json::json!({"type": "context", "topic": format!("{:?}", context_match)}).to_string())
|
||||
}
|
||||
ProspectiveTrigger::Recurring { .. } => {
|
||||
("recurring".to_string(), serde_json::json!({"type": "recurring"}).to_string())
|
||||
}
|
||||
_ => {
|
||||
("event".to_string(), serde_json::json!({"type": "event"}).to_string())
|
||||
}
|
||||
};
|
||||
nlp_trigger_type = Some(t_type);
|
||||
nlp_trigger_data = Some(t_data);
|
||||
|
||||
// Use NLP-detected priority if user didn't specify one
|
||||
if args.priority.is_none() {
|
||||
nlp_priority = Some(parsed.priority);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -355,10 +355,8 @@ async fn execute_set(
|
|||
DateTime::parse_from_rfc3339(at)
|
||||
.ok()
|
||||
.map(|dt| dt.with_timezone(&Utc))
|
||||
} else if let Some(mins) = trigger.in_minutes {
|
||||
Some(now + Duration::minutes(mins))
|
||||
} else {
|
||||
None
|
||||
trigger.in_minutes.map(|mins| now + Duration::minutes(mins))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
|
@ -410,21 +408,21 @@ async fn execute_check(
|
|||
// ====================================================================
|
||||
// COGNITIVE: Update prospective memory context
|
||||
// ====================================================================
|
||||
if let Some(ctx) = &args.context {
|
||||
if let Ok(cog) = cognitive.try_lock() {
|
||||
let mut prospective_ctx = ProspectiveContext::new();
|
||||
if let Some(codebase) = &ctx.codebase {
|
||||
prospective_ctx.project_name = Some(codebase.clone());
|
||||
}
|
||||
if let Some(file) = &ctx.file {
|
||||
prospective_ctx.active_files = vec![file.clone()];
|
||||
}
|
||||
if let Some(topics) = &ctx.topics {
|
||||
prospective_ctx.active_topics = topics.clone();
|
||||
}
|
||||
// Update context on prospective memory (triggers internal monitoring)
|
||||
let _ = cog.prospective_memory.update_context(prospective_ctx);
|
||||
if let Some(ctx) = &args.context
|
||||
&& let Ok(cog) = cognitive.try_lock()
|
||||
{
|
||||
let mut prospective_ctx = ProspectiveContext::new();
|
||||
if let Some(codebase) = &ctx.codebase {
|
||||
prospective_ctx.project_name = Some(codebase.clone());
|
||||
}
|
||||
if let Some(file) = &ctx.file {
|
||||
prospective_ctx.active_files = vec![file.clone()];
|
||||
}
|
||||
if let Some(topics) = &ctx.topics {
|
||||
prospective_ctx.active_topics = topics.clone();
|
||||
}
|
||||
// Update context on prospective memory (triggers internal monitoring)
|
||||
let _ = cog.prospective_memory.update_context(prospective_ctx);
|
||||
}
|
||||
|
||||
let storage = storage.lock().await;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Intentions Tools (Deprecated - use intention_unified instead)
|
||||
//!
|
||||
//! Prospective memory tools for setting and checking future intentions.
|
||||
|
|
@ -264,10 +263,8 @@ pub async fn execute_set(
|
|||
let trigger_at = if let Some(trigger) = &args.trigger {
|
||||
if let Some(at) = &trigger.at {
|
||||
DateTime::parse_from_rfc3339(at).ok().map(|dt| dt.with_timezone(&Utc))
|
||||
} else if let Some(mins) = trigger.in_minutes {
|
||||
Some(now + Duration::minutes(mins))
|
||||
} else {
|
||||
None
|
||||
trigger.in_minutes.map(|mins| now + Duration::minutes(mins))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Knowledge Tools (Deprecated - use memory_unified instead)
|
||||
//!
|
||||
//! Get and delete specific knowledge nodes.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Memory States Tool (Deprecated - use memory_unified instead)
|
||||
//!
|
||||
//! Query and manage memory states (Active, Dormant, Silent, Unavailable).
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Recall Tool (Deprecated - use search_unified instead)
|
||||
//!
|
||||
//! Search and retrieve knowledge from memory.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Review Tool (Deprecated)
|
||||
//!
|
||||
//! Mark memories as reviewed using FSRS-6 algorithm.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Search Tools (Deprecated - use search_unified instead)
|
||||
//!
|
||||
//! Semantic and hybrid search implementations.
|
||||
|
|
|
|||
|
|
@ -226,19 +226,19 @@ pub async fn execute(
|
|||
// ====================================================================
|
||||
// STAGE 5: Context matching (Tulving 1973 encoding specificity)
|
||||
// ====================================================================
|
||||
if let Some(ref topics) = args.context_topics {
|
||||
if !topics.is_empty() {
|
||||
let retrieval_ctx = EncodingContext::new()
|
||||
.with_topical(TopicalContext::with_topics(topics.clone()));
|
||||
if let Ok(cog) = cognitive.try_lock() {
|
||||
for result in &mut filtered_results {
|
||||
// Build encoding context from memory's tags
|
||||
let encoding_ctx = EncodingContext::new()
|
||||
.with_topical(TopicalContext::with_topics(result.node.tags.clone()));
|
||||
let context_score = cog.context_matcher.match_contexts(&encoding_ctx, &retrieval_ctx);
|
||||
// Blend: context match boosts relevance up to +30%
|
||||
result.combined_score *= 1.0 + (context_score as f32 * 0.3);
|
||||
}
|
||||
if let Some(ref topics) = args.context_topics
|
||||
&& !topics.is_empty()
|
||||
{
|
||||
let retrieval_ctx = EncodingContext::new()
|
||||
.with_topical(TopicalContext::with_topics(topics.clone()));
|
||||
if let Ok(cog) = cognitive.try_lock() {
|
||||
for result in &mut filtered_results {
|
||||
// Build encoding context from memory's tags
|
||||
let encoding_ctx = EncodingContext::new()
|
||||
.with_topical(TopicalContext::with_topics(result.node.tags.clone()));
|
||||
let context_score = cog.context_matcher.match_contexts(&encoding_ctx, &retrieval_ctx);
|
||||
// Blend: context match boosts relevance up to +30%
|
||||
result.combined_score *= 1.0 + (context_score as f32 * 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -270,23 +270,23 @@ pub async fn execute(
|
|||
// STAGE 5B: Retrieval competition (Anderson et al. 1994)
|
||||
// ====================================================================
|
||||
let mut suppressed_count = 0_usize;
|
||||
if filtered_results.len() > 1 {
|
||||
if let Ok(mut cog) = cognitive.try_lock() {
|
||||
let candidates: Vec<CompetitionCandidate> = filtered_results
|
||||
.iter()
|
||||
.map(|r| CompetitionCandidate {
|
||||
memory_id: r.node.id.clone(),
|
||||
relevance_score: r.combined_score as f64,
|
||||
similarity_to_query: r.semantic_score.unwrap_or(0.0) as f64,
|
||||
})
|
||||
.collect();
|
||||
if let Some(result) = cog.competition_mgr.run_competition(&candidates, 0.7) {
|
||||
// Apply suppression: losers get penalized
|
||||
for suppressed_id in &result.suppressed_ids {
|
||||
if let Some(r) = filtered_results.iter_mut().find(|r| &r.node.id == suppressed_id) {
|
||||
r.combined_score *= 0.85; // 15% suppression penalty
|
||||
suppressed_count += 1;
|
||||
}
|
||||
if filtered_results.len() > 1
|
||||
&& let Ok(mut cog) = cognitive.try_lock()
|
||||
{
|
||||
let candidates: Vec<CompetitionCandidate> = filtered_results
|
||||
.iter()
|
||||
.map(|r| CompetitionCandidate {
|
||||
memory_id: r.node.id.clone(),
|
||||
relevance_score: r.combined_score as f64,
|
||||
similarity_to_query: r.semantic_score.unwrap_or(0.0) as f64,
|
||||
})
|
||||
.collect();
|
||||
if let Some(result) = cog.competition_mgr.run_competition(&candidates, 0.7) {
|
||||
// Apply suppression: losers get penalized
|
||||
for suppressed_id in &result.suppressed_ids {
|
||||
if let Some(r) = filtered_results.iter_mut().find(|r| &r.node.id == suppressed_id) {
|
||||
r.combined_score *= 0.85; // 15% suppression penalty
|
||||
suppressed_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ pub async fn execute(
|
|||
// Post-ingest cognitive side effects
|
||||
run_post_ingest(cognitive, &node_id, &node_content, &node_type, importance_composite);
|
||||
|
||||
return Ok(serde_json::json!({
|
||||
Ok(serde_json::json!({
|
||||
"success": true,
|
||||
"decision": result.decision,
|
||||
"nodeId": node_id,
|
||||
|
|
@ -191,7 +191,7 @@ pub async fn execute(
|
|||
"add_context" => "Added new content as context to existing memory",
|
||||
_ => "Memory processed successfully"
|
||||
}
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "embeddings", feature = "vector-search")))]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Stats Tools (Deprecated - use memory_unified instead)
|
||||
//!
|
||||
//! Memory statistics and health check.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
//! Synaptic Tagging Tool (Deprecated)
|
||||
//!
|
||||
//! Retroactive importance assignment based on Synaptic Tagging & Capture theory.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue