Skip to main content

j_agent/tools/
work_done.rs

1use crate::agent::thread_identity::current_agent_name;
2use crate::teammate::TeammateManager;
3use crate::tools::{PlanDecision, Tool, ToolResult, parse_tool_args, schema_to_tool_params};
4use schemars::JsonSchema;
5use serde::Deserialize;
6use serde_json::Value;
7use std::borrow::Cow;
8use std::sync::{
9    Arc, Mutex,
10    atomic::{AtomicBool, Ordering},
11};
12
13#[derive(Deserialize, JsonSchema)]
14struct WorkDoneParams {
15    /// Short summary of what you accomplished (one or two sentences)
16    #[serde(default)]
17    summary: Option<String>,
18}
19
20/// WorkDone 工具:teammate 明确声明自己完成工作并进入终态
21///
22/// 调用后:
23/// - set work_done=true,teammate_loop 下次检查时 break 主循环
24/// - 自动广播一条 `<self> [work completed] summary` 给团队(帮 @Main 感知)
25pub struct WorkDoneTool {
26    /// 该 teammate 的 work_done 标志(与 TeammateHandle 共享)
27    pub work_done: Arc<AtomicBool>,
28    pub teammate_manager: Arc<Mutex<TeammateManager>>,
29}
30
31impl WorkDoneTool {
32    pub const NAME: &'static str = "WorkDone";
33}
34
35impl Tool for WorkDoneTool {
36    fn name(&self) -> &str {
37        Self::NAME
38    }
39
40    fn description(&self) -> Cow<'_, str> {
41        r#"
42        Declare that you have finished your assigned work and exit the chat loop.
43
44        Call this when your role's task is complete and you don't need to do anything else.
45        Once called, you will stop responding to general messages — the team will see you as finished.
46
47        IMPORTANT:
48        - Before calling WorkDone, send a SendMessage to @Main summarizing your results.
49        - If another agent @mentions you after WorkDone, you will be re-activated and can continue working.
50        - If another agent might still need you, DO NOT call WorkDone — just stay idle and wait.
51        - Do not call WorkDone just because the conversation is quiet; only call when your role's task is objectively done.
52
53        Usage:
54        {"summary": "Frontend pages complete, all components in src/components/"}
55        "#.into()
56    }
57
58    fn parameters_schema(&self) -> Value {
59        schema_to_tool_params::<WorkDoneParams>()
60    }
61
62    fn execute(&self, arguments: &str, _cancelled: &Arc<AtomicBool>) -> ToolResult {
63        let params: WorkDoneParams = match parse_tool_args(arguments) {
64            Ok(p) => p,
65            Err(e) => return e,
66        };
67
68        let from = current_agent_name();
69
70        // 通过 broadcast 通知所有 agent(包括其他 teammate 和 Main)
71        // broadcast 会处理 display/context 双通道 + main_agent_inbox 唤醒信号
72        let broadcast_text = match params.summary.as_deref() {
73            Some(s) if !s.trim().is_empty() => {
74                format!("[work completed] {}", s.trim())
75            }
76            _ => "[work completed]".to_string(),
77        };
78        if let Ok(manager) = self.teammate_manager.lock() {
79            manager.broadcast(&from, &broadcast_text, None);
80        }
81
82        self.work_done.store(true, Ordering::Relaxed);
83
84        ToolResult {
85            output: format!("Teammate '{}' marked as done; exiting chat loop.", from),
86            is_error: false,
87            images: vec![],
88            plan_decision: PlanDecision::None,
89        }
90    }
91
92    fn requires_confirmation(&self) -> bool {
93        false
94    }
95}