Skip to main content

mofa_foundation/secretary/default/
behavior.rs

1//! 默认秘书行为实现
2//!
3//! 提供一个开箱即用的秘书行为实现,包含完整的5阶段工作流程。
4
5use super::clarifier::{ClarificationStrategy, RequirementClarifier};
6use super::coordinator::{DispatchStrategy, TaskCoordinator};
7use super::monitor::TaskMonitor;
8use super::reporter::{ReportConfig, Reporter};
9use super::todo::TodoManager;
10use super::types::*;
11
12use crate::secretary::agent_router::{AgentInfo, AgentProvider, AgentRouter};
13use crate::secretary::llm::{ChatMessage, ConversationHistory, LLMProvider};
14
15// 使用 mofa-kernel 的核心抽象
16use mofa_kernel::agent::secretary::{SecretaryBehavior, SecretaryContext};
17
18use async_trait::async_trait;
19use std::collections::HashMap;
20use std::sync::Arc;
21
22// =============================================================================
23// 默认秘书状态
24// =============================================================================
25
26/// 默认秘书状态
27pub struct DefaultSecretaryState {
28    /// 任务管理器
29    pub todo_manager: TodoManager,
30    /// 需求澄清器
31    pub clarifier: RequirementClarifier,
32    /// 任务协调器
33    pub coordinator: TaskCoordinator,
34    /// 任务监控器
35    pub monitor: TaskMonitor,
36    /// 汇报器
37    pub reporter: Reporter,
38    /// 对话历史
39    pub conversation_history: Vec<ChatMessage>,
40    /// 当前工作阶段
41    pub current_phase: WorkPhase,
42}
43
44impl DefaultSecretaryState {
45    /// 创建新的默认状态
46    pub fn new(
47        clarification_strategy: ClarificationStrategy,
48        dispatch_strategy: DispatchStrategy,
49        report_config: ReportConfig,
50    ) -> Self {
51        Self {
52            todo_manager: TodoManager::new(),
53            clarifier: RequirementClarifier::new(clarification_strategy),
54            coordinator: TaskCoordinator::new(dispatch_strategy),
55            monitor: TaskMonitor::new(),
56            reporter: Reporter::new(report_config),
57            conversation_history: Vec::new(),
58            current_phase: WorkPhase::ReceivingIdea,
59        }
60    }
61}
62
63// =============================================================================
64// 默认秘书配置
65// =============================================================================
66
67/// 默认秘书配置
68#[derive(Debug, Clone)]
69pub struct DefaultSecretaryConfig {
70    /// 秘书名称
71    pub name: String,
72    /// 澄清策略
73    pub clarification_strategy: ClarificationStrategy,
74    /// 分配策略
75    pub dispatch_strategy: DispatchStrategy,
76    /// 汇报配置
77    pub report_config: ReportConfig,
78    /// 是否自动澄清
79    pub auto_clarify: bool,
80    /// 是否自动分配
81    pub auto_dispatch: bool,
82    /// 是否使用LLM
83    pub use_llm: bool,
84    /// 系统提示词
85    pub system_prompt: Option<String>,
86}
87
88impl Default for DefaultSecretaryConfig {
89    fn default() -> Self {
90        Self {
91            name: "智能秘书".to_string(),
92            clarification_strategy: ClarificationStrategy::Automatic,
93            dispatch_strategy: DispatchStrategy::CapabilityFirst,
94            report_config: ReportConfig::default(),
95            auto_clarify: true,
96            auto_dispatch: true,
97            use_llm: true,
98            system_prompt: None,
99        }
100    }
101}
102
103// =============================================================================
104// 默认秘书行为
105// =============================================================================
106
107/// 默认秘书行为实现
108///
109/// 实现了完整的5阶段工作流程:
110/// 1. 接收想法 → 记录Todo
111/// 2. 澄清需求 → 生成项目文档
112/// 3. 调度分配 → 调用执行Agent
113/// 4. 监控反馈 → 推送关键决策
114/// 5. 验收汇报 → 更新Todo
115pub struct DefaultSecretaryBehavior {
116    /// 配置
117    config: DefaultSecretaryConfig,
118    /// LLM提供者
119    llm: Option<Arc<dyn LLMProvider>>,
120    /// Agent提供者
121    agent_provider: Option<Arc<dyn AgentProvider>>,
122    /// Agent路由器
123    agent_router: Option<Arc<dyn AgentRouter>>,
124    /// 预注册的执行器
125    executors: Vec<AgentInfo>,
126}
127
128impl DefaultSecretaryBehavior {
129    /// 创建新的默认秘书行为
130    pub fn new(config: DefaultSecretaryConfig) -> Self {
131        Self {
132            config,
133            llm: None,
134            agent_provider: None,
135            agent_router: None,
136            executors: Vec::new(),
137        }
138    }
139
140    /// 设置LLM提供者
141    pub fn with_llm(mut self, llm: Arc<dyn LLMProvider>) -> Self {
142        self.llm = Some(llm);
143        self
144    }
145
146    /// 设置Agent提供者
147    pub fn with_agent_provider(mut self, provider: Arc<dyn AgentProvider>) -> Self {
148        self.agent_provider = Some(provider);
149        self
150    }
151
152    /// 设置Agent路由器
153    pub fn with_agent_router(mut self, router: Arc<dyn AgentRouter>) -> Self {
154        self.agent_router = Some(router);
155        self
156    }
157
158    /// 添加执行器
159    pub fn with_executor(mut self, executor: AgentInfo) -> Self {
160        self.executors.push(executor);
161        self
162    }
163
164    /// 获取默认系统提示词
165    fn default_system_prompt(&self) -> &'static str {
166        r#"你是一个专业的项目秘书Agent,负责帮助用户管理任务和协调工作。
167
168你的主要职责包括:
1691. 接收用户的想法和需求,记录为TODO任务
1702. 与用户交互澄清需求,生成结构化的项目需求文档
1713. 根据需求分析,将任务分配给合适的执行Agent
1724. 监控任务执行进度,在需要时请求用户决策
1735. 汇总执行结果,生成汇报并更新TODO状态
174
175你应该:
176- 始终保持专业、礼貌的态度
177- 主动询问澄清模糊的需求
178- 合理评估任务优先级
179- 及时汇报重要进展
180- 在遇到需要人类决策的问题时,清晰地呈现选项"#
181    }
182
183    // =========================================================================
184    // 阶段处理方法
185    // =========================================================================
186
187    /// 阶段1: 处理新想法
188    async fn handle_idea(
189        &self,
190        content: &str,
191        priority: Option<TodoPriority>,
192        metadata: Option<HashMap<String, String>>,
193        ctx: &mut SecretaryContext<DefaultSecretaryState>,
194    ) -> anyhow::Result<Vec<DefaultOutput>> {
195        let mut outputs = Vec::new();
196
197        // 创建Todo
198        let todo = ctx
199            .state_mut()
200            .todo_manager
201            .receive_idea(content, priority, metadata)
202            .await;
203
204        outputs.push(DefaultOutput::Acknowledgment {
205            message: format!(
206                "已记录您的需求,任务ID: {}。优先级: {:?}",
207                todo.id, todo.priority
208            ),
209        });
210
211        tracing::info!("Received idea: {} -> {}", todo.id, content);
212
213        // 自动澄清
214        if self.config.auto_clarify {
215            let clarify_outputs = self.clarify_requirement_internal(&todo.id, ctx).await?;
216            outputs.extend(clarify_outputs);
217        }
218
219        Ok(outputs)
220    }
221
222    /// 阶段2: 澄清需求
223    async fn clarify_requirement_internal(
224        &self,
225        todo_id: &str,
226        ctx: &mut SecretaryContext<DefaultSecretaryState>,
227    ) -> anyhow::Result<Vec<DefaultOutput>> {
228        let mut outputs = Vec::new();
229
230        let todo = ctx
231            .state()
232            .todo_manager
233            .get_todo(todo_id)
234            .await
235            .ok_or_else(|| anyhow::anyhow!("Todo not found: {}", todo_id))?;
236
237        ctx.state_mut()
238            .todo_manager
239            .update_status(todo_id, TodoStatus::Clarifying)
240            .await;
241
242        // 生成需求文档 - 优先使用LLM
243        let requirement = if let Some(ref llm) = self.llm {
244            tracing::info!("Using LLM for requirement clarification");
245
246            // 构建对话历史
247            let mut conversation = ConversationHistory::new();
248
249            // 系统提示词
250            conversation.add_system(
251                "你是一个专业的需求分析师,请将用户的需求想法转换为结构化的项目需求文档。",
252            );
253
254            // 用户需求
255            conversation.add_user(format!("用户需求: {}", todo.raw_idea));
256
257            // 发送请求给LLM
258            let response = llm.chat(conversation.to_vec()).await?;
259            tracing::info!("LLM response: {}", response);
260
261            // 解析LLM的JSON响应
262            serde_json::from_str::<ProjectRequirement>(response.as_str())?
263        } else {
264            // 回退到快速澄清
265            ctx.state()
266                .clarifier
267                .quick_clarify(todo_id, &todo.raw_idea)
268                .await?
269        };
270
271        ctx.state_mut()
272            .todo_manager
273            .set_requirement(todo_id, requirement.clone())
274            .await;
275
276        outputs.push(DefaultOutput::Acknowledgment {
277            message: format!(
278                "需求已分析完成:\n标题: {}\n子任务数: {}\n验收标准: {} 条",
279                requirement.title,
280                requirement.subtasks.len(),
281                requirement.acceptance_criteria.len()
282            ),
283        });
284
285        // 自动分配
286        if self.config.auto_dispatch {
287            let dispatch_outputs = self.dispatch_task_internal(todo_id, ctx).await?;
288            outputs.extend(dispatch_outputs);
289        }
290
291        Ok(outputs)
292    }
293
294    /// 阶段3: 分配任务
295    async fn dispatch_task_internal(
296        &self,
297        todo_id: &str,
298        ctx: &mut SecretaryContext<DefaultSecretaryState>,
299    ) -> anyhow::Result<Vec<DefaultOutput>> {
300        let mut outputs = Vec::new();
301
302        let todo = ctx
303            .state()
304            .todo_manager
305            .get_todo(todo_id)
306            .await
307            .ok_or_else(|| anyhow::anyhow!("Todo not found: {}", todo_id))?;
308
309        let requirement = todo
310            .clarified_requirement
311            .ok_or_else(|| anyhow::anyhow!("Requirement not clarified for: {}", todo_id))?;
312
313        // 检查可用执行器
314        let executors = ctx.state().coordinator.list_available_executors().await;
315        if executors.is_empty() {
316            outputs.push(DefaultOutput::Message {
317                content: "当前没有可用的执行Agent,任务将等待分配。".to_string(),
318            });
319            return Ok(outputs);
320        }
321
322        // 准备上下文
323        let mut context = HashMap::new();
324        context.insert("todo_id".to_string(), todo_id.to_string());
325        context.insert("raw_idea".to_string(), todo.raw_idea.clone());
326
327        // 分配任务
328        let results = ctx
329            .state()
330            .coordinator
331            .dispatch_requirement(&requirement, context)
332            .await?;
333
334        // 记录分配
335        let agent_ids: Vec<String> = results.iter().map(|r| r.agent_id.clone()).collect();
336        ctx.state_mut()
337            .todo_manager
338            .assign_agents(todo_id, agent_ids.clone())
339            .await;
340
341        // 开始监控
342        for result in &results {
343            ctx.state()
344                .monitor
345                .start_monitoring(&result.subtask_id, &result.agent_id)
346                .await;
347        }
348
349        ctx.state_mut()
350            .todo_manager
351            .update_status(todo_id, TodoStatus::InProgress)
352            .await;
353
354        outputs.push(DefaultOutput::Acknowledgment {
355            message: format!(
356                "任务已分配给 {} 个执行Agent: {}",
357                results.len(),
358                agent_ids.join(", ")
359            ),
360        });
361
362        Ok(outputs)
363    }
364
365    /// 处理决策响应
366    async fn handle_decision(
367        &self,
368        decision_id: &str,
369        selected_option: usize,
370        comment: Option<String>,
371        ctx: &mut SecretaryContext<DefaultSecretaryState>,
372    ) -> anyhow::Result<Vec<DefaultOutput>> {
373        ctx.state()
374            .monitor
375            .submit_human_response(decision_id, selected_option, comment)
376            .await?;
377
378        Ok(vec![DefaultOutput::Acknowledgment {
379            message: format!(
380                "决策 {} 已记录,选择了选项 {}",
381                decision_id, selected_option
382            ),
383        }])
384    }
385
386    /// 处理查询
387    async fn handle_query(
388        &self,
389        query: QueryType,
390        ctx: &mut SecretaryContext<DefaultSecretaryState>,
391    ) -> anyhow::Result<Vec<DefaultOutput>> {
392        match query {
393            QueryType::ListTodos { filter } => {
394                let todos = if let Some(status) = filter {
395                    ctx.state().todo_manager.list_by_status(status).await
396                } else {
397                    ctx.state().todo_manager.list_todos().await
398                };
399
400                let summary = if todos.is_empty() {
401                    "当前没有任务。".to_string()
402                } else {
403                    let mut s = format!("共 {} 个任务:\n", todos.len());
404                    for todo in &todos {
405                        s.push_str(&format!(
406                            "- {} [{:?}] {:?}: {}\n",
407                            todo.id,
408                            todo.priority,
409                            todo.status,
410                            todo.raw_idea.chars().take(30).collect::<String>()
411                        ));
412                    }
413                    s
414                };
415
416                Ok(vec![DefaultOutput::Message { content: summary }])
417            }
418            QueryType::GetTodo { todo_id } => {
419                if let Some(todo) = ctx.state().todo_manager.get_todo(&todo_id).await {
420                    let detail = format!(
421                        "任务详情:\nID: {}\n需求: {}\n状态: {:?}\n优先级: {:?}\n分配Agent: {:?}",
422                        todo.id, todo.raw_idea, todo.status, todo.priority, todo.assigned_agents
423                    );
424                    Ok(vec![DefaultOutput::Message { content: detail }])
425                } else {
426                    Ok(vec![DefaultOutput::Error {
427                        message: format!("未找到任务: {}", todo_id),
428                    }])
429                }
430            }
431            QueryType::Statistics => {
432                let stats = ctx.state().todo_manager.get_statistics().await;
433                let summary = format!(
434                    "统计信息:\n{}",
435                    stats
436                        .iter()
437                        .map(|(k, v)| format!("- {}: {}", k, v))
438                        .collect::<Vec<_>>()
439                        .join("\n")
440                );
441                Ok(vec![DefaultOutput::Message { content: summary }])
442            }
443            QueryType::PendingDecisions => {
444                let decisions = ctx.state().monitor.get_pending_decisions().await;
445                if decisions.is_empty() {
446                    Ok(vec![DefaultOutput::Message {
447                        content: "当前没有待处理的决策。".to_string(),
448                    }])
449                } else {
450                    Ok(decisions
451                        .into_iter()
452                        .map(|d| DefaultOutput::DecisionRequired { decision: d })
453                        .collect())
454                }
455            }
456            QueryType::Reports { report_type } => {
457                let reports = if let Some(rt) = report_type {
458                    ctx.state().reporter.get_by_type(rt).await
459                } else {
460                    ctx.state().reporter.get_history().await
461                };
462
463                if reports.is_empty() {
464                    Ok(vec![DefaultOutput::Message {
465                        content: "暂无汇报历史。".to_string(),
466                    }])
467                } else {
468                    Ok(reports
469                        .into_iter()
470                        .map(|r| DefaultOutput::Report { report: r })
471                        .collect())
472                }
473            }
474        }
475    }
476
477    /// 处理命令
478    async fn handle_command(
479        &self,
480        cmd: SecretaryCommand,
481        ctx: &mut SecretaryContext<DefaultSecretaryState>,
482    ) -> anyhow::Result<Vec<DefaultOutput>> {
483        match cmd {
484            SecretaryCommand::Clarify { todo_id } => {
485                self.clarify_requirement_internal(&todo_id, ctx).await
486            }
487            SecretaryCommand::Dispatch { todo_id } => {
488                self.dispatch_task_internal(&todo_id, ctx).await
489            }
490            SecretaryCommand::Cancel { todo_id, reason } => {
491                ctx.state_mut()
492                    .todo_manager
493                    .update_status(&todo_id, TodoStatus::Cancelled)
494                    .await;
495                Ok(vec![DefaultOutput::Acknowledgment {
496                    message: format!("任务 {} 已取消,原因: {}", todo_id, reason),
497                }])
498            }
499            SecretaryCommand::GenerateReport { report_type } => {
500                let todos = ctx.state().todo_manager.list_todos().await;
501                let report = match report_type {
502                    ReportType::Progress => {
503                        let stats = ctx.state().todo_manager.get_statistics().await;
504                        let stats_json: HashMap<String, serde_json::Value> = stats
505                            .into_iter()
506                            .map(|(k, v)| (k, serde_json::json!(v)))
507                            .collect();
508                        ctx.state()
509                            .reporter
510                            .generate_progress_report(&todos, stats_json)
511                            .await
512                    }
513                    ReportType::DailySummary => {
514                        ctx.state().reporter.generate_daily_summary(&todos).await
515                    }
516                    _ => {
517                        let stats = ctx.state().todo_manager.get_statistics().await;
518                        let stats_json: HashMap<String, serde_json::Value> = stats
519                            .into_iter()
520                            .map(|(k, v)| (k, serde_json::json!(v)))
521                            .collect();
522                        ctx.state()
523                            .reporter
524                            .generate_progress_report(&todos, stats_json)
525                            .await
526                    }
527                };
528                Ok(vec![DefaultOutput::Report { report }])
529            }
530            SecretaryCommand::Pause | SecretaryCommand::Resume | SecretaryCommand::Shutdown => {
531                // 这些命令由核心引擎处理
532                Ok(vec![DefaultOutput::Acknowledgment {
533                    message: "命令已收到".to_string(),
534                }])
535            }
536        }
537    }
538}
539
540#[async_trait]
541impl SecretaryBehavior for DefaultSecretaryBehavior {
542    type Input = DefaultInput;
543    type Output = DefaultOutput;
544    type State = DefaultSecretaryState;
545
546    fn initial_state(&self) -> Self::State {
547        let mut state = DefaultSecretaryState::new(
548            self.config.clarification_strategy.clone(),
549            self.config.dispatch_strategy.clone(),
550            self.config.report_config.clone(),
551        );
552
553        // 设置Agent提供者和路由器
554        if let Some(ref provider) = self.agent_provider {
555            state.coordinator.set_agent_provider(provider.clone());
556        }
557        if let Some(ref router) = self.agent_router {
558            state.coordinator.set_agent_router(router.clone());
559        }
560
561        // 初始化系统提示词
562        let system_prompt = self
563            .config
564            .system_prompt
565            .as_deref()
566            .unwrap_or_else(|| self.default_system_prompt());
567        state
568            .conversation_history
569            .push(ChatMessage::system(system_prompt));
570
571        state
572    }
573
574    fn welcome_message(&self) -> Option<Self::Output> {
575        Some(DefaultOutput::Message {
576            content: format!(
577                "您好!我是{},您的智能秘书。我可以帮您管理任务、协调工作。请告诉我您的需求。",
578                self.config.name
579            ),
580        })
581    }
582
583    async fn handle_input(
584        &self,
585        input: Self::Input,
586        ctx: &mut SecretaryContext<Self::State>,
587    ) -> anyhow::Result<Vec<Self::Output>> {
588        match input {
589            DefaultInput::Idea {
590                content,
591                priority,
592                metadata,
593            } => self.handle_idea(&content, priority, metadata, ctx).await,
594            DefaultInput::Decision {
595                decision_id,
596                selected_option,
597                comment,
598            } => {
599                self.handle_decision(&decision_id, selected_option, comment, ctx)
600                    .await
601            }
602            DefaultInput::Query(query) => self.handle_query(query, ctx).await,
603            DefaultInput::Command(cmd) => self.handle_command(cmd, ctx).await,
604        }
605    }
606
607    async fn periodic_check(
608        &self,
609        ctx: &mut SecretaryContext<Self::State>,
610    ) -> anyhow::Result<Vec<Self::Output>> {
611        // 检查待处理的决策
612        let pending_decisions = ctx.state().monitor.get_pending_decisions().await;
613        Ok(pending_decisions
614            .into_iter()
615            .map(|d| DefaultOutput::DecisionRequired { decision: d })
616            .collect())
617    }
618
619    fn handle_error(&self, error: &anyhow::Error) -> Option<Self::Output> {
620        Some(DefaultOutput::Error {
621            message: format!("处理请求时出错: {}", error),
622        })
623    }
624}
625
626// =============================================================================
627// 构建器
628// =============================================================================
629
630/// 默认秘书构建器
631pub struct DefaultSecretaryBuilder {
632    config: DefaultSecretaryConfig,
633    llm: Option<Arc<dyn LLMProvider>>,
634    agent_provider: Option<Arc<dyn AgentProvider>>,
635    agent_router: Option<Arc<dyn AgentRouter>>,
636    executors: Vec<AgentInfo>,
637}
638
639impl DefaultSecretaryBuilder {
640    /// 创建新的构建器
641    pub fn new() -> Self {
642        Self {
643            config: DefaultSecretaryConfig::default(),
644            llm: None,
645            agent_provider: None,
646            agent_router: None,
647            executors: Vec::new(),
648        }
649    }
650
651    /// 设置名称
652    pub fn with_name(mut self, name: impl Into<String>) -> Self {
653        self.config.name = name.into();
654        self
655    }
656
657    /// 设置LLM
658    pub fn with_llm(mut self, llm: Arc<dyn LLMProvider>) -> Self {
659        self.llm = Some(llm);
660        self
661    }
662
663    /// 设置澄清策略
664    pub fn with_clarification_strategy(mut self, strategy: ClarificationStrategy) -> Self {
665        self.config.clarification_strategy = strategy;
666        self
667    }
668
669    /// 设置分配策略
670    pub fn with_dispatch_strategy(mut self, strategy: DispatchStrategy) -> Self {
671        self.config.dispatch_strategy = strategy;
672        self
673    }
674
675    /// 设置是否自动澄清
676    pub fn with_auto_clarify(mut self, auto: bool) -> Self {
677        self.config.auto_clarify = auto;
678        self
679    }
680
681    /// 设置是否自动分配
682    pub fn with_auto_dispatch(mut self, auto: bool) -> Self {
683        self.config.auto_dispatch = auto;
684        self
685    }
686
687    /// 设置系统提示词
688    pub fn with_system_prompt(mut self, prompt: impl Into<String>) -> Self {
689        self.config.system_prompt = Some(prompt.into());
690        self
691    }
692
693    /// 设置Agent提供者
694    pub fn with_agent_provider(mut self, provider: Arc<dyn AgentProvider>) -> Self {
695        self.agent_provider = Some(provider);
696        self
697    }
698
699    /// 设置Agent路由器
700    pub fn with_agent_router(mut self, router: Arc<dyn AgentRouter>) -> Self {
701        self.agent_router = Some(router);
702        self
703    }
704
705    /// 添加执行器
706    pub fn with_executor(mut self, executor: AgentInfo) -> Self {
707        self.executors.push(executor);
708        self
709    }
710
711    /// 构建秘书行为
712    pub fn build(self) -> DefaultSecretaryBehavior {
713        let mut behavior = DefaultSecretaryBehavior::new(self.config);
714
715        if let Some(llm) = self.llm {
716            behavior = behavior.with_llm(llm);
717        }
718        if let Some(provider) = self.agent_provider {
719            behavior = behavior.with_agent_provider(provider);
720        }
721        if let Some(router) = self.agent_router {
722            behavior = behavior.with_agent_router(router);
723        }
724        for executor in self.executors {
725            behavior = behavior.with_executor(executor);
726        }
727
728        behavior
729    }
730}
731
732impl Default for DefaultSecretaryBuilder {
733    fn default() -> Self {
734        Self::new()
735    }
736}
737
738#[cfg(test)]
739mod tests {
740    use super::*;
741
742    #[test]
743    fn test_builder() {
744        let behavior = DefaultSecretaryBuilder::new()
745            .with_name("测试秘书")
746            .with_auto_clarify(false)
747            .build();
748
749        assert!(!behavior.config.auto_clarify);
750        assert_eq!(behavior.config.name, "测试秘书");
751    }
752
753    #[test]
754    fn test_welcome_message() {
755        let behavior = DefaultSecretaryBuilder::new().with_name("小助手").build();
756
757        let welcome = behavior.welcome_message().unwrap();
758        match welcome {
759            DefaultOutput::Message { content } => {
760                assert!(content.contains("小助手"));
761            }
762            _ => panic!("Expected Message output"),
763        }
764    }
765}