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,45 +1,33 @@
1
1
  import abc
2
2
  import asyncio
3
- import re
4
3
  import hashlib
4
+ import re
5
5
  import uuid
6
- from dataclasses import dataclass
7
- from typing import List, Union, Optional, AsyncGenerator
6
+ from collections.abc import AsyncGenerator
7
+ from typing import Any
8
8
 
9
+ from astrbot import logger
9
10
  from astrbot.core.db.po import Conversation
10
11
  from astrbot.core.message.components import (
11
- Plain,
12
- Image,
13
- BaseMessageComponent,
14
- Face,
15
12
  At,
16
13
  AtAll,
14
+ BaseMessageComponent,
15
+ Face,
17
16
  Forward,
17
+ Image,
18
+ Plain,
18
19
  Reply,
19
20
  )
20
- from astrbot.core.message.message_event_result import MessageEventResult, MessageChain
21
+ from astrbot.core.message.message_event_result import MessageChain, MessageEventResult
21
22
  from astrbot.core.platform.message_type import MessageType
22
23
  from astrbot.core.provider.entities import ProviderRequest
23
24
  from astrbot.core.utils.metrics import Metric
25
+
24
26
  from .astrbot_message import AstrBotMessage, Group
27
+ from .message_session import MessageSesion, MessageSession # noqa
25
28
  from .platform_metadata import PlatformMetadata
26
29
 
27
30
 
28
- @dataclass
29
- class MessageSesion:
30
- platform_name: str
31
- message_type: MessageType
32
- session_id: str
33
-
34
- def __str__(self):
35
- return f"{self.platform_name}:{self.message_type.value}:{self.session_id}"
36
-
37
- @staticmethod
38
- def from_str(session_str: str):
39
- platform_name, message_type, session_id = session_str.split(":")
40
- return MessageSesion(platform_name, MessageType(message_type), session_id)
41
-
42
-
43
31
  class AstrMessageEvent(abc.ABC):
44
32
  def __init__(
45
33
  self,
@@ -62,15 +50,15 @@ class AstrMessageEvent(abc.ABC):
62
50
  """是否唤醒(是否通过 WakingStage)"""
63
51
  self.is_at_or_wake_command = False
64
52
  """是否是 At 机器人或者带有唤醒词或者是私聊(插件注册的事件监听器会让 is_wake 设为 True, 但是不会让这个属性置为 True)"""
65
- self._extras = {}
53
+ self._extras: dict[str, Any] = {}
66
54
  self.session = MessageSesion(
67
- platform_name=platform_meta.name,
55
+ platform_name=platform_meta.id,
68
56
  message_type=message_obj.type,
69
57
  session_id=session_id,
70
58
  )
71
59
  self.unified_msg_origin = str(self.session)
72
60
  """统一的消息来源字符串。格式为 platform_name:message_type:session_id"""
73
- self._result: MessageEventResult = None
61
+ self._result: MessageEventResult | None = None
74
62
  """消息事件的结果"""
75
63
 
76
64
  self._has_send_oper = False
@@ -78,140 +66,124 @@ class AstrMessageEvent(abc.ABC):
78
66
  self.call_llm = False
79
67
  """是否在此消息事件中禁止默认的 LLM 请求"""
80
68
 
69
+ self.plugins_name: list[str] | None = None
70
+ """该事件启用的插件名称列表。None 表示所有插件都启用。空列表表示没有启用任何插件。"""
71
+
81
72
  # back_compability
82
73
  self.platform = platform_meta
83
74
 
84
75
  def get_platform_name(self):
76
+ """获取这个事件所属的平台的类型(如 aiocqhttp, slack, discord 等)。
77
+
78
+ NOTE: 用户可能会同时运行多个相同类型的平台适配器。
79
+ """
85
80
  return self.platform_meta.name
86
81
 
87
82
  def get_platform_id(self):
83
+ """获取这个事件所属的平台的 ID。
84
+
85
+ NOTE: 用户可能会同时运行多个相同类型的平台适配器,但能确定的是 ID 是唯一的。
86
+ """
88
87
  return self.platform_meta.id
89
88
 
90
89
  def get_message_str(self) -> str:
91
- """
92
- 获取消息字符串。
93
- """
90
+ """获取消息字符串。"""
94
91
  return self.message_str
95
92
 
96
- def _outline_chain(self, chain: List[BaseMessageComponent]) -> str:
97
- outline = ""
93
+ def _outline_chain(self, chain: list[BaseMessageComponent] | None) -> str:
94
+ if not chain:
95
+ return ""
96
+
97
+ parts = []
98
98
  for i in chain:
99
99
  if isinstance(i, Plain):
100
- outline += i.text
100
+ parts.append(i.text)
101
101
  elif isinstance(i, Image):
102
- outline += "[图片]"
102
+ parts.append("[图片]")
103
103
  elif isinstance(i, Face):
104
- outline += f"[表情:{i.id}]"
104
+ parts.append(f"[表情:{i.id}]")
105
105
  elif isinstance(i, At):
106
- outline += f"[At:{i.qq}]"
106
+ parts.append(f"[At:{i.qq}]")
107
107
  elif isinstance(i, AtAll):
108
- outline += "[At:全体成员]"
108
+ parts.append("[At:全体成员]")
109
109
  elif isinstance(i, Forward):
110
110
  # 转发消息
111
- outline += "[转发消息]"
111
+ parts.append("[转发消息]")
112
112
  elif isinstance(i, Reply):
113
113
  # 引用回复
114
114
  if i.message_str:
115
- outline += f"[引用消息({i.sender_nickname}: {i.message_str})]"
115
+ parts.append(f"[引用消息({i.sender_nickname}: {i.message_str})]")
116
116
  else:
117
- outline += "[引用消息]"
117
+ parts.append("[引用消息]")
118
118
  else:
119
- outline += f"[{i.type}]"
120
- outline += " "
121
- return outline
119
+ parts.append(f"[{i.type}]")
120
+ parts.append(" ")
121
+ return "".join(parts)
122
122
 
123
123
  def get_message_outline(self) -> str:
124
- """
125
- 获取消息概要。
124
+ """获取消息概要。
126
125
 
127
126
  除了文本消息外,其他消息类型会被转换为对应的占位符。如图片消息会被转换为 [图片]。
128
127
  """
129
128
  return self._outline_chain(self.message_obj.message)
130
129
 
131
- def get_messages(self) -> List[BaseMessageComponent]:
132
- """
133
- 获取消息链。
134
- """
130
+ def get_messages(self) -> list[BaseMessageComponent]:
131
+ """获取消息链。"""
135
132
  return self.message_obj.message
136
133
 
137
134
  def get_message_type(self) -> MessageType:
138
- """
139
- 获取消息类型。
140
- """
135
+ """获取消息类型。"""
141
136
  return self.message_obj.type
142
137
 
143
138
  def get_session_id(self) -> str:
144
- """
145
- 获取会话id。
146
- """
139
+ """获取会话id。"""
147
140
  return self.session_id
148
141
 
149
142
  def get_group_id(self) -> str:
150
- """
151
- 获取群组id。如果不是群组消息,返回空字符串。
152
- """
143
+ """获取群组id。如果不是群组消息,返回空字符串。"""
153
144
  return self.message_obj.group_id
154
145
 
155
146
  def get_self_id(self) -> str:
156
- """
157
- 获取机器人自身的id。
158
- """
147
+ """获取机器人自身的id。"""
159
148
  return self.message_obj.self_id
160
149
 
161
150
  def get_sender_id(self) -> str:
162
- """
163
- 获取消息发送者的id。
164
- """
151
+ """获取消息发送者的id。"""
165
152
  return self.message_obj.sender.user_id
166
153
 
167
154
  def get_sender_name(self) -> str:
168
- """
169
- 获取消息发送者的名称。(可能会返回空字符串)
170
- """
155
+ """获取消息发送者的名称。(可能会返回空字符串)"""
171
156
  return self.message_obj.sender.nickname
172
157
 
173
158
  def set_extra(self, key, value):
174
- """
175
- 设置额外的信息。
176
- """
159
+ """设置额外的信息。"""
177
160
  self._extras[key] = value
178
161
 
179
- def get_extra(self, key=None):
180
- """
181
- 获取额外的信息。
182
- """
162
+ def get_extra(self, key: str | None = None, default=None) -> Any:
163
+ """获取额外的信息。"""
183
164
  if key is None:
184
165
  return self._extras
185
- return self._extras.get(key, None)
166
+ return self._extras.get(key, default)
186
167
 
187
168
  def clear_extra(self):
188
- """
189
- 清除额外的信息。
190
- """
169
+ """清除额外的信息。"""
170
+ logger.info(f"清除 {self.get_platform_name()} 的额外信息: {self._extras}")
191
171
  self._extras.clear()
192
172
 
193
173
  def is_private_chat(self) -> bool:
194
- """
195
- 是否是私聊。
196
- """
174
+ """是否是私聊。"""
197
175
  return self.message_obj.type.value == (MessageType.FRIEND_MESSAGE).value
198
176
 
199
177
  def is_wake_up(self) -> bool:
200
- """
201
- 是否是唤醒机器人的事件。
202
- """
178
+ """是否是唤醒机器人的事件。"""
203
179
  return self.is_wake
204
180
 
205
181
  def is_admin(self) -> bool:
206
- """
207
- 是否是管理员。
208
- """
182
+ """是否是管理员。"""
209
183
  return self.role == "admin"
210
184
 
211
185
  async def process_buffer(self, buffer: str, pattern: re.Pattern) -> str:
212
- """
213
- 将消息缓冲区中的文本按指定正则表达式分割后发送至消息平台,作为不支持流式输出平台的Fallback。
214
- """
186
+ """将消息缓冲区中的文本按指定正则表达式分割后发送至消息平台,作为不支持流式输出平台的Fallback。"""
215
187
  while True:
216
188
  match = re.search(pattern, buffer)
217
189
  if not match:
@@ -223,24 +195,26 @@ class AstrMessageEvent(abc.ABC):
223
195
  return buffer
224
196
 
225
197
  async def send_streaming(
226
- self, generator: AsyncGenerator[MessageChain, None], use_fallback: bool = False
198
+ self,
199
+ generator: AsyncGenerator[MessageChain, None],
200
+ use_fallback: bool = False,
227
201
  ):
228
202
  """发送流式消息到消息平台,使用异步生成器。
229
203
  目前仅支持: telegram,qq official 私聊。
230
- Fallback仅支持 aiocqhttp, gewechat
204
+ Fallback仅支持 aiocqhttp。
231
205
  """
232
206
  asyncio.create_task(
233
- Metric.upload(msg_event_tick=1, adapter_name=self.platform_meta.name)
207
+ Metric.upload(msg_event_tick=1, adapter_name=self.platform_meta.name),
234
208
  )
235
209
  self._has_send_oper = True
236
210
 
237
211
  async def _pre_send(self):
238
- """调度器会在执行 send() 前调用该方法"""
212
+ """调度器会在执行 send() 前调用该方法 deprecated in v3.5.18"""
239
213
 
240
214
  async def _post_send(self):
241
- """调度器会在执行 send() 后调用该方法"""
215
+ """调度器会在执行 send() 后调用该方法 deprecated in v3.5.18"""
242
216
 
243
- def set_result(self, result: Union[MessageEventResult, str]):
217
+ def set_result(self, result: MessageEventResult | str):
244
218
  """设置消息事件的结果。
245
219
 
246
220
  Note:
@@ -260,9 +234,13 @@ class AstrMessageEvent(abc.ABC):
260
234
  event.set_result(MessageEventResult().set_console_log("数量已增加", logging.DEBUG).set_result_type(EventResultType.CONTINUE))
261
235
  return
262
236
  ```
237
+
263
238
  """
264
239
  if isinstance(result, str):
265
240
  result = MessageEventResult().message(result)
241
+ # 兼容外部插件或调用方传入的 chain=None 的情况,确保为可迭代列表
242
+ if isinstance(result, MessageEventResult) and result.chain is None:
243
+ result.chain = []
266
244
  self._result = result
267
245
 
268
246
  def stop_event(self):
@@ -280,41 +258,32 @@ class AstrMessageEvent(abc.ABC):
280
258
  self._result.continue_event()
281
259
 
282
260
  def is_stopped(self) -> bool:
283
- """
284
- 是否终止事件传播。
285
- """
261
+ """是否终止事件传播。"""
286
262
  if self._result is None:
287
263
  return False # 默认是继续传播
288
264
  return self._result.is_stopped()
289
265
 
290
266
  def should_call_llm(self, call_llm: bool):
291
- """
292
- 是否在此消息事件中禁止默认的 LLM 请求。
267
+ """是否在此消息事件中禁止默认的 LLM 请求。
293
268
 
294
269
  只会阻止 AstrBot 默认的 LLM 请求链路,不会阻止插件中的 LLM 请求。
295
270
  """
296
271
  self.call_llm = call_llm
297
272
 
298
273
  def get_result(self) -> MessageEventResult:
299
- """
300
- 获取消息事件的结果。
301
- """
274
+ """获取消息事件的结果。"""
302
275
  return self._result
303
276
 
304
277
  def clear_result(self):
305
- """
306
- 清除消息事件的结果。
307
- """
278
+ """清除消息事件的结果。"""
308
279
  self._result = None
309
280
 
310
281
  """消息链相关"""
311
282
 
312
283
  def make_result(self) -> MessageEventResult:
313
- """
314
- 创建一个空的消息事件结果。
284
+ """创建一个空的消息事件结果。
315
285
 
316
286
  Example:
317
-
318
287
  ```python
319
288
  # 纯文本回复
320
289
  yield event.make_result().message("Hi")
@@ -322,18 +291,16 @@ class AstrMessageEvent(abc.ABC):
322
291
  yield event.make_result().url_image("https://example.com/image.jpg")
323
292
  yield event.make_result().file_image("image.jpg")
324
293
  ```
294
+
325
295
  """
326
296
  return MessageEventResult()
327
297
 
328
298
  def plain_result(self, text: str) -> MessageEventResult:
329
- """
330
- 创建一个空的消息事件结果,只包含一条文本消息。
331
- """
299
+ """创建一个空的消息事件结果,只包含一条文本消息。"""
332
300
  return MessageEventResult().message(text)
333
301
 
334
302
  def image_result(self, url_or_path: str) -> MessageEventResult:
335
- """
336
- 创建一个空的消息事件结果,只包含一条图片消息。
303
+ """创建一个空的消息事件结果,只包含一条图片消息。
337
304
 
338
305
  根据开头是否包含 http 来判断是网络图片还是本地图片。
339
306
  """
@@ -341,10 +308,8 @@ class AstrMessageEvent(abc.ABC):
341
308
  return MessageEventResult().url_image(url_or_path)
342
309
  return MessageEventResult().file_image(url_or_path)
343
310
 
344
- def chain_result(self, chain: List[BaseMessageComponent]) -> MessageEventResult:
345
- """
346
- 创建一个空的消息事件结果,包含指定的消息链。
347
- """
311
+ def chain_result(self, chain: list[BaseMessageComponent]) -> MessageEventResult:
312
+ """创建一个空的消息事件结果,包含指定的消息链。"""
348
313
  mer = MessageEventResult()
349
314
  mer.chain = chain
350
315
  return mer
@@ -356,13 +321,12 @@ class AstrMessageEvent(abc.ABC):
356
321
  prompt: str,
357
322
  func_tool_manager=None,
358
323
  session_id: str = None,
359
- image_urls: List[str] = [],
360
- contexts: List = [],
324
+ image_urls: list[str] | None = None,
325
+ contexts: list | None = None,
361
326
  system_prompt: str = "",
362
- conversation: Conversation = None,
327
+ conversation: Conversation | None = None,
363
328
  ) -> ProviderRequest:
364
- """
365
- 创建一个 LLM 请求。
329
+ """创建一个 LLM 请求。
366
330
 
367
331
  Examples:
368
332
  ```py
@@ -381,8 +345,12 @@ class AstrMessageEvent(abc.ABC):
381
345
  func_tool_manager: 函数工具管理器,用于调用函数工具。用 self.context.get_llm_tool_manager() 获取。
382
346
 
383
347
  conversation: 可选。如果指定,将在指定的对话中进行 LLM 请求。对话的人格会被用于 LLM 请求,并且结果将会被记录到对话中。
384
- """
385
348
 
349
+ """
350
+ if image_urls is None:
351
+ image_urls = []
352
+ if contexts is None:
353
+ contexts = []
386
354
  if len(contexts) > 0 and conversation:
387
355
  conversation = None
388
356
 
@@ -403,23 +371,33 @@ class AstrMessageEvent(abc.ABC):
403
371
 
404
372
  Args:
405
373
  message (MessageChain): 消息链,具体使用方式请参考文档。
374
+
406
375
  """
407
376
  # Leverage BLAKE2 hash function to generate a non-reversible hash of the sender ID for privacy.
408
377
  hash_obj = hashlib.blake2b(self.get_sender_id().encode("utf-8"), digest_size=16)
409
378
  sid = str(uuid.UUID(bytes=hash_obj.digest()))
410
379
  asyncio.create_task(
411
380
  Metric.upload(
412
- msg_event_tick=1, adapter_name=self.platform_meta.name, sid=sid
413
- )
381
+ msg_event_tick=1,
382
+ adapter_name=self.platform_meta.name,
383
+ sid=sid,
384
+ ),
414
385
  )
415
386
  self._has_send_oper = True
416
387
 
417
- async def get_group(self, group_id: str = None, **kwargs) -> Optional[Group]:
388
+ async def react(self, emoji: str):
389
+ """对消息添加表情回应。
390
+
391
+ 默认实现为发送一条包含该表情的消息。
392
+ 注意:此实现并不一定符合所有平台的原生“表情回应”行为。
393
+ 如需支持平台原生的消息反应功能,请在对应平台的子类中重写本方法。
394
+ """
395
+ await self.send(MessageChain([Plain(emoji)]))
396
+
397
+ async def get_group(self, group_id: str | None = None, **kwargs) -> Group | None:
418
398
  """获取一个群聊的数据, 如果不填写 group_id: 如果是私聊消息,返回 None。如果是群聊消息,返回当前群聊的数据。
419
399
 
420
400
  适配情况:
421
401
 
422
- - gewechat
423
402
  - aiocqhttp(OneBotv11)
424
403
  """
425
- ...
@@ -1,14 +1,15 @@
1
1
  import time
2
- from typing import List
3
2
  from dataclasses import dataclass
3
+
4
4
  from astrbot.core.message.components import BaseMessageComponent
5
+
5
6
  from .message_type import MessageType
6
7
 
7
8
 
8
9
  @dataclass
9
10
  class MessageMember:
10
11
  user_id: str # 发送者id
11
- nickname: str = None
12
+ nickname: str | None = None
12
13
 
13
14
  def __str__(self):
14
15
  # 使用 f-string 来构建返回的字符串表示形式
@@ -22,15 +23,15 @@ class MessageMember:
22
23
  class Group:
23
24
  group_id: str
24
25
  """群号"""
25
- group_name: str = None
26
+ group_name: str | None = None
26
27
  """群名称"""
27
- group_avatar: str = None
28
+ group_avatar: str | None = None
28
29
  """群头像"""
29
- group_owner: str = None
30
+ group_owner: str | None = None
30
31
  """群主 id"""
31
- group_admins: List[str] = None
32
+ group_admins: list[str] | None = None
32
33
  """群管理员 id"""
33
- members: List[MessageMember] = None
34
+ members: list[MessageMember] | None = None
34
35
  """所有群成员"""
35
36
 
36
37
  def __str__(self):
@@ -47,23 +48,42 @@ class Group:
47
48
 
48
49
 
49
50
  class AstrBotMessage:
50
- """
51
- AstrBot 的消息对象
52
- """
51
+ """AstrBot 的消息对象"""
53
52
 
54
53
  type: MessageType # 消息类型
55
54
  self_id: str # 机器人的识别id
56
55
  session_id: str # 会话id。取决于 unique_session 的设置。
57
56
  message_id: str # 消息id
58
- group_id: str = "" # 群组id,如果为私聊,则为空
57
+ group: Group # 群组
59
58
  sender: MessageMember # 发送者
60
- message: List[BaseMessageComponent] # 消息链使用 Nakuru 的消息链格式
59
+ message: list[BaseMessageComponent] # 消息链使用 Nakuru 的消息链格式
61
60
  message_str: str # 最直观的纯文本消息字符串
62
61
  raw_message: object
63
62
  timestamp: int # 消息时间戳
64
63
 
65
64
  def __init__(self) -> None:
66
65
  self.timestamp = int(time.time())
66
+ self.group = None
67
67
 
68
68
  def __str__(self) -> str:
69
69
  return str(self.__dict__)
70
+
71
+ @property
72
+ def group_id(self) -> str:
73
+ """向后兼容的 group_id 属性
74
+ 群组id,如果为私聊,则为空
75
+ """
76
+ if self.group:
77
+ return self.group.group_id
78
+ return ""
79
+
80
+ @group_id.setter
81
+ def group_id(self, value: str):
82
+ """设置 group_id"""
83
+ if value:
84
+ if self.group:
85
+ self.group.group_id = value
86
+ else:
87
+ self.group = Group(group_id=value)
88
+ else:
89
+ self.group = None