fix(audit): 修复深度审计发现的 P0/P1 问题 (8项)
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
基于 DEEP_AUDIT_REPORT.md 修复 2 CRITICAL + 4 HIGH + 1 MEDIUM 问题: - C1: PromptOnly 技能集成 LLM 调用 — 定义 LlmCompleter trait, 通过 LlmDriverAdapter 桥接 zclaw_runtime::LlmDriver, PromptOnlySkill.execute() 现在调用 LLM 生成内容 - C2: 反思引擎空记忆 bug — 新增 query_memories_for_reflection() 从 VikingStorage 查询真实记忆传入 reflect() - H7: Agent Store 接口适配 — KernelClient 添加 listClones/createClone/ deleteClone/updateClone 方法,映射到 agent_* 命令 - H8: Hand 审批检查 — hand_execute 执行前检查 needs_approval, 需审批返回 pending_approval 状态 - M1: 幽灵命令注册 — 注册 hand_get/hand_run_status/hand_run_list 三个 Tauri 桩命令 - H1/H2: SpeechHand/TwitterHand 添加 demo 标签 - H5: 归档过时 VERIFICATION_REPORT 文档更新: DEEP_AUDIT_REPORT.md 标记修复状态,README.md 更新 关键指标和变更历史。整体完成度从 ~50% 提升至 ~58%。
This commit is contained in:
@@ -9,7 +9,7 @@ use tracing::debug;
|
||||
|
||||
use crate::intelligence::identity::IdentityManagerState;
|
||||
use crate::intelligence::heartbeat::HeartbeatEngineState;
|
||||
use crate::intelligence::reflection::ReflectionEngineState;
|
||||
use crate::intelligence::reflection::{MemoryEntryForAnalysis, ReflectionEngineState};
|
||||
|
||||
/// Run pre-conversation intelligence hooks
|
||||
///
|
||||
@@ -40,6 +40,7 @@ pub async fn pre_conversation_hook(
|
||||
/// 2. Record conversation for reflection engine, trigger reflection if needed
|
||||
pub async fn post_conversation_hook(
|
||||
agent_id: &str,
|
||||
_user_message: &str,
|
||||
_heartbeat_state: &HeartbeatEngineState,
|
||||
reflection_state: &ReflectionEngineState,
|
||||
) {
|
||||
@@ -48,7 +49,6 @@ pub async fn post_conversation_hook(
|
||||
debug!("[intelligence_hooks] Recorded interaction for agent: {}", agent_id);
|
||||
|
||||
// Step 2: Record conversation for reflection
|
||||
// tokio::sync::Mutex::lock() returns MutexGuard directly (panics on poison)
|
||||
let mut engine = reflection_state.lock().await;
|
||||
|
||||
engine.record_conversation();
|
||||
@@ -62,7 +62,17 @@ pub async fn post_conversation_hook(
|
||||
"[intelligence_hooks] Reflection threshold reached for agent: {}",
|
||||
agent_id
|
||||
);
|
||||
let reflection_result = engine.reflect(agent_id, &[]);
|
||||
|
||||
// Query actual memories from VikingStorage for reflection analysis
|
||||
let memories = query_memories_for_reflection(agent_id).await
|
||||
.unwrap_or_default();
|
||||
|
||||
debug!(
|
||||
"[intelligence_hooks] Fetched {} memories for reflection",
|
||||
memories.len()
|
||||
);
|
||||
|
||||
let reflection_result = engine.reflect(agent_id, &memories);
|
||||
debug!(
|
||||
"[intelligence_hooks] Reflection completed: {} patterns, {} suggestions",
|
||||
reflection_result.patterns.len(),
|
||||
@@ -151,3 +161,38 @@ async fn build_identity_prompt(
|
||||
|
||||
Ok(prompt)
|
||||
}
|
||||
|
||||
/// Query agent memories from VikingStorage and convert to MemoryEntryForAnalysis
|
||||
/// for the reflection engine.
|
||||
///
|
||||
/// Fetches up to 50 recent memories scoped to the given agent, without token
|
||||
/// truncation (unlike build_memory_context which is size-limited for prompts).
|
||||
async fn query_memories_for_reflection(
|
||||
agent_id: &str,
|
||||
) -> Result<Vec<MemoryEntryForAnalysis>, String> {
|
||||
let storage = crate::viking_commands::get_storage().await?;
|
||||
|
||||
let options = zclaw_growth::FindOptions {
|
||||
scope: Some(format!("agent://{}", agent_id)),
|
||||
limit: Some(50),
|
||||
min_similarity: Some(0.0), // Fetch all, no similarity filter
|
||||
};
|
||||
|
||||
let results: Vec<zclaw_growth::MemoryEntry> =
|
||||
zclaw_growth::VikingStorage::find(storage.as_ref(), "", options)
|
||||
.await
|
||||
.map_err(|e| format!("Memory query for reflection failed: {}", e))?;
|
||||
|
||||
let memories: Vec<MemoryEntryForAnalysis> = results
|
||||
.into_iter()
|
||||
.map(|entry| MemoryEntryForAnalysis {
|
||||
memory_type: entry.memory_type.to_string(),
|
||||
content: entry.content,
|
||||
importance: entry.importance as usize,
|
||||
access_count: entry.access_count as usize,
|
||||
tags: entry.keywords,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(memories)
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ pub async fn agent_chat_stream(
|
||||
// Start the stream - this spawns a background task
|
||||
// Use intelligence-enhanced system prompt if available
|
||||
let prompt_arg = if enhanced_prompt.is_empty() { None } else { Some(enhanced_prompt) };
|
||||
kernel.send_message_stream_with_prompt(&id, message, prompt_arg)
|
||||
kernel.send_message_stream_with_prompt(&id, message.clone(), prompt_arg)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to start streaming: {}", e))?
|
||||
};
|
||||
@@ -492,7 +492,7 @@ pub async fn agent_chat_stream(
|
||||
|
||||
// POST-CONVERSATION: record interaction + trigger reflection
|
||||
crate::intelligence_hooks::post_conversation_hook(
|
||||
&agent_id_str, &hb_state, &rf_state,
|
||||
&agent_id_str, &message, &hb_state, &rf_state,
|
||||
).await;
|
||||
|
||||
StreamChatEvent::Complete {
|
||||
@@ -632,6 +632,7 @@ impl From<SkillContext> for zclaw_skills::SkillContext {
|
||||
timeout_secs: 300,
|
||||
network_allowed: true,
|
||||
file_access_allowed: true,
|
||||
llm: None, // Injected by Kernel.execute_skill()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -800,7 +801,8 @@ pub async fn hand_list(
|
||||
/// Execute a hand
|
||||
///
|
||||
/// Executes a hand with the given ID and input.
|
||||
/// Returns the hand result as JSON.
|
||||
/// If the hand has `needs_approval = true`, creates a pending approval instead.
|
||||
/// Returns the hand result as JSON, or a pending status with approval ID.
|
||||
#[tauri::command]
|
||||
pub async fn hand_execute(
|
||||
state: State<'_, KernelState>,
|
||||
@@ -812,7 +814,26 @@ pub async fn hand_execute(
|
||||
let kernel = kernel_lock.as_ref()
|
||||
.ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?;
|
||||
|
||||
// Execute hand
|
||||
// Check if hand requires approval before execution
|
||||
let hands = kernel.list_hands().await;
|
||||
if let Some(hand_config) = hands.iter().find(|h| h.id == id) {
|
||||
if hand_config.needs_approval {
|
||||
let approval = kernel.create_approval(id.clone(), input).await;
|
||||
return Ok(HandResult {
|
||||
success: false,
|
||||
output: serde_json::json!({
|
||||
"status": "pending_approval",
|
||||
"approval_id": approval.id,
|
||||
"hand_id": approval.hand_id,
|
||||
"message": "This hand requires approval before execution"
|
||||
}),
|
||||
error: None,
|
||||
duration_ms: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Execute hand directly
|
||||
let result = kernel.execute_hand(&id, input).await
|
||||
.map_err(|e| format!("Failed to execute hand: {}", e))?;
|
||||
|
||||
@@ -1139,6 +1160,63 @@ pub async fn hand_cancel(
|
||||
Ok(serde_json::json!({ "status": "cancelled" }))
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Hand Stub Commands (not yet fully implemented)
|
||||
// ============================================================
|
||||
|
||||
/// Get detailed info for a single hand
|
||||
#[tauri::command]
|
||||
pub async fn hand_get(
|
||||
state: State<'_, KernelState>,
|
||||
name: String,
|
||||
) -> Result<serde_json::Value, String> {
|
||||
let kernel_lock = state.lock().await;
|
||||
let kernel = kernel_lock.as_ref()
|
||||
.ok_or_else(|| "Kernel not initialized".to_string())?;
|
||||
|
||||
let hands = kernel.list_hands().await;
|
||||
let found = hands.iter().find(|h| h.id == name)
|
||||
.ok_or_else(|| format!("Hand '{}' not found", name))?;
|
||||
|
||||
Ok(serde_json::to_value(found)
|
||||
.map_err(|e| format!("Serialization error: {}", e))?)
|
||||
}
|
||||
|
||||
/// Get status of a specific hand run
|
||||
#[tauri::command]
|
||||
pub async fn hand_run_status(
|
||||
_state: State<'_, KernelState>,
|
||||
hand_name: String,
|
||||
run_id: String,
|
||||
) -> Result<serde_json::Value, String> {
|
||||
// Hand run tracking not yet implemented — return not-found status
|
||||
Ok(serde_json::json!({
|
||||
"status": "not_found",
|
||||
"hand_name": hand_name,
|
||||
"run_id": run_id,
|
||||
"message": "Hand run history tracking is not yet implemented"
|
||||
}))
|
||||
}
|
||||
|
||||
/// List run history for a hand
|
||||
#[tauri::command]
|
||||
pub async fn hand_run_list(
|
||||
_state: State<'_, KernelState>,
|
||||
hand_name: String,
|
||||
limit: Option<u32>,
|
||||
offset: Option<u32>,
|
||||
) -> Result<serde_json::Value, String> {
|
||||
// Hand run history not yet implemented — return empty list
|
||||
Ok(serde_json::json!({
|
||||
"runs": [],
|
||||
"hand_name": hand_name,
|
||||
"total": 0,
|
||||
"limit": limit.unwrap_or(20),
|
||||
"offset": offset.unwrap_or(0),
|
||||
"message": "Hand run history tracking is not yet implemented"
|
||||
}))
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Scheduled Task Commands
|
||||
// ============================================================
|
||||
|
||||
@@ -1341,6 +1341,9 @@ pub fn run() {
|
||||
kernel_commands::hand_execute,
|
||||
kernel_commands::hand_approve,
|
||||
kernel_commands::hand_cancel,
|
||||
kernel_commands::hand_get,
|
||||
kernel_commands::hand_run_status,
|
||||
kernel_commands::hand_run_list,
|
||||
// Scheduled task commands
|
||||
kernel_commands::scheduled_task_create,
|
||||
kernel_commands::scheduled_task_list,
|
||||
|
||||
Reference in New Issue
Block a user