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

@@ -0,0 +1,138 @@
//! Adapter types bridging runtime interfaces
use std::pin::Pin;
use std::sync::Arc;
use async_trait::async_trait;
use serde_json::Value;
use zclaw_runtime::{LlmDriver, tool::SkillExecutor};
use zclaw_skills::{SkillRegistry, LlmCompleter};
use zclaw_types::Result;
/// Adapter that bridges `zclaw_runtime::LlmDriver` -> `zclaw_skills::LlmCompleter`
pub(crate) struct LlmDriverAdapter {
pub(crate) driver: Arc<dyn LlmDriver>,
pub(crate) max_tokens: u32,
pub(crate) temperature: f32,
}
impl LlmCompleter for LlmDriverAdapter {
fn complete(
&self,
prompt: &str,
) -> Pin<Box<dyn std::future::Future<Output = std::result::Result<String, String>> + Send + '_>> {
let driver = self.driver.clone();
let prompt = prompt.to_string();
Box::pin(async move {
let request = zclaw_runtime::CompletionRequest {
messages: vec![zclaw_types::Message::user(prompt)],
max_tokens: Some(self.max_tokens),
temperature: Some(self.temperature),
..Default::default()
};
let response = driver.complete(request).await
.map_err(|e| format!("LLM completion error: {}", e))?;
// Extract text from content blocks
let text: String = response.content.iter()
.filter_map(|block| match block {
zclaw_runtime::ContentBlock::Text { text } => Some(text.as_str()),
_ => None,
})
.collect::<Vec<_>>()
.join("");
Ok(text)
})
}
}
/// Skill executor implementation for Kernel
pub struct KernelSkillExecutor {
pub(crate) skills: Arc<SkillRegistry>,
pub(crate) llm: Arc<dyn LlmCompleter>,
}
impl KernelSkillExecutor {
pub fn new(skills: Arc<SkillRegistry>, driver: Arc<dyn LlmDriver>) -> Self {
let llm: Arc<dyn zclaw_skills::LlmCompleter> = Arc::new(LlmDriverAdapter { driver, max_tokens: 4096, temperature: 0.7 });
Self { skills, llm }
}
}
#[async_trait]
impl SkillExecutor for KernelSkillExecutor {
async fn execute_skill(
&self,
skill_id: &str,
agent_id: &str,
session_id: &str,
input: Value,
) -> Result<Value> {
let context = zclaw_skills::SkillContext {
agent_id: agent_id.to_string(),
session_id: session_id.to_string(),
llm: Some(self.llm.clone()),
..Default::default()
};
let result = self.skills.execute(&zclaw_types::SkillId::new(skill_id), &context, input).await?;
Ok(result.output)
}
fn get_skill_detail(&self, skill_id: &str) -> Option<zclaw_runtime::tool::SkillDetail> {
let manifests = self.skills.manifests_snapshot();
let manifest = manifests.get(&zclaw_types::SkillId::new(skill_id))?;
Some(zclaw_runtime::tool::SkillDetail {
id: manifest.id.as_str().to_string(),
name: manifest.name.clone(),
description: manifest.description.clone(),
category: manifest.category.clone(),
input_schema: manifest.input_schema.clone(),
triggers: manifest.triggers.clone(),
capabilities: manifest.capabilities.clone(),
})
}
fn list_skill_index(&self) -> Vec<zclaw_runtime::tool::SkillIndexEntry> {
let manifests = self.skills.manifests_snapshot();
manifests.values()
.filter(|m| m.enabled)
.map(|m| zclaw_runtime::tool::SkillIndexEntry {
id: m.id.as_str().to_string(),
description: m.description.clone(),
triggers: m.triggers.clone(),
})
.collect()
}
}
/// Inbox wrapper for A2A message receivers that supports re-queuing
/// non-matching messages instead of dropping them.
#[cfg(feature = "multi-agent")]
pub(crate) struct AgentInbox {
pub(crate) rx: tokio::sync::mpsc::Receiver<zclaw_protocols::A2aEnvelope>,
pub(crate) pending: std::collections::VecDeque<zclaw_protocols::A2aEnvelope>,
}
#[cfg(feature = "multi-agent")]
impl AgentInbox {
pub(crate) fn new(rx: tokio::sync::mpsc::Receiver<zclaw_protocols::A2aEnvelope>) -> Self {
Self { rx, pending: std::collections::VecDeque::new() }
}
pub(crate) fn try_recv(&mut self) -> std::result::Result<zclaw_protocols::A2aEnvelope, tokio::sync::mpsc::error::TryRecvError> {
if let Some(msg) = self.pending.pop_front() {
return Ok(msg);
}
self.rx.try_recv()
}
pub(crate) async fn recv(&mut self) -> Option<zclaw_protocols::A2aEnvelope> {
if let Some(msg) = self.pending.pop_front() {
return Some(msg);
}
self.rx.recv().await
}
pub(crate) fn requeue(&mut self, envelope: zclaw_protocols::A2aEnvelope) {
self.pending.push_back(envelope);
}
}