feat: add silent scheduler agent tasks

This commit is contained in:
AaronZ345
2026-07-14 12:08:37 +08:00
parent eeb4b7981e
commit d5fdd644cf
3 changed files with 107 additions and 0 deletions

View File

@@ -255,6 +255,12 @@ def _execute_agent_task(task: dict, agent_bridge) -> bool:
logger.error(f"[Scheduler] Task {task['id']}: No result from agent execution") logger.error(f"[Scheduler] Task {task['id']}: No result from agent execution")
return True # agent ran but produced nothing; don't loop return True # agent ran but produced nothing; don't loop
if action.get("silent", False):
logger.info(
f"[Scheduler] Task {task['id']} executed successfully in silent mode"
)
return True
from channel.channel_factory import create_channel from channel.channel_factory import create_channel
channel = create_channel(channel_type) channel = create_channel(channel_type)
if not channel: if not channel:

View File

@@ -24,6 +24,7 @@ class SchedulerTool(BaseTool):
"⚠️ 重要:仅当需要「定时/提醒/每天/每周/X分钟后/X点」等延迟或周期执行时才使用此工具。" "⚠️ 重要:仅当需要「定时/提醒/每天/每周/X分钟后/X点」等延迟或周期执行时才使用此工具。"
"使用方法:\n" "使用方法:\n"
"- 创建action='create', name='任务名', message/ai_task='内容', schedule_type='once/interval/cron', schedule_value='...'\n" "- 创建action='create', name='任务名', message/ai_task='内容', schedule_type='once/interval/cron', schedule_value='...'\n"
"- 静默AI任务创建 ai_task 时设置 silent=true任务会正常执行但不向聊天发送结果\n"
"- 查询action='list' / action='get', task_id='任务ID'\n" "- 查询action='list' / action='get', task_id='任务ID'\n"
"- 管理action='delete/enable/disable', task_id='任务ID'\n\n" "- 管理action='delete/enable/disable', task_id='任务ID'\n\n"
"调度类型:\n" "调度类型:\n"
@@ -64,6 +65,11 @@ class SchedulerTool(BaseTool):
"schedule_value": { "schedule_value": {
"type": "string", "type": "string",
"description": "调度值: cron表达式/间隔秒数/时间(+5s,+10m,+1h或ISO格式)" "description": "调度值: cron表达式/间隔秒数/时间(+5s,+10m,+1h或ISO格式)"
},
"silent": {
"type": "boolean",
"default": False,
"description": "静默模式仅用于AI任务: true时正常执行AI任务但不向用户会话发送结果"
} }
}, },
"required": ["action"] "required": ["action"]
@@ -184,6 +190,8 @@ class SchedulerTool(BaseTool):
"channel_type": self.config.get("channel_type", "unknown"), "channel_type": self.config.get("channel_type", "unknown"),
"notify_session_id": notify_session_id, "notify_session_id": notify_session_id,
} }
if kwargs.get("silent", False):
action["silent"] = True
# 针对钉钉单聊,额外存储 sender_staff_id # 针对钉钉单聊,额外存储 sender_staff_id
msg = context.kwargs.get("msg") msg = context.kwargs.get("msg")

View File

@@ -0,0 +1,93 @@
"""Regression tests for silent scheduled agent tasks."""
import os
import sys
import unittest
from types import SimpleNamespace
from unittest.mock import patch
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from agent.tools.scheduler.integration import _execute_agent_task
from agent.tools.scheduler.scheduler_tool import SchedulerTool
class _Context(dict):
kwargs = {}
class _TaskStore:
def __init__(self):
self.added = []
def add_task(self, task):
self.added.append(task)
class _AgentBridge:
def __init__(self, content="maintenance complete"):
self.content = content
self.calls = []
def agent_reply(self, task_description, **kwargs):
self.calls.append((task_description, kwargs))
return SimpleNamespace(content=self.content)
class TestSchedulerSilentMode(unittest.TestCase):
def test_schema_exposes_silent_for_agent_tasks(self):
silent = SchedulerTool.params["properties"]["silent"]
self.assertEqual(silent["type"], "boolean")
self.assertFalse(silent["default"])
self.assertIn("AI", silent["description"])
def test_create_persists_silent_on_agent_task(self):
tool = SchedulerTool({"channel_type": "web"})
store = _TaskStore()
tool.task_store = store
tool.current_context = _Context(
receiver="user-1",
session_id="session-1",
isgroup=False,
)
result = tool.execute(
{
"action": "create",
"name": "refresh token",
"ai_task": "refresh the token",
"schedule_type": "interval",
"schedule_value": "3000",
"silent": True,
}
)
self.assertEqual(result.status, "success")
self.assertEqual(len(store.added), 1)
self.assertIs(store.added[0]["action"]["silent"], True)
def test_silent_agent_task_executes_without_delivery(self):
bridge = _AgentBridge()
task = {
"id": "task-1",
"action": {
"type": "agent_task",
"task_description": "rotate logs",
"receiver": "user-1",
"is_group": False,
"channel_type": "web",
"silent": True,
},
}
with patch("channel.channel_factory.create_channel") as create_channel:
result = _execute_agent_task(task, bridge)
self.assertTrue(result)
self.assertEqual(len(bridge.calls), 1)
create_channel.assert_not_called()
if __name__ == "__main__":
unittest.main()