AstrBot 4.13.2__py3-none-any.whl → 4.14.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. astrbot/builtin_stars/astrbot/main.py +0 -6
  2. astrbot/builtin_stars/session_controller/main.py +1 -2
  3. astrbot/cli/__init__.py +1 -1
  4. astrbot/core/agent/agent.py +2 -1
  5. astrbot/core/agent/handoff.py +14 -1
  6. astrbot/core/agent/runners/tool_loop_agent_runner.py +14 -1
  7. astrbot/core/agent/tool.py +5 -0
  8. astrbot/core/astr_agent_run_util.py +21 -3
  9. astrbot/core/astr_agent_tool_exec.py +178 -3
  10. astrbot/core/astr_main_agent.py +980 -0
  11. astrbot/core/astr_main_agent_resources.py +453 -0
  12. astrbot/core/computer/computer_client.py +10 -1
  13. astrbot/core/computer/tools/fs.py +22 -14
  14. astrbot/core/config/default.py +84 -58
  15. astrbot/core/core_lifecycle.py +43 -1
  16. astrbot/core/cron/__init__.py +3 -0
  17. astrbot/core/cron/events.py +67 -0
  18. astrbot/core/cron/manager.py +376 -0
  19. astrbot/core/db/__init__.py +60 -0
  20. astrbot/core/db/po.py +31 -0
  21. astrbot/core/db/sqlite.py +120 -0
  22. astrbot/core/event_bus.py +0 -1
  23. astrbot/core/message/message_event_result.py +21 -3
  24. astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +111 -580
  25. astrbot/core/pipeline/scheduler.py +0 -2
  26. astrbot/core/platform/astr_message_event.py +5 -5
  27. astrbot/core/platform/platform.py +9 -0
  28. astrbot/core/platform/platform_metadata.py +2 -0
  29. astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +1 -0
  30. astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +1 -0
  31. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +1 -0
  32. astrbot/core/platform/sources/webchat/webchat_adapter.py +1 -0
  33. astrbot/core/platform/sources/wecom/wecom_adapter.py +1 -0
  34. astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +1 -0
  35. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +1 -0
  36. astrbot/core/provider/entities.py +1 -1
  37. astrbot/core/skills/skill_manager.py +9 -8
  38. astrbot/core/star/context.py +8 -0
  39. astrbot/core/star/filter/custom_filter.py +3 -3
  40. astrbot/core/star/register/star_handler.py +1 -1
  41. astrbot/core/subagent_orchestrator.py +96 -0
  42. astrbot/core/tools/cron_tools.py +174 -0
  43. astrbot/core/utils/history_saver.py +31 -0
  44. astrbot/core/utils/trace.py +4 -0
  45. astrbot/dashboard/routes/__init__.py +4 -0
  46. astrbot/dashboard/routes/cron.py +174 -0
  47. astrbot/dashboard/routes/log.py +36 -0
  48. astrbot/dashboard/routes/plugin.py +11 -0
  49. astrbot/dashboard/routes/skills.py +12 -37
  50. astrbot/dashboard/routes/subagent.py +117 -0
  51. astrbot/dashboard/routes/tools.py +41 -14
  52. astrbot/dashboard/server.py +3 -0
  53. {astrbot-4.13.2.dist-info → astrbot-4.14.1.dist-info}/METADATA +21 -2
  54. {astrbot-4.13.2.dist-info → astrbot-4.14.1.dist-info}/RECORD +57 -51
  55. astrbot/builtin_stars/astrbot/process_llm_request.py +0 -308
  56. astrbot/builtin_stars/reminder/main.py +0 -266
  57. astrbot/builtin_stars/reminder/metadata.yaml +0 -4
  58. astrbot/core/pipeline/process_stage/utils.py +0 -219
  59. {astrbot-4.13.2.dist-info → astrbot-4.14.1.dist-info}/WHEEL +0 -0
  60. {astrbot-4.13.2.dist-info → astrbot-4.14.1.dist-info}/entry_points.txt +0 -0
  61. {astrbot-4.13.2.dist-info → astrbot-4.14.1.dist-info}/licenses/LICENSE +0 -0
@@ -5,7 +5,7 @@ from typing import Any, TypedDict
5
5
 
6
6
  from astrbot.core.utils.astrbot_path import get_astrbot_data_path
7
7
 
8
- VERSION = "4.13.2"
8
+ VERSION = "4.14.1"
9
9
  DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
10
10
 
11
11
  WEBHOOK_SUPPORTED_PLATFORMS = [
@@ -91,7 +91,7 @@ DEFAULT_CONFIG = {
91
91
  "3. If there was an initial user goal, state it first and describe the current progress/status.\n"
92
92
  "4. Write the summary in the user's language.\n"
93
93
  ),
94
- "llm_compress_keep_recent": 4,
94
+ "llm_compress_keep_recent": 6,
95
95
  "llm_compress_provider_id": "",
96
96
  "max_context_length": -1,
97
97
  "dequeue_context_length": 1,
@@ -114,15 +114,31 @@ DEFAULT_CONFIG = {
114
114
  "provider": "moonshotai",
115
115
  "moonshotai_api_key": "",
116
116
  },
117
+ "proactive_capability": {
118
+ "add_cron_tools": True,
119
+ },
120
+ "computer_use_runtime": "local",
117
121
  "sandbox": {
118
- "enable": False,
119
122
  "booter": "shipyard",
120
123
  "shipyard_endpoint": "",
121
124
  "shipyard_access_token": "",
122
125
  "shipyard_ttl": 3600,
123
126
  "shipyard_max_sessions": 10,
124
127
  },
125
- "skills": {"runtime": "sandbox"},
128
+ },
129
+ # SubAgent orchestrator mode:
130
+ # - main_enable = False: disabled; main LLM mounts tools normally (persona selection).
131
+ # - main_enable = True: enabled; main LLM will include handoff tools and can optionally
132
+ # remove tools that are duplicated on subagents via remove_main_duplicate_tools.
133
+ "subagent_orchestrator": {
134
+ "main_enable": False,
135
+ "remove_main_duplicate_tools": False,
136
+ "router_system_prompt": (
137
+ "You are a task router. Your job is to chat naturally, recognize user intent, "
138
+ "and delegate work to the most suitable subagent using transfer_to_* tools. "
139
+ "Do not try to use domain tools yourself. If no subagent fits, respond directly."
140
+ ),
141
+ "agents": [],
126
142
  },
127
143
  "provider_stt_settings": {
128
144
  "enable": False,
@@ -185,6 +201,7 @@ DEFAULT_CONFIG = {
185
201
  "log_file_enable": False,
186
202
  "log_file_path": "logs/astrbot.log",
187
203
  "log_file_max_mb": 20,
204
+ "trace_enable": False,
188
205
  "trace_log_enable": False,
189
206
  "trace_log_path": "logs/astrbot.trace.log",
190
207
  "trace_log_max_mb": 20,
@@ -2207,15 +2224,12 @@ CONFIG_METADATA_2 = {
2207
2224
  },
2208
2225
  },
2209
2226
  },
2210
- "skills": {
2227
+ "proactive_capability": {
2211
2228
  "type": "object",
2212
2229
  "items": {
2213
- "enable": {
2230
+ "add_cron_tools": {
2214
2231
  "type": "bool",
2215
2232
  },
2216
- "runtime": {
2217
- "type": "string",
2218
- },
2219
2233
  },
2220
2234
  },
2221
2235
  },
@@ -2490,6 +2504,7 @@ CONFIG_METADATA_3 = {
2490
2504
  },
2491
2505
  "persona": {
2492
2506
  "description": "人格",
2507
+ "hint": "",
2493
2508
  "type": "object",
2494
2509
  "items": {
2495
2510
  "provider_settings.default_personality": {
@@ -2505,6 +2520,7 @@ CONFIG_METADATA_3 = {
2505
2520
  },
2506
2521
  "knowledgebase": {
2507
2522
  "description": "知识库",
2523
+ "hint": "",
2508
2524
  "type": "object",
2509
2525
  "items": {
2510
2526
  "kb_names": {
@@ -2537,6 +2553,7 @@ CONFIG_METADATA_3 = {
2537
2553
  },
2538
2554
  "websearch": {
2539
2555
  "description": "网页搜索",
2556
+ "hint": "",
2540
2557
  "type": "object",
2541
2558
  "items": {
2542
2559
  "provider_settings.web_search": {
@@ -2547,6 +2564,9 @@ CONFIG_METADATA_3 = {
2547
2564
  "description": "网页搜索提供商",
2548
2565
  "type": "string",
2549
2566
  "options": ["default", "tavily", "baidu_ai_search"],
2567
+ "condition": {
2568
+ "provider_settings.web_search": True,
2569
+ },
2550
2570
  },
2551
2571
  "provider_settings.websearch_tavily_key": {
2552
2572
  "description": "Tavily API Key",
@@ -2555,6 +2575,7 @@ CONFIG_METADATA_3 = {
2555
2575
  "hint": "可添加多个 Key 进行轮询。",
2556
2576
  "condition": {
2557
2577
  "provider_settings.websearch_provider": "tavily",
2578
+ "provider_settings.web_search": True,
2558
2579
  },
2559
2580
  },
2560
2581
  "provider_settings.websearch_baidu_app_builder_key": {
@@ -2568,6 +2589,9 @@ CONFIG_METADATA_3 = {
2568
2589
  "provider_settings.web_search_link": {
2569
2590
  "description": "显示来源引用",
2570
2591
  "type": "bool",
2592
+ "condition": {
2593
+ "provider_settings.web_search": True,
2594
+ },
2571
2595
  },
2572
2596
  },
2573
2597
  "condition": {
@@ -2575,45 +2599,17 @@ CONFIG_METADATA_3 = {
2575
2599
  "provider_settings.enable": True,
2576
2600
  },
2577
2601
  },
2578
- # "file_extract": {
2579
- # "description": "文档解析能力 [beta]",
2580
- # "type": "object",
2581
- # "items": {
2582
- # "provider_settings.file_extract.enable": {
2583
- # "description": "启用文档解析能力",
2584
- # "type": "bool",
2585
- # },
2586
- # "provider_settings.file_extract.provider": {
2587
- # "description": "文档解析提供商",
2588
- # "type": "string",
2589
- # "options": ["moonshotai"],
2590
- # "condition": {
2591
- # "provider_settings.file_extract.enable": True,
2592
- # },
2593
- # },
2594
- # "provider_settings.file_extract.moonshotai_api_key": {
2595
- # "description": "Moonshot AI API Key",
2596
- # "type": "string",
2597
- # "condition": {
2598
- # "provider_settings.file_extract.provider": "moonshotai",
2599
- # "provider_settings.file_extract.enable": True,
2600
- # },
2601
- # },
2602
- # },
2603
- # "condition": {
2604
- # "provider_settings.agent_runner_type": "local",
2605
- # "provider_settings.enable": True,
2606
- # },
2607
- # },
2608
- "sandbox": {
2609
- "description": "Agent 沙箱环境",
2602
+ "agent_computer_use": {
2603
+ "description": "Agent Computer Use",
2610
2604
  "hint": "",
2611
2605
  "type": "object",
2612
2606
  "items": {
2613
- "provider_settings.sandbox.enable": {
2614
- "description": "启用沙箱环境",
2615
- "type": "bool",
2616
- "hint": "启用后,Agent 可以使用沙箱环境中的工具和资源,如 Python 代码执行、Shell 等。",
2607
+ "provider_settings.computer_use_runtime": {
2608
+ "description": "Computer Use Runtime",
2609
+ "type": "string",
2610
+ "options": ["none", "local", "sandbox"],
2611
+ "labels": ["无", "本地", "沙箱"],
2612
+ "hint": "选择 Computer Use 运行环境。",
2617
2613
  },
2618
2614
  "provider_settings.sandbox.booter": {
2619
2615
  "description": "沙箱环境驱动器",
@@ -2621,7 +2617,7 @@ CONFIG_METADATA_3 = {
2621
2617
  "options": ["shipyard"],
2622
2618
  "labels": ["Shipyard"],
2623
2619
  "condition": {
2624
- "provider_settings.sandbox.enable": True,
2620
+ "provider_settings.computer_use_runtime": "sandbox",
2625
2621
  },
2626
2622
  },
2627
2623
  "provider_settings.sandbox.shipyard_endpoint": {
@@ -2629,7 +2625,7 @@ CONFIG_METADATA_3 = {
2629
2625
  "type": "string",
2630
2626
  "hint": "Shipyard 服务的 API 访问地址。",
2631
2627
  "condition": {
2632
- "provider_settings.sandbox.enable": True,
2628
+ "provider_settings.computer_use_runtime": "sandbox",
2633
2629
  "provider_settings.sandbox.booter": "shipyard",
2634
2630
  },
2635
2631
  "_special": "check_shipyard_connection",
@@ -2639,7 +2635,7 @@ CONFIG_METADATA_3 = {
2639
2635
  "type": "string",
2640
2636
  "hint": "用于访问 Shipyard 服务的访问令牌。",
2641
2637
  "condition": {
2642
- "provider_settings.sandbox.enable": True,
2638
+ "provider_settings.computer_use_runtime": "sandbox",
2643
2639
  "provider_settings.sandbox.booter": "shipyard",
2644
2640
  },
2645
2641
  },
@@ -2648,7 +2644,7 @@ CONFIG_METADATA_3 = {
2648
2644
  "type": "int",
2649
2645
  "hint": "Shipyard 会话的生存时间(秒)。",
2650
2646
  "condition": {
2651
- "provider_settings.sandbox.enable": True,
2647
+ "provider_settings.computer_use_runtime": "sandbox",
2652
2648
  "provider_settings.sandbox.booter": "shipyard",
2653
2649
  },
2654
2650
  },
@@ -2657,7 +2653,7 @@ CONFIG_METADATA_3 = {
2657
2653
  "type": "int",
2658
2654
  "hint": "Shipyard 最大会话数量。",
2659
2655
  "condition": {
2660
- "provider_settings.sandbox.enable": True,
2656
+ "provider_settings.computer_use_runtime": "sandbox",
2661
2657
  "provider_settings.sandbox.booter": "shipyard",
2662
2658
  },
2663
2659
  },
@@ -2667,16 +2663,45 @@ CONFIG_METADATA_3 = {
2667
2663
  "provider_settings.enable": True,
2668
2664
  },
2669
2665
  },
2670
- "skills": {
2671
- "description": "Skills",
2666
+ # "file_extract": {
2667
+ # "description": "文档解析能力 [beta]",
2668
+ # "type": "object",
2669
+ # "items": {
2670
+ # "provider_settings.file_extract.enable": {
2671
+ # "description": "启用文档解析能力",
2672
+ # "type": "bool",
2673
+ # },
2674
+ # "provider_settings.file_extract.provider": {
2675
+ # "description": "文档解析提供商",
2676
+ # "type": "string",
2677
+ # "options": ["moonshotai"],
2678
+ # "condition": {
2679
+ # "provider_settings.file_extract.enable": True,
2680
+ # },
2681
+ # },
2682
+ # "provider_settings.file_extract.moonshotai_api_key": {
2683
+ # "description": "Moonshot AI API Key",
2684
+ # "type": "string",
2685
+ # "condition": {
2686
+ # "provider_settings.file_extract.provider": "moonshotai",
2687
+ # "provider_settings.file_extract.enable": True,
2688
+ # },
2689
+ # },
2690
+ # },
2691
+ # "condition": {
2692
+ # "provider_settings.agent_runner_type": "local",
2693
+ # "provider_settings.enable": True,
2694
+ # },
2695
+ # },
2696
+ "proactive_capability": {
2697
+ "description": "主动型 Agent",
2698
+ "hint": "https://docs.astrbot.app/use/proactive-agent.html",
2672
2699
  "type": "object",
2673
2700
  "items": {
2674
- "provider_settings.skills.runtime": {
2675
- "description": "Skill Runtime",
2676
- "type": "string",
2677
- "options": ["local", "sandbox"],
2678
- "labels": ["本地", "沙箱"],
2679
- "hint": "选择 Skills 运行环境。使用沙箱时需先启用沙箱环境。",
2701
+ "provider_settings.proactive_capability.add_cron_tools": {
2702
+ "description": "启用",
2703
+ "type": "bool",
2704
+ "hint": "启用后,将会传递给 Agent 相关工具来实现主动型 Agent。你可以告诉 AstrBot 未来某个时间要做的事情,它将被定时触发然后执行任务。",
2680
2705
  },
2681
2706
  },
2682
2707
  "condition": {
@@ -2685,6 +2710,7 @@ CONFIG_METADATA_3 = {
2685
2710
  },
2686
2711
  },
2687
2712
  "truncate_and_compress": {
2713
+ "hint": "",
2688
2714
  "description": "上下文管理策略",
2689
2715
  "type": "object",
2690
2716
  "items": {
@@ -21,6 +21,7 @@ from astrbot.core import LogBroker, LogManager
21
21
  from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
22
22
  from astrbot.core.config.default import VERSION
23
23
  from astrbot.core.conversation_mgr import ConversationManager
24
+ from astrbot.core.cron import CronJobManager
24
25
  from astrbot.core.db import BaseDatabase
25
26
  from astrbot.core.knowledge_base.kb_mgr import KnowledgeBaseManager
26
27
  from astrbot.core.persona_mgr import PersonaManager
@@ -31,6 +32,7 @@ from astrbot.core.provider.manager import ProviderManager
31
32
  from astrbot.core.star import PluginManager
32
33
  from astrbot.core.star.context import Context
33
34
  from astrbot.core.star.star_handler import EventType, star_handlers_registry, star_map
35
+ from astrbot.core.subagent_orchestrator import SubAgentOrchestrator
34
36
  from astrbot.core.umop_config_router import UmopConfigRouter
35
37
  from astrbot.core.updator import AstrBotUpdator
36
38
  from astrbot.core.utils.llm_metadata import update_llm_metadata
@@ -53,6 +55,9 @@ class AstrBotCoreLifecycle:
53
55
  self.astrbot_config = astrbot_config # 初始化配置
54
56
  self.db = db # 初始化数据库
55
57
 
58
+ self.subagent_orchestrator: SubAgentOrchestrator | None = None
59
+ self.cron_manager: CronJobManager | None = None
60
+
56
61
  # 设置代理
57
62
  proxy_config = self.astrbot_config.get("http_proxy", "")
58
63
  if proxy_config != "":
@@ -72,6 +77,24 @@ class AstrBotCoreLifecycle:
72
77
  del os.environ["no_proxy"]
73
78
  logger.debug("HTTP proxy cleared")
74
79
 
80
+ async def _init_or_reload_subagent_orchestrator(self) -> None:
81
+ """Create (if needed) and reload the subagent orchestrator from config.
82
+
83
+ This keeps lifecycle wiring in one place while allowing the orchestrator
84
+ to manage enable/disable and tool registration details.
85
+ """
86
+ try:
87
+ if self.subagent_orchestrator is None:
88
+ self.subagent_orchestrator = SubAgentOrchestrator(
89
+ self.provider_manager.llm_tools,
90
+ self.persona_mgr,
91
+ )
92
+ await self.subagent_orchestrator.reload_from_config(
93
+ self.astrbot_config.get("subagent_orchestrator", {}),
94
+ )
95
+ except Exception as e:
96
+ logger.error(f"Subagent orchestrator init failed: {e}", exc_info=True)
97
+
75
98
  async def initialize(self) -> None:
76
99
  """初始化 AstrBot 核心生命周期管理类.
77
100
 
@@ -141,6 +164,12 @@ class AstrBotCoreLifecycle:
141
164
  # 初始化知识库管理器
142
165
  self.kb_manager = KnowledgeBaseManager(self.provider_manager)
143
166
 
167
+ # 初始化 CronJob 管理器
168
+ self.cron_manager = CronJobManager(self.db)
169
+
170
+ # Dynamic subagents (handoff tools) from config.
171
+ await self._init_or_reload_subagent_orchestrator()
172
+
144
173
  # 初始化提供给插件的上下文
145
174
  self.star_context = Context(
146
175
  self.event_queue,
@@ -153,6 +182,8 @@ class AstrBotCoreLifecycle:
153
182
  self.persona_mgr,
154
183
  self.astrbot_config_mgr,
155
184
  self.kb_manager,
185
+ self.cron_manager,
186
+ self.subagent_orchestrator,
156
187
  )
157
188
 
158
189
  # 初始化插件管理器
@@ -201,13 +232,21 @@ class AstrBotCoreLifecycle:
201
232
  self.event_bus.dispatch(),
202
233
  name="event_bus",
203
234
  )
235
+ cron_task = None
236
+ if self.cron_manager:
237
+ cron_task = asyncio.create_task(
238
+ self.cron_manager.start(self.star_context),
239
+ name="cron_manager",
240
+ )
204
241
 
205
242
  # 把插件中注册的所有协程函数注册到事件总线中并执行
206
243
  extra_tasks = []
207
244
  for task in self.star_context._register_tasks:
208
245
  extra_tasks.append(asyncio.create_task(task, name=task.__name__)) # type: ignore
209
246
 
210
- tasks_ = [event_bus_task, *extra_tasks]
247
+ tasks_ = [event_bus_task, *(extra_tasks if extra_tasks else [])]
248
+ if cron_task:
249
+ tasks_.append(cron_task)
211
250
  for task in tasks_:
212
251
  self.curr_tasks.append(
213
252
  asyncio.create_task(self._task_wrapper(task), name=task.get_name()),
@@ -263,6 +302,9 @@ class AstrBotCoreLifecycle:
263
302
  for task in self.curr_tasks:
264
303
  task.cancel()
265
304
 
305
+ if self.cron_manager:
306
+ await self.cron_manager.shutdown()
307
+
266
308
  for plugin in self.plugin_manager.context.get_all_stars():
267
309
  try:
268
310
  await self.plugin_manager._terminate_plugin(plugin)
@@ -0,0 +1,3 @@
1
+ from .manager import CronJobManager
2
+
3
+ __all__ = ["CronJobManager"]
@@ -0,0 +1,67 @@
1
+ import time
2
+ import uuid
3
+ from typing import Any
4
+
5
+ from astrbot.core.message.components import Plain
6
+ from astrbot.core.message.message_event_result import MessageChain
7
+ from astrbot.core.platform.astr_message_event import AstrMessageEvent
8
+ from astrbot.core.platform.astrbot_message import AstrBotMessage, MessageMember
9
+ from astrbot.core.platform.message_session import MessageSession
10
+ from astrbot.core.platform.message_type import MessageType
11
+ from astrbot.core.platform.platform_metadata import PlatformMetadata
12
+
13
+
14
+ class CronMessageEvent(AstrMessageEvent):
15
+ """Synthetic event used when a cron job triggers the main agent loop."""
16
+
17
+ def __init__(
18
+ self,
19
+ *,
20
+ context,
21
+ session: MessageSession,
22
+ message: str,
23
+ sender_id: str = "astrbot",
24
+ sender_name: str = "Scheduler",
25
+ extras: dict[str, Any] | None = None,
26
+ message_type: MessageType = MessageType.FRIEND_MESSAGE,
27
+ ):
28
+ platform_meta = PlatformMetadata(
29
+ name="cron",
30
+ description="CronJob",
31
+ id=session.platform_id,
32
+ )
33
+
34
+ msg_obj = AstrBotMessage()
35
+ msg_obj.type = message_type
36
+ msg_obj.self_id = sender_id
37
+ msg_obj.session_id = session.session_id
38
+ msg_obj.message_id = uuid.uuid4().hex
39
+ msg_obj.sender = MessageMember(user_id=session.session_id, nickname=sender_name)
40
+ msg_obj.message = [Plain(message)]
41
+ msg_obj.message_str = message
42
+ msg_obj.raw_message = message
43
+ msg_obj.timestamp = int(time.time())
44
+
45
+ super().__init__(message, msg_obj, platform_meta, session.session_id)
46
+
47
+ # Ensure we use the original session for sending messages
48
+ self.session = session
49
+ self.context_obj = context
50
+ self.is_at_or_wake_command = True
51
+ self.is_wake = True
52
+
53
+ if extras:
54
+ self._extras.update(extras)
55
+
56
+ async def send(self, message: MessageChain):
57
+ if message is None:
58
+ return
59
+ await self.context_obj.send_message(self.session, message)
60
+ await super().send(message)
61
+
62
+ async def send_streaming(self, generator, use_fallback: bool = False):
63
+ async for chain in generator:
64
+ await self.send(chain)
65
+
66
+
67
+ __all__ = ["CronMessageEvent"]