//! Chat smoke test — full lifecycle: send → stream → persist //! //! Uses MockLlmDriver to verify the complete chat pipeline without a real LLM. use std::sync::Arc; use zclaw_kernel::{Kernel, KernelConfig}; use zclaw_runtime::test_util::MockLlmDriver; use zclaw_runtime::{LoopEvent, LlmDriver}; use zclaw_types::AgentConfig; #[tokio::test] async fn smoke_chat_full_lifecycle() { let mock = MockLlmDriver::new().with_text_response("Hello! I am the mock assistant."); let config = KernelConfig::default(); let kernel = Kernel::boot_with_driver(config, Arc::new(mock) as Arc) .await .expect("kernel boot"); let agent = AgentConfig::new("smoke-agent") .with_system_prompt("You are a test assistant."); let id = agent.id; kernel.spawn_agent(agent).await.expect("spawn agent"); // 1. Non-streaming: send and get response let resp = kernel.send_message(&id, "Hello".to_string()).await.expect("send"); assert!(!resp.content.is_empty()); assert!(resp.output_tokens > 0); // 2. Streaming: send and collect all events let mut rx = kernel .send_message_stream(&id, "Tell me more".to_string()) .await .expect("stream"); let mut delta_count = 0; let mut complete_result = None; while let Some(event) = rx.recv().await { match event { LoopEvent::Delta(text) => { delta_count += 1; assert!(!text.is_empty(), "delta should have content"); } LoopEvent::Complete(result) => { complete_result = Some(result); break; } LoopEvent::Error(msg) => panic!("unexpected error: {}", msg), _ => {} } } assert!(delta_count > 0, "should receive at least one delta"); let result = complete_result.expect("should receive complete"); assert!(result.output_tokens > 0); // 3. Verify session persistence — messages were saved let agent_info = kernel.get_agent(&id).expect("agent should exist"); assert!(agent_info.message_count >= 2, "at least 2 messages should be tracked"); }