Skip to main content

sh_layer2/
agent_runtime.rs

1//! # Agent Runtime
2//!
3//! Agent 执行运行时实现。
4//!
5//! 支持真实 LLM API 调用(Anthropic/OpenAI/Gemini)。
6//! 集成任务规划器和执行监控器,支持复杂任务分解和自我纠错。
7
8use async_trait::async_trait;
9use std::sync::atomic::{AtomicBool, Ordering};
10use std::sync::Arc;
11use tracing::{debug, info, warn};
12
13use crate::execution_monitor::{CorrectionStrategy, ExecutionMonitor};
14use crate::permission::types::{PermissionAction, PermissionRequest};
15use crate::permission::PermissionManager;
16use crate::planner::{DecompositionStrategy, ExecutionPlan, TaskDecomposer};
17use crate::session_manager::{ConcurrentSessionManager, SessionConfig, SessionManagerTrait};
18use crate::tool_registry::{ToolRegistry, ToolRegistryTrait};
19use crate::types::{
20    AgentId, AgentState, Layer2Error, Layer2Result, Message, MessageRole, SessionId, ToolCall,
21    ToolResult,
22};
23
24/// Agent 执行结果
25#[derive(Debug, Clone)]
26pub struct AgentResult {
27    pub session_id: SessionId,
28    pub final_state: AgentState,
29    pub messages: Vec<Message>,
30    pub tool_calls: Vec<ToolCall>,
31    pub tool_results: Vec<ToolResult>,
32    pub iterations: i32,
33    pub tokens_used: i64,
34}
35
36/// Agent 配置
37#[derive(Debug, Clone)]
38pub struct AgentConfig {
39    pub agent_id: AgentId,
40    pub model: String,
41    pub temperature: f32,
42    pub max_iterations: i32,
43    pub system_prompt: Option<String>,
44}
45
46impl Default for AgentConfig {
47    fn default() -> Self {
48        Self {
49            agent_id: AgentId::new(),
50            model: "claude-sonnet-4-6".to_string(),
51            temperature: 0.7,
52            max_iterations: 100,
53            system_prompt: None,
54        }
55    }
56}
57
58impl From<&AgentConfig> for SessionConfig {
59    fn from(config: &AgentConfig) -> Self {
60        SessionConfig {
61            model: config.model.clone(),
62            temperature: config.temperature,
63            max_iterations: config.max_iterations,
64            system_prompt: config.system_prompt.clone(),
65            ..Default::default()
66        }
67    }
68}
69
70/// Agent 运行时接口
71///
72/// 定义 Agent 执行的核心生命周期操作。
73#[async_trait]
74pub trait AgentRuntimeTrait: Send + Sync {
75    /// 启动 Agent 执行
76    ///
77    /// # Arguments
78    /// * `task` - 用户任务描述
79    /// * `config` - Agent 配置
80    ///
81    /// # Returns
82    /// 执行结果,包含最终状态和输出
83    async fn run(&self, task: &str, config: AgentConfig) -> Layer2Result<AgentResult>;
84
85    /// 流式启动 Agent 执行
86    async fn run_stream(
87        &self,
88        task: &str,
89        config: AgentConfig,
90        callback: &dyn AgentLoopCallback,
91    ) -> Layer2Result<AgentResult>;
92
93    /// 流式启动 Agent 执行(支持中断)
94    async fn run_stream_abortable(
95        &self,
96        task: &str,
97        config: AgentConfig,
98        callback: &dyn AgentLoopCallback,
99        abort_flag: Arc<AtomicBool>,
100    ) -> Layer2Result<AgentResult>;
101
102    /// 启动 Agent 并返回会话 ID(用于流式执行)
103    ///
104    /// # Arguments
105    /// * `task` - 用户任务描述
106    /// * `config` - Agent 配置
107    ///
108    /// # Returns
109    /// 会话 ID,用于后续操作
110    async fn start(&self, task: &str, config: AgentConfig) -> Layer2Result<SessionId>;
111
112    /// 暂停正在执行的 Agent
113    ///
114    /// # Arguments
115    /// * `session_id` - 会话 ID
116    async fn pause(&self, session_id: &SessionId) -> Layer2Result<()>;
117
118    /// 恢复暂停的 Agent
119    ///
120    /// # Arguments
121    /// * `session_id` - 会话 ID
122    async fn resume(&self, session_id: &SessionId) -> Layer2Result<()>;
123
124    /// 停止 Agent 执行
125    ///
126    /// # Arguments
127    /// * `session_id` - 会话 ID
128    async fn stop(&self, session_id: &SessionId) -> Layer2Result<()>;
129
130    /// 获取 Agent 当前状态
131    ///
132    /// # Arguments
133    /// * `session_id` - 会话 ID
134    fn status(&self, session_id: &SessionId) -> Layer2Result<AgentState>;
135
136    /// 向 Agent 发送消息
137    ///
138    /// # Arguments
139    /// * `session_id` - 会话 ID
140    /// * `message` - 消息内容
141    async fn send_message(&self, session_id: &SessionId, message: &str) -> Layer2Result<()>;
142
143    /// 获取 Agent 的工具调用结果
144    ///
145    /// # Arguments
146    /// * `session_id` - 会话 ID
147    /// * `tool_call_id` - 工具调用 ID
148    async fn submit_tool_result(
149        &self,
150        session_id: &SessionId,
151        tool_call_id: &str,
152        result: ToolResult,
153    ) -> Layer2Result<()>;
154}
155
156/// Agent 执行循环回调接口
157///
158/// 用于在执行过程中注入自定义逻辑。
159#[async_trait]
160pub trait AgentLoopCallback: Send + Sync {
161    /// 在每次迭代前调用
162    async fn before_iteration(&self, session_id: &SessionId, iteration: i32) -> Layer2Result<bool>;
163
164    /// 在每次迭代后调用
165    async fn after_iteration(
166        &self,
167        session_id: &SessionId,
168        iteration: i32,
169        result: &IterationResult,
170    ) -> Layer2Result<()>;
171
172    /// 在工具调用前调用
173    async fn before_tool_call(
174        &self,
175        session_id: &SessionId,
176        tool_call: &ToolCall,
177    ) -> Layer2Result<bool>;
178
179    /// 在工具调用后调用
180    async fn after_tool_call(
181        &self,
182        session_id: &SessionId,
183        tool_call: &ToolCall,
184        result: &ToolResult,
185    ) -> Layer2Result<()>;
186}
187
188/// 单次迭代结果
189#[derive(Debug, Clone)]
190pub struct IterationResult {
191    pub iteration: i32,
192    pub state: AgentState,
193    pub message: Option<Message>,
194    pub tool_calls: Vec<ToolCall>,
195    pub should_continue: bool,
196}
197
198/// 默认 Agent Runtime 实现
199///
200/// 使用 ConcurrentSessionManager 管理会话,ToolRegistry 执行工具。
201/// 支持完整的执行生命周期:start -> run/pause/resume/stop。
202/// 集成 TaskDecomposer 进行任务分解,ExecutionMonitor 进行执行监控和纠错。
203/// 支持真实 LLM API 调用(通过 Layer1 LlmClient)。
204pub struct AgentRuntime {
205    session_manager: Arc<ConcurrentSessionManager>,
206    tool_registry: Arc<ToolRegistry>,
207    permission_manager: Option<Arc<PermissionManager>>,
208    /// 任务分解器(可选)
209    task_decomposer: Option<TaskDecomposer>,
210    /// LLM 客户端(可选,用于真实 API 调用)
211    llm_client: Option<Arc<sh_layer1::LlmClient>>,
212}
213
214impl AgentRuntime {
215    /// 创建新的 AgentRuntime
216    pub fn new(
217        session_manager: Arc<ConcurrentSessionManager>,
218        tool_registry: Arc<ToolRegistry>,
219    ) -> Self {
220        Self {
221            session_manager,
222            tool_registry,
223            permission_manager: None,
224            task_decomposer: None,
225            llm_client: None,
226        }
227    }
228
229    /// 创建带权限管理的 AgentRuntime
230    pub fn with_permissions(
231        session_manager: Arc<ConcurrentSessionManager>,
232        tool_registry: Arc<ToolRegistry>,
233        permission_manager: Arc<PermissionManager>,
234    ) -> Self {
235        Self {
236            session_manager,
237            tool_registry,
238            permission_manager: Some(permission_manager),
239            task_decomposer: None,
240            llm_client: None,
241        }
242    }
243
244    /// 创建带任务分解器的 AgentRuntime
245    pub fn with_decomposer(
246        session_manager: Arc<ConcurrentSessionManager>,
247        tool_registry: Arc<ToolRegistry>,
248        strategy: DecompositionStrategy,
249    ) -> Self {
250        Self {
251            session_manager,
252            tool_registry,
253            permission_manager: None,
254            task_decomposer: Some(TaskDecomposer::new().with_strategy(strategy)),
255            llm_client: None,
256        }
257    }
258
259    /// 使用默认组件创建(带任务分解器)
260    pub fn with_defaults() -> Self {
261        Self {
262            session_manager: Arc::new(ConcurrentSessionManager::default_config()),
263            tool_registry: Arc::new(ToolRegistry::new()),
264            permission_manager: None,
265            task_decomposer: Some(TaskDecomposer::new()),
266            llm_client: None,
267        }
268    }
269
270    /// 创建带 LLM 客户端的 AgentRuntime
271    pub fn with_llm_client(
272        session_manager: Arc<ConcurrentSessionManager>,
273        tool_registry: Arc<ToolRegistry>,
274        llm_client: Arc<sh_layer1::LlmClient>,
275    ) -> Self {
276        Self {
277            session_manager,
278            tool_registry,
279            permission_manager: None,
280            task_decomposer: Some(TaskDecomposer::new()),
281            llm_client: Some(llm_client),
282        }
283    }
284
285    /// 设置权限管理器
286    pub fn set_permission_manager(&mut self, manager: Arc<PermissionManager>) {
287        self.permission_manager = Some(manager);
288    }
289
290    /// 设置任务分解策略
291    pub fn set_decomposition_strategy(&mut self, strategy: DecompositionStrategy) {
292        self.task_decomposer = Some(TaskDecomposer::new().with_strategy(strategy));
293    }
294
295    /// 设置 LLM 客户端
296    pub fn set_llm_client(&mut self, client: Arc<sh_layer1::LlmClient>) {
297        self.llm_client = Some(client);
298    }
299
300    /// 获取权限管理器引用
301    pub fn permission_manager(&self) -> Option<&Arc<PermissionManager>> {
302        self.permission_manager.as_ref()
303    }
304
305    /// 获取任务分解器引用
306    pub fn task_decomposer(&self) -> Option<&TaskDecomposer> {
307        self.task_decomposer.as_ref()
308    }
309
310    /// 获取 LLM 客户端引用
311    pub fn llm_client(&self) -> Option<&Arc<sh_layer1::LlmClient>> {
312        self.llm_client.as_ref()
313    }
314
315    /// 分解任务为执行计划
316    ///
317    /// 如果配置了任务分解器,将复杂任务分解为子任务序列。
318    /// 返回执行计划,包含子任务列表和执行顺序。
319    pub fn decompose_task(&self, task: &str) -> Layer2Result<Option<ExecutionPlan>> {
320        if let Some(decomposer) = &self.task_decomposer {
321            let plan = decomposer.decompose(task)?;
322            info!(
323                task = %task,
324                subtasks = plan.subtasks.len(),
325                strategy = ?plan.strategy,
326                risk = ?plan.risk_level,
327                "Task decomposed into execution plan"
328            );
329            Ok(Some(plan))
330        } else {
331            Ok(None)
332        }
333    }
334
335    /// 创建执行监控器
336    ///
337    /// 为给定的执行计划创建监控器,用于跟踪执行进度和处理错误。
338    pub fn create_monitor(&self, plan: ExecutionPlan) -> ExecutionMonitor {
339        ExecutionMonitor::new(plan)
340    }
341
342    /// 使用执行计划运行 Agent
343    ///
344    /// 先分解任务,然后按照执行计划的顺序依次执行子任务。
345    /// 使用执行监控器跟踪进度和错误。
346    pub async fn run_with_plan(
347        &self,
348        task: &str,
349        config: AgentConfig,
350    ) -> Layer2Result<AgentResult> {
351        // 尝试分解任务
352        let plan_option = self.decompose_task(task)?;
353
354        // 如果有执行计划,按计划执行
355        if let Some(plan) = plan_option {
356            self.run_with_execution_plan(plan, config).await
357        } else {
358            // 没有分解器,直接运行
359            self.run(task, config).await
360        }
361    }
362
363    /// 按照执行计划运行 Agent
364    async fn run_with_execution_plan(
365        &self,
366        plan: ExecutionPlan,
367        config: AgentConfig,
368    ) -> Layer2Result<AgentResult> {
369        let monitor = self.create_monitor(plan.clone());
370        monitor.start().await?;
371
372        info!(
373            plan_id = %plan.id,
374            steps = plan.subtasks.len(),
375            "Starting planned execution"
376        );
377
378        // 执行各个子任务
379        let mut all_messages = Vec::new();
380        let mut all_tool_calls = Vec::new();
381        let mut all_tool_results = Vec::new();
382        let mut total_iterations = 0;
383        let mut total_tokens = 0i64;
384
385        for subtask_id in &plan.execution_order {
386            if let Some(subtask) = plan.subtasks.iter().find(|s| &s.id == subtask_id) {
387                // 检查依赖是否已完成(简化:假设拓扑排序保证依赖已执行)
388                // 拓扑排序确保依赖在当前任务之前执行
389
390                // 运行子任务
391                let subtask_result = self.run(&subtask.description, config.clone()).await;
392
393                match subtask_result {
394                    Ok(result) => {
395                        monitor
396                            .report_step_completed(subtask_id, result.final_state.to_string())
397                            .await?;
398                        all_messages.extend(result.messages);
399                        all_tool_calls.extend(result.tool_calls);
400                        all_tool_results.extend(result.tool_results);
401                        total_iterations += result.iterations;
402                        total_tokens += result.tokens_used;
403                    }
404                    Err(e) => {
405                        let error_msg = e.to_string();
406                        let decision = monitor
407                            .report_step_failed(subtask_id, error_msg.clone())
408                            .await?;
409
410                        // 根据纠错决策处理
411                        if decision.should_continue {
412                            match &decision.strategy {
413                                CorrectionStrategy::Retry { max_attempts } => {
414                                    // 简单重试逻辑
415                                    for attempt in 1..=*max_attempts {
416                                        warn!(
417                                            subtask_id = %subtask_id,
418                                            attempt = attempt,
419                                            max = max_attempts,
420                                            "Retrying subtask"
421                                        );
422                                        let retry_result =
423                                            self.run(&subtask.description, config.clone()).await;
424                                        if let Ok(result) = retry_result {
425                                            monitor
426                                                .report_step_completed(
427                                                    subtask_id,
428                                                    format!("Retry {} succeeded", attempt),
429                                                )
430                                                .await?;
431                                            all_messages.extend(result.messages);
432                                            all_tool_calls.extend(result.tool_calls);
433                                            all_tool_results.extend(result.tool_results);
434                                            total_iterations += result.iterations;
435                                            total_tokens += result.tokens_used;
436                                            break;
437                                        }
438                                    }
439                                }
440                                CorrectionStrategy::Skip => {
441                                    monitor
442                                        .report_step_completed(subtask_id, "[SKIPPED]".to_string())
443                                        .await?;
444                                }
445                                _ => {
446                                    // 其他策略暂时标记为完成
447                                    monitor
448                                        .report_step_completed(
449                                            subtask_id,
450                                            format!(
451                                                "[HANDLED] {}",
452                                                decision.strategy.clone().debug_name()
453                                            ),
454                                        )
455                                        .await?;
456                                }
457                            }
458                        } else {
459                            // 不能继续,返回错误
460                            return Err(e);
461                        }
462                    }
463                }
464            }
465        }
466
467        let summary = monitor.complete().await?;
468        info!(
469            plan_id = %plan.id,
470            completed = summary.completed_steps,
471            failed = summary.failed_steps,
472            corrections = summary.correction_count,
473            duration_ms = summary.duration.as_millis(),
474            "Planned execution completed"
475        );
476
477        Ok(AgentResult {
478            session_id: SessionId::new(),
479            final_state: if summary.failed_steps > 0 && summary.completed_steps == 0 {
480                AgentState::Error
481            } else {
482                AgentState::Completed
483            },
484            messages: all_messages,
485            tool_calls: all_tool_calls,
486            tool_results: all_tool_results,
487            iterations: total_iterations,
488            tokens_used: total_tokens,
489        })
490    }
491
492    /// 获取会话管理器引用
493    pub fn session_manager(&self) -> &Arc<ConcurrentSessionManager> {
494        &self.session_manager
495    }
496
497    /// 获取工具注册表引用
498    pub fn tool_registry(&self) -> &Arc<ToolRegistry> {
499        &self.tool_registry
500    }
501
502    /// 验证状态转换是否合法
503    fn validate_transition(current: AgentState, target: AgentState) -> Layer2Result<()> {
504        let valid = match (current, target) {
505            // Idle -> Running (start/resume)
506            (AgentState::Idle, AgentState::Running) => true,
507            // Running -> ToolCalling (tool call detected)
508            (AgentState::Running, AgentState::ToolCalling) => true,
509            // Running -> WaitingTool (waiting for tool result)
510            (AgentState::Running, AgentState::WaitingTool) => true,
511            // Running -> Completed (task finished)
512            (AgentState::Running, AgentState::Completed) => true,
513            // Running -> Stopped (manual stop)
514            (AgentState::Running, AgentState::Stopped) => true,
515            // Running -> Error
516            (AgentState::Running, AgentState::Error) => true,
517            // ToolCalling -> WaitingTool
518            (AgentState::ToolCalling, AgentState::WaitingTool) => true,
519            // ToolCalling -> Running (after tool result)
520            (AgentState::ToolCalling, AgentState::Running) => true,
521            // ToolCalling -> Error
522            (AgentState::ToolCalling, AgentState::Error) => true,
523            // WaitingTool -> Running (tool result submitted)
524            (AgentState::WaitingTool, AgentState::Running) => true,
525            // WaitingTool -> Stopped
526            (AgentState::WaitingTool, AgentState::Stopped) => true,
527            // WaitingTool -> Error
528            (AgentState::WaitingTool, AgentState::Error) => true,
529            // Stopped -> Running (resume)
530            (AgentState::Stopped, AgentState::Running) => true,
531            // Completed -> Idle (reuse session)
532            (AgentState::Completed, AgentState::Idle) => true,
533            // Same state is always valid (idempotent)
534            (_, _) if current == target => true,
535            _ => false,
536        };
537
538        if valid {
539            Ok(())
540        } else {
541            Err(Layer2Error::InvalidStateTransition {
542                from: current,
543                to: target,
544            }
545            .into())
546        }
547    }
548
549    /// 确保会话存在,否则返回 SessionNotFound 错误
550    async fn require_session(&self, session_id: &SessionId) -> Layer2Result<()> {
551        let session = self.session_manager.get(session_id).await?;
552        if session.is_some() {
553            Ok(())
554        } else {
555            Err(Layer2Error::SessionNotFound(session_id.clone()).into())
556        }
557    }
558
559    /// 执行一轮工具调用:将 pending 的 tool calls 全部执行,
560    /// 将结果写入 session 的 tool_results_cache,并清除 pending。
561    async fn execute_pending_tool_calls(&self, session_id: &SessionId) -> Layer2Result<()> {
562        // Collect pending tool calls from the session
563        let pending: Vec<ToolCall> = self
564            .session_manager
565            .read(session_id, |s| s.tool_calls_pending.clone())
566            .await?
567            .unwrap_or_default();
568
569        if pending.is_empty() {
570            return Ok(());
571        }
572
573        debug!(
574            session_id = %session_id,
575            count = pending.len(),
576            "Executing pending tool calls"
577        );
578
579        // Execute each tool call and collect results
580        let mut results = Vec::with_capacity(pending.len());
581        for tc in &pending {
582            // Check permission before executing tool
583            if let Some(pm) = &self.permission_manager {
584                let request = PermissionRequest::new(PermissionAction::Custom {
585                    description: format!("Execute tool: {} with args: {}", tc.name, tc.arguments),
586                });
587
588                match pm.check_permission(request) {
589                    Ok(response) => {
590                        if !response.decision.is_allowed() {
591                            warn!(
592                                tool = %tc.name,
593                                tool_call_id = %tc.id,
594                                "Tool execution denied by permission system"
595                            );
596                            results.push(ToolResult {
597                                tool_call_id: tc.id.clone(),
598                                name: tc.name.clone(),
599                                content: "Tool execution denied by permission system".to_string(),
600                                is_error: true,
601                            });
602                            continue;
603                        }
604                    }
605                    Err(e) => {
606                        warn!(
607                            tool = %tc.name,
608                            tool_call_id = %tc.id,
609                            error = %e,
610                            "Permission check failed"
611                        );
612                        results.push(ToolResult {
613                            tool_call_id: tc.id.clone(),
614                            name: tc.name.clone(),
615                            content: format!("Permission check failed: {}", e),
616                            is_error: true,
617                        });
618                        continue;
619                    }
620                }
621            }
622
623            let result = match self.tool_registry.execute(&tc.name, &tc.arguments).await {
624                Ok(tool_result) => tool_result,
625                Err(e) => {
626                    warn!(
627                        tool = %tc.name,
628                        tool_call_id = %tc.id,
629                        error = %e,
630                        "Tool execution failed"
631                    );
632                    ToolResult {
633                        tool_call_id: tc.id.clone(),
634                        name: tc.name.clone(),
635                        content: format!("Tool execution error: {}", e),
636                        is_error: true,
637                    }
638                }
639            };
640            results.push(result);
641        }
642
643        // Write results back to the session and clear pending
644        self.session_manager
645            .update(session_id, |s| {
646                s.tool_results_cache.extend(results);
647                s.tool_calls_pending.clear();
648            })
649            .await?;
650
651        Ok(())
652    }
653
654    /// 模拟 LLM 调用:生成一个简单的助手响应。
655    ///
656    /// 在真实的 Agent 循环中,这里会调用 LLM API 来获取下一步动作。
657    /// 当前实现作为本地模拟,根据任务文本和注册的工具产生响应。
658    async fn simulate_llm_step(
659        &self,
660        session_id: &SessionId,
661        task: &str,
662        iteration: i32,
663        max_iterations: i32,
664    ) -> Layer2Result<IterationResult> {
665        let tools = self.tool_registry.list();
666
667        // Check if there are pending tool results to process
668        let has_pending_results: bool = self
669            .session_manager
670            .read(session_id, |s| !s.tool_results_cache.is_empty())
671            .await?
672            .unwrap_or(false);
673
674        let should_continue = iteration < max_iterations;
675
676        // If we have pending tool results, process them and continue
677        if has_pending_results {
678            let tool_results: Vec<ToolResult> = self
679                .session_manager
680                .read(session_id, |s| s.tool_results_cache.clone())
681                .await?
682                .unwrap_or_default();
683
684            // Generate assistant response acknowledging tool results
685            let summary: Vec<String> = tool_results
686                .iter()
687                .map(|r| {
688                    if r.is_error {
689                        format!("Tool {} failed: {}", r.name, r.content)
690                    } else {
691                        format!("Tool {} succeeded: {}", r.name, r.content)
692                    }
693                })
694                .collect();
695
696            let response = if !should_continue {
697                format!(
698                    "I've processed the tool results. Task '{}' is now complete.\n{}",
699                    task,
700                    summary.join("\n")
701                )
702            } else {
703                format!(
704                    "Processing tool results, continuing...\n{}",
705                    summary.join("\n")
706                )
707            };
708
709            // Clear the tool results cache after processing
710            self.session_manager
711                .update(session_id, |s| {
712                    s.tool_results_cache.clear();
713                })
714                .await?;
715
716            return Ok(IterationResult {
717                iteration,
718                state: if should_continue {
719                    AgentState::Running
720                } else {
721                    AgentState::Completed
722                },
723                message: Some(Message::assistant(&response)),
724                tool_calls: Vec::new(),
725                should_continue,
726            });
727        }
728
729        // First iteration: acknowledge the task
730        if iteration == 1 {
731            let response = format!("Starting task: {}", task);
732            return Ok(IterationResult {
733                iteration,
734                state: AgentState::Running,
735                message: Some(Message::assistant(&response)),
736                tool_calls: Vec::new(),
737                should_continue: true,
738            });
739        }
740
741        // If there are registered tools, try to use them
742        if !tools.is_empty() && iteration <= 2 {
743            // Simulate a tool call on the second iteration
744            let tool_name = &tools[0];
745            let tool_call = ToolCall {
746                id: sh_layer1::generate_prefixed_id("tc"),
747                name: tool_name.clone(),
748                arguments: serde_json::json!({"task": task}).to_string(),
749            };
750
751            return Ok(IterationResult {
752                iteration,
753                state: AgentState::ToolCalling,
754                message: Some(Message::assistant(format!(
755                    "I'll use the {} tool to help with this task.",
756                    tool_name
757                ))),
758                tool_calls: vec![tool_call],
759                should_continue: true,
760            });
761        }
762
763        // Final iteration: complete the task
764        let response = format!("Task '{}' has been completed.", task);
765        Ok(IterationResult {
766            iteration,
767            state: AgentState::Completed,
768            message: Some(Message::assistant(&response)),
769            tool_calls: Vec::new(),
770            should_continue: false,
771        })
772    }
773
774    /// 真实 LLM 调用:使用 Layer1 LlmClient 发送流式请求。
775    ///
776    /// 当配置了 LLM 客户端时使用此方法,否则回退到 simulate_llm_step。
777    async fn real_llm_step(
778        &self,
779        session_id: &SessionId,
780        task: &str,
781        iteration: i32,
782        max_iterations: i32,
783        config: &AgentConfig,
784        abort_flag: Option<Arc<AtomicBool>>,
785    ) -> Layer2Result<IterationResult> {
786        use sh_layer1::{LlmClientTrait, LlmRequestConfig};
787
788        let llm_client = self
789            .llm_client
790            .as_ref()
791            .ok_or_else(|| anyhow::anyhow!("LLM client not configured"))?;
792
793        // Get session messages
794        let session_messages: Vec<Message> = self
795            .session_manager
796            .read(session_id, |s| s.messages.clone())
797            .await?
798            .unwrap_or_default();
799
800        // Convert to Layer1 messages
801        let mut llm_messages: Vec<sh_layer1::Message> = session_messages
802            .iter()
803            .map(|m| sh_layer1::Message {
804                role: match m.role {
805                    MessageRole::System => sh_layer1::MessageRole::System,
806                    MessageRole::User => sh_layer1::MessageRole::User,
807                    MessageRole::Assistant => sh_layer1::MessageRole::Assistant,
808                    MessageRole::Tool => sh_layer1::MessageRole::User, // Tool results as user
809                },
810                content: m.content.clone(),
811            })
812            .collect();
813
814        // Add current task if not already present
815        if iteration == 1 {
816            llm_messages.push(sh_layer1::Message {
817                role: sh_layer1::MessageRole::User,
818                content: task.to_string(),
819            });
820        }
821
822        // Build request config
823        let request_config = LlmRequestConfig {
824            model: config.model.clone(),
825            max_tokens: 4096,
826            temperature: config.temperature,
827            system_prompt: config.system_prompt.clone(),
828            stop_sequences: vec!["\n\n\n".to_string()],
829        };
830
831        // Send streaming request
832        let response = if let Some(flag) = abort_flag {
833            llm_client
834                .send_stream_abortable(llm_messages, &request_config, flag)
835                .await
836                .map_err(|e| anyhow::anyhow!("LLM stream error: {}", e))?
837        } else {
838            llm_client
839                .send(llm_messages, &request_config)
840                .await
841                .map_err(|e| anyhow::anyhow!("LLM error: {}", e))?
842        };
843
844        // Update token usage in session
845        let tokens_used = response.usage.input_tokens as i64 + response.usage.output_tokens as i64;
846        self.session_manager
847            .update(session_id, |s| {
848                s.tokens_total += tokens_used;
849            })
850            .await?;
851
852        // Parse response for tool calls
853        let tool_calls = self.parse_tool_calls_from_response(&response.content);
854
855        // Determine state based on response
856        let state = if !tool_calls.is_empty() {
857            AgentState::ToolCalling
858        } else if iteration >= max_iterations {
859            AgentState::Completed
860        } else {
861            AgentState::Running
862        };
863
864        let should_continue = iteration < max_iterations && state != AgentState::Completed;
865
866        Ok(IterationResult {
867            iteration,
868            state,
869            message: Some(Message::assistant(&response.content)),
870            tool_calls,
871            should_continue,
872        })
873    }
874
875    /// 从 LLM 响应中解析工具调用
876    ///
877    /// 支持 Anthropic tool_use 格式和 OpenAI function_call 格式
878    fn parse_tool_calls_from_response(&self, content: &str) -> Vec<ToolCall> {
879        let mut tool_calls = Vec::new();
880
881        // Try to parse Anthropic-style tool_use blocks
882        // Format: <tool_use>{"name": "...", "input": {...}}</tool_use>
883        if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(content) {
884            // Check if it's a tool_use response
885            if let Some(content_array) = json_value.get("content").and_then(|c| c.as_array()) {
886                for block in content_array {
887                    if block.get("type").and_then(|t| t.as_str()) == Some("tool_use") {
888                        if let (Some(name), Some(id), Some(input)) = (
889                            block.get("name").and_then(|n| n.as_str()),
890                            block.get("id").and_then(|i| i.as_str()),
891                            block.get("input"),
892                        ) {
893                            tool_calls.push(ToolCall {
894                                id: id.to_string(),
895                                name: name.to_string(),
896                                arguments: input.to_string(),
897                            });
898                        }
899                    }
900                }
901            }
902        }
903
904        // Also try OpenAI-style function_call
905        // Format: {"function_call": {"name": "...", "arguments": "..."}}
906        if tool_calls.is_empty() {
907            if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(content) {
908                if let Some(func_call) = json_value.get("function_call") {
909                    if let (Some(name), Some(args)) = (
910                        func_call.get("name").and_then(|n| n.as_str()),
911                        func_call.get("arguments").and_then(|a| a.as_str()),
912                    ) {
913                        tool_calls.push(ToolCall {
914                            id: sh_layer1::generate_prefixed_id("tc"),
915                            name: name.to_string(),
916                            arguments: args.to_string(),
917                        });
918                    }
919                }
920            }
921        }
922
923        // Also parse tool blocks in text format
924        // Format: ```tool\n{"name": "tool_name", "arguments": {...}}\n```
925        if tool_calls.is_empty() {
926            let re = regex::Regex::new(r"```tool\n(\{.*?\})\n```").unwrap();
927            for cap in re.captures_iter(content) {
928                if let Ok(tool_json) = serde_json::from_str::<serde_json::Value>(&cap[1]) {
929                    if let Some(name) = tool_json.get("name").and_then(|n| n.as_str()) {
930                        let args = tool_json
931                            .get("arguments")
932                            .cloned()
933                            .unwrap_or(serde_json::Value::Null);
934                        tool_calls.push(ToolCall {
935                            id: sh_layer1::generate_prefixed_id("tc"),
936                            name: name.to_string(),
937                            arguments: args.to_string(),
938                        });
939                    }
940                }
941            }
942        }
943
944        tool_calls
945    }
946
947    /// 执行一步 LLM 调用(自动选择真实或模拟)
948    ///
949    /// 如果配置了 LLM 客户端则使用真实调用,否则使用模拟。
950    async fn llm_step(
951        &self,
952        session_id: &SessionId,
953        task: &str,
954        iteration: i32,
955        max_iterations: i32,
956        config: &AgentConfig,
957        abort_flag: Option<Arc<AtomicBool>>,
958    ) -> Layer2Result<IterationResult> {
959        if self.llm_client.is_some() {
960            self.real_llm_step(
961                session_id,
962                task,
963                iteration,
964                max_iterations,
965                config,
966                abort_flag,
967            )
968            .await
969        } else {
970            self.simulate_llm_step(session_id, task, iteration, max_iterations)
971                .await
972        }
973    }
974}
975
976impl Default for AgentRuntime {
977    fn default() -> Self {
978        Self::with_defaults()
979    }
980}
981
982#[async_trait]
983impl AgentRuntimeTrait for AgentRuntime {
984    /// 运行 Agent 执行完整循环,直到完成或出错。
985    ///
986    /// 这是同步(阻塞式)的执行方式:创建会话、运行循环、返回结果。
987    async fn run(&self, task: &str, config: AgentConfig) -> Layer2Result<AgentResult> {
988        info!(task = %task, agent_id = %config.agent_id, "Starting agent run");
989
990        // Create session
991        let session_config = SessionConfig::from(&config);
992        let session_id = self.session_manager.create(session_config).await?;
993
994        // Set agent_id on the session
995        let agent_id = config.agent_id.clone();
996        self.session_manager
997            .update(&session_id, |s| {
998                s.agent_id = agent_id;
999            })
1000            .await?;
1001
1002        // Add system prompt if configured
1003        if let Some(ref prompt) = config.system_prompt {
1004            self.session_manager
1005                .add_message(&session_id, Message::system(prompt))
1006                .await?;
1007        }
1008
1009        // Add user task message
1010        self.session_manager
1011            .add_message(&session_id, Message::user(task))
1012            .await?;
1013
1014        // Transition to Running
1015        self.session_manager
1016            .set_state(&session_id, AgentState::Running)
1017            .await?;
1018
1019        // Execute the loop
1020        let mut iterations = 0;
1021        let max_iterations = config.max_iterations;
1022
1023        loop {
1024            iterations += 1;
1025
1026            if iterations > max_iterations {
1027                warn!(
1028                    session_id = %session_id,
1029                    max = max_iterations,
1030                    "Max iterations reached"
1031                );
1032                self.session_manager
1033                    .set_state(&session_id, AgentState::Error)
1034                    .await?;
1035                return Err(Layer2Error::MaxIterations(max_iterations).into());
1036            }
1037
1038            // Check if session can continue (respect stopped/paused states)
1039            let can_continue: bool = self
1040                .session_manager
1041                .read(&session_id, |s| s.can_continue())
1042                .await?
1043                .unwrap_or(false);
1044
1045            if !can_continue {
1046                let current_state: AgentState = self
1047                    .session_manager
1048                    .read(&session_id, |s| s.state)
1049                    .await?
1050                    .unwrap_or(AgentState::Stopped);
1051
1052                if current_state == AgentState::Stopped {
1053                    info!(session_id = %session_id, "Agent stopped by user");
1054                    break;
1055                }
1056                // Paused or other non-continuable state — break out
1057                break;
1058            }
1059
1060            // Execute one LLM step (real or simulated)
1061            let step_result = self
1062                .llm_step(&session_id, task, iterations, max_iterations, &config, None)
1063                .await?;
1064
1065            // Add the assistant message if any
1066            if let Some(msg) = step_result.message {
1067                self.session_manager.add_message(&session_id, msg).await?;
1068            }
1069
1070            // Handle tool calls
1071            if !step_result.tool_calls.is_empty() {
1072                // Store pending tool calls in session
1073                let tool_calls = step_result.tool_calls.clone();
1074                self.session_manager
1075                    .update(&session_id, |s| {
1076                        s.tool_calls_pending = tool_calls;
1077                        s.state = AgentState::ToolCalling;
1078                    })
1079                    .await?;
1080
1081                // Execute the tools
1082                self.execute_pending_tool_calls(&session_id).await?;
1083
1084                // Transition to WaitingTool briefly, then back to Running
1085                self.session_manager
1086                    .set_state(&session_id, AgentState::WaitingTool)
1087                    .await?;
1088                self.session_manager
1089                    .set_state(&session_id, AgentState::Running)
1090                    .await?;
1091            } else {
1092                // Update state from step result
1093                self.session_manager
1094                    .set_state(&session_id, step_result.state)
1095                    .await?;
1096            }
1097
1098            // Check if we should stop
1099            if !step_result.should_continue {
1100                break;
1101            }
1102        }
1103
1104        // Collect final results
1105        let session = self
1106            .session_manager
1107            .get(&session_id)
1108            .await?
1109            .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1110
1111        let tokens_used = session.tokens_total;
1112
1113        Ok(AgentResult {
1114            session_id: session.session_id.clone(),
1115            final_state: session.state,
1116            messages: session.messages,
1117            tool_calls: session.tool_calls_pending,
1118            tool_results: session.tool_results_cache,
1119            iterations,
1120            tokens_used,
1121        })
1122    }
1123
1124    /// 流式运行 Agent 执行完整循环,通过回调通知每次迭代。
1125    ///
1126    /// 与 run() 类似,但在每次迭代前后通过回调通知外部调用者。
1127    async fn run_stream(
1128        &self,
1129        task: &str,
1130        config: AgentConfig,
1131        callback: &dyn AgentLoopCallback,
1132    ) -> Layer2Result<AgentResult> {
1133        info!(task = %task, agent_id = %config.agent_id, "Starting agent run_stream");
1134
1135        // Create session
1136        let session_config = SessionConfig::from(&config);
1137        let session_id = self.session_manager.create(session_config).await?;
1138
1139        // Set agent_id on the session
1140        let agent_id = config.agent_id.clone();
1141        self.session_manager
1142            .update(&session_id, |s| {
1143                s.agent_id = agent_id;
1144            })
1145            .await?;
1146
1147        // Add system prompt if configured
1148        if let Some(ref prompt) = config.system_prompt {
1149            self.session_manager
1150                .add_message(&session_id, Message::system(prompt))
1151                .await?;
1152        }
1153
1154        // Add user task message
1155        self.session_manager
1156            .add_message(&session_id, Message::user(task))
1157            .await?;
1158
1159        // Transition to Running
1160        self.session_manager
1161            .set_state(&session_id, AgentState::Running)
1162            .await?;
1163
1164        // Execute the loop with callbacks
1165        let mut iterations = 0;
1166        let max_iterations = config.max_iterations;
1167
1168        loop {
1169            iterations += 1;
1170
1171            if iterations > max_iterations {
1172                warn!(
1173                    session_id = %session_id,
1174                    max = max_iterations,
1175                    "Max iterations reached"
1176                );
1177                self.session_manager
1178                    .set_state(&session_id, AgentState::Error)
1179                    .await?;
1180                return Err(Layer2Error::MaxIterations(max_iterations).into());
1181            }
1182
1183            // before_iteration callback
1184            let should_continue_iter = callback.before_iteration(&session_id, iterations).await?;
1185            if !should_continue_iter {
1186                info!(session_id = %session_id, "Callback requested stop");
1187                break;
1188            }
1189
1190            // Check if session can continue
1191            let can_continue: bool = self
1192                .session_manager
1193                .read(&session_id, |s| s.can_continue())
1194                .await?
1195                .unwrap_or(false);
1196
1197            if !can_continue {
1198                let current_state: AgentState = self
1199                    .session_manager
1200                    .read(&session_id, |s| s.state)
1201                    .await?
1202                    .unwrap_or(AgentState::Stopped);
1203
1204                if current_state == AgentState::Stopped {
1205                    info!(session_id = %session_id, "Agent stopped by user");
1206                    break;
1207                }
1208                break;
1209            }
1210
1211            // Execute one LLM step (real or simulated)
1212            let step_result = self
1213                .llm_step(&session_id, task, iterations, max_iterations, &config, None)
1214                .await?;
1215
1216            // Add the assistant message if any
1217            if let Some(msg) = step_result.message.clone() {
1218                self.session_manager.add_message(&session_id, msg).await?;
1219            }
1220
1221            // Handle tool calls with callbacks
1222            if !step_result.tool_calls.is_empty() {
1223                let tool_calls = step_result.tool_calls.clone();
1224
1225                // before_tool_call callback for each tool
1226                for tc in &tool_calls {
1227                    let should_execute = callback.before_tool_call(&session_id, tc).await?;
1228                    if !should_execute {
1229                        info!(tool_call_id = %tc.id, "Callback rejected tool call");
1230                        continue;
1231                    }
1232                }
1233
1234                // Store pending tool calls
1235                self.session_manager
1236                    .update(&session_id, |s| {
1237                        s.tool_calls_pending = tool_calls;
1238                        s.state = AgentState::ToolCalling;
1239                    })
1240                    .await?;
1241
1242                // Execute the tools
1243                self.execute_pending_tool_calls(&session_id).await?;
1244
1245                // Get results and call after_tool_call callback
1246                let results: Vec<ToolResult> = self
1247                    .session_manager
1248                    .read(&session_id, |s| s.tool_results_cache.clone())
1249                    .await?
1250                    .unwrap_or_default();
1251
1252                // Call after_tool_call for each result
1253                for tc in &step_result.tool_calls {
1254                    if let Some(result) = results.iter().find(|r| r.tool_call_id == tc.id) {
1255                        callback.after_tool_call(&session_id, tc, result).await?;
1256                    }
1257                }
1258
1259                // Transition states
1260                self.session_manager
1261                    .set_state(&session_id, AgentState::WaitingTool)
1262                    .await?;
1263                self.session_manager
1264                    .set_state(&session_id, AgentState::Running)
1265                    .await?;
1266            } else {
1267                self.session_manager
1268                    .set_state(&session_id, step_result.state)
1269                    .await?;
1270            }
1271
1272            // Create iteration result for callback
1273            let iter_result = IterationResult {
1274                iteration: iterations,
1275                state: self
1276                    .session_manager
1277                    .read(&session_id, |s| s.state)
1278                    .await?
1279                    .unwrap_or(AgentState::Running),
1280                message: step_result.message,
1281                tool_calls: step_result.tool_calls,
1282                should_continue: step_result.should_continue,
1283            };
1284
1285            // after_iteration callback
1286            callback
1287                .after_iteration(&session_id, iterations, &iter_result)
1288                .await?;
1289
1290            if !iter_result.should_continue {
1291                break;
1292            }
1293        }
1294
1295        // Collect final results
1296        let session = self
1297            .session_manager
1298            .get(&session_id)
1299            .await?
1300            .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1301
1302        let tokens_used = session.tokens_total;
1303
1304        Ok(AgentResult {
1305            session_id: session.session_id.clone(),
1306            final_state: session.state,
1307            messages: session.messages,
1308            tool_calls: session.tool_calls_pending,
1309            tool_results: session.tool_results_cache,
1310            iterations,
1311            tokens_used,
1312        })
1313    }
1314
1315    /// 流式运行 Agent(支持中断)。
1316    ///
1317    /// 与 run_stream 类似,但支持通过 abort_flag 中断执行。
1318    async fn run_stream_abortable(
1319        &self,
1320        task: &str,
1321        config: AgentConfig,
1322        callback: &dyn AgentLoopCallback,
1323        abort_flag: Arc<AtomicBool>,
1324    ) -> Layer2Result<AgentResult> {
1325        info!(task = %task, agent_id = %config.agent_id, "Starting agent run_stream_abortable");
1326
1327        // Create session
1328        let session_config = SessionConfig::from(&config);
1329        let session_id = self.session_manager.create(session_config).await?;
1330
1331        // Set agent_id on the session
1332        let agent_id = config.agent_id.clone();
1333        self.session_manager
1334            .update(&session_id, |s| {
1335                s.agent_id = agent_id;
1336            })
1337            .await?;
1338
1339        // Add system prompt if configured
1340        if let Some(ref prompt) = config.system_prompt {
1341            self.session_manager
1342                .add_message(&session_id, Message::system(prompt))
1343                .await?;
1344        }
1345
1346        // Add user task message
1347        self.session_manager
1348            .add_message(&session_id, Message::user(task))
1349            .await?;
1350
1351        // Transition to Running
1352        self.session_manager
1353            .set_state(&session_id, AgentState::Running)
1354            .await?;
1355
1356        // Execute the loop with callbacks and abort check
1357        let mut iterations = 0;
1358        let max_iterations = config.max_iterations;
1359
1360        loop {
1361            // Check abort flag first
1362            if abort_flag.load(Ordering::Relaxed) {
1363                info!(session_id = %session_id, "Abort flag set, stopping agent");
1364                self.session_manager
1365                    .set_state(&session_id, AgentState::Stopped)
1366                    .await?;
1367                break;
1368            }
1369
1370            iterations += 1;
1371
1372            if iterations > max_iterations {
1373                warn!(
1374                    session_id = %session_id,
1375                    max = max_iterations,
1376                    "Max iterations reached"
1377                );
1378                self.session_manager
1379                    .set_state(&session_id, AgentState::Error)
1380                    .await?;
1381                return Err(Layer2Error::MaxIterations(max_iterations).into());
1382            }
1383
1384            // before_iteration callback
1385            let should_continue_iter = callback.before_iteration(&session_id, iterations).await?;
1386            if !should_continue_iter {
1387                info!(session_id = %session_id, "Callback requested stop");
1388                break;
1389            }
1390
1391            // Check abort flag again after callback
1392            if abort_flag.load(Ordering::Relaxed) {
1393                info!(session_id = %session_id, "Abort flag set after callback, stopping agent");
1394                self.session_manager
1395                    .set_state(&session_id, AgentState::Stopped)
1396                    .await?;
1397                break;
1398            }
1399
1400            // Check if session can continue
1401            let can_continue: bool = self
1402                .session_manager
1403                .read(&session_id, |s| s.can_continue())
1404                .await?
1405                .unwrap_or(false);
1406
1407            if !can_continue {
1408                let current_state: AgentState = self
1409                    .session_manager
1410                    .read(&session_id, |s| s.state)
1411                    .await?
1412                    .unwrap_or(AgentState::Stopped);
1413
1414                if current_state == AgentState::Stopped {
1415                    info!(session_id = %session_id, "Agent stopped by user");
1416                    break;
1417                }
1418                break;
1419            }
1420
1421            // Execute one LLM step (real or simulated)
1422            let step_result = self
1423                .llm_step(
1424                    &session_id,
1425                    task,
1426                    iterations,
1427                    max_iterations,
1428                    &config,
1429                    Some(abort_flag.clone()),
1430                )
1431                .await?;
1432
1433            // Add the assistant message if any
1434            if let Some(msg) = step_result.message.clone() {
1435                self.session_manager.add_message(&session_id, msg).await?;
1436            }
1437
1438            // Handle tool calls with callbacks
1439            if !step_result.tool_calls.is_empty() {
1440                let tool_calls = step_result.tool_calls.clone();
1441
1442                // Check abort before tool calls
1443                if abort_flag.load(Ordering::Relaxed) {
1444                    info!(session_id = %session_id, "Abort flag set before tool calls");
1445                    self.session_manager
1446                        .set_state(&session_id, AgentState::Stopped)
1447                        .await?;
1448                    break;
1449                }
1450
1451                // before_tool_call callback for each tool
1452                for tc in &tool_calls {
1453                    let should_execute = callback.before_tool_call(&session_id, tc).await?;
1454                    if !should_execute {
1455                        info!(tool_call_id = %tc.id, "Callback rejected tool call");
1456                        continue;
1457                    }
1458                }
1459
1460                // Store pending tool calls
1461                self.session_manager
1462                    .update(&session_id, |s| {
1463                        s.tool_calls_pending = tool_calls;
1464                        s.state = AgentState::ToolCalling;
1465                    })
1466                    .await?;
1467
1468                // Execute the tools
1469                self.execute_pending_tool_calls(&session_id).await?;
1470
1471                // Get results and call after_tool_call callback
1472                let results: Vec<ToolResult> = self
1473                    .session_manager
1474                    .read(&session_id, |s| s.tool_results_cache.clone())
1475                    .await?
1476                    .unwrap_or_default();
1477
1478                // Call after_tool_call for each result
1479                for tc in &step_result.tool_calls {
1480                    if let Some(result) = results.iter().find(|r| r.tool_call_id == tc.id) {
1481                        callback.after_tool_call(&session_id, tc, result).await?;
1482                    }
1483                }
1484
1485                // Transition states
1486                self.session_manager
1487                    .set_state(&session_id, AgentState::WaitingTool)
1488                    .await?;
1489                self.session_manager
1490                    .set_state(&session_id, AgentState::Running)
1491                    .await?;
1492            } else {
1493                self.session_manager
1494                    .set_state(&session_id, step_result.state)
1495                    .await?;
1496            }
1497
1498            // Create iteration result for callback
1499            let iter_result = IterationResult {
1500                iteration: iterations,
1501                state: self
1502                    .session_manager
1503                    .read(&session_id, |s| s.state)
1504                    .await?
1505                    .unwrap_or(AgentState::Running),
1506                message: step_result.message,
1507                tool_calls: step_result.tool_calls,
1508                should_continue: step_result.should_continue,
1509            };
1510
1511            // after_iteration callback
1512            callback
1513                .after_iteration(&session_id, iterations, &iter_result)
1514                .await?;
1515
1516            if !iter_result.should_continue {
1517                break;
1518            }
1519        }
1520
1521        // Collect final results
1522        let session = self
1523            .session_manager
1524            .get(&session_id)
1525            .await?
1526            .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1527
1528        let tokens_used = session.tokens_total;
1529
1530        Ok(AgentResult {
1531            session_id: session.session_id.clone(),
1532            final_state: session.state,
1533            messages: session.messages,
1534            tool_calls: session.tool_calls_pending,
1535            tool_results: session.tool_results_cache,
1536            iterations,
1537            tokens_used,
1538        })
1539    }
1540
1541    /// 启动 Agent 并返回会话 ID(用于异步/流式执行)。
1542    ///
1543    /// 创建会话,设置为 Running 状态,但不执行循环。
1544    /// 调用者可以通过 send_message / submit_tool_result 与 Agent 交互。
1545    async fn start(&self, task: &str, config: AgentConfig) -> Layer2Result<SessionId> {
1546        info!(task = %task, agent_id = %config.agent_id, "Starting agent session");
1547
1548        let session_config = SessionConfig::from(&config);
1549        let session_id = self.session_manager.create(session_config).await?;
1550
1551        // Set agent_id
1552        let agent_id = config.agent_id.clone();
1553        self.session_manager
1554            .update(&session_id, |s| {
1555                s.agent_id = agent_id;
1556            })
1557            .await?;
1558
1559        // Add system prompt if configured
1560        if let Some(ref prompt) = config.system_prompt {
1561            self.session_manager
1562                .add_message(&session_id, Message::system(prompt))
1563                .await?;
1564        }
1565
1566        // Add user task message
1567        self.session_manager
1568            .add_message(&session_id, Message::user(task))
1569            .await?;
1570
1571        // Transition to Running
1572        self.session_manager
1573            .set_state(&session_id, AgentState::Running)
1574            .await?;
1575
1576        Ok(session_id)
1577    }
1578
1579    /// 暂停正在执行的 Agent。
1580    ///
1581    /// 将状态从 Running/ToolCalling/WaitingTool 转换为 Stopped(暂停)。
1582    /// 在暂停状态下,Agent 不会继续执行迭代。
1583    async fn pause(&self, session_id: &SessionId) -> Layer2Result<()> {
1584        self.require_session(session_id).await?;
1585
1586        let current_state: AgentState =
1587            self.session_manager
1588                .read(session_id, |s| s.state)
1589                .await?
1590                .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1591
1592        match current_state {
1593            AgentState::Running | AgentState::ToolCalling | AgentState::WaitingTool => {
1594                AgentRuntime::validate_transition(current_state, AgentState::Stopped)?;
1595                self.session_manager
1596                    .set_state(session_id, AgentState::Stopped)
1597                    .await?;
1598                info!(session_id = %session_id, "Agent paused");
1599                Ok(())
1600            }
1601            AgentState::Stopped => {
1602                // Already paused, idempotent
1603                debug!(session_id = %session_id, "Agent already paused");
1604                Ok(())
1605            }
1606            other => Err(Layer2Error::InvalidStateTransition {
1607                from: other,
1608                to: AgentState::Stopped,
1609            }
1610            .into()),
1611        }
1612    }
1613
1614    /// 恢复暂停的 Agent。
1615    ///
1616    /// 将状态从 Stopped 转换回 Running。
1617    async fn resume(&self, session_id: &SessionId) -> Layer2Result<()> {
1618        self.require_session(session_id).await?;
1619
1620        let current_state: AgentState =
1621            self.session_manager
1622                .read(session_id, |s| s.state)
1623                .await?
1624                .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1625
1626        match current_state {
1627            AgentState::Stopped => {
1628                AgentRuntime::validate_transition(current_state, AgentState::Running)?;
1629                self.session_manager
1630                    .set_state(session_id, AgentState::Running)
1631                    .await?;
1632                info!(session_id = %session_id, "Agent resumed");
1633                Ok(())
1634            }
1635            AgentState::Running => {
1636                // Already running, idempotent
1637                debug!(session_id = %session_id, "Agent already running");
1638                Ok(())
1639            }
1640            other => Err(Layer2Error::InvalidStateTransition {
1641                from: other,
1642                to: AgentState::Running,
1643            }
1644            .into()),
1645        }
1646    }
1647
1648    /// 停止 Agent 执行。
1649    ///
1650    /// 无论当前处于什么状态(除了 Completed/Idle),都转换到 Stopped。
1651    /// 这与 pause 的区别在于 stop 是终止性的,表示用户主动取消。
1652    async fn stop(&self, session_id: &SessionId) -> Layer2Result<()> {
1653        self.require_session(session_id).await?;
1654
1655        let current_state: AgentState =
1656            self.session_manager
1657                .read(session_id, |s| s.state)
1658                .await?
1659                .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1660
1661        match current_state {
1662            AgentState::Running
1663            | AgentState::ToolCalling
1664            | AgentState::WaitingTool
1665            | AgentState::Stopped => {
1666                self.session_manager
1667                    .set_state(session_id, AgentState::Stopped)
1668                    .await?;
1669                info!(session_id = %session_id, "Agent stopped");
1670                Ok(())
1671            }
1672            AgentState::Idle | AgentState::Completed | AgentState::Error => {
1673                Err(Layer2Error::InvalidStateTransition {
1674                    from: current_state,
1675                    to: AgentState::Stopped,
1676                }
1677                .into())
1678            }
1679        }
1680    }
1681
1682    /// 获取 Agent 当前状态。
1683    fn status(&self, session_id: &SessionId) -> Layer2Result<AgentState> {
1684        // Use the synchronous accessor provided by ConcurrentSessionManager.
1685        // Since ConcurrentSessionManager uses parking_lot::RwLock internally,
1686        // we can do a synchronous read safely.
1687        self.session_manager
1688            .get_state_sync(session_id)
1689            .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()).into())
1690    }
1691
1692    /// 向 Agent 发送消息。
1693    ///
1694    /// 将消息添加到会话的消息历史中。Agent 在下一次迭代时可以读取。
1695    async fn send_message(&self, session_id: &SessionId, message: &str) -> Layer2Result<()> {
1696        self.require_session(session_id).await?;
1697
1698        let current_state: AgentState =
1699            self.session_manager
1700                .read(session_id, |s| s.state)
1701                .await?
1702                .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1703
1704        // Allow sending messages in Running, WaitingTool, or Stopped states
1705        match current_state {
1706            AgentState::Running
1707            | AgentState::WaitingTool
1708            | AgentState::Stopped
1709            | AgentState::Idle
1710            | AgentState::ToolCalling => {
1711                self.session_manager
1712                    .add_message(session_id, Message::user(message))
1713                    .await?;
1714                debug!(
1715                    session_id = %session_id,
1716                    msg_len = message.len(),
1717                    "Message sent to agent"
1718                );
1719                Ok(())
1720            }
1721            AgentState::Completed | AgentState::Error => {
1722                Err(Layer2Error::InvalidStateTransition {
1723                    from: current_state,
1724                    to: current_state, // no transition, just rejection
1725                }
1726                .into())
1727            }
1728        }
1729    }
1730
1731    /// 提交工具调用结果。
1732    ///
1733    /// 当 Agent 处于 WaitingTool 状态时,外部系统可以通过此方法
1734    /// 提交工具执行的结果,使 Agent 能够继续执行。
1735    async fn submit_tool_result(
1736        &self,
1737        session_id: &SessionId,
1738        tool_call_id: &str,
1739        result: ToolResult,
1740    ) -> Layer2Result<()> {
1741        self.require_session(session_id).await?;
1742
1743        let current_state: AgentState =
1744            self.session_manager
1745                .read(session_id, |s| s.state)
1746                .await?
1747                .ok_or_else(|| Layer2Error::SessionNotFound(session_id.clone()))?;
1748
1749        match current_state {
1750            AgentState::WaitingTool | AgentState::ToolCalling | AgentState::Running => {
1751                // Verify the tool_call_id matches an expected pending call
1752                let _pending_ids: Vec<String> = self
1753                    .session_manager
1754                    .read(session_id, |s| {
1755                        s.tool_calls_pending
1756                            .iter()
1757                            .map(|tc| tc.id.clone())
1758                            .collect()
1759                    })
1760                    .await?
1761                    .unwrap_or_default();
1762
1763                // Remove the matched pending tool call and store the result
1764                self.session_manager
1765                    .update(session_id, |s| {
1766                        // Remove the matching pending tool call
1767                        s.tool_calls_pending.retain(|tc| tc.id != tool_call_id);
1768                        // Store the result
1769                        s.tool_results_cache.push(result);
1770
1771                        // If no more pending tool calls, transition back to Running
1772                        if s.tool_calls_pending.is_empty() {
1773                            s.state = AgentState::Running;
1774                        }
1775                    })
1776                    .await?;
1777
1778                debug!(
1779                    session_id = %session_id,
1780                    tool_call_id = %tool_call_id,
1781                    "Tool result submitted"
1782                );
1783                Ok(())
1784            }
1785            other => Err(Layer2Error::InvalidStateTransition {
1786                from: other,
1787                to: AgentState::Running,
1788            }
1789            .into()),
1790        }
1791    }
1792}
1793
1794#[cfg(test)]
1795mod tests {
1796    use super::*;
1797    use crate::tool_registry::Tool;
1798    use crate::types::MessageRole;
1799
1800    /// Mock tool for testing
1801    struct MockTool {
1802        name: String,
1803        description: String,
1804    }
1805
1806    impl MockTool {
1807        fn new(name: &str) -> Self {
1808            Self {
1809                name: name.to_string(),
1810                description: format!("Mock tool: {}", name),
1811            }
1812        }
1813    }
1814
1815    #[async_trait]
1816    impl Tool for MockTool {
1817        fn name(&self) -> &str {
1818            &self.name
1819        }
1820
1821        fn description(&self) -> &str {
1822            &self.description
1823        }
1824
1825        fn parameters(&self) -> serde_json::Value {
1826            serde_json::json!({
1827                "type": "object",
1828                "properties": {
1829                    "input": {
1830                        "type": "string"
1831                    }
1832                }
1833            })
1834        }
1835
1836        async fn execute(&self, args: &str) -> Layer2Result<ToolResult> {
1837            Ok(ToolResult {
1838                tool_call_id: "mock_id".to_string(),
1839                name: self.name.clone(),
1840                content: format!("Executed with args: {}", args),
1841                is_error: false,
1842            })
1843        }
1844    }
1845
1846    #[test]
1847    fn test_agent_config_default() {
1848        let config = AgentConfig::default();
1849        assert_eq!(config.model, "claude-sonnet-4-6");
1850        assert_eq!(config.max_iterations, 100);
1851        assert_eq!(config.temperature, 0.7);
1852    }
1853
1854    #[test]
1855    fn test_agent_runtime_creation() {
1856        let runtime = AgentRuntime::with_defaults();
1857        assert!(runtime.session_manager().stats().total_sessions == 0);
1858        assert!(runtime.tool_registry().count() == 0);
1859    }
1860
1861    #[test]
1862    fn test_agent_config_to_session_config() {
1863        let agent_config = AgentConfig {
1864            agent_id: AgentId::new(),
1865            model: "custom-model".to_string(),
1866            temperature: 0.5,
1867            max_iterations: 50,
1868            system_prompt: Some("Custom prompt".to_string()),
1869        };
1870
1871        let session_config = SessionConfig::from(&agent_config);
1872        assert_eq!(session_config.model, "custom-model");
1873        assert_eq!(session_config.temperature, 0.5);
1874        assert_eq!(session_config.max_iterations, 50);
1875        assert_eq!(
1876            session_config.system_prompt,
1877            Some("Custom prompt".to_string())
1878        );
1879    }
1880
1881    #[test]
1882    fn test_state_transition_validation() {
1883        // Valid transitions
1884        assert!(AgentRuntime::validate_transition(AgentState::Idle, AgentState::Running).is_ok());
1885        assert!(
1886            AgentRuntime::validate_transition(AgentState::Running, AgentState::ToolCalling).is_ok()
1887        );
1888        assert!(
1889            AgentRuntime::validate_transition(AgentState::Running, AgentState::Stopped).is_ok()
1890        );
1891        assert!(
1892            AgentRuntime::validate_transition(AgentState::Stopped, AgentState::Running).is_ok()
1893        );
1894        assert!(
1895            AgentRuntime::validate_transition(AgentState::Running, AgentState::Completed).is_ok()
1896        );
1897        assert!(
1898            AgentRuntime::validate_transition(AgentState::Running, AgentState::Running).is_ok()
1899        );
1900
1901        // Invalid transitions
1902        assert!(
1903            AgentRuntime::validate_transition(AgentState::Idle, AgentState::ToolCalling).is_err()
1904        );
1905        assert!(
1906            AgentRuntime::validate_transition(AgentState::Completed, AgentState::Running).is_err()
1907        );
1908        assert!(AgentRuntime::validate_transition(AgentState::Error, AgentState::Running).is_err());
1909    }
1910
1911    #[tokio::test]
1912    async fn test_agent_run_basic() {
1913        let runtime = AgentRuntime::with_defaults();
1914        let config = AgentConfig {
1915            max_iterations: 5,
1916            ..Default::default()
1917        };
1918
1919        let result = runtime.run("Test task", config).await;
1920        assert!(result.is_ok());
1921
1922        let agent_result = result.unwrap();
1923        assert!(!agent_result.session_id.0.is_empty());
1924        assert!(agent_result.iterations > 0);
1925        assert!(agent_result.iterations <= 5);
1926        // Messages should include system (if configured), user task, and assistant responses
1927        assert!(!agent_result.messages.is_empty());
1928    }
1929
1930    #[tokio::test]
1931    async fn test_agent_run_with_tools() {
1932        let runtime = AgentRuntime::with_defaults();
1933
1934        // Register a mock tool
1935        runtime
1936            .tool_registry()
1937            .register(Box::new(MockTool::new("test_tool")))
1938            .unwrap();
1939
1940        assert!(runtime.tool_registry().count() == 1);
1941
1942        let config = AgentConfig {
1943            max_iterations: 10,
1944            ..Default::default()
1945        };
1946
1947        let result = runtime.run("Test task with tools", config).await;
1948        assert!(result.is_ok());
1949
1950        let agent_result = result.unwrap();
1951        // Should have executed the tool
1952        assert!(!agent_result.tool_results.is_empty() || agent_result.tool_calls.is_empty());
1953    }
1954
1955    #[tokio::test]
1956    async fn test_agent_start_creates_session() {
1957        let runtime = AgentRuntime::with_defaults();
1958        let config = AgentConfig::default();
1959
1960        let session_id = runtime.start("Test task", config).await.unwrap();
1961
1962        // Verify session was created
1963        let session = runtime.session_manager().get(&session_id).await.unwrap();
1964        assert!(session.is_some());
1965
1966        let session = session.unwrap();
1967        assert_eq!(session.state, AgentState::Running);
1968        assert!(!session.messages.is_empty());
1969    }
1970
1971    #[tokio::test]
1972    async fn test_agent_start_with_system_prompt() {
1973        let runtime = AgentRuntime::with_defaults();
1974        let config = AgentConfig {
1975            system_prompt: Some("You are a helpful assistant".to_string()),
1976            ..Default::default()
1977        };
1978
1979        let session_id = runtime.start("Test task", config).await.unwrap();
1980
1981        let messages = runtime
1982            .session_manager()
1983            .get_messages(&session_id)
1984            .await
1985            .unwrap()
1986            .unwrap();
1987
1988        // First message should be system prompt
1989        assert!(messages.len() >= 2);
1990        assert_eq!(messages[0].role, MessageRole::System);
1991        assert_eq!(messages[0].content, "You are a helpful assistant");
1992    }
1993
1994    #[tokio::test]
1995    async fn test_agent_pause_resume() {
1996        let runtime = AgentRuntime::with_defaults();
1997        let config = AgentConfig::default();
1998
1999        let session_id = runtime.start("Test task", config).await.unwrap();
2000
2001        // Pause the agent
2002        let pause_result = runtime.pause(&session_id).await;
2003        assert!(pause_result.is_ok());
2004
2005        let state = runtime
2006            .session_manager()
2007            .get_state(&session_id)
2008            .await
2009            .unwrap()
2010            .unwrap();
2011        assert_eq!(state, AgentState::Stopped);
2012
2013        // Resume the agent
2014        let resume_result = runtime.resume(&session_id).await;
2015        assert!(resume_result.is_ok());
2016
2017        let state = runtime
2018            .session_manager()
2019            .get_state(&session_id)
2020            .await
2021            .unwrap()
2022            .unwrap();
2023        assert_eq!(state, AgentState::Running);
2024
2025        // Pause again should be idempotent
2026        runtime.pause(&session_id).await.unwrap();
2027        runtime.pause(&session_id).await.unwrap();
2028        let state = runtime
2029            .session_manager()
2030            .get_state(&session_id)
2031            .await
2032            .unwrap()
2033            .unwrap();
2034        assert_eq!(state, AgentState::Stopped);
2035    }
2036
2037    #[tokio::test]
2038    async fn test_agent_stop() {
2039        let runtime = AgentRuntime::with_defaults();
2040        let config = AgentConfig::default();
2041
2042        let session_id = runtime.start("Test task", config).await.unwrap();
2043
2044        // Stop the agent
2045        runtime.stop(&session_id).await.unwrap();
2046
2047        let state = runtime
2048            .session_manager()
2049            .get_state(&session_id)
2050            .await
2051            .unwrap()
2052            .unwrap();
2053        assert_eq!(state, AgentState::Stopped);
2054    }
2055
2056    #[tokio::test]
2057    async fn test_agent_pause_nonexistent_session() {
2058        let runtime = AgentRuntime::with_defaults();
2059        let fake_id = SessionId::new();
2060
2061        let result = runtime.pause(&fake_id).await;
2062        assert!(result.is_err());
2063        // Verify error is SessionNotFound
2064        let err = result.unwrap_err();
2065        let err_str = err.to_string();
2066        assert!(err_str.contains("Session not found"));
2067    }
2068
2069    #[tokio::test]
2070    async fn test_agent_status() {
2071        let runtime = AgentRuntime::with_defaults();
2072        let config = AgentConfig::default();
2073
2074        let session_id = runtime.start("Test task", config).await.unwrap();
2075
2076        let status = runtime.status(&session_id);
2077        assert!(status.is_ok());
2078        assert_eq!(status.unwrap(), AgentState::Running);
2079
2080        runtime.pause(&session_id).await.unwrap();
2081        let status = runtime.status(&session_id);
2082        assert!(status.is_ok());
2083        assert_eq!(status.unwrap(), AgentState::Stopped);
2084    }
2085
2086    #[tokio::test]
2087    async fn test_agent_send_message() {
2088        let runtime = AgentRuntime::with_defaults();
2089        let config = AgentConfig::default();
2090
2091        let session_id = runtime.start("Test task", config).await.unwrap();
2092
2093        // Send a message
2094        runtime
2095            .send_message(&session_id, "Additional message")
2096            .await
2097            .unwrap();
2098
2099        let messages = runtime
2100            .session_manager()
2101            .get_messages(&session_id)
2102            .await
2103            .unwrap()
2104            .unwrap();
2105
2106        // Should have original task message plus the new message
2107        assert!(messages.len() >= 2);
2108        let last_user_msg = messages.iter().rev().find(|m| m.role == MessageRole::User);
2109        assert!(last_user_msg.is_some());
2110        assert_eq!(last_user_msg.unwrap().content, "Additional message");
2111    }
2112
2113    #[tokio::test]
2114    async fn test_agent_submit_tool_result() {
2115        let runtime = AgentRuntime::with_defaults();
2116        let config = AgentConfig::default();
2117
2118        let session_id = runtime.start("Test task", config).await.unwrap();
2119
2120        // Manually set up a pending tool call
2121        runtime
2122            .session_manager()
2123            .update(&session_id, |s| {
2124                s.tool_calls_pending.push(ToolCall {
2125                    id: "tc_123".to_string(),
2126                    name: "test_tool".to_string(),
2127                    arguments: "{}".to_string(),
2128                });
2129                s.state = AgentState::WaitingTool;
2130            })
2131            .await
2132            .unwrap();
2133
2134        // Submit the tool result
2135        let tool_result = ToolResult {
2136            tool_call_id: "tc_123".to_string(),
2137            name: "test_tool".to_string(),
2138            content: "Tool executed successfully".to_string(),
2139            is_error: false,
2140        };
2141
2142        runtime
2143            .submit_tool_result(&session_id, "tc_123", tool_result)
2144            .await
2145            .unwrap();
2146
2147        // Verify the pending tool call was removed
2148        let pending_count: usize = runtime
2149            .session_manager()
2150            .read(&session_id, |s| s.tool_calls_pending.len())
2151            .await
2152            .unwrap()
2153            .unwrap_or(0);
2154        assert_eq!(pending_count, 0);
2155
2156        // Verify the result was cached
2157        let cached_results: Vec<ToolResult> = runtime
2158            .session_manager()
2159            .read(&session_id, |s| s.tool_results_cache.clone())
2160            .await
2161            .unwrap()
2162            .unwrap_or_default();
2163        assert_eq!(cached_results.len(), 1);
2164        assert_eq!(cached_results[0].tool_call_id, "tc_123");
2165
2166        // Verify state transitioned back to Running
2167        let state = runtime
2168            .session_manager()
2169            .get_state(&session_id)
2170            .await
2171            .unwrap()
2172            .unwrap();
2173        assert_eq!(state, AgentState::Running);
2174    }
2175
2176    #[tokio::test]
2177    async fn test_agent_run_respects_stopped_state() {
2178        let runtime = AgentRuntime::with_defaults();
2179        let config = AgentConfig {
2180            max_iterations: 100,
2181            ..Default::default()
2182        };
2183
2184        // Start a session
2185        let session_id = runtime.start("Test task", config.clone()).await.unwrap();
2186
2187        // Immediately stop it
2188        runtime.stop(&session_id).await.unwrap();
2189
2190        // Now try to run - it should handle the stopped state gracefully
2191        // Note: run() creates a new session, so this tests that the original
2192        // session is properly in stopped state
2193        let state = runtime
2194            .session_manager()
2195            .get_state(&session_id)
2196            .await
2197            .unwrap()
2198            .unwrap();
2199        assert_eq!(state, AgentState::Stopped);
2200    }
2201
2202    #[tokio::test]
2203    async fn test_agent_run_max_iterations() {
2204        let runtime = AgentRuntime::with_defaults();
2205        let config = AgentConfig {
2206            max_iterations: 3,
2207            ..Default::default()
2208        };
2209
2210        let result = runtime.run("Test task", config).await.unwrap();
2211
2212        // Should complete within max iterations
2213        assert!(result.iterations <= 3);
2214        // Final state should be Completed
2215        assert_eq!(result.final_state, AgentState::Completed);
2216    }
2217
2218    #[test]
2219    fn test_iteration_result_creation() {
2220        let result = IterationResult {
2221            iteration: 1,
2222            state: AgentState::Running,
2223            message: Some(Message::assistant("Test")),
2224            tool_calls: vec![ToolCall {
2225                id: "tc_1".to_string(),
2226                name: "test_tool".to_string(),
2227                arguments: "{}".to_string(),
2228            }],
2229            should_continue: true,
2230        };
2231
2232        assert_eq!(result.iteration, 1);
2233        assert_eq!(result.state, AgentState::Running);
2234        assert!(result.message.is_some());
2235        assert_eq!(result.tool_calls.len(), 1);
2236        assert!(result.should_continue);
2237    }
2238
2239    #[test]
2240    fn test_agent_runtime_with_permission_manager() {
2241        use crate::permission::policy::PermissionPolicy;
2242
2243        let policy = PermissionPolicy::trusted();
2244        let pm = Arc::new(PermissionManager::new(policy));
2245
2246        let session_manager = Arc::new(ConcurrentSessionManager::default_config());
2247        let tool_registry = Arc::new(ToolRegistry::new());
2248
2249        let runtime = AgentRuntime::with_permissions(session_manager, tool_registry, pm.clone());
2250
2251        assert!(runtime.permission_manager().is_some());
2252        assert_eq!(
2253            runtime.permission_manager().unwrap().security_level(),
2254            crate::permission::policy::SecurityLevel::Trusted
2255        );
2256    }
2257
2258    #[test]
2259    fn test_agent_runtime_set_permission_manager() {
2260        use crate::permission::policy::PermissionPolicy;
2261
2262        let mut runtime = AgentRuntime::with_defaults();
2263        assert!(runtime.permission_manager().is_none());
2264
2265        let policy = PermissionPolicy::default();
2266        let pm = Arc::new(PermissionManager::new(policy));
2267        runtime.set_permission_manager(pm);
2268
2269        assert!(runtime.permission_manager().is_some());
2270        assert_eq!(
2271            runtime.permission_manager().unwrap().security_level(),
2272            crate::permission::policy::SecurityLevel::Standard
2273        );
2274    }
2275
2276    #[test]
2277    fn test_agent_runtime_has_decomposer() {
2278        let runtime = AgentRuntime::with_defaults();
2279        // with_defaults() now creates a TaskDecomposer
2280        assert!(runtime.task_decomposer().is_some());
2281    }
2282
2283    #[test]
2284    fn test_agent_decompose_task() {
2285        let runtime = AgentRuntime::with_defaults();
2286
2287        // Test simple task decomposition
2288        let plan = runtime.decompose_task("Read a file and write output");
2289        assert!(plan.is_ok());
2290        let plan = plan.unwrap();
2291        assert!(plan.is_some());
2292
2293        let plan = plan.unwrap();
2294        assert!(!plan.subtasks.is_empty());
2295        assert!(!plan.execution_order.is_empty());
2296    }
2297
2298    #[test]
2299    fn test_agent_set_decomposition_strategy() {
2300        let mut runtime = AgentRuntime::with_defaults();
2301        runtime.set_decomposition_strategy(DecompositionStrategy::Parallel);
2302
2303        let decomposer = runtime.task_decomposer().unwrap();
2304        let plan = decomposer.decompose("Task A and Task B").unwrap();
2305        assert_eq!(plan.strategy, DecompositionStrategy::Parallel);
2306    }
2307
2308    #[tokio::test]
2309    async fn test_agent_run_with_plan_simple() {
2310        let runtime = AgentRuntime::with_defaults();
2311        let config = AgentConfig {
2312            max_iterations: 5,
2313            ..Default::default()
2314        };
2315
2316        // Test run_with_plan for a simple task
2317        let result = runtime.run_with_plan("Simple task", config).await;
2318        assert!(result.is_ok());
2319
2320        let agent_result = result.unwrap();
2321        assert_eq!(agent_result.final_state, AgentState::Completed);
2322    }
2323}