Skip to main content

j_agent/tools/
ignore_message.rs

1use crate::teammate::TeammateManager;
2use crate::tools::{PlanDecision, Tool, ToolResult, parse_tool_args, schema_to_tool_params};
3use schemars::JsonSchema;
4use serde::Deserialize;
5use serde_json::Value;
6use std::borrow::Cow;
7use std::sync::{Arc, Mutex, atomic::AtomicBool};
8
9#[derive(Deserialize, JsonSchema)]
10struct IgnoreMessageParams {
11    /// Optional: brief one-line note for your own log; not broadcast to anyone.
12    #[serde(default)]
13    #[allow(dead_code)]
14    reason: Option<String>,
15}
16
17/// IgnoreMessage 工具:显式声明「我看到了广播但选择不响应」
18///
19/// 用于避免被无关 broadcast 唤醒后被迫凑话回应(thrash)。
20/// 调用本工具时,本轮的 assistant 文本不会被广播到聊天室,
21/// 因此不会触发其他 agent 的 wake_flag,loop 自然回到 idle。
22///
23/// teammate 与 Main 共用此工具:
24/// - teammate 通过 `teammate_manager=None` 注册,始终可用
25/// - Main 通过 `teammate_manager=Some(_)` 注册,仅在有活跃 teammate 时可用
26pub struct IgnoreMessageTool {
27    pub teammate_manager: Option<Arc<Mutex<TeammateManager>>>,
28}
29
30impl IgnoreMessageTool {
31    pub const NAME: &'static str = "IgnoreMessage";
32}
33
34impl Tool for IgnoreMessageTool {
35    fn name(&self) -> &str {
36        Self::NAME
37    }
38
39    fn description(&self) -> Cow<'_, str> {
40        r#"
41        Acknowledge incoming broadcasts without producing any reply.
42
43        Call this when you were notified of broadcasts or @mentions but, after
44        reading them, decided no response is needed. This keeps you idle without
45        sending a noisy "ok"/"got it" message that would wake other agents.
46
47        Usage:
48        - reason: Optional one-line note for your own log (NOT broadcast).
49
50        Examples:
51        {}
52        {"reason": "B's progress update doesn't require my input"}
53        {"reason": "Noted schema change, does not affect my current task"}
54
55        IMPORTANT:
56        - Calling IgnoreMessage suppresses the prose of THIS turn — do NOT also
57          write any reply text; just call the tool.
58        - If a real response is needed, use SendMessage instead.
59        - You will remain idle until @mentioned again or until the chat is closed.
60        "#
61        .into()
62    }
63
64    fn parameters_schema(&self) -> Value {
65        schema_to_tool_params::<IgnoreMessageParams>()
66    }
67
68    fn execute(&self, arguments: &str, _cancelled: &Arc<AtomicBool>) -> ToolResult {
69        // Validate args (reason is optional and unused at runtime; we just ensure parse OK)
70        let _params: IgnoreMessageParams = match parse_tool_args(arguments) {
71            Ok(p) => p,
72            Err(e) => return e,
73        };
74
75        ToolResult {
76            output: "Messages acknowledged; no reply sent. Returning to idle.".to_string(),
77            is_error: false,
78            images: vec![],
79            plan_decision: PlanDecision::None,
80        }
81    }
82
83    fn requires_confirmation(&self) -> bool {
84        false
85    }
86
87    fn is_available(&self) -> bool {
88        match &self.teammate_manager {
89            Some(mgr) => mgr
90                .lock()
91                .map(|m| m.has_active_teammates())
92                .unwrap_or(false),
93            None => true,
94        }
95    }
96}