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:
iven
2026-04-03 00:28:03 +08:00
parent 0a04b260a4
commit 52bdafa633
55 changed files with 4130 additions and 1959 deletions

View File

@@ -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,