AstrBot 3.5.6__py3-none-any.whl → 4.7.0__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 (288) hide show
  1. astrbot/api/__init__.py +16 -4
  2. astrbot/api/all.py +2 -1
  3. astrbot/api/event/__init__.py +5 -6
  4. astrbot/api/event/filter/__init__.py +37 -34
  5. astrbot/api/platform/__init__.py +7 -8
  6. astrbot/api/provider/__init__.py +8 -7
  7. astrbot/api/star/__init__.py +3 -4
  8. astrbot/api/util/__init__.py +2 -2
  9. astrbot/cli/__init__.py +1 -0
  10. astrbot/cli/__main__.py +18 -197
  11. astrbot/cli/commands/__init__.py +6 -0
  12. astrbot/cli/commands/cmd_conf.py +209 -0
  13. astrbot/cli/commands/cmd_init.py +56 -0
  14. astrbot/cli/commands/cmd_plug.py +245 -0
  15. astrbot/cli/commands/cmd_run.py +62 -0
  16. astrbot/cli/utils/__init__.py +18 -0
  17. astrbot/cli/utils/basic.py +76 -0
  18. astrbot/cli/utils/plugin.py +246 -0
  19. astrbot/cli/utils/version_comparator.py +90 -0
  20. astrbot/core/__init__.py +17 -19
  21. astrbot/core/agent/agent.py +14 -0
  22. astrbot/core/agent/handoff.py +38 -0
  23. astrbot/core/agent/hooks.py +30 -0
  24. astrbot/core/agent/mcp_client.py +385 -0
  25. astrbot/core/agent/message.py +175 -0
  26. astrbot/core/agent/response.py +14 -0
  27. astrbot/core/agent/run_context.py +22 -0
  28. astrbot/core/agent/runners/__init__.py +3 -0
  29. astrbot/core/agent/runners/base.py +65 -0
  30. astrbot/core/agent/runners/coze/coze_agent_runner.py +367 -0
  31. astrbot/core/agent/runners/coze/coze_api_client.py +324 -0
  32. astrbot/core/agent/runners/dashscope/dashscope_agent_runner.py +403 -0
  33. astrbot/core/agent/runners/dify/dify_agent_runner.py +336 -0
  34. astrbot/core/agent/runners/dify/dify_api_client.py +195 -0
  35. astrbot/core/agent/runners/tool_loop_agent_runner.py +400 -0
  36. astrbot/core/agent/tool.py +285 -0
  37. astrbot/core/agent/tool_executor.py +17 -0
  38. astrbot/core/astr_agent_context.py +19 -0
  39. astrbot/core/astr_agent_hooks.py +36 -0
  40. astrbot/core/astr_agent_run_util.py +80 -0
  41. astrbot/core/astr_agent_tool_exec.py +246 -0
  42. astrbot/core/astrbot_config_mgr.py +275 -0
  43. astrbot/core/config/__init__.py +2 -2
  44. astrbot/core/config/astrbot_config.py +60 -20
  45. astrbot/core/config/default.py +1972 -453
  46. astrbot/core/config/i18n_utils.py +110 -0
  47. astrbot/core/conversation_mgr.py +285 -75
  48. astrbot/core/core_lifecycle.py +167 -62
  49. astrbot/core/db/__init__.py +305 -102
  50. astrbot/core/db/migration/helper.py +69 -0
  51. astrbot/core/db/migration/migra_3_to_4.py +357 -0
  52. astrbot/core/db/migration/migra_45_to_46.py +44 -0
  53. astrbot/core/db/migration/migra_webchat_session.py +131 -0
  54. astrbot/core/db/migration/shared_preferences_v3.py +48 -0
  55. astrbot/core/db/migration/sqlite_v3.py +497 -0
  56. astrbot/core/db/po.py +259 -55
  57. astrbot/core/db/sqlite.py +773 -528
  58. astrbot/core/db/vec_db/base.py +73 -0
  59. astrbot/core/db/vec_db/faiss_impl/__init__.py +3 -0
  60. astrbot/core/db/vec_db/faiss_impl/document_storage.py +392 -0
  61. astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +93 -0
  62. astrbot/core/db/vec_db/faiss_impl/sqlite_init.sql +17 -0
  63. astrbot/core/db/vec_db/faiss_impl/vec_db.py +204 -0
  64. astrbot/core/event_bus.py +26 -22
  65. astrbot/core/exceptions.py +9 -0
  66. astrbot/core/file_token_service.py +98 -0
  67. astrbot/core/initial_loader.py +19 -10
  68. astrbot/core/knowledge_base/chunking/__init__.py +9 -0
  69. astrbot/core/knowledge_base/chunking/base.py +25 -0
  70. astrbot/core/knowledge_base/chunking/fixed_size.py +59 -0
  71. astrbot/core/knowledge_base/chunking/recursive.py +161 -0
  72. astrbot/core/knowledge_base/kb_db_sqlite.py +301 -0
  73. astrbot/core/knowledge_base/kb_helper.py +642 -0
  74. astrbot/core/knowledge_base/kb_mgr.py +330 -0
  75. astrbot/core/knowledge_base/models.py +120 -0
  76. astrbot/core/knowledge_base/parsers/__init__.py +13 -0
  77. astrbot/core/knowledge_base/parsers/base.py +51 -0
  78. astrbot/core/knowledge_base/parsers/markitdown_parser.py +26 -0
  79. astrbot/core/knowledge_base/parsers/pdf_parser.py +101 -0
  80. astrbot/core/knowledge_base/parsers/text_parser.py +42 -0
  81. astrbot/core/knowledge_base/parsers/url_parser.py +103 -0
  82. astrbot/core/knowledge_base/parsers/util.py +13 -0
  83. astrbot/core/knowledge_base/prompts.py +65 -0
  84. astrbot/core/knowledge_base/retrieval/__init__.py +14 -0
  85. astrbot/core/knowledge_base/retrieval/hit_stopwords.txt +767 -0
  86. astrbot/core/knowledge_base/retrieval/manager.py +276 -0
  87. astrbot/core/knowledge_base/retrieval/rank_fusion.py +142 -0
  88. astrbot/core/knowledge_base/retrieval/sparse_retriever.py +136 -0
  89. astrbot/core/log.py +21 -15
  90. astrbot/core/message/components.py +413 -287
  91. astrbot/core/message/message_event_result.py +35 -24
  92. astrbot/core/persona_mgr.py +192 -0
  93. astrbot/core/pipeline/__init__.py +14 -14
  94. astrbot/core/pipeline/content_safety_check/stage.py +13 -9
  95. astrbot/core/pipeline/content_safety_check/strategies/__init__.py +1 -2
  96. astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +13 -14
  97. astrbot/core/pipeline/content_safety_check/strategies/keywords.py +2 -1
  98. astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
  99. astrbot/core/pipeline/context.py +7 -1
  100. astrbot/core/pipeline/context_utils.py +107 -0
  101. astrbot/core/pipeline/preprocess_stage/stage.py +63 -36
  102. astrbot/core/pipeline/process_stage/method/agent_request.py +48 -0
  103. astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +464 -0
  104. astrbot/core/pipeline/process_stage/method/agent_sub_stages/third_party.py +202 -0
  105. astrbot/core/pipeline/process_stage/method/star_request.py +26 -32
  106. astrbot/core/pipeline/process_stage/stage.py +21 -15
  107. astrbot/core/pipeline/process_stage/utils.py +125 -0
  108. astrbot/core/pipeline/rate_limit_check/stage.py +34 -36
  109. astrbot/core/pipeline/respond/stage.py +142 -101
  110. astrbot/core/pipeline/result_decorate/stage.py +124 -57
  111. astrbot/core/pipeline/scheduler.py +21 -16
  112. astrbot/core/pipeline/session_status_check/stage.py +37 -0
  113. astrbot/core/pipeline/stage.py +11 -76
  114. astrbot/core/pipeline/waking_check/stage.py +69 -33
  115. astrbot/core/pipeline/whitelist_check/stage.py +10 -7
  116. astrbot/core/platform/__init__.py +6 -6
  117. astrbot/core/platform/astr_message_event.py +107 -129
  118. astrbot/core/platform/astrbot_message.py +32 -12
  119. astrbot/core/platform/manager.py +62 -18
  120. astrbot/core/platform/message_session.py +30 -0
  121. astrbot/core/platform/platform.py +16 -24
  122. astrbot/core/platform/platform_metadata.py +9 -4
  123. astrbot/core/platform/register.py +12 -7
  124. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +136 -60
  125. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +126 -46
  126. astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +63 -31
  127. astrbot/core/platform/sources/dingtalk/dingtalk_event.py +30 -26
  128. astrbot/core/platform/sources/discord/client.py +129 -0
  129. astrbot/core/platform/sources/discord/components.py +139 -0
  130. astrbot/core/platform/sources/discord/discord_platform_adapter.py +473 -0
  131. astrbot/core/platform/sources/discord/discord_platform_event.py +313 -0
  132. astrbot/core/platform/sources/lark/lark_adapter.py +27 -18
  133. astrbot/core/platform/sources/lark/lark_event.py +39 -13
  134. astrbot/core/platform/sources/misskey/misskey_adapter.py +770 -0
  135. astrbot/core/platform/sources/misskey/misskey_api.py +964 -0
  136. astrbot/core/platform/sources/misskey/misskey_event.py +163 -0
  137. astrbot/core/platform/sources/misskey/misskey_utils.py +550 -0
  138. astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +149 -33
  139. astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +41 -26
  140. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +36 -17
  141. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +3 -1
  142. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +14 -8
  143. astrbot/core/platform/sources/satori/satori_adapter.py +792 -0
  144. astrbot/core/platform/sources/satori/satori_event.py +432 -0
  145. astrbot/core/platform/sources/slack/client.py +164 -0
  146. astrbot/core/platform/sources/slack/slack_adapter.py +416 -0
  147. astrbot/core/platform/sources/slack/slack_event.py +253 -0
  148. astrbot/core/platform/sources/telegram/tg_adapter.py +100 -43
  149. astrbot/core/platform/sources/telegram/tg_event.py +136 -36
  150. astrbot/core/platform/sources/webchat/webchat_adapter.py +72 -22
  151. astrbot/core/platform/sources/webchat/webchat_event.py +46 -22
  152. astrbot/core/platform/sources/webchat/webchat_queue_mgr.py +35 -0
  153. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +926 -0
  154. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +178 -0
  155. astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +159 -0
  156. astrbot/core/platform/sources/wecom/wecom_adapter.py +169 -27
  157. astrbot/core/platform/sources/wecom/wecom_event.py +162 -77
  158. astrbot/core/platform/sources/wecom/wecom_kf.py +279 -0
  159. astrbot/core/platform/sources/wecom/wecom_kf_message.py +196 -0
  160. astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +297 -0
  161. astrbot/core/platform/sources/wecom_ai_bot/__init__.py +15 -0
  162. astrbot/core/platform/sources/wecom_ai_bot/ierror.py +19 -0
  163. astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +472 -0
  164. astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +417 -0
  165. astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +152 -0
  166. astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +153 -0
  167. astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +168 -0
  168. astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +209 -0
  169. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +306 -0
  170. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +186 -0
  171. astrbot/core/platform_message_history_mgr.py +49 -0
  172. astrbot/core/provider/__init__.py +2 -3
  173. astrbot/core/provider/entites.py +8 -8
  174. astrbot/core/provider/entities.py +154 -98
  175. astrbot/core/provider/func_tool_manager.py +446 -458
  176. astrbot/core/provider/manager.py +345 -207
  177. astrbot/core/provider/provider.py +188 -73
  178. astrbot/core/provider/register.py +9 -7
  179. astrbot/core/provider/sources/anthropic_source.py +295 -115
  180. astrbot/core/provider/sources/azure_tts_source.py +224 -0
  181. astrbot/core/provider/sources/bailian_rerank_source.py +236 -0
  182. astrbot/core/provider/sources/dashscope_tts.py +138 -14
  183. astrbot/core/provider/sources/edge_tts_source.py +24 -19
  184. astrbot/core/provider/sources/fishaudio_tts_api_source.py +58 -13
  185. astrbot/core/provider/sources/gemini_embedding_source.py +61 -0
  186. astrbot/core/provider/sources/gemini_source.py +310 -132
  187. astrbot/core/provider/sources/gemini_tts_source.py +81 -0
  188. astrbot/core/provider/sources/groq_source.py +15 -0
  189. astrbot/core/provider/sources/gsv_selfhosted_source.py +151 -0
  190. astrbot/core/provider/sources/gsvi_tts_source.py +14 -7
  191. astrbot/core/provider/sources/minimax_tts_api_source.py +159 -0
  192. astrbot/core/provider/sources/openai_embedding_source.py +40 -0
  193. astrbot/core/provider/sources/openai_source.py +241 -145
  194. astrbot/core/provider/sources/openai_tts_api_source.py +18 -7
  195. astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
  196. astrbot/core/provider/sources/vllm_rerank_source.py +71 -0
  197. astrbot/core/provider/sources/volcengine_tts.py +115 -0
  198. astrbot/core/provider/sources/whisper_api_source.py +18 -13
  199. astrbot/core/provider/sources/whisper_selfhosted_source.py +19 -12
  200. astrbot/core/provider/sources/xinference_rerank_source.py +116 -0
  201. astrbot/core/provider/sources/xinference_stt_provider.py +197 -0
  202. astrbot/core/provider/sources/zhipu_source.py +6 -73
  203. astrbot/core/star/__init__.py +43 -11
  204. astrbot/core/star/config.py +17 -18
  205. astrbot/core/star/context.py +362 -138
  206. astrbot/core/star/filter/__init__.py +4 -3
  207. astrbot/core/star/filter/command.py +111 -35
  208. astrbot/core/star/filter/command_group.py +46 -34
  209. astrbot/core/star/filter/custom_filter.py +6 -5
  210. astrbot/core/star/filter/event_message_type.py +4 -2
  211. astrbot/core/star/filter/permission.py +4 -2
  212. astrbot/core/star/filter/platform_adapter_type.py +45 -12
  213. astrbot/core/star/filter/regex.py +4 -2
  214. astrbot/core/star/register/__init__.py +19 -15
  215. astrbot/core/star/register/star.py +41 -13
  216. astrbot/core/star/register/star_handler.py +236 -86
  217. astrbot/core/star/session_llm_manager.py +280 -0
  218. astrbot/core/star/session_plugin_manager.py +170 -0
  219. astrbot/core/star/star.py +36 -43
  220. astrbot/core/star/star_handler.py +47 -85
  221. astrbot/core/star/star_manager.py +442 -260
  222. astrbot/core/star/star_tools.py +167 -45
  223. astrbot/core/star/updator.py +17 -20
  224. astrbot/core/umop_config_router.py +106 -0
  225. astrbot/core/updator.py +38 -13
  226. astrbot/core/utils/astrbot_path.py +39 -0
  227. astrbot/core/utils/command_parser.py +1 -1
  228. astrbot/core/utils/io.py +119 -60
  229. astrbot/core/utils/log_pipe.py +1 -1
  230. astrbot/core/utils/metrics.py +11 -10
  231. astrbot/core/utils/migra_helper.py +73 -0
  232. astrbot/core/utils/path_util.py +63 -62
  233. astrbot/core/utils/pip_installer.py +37 -15
  234. astrbot/core/utils/session_lock.py +29 -0
  235. astrbot/core/utils/session_waiter.py +19 -20
  236. astrbot/core/utils/shared_preferences.py +174 -34
  237. astrbot/core/utils/t2i/__init__.py +4 -1
  238. astrbot/core/utils/t2i/local_strategy.py +386 -238
  239. astrbot/core/utils/t2i/network_strategy.py +109 -49
  240. astrbot/core/utils/t2i/renderer.py +29 -14
  241. astrbot/core/utils/t2i/template/astrbot_powershell.html +184 -0
  242. astrbot/core/utils/t2i/template_manager.py +111 -0
  243. astrbot/core/utils/tencent_record_helper.py +115 -1
  244. astrbot/core/utils/version_comparator.py +10 -13
  245. astrbot/core/zip_updator.py +112 -65
  246. astrbot/dashboard/routes/__init__.py +20 -13
  247. astrbot/dashboard/routes/auth.py +20 -9
  248. astrbot/dashboard/routes/chat.py +297 -141
  249. astrbot/dashboard/routes/config.py +652 -55
  250. astrbot/dashboard/routes/conversation.py +107 -37
  251. astrbot/dashboard/routes/file.py +26 -0
  252. astrbot/dashboard/routes/knowledge_base.py +1244 -0
  253. astrbot/dashboard/routes/log.py +27 -2
  254. astrbot/dashboard/routes/persona.py +202 -0
  255. astrbot/dashboard/routes/plugin.py +197 -139
  256. astrbot/dashboard/routes/route.py +27 -7
  257. astrbot/dashboard/routes/session_management.py +354 -0
  258. astrbot/dashboard/routes/stat.py +85 -18
  259. astrbot/dashboard/routes/static_file.py +5 -2
  260. astrbot/dashboard/routes/t2i.py +233 -0
  261. astrbot/dashboard/routes/tools.py +184 -120
  262. astrbot/dashboard/routes/update.py +59 -36
  263. astrbot/dashboard/server.py +96 -36
  264. astrbot/dashboard/utils.py +165 -0
  265. astrbot-4.7.0.dist-info/METADATA +294 -0
  266. astrbot-4.7.0.dist-info/RECORD +274 -0
  267. {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/WHEEL +1 -1
  268. astrbot/core/db/plugin/sqlite_impl.py +0 -112
  269. astrbot/core/db/sqlite_init.sql +0 -50
  270. astrbot/core/pipeline/platform_compatibility/stage.py +0 -56
  271. astrbot/core/pipeline/process_stage/method/llm_request.py +0 -606
  272. astrbot/core/platform/sources/gewechat/client.py +0 -806
  273. astrbot/core/platform/sources/gewechat/downloader.py +0 -55
  274. astrbot/core/platform/sources/gewechat/gewechat_event.py +0 -255
  275. astrbot/core/platform/sources/gewechat/gewechat_platform_adapter.py +0 -103
  276. astrbot/core/platform/sources/gewechat/xml_data_parser.py +0 -110
  277. astrbot/core/provider/sources/dashscope_source.py +0 -203
  278. astrbot/core/provider/sources/dify_source.py +0 -281
  279. astrbot/core/provider/sources/llmtuner_source.py +0 -132
  280. astrbot/core/rag/embedding/openai_source.py +0 -20
  281. astrbot/core/rag/knowledge_db_mgr.py +0 -94
  282. astrbot/core/rag/store/__init__.py +0 -9
  283. astrbot/core/rag/store/chroma_db.py +0 -42
  284. astrbot/core/utils/dify_api_client.py +0 -152
  285. astrbot-3.5.6.dist-info/METADATA +0 -249
  286. astrbot-3.5.6.dist-info/RECORD +0 -158
  287. {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/entry_points.txt +0 -0
  288. {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,73 +1,101 @@
1
1
  from __future__ import annotations
2
+
3
+ import re
4
+ from collections.abc import Awaitable, Callable
5
+ from typing import Any
6
+
2
7
  import docstring_parser
3
8
 
4
- from ..star_handler import star_handlers_registry, StarHandlerMetadata, EventType
9
+ from astrbot.core import logger
10
+ from astrbot.core.agent.agent import Agent
11
+ from astrbot.core.agent.handoff import HandoffTool
12
+ from astrbot.core.agent.hooks import BaseAgentRunHooks
13
+ from astrbot.core.agent.tool import FunctionTool
14
+ from astrbot.core.astr_agent_context import AstrAgentContext
15
+ from astrbot.core.provider.func_tool_manager import PY_TO_JSON_TYPE, SUPPORTED_TYPES
16
+ from astrbot.core.provider.register import llm_tools
17
+
5
18
  from ..filter.command import CommandFilter
6
19
  from ..filter.command_group import CommandGroupFilter
7
- from ..filter.event_message_type import EventMessageTypeFilter, EventMessageType
20
+ from ..filter.custom_filter import CustomFilterAnd, CustomFilterOr
21
+ from ..filter.event_message_type import EventMessageType, EventMessageTypeFilter
22
+ from ..filter.permission import PermissionType, PermissionTypeFilter
8
23
  from ..filter.platform_adapter_type import (
9
- PlatformAdapterTypeFilter,
10
24
  PlatformAdapterType,
25
+ PlatformAdapterTypeFilter,
11
26
  )
12
- from ..filter.permission import PermissionTypeFilter, PermissionType
13
- from ..filter.custom_filter import CustomFilterAnd, CustomFilterOr
14
27
  from ..filter.regex import RegexFilter
15
- from typing import Awaitable
16
- from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES
17
- from astrbot.core.provider.register import llm_tools
28
+ from ..star_handler import EventType, StarHandlerMetadata, star_handlers_registry
18
29
 
19
30
 
20
- def get_handler_full_name(awaitable: Awaitable) -> str:
31
+ def get_handler_full_name(awaitable: Callable[..., Awaitable[Any]]) -> str:
21
32
  """获取 Handler 的全名"""
22
33
  return f"{awaitable.__module__}_{awaitable.__name__}"
23
34
 
24
35
 
25
36
  def get_handler_or_create(
26
- handler: Awaitable, event_type: EventType, dont_add=False, **kwargs
37
+ handler: Callable[..., Awaitable[Any]],
38
+ event_type: EventType,
39
+ dont_add=False,
40
+ **kwargs,
27
41
  ) -> StarHandlerMetadata:
28
42
  """获取 Handler 或者创建一个新的 Handler"""
29
43
  handler_full_name = get_handler_full_name(handler)
30
44
  md = star_handlers_registry.get_handler_by_full_name(handler_full_name)
31
45
  if md:
32
46
  return md
33
- else:
34
- md = StarHandlerMetadata(
35
- event_type=event_type,
36
- handler_full_name=handler_full_name,
37
- handler_name=handler.__name__,
38
- handler_module_path=handler.__module__,
39
- handler=handler,
40
- event_filters=[],
41
- )
42
-
43
- # 插件handler的附加额外信息
44
- if handler.__doc__:
45
- md.desc = handler.__doc__.strip()
46
- if "desc" in kwargs:
47
- md.desc = kwargs["desc"]
48
- del kwargs["desc"]
49
- md.extras_configs = kwargs
50
-
51
- if not dont_add:
52
- star_handlers_registry.append(md)
53
- return md
47
+ md = StarHandlerMetadata(
48
+ event_type=event_type,
49
+ handler_full_name=handler_full_name,
50
+ handler_name=handler.__name__,
51
+ handler_module_path=handler.__module__,
52
+ handler=handler,
53
+ event_filters=[],
54
+ )
55
+
56
+ # 插件handler的附加额外信息
57
+ if handler.__doc__:
58
+ md.desc = handler.__doc__.strip()
59
+ if "desc" in kwargs:
60
+ md.desc = kwargs["desc"]
61
+ del kwargs["desc"]
62
+ md.extras_configs = kwargs
63
+
64
+ if not dont_add:
65
+ star_handlers_registry.append(md)
66
+ return md
54
67
 
55
68
 
56
69
  def register_command(
57
- command_name: str = None, sub_command: str = None, alias: set = None, **kwargs
70
+ command_name: str | None = None,
71
+ sub_command: str | None = None,
72
+ alias: set | None = None,
73
+ **kwargs,
58
74
  ):
59
75
  """注册一个 Command."""
60
76
  new_command = None
61
77
  add_to_event_filters = False
62
78
  if isinstance(command_name, RegisteringCommandable):
63
79
  # 子指令
64
- parent_command_names = command_name.parent_group.get_complete_command_names()
65
- new_command = CommandFilter(
66
- sub_command, alias, None, parent_command_names=parent_command_names
67
- )
68
- command_name.parent_group.add_sub_command_filter(new_command)
80
+ if sub_command is not None:
81
+ parent_command_names = (
82
+ command_name.parent_group.get_complete_command_names()
83
+ )
84
+ new_command = CommandFilter(
85
+ sub_command,
86
+ alias,
87
+ None,
88
+ parent_command_names=parent_command_names,
89
+ )
90
+ command_name.parent_group.add_sub_command_filter(new_command)
91
+ else:
92
+ logger.warning(
93
+ f"注册指令{command_name} 的子指令时未提供 sub_command 参数。",
94
+ )
95
+ # 裸指令
96
+ elif command_name is None:
97
+ logger.warning("注册裸指令时未提供 command_name 参数。")
69
98
  else:
70
- # 裸指令
71
99
  new_command = CommandFilter(command_name, alias, None)
72
100
  add_to_event_filters = True
73
101
 
@@ -77,10 +105,13 @@ def register_command(
77
105
  True # 打一个标记,表示这是一个子指令,再 wakingstage 阶段这个 handler 将会直接被跳过(其父指令会接管)
78
106
  )
79
107
  handler_md = get_handler_or_create(
80
- awaitable, EventType.AdapterMessageEvent, **kwargs
108
+ awaitable,
109
+ EventType.AdapterMessageEvent,
110
+ **kwargs,
81
111
  )
82
- new_command.init_handler_md(handler_md)
83
- handler_md.event_filters.append(new_command)
112
+ if new_command:
113
+ new_command.init_handler_md(handler_md)
114
+ handler_md.event_filters.append(new_command)
84
115
  return awaitable
85
116
 
86
117
  return decorator
@@ -93,6 +124,7 @@ def register_custom_filter(custom_type_filter, *args, **kwargs):
93
124
  custom_type_filter: 在裸指令时为CustomFilter对象
94
125
  在指令组时为父指令的RegisteringCommandable对象,即self或者command_group的返回
95
126
  raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True
127
+
96
128
  """
97
129
  add_to_event_filters = False
98
130
  raise_error = True
@@ -117,19 +149,20 @@ def register_custom_filter(custom_type_filter, *args, **kwargs):
117
149
  def decorator(awaitable):
118
150
  # 裸指令,子指令与指令组的区分,指令组会因为标记跳过wake。
119
151
  if (
120
- not add_to_event_filters
121
- and isinstance(awaitable, RegisteringCommandable)
122
- or (add_to_event_filters and isinstance(awaitable, RegisteringCommandable))
123
- ):
152
+ not add_to_event_filters and isinstance(awaitable, RegisteringCommandable)
153
+ ) or (add_to_event_filters and isinstance(awaitable, RegisteringCommandable)):
124
154
  # 指令组 与 根指令组,添加到本层的grouphandle中一起判断
125
155
  awaitable.parent_group.add_custom_filter(custom_filter)
126
156
  else:
127
157
  handler_md = get_handler_or_create(
128
- awaitable, EventType.AdapterMessageEvent, **kwargs
158
+ awaitable,
159
+ EventType.AdapterMessageEvent,
160
+ **kwargs,
129
161
  )
130
162
 
131
163
  if not add_to_event_filters and not isinstance(
132
- awaitable, RegisteringCommandable
164
+ awaitable,
165
+ RegisteringCommandable,
133
166
  ):
134
167
  # 底层子指令
135
168
  handle_full_name = get_handler_full_name(awaitable)
@@ -148,7 +181,9 @@ def register_custom_filter(custom_type_filter, *args, **kwargs):
148
181
  else:
149
182
  # 裸指令
150
183
  handler_md = get_handler_or_create(
151
- awaitable, EventType.AdapterMessageEvent, **kwargs
184
+ awaitable,
185
+ EventType.AdapterMessageEvent,
186
+ **kwargs,
152
187
  )
153
188
  handler_md.event_filters.append(custom_filter)
154
189
 
@@ -158,26 +193,41 @@ def register_custom_filter(custom_type_filter, *args, **kwargs):
158
193
 
159
194
 
160
195
  def register_command_group(
161
- command_group_name: str = None, sub_command: str = None, alias: set = None, **kwargs
196
+ command_group_name: str | None = None,
197
+ sub_command: str | None = None,
198
+ alias: set | None = None,
199
+ **kwargs,
162
200
  ):
163
201
  """注册一个 CommandGroup"""
164
202
  new_group = None
165
203
  if isinstance(command_group_name, RegisteringCommandable):
166
204
  # 子指令组
167
- new_group = CommandGroupFilter(
168
- sub_command, alias, parent_group=command_group_name.parent_group
169
- )
170
- command_group_name.parent_group.add_sub_command_filter(new_group)
205
+ if sub_command is None:
206
+ logger.warning(f"{command_group_name} 指令组的子指令组 sub_command 未指定")
207
+ else:
208
+ new_group = CommandGroupFilter(
209
+ sub_command,
210
+ alias,
211
+ parent_group=command_group_name.parent_group,
212
+ )
213
+ command_group_name.parent_group.add_sub_command_filter(new_group)
214
+ # 根指令组
215
+ elif command_group_name is None:
216
+ logger.warning("根指令组的名称未指定")
171
217
  else:
172
- # 根指令组
173
218
  new_group = CommandGroupFilter(command_group_name, alias)
174
219
 
175
220
  def decorator(obj):
176
- # 根指令组
177
- handler_md = get_handler_or_create(obj, EventType.AdapterMessageEvent, **kwargs)
178
- handler_md.event_filters.append(new_group)
221
+ if new_group:
222
+ handler_md = get_handler_or_create(
223
+ obj,
224
+ EventType.AdapterMessageEvent,
225
+ **kwargs,
226
+ )
227
+ handler_md.event_filters.append(new_group)
179
228
 
180
- return RegisteringCommandable(new_group)
229
+ return RegisteringCommandable(new_group)
230
+ raise ValueError("注册指令组失败。")
181
231
 
182
232
  return decorator
183
233
 
@@ -185,9 +235,9 @@ def register_command_group(
185
235
  class RegisteringCommandable:
186
236
  """用于指令组级联注册"""
187
237
 
188
- group: CommandGroupFilter = register_command_group
189
- command: CommandFilter = register_command
190
- custom_filter = register_custom_filter
238
+ group: Callable[..., Callable[..., RegisteringCommandable]] = register_command_group
239
+ command: Callable[..., Callable[..., None]] = register_command
240
+ custom_filter: Callable[..., Callable[..., None]] = register_custom_filter
191
241
 
192
242
  def __init__(self, parent_group: CommandGroupFilter):
193
243
  self.parent_group = parent_group
@@ -198,7 +248,9 @@ def register_event_message_type(event_message_type: EventMessageType, **kwargs):
198
248
 
199
249
  def decorator(awaitable):
200
250
  handler_md = get_handler_or_create(
201
- awaitable, EventType.AdapterMessageEvent, **kwargs
251
+ awaitable,
252
+ EventType.AdapterMessageEvent,
253
+ **kwargs,
202
254
  )
203
255
  handler_md.event_filters.append(EventMessageTypeFilter(event_message_type))
204
256
  return awaitable
@@ -207,14 +259,15 @@ def register_event_message_type(event_message_type: EventMessageType, **kwargs):
207
259
 
208
260
 
209
261
  def register_platform_adapter_type(
210
- platform_adapter_type: PlatformAdapterType, **kwargs
262
+ platform_adapter_type: PlatformAdapterType,
263
+ **kwargs,
211
264
  ):
212
265
  """注册一个 PlatformAdapterType"""
213
266
 
214
267
  def decorator(awaitable):
215
268
  handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent)
216
269
  handler_md.event_filters.append(
217
- PlatformAdapterTypeFilter(platform_adapter_type)
270
+ PlatformAdapterTypeFilter(platform_adapter_type),
218
271
  )
219
272
  return awaitable
220
273
 
@@ -226,7 +279,9 @@ def register_regex(regex: str, **kwargs):
226
279
 
227
280
  def decorator(awaitable):
228
281
  handler_md = get_handler_or_create(
229
- awaitable, EventType.AdapterMessageEvent, **kwargs
282
+ awaitable,
283
+ EventType.AdapterMessageEvent,
284
+ **kwargs,
230
285
  )
231
286
  handler_md.event_filters.append(RegexFilter(regex))
232
287
  return awaitable
@@ -240,12 +295,13 @@ def register_permission_type(permission_type: PermissionType, raise_error: bool
240
295
  Args:
241
296
  permission_type: PermissionType
242
297
  raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True
298
+
243
299
  """
244
300
 
245
301
  def decorator(awaitable):
246
302
  handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent)
247
303
  handler_md.event_filters.append(
248
- PermissionTypeFilter(permission_type, raise_error)
304
+ PermissionTypeFilter(permission_type, raise_error),
249
305
  )
250
306
  return awaitable
251
307
 
@@ -262,6 +318,16 @@ def register_on_astrbot_loaded(**kwargs):
262
318
  return decorator
263
319
 
264
320
 
321
+ def register_on_platform_loaded(**kwargs):
322
+ """当平台加载完成时"""
323
+
324
+ def decorator(awaitable):
325
+ _ = get_handler_or_create(awaitable, EventType.OnPlatformLoadedEvent, **kwargs)
326
+ return awaitable
327
+
328
+ return decorator
329
+
330
+
265
331
  def register_on_llm_request(**kwargs):
266
332
  """当有 LLM 请求时的事件
267
333
 
@@ -275,6 +341,7 @@ def register_on_llm_request(**kwargs):
275
341
  ```
276
342
 
277
343
  请务必接收两个参数:event, request
344
+
278
345
  """
279
346
 
280
347
  def decorator(awaitable):
@@ -297,6 +364,7 @@ def register_on_llm_response(**kwargs):
297
364
  ```
298
365
 
299
366
  请务必接收两个参数:event, request
367
+
300
368
  """
301
369
 
302
370
  def decorator(awaitable):
@@ -306,7 +374,7 @@ def register_on_llm_response(**kwargs):
306
374
  return decorator
307
375
 
308
376
 
309
- def register_llm_tool(name: str = None):
377
+ def register_llm_tool(name: str | None = None, **kwargs):
310
378
  """为函数调用(function-calling / tools-use)添加工具。
311
379
 
312
380
  请务必按照以下格式编写一个工具(包括函数注释,AstrBot 会尝试解析该函数注释)
@@ -316,7 +384,7 @@ def register_llm_tool(name: str = None):
316
384
  async def get_weather(event: AstrMessageEvent, location: str):
317
385
  \'\'\'获取天气信息。
318
386
 
319
- Args:
387
+ Args:
320
388
  location(string): 地点
321
389
  \'\'\'
322
390
  # 处理逻辑
@@ -337,41 +405,121 @@ def register_llm_tool(name: str = None):
337
405
  event.stop_event()
338
406
  yield
339
407
  ```
340
- """
341
408
 
409
+ """
342
410
  name_ = name
411
+ registering_agent = None
412
+ if kwargs.get("registering_agent"):
413
+ registering_agent = kwargs["registering_agent"]
343
414
 
344
- def decorator(awaitable: Awaitable):
415
+ def decorator(awaitable: Callable[..., Awaitable[Any]]):
345
416
  llm_tool_name = name_ if name_ else awaitable.__name__
346
- docstring = docstring_parser.parse(awaitable.__doc__)
417
+ func_doc = awaitable.__doc__ or ""
418
+ docstring = docstring_parser.parse(func_doc)
347
419
  args = []
348
420
  for arg in docstring.params:
349
- if arg.type_name not in SUPPORTED_TYPES:
421
+ sub_type_name = None
422
+ type_name = arg.type_name
423
+ if not type_name:
350
424
  raise ValueError(
351
- f"LLM 函数工具 {awaitable.__module__}_{llm_tool_name} 不支持的参数类型:{arg.type_name}"
425
+ f"LLM 函数工具 {awaitable.__module__}_{llm_tool_name} 的参数 {arg.arg_name} 缺少类型注释。",
352
426
  )
353
- args.append(
354
- {
355
- "type": arg.type_name,
356
- "name": arg.arg_name,
357
- "description": arg.description,
358
- }
359
- )
360
- md = get_handler_or_create(awaitable, EventType.OnCallingFuncToolEvent)
361
- llm_tools.add_func(
362
- llm_tool_name, args, docstring.description.strip(), md.handler
363
- )
427
+ # parse type_name to handle cases like "list[string]"
428
+ match = re.match(r"(\w+)\[(\w+)\]", type_name)
429
+ if match:
430
+ type_name = match.group(1)
431
+ sub_type_name = match.group(2)
432
+ type_name = PY_TO_JSON_TYPE.get(type_name, type_name)
433
+ if sub_type_name:
434
+ sub_type_name = PY_TO_JSON_TYPE.get(sub_type_name, sub_type_name)
435
+ if type_name not in SUPPORTED_TYPES or (
436
+ sub_type_name and sub_type_name not in SUPPORTED_TYPES
437
+ ):
438
+ raise ValueError(
439
+ f"LLM 函数工具 {awaitable.__module__}_{llm_tool_name} 不支持的参数类型:{arg.type_name}",
440
+ )
441
+
442
+ arg_json_schema = {
443
+ "type": type_name,
444
+ "name": arg.arg_name,
445
+ "description": arg.description,
446
+ }
447
+ if sub_type_name:
448
+ if type_name == "array":
449
+ arg_json_schema["items"] = {"type": sub_type_name}
450
+ args.append(arg_json_schema)
451
+
452
+ if not registering_agent:
453
+ doc_desc = docstring.description.strip() if docstring.description else ""
454
+ md = get_handler_or_create(awaitable, EventType.OnCallingFuncToolEvent)
455
+ llm_tools.add_func(llm_tool_name, args, doc_desc, md.handler)
456
+ else:
457
+ assert isinstance(registering_agent, RegisteringAgent)
458
+ # print(f"Registering tool {llm_tool_name} for agent", registering_agent._agent.name)
459
+ if registering_agent._agent.tools is None:
460
+ registering_agent._agent.tools = []
461
+
462
+ desc = docstring.description.strip() if docstring.description else ""
463
+ tool = llm_tools.spec_to_func(llm_tool_name, args, desc, awaitable)
464
+ registering_agent._agent.tools.append(tool)
465
+
364
466
  return awaitable
365
467
 
366
468
  return decorator
367
469
 
368
470
 
471
+ class RegisteringAgent:
472
+ """用于 Agent 注册"""
473
+
474
+ def llm_tool(self, *args, **kwargs):
475
+ kwargs["registering_agent"] = self
476
+ return register_llm_tool(*args, **kwargs)
477
+
478
+ def __init__(self, agent: Agent[AstrAgentContext]):
479
+ self._agent = agent
480
+
481
+
482
+ def register_agent(
483
+ name: str,
484
+ instruction: str,
485
+ tools: list[str | FunctionTool] | None = None,
486
+ run_hooks: BaseAgentRunHooks[AstrAgentContext] | None = None,
487
+ ):
488
+ """注册一个 Agent
489
+
490
+ Args:
491
+ name: Agent 的名称
492
+ instruction: Agent 的指令
493
+ tools: Agent 使用的工具列表
494
+ run_hooks: Agent 运行时的钩子函数
495
+
496
+ """
497
+ tools_ = tools or []
498
+
499
+ def decorator(awaitable: Callable[..., Awaitable[Any]]):
500
+ AstrAgent = Agent[AstrAgentContext]
501
+ agent = AstrAgent(
502
+ name=name,
503
+ instructions=instruction,
504
+ tools=tools_,
505
+ run_hooks=run_hooks or BaseAgentRunHooks[AstrAgentContext](),
506
+ )
507
+ handoff_tool = HandoffTool(agent=agent)
508
+ handoff_tool.handler = awaitable
509
+ llm_tools.func_list.append(handoff_tool)
510
+ return RegisteringAgent(agent)
511
+
512
+ return decorator
513
+
514
+
369
515
  def register_on_decorating_result(**kwargs):
370
516
  """在发送消息前的事件"""
371
517
 
372
518
  def decorator(awaitable):
373
519
  _ = get_handler_or_create(
374
- awaitable, EventType.OnDecoratingResultEvent, **kwargs
520
+ awaitable,
521
+ EventType.OnDecoratingResultEvent,
522
+ **kwargs,
375
523
  )
376
524
  return awaitable
377
525
 
@@ -383,7 +531,9 @@ def register_after_message_sent(**kwargs):
383
531
 
384
532
  def decorator(awaitable):
385
533
  _ = get_handler_or_create(
386
- awaitable, EventType.OnAfterMessageSentEvent, **kwargs
534
+ awaitable,
535
+ EventType.OnAfterMessageSentEvent,
536
+ **kwargs,
387
537
  )
388
538
  return awaitable
389
539