test(kernel,growth): Phase 1 缝测试安全网 — 3条核心链路 19 测试全部通过
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
对话链路: 4 缝测试 (Tauri→Kernel / Kernel→LLM / LLM→UI / 流式生命周期) Hands链路: 3 缝测试 (工具路由 / 执行回调 / 通用工具) 记忆链路: 3 缝测试 (FTS5存储 / 模式检索 / 去重) 冒烟测试: 3 Rust + 8 TypeScript 全量 PASS - Kernel::boot_with_driver() 测试辅助方法 - 全量 cargo test 0 回归 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
93
crates/zclaw-kernel/tests/smoke_hands.rs
Normal file
93
crates/zclaw-kernel/tests/smoke_hands.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
//! Hands smoke test — full lifecycle: trigger tool_call → hand execute → result
|
||||
//!
|
||||
//! Uses MockLlmDriver with stream chunks to simulate a real tool call flow.
|
||||
|
||||
use std::sync::Arc;
|
||||
use zclaw_kernel::{Kernel, KernelConfig};
|
||||
use zclaw_runtime::stream::StreamChunk;
|
||||
use zclaw_runtime::test_util::MockLlmDriver;
|
||||
use zclaw_runtime::{LoopEvent, LlmDriver};
|
||||
use zclaw_types::AgentConfig;
|
||||
|
||||
#[tokio::test]
|
||||
async fn smoke_hands_full_lifecycle() {
|
||||
// Simulate: LLM calls hand_quiz → quiz hand executes → LLM summarizes
|
||||
let mock = MockLlmDriver::new()
|
||||
.with_stream_chunks(vec![
|
||||
StreamChunk::TextDelta { delta: "正在生成测验...".to_string() },
|
||||
StreamChunk::ToolUseStart {
|
||||
id: "call_1".to_string(),
|
||||
name: "hand_quiz".to_string(),
|
||||
},
|
||||
StreamChunk::ToolUseEnd {
|
||||
id: "call_1".to_string(),
|
||||
input: serde_json::json!({ "topic": "历史", "count": 2 }),
|
||||
},
|
||||
StreamChunk::Complete {
|
||||
input_tokens: 15,
|
||||
output_tokens: 10,
|
||||
stop_reason: "tool_use".to_string(),
|
||||
},
|
||||
])
|
||||
// After hand_quiz returns, LLM generates final response
|
||||
.with_stream_chunks(vec![
|
||||
StreamChunk::TextDelta { delta: "测验已生成!".to_string() },
|
||||
StreamChunk::Complete {
|
||||
input_tokens: 20,
|
||||
output_tokens: 5,
|
||||
stop_reason: "end_turn".to_string(),
|
||||
},
|
||||
]);
|
||||
|
||||
let config = KernelConfig::default();
|
||||
let kernel = Kernel::boot_with_driver(config, Arc::new(mock) as Arc<dyn LlmDriver>)
|
||||
.await
|
||||
.expect("kernel boot");
|
||||
|
||||
let agent = AgentConfig::new("smoke-agent");
|
||||
let id = agent.id;
|
||||
kernel.spawn_agent(agent).await.expect("spawn agent");
|
||||
|
||||
let mut rx = kernel
|
||||
.send_message_stream(&id, "生成一个历史测验".to_string())
|
||||
.await
|
||||
.expect("stream");
|
||||
|
||||
let mut saw_tool_start = false;
|
||||
let mut saw_tool_end = false;
|
||||
let mut saw_delta_before_tool = false;
|
||||
let mut saw_delta_after_tool = false;
|
||||
let mut phase = "before_tool";
|
||||
let mut got_complete = false;
|
||||
|
||||
while let Some(event) = rx.recv().await {
|
||||
match event {
|
||||
LoopEvent::Delta(_) if phase == "before_tool" => saw_delta_before_tool = true,
|
||||
LoopEvent::Delta(_) if phase == "after_tool" => saw_delta_after_tool = true,
|
||||
LoopEvent::ToolStart { name, .. } => {
|
||||
assert_eq!(name, "hand_quiz", "should be hand_quiz");
|
||||
saw_tool_start = true;
|
||||
}
|
||||
LoopEvent::ToolEnd { name, output } => {
|
||||
assert!(name.starts_with("hand_"), "should be hand tool");
|
||||
assert!(output.is_object() || output.is_string(), "hand should produce output");
|
||||
saw_tool_end = true;
|
||||
phase = "after_tool";
|
||||
}
|
||||
LoopEvent::Complete(result) => {
|
||||
assert!(result.output_tokens > 0, "should have output tokens");
|
||||
assert!(result.iterations >= 2, "should take at least 2 iterations");
|
||||
got_complete = true;
|
||||
break;
|
||||
}
|
||||
LoopEvent::Error(msg) => panic!("unexpected error: {}", msg),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
assert!(saw_delta_before_tool, "should see delta before tool execution");
|
||||
assert!(saw_tool_start, "should see hand_quiz ToolStart");
|
||||
assert!(saw_tool_end, "should see hand_quiz ToolEnd");
|
||||
assert!(saw_delta_after_tool, "should see delta after tool execution");
|
||||
assert!(got_complete, "should receive complete event");
|
||||
}
|
||||
Reference in New Issue
Block a user