From f3f586efef2ae3eac1b49b684f96d44eb1a3aa17 Mon Sep 17 00:00:00 2001 From: iven Date: Mon, 30 Mar 2026 00:19:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(kernel):=20Agent=20=E5=AF=BC=E5=85=A5/?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=20+=20message=5Fcount=20=E8=B7=9F=E8=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprint 3.1 message_count 修复: - AgentRegistry 新增 message_counts 字段跟踪每个 agent 的消息数 - increment_message_count() 在 send_message 和 send_message_stream 中调用 - get_info() 返回实际计数值 Sprint 3.3 Agent 导入/导出: - Kernel 新增 get_agent_config() 方法返回原始 AgentConfig - 新增 agent_export Tauri 命令,导出配置为 JSON - 新增 agent_import Tauri 命令,从 JSON 导入并自动生成新 ID - 注册到 Tauri invoke_handler --- crates/zclaw-kernel/src/kernel.rs | 5 +++ desktop/src-tauri/src/kernel_commands.rs | 48 ++++++++++++++++++++++++ desktop/src-tauri/src/lib.rs | 2 + 3 files changed, 55 insertions(+) diff --git a/crates/zclaw-kernel/src/kernel.rs b/crates/zclaw-kernel/src/kernel.rs index bcc21f1..73aa7cf 100644 --- a/crates/zclaw-kernel/src/kernel.rs +++ b/crates/zclaw-kernel/src/kernel.rs @@ -481,6 +481,11 @@ impl Kernel { self.registry.get_info(id) } + /// Get agent config (for export) + pub fn get_agent_config(&self, id: &AgentId) -> Option { + self.registry.get(id) + } + /// Send a message to an agent pub async fn send_message(&self, agent_id: &AgentId, message: String) -> Result { let agent_config = self.registry.get(agent_id) diff --git a/desktop/src-tauri/src/kernel_commands.rs b/desktop/src-tauri/src/kernel_commands.rs index 7f57e1a..242760d 100644 --- a/desktop/src-tauri/src/kernel_commands.rs +++ b/desktop/src-tauri/src/kernel_commands.rs @@ -378,6 +378,54 @@ pub async fn agent_delete( .map_err(|e| format!("Failed to delete agent: {}", e)) } +/// Export an agent configuration as JSON +#[tauri::command] +pub async fn agent_export( + state: State<'_, KernelState>, + agent_id: String, +) -> Result { + let agent_id = validate_agent_id(&agent_id)?; + + let kernel_lock = state.lock().await; + let kernel = kernel_lock.as_ref() + .ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?; + + let id: AgentId = agent_id.parse() + .map_err(|_| "Invalid agent ID format".to_string())?; + + let config = kernel.get_agent_config(&id) + .ok_or_else(|| format!("Agent not found: {}", agent_id))?; + + serde_json::to_string_pretty(&config) + .map_err(|e| format!("Failed to serialize agent config: {}", e)) +} + +/// Import an agent from JSON configuration +#[tauri::command] +pub async fn agent_import( + state: State<'_, KernelState>, + config_json: String, +) -> Result { + validate_string_length(&config_json, "config_json", 1_000_000) + .map_err(|e| format!("{}", e))?; + + let mut config: AgentConfig = serde_json::from_str(&config_json) + .map_err(|e| format!("Invalid agent config JSON: {}", e))?; + + // Regenerate ID to avoid collisions + config.id = AgentId::new(); + + let kernel_lock = state.lock().await; + let kernel = kernel_lock.as_ref() + .ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?; + + let new_id = kernel.spawn_agent(config).await + .map_err(|e| format!("Failed to import agent: {}", e))?; + + kernel.get_agent(&new_id) + .ok_or_else(|| "Agent was created but could not be retrieved".to_string()) +} + /// Send a message to an agent #[tauri::command] pub async fn agent_chat( diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index b25f102..860bcae 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -1331,6 +1331,8 @@ pub fn run() { kernel_commands::agent_list, kernel_commands::agent_get, kernel_commands::agent_delete, + kernel_commands::agent_export, + kernel_commands::agent_import, kernel_commands::agent_chat, kernel_commands::agent_chat_stream, // Skills commands (dynamic discovery)