diff --git a/crates/zclaw-kernel/src/kernel.rs b/crates/zclaw-kernel/src/kernel.rs index 61fef3c..df871da 100644 --- a/crates/zclaw-kernel/src/kernel.rs +++ b/crates/zclaw-kernel/src/kernel.rs @@ -130,6 +130,8 @@ pub struct Kernel { pending_approvals: Arc>>, /// Running hand runs that can be cancelled (run_id -> cancelled flag) running_hand_runs: Arc>>, + /// Shared memory storage backend for Growth system + viking: Arc, /// A2A router for inter-agent messaging (gated by multi-agent feature) #[cfg(feature = "multi-agent")] a2a_router: Arc, @@ -190,6 +192,9 @@ impl Kernel { // Initialize trigger manager let trigger_manager = crate::trigger_manager::TriggerManager::new(hands.clone()); + // Initialize Growth system — shared VikingAdapter for memory storage + let viking = Arc::new(zclaw_runtime::VikingAdapter::in_memory()); + // Restore persisted agents let persisted = memory.list_agents().await?; for agent in persisted { @@ -217,6 +222,7 @@ impl Kernel { trigger_manager, pending_approvals: Arc::new(Mutex::new(Vec::new())), running_hand_runs: Arc::new(dashmap::DashMap::new()), + viking, #[cfg(feature = "multi-agent")] a2a_router, #[cfg(feature = "multi-agent")] @@ -239,19 +245,30 @@ impl Kernel { fn create_middleware_chain(&self) -> Option { let mut chain = zclaw_runtime::middleware::MiddlewareChain::new(); + // Growth integration — shared VikingAdapter for memory middleware & compaction + let growth = zclaw_runtime::GrowthIntegration::new(self.viking.clone()); + // Compaction middleware — only register when threshold > 0 let threshold = self.config.compaction_threshold(); if threshold > 0 { use std::sync::Arc; + let growth_for_compaction = zclaw_runtime::GrowthIntegration::new(self.viking.clone()); let mw = zclaw_runtime::middleware::compaction::CompactionMiddleware::new( threshold, zclaw_runtime::CompactionConfig::default(), Some(self.driver.clone()), - None, // growth not wired in kernel yet + Some(growth_for_compaction), ); chain.register(Arc::new(mw)); } + // Memory middleware — auto-extract memories after conversations + { + use std::sync::Arc; + let mw = zclaw_runtime::middleware::memory::MemoryMiddleware::new(growth); + chain.register(Arc::new(mw)); + } + // Loop guard middleware { use std::sync::Arc; @@ -965,13 +982,62 @@ impl Kernel { let input = entry.input.clone(); drop(approvals); // Release lock before async hand execution - // Execute the hand in background + // Execute the hand in background with HandRun tracking let hands = self.hands.clone(); let approvals = self.pending_approvals.clone(); + let memory = self.memory.clone(); + let running_hand_runs = self.running_hand_runs.clone(); let id_owned = id.to_string(); tokio::spawn(async move { + // Create HandRun record for tracking + let run_id = HandRunId::new(); + let now = chrono::Utc::now().to_rfc3339(); + let mut run = HandRun { + id: run_id, + hand_name: hand_id.clone(), + 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, + }; + let _ = memory.save_hand_run(&run).await; + run.status = HandRunStatus::Running; + run.started_at = Some(chrono::Utc::now().to_rfc3339()); + let _ = memory.update_hand_run(&run).await; + + // Register cancellation flag + let cancel_flag = Arc::new(std::sync::atomic::AtomicBool::new(false)); + running_hand_runs.insert(run.id, cancel_flag.clone()); + let context = HandContext::default(); + let start = std::time::Instant::now(); let result = hands.execute(&hand_id, &context, input).await; + let duration = start.elapsed(); + + // Remove from running map + running_hand_runs.remove(&run.id); + + // Update HandRun with result + let completed_at = chrono::Utc::now().to_rfc3339(); + match &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); + let _ = memory.update_hand_run(&run).await; // Update approval status based on execution result let mut approvals = approvals.lock().await; @@ -980,7 +1046,6 @@ impl Kernel { Ok(_) => entry.status = "completed".to_string(), Err(e) => { entry.status = "failed".to_string(); - // Store error in input metadata if let Some(obj) = entry.input.as_object_mut() { obj.insert("error".to_string(), Value::String(format!("{}", e))); } diff --git a/crates/zclaw-runtime/src/lib.rs b/crates/zclaw-runtime/src/lib.rs index 16de32c..bc6eedd 100644 --- a/crates/zclaw-runtime/src/lib.rs +++ b/crates/zclaw-runtime/src/lib.rs @@ -27,4 +27,5 @@ pub use loop_runner::{AgentLoop, AgentLoopResult, LoopEvent}; pub use loop_guard::{LoopGuard, LoopGuardConfig, LoopGuardResult}; pub use stream::{StreamEvent, StreamSender}; pub use growth::GrowthIntegration; +pub use zclaw_growth::VikingAdapter; pub use compaction::{CompactionConfig, CompactionOutcome};