refactor(crates): kernel/generation module split + DeerFlow optimizations + middleware + dead code cleanup
- Split zclaw-kernel/kernel.rs (1486 lines) into 9 domain modules - Split zclaw-kernel/generation.rs (1080 lines) into 3 modules - Add DeerFlow-inspired middleware: DanglingTool, SubagentLimit, ToolError, ToolOutputGuard - Add PromptBuilder for structured system prompt assembly - Add FactStore (zclaw-memory) for persistent fact extraction - Add task builtin tool for agent task management - Driver improvements: Anthropic/OpenAI extended thinking, Gemini safety settings - Replace let _ = with proper log::warn! across SaaS handlers - Remove unused dependency (url) from zclaw-hands
This commit is contained in:
@@ -16,6 +16,7 @@ use zclaw_growth::{
|
||||
MemoryExtractor, MemoryRetriever, PromptInjector, RetrievalResult,
|
||||
VikingAdapter,
|
||||
};
|
||||
use zclaw_memory::{ExtractedFactBatch, Fact, FactCategory};
|
||||
use zclaw_types::{AgentId, Message, Result, SessionId};
|
||||
|
||||
/// Growth system integration for AgentLoop
|
||||
@@ -212,6 +213,80 @@ impl GrowthIntegration {
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
/// Combined extraction: single LLM call that produces both stored memories
|
||||
/// and structured facts, avoiding double extraction overhead.
|
||||
///
|
||||
/// Returns `(memory_count, Option<ExtractedFactBatch>)` on success.
|
||||
pub async fn extract_combined(
|
||||
&self,
|
||||
agent_id: &AgentId,
|
||||
messages: &[Message],
|
||||
session_id: &SessionId,
|
||||
) -> Result<Option<(usize, ExtractedFactBatch)>> {
|
||||
if !self.config.enabled || !self.config.auto_extract {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Single LLM extraction call
|
||||
let extracted = self
|
||||
.extractor
|
||||
.extract(messages, session_id.clone())
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
tracing::warn!("[GrowthIntegration] Combined extraction failed: {}", e);
|
||||
Vec::new()
|
||||
});
|
||||
|
||||
if extracted.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mem_count = extracted.len();
|
||||
|
||||
// Store raw memories
|
||||
self.extractor
|
||||
.store_memories(&agent_id.to_string(), &extracted)
|
||||
.await?;
|
||||
|
||||
// Track learning event
|
||||
self.tracker
|
||||
.record_learning(agent_id, &session_id.to_string(), mem_count)
|
||||
.await?;
|
||||
|
||||
// Convert same extracted memories to structured facts (no extra LLM call)
|
||||
let facts: Vec<Fact> = extracted
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
let category = match m.memory_type {
|
||||
zclaw_growth::types::MemoryType::Preference => FactCategory::Preference,
|
||||
zclaw_growth::types::MemoryType::Knowledge => FactCategory::Knowledge,
|
||||
zclaw_growth::types::MemoryType::Experience => FactCategory::Behavior,
|
||||
_ => FactCategory::General,
|
||||
};
|
||||
Fact::new(m.content, category, f64::from(m.confidence))
|
||||
.with_source(session_id.to_string())
|
||||
})
|
||||
.collect();
|
||||
|
||||
let batch = ExtractedFactBatch {
|
||||
facts,
|
||||
agent_id: agent_id.to_string(),
|
||||
session_id: session_id.to_string(),
|
||||
}
|
||||
.deduplicate()
|
||||
.filter_by_confidence(0.7);
|
||||
|
||||
if batch.is_empty() {
|
||||
return Ok(Some((mem_count, ExtractedFactBatch {
|
||||
facts: vec![],
|
||||
agent_id: agent_id.to_string(),
|
||||
session_id: session_id.to_string(),
|
||||
})));
|
||||
}
|
||||
|
||||
Ok(Some((mem_count, batch)))
|
||||
}
|
||||
|
||||
/// Retrieve memories for a query without injection
|
||||
pub async fn retrieve_memories(
|
||||
&self,
|
||||
|
||||
Reference in New Issue
Block a user