fix(growth,kernel,runtime,desktop): 50 轮功能链路审计 7 项断链修复
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
P0 修复: - B-MEM-2: 跨会话记忆丢失 — 添加 IdentityRecall 查询意图检测, 身份类查询绕过 FTS5/LIKE 文本搜索,直接按 scope 检索全部偏好+知识记忆; 缓存 GrowthIntegration 到 Kernel 避免每次请求重建空 scorer - B-HAND-1: Hands 未触发 — 创建 HandTool wrapper 实现 Tool trait, 在 create_tool_registry() 中注册所有已启用 Hands 为 LLM 可调用工具 P1 修复: - B-SCHED-4: 一次性定时未拦截 — 添加 RE_ONE_SHOT_TODAY 正则匹配 "下午3点半提醒我..."类无日期前缀的同日触发模式 - B-CHAT-2: 工具调用循环 — ToolErrorMiddleware 添加连续失败计数器, 3 次连续失败后自动 AbortLoop 防止无限重试 - B-CHAT-5: Stream 竞态 — cancelStream 后添加 500ms cancelCooldown, 防止后端 active-stream 检查竞态
This commit is contained in:
@@ -41,12 +41,16 @@ pub struct Kernel {
|
||||
skills: Arc<SkillRegistry>,
|
||||
skill_executor: Arc<KernelSkillExecutor>,
|
||||
hands: Arc<HandRegistry>,
|
||||
/// Cached hand configs (populated at boot, used for tool registry)
|
||||
hand_configs: Vec<zclaw_hands::HandConfig>,
|
||||
trigger_manager: crate::trigger_manager::TriggerManager,
|
||||
pending_approvals: Arc<Mutex<Vec<ApprovalEntry>>>,
|
||||
/// Running hand runs that can be cancelled (run_id -> cancelled flag)
|
||||
running_hand_runs: Arc<dashmap::DashMap<zclaw_types::HandRunId, Arc<std::sync::atomic::AtomicBool>>>,
|
||||
/// Shared memory storage backend for Growth system
|
||||
viking: Arc<zclaw_runtime::VikingAdapter>,
|
||||
/// Cached GrowthIntegration — avoids recreating empty scorer per request
|
||||
growth: std::sync::Mutex<Option<std::sync::Arc<zclaw_runtime::GrowthIntegration>>>,
|
||||
/// Optional LLM driver for memory extraction (set by Tauri desktop layer)
|
||||
extraction_driver: Option<Arc<dyn zclaw_runtime::LlmDriverForExtraction>>,
|
||||
/// MCP tool adapters — shared with Tauri MCP manager, updated dynamically
|
||||
@@ -95,6 +99,9 @@ impl Kernel {
|
||||
hands.register(Arc::new(TwitterHand::new())).await;
|
||||
hands.register(Arc::new(ReminderHand::new())).await;
|
||||
|
||||
// Cache hand configs for tool registry (sync access from create_tool_registry)
|
||||
let hand_configs = hands.list().await;
|
||||
|
||||
// Create skill executor
|
||||
let skill_executor = Arc::new(KernelSkillExecutor::new(skills.clone(), driver.clone()));
|
||||
|
||||
@@ -146,10 +153,12 @@ impl Kernel {
|
||||
skills,
|
||||
skill_executor,
|
||||
hands,
|
||||
hand_configs,
|
||||
trigger_manager,
|
||||
pending_approvals: Arc::new(Mutex::new(Vec::new())),
|
||||
running_hand_runs: Arc::new(dashmap::DashMap::new()),
|
||||
viking,
|
||||
growth: std::sync::Mutex::new(None),
|
||||
extraction_driver: None,
|
||||
mcp_adapters: Arc::new(std::sync::RwLock::new(Vec::new())),
|
||||
industry_keywords: Arc::new(tokio::sync::RwLock::new(Vec::new())),
|
||||
@@ -158,7 +167,7 @@ impl Kernel {
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a tool registry with built-in tools + MCP tools.
|
||||
/// Create a tool registry with built-in tools + Hand tools + MCP tools.
|
||||
/// When `subagent_enabled` is false, TaskTool is excluded to prevent
|
||||
/// the LLM from attempting sub-agent delegation in non-Ultra modes.
|
||||
pub(crate) fn create_tool_registry(&self, subagent_enabled: bool) -> ToolRegistry {
|
||||
@@ -175,6 +184,20 @@ impl Kernel {
|
||||
tools.register(Box::new(task_tool));
|
||||
}
|
||||
|
||||
// Register Hand tools — expose registered Hands as LLM-callable tools
|
||||
// (e.g., hand_quiz, hand_researcher, hand_browser, etc.)
|
||||
for config in &self.hand_configs {
|
||||
if !config.enabled {
|
||||
continue;
|
||||
}
|
||||
let tool = zclaw_runtime::tool::hand_tool::HandTool::from_config(
|
||||
&config.id,
|
||||
&config.description,
|
||||
config.input_schema.clone(),
|
||||
);
|
||||
tools.register(Box::new(tool));
|
||||
}
|
||||
|
||||
// Register MCP tools (dynamically updated by Tauri MCP manager)
|
||||
if let Ok(adapters) = self.mcp_adapters.read() {
|
||||
for adapter in adapters.iter() {
|
||||
@@ -249,11 +272,18 @@ impl Kernel {
|
||||
chain.register(Arc::new(mw));
|
||||
}
|
||||
|
||||
// Growth integration — shared VikingAdapter for memory middleware & compaction
|
||||
let mut growth = zclaw_runtime::GrowthIntegration::new(self.viking.clone());
|
||||
if let Some(ref driver) = self.extraction_driver {
|
||||
growth = growth.with_llm_driver(driver.clone());
|
||||
}
|
||||
// Growth integration — cached to avoid recreating empty scorer per request
|
||||
let growth = {
|
||||
let mut cached = self.growth.lock().expect("growth lock");
|
||||
if cached.is_none() {
|
||||
let mut g = zclaw_runtime::GrowthIntegration::new(self.viking.clone());
|
||||
if let Some(ref driver) = self.extraction_driver {
|
||||
g = g.with_llm_driver(driver.clone());
|
||||
}
|
||||
*cached = Some(std::sync::Arc::new(g));
|
||||
}
|
||||
cached.as_ref().expect("growth present").clone()
|
||||
};
|
||||
|
||||
// Evolution middleware — pushes evolution candidate skills into system prompt
|
||||
// priority=78, executed first by chain (before ButlerRouter@80)
|
||||
@@ -282,7 +312,7 @@ impl Kernel {
|
||||
// Memory middleware — auto-extract memories + check evolution after conversations
|
||||
{
|
||||
use std::sync::Arc;
|
||||
let mw = zclaw_runtime::middleware::memory::MemoryMiddleware::new(growth)
|
||||
let mw = zclaw_runtime::middleware::memory::MemoryMiddleware::new(growth.clone())
|
||||
.with_evolution(evolution_mw);
|
||||
chain.register(Arc::new(mw));
|
||||
}
|
||||
@@ -415,6 +445,10 @@ impl Kernel {
|
||||
pub fn set_viking(&mut self, viking: Arc<zclaw_runtime::VikingAdapter>) {
|
||||
tracing::info!("[Kernel] Replacing in-memory VikingAdapter with persistent storage");
|
||||
self.viking = viking;
|
||||
// Invalidate cached GrowthIntegration so next request builds with new storage
|
||||
if let Ok(mut g) = self.growth.lock() {
|
||||
*g = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the shared VikingAdapter
|
||||
@@ -429,6 +463,10 @@ impl Kernel {
|
||||
pub fn set_extraction_driver(&mut self, driver: Arc<dyn zclaw_runtime::LlmDriverForExtraction>) {
|
||||
tracing::info!("[Kernel] Extraction driver configured for Growth system");
|
||||
self.extraction_driver = Some(driver);
|
||||
// Invalidate cached GrowthIntegration so next request uses new driver
|
||||
if let Ok(mut g) = self.growth.lock() {
|
||||
*g = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the shared MCP adapters list.
|
||||
|
||||
Reference in New Issue
Block a user