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:
209
crates/zclaw-kernel/src/kernel/hands.rs
Normal file
209
crates/zclaw-kernel/src/kernel/hands.rs
Normal file
@@ -0,0 +1,209 @@
|
||||
//! Hand execution and run tracking
|
||||
|
||||
use std::sync::Arc;
|
||||
use zclaw_types::{Result, HandRun, HandRunId, HandRunStatus, HandRunFilter, TriggerSource};
|
||||
use zclaw_hands::{HandContext, HandResult};
|
||||
|
||||
use super::Kernel;
|
||||
|
||||
impl Kernel {
|
||||
/// Get the hands registry
|
||||
pub fn hands(&self) -> &Arc<zclaw_hands::HandRegistry> {
|
||||
&self.hands
|
||||
}
|
||||
|
||||
/// List all registered hands
|
||||
pub async fn list_hands(&self) -> Vec<zclaw_hands::HandConfig> {
|
||||
self.hands.list().await
|
||||
}
|
||||
|
||||
/// Execute a hand with the given input, tracking the run
|
||||
pub async fn execute_hand(
|
||||
&self,
|
||||
hand_id: &str,
|
||||
input: serde_json::Value,
|
||||
) -> Result<(HandResult, HandRunId)> {
|
||||
let run_id = HandRunId::new();
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
|
||||
// Create the initial HandRun record
|
||||
let mut run = HandRun {
|
||||
id: run_id,
|
||||
hand_name: hand_id.to_string(),
|
||||
trigger_source: TriggerSource::Manual,
|
||||
params: input.clone(),
|
||||
status: HandRunStatus::Pending,
|
||||
result: None,
|
||||
error: None,
|
||||
duration_ms: None,
|
||||
created_at: now.clone(),
|
||||
started_at: None,
|
||||
completed_at: None,
|
||||
};
|
||||
self.memory.save_hand_run(&run).await?;
|
||||
|
||||
// Transition to Running
|
||||
run.status = HandRunStatus::Running;
|
||||
run.started_at = Some(chrono::Utc::now().to_rfc3339());
|
||||
self.memory.update_hand_run(&run).await?;
|
||||
|
||||
// Register cancellation flag
|
||||
let cancel_flag = Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
self.running_hand_runs.insert(run_id, cancel_flag.clone());
|
||||
|
||||
// Execute the hand
|
||||
let context = HandContext::default();
|
||||
let start = std::time::Instant::now();
|
||||
let hand_result = self.hands.execute(hand_id, &context, input).await;
|
||||
let duration = start.elapsed();
|
||||
|
||||
// Check if cancelled during execution
|
||||
if cancel_flag.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
let mut run_update = run.clone();
|
||||
run_update.status = HandRunStatus::Cancelled;
|
||||
run_update.completed_at = Some(chrono::Utc::now().to_rfc3339());
|
||||
run_update.duration_ms = Some(duration.as_millis() as u64);
|
||||
self.memory.update_hand_run(&run_update).await?;
|
||||
self.running_hand_runs.remove(&run_id);
|
||||
return Err(zclaw_types::ZclawError::Internal("Hand execution cancelled".to_string()));
|
||||
}
|
||||
|
||||
// Remove from running map
|
||||
self.running_hand_runs.remove(&run_id);
|
||||
|
||||
// Update HandRun with result
|
||||
let completed_at = chrono::Utc::now().to_rfc3339();
|
||||
match &hand_result {
|
||||
Ok(res) => {
|
||||
run.status = HandRunStatus::Completed;
|
||||
run.result = Some(res.output.clone());
|
||||
run.error = res.error.clone();
|
||||
}
|
||||
Err(e) => {
|
||||
run.status = HandRunStatus::Failed;
|
||||
run.error = Some(e.to_string());
|
||||
}
|
||||
}
|
||||
run.duration_ms = Some(duration.as_millis() as u64);
|
||||
run.completed_at = Some(completed_at);
|
||||
self.memory.update_hand_run(&run).await?;
|
||||
|
||||
hand_result.map(|res| (res, run_id))
|
||||
}
|
||||
|
||||
/// Execute a hand with a specific trigger source (for scheduled/event triggers)
|
||||
pub async fn execute_hand_with_source(
|
||||
&self,
|
||||
hand_id: &str,
|
||||
input: serde_json::Value,
|
||||
trigger_source: TriggerSource,
|
||||
) -> Result<(HandResult, HandRunId)> {
|
||||
let run_id = HandRunId::new();
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
|
||||
let mut run = HandRun {
|
||||
id: run_id,
|
||||
hand_name: hand_id.to_string(),
|
||||
trigger_source,
|
||||
params: input.clone(),
|
||||
status: HandRunStatus::Pending,
|
||||
result: None,
|
||||
error: None,
|
||||
duration_ms: None,
|
||||
created_at: now,
|
||||
started_at: None,
|
||||
completed_at: None,
|
||||
};
|
||||
self.memory.save_hand_run(&run).await?;
|
||||
|
||||
run.status = HandRunStatus::Running;
|
||||
run.started_at = Some(chrono::Utc::now().to_rfc3339());
|
||||
self.memory.update_hand_run(&run).await?;
|
||||
|
||||
let cancel_flag = Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
self.running_hand_runs.insert(run_id, cancel_flag.clone());
|
||||
|
||||
let context = HandContext::default();
|
||||
let start = std::time::Instant::now();
|
||||
let hand_result = self.hands.execute(hand_id, &context, input).await;
|
||||
let duration = start.elapsed();
|
||||
|
||||
// Check if cancelled during execution
|
||||
if cancel_flag.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
run.status = HandRunStatus::Cancelled;
|
||||
run.completed_at = Some(chrono::Utc::now().to_rfc3339());
|
||||
run.duration_ms = Some(duration.as_millis() as u64);
|
||||
self.memory.update_hand_run(&run).await?;
|
||||
self.running_hand_runs.remove(&run_id);
|
||||
return Err(zclaw_types::ZclawError::Internal("Hand execution cancelled".to_string()));
|
||||
}
|
||||
|
||||
self.running_hand_runs.remove(&run_id);
|
||||
|
||||
let completed_at = chrono::Utc::now().to_rfc3339();
|
||||
match &hand_result {
|
||||
Ok(res) => {
|
||||
run.status = HandRunStatus::Completed;
|
||||
run.result = Some(res.output.clone());
|
||||
run.error = res.error.clone();
|
||||
}
|
||||
Err(e) => {
|
||||
run.status = HandRunStatus::Failed;
|
||||
run.error = Some(e.to_string());
|
||||
}
|
||||
}
|
||||
run.duration_ms = Some(duration.as_millis() as u64);
|
||||
run.completed_at = Some(completed_at);
|
||||
self.memory.update_hand_run(&run).await?;
|
||||
|
||||
hand_result.map(|res| (res, run_id))
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Hand Run Tracking
|
||||
// ============================================================
|
||||
|
||||
/// Get a hand run by ID
|
||||
pub async fn get_hand_run(&self, id: &HandRunId) -> Result<Option<HandRun>> {
|
||||
self.memory.get_hand_run(id).await
|
||||
}
|
||||
|
||||
/// List hand runs with filter
|
||||
pub async fn list_hand_runs(&self, filter: &HandRunFilter) -> Result<Vec<HandRun>> {
|
||||
self.memory.list_hand_runs(filter).await
|
||||
}
|
||||
|
||||
/// Count hand runs matching filter
|
||||
pub async fn count_hand_runs(&self, filter: &HandRunFilter) -> Result<u32> {
|
||||
self.memory.count_hand_runs(filter).await
|
||||
}
|
||||
|
||||
/// Cancel a running hand execution
|
||||
pub async fn cancel_hand_run(&self, id: &HandRunId) -> Result<()> {
|
||||
if let Some((_, flag)) = self.running_hand_runs.remove(id) {
|
||||
flag.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
// Note: the actual status update happens in execute_hand_with_source
|
||||
// when it detects the cancel flag
|
||||
Ok(())
|
||||
} else {
|
||||
// Not currently running — check if exists at all
|
||||
let run = self.memory.get_hand_run(id).await?;
|
||||
match run {
|
||||
Some(r) if r.status == HandRunStatus::Pending => {
|
||||
let mut updated = r;
|
||||
updated.status = HandRunStatus::Cancelled;
|
||||
updated.completed_at = Some(chrono::Utc::now().to_rfc3339());
|
||||
self.memory.update_hand_run(&updated).await?;
|
||||
Ok(())
|
||||
}
|
||||
Some(r) => Err(zclaw_types::ZclawError::InvalidInput(
|
||||
format!("Cannot cancel hand run {} with status {}", id, r.status)
|
||||
)),
|
||||
None => Err(zclaw_types::ZclawError::NotFound(
|
||||
format!("Hand run {} not found", id)
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user