fix(runtime,kernel): HandTool 空壳修复 — 桥接到 HandRegistry 真实执行
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
B-HAND-1 修复: LLM 调用 hand_quiz/hand_researcher 等 Hand 工具后,
HandTool::execute() 原来返回假成功 JSON, 实际 Hand 并不执行.
修复方案 (沿用 SkillExecutor 模式):
- tool.rs: 新增 HandExecutor trait + ToolContext.hand_executor 字段
- hand_tool.rs: execute() 通过 context.hand_executor 分发到真实执行
- loop_runner.rs: AgentLoop 新增 hand_executor 字段 + builder + 3处 ToolContext 传递
- adapters.rs: 新增 KernelHandExecutor 桥接 HandRegistry.execute()
- kernel/mod.rs: 初始化 KernelHandExecutor + 注册到 AgentLoop
- messaging.rs: 两处 AgentLoop 构建添加 .with_hand_executor()
数据流: LLM tool call → HandTool::execute() → ToolContext.hand_executor
→ KernelHandExecutor → HandRegistry.execute() → Hand trait impl
809 tests passed, 0 failed.
This commit is contained in:
@@ -139,6 +139,7 @@ mod tests {
|
||||
working_directory: None,
|
||||
session_id: None,
|
||||
skill_executor: None,
|
||||
hand_executor: None,
|
||||
path_validator,
|
||||
event_sender: None,
|
||||
};
|
||||
|
||||
@@ -162,6 +162,7 @@ mod tests {
|
||||
working_directory: None,
|
||||
session_id: None,
|
||||
skill_executor: None,
|
||||
hand_executor: None,
|
||||
path_validator,
|
||||
event_sender: None,
|
||||
}
|
||||
|
||||
@@ -78,21 +78,26 @@ impl Tool for HandTool {
|
||||
self.input_schema.clone()
|
||||
}
|
||||
|
||||
async fn execute(&self, input: Value, _context: &ToolContext) -> Result<Value> {
|
||||
// Hand execution is delegated to HandRegistry via the kernel's
|
||||
// hand execution path. This tool acts as the LLM-facing interface.
|
||||
// The actual execution is handled by the HandRegistry when the
|
||||
// kernel processes the tool call.
|
||||
|
||||
// For now, return a structured result that indicates the hand was invoked.
|
||||
// The kernel's hand execution layer will handle the actual execution
|
||||
// and emit HandStart/HandEnd events.
|
||||
Ok(json!({
|
||||
"hand_id": self.hand_id,
|
||||
"status": "invoked",
|
||||
"input": input,
|
||||
"message": format!("Hand '{}' invoked successfully", self.hand_id)
|
||||
}))
|
||||
async fn execute(&self, input: Value, context: &ToolContext) -> Result<Value> {
|
||||
// Delegate to the HandExecutor (bridged from HandRegistry via kernel).
|
||||
// If no hand_executor is available (e.g., standalone runtime without kernel),
|
||||
// return a descriptive error so the LLM knows the hand is unavailable.
|
||||
match &context.hand_executor {
|
||||
Some(executor) => {
|
||||
executor.execute_hand(&self.hand_id, &context.agent_id, input).await
|
||||
}
|
||||
None => {
|
||||
Ok(json!({
|
||||
"hand_id": self.hand_id,
|
||||
"status": "unavailable",
|
||||
"error": format!(
|
||||
"Hand '{}' cannot execute: no hand executor configured. \
|
||||
This usually means the kernel is not running or hands are not registered.",
|
||||
self.hand_id
|
||||
)
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,13 +135,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_hand_tool_execute() {
|
||||
async fn test_hand_tool_execute_no_executor() {
|
||||
let tool = HandTool::from_config("quiz", "Generate quizzes", None);
|
||||
let ctx = ToolContext {
|
||||
agent_id: zclaw_types::AgentId::new(),
|
||||
working_directory: None,
|
||||
session_id: None,
|
||||
skill_executor: None,
|
||||
hand_executor: None,
|
||||
path_validator: None,
|
||||
event_sender: None,
|
||||
};
|
||||
@@ -144,6 +150,6 @@ mod tests {
|
||||
assert!(result.is_ok());
|
||||
let val = result.unwrap();
|
||||
assert_eq!(val["hand_id"], "quiz");
|
||||
assert_eq!(val["status"], "invoked");
|
||||
assert_eq!(val["status"], "unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user