//! agent_switch_demo —— Agent 角色热切换示例。 //! Required features: cargo run --example agent_switch_demo --features "engine" //! //! 演示: //! 1. 创建 session(绑定 Analyst agent) //! 2. 提交一轮对话(角色 A 输出"分析数据") //! 3. switch_agent 切换为 Reporter agent //! 4. 提交第二轮对话(角色 B 基于已有上下文输出"报告") //! 5. 验证:turn_index 连续、session_memory 保留、slot 历史保留 //! //! 运行:`cargo run --example agent_switch_demo` use std::sync::Arc; use agcore::agent::{Agent, AgentBuilder}; use agcore::engine::SessionManager; use agcore::llm::hooks::HookExecutor; use agcore::llm::mock::MockProvider; use agcore::llm::types::Usage; use agcore::llm::types::message::{ContentBlock, Message}; use agcore::llm::types::response_v2::{MessageResponse, StopReason}; use agcore::memory::store::InMemoryStore; use agcore::tools::ToolRegistry; struct AnalystAgent; struct ReporterAgent; impl Agent for AnalystAgent { fn name(&self) -> &str { "analyst" } fn system_prompt(&self) -> Option<&str> { Some("You are a data analyst. Analyze the input concisely.") } } impl Agent for ReporterAgent { fn name(&self) -> &str { "reporter" } fn system_prompt(&self) -> Option<&str> { Some("You are a report writer. Write concise reports based on context.") } } fn assistant_text(text: &str) -> MessageResponse { MessageResponse { id: String::new(), model: String::new(), message: Message::Assistant { content: vec![ContentBlock::Text { text: text.into() }], }, usage: Usage::from_input_output(8, 4), stop_reason: StopReason::Stop, extra: Default::default(), } } #[tokio::main] async fn main() { println!("=== Agent Switch Demo ===\n"); // 1. 准备组件 let store: Arc = Arc::new(InMemoryStore::new()); let provider = Arc::new(MockProvider::new(vec![ assistant_text("Analyst: data analyzed (Q3 sales up 15%)"), assistant_text("Reporter: report drafted (3 paragraphs)"), ])); let bundle = Arc::new( AgentBuilder::new() .provider(provider) .tool_registry(Arc::new(ToolRegistry::new())) .hook_executor(Arc::new(HookExecutor::new())) .session_memory_backend(store.clone()) .build() .expect("RuntimeBundle 装配失败"), ); let analyst: Arc = Arc::new(AnalystAgent); let reporter: Arc = Arc::new(ReporterAgent); let sm = Arc::new(SessionManager::new(store)); let session_id = sm.create(analyst, bundle.clone()).await.expect("create"); println!("[1] session created: {session_id}"); // 2. Analyst 跑一轮 let resp1 = sm .submit_turn(&session_id, "Analyze Q3 sales data") .await .expect("submit_turn 1"); println!("[2] analyst turn 1: {:?}", resp1.text()); // 3. 切换到 Reporter sm.switch_agent(&session_id, reporter) .await .expect("switch_agent"); println!("[3] agent switched to 'reporter'"); // 4. Reporter 跑一轮(基于已有上下文) let resp2 = sm .submit_turn(&session_id, "Write a report based on the analysis") .await .expect("submit_turn 2"); println!("[4] reporter turn 2: {:?}", resp2.text()); // 5. 验证 turn_index 连续 let (turn_index, agent_name_owned) = { let session = sm.get(&session_id).await.unwrap(); let guard = session.lock().await; (guard.turn_index(), guard.agent.name().to_string()) }; println!("\n[verify] turn_index = {turn_index}, agent = {agent_name_owned}"); assert_eq!(turn_index, 2, "turn_index should be 2 after 2 turns"); assert_eq!( agent_name_owned, "reporter", "current agent should be reporter" ); println!("✓ context preserved across agent switch"); }