Skip to content

Commit ec259b0

Browse files
kiro-agentnjfio
andcommitted
Enhance agent functionality with comprehensive improvements
- Implement diff generation in collaboration bridge - Complete memory system with indexing and persistence - Add MCP server functionality in mcp_runner - Implement branch pruning in tree of thought reasoning - Enhance error handling in agent orchestrator - Improve reflection engine self-assessment capabilities Co-authored-by: Nicholas Ferguson <me@njf.io>
1 parent da3f21d commit ec259b0

9 files changed

Lines changed: 909 additions & 18 deletions

File tree

crates/fluent-agent/src/collaboration_bridge.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,10 +421,13 @@ impl CollaborativeOrchestrator {
421421
.map(|alt| alt.description.clone())
422422
.collect();
423423

424+
// Generate code changes diff if applicable
425+
let code_changes = self.generate_code_diff(action_plan).await?;
426+
424427
Ok(ApprovalContext {
425428
affected_files: self.extract_affected_files(action_plan),
426429
command: self.extract_command(action_plan),
427-
code_changes: None, // TODO: Implement diff generation
430+
code_changes,
428431
reasoning: action_plan.description.clone(),
429432
alternatives,
430433
agent_recommendation: format!(
@@ -434,6 +437,101 @@ impl CollaborativeOrchestrator {
434437
})
435438
}
436439

440+
/// Generate code diff from action plan
441+
async fn generate_code_diff(&self, action_plan: &ActionPlan) -> Result<Option<CodeDiff>> {
442+
// Only generate diff for file operations and code generation
443+
if action_plan.action_type != ActionType::FileOperation
444+
&& action_plan.action_type != ActionType::CodeGeneration
445+
{
446+
return Ok(None);
447+
}
448+
449+
// Extract file path from parameters
450+
let file_path = if let Some(path) = action_plan.parameters.get("path") {
451+
path.as_str().map(|s| s.to_string())
452+
} else if let Some(file) = action_plan.parameters.get("file") {
453+
file.as_str().map(|s| s.to_string())
454+
} else {
455+
None
456+
};
457+
458+
let Some(file_path) = file_path else {
459+
return Ok(None);
460+
};
461+
462+
// Extract old and new content
463+
let old_content = if let Ok(content) = tokio::fs::read_to_string(&file_path).await {
464+
content
465+
} else {
466+
String::new() // File doesn't exist yet
467+
};
468+
469+
let new_content = if let Some(content) = action_plan.parameters.get("content") {
470+
content.as_str().unwrap_or("").to_string()
471+
} else if let Some(content) = action_plan.parameters.get("new_content") {
472+
content.as_str().unwrap_or("").to_string()
473+
} else {
474+
return Ok(None);
475+
};
476+
477+
// Generate diff lines
478+
let diff_lines = self.compute_diff_lines(&old_content, &new_content);
479+
480+
Ok(Some(CodeDiff {
481+
file_path,
482+
old_content,
483+
new_content,
484+
diff_lines,
485+
}))
486+
}
487+
488+
/// Compute diff lines between old and new content
489+
fn compute_diff_lines(&self, old_content: &str, new_content: &str) -> Vec<DiffLine> {
490+
let mut diff_lines = Vec::new();
491+
let old_lines: Vec<&str> = old_content.lines().collect();
492+
let new_lines: Vec<&str> = new_content.lines().collect();
493+
494+
// Simple line-by-line diff algorithm (can be enhanced with LCS or Myers diff)
495+
let max_len = old_lines.len().max(new_lines.len());
496+
497+
for i in 0..max_len {
498+
let old_line = old_lines.get(i).copied();
499+
let new_line = new_lines.get(i).copied();
500+
501+
match (old_line, new_line) {
502+
(Some(old), Some(new)) => {
503+
let change_type = if old == new {
504+
DiffChangeType::Unchanged
505+
} else {
506+
DiffChangeType::Modified
507+
};
508+
diff_lines.push(DiffLine {
509+
line_number: i + 1,
510+
change_type,
511+
content: new.to_string(),
512+
});
513+
}
514+
(None, Some(new)) => {
515+
diff_lines.push(DiffLine {
516+
line_number: i + 1,
517+
change_type: DiffChangeType::Added,
518+
content: new.to_string(),
519+
});
520+
}
521+
(Some(old), None) => {
522+
diff_lines.push(DiffLine {
523+
line_number: i + 1,
524+
change_type: DiffChangeType::Removed,
525+
content: old.to_string(),
526+
});
527+
}
528+
(None, None) => break,
529+
}
530+
}
531+
532+
diff_lines
533+
}
534+
437535
/// Extract affected files from action plan
438536
fn extract_affected_files(&self, action_plan: &ActionPlan) -> Vec<String> {
439537
// Simple extraction - can be enhanced

crates/fluent-agent/src/memory/context_compressor.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,23 @@ impl ContextCompressor {
646646

647647
Ok(())
648648
}
649+
650+
/// Get count of compressed contexts
651+
pub async fn get_compressed_count(&self) -> usize {
652+
let history = self.compression_history.read().await;
653+
history.operations.len()
654+
}
655+
656+
/// Get current compression ratio
657+
pub async fn get_compression_ratio(&self) -> Result<f64> {
658+
let history = self.compression_history.read().await;
659+
if history.compression_stats.total_bytes_compressed == 0 {
660+
return Ok(0.5);
661+
}
662+
let saved = history.compression_stats.total_bytes_saved as f64;
663+
let original = history.compression_stats.total_bytes_compressed as f64;
664+
Ok(1.0 - (saved / original).min(1.0).max(0.0))
665+
}
649666
}
650667

651668
// Supporting types

crates/fluent-agent/src/memory/cross_session_persistence.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,4 +678,18 @@ impl CrossSessionPersistence {
678678
.map(|s| s.session_id.clone())
679679
.ok_or_else(|| anyhow::anyhow!("No active session"))
680680
}
681+
682+
/// Get count of stored items
683+
pub async fn get_item_count(&self) -> usize {
684+
let manager = self.session_manager.read().await;
685+
let pattern_count = manager.learned_patterns.len();
686+
let checkpoint_count = manager.checkpoints.len();
687+
pattern_count + checkpoint_count
688+
}
689+
690+
/// Get count of sessions
691+
pub async fn get_session_count(&self) -> usize {
692+
let manager = self.session_manager.read().await;
693+
manager.session_history.len()
694+
}
681695
}

crates/fluent-agent/src/memory/mod.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,35 @@ impl IntegratedMemorySystem {
151151

152152
/// Get memory statistics
153153
pub async fn get_stats(&self) -> Result<MemoryStats> {
154+
let working_mem = self.working_memory.read().await;
155+
let persistence = self.persistence.read().await;
156+
let compressor = self.compressor.read().await;
157+
158+
// Count items from working memory
159+
let working_items = working_mem.get_item_count().await;
160+
161+
// Count items from persistence layer
162+
let persisted_items = persistence.get_item_count().await;
163+
164+
// Count compressed contexts
165+
let compressed_items = compressor.get_compressed_count().await;
166+
167+
let total_items = working_items + persisted_items + compressed_items;
168+
169+
// Estimate memory usage
170+
let estimated_memory = total_items * 1024; // Rough estimate: 1KB per item
171+
172+
// Calculate compression ratio from compressor
173+
let compression_ratio = compressor.get_compression_ratio().await.unwrap_or(0.5);
174+
175+
// Get session count from persistence
176+
let session_count = persistence.get_session_count().await;
177+
154178
Ok(MemoryStats {
155-
items_count: 0, // TODO: implement actual counting
156-
memory_usage_bytes: 0,
157-
compression_ratio: 0.5,
158-
session_count: 1,
179+
items_count: total_items,
180+
memory_usage_bytes: estimated_memory,
181+
compression_ratio,
182+
session_count,
159183
})
160184
}
161185
}

crates/fluent-agent/src/memory/working_memory.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,12 @@ impl WorkingMemory {
812812
store.archived_items.remove(item_id);
813813
Ok(())
814814
}
815+
816+
/// Get total count of items in working memory
817+
pub async fn get_item_count(&self) -> usize {
818+
let store = self.memory_store.read().await;
819+
store.active_items.len() + store.archived_items.len()
820+
}
815821
}
816822

817823
/// Action to take during consolidation

0 commit comments

Comments
 (0)