// src/agent/autonomous.rs // // 自治研究循环 — 空闲时自动轮询新任务。 // 参考 learn-claude-code s17 Autonomous Agents。 // // 当 Agent 完成当前回合后,进入 IDLE 阶段: // 1. 检查是否有未认领的团队任务 // 2. 检查批量同步任务队列 // 3. 检查订阅分类的新论文 // 发现工作后自动认领并执行。 use std::sync::Arc; use std::time::Duration; use tokio::sync::Notify; use tracing::{info, warn}; use crate::api::AppState; /// 自治研究配置 #[derive(Debug, Clone)] pub struct AutoResearchConfig { /// 是否启用自治模式 pub enabled: bool, /// 订阅的 arXiv 分类 pub subscribed_categories: Vec, /// 最大自治轮次(防止无限循环) pub max_autonomous_turns: usize, /// IDLE 超时(分钟) pub idle_timeout_minutes: u64, } impl Default for AutoResearchConfig { fn default() -> Self { AutoResearchConfig { enabled: false, subscribed_categories: vec!["astro-ph".to_string()], max_autonomous_turns: 5, idle_timeout_minutes: 60, } } } /// IDLE 轮询器 — 在 Agent 空闲时检查是否有待处理工作。 pub struct IdlePoller { app_state: Arc, config: AutoResearchConfig, poll_interval: Duration, /// 唤醒通知(当外部事件触发时,如新论文到达、任务分配) wake_notify: Arc, } impl IdlePoller { pub fn new(app_state: Arc, config: AutoResearchConfig) -> Self { IdlePoller { app_state, config, poll_interval: Duration::from_secs(30), wake_notify: Arc::new(Notify::new()), } } /// 获取唤醒通知器的 clone(供外部触发) pub fn wake_sender(&self) -> Arc { self.wake_notify.clone() } /// 启动 IDLE 循环(应在独立的 tokio::spawn 中运行) pub async fn start(self) { info!( "[IdlePoller] 启动自治轮询 (间隔={:?}, 最大轮次={})", self.poll_interval, self.config.max_autonomous_turns ); let mut autonomous_turns: usize = 0; loop { // 等待 poll_interval 或被 notify 唤醒 tokio::select! { _ = tokio::time::sleep(self.poll_interval) => {} _ = self.wake_notify.notified() => { info!("[IdlePoller] 被外部事件唤醒"); } } if !self.config.enabled { continue; } if autonomous_turns >= self.config.max_autonomous_turns { info!( "[IdlePoller] 已达到最大自治轮次 ({}),停止轮询", self.config.max_autonomous_turns ); break; } // 1. 检查未认领的团队任务 let task_board = crate::agent::task_board::TaskBoard::new(self.app_state.db.clone()); match task_board.list_available_tasks(5).await { Ok(tasks) if !tasks.is_empty() => { for task in tasks { if task.can_start { info!( "[IdlePoller] 发现可认领任务: {} (session={})", task.task_id, task.session_id ); if let Ok(true) = task_board .claim_task(&task.session_id, &task.task_id, "auto") .await { autonomous_turns += 1; // 创建 AgentRuntime 并执行任务 let runtime = crate::agent::runtime::AgentRuntime::new( self.app_state.clone(), ); let (tx, _rx) = tokio::sync::mpsc::unbounded_channel(); let _ = runtime .run_turn(Some(task.session_id.clone()), &task.content, tx) .await; } } } continue; } Ok(_) => {} Err(e) => { warn!("[IdlePoller] 任务查询失败: {}", e); } } // 2. 检查批量同步状态 (placeholder) // 未来: 检查订阅分类的新论文并自动触发同步 } info!("[IdlePoller] IDLE 循环结束"); } }