fix(hands): add max_concurrent + timeout_secs fields + hand timeout enforcement
Some checks failed
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
M3-04/M3-05 audit fixes: - HandConfig: add max_concurrent (u32) and timeout_secs (u64) with serde defaults - Kernel execute_hand: enforce timeout via tokio::time::timeout, cancel on expiry - All 9 hand implementations: add max_concurrent: 0, timeout_secs: 0 - Agent createClone: pass soul field through to kernel - Fix duplicate soul block in agent_create command
This commit is contained in:
@@ -51,12 +51,40 @@ impl Kernel {
|
||||
let cancel_flag = Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
self.running_hand_runs.insert(run_id, cancel_flag.clone());
|
||||
|
||||
// Execute the hand
|
||||
// Execute the hand (with optional timeout from HandConfig)
|
||||
let context = HandContext::default();
|
||||
let start = std::time::Instant::now();
|
||||
let hand_result = self.hands.execute(hand_id, &context, input).await;
|
||||
|
||||
// Determine timeout: prefer HandConfig.timeout_secs, fallback to context default (300s)
|
||||
let timeout_secs = self.hands.get_config(hand_id)
|
||||
.await
|
||||
.map(|c| if c.timeout_secs > 0 { c.timeout_secs } else { context.timeout_secs })
|
||||
.unwrap_or(context.timeout_secs);
|
||||
|
||||
let hand_result = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(timeout_secs),
|
||||
self.hands.execute(hand_id, &context, input),
|
||||
).await;
|
||||
|
||||
let duration = start.elapsed();
|
||||
|
||||
// Handle timeout
|
||||
let hand_result = match hand_result {
|
||||
Ok(result) => result,
|
||||
Err(_) => {
|
||||
// Timeout elapsed
|
||||
cancel_flag.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
let mut run_update = run.clone();
|
||||
run_update.status = HandRunStatus::Failed;
|
||||
run_update.error = Some(format!("Hand execution timed out after {}s", timeout_secs));
|
||||
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::Timeout(format!("Hand '{}' timed out after {}s", hand_id, timeout_secs)));
|
||||
}
|
||||
};
|
||||
|
||||
// Check if cancelled during execution
|
||||
if cancel_flag.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
let mut run_update = run.clone();
|
||||
|
||||
Reference in New Issue
Block a user