AstrBot 4.5.1__py3-none-any.whl → 4.5.3__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 (244) hide show
  1. astrbot/api/__init__.py +10 -11
  2. astrbot/api/event/__init__.py +5 -6
  3. astrbot/api/event/filter/__init__.py +37 -36
  4. astrbot/api/platform/__init__.py +7 -8
  5. astrbot/api/provider/__init__.py +7 -7
  6. astrbot/api/star/__init__.py +3 -4
  7. astrbot/api/util/__init__.py +2 -2
  8. astrbot/cli/__main__.py +5 -5
  9. astrbot/cli/commands/__init__.py +3 -3
  10. astrbot/cli/commands/cmd_conf.py +19 -16
  11. astrbot/cli/commands/cmd_init.py +3 -2
  12. astrbot/cli/commands/cmd_plug.py +8 -10
  13. astrbot/cli/commands/cmd_run.py +5 -6
  14. astrbot/cli/utils/__init__.py +6 -6
  15. astrbot/cli/utils/basic.py +14 -14
  16. astrbot/cli/utils/plugin.py +24 -15
  17. astrbot/cli/utils/version_comparator.py +10 -12
  18. astrbot/core/__init__.py +8 -6
  19. astrbot/core/agent/agent.py +3 -2
  20. astrbot/core/agent/handoff.py +6 -2
  21. astrbot/core/agent/hooks.py +9 -6
  22. astrbot/core/agent/mcp_client.py +50 -15
  23. astrbot/core/agent/message.py +168 -0
  24. astrbot/core/agent/response.py +2 -1
  25. astrbot/core/agent/run_context.py +2 -3
  26. astrbot/core/agent/runners/base.py +10 -13
  27. astrbot/core/agent/runners/tool_loop_agent_runner.py +52 -51
  28. astrbot/core/agent/tool.py +60 -41
  29. astrbot/core/agent/tool_executor.py +9 -3
  30. astrbot/core/astr_agent_context.py +3 -1
  31. astrbot/core/astrbot_config_mgr.py +29 -9
  32. astrbot/core/config/__init__.py +2 -2
  33. astrbot/core/config/astrbot_config.py +28 -26
  34. astrbot/core/config/default.py +4 -6
  35. astrbot/core/conversation_mgr.py +105 -36
  36. astrbot/core/core_lifecycle.py +68 -54
  37. astrbot/core/db/__init__.py +33 -18
  38. astrbot/core/db/migration/helper.py +12 -10
  39. astrbot/core/db/migration/migra_3_to_4.py +53 -34
  40. astrbot/core/db/migration/migra_45_to_46.py +1 -1
  41. astrbot/core/db/migration/shared_preferences_v3.py +2 -1
  42. astrbot/core/db/migration/sqlite_v3.py +26 -23
  43. astrbot/core/db/po.py +27 -18
  44. astrbot/core/db/sqlite.py +74 -45
  45. astrbot/core/db/vec_db/base.py +10 -14
  46. astrbot/core/db/vec_db/faiss_impl/document_storage.py +90 -77
  47. astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +9 -3
  48. astrbot/core/db/vec_db/faiss_impl/vec_db.py +36 -31
  49. astrbot/core/event_bus.py +8 -6
  50. astrbot/core/file_token_service.py +6 -5
  51. astrbot/core/initial_loader.py +7 -5
  52. astrbot/core/knowledge_base/chunking/__init__.py +1 -3
  53. astrbot/core/knowledge_base/chunking/base.py +1 -0
  54. astrbot/core/knowledge_base/chunking/fixed_size.py +2 -0
  55. astrbot/core/knowledge_base/chunking/recursive.py +16 -10
  56. astrbot/core/knowledge_base/kb_db_sqlite.py +50 -48
  57. astrbot/core/knowledge_base/kb_helper.py +30 -17
  58. astrbot/core/knowledge_base/kb_mgr.py +6 -7
  59. astrbot/core/knowledge_base/models.py +10 -4
  60. astrbot/core/knowledge_base/parsers/__init__.py +3 -5
  61. astrbot/core/knowledge_base/parsers/base.py +1 -0
  62. astrbot/core/knowledge_base/parsers/markitdown_parser.py +2 -1
  63. astrbot/core/knowledge_base/parsers/pdf_parser.py +2 -1
  64. astrbot/core/knowledge_base/parsers/text_parser.py +1 -0
  65. astrbot/core/knowledge_base/parsers/util.py +1 -1
  66. astrbot/core/knowledge_base/retrieval/__init__.py +6 -8
  67. astrbot/core/knowledge_base/retrieval/manager.py +17 -14
  68. astrbot/core/knowledge_base/retrieval/rank_fusion.py +7 -3
  69. astrbot/core/knowledge_base/retrieval/sparse_retriever.py +11 -5
  70. astrbot/core/log.py +21 -13
  71. astrbot/core/message/components.py +123 -217
  72. astrbot/core/message/message_event_result.py +24 -24
  73. astrbot/core/persona_mgr.py +20 -11
  74. astrbot/core/pipeline/__init__.py +7 -7
  75. astrbot/core/pipeline/content_safety_check/stage.py +13 -9
  76. astrbot/core/pipeline/content_safety_check/strategies/__init__.py +1 -2
  77. astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +12 -13
  78. astrbot/core/pipeline/content_safety_check/strategies/keywords.py +1 -0
  79. astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
  80. astrbot/core/pipeline/context.py +4 -1
  81. astrbot/core/pipeline/context_utils.py +77 -7
  82. astrbot/core/pipeline/preprocess_stage/stage.py +12 -9
  83. astrbot/core/pipeline/process_stage/method/llm_request.py +125 -72
  84. astrbot/core/pipeline/process_stage/method/star_request.py +19 -17
  85. astrbot/core/pipeline/process_stage/stage.py +13 -10
  86. astrbot/core/pipeline/process_stage/utils.py +6 -5
  87. astrbot/core/pipeline/rate_limit_check/stage.py +37 -36
  88. astrbot/core/pipeline/respond/stage.py +23 -20
  89. astrbot/core/pipeline/result_decorate/stage.py +31 -23
  90. astrbot/core/pipeline/scheduler.py +12 -8
  91. astrbot/core/pipeline/session_status_check/stage.py +12 -8
  92. astrbot/core/pipeline/stage.py +10 -4
  93. astrbot/core/pipeline/waking_check/stage.py +24 -18
  94. astrbot/core/pipeline/whitelist_check/stage.py +10 -7
  95. astrbot/core/platform/__init__.py +6 -6
  96. astrbot/core/platform/astr_message_event.py +76 -110
  97. astrbot/core/platform/astrbot_message.py +11 -13
  98. astrbot/core/platform/manager.py +16 -15
  99. astrbot/core/platform/message_session.py +5 -3
  100. astrbot/core/platform/platform.py +16 -24
  101. astrbot/core/platform/platform_metadata.py +4 -4
  102. astrbot/core/platform/register.py +8 -8
  103. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +23 -15
  104. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +51 -33
  105. astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +42 -27
  106. astrbot/core/platform/sources/dingtalk/dingtalk_event.py +7 -3
  107. astrbot/core/platform/sources/discord/client.py +9 -6
  108. astrbot/core/platform/sources/discord/components.py +18 -14
  109. astrbot/core/platform/sources/discord/discord_platform_adapter.py +45 -30
  110. astrbot/core/platform/sources/discord/discord_platform_event.py +38 -30
  111. astrbot/core/platform/sources/lark/lark_adapter.py +23 -17
  112. astrbot/core/platform/sources/lark/lark_event.py +21 -14
  113. astrbot/core/platform/sources/misskey/misskey_adapter.py +107 -67
  114. astrbot/core/platform/sources/misskey/misskey_api.py +153 -129
  115. astrbot/core/platform/sources/misskey/misskey_event.py +20 -15
  116. astrbot/core/platform/sources/misskey/misskey_utils.py +74 -62
  117. astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +63 -44
  118. astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +41 -26
  119. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +36 -17
  120. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +3 -1
  121. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +12 -7
  122. astrbot/core/platform/sources/satori/satori_adapter.py +56 -38
  123. astrbot/core/platform/sources/satori/satori_event.py +34 -25
  124. astrbot/core/platform/sources/slack/client.py +11 -9
  125. astrbot/core/platform/sources/slack/slack_adapter.py +52 -36
  126. astrbot/core/platform/sources/slack/slack_event.py +34 -24
  127. astrbot/core/platform/sources/telegram/tg_adapter.py +38 -18
  128. astrbot/core/platform/sources/telegram/tg_event.py +32 -18
  129. astrbot/core/platform/sources/webchat/webchat_adapter.py +27 -17
  130. astrbot/core/platform/sources/webchat/webchat_event.py +14 -10
  131. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +115 -120
  132. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +9 -8
  133. astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +15 -16
  134. astrbot/core/platform/sources/wecom/wecom_adapter.py +35 -18
  135. astrbot/core/platform/sources/wecom/wecom_event.py +55 -48
  136. astrbot/core/platform/sources/wecom/wecom_kf.py +34 -44
  137. astrbot/core/platform/sources/wecom/wecom_kf_message.py +26 -10
  138. astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +18 -10
  139. astrbot/core/platform/sources/wecom_ai_bot/__init__.py +3 -5
  140. astrbot/core/platform/sources/wecom_ai_bot/ierror.py +0 -1
  141. astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +61 -37
  142. astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +67 -28
  143. astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +8 -9
  144. astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +18 -9
  145. astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +14 -12
  146. astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +22 -12
  147. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +40 -26
  148. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +47 -45
  149. astrbot/core/platform_message_history_mgr.py +5 -3
  150. astrbot/core/provider/__init__.py +2 -3
  151. astrbot/core/provider/entites.py +8 -8
  152. astrbot/core/provider/entities.py +61 -75
  153. astrbot/core/provider/func_tool_manager.py +59 -55
  154. astrbot/core/provider/manager.py +32 -22
  155. astrbot/core/provider/provider.py +72 -46
  156. astrbot/core/provider/register.py +7 -7
  157. astrbot/core/provider/sources/anthropic_source.py +48 -30
  158. astrbot/core/provider/sources/azure_tts_source.py +17 -13
  159. astrbot/core/provider/sources/coze_api_client.py +27 -17
  160. astrbot/core/provider/sources/coze_source.py +104 -87
  161. astrbot/core/provider/sources/dashscope_source.py +18 -11
  162. astrbot/core/provider/sources/dashscope_tts.py +36 -23
  163. astrbot/core/provider/sources/dify_source.py +25 -20
  164. astrbot/core/provider/sources/edge_tts_source.py +21 -17
  165. astrbot/core/provider/sources/fishaudio_tts_api_source.py +22 -14
  166. astrbot/core/provider/sources/gemini_embedding_source.py +12 -13
  167. astrbot/core/provider/sources/gemini_source.py +72 -58
  168. astrbot/core/provider/sources/gemini_tts_source.py +8 -6
  169. astrbot/core/provider/sources/gsv_selfhosted_source.py +17 -14
  170. astrbot/core/provider/sources/gsvi_tts_source.py +11 -7
  171. astrbot/core/provider/sources/minimax_tts_api_source.py +50 -40
  172. astrbot/core/provider/sources/openai_embedding_source.py +6 -8
  173. astrbot/core/provider/sources/openai_source.py +77 -69
  174. astrbot/core/provider/sources/openai_tts_api_source.py +14 -6
  175. astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
  176. astrbot/core/provider/sources/vllm_rerank_source.py +10 -4
  177. astrbot/core/provider/sources/volcengine_tts.py +38 -31
  178. astrbot/core/provider/sources/whisper_api_source.py +14 -12
  179. astrbot/core/provider/sources/whisper_selfhosted_source.py +15 -11
  180. astrbot/core/provider/sources/xinference_rerank_source.py +16 -8
  181. astrbot/core/provider/sources/xinference_stt_provider.py +35 -25
  182. astrbot/core/star/__init__.py +16 -11
  183. astrbot/core/star/config.py +10 -15
  184. astrbot/core/star/context.py +97 -75
  185. astrbot/core/star/filter/__init__.py +4 -3
  186. astrbot/core/star/filter/command.py +30 -28
  187. astrbot/core/star/filter/command_group.py +27 -24
  188. astrbot/core/star/filter/custom_filter.py +6 -5
  189. astrbot/core/star/filter/event_message_type.py +4 -2
  190. astrbot/core/star/filter/permission.py +4 -2
  191. astrbot/core/star/filter/platform_adapter_type.py +4 -2
  192. astrbot/core/star/filter/regex.py +4 -2
  193. astrbot/core/star/register/__init__.py +19 -19
  194. astrbot/core/star/register/star.py +6 -2
  195. astrbot/core/star/register/star_handler.py +96 -73
  196. astrbot/core/star/session_llm_manager.py +48 -14
  197. astrbot/core/star/session_plugin_manager.py +29 -15
  198. astrbot/core/star/star.py +1 -2
  199. astrbot/core/star/star_handler.py +13 -8
  200. astrbot/core/star/star_manager.py +151 -59
  201. astrbot/core/star/star_tools.py +44 -37
  202. astrbot/core/star/updator.py +10 -10
  203. astrbot/core/umop_config_router.py +10 -4
  204. astrbot/core/updator.py +13 -5
  205. astrbot/core/utils/astrbot_path.py +3 -5
  206. astrbot/core/utils/dify_api_client.py +33 -15
  207. astrbot/core/utils/io.py +66 -42
  208. astrbot/core/utils/log_pipe.py +1 -1
  209. astrbot/core/utils/metrics.py +7 -7
  210. astrbot/core/utils/path_util.py +15 -16
  211. astrbot/core/utils/pip_installer.py +5 -5
  212. astrbot/core/utils/session_waiter.py +19 -20
  213. astrbot/core/utils/shared_preferences.py +45 -20
  214. astrbot/core/utils/t2i/__init__.py +4 -1
  215. astrbot/core/utils/t2i/network_strategy.py +35 -26
  216. astrbot/core/utils/t2i/renderer.py +11 -5
  217. astrbot/core/utils/t2i/template_manager.py +14 -15
  218. astrbot/core/utils/tencent_record_helper.py +19 -13
  219. astrbot/core/utils/version_comparator.py +10 -13
  220. astrbot/core/zip_updator.py +43 -40
  221. astrbot/dashboard/routes/__init__.py +18 -18
  222. astrbot/dashboard/routes/auth.py +10 -8
  223. astrbot/dashboard/routes/chat.py +30 -21
  224. astrbot/dashboard/routes/config.py +92 -75
  225. astrbot/dashboard/routes/conversation.py +46 -39
  226. astrbot/dashboard/routes/file.py +4 -2
  227. astrbot/dashboard/routes/knowledge_base.py +47 -40
  228. astrbot/dashboard/routes/log.py +9 -4
  229. astrbot/dashboard/routes/persona.py +19 -16
  230. astrbot/dashboard/routes/plugin.py +69 -55
  231. astrbot/dashboard/routes/route.py +3 -1
  232. astrbot/dashboard/routes/session_management.py +130 -116
  233. astrbot/dashboard/routes/stat.py +34 -34
  234. astrbot/dashboard/routes/t2i.py +15 -12
  235. astrbot/dashboard/routes/tools.py +56 -53
  236. astrbot/dashboard/routes/update.py +32 -28
  237. astrbot/dashboard/server.py +30 -26
  238. astrbot/dashboard/utils.py +8 -4
  239. {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/METADATA +2 -1
  240. astrbot-4.5.3.dist-info/RECORD +261 -0
  241. astrbot-4.5.1.dist-info/RECORD +0 -260
  242. {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/WHEEL +0 -0
  243. {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/entry_points.txt +0 -0
  244. {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,10 @@
1
1
  import asyncio
2
+ import os
2
3
  import random
3
- from typing import Dict, Any, Optional, Awaitable, List
4
+ from collections.abc import Awaitable
5
+ from typing import Any
4
6
 
7
+ import astrbot.api.message_components as Comp
5
8
  from astrbot.api import logger
6
9
  from astrbot.api.event import MessageChain
7
10
  from astrbot.api.platform import (
@@ -11,32 +14,31 @@ from astrbot.api.platform import (
11
14
  register_platform_adapter,
12
15
  )
13
16
  from astrbot.core.platform.astr_message_event import MessageSession
14
- import astrbot.api.message_components as Comp
15
17
 
16
18
  from .misskey_api import MisskeyAPI
17
- import os
18
19
 
19
20
  try:
20
21
  import magic # type: ignore
21
22
  except Exception:
22
23
  magic = None
23
24
 
25
+ from astrbot.core.utils.astrbot_path import get_astrbot_data_path
26
+
24
27
  from .misskey_event import MisskeyPlatformEvent
25
28
  from .misskey_utils import (
26
- serialize_message_chain,
27
- resolve_message_visibility,
28
- is_valid_user_session_id,
29
- is_valid_room_session_id,
30
29
  add_at_mention_if_needed,
31
- process_files,
32
- extract_sender_info,
30
+ cache_room_info,
31
+ cache_user_info,
33
32
  create_base_message,
34
- process_at_mention,
33
+ extract_sender_info,
35
34
  format_poll,
36
- cache_user_info,
37
- cache_room_info,
35
+ is_valid_room_session_id,
36
+ is_valid_user_session_id,
37
+ process_at_mention,
38
+ process_files,
39
+ resolve_message_visibility,
40
+ serialize_message_chain,
38
41
  )
39
- from astrbot.core.utils.astrbot_path import get_astrbot_data_path
40
42
 
41
43
  # Constants
42
44
  MAX_FILE_UPLOAD_COUNT = 16
@@ -46,7 +48,10 @@ DEFAULT_UPLOAD_CONCURRENCY = 3
46
48
  @register_platform_adapter("misskey", "Misskey 平台适配器")
47
49
  class MisskeyPlatformAdapter(Platform):
48
50
  def __init__(
49
- self, platform_config: dict, platform_settings: dict, event_queue: asyncio.Queue
51
+ self,
52
+ platform_config: dict,
53
+ platform_settings: dict,
54
+ event_queue: asyncio.Queue,
50
55
  ) -> None:
51
56
  super().__init__(event_queue)
52
57
  self.config = platform_config or {}
@@ -55,7 +60,8 @@ class MisskeyPlatformAdapter(Platform):
55
60
  self.access_token = self.config.get("misskey_token", "")
56
61
  self.max_message_length = self.config.get("max_message_length", 3000)
57
62
  self.default_visibility = self.config.get(
58
- "misskey_default_visibility", "public"
63
+ "misskey_default_visibility",
64
+ "public",
59
65
  )
60
66
  self.local_only = self.config.get("misskey_local_only", False)
61
67
  self.enable_chat = self.config.get("misskey_enable_chat", True)
@@ -64,7 +70,7 @@ class MisskeyPlatformAdapter(Platform):
64
70
 
65
71
  # download / security related options (exposed to platform_config)
66
72
  self.allow_insecure_downloads = bool(
67
- self.config.get("misskey_allow_insecure_downloads", False)
73
+ self.config.get("misskey_allow_insecure_downloads", False),
68
74
  )
69
75
  # parse download timeout and chunk size safely
70
76
  _dt = self.config.get("misskey_download_timeout")
@@ -87,7 +93,7 @@ class MisskeyPlatformAdapter(Platform):
87
93
 
88
94
  self.unique_session = platform_settings["unique_session"]
89
95
 
90
- self.api: Optional[MisskeyAPI] = None
96
+ self.api: MisskeyAPI | None = None
91
97
  self._running = False
92
98
  self.client_self_id = ""
93
99
  self._bot_username = ""
@@ -136,7 +142,7 @@ class MisskeyPlatformAdapter(Platform):
136
142
  self.client_self_id = str(user_info.get("id", ""))
137
143
  self._bot_username = user_info.get("username", "")
138
144
  logger.info(
139
- f"[Misskey] 已连接用户: {self._bot_username} (ID: {self.client_self_id})"
145
+ f"[Misskey] 已连接用户: {self._bot_username} (ID: {self.client_self_id})",
140
146
  )
141
147
  except Exception as e:
142
148
  logger.error(f"[Misskey] 获取用户信息失败: {e}")
@@ -153,12 +159,17 @@ class MisskeyPlatformAdapter(Platform):
153
159
  if self.enable_chat:
154
160
  streaming.add_message_handler("newChatMessage", self._handle_chat_message)
155
161
  streaming.add_message_handler(
156
- "messaging:newChatMessage", self._handle_chat_message
162
+ "messaging:newChatMessage",
163
+ self._handle_chat_message,
157
164
  )
158
165
  streaming.add_message_handler("_debug", self._debug_handler)
159
166
 
160
167
  async def _send_text_only_message(
161
- self, session_id: str, text: str, session, message_chain
168
+ self,
169
+ session_id: str,
170
+ text: str,
171
+ session,
172
+ message_chain,
162
173
  ):
163
174
  """发送纯文本消息(无文件上传)"""
164
175
  if not self.api:
@@ -168,7 +179,7 @@ class MisskeyPlatformAdapter(Platform):
168
179
  from .misskey_utils import extract_user_id_from_session_id
169
180
 
170
181
  user_id = extract_user_id_from_session_id(session_id)
171
- payload: Dict[str, Any] = {"toUserId": user_id, "text": text}
182
+ payload: dict[str, Any] = {"toUserId": user_id, "text": text}
172
183
  await self.api.send_message(payload)
173
184
  elif session_id and is_valid_room_session_id(session_id):
174
185
  from .misskey_utils import extract_room_id_from_session_id
@@ -180,14 +191,17 @@ class MisskeyPlatformAdapter(Platform):
180
191
  return await super().send_by_session(session, message_chain)
181
192
 
182
193
  def _process_poll_data(
183
- self, message: AstrBotMessage, poll: Dict[str, Any], message_parts: List[str]
194
+ self,
195
+ message: AstrBotMessage,
196
+ poll: dict[str, Any],
197
+ message_parts: list[str],
184
198
  ):
185
199
  """处理投票数据,将其添加到消息中"""
186
200
  try:
187
201
  if not isinstance(message.raw_message, dict):
188
202
  message.raw_message = {}
189
203
  message.raw_message["poll"] = poll
190
- setattr(message, "poll", poll)
204
+ message.poll = poll
191
205
  except Exception:
192
206
  pass
193
207
 
@@ -196,25 +210,26 @@ class MisskeyPlatformAdapter(Platform):
196
210
  message.message.append(Comp.Plain(poll_text))
197
211
  message_parts.append(poll_text)
198
212
 
199
- def _extract_additional_fields(self, session, message_chain) -> Dict[str, Any]:
213
+ def _extract_additional_fields(self, session, message_chain) -> dict[str, Any]:
200
214
  """从会话和消息链中提取额外字段"""
201
215
  fields = {"cw": None, "poll": None, "renote_id": None, "channel_id": None}
202
216
 
203
217
  for comp in message_chain.chain:
204
218
  if hasattr(comp, "cw") and getattr(comp, "cw", None):
205
- fields["cw"] = getattr(comp, "cw")
219
+ fields["cw"] = comp.cw
206
220
  break
207
221
 
208
222
  if hasattr(session, "extra_data") and isinstance(
209
- getattr(session, "extra_data", None), dict
223
+ getattr(session, "extra_data", None),
224
+ dict,
210
225
  ):
211
- extra_data = getattr(session, "extra_data")
226
+ extra_data = session.extra_data
212
227
  fields.update(
213
228
  {
214
229
  "poll": extra_data.get("poll"),
215
230
  "renote_id": extra_data.get("renote_id"),
216
231
  "channel_id": extra_data.get("channel_id"),
217
- }
232
+ },
218
233
  )
219
234
 
220
235
  return fields
@@ -237,7 +252,7 @@ class MisskeyPlatformAdapter(Platform):
237
252
 
238
253
  if await streaming.connect():
239
254
  logger.info(
240
- f"[Misskey] WebSocket 已连接 (尝试 #{connection_attempts})"
255
+ f"[Misskey] WebSocket 已连接 (尝试 #{connection_attempts})",
241
256
  )
242
257
  connection_attempts = 0
243
258
  await streaming.subscribe_channel("main")
@@ -250,34 +265,34 @@ class MisskeyPlatformAdapter(Platform):
250
265
  await streaming.listen()
251
266
  else:
252
267
  logger.error(
253
- f"[Misskey] WebSocket 连接失败 (尝试 #{connection_attempts})"
268
+ f"[Misskey] WebSocket 连接失败 (尝试 #{connection_attempts})",
254
269
  )
255
270
 
256
271
  except Exception as e:
257
272
  logger.error(
258
- f"[Misskey] WebSocket 异常 (尝试 #{connection_attempts}): {e}"
273
+ f"[Misskey] WebSocket 异常 (尝试 #{connection_attempts}): {e}",
259
274
  )
260
275
 
261
276
  if self._running:
262
277
  jitter = random.uniform(0, 1.0)
263
278
  sleep_time = backoff_delay + jitter
264
279
  logger.info(
265
- f"[Misskey] {sleep_time:.1f}秒后重连 (下次尝试 #{connection_attempts + 1})"
280
+ f"[Misskey] {sleep_time:.1f}秒后重连 (下次尝试 #{connection_attempts + 1})",
266
281
  )
267
282
  await asyncio.sleep(sleep_time)
268
283
  backoff_delay = min(backoff_delay * backoff_multiplier, max_backoff)
269
284
 
270
- async def _handle_notification(self, data: Dict[str, Any]):
285
+ async def _handle_notification(self, data: dict[str, Any]):
271
286
  try:
272
287
  notification_type = data.get("type")
273
288
  logger.debug(
274
- f"[Misskey] 收到通知事件: type={notification_type}, user_id={data.get('userId', 'unknown')}"
289
+ f"[Misskey] 收到通知事件: type={notification_type}, user_id={data.get('userId', 'unknown')}",
275
290
  )
276
291
  if notification_type in ["mention", "reply", "quote"]:
277
292
  note = data.get("note")
278
293
  if note and self._is_bot_mentioned(note):
279
294
  logger.info(
280
- f"[Misskey] 处理贴文提及: {note.get('text', '')[:50]}..."
295
+ f"[Misskey] 处理贴文提及: {note.get('text', '')[:50]}...",
281
296
  )
282
297
  message = await self.convert_message(note)
283
298
  event = MisskeyPlatformEvent(
@@ -291,14 +306,14 @@ class MisskeyPlatformAdapter(Platform):
291
306
  except Exception as e:
292
307
  logger.error(f"[Misskey] 处理通知失败: {e}")
293
308
 
294
- async def _handle_chat_message(self, data: Dict[str, Any]):
309
+ async def _handle_chat_message(self, data: dict[str, Any]):
295
310
  try:
296
311
  sender_id = str(
297
- data.get("fromUserId", "") or data.get("fromUser", {}).get("id", "")
312
+ data.get("fromUserId", "") or data.get("fromUser", {}).get("id", ""),
298
313
  )
299
314
  room_id = data.get("toRoomId")
300
315
  logger.debug(
301
- f"[Misskey] 收到聊天事件: sender_id={sender_id}, room_id={room_id}, is_self={sender_id == self.client_self_id}"
316
+ f"[Misskey] 收到聊天事件: sender_id={sender_id}, room_id={room_id}, is_self={sender_id == self.client_self_id}",
302
317
  )
303
318
  if sender_id == self.client_self_id:
304
319
  return
@@ -306,7 +321,7 @@ class MisskeyPlatformAdapter(Platform):
306
321
  if room_id:
307
322
  raw_text = data.get("text", "")
308
323
  logger.debug(
309
- f"[Misskey] 检查群聊消息: '{raw_text}', 机器人用户名: '{self._bot_username}'"
324
+ f"[Misskey] 检查群聊消息: '{raw_text}', 机器人用户名: '{self._bot_username}'",
310
325
  )
311
326
 
312
327
  message = await self.convert_room_message(data)
@@ -326,13 +341,13 @@ class MisskeyPlatformAdapter(Platform):
326
341
  except Exception as e:
327
342
  logger.error(f"[Misskey] 处理聊天消息失败: {e}")
328
343
 
329
- async def _debug_handler(self, data: Dict[str, Any]):
344
+ async def _debug_handler(self, data: dict[str, Any]):
330
345
  event_type = data.get("type", "unknown")
331
346
  logger.debug(
332
- f"[Misskey] 收到未处理事件: type={event_type}, channel={data.get('channel', 'unknown')}"
347
+ f"[Misskey] 收到未处理事件: type={event_type}, channel={data.get('channel', 'unknown')}",
333
348
  )
334
349
 
335
- def _is_bot_mentioned(self, note: Dict[str, Any]) -> bool:
350
+ def _is_bot_mentioned(self, note: dict[str, Any]) -> bool:
336
351
  text = note.get("text", "")
337
352
  if not text:
338
353
  return False
@@ -352,7 +367,9 @@ class MisskeyPlatformAdapter(Platform):
352
367
  return False
353
368
 
354
369
  async def send_by_session(
355
- self, session: MessageSession, message_chain: MessageChain
370
+ self,
371
+ session: MessageSession,
372
+ message_chain: MessageChain,
356
373
  ) -> Awaitable[Any]:
357
374
  if not self.api:
358
375
  logger.error("[Misskey] API 客户端未初始化")
@@ -394,30 +411,33 @@ class MisskeyPlatformAdapter(Platform):
394
411
  if not has_file_components:
395
412
  logger.warning("[Misskey] 消息内容为空且无文件组件,跳过发送")
396
413
  return await super().send_by_session(session, message_chain)
397
- else:
398
- text = ""
414
+ text = ""
399
415
 
400
416
  if len(text) > self.max_message_length:
401
417
  text = text[: self.max_message_length] + "..."
402
418
 
403
- file_ids: List[str] = []
404
- fallback_urls: List[str] = []
419
+ file_ids: list[str] = []
420
+ fallback_urls: list[str] = []
405
421
 
406
422
  if not self.enable_file_upload:
407
423
  return await self._send_text_only_message(
408
- session_id, text, session, message_chain
424
+ session_id,
425
+ text,
426
+ session,
427
+ message_chain,
409
428
  )
410
429
 
411
430
  MAX_UPLOAD_CONCURRENCY = 10
412
431
  upload_concurrency = int(
413
432
  self.config.get(
414
- "misskey_upload_concurrency", DEFAULT_UPLOAD_CONCURRENCY
415
- )
433
+ "misskey_upload_concurrency",
434
+ DEFAULT_UPLOAD_CONCURRENCY,
435
+ ),
416
436
  )
417
437
  upload_concurrency = min(upload_concurrency, MAX_UPLOAD_CONCURRENCY)
418
438
  sem = asyncio.Semaphore(upload_concurrency)
419
439
 
420
- async def _upload_comp(comp) -> Optional[object]:
440
+ async def _upload_comp(comp) -> object | None:
421
441
  """组件上传函数:处理 URL(下载后上传)或本地文件(直接上传)"""
422
442
  from .misskey_utils import (
423
443
  resolve_component_url_or_path,
@@ -432,14 +452,16 @@ class MisskeyPlatformAdapter(Platform):
432
452
 
433
453
  # 解析组件的 URL 或本地路径
434
454
  url_candidate, local_path = await resolve_component_url_or_path(
435
- comp
455
+ comp,
436
456
  )
437
457
 
438
458
  if not url_candidate and not local_path:
439
459
  return None
440
460
 
441
461
  preferred_name = getattr(comp, "name", None) or getattr(
442
- comp, "file", None
462
+ comp,
463
+ "file",
464
+ None,
443
465
  )
444
466
 
445
467
  # URL 上传:下载后本地上传
@@ -479,7 +501,7 @@ class MisskeyPlatformAdapter(Platform):
479
501
  if local_path and isinstance(local_path, str):
480
502
  data_temp = os.path.join(get_astrbot_data_path(), "temp")
481
503
  if local_path.startswith(data_temp) and os.path.exists(
482
- local_path
504
+ local_path,
483
505
  ):
484
506
  try:
485
507
  os.remove(local_path)
@@ -508,7 +530,7 @@ class MisskeyPlatformAdapter(Platform):
508
530
 
509
531
  if len(file_components) > MAX_FILE_UPLOAD_COUNT:
510
532
  logger.warning(
511
- f"[Misskey] 文件数量超过限制 ({len(file_components)} > {MAX_FILE_UPLOAD_COUNT}),只上传前{MAX_FILE_UPLOAD_COUNT}个文件"
533
+ f"[Misskey] 文件数量超过限制 ({len(file_components)} > {MAX_FILE_UPLOAD_COUNT}),只上传前{MAX_FILE_UPLOAD_COUNT}个文件",
512
534
  )
513
535
  file_components = file_components[:MAX_FILE_UPLOAD_COUNT]
514
536
 
@@ -540,7 +562,7 @@ class MisskeyPlatformAdapter(Platform):
540
562
  if fallback_urls:
541
563
  appended = "\n" + "\n".join(fallback_urls)
542
564
  text = (text or "") + appended
543
- payload: Dict[str, Any] = {"toRoomId": room_id, "text": text}
565
+ payload: dict[str, Any] = {"toRoomId": room_id, "text": text}
544
566
  if file_ids:
545
567
  payload["fileIds"] = file_ids
546
568
  await self.api.send_room_message(payload)
@@ -555,13 +577,13 @@ class MisskeyPlatformAdapter(Platform):
555
577
  if fallback_urls:
556
578
  appended = "\n" + "\n".join(fallback_urls)
557
579
  text = (text or "") + appended
558
- payload: Dict[str, Any] = {"toUserId": user_id, "text": text}
580
+ payload: dict[str, Any] = {"toUserId": user_id, "text": text}
559
581
  if file_ids:
560
582
  # 聊天消息只支持单个文件,使用 fileId 而不是 fileIds
561
583
  payload["fileId"] = file_ids[0]
562
584
  if len(file_ids) > 1:
563
585
  logger.warning(
564
- f"[Misskey] 聊天消息只支持单个文件,忽略其余 {len(file_ids) - 1} 个文件"
586
+ f"[Misskey] 聊天消息只支持单个文件,忽略其余 {len(file_ids) - 1} 个文件",
565
587
  )
566
588
  await self.api.send_message(payload)
567
589
  else:
@@ -581,7 +603,7 @@ class MisskeyPlatformAdapter(Platform):
581
603
  default_visibility=self.default_visibility,
582
604
  )
583
605
  logger.debug(
584
- f"[Misskey] 解析可见性: visibility={visibility}, visible_user_ids={visible_user_ids}, session_id={session_id}, user_id_for_cache={user_id_for_cache}"
606
+ f"[Misskey] 解析可见性: visibility={visibility}, visible_user_ids={visible_user_ids}, session_id={session_id}, user_id_for_cache={user_id_for_cache}",
585
607
  )
586
608
 
587
609
  fields = self._extract_additional_fields(session, message_chain)
@@ -610,7 +632,7 @@ class MisskeyPlatformAdapter(Platform):
610
632
 
611
633
  return await super().send_by_session(session, message_chain)
612
634
 
613
- async def convert_message(self, raw_data: Dict[str, Any]) -> AstrBotMessage:
635
+ async def convert_message(self, raw_data: dict[str, Any]) -> AstrBotMessage:
614
636
  """将 Misskey 贴文数据转换为 AstrBotMessage 对象"""
615
637
  sender_info = extract_sender_info(raw_data, is_chat=False)
616
638
  message = create_base_message(
@@ -621,7 +643,11 @@ class MisskeyPlatformAdapter(Platform):
621
643
  unique_session=self.unique_session,
622
644
  )
623
645
  cache_user_info(
624
- self._user_cache, sender_info, raw_data, self.client_self_id, is_chat=False
646
+ self._user_cache,
647
+ sender_info,
648
+ raw_data,
649
+ self.client_self_id,
650
+ is_chat=False,
625
651
  )
626
652
 
627
653
  message_parts = []
@@ -629,7 +655,10 @@ class MisskeyPlatformAdapter(Platform):
629
655
 
630
656
  if raw_text:
631
657
  text_parts, processed_text = process_at_mention(
632
- message, raw_text, self._bot_username, self.client_self_id
658
+ message,
659
+ raw_text,
660
+ self._bot_username,
661
+ self.client_self_id,
633
662
  )
634
663
  message_parts.extend(text_parts)
635
664
 
@@ -652,7 +681,7 @@ class MisskeyPlatformAdapter(Platform):
652
681
  )
653
682
  return message
654
683
 
655
- async def convert_chat_message(self, raw_data: Dict[str, Any]) -> AstrBotMessage:
684
+ async def convert_chat_message(self, raw_data: dict[str, Any]) -> AstrBotMessage:
656
685
  """将 Misskey 聊天消息数据转换为 AstrBotMessage 对象"""
657
686
  sender_info = extract_sender_info(raw_data, is_chat=True)
658
687
  message = create_base_message(
@@ -663,7 +692,11 @@ class MisskeyPlatformAdapter(Platform):
663
692
  unique_session=self.unique_session,
664
693
  )
665
694
  cache_user_info(
666
- self._user_cache, sender_info, raw_data, self.client_self_id, is_chat=True
695
+ self._user_cache,
696
+ sender_info,
697
+ raw_data,
698
+ self.client_self_id,
699
+ is_chat=True,
667
700
  )
668
701
 
669
702
  raw_text = raw_data.get("text", "")
@@ -676,7 +709,7 @@ class MisskeyPlatformAdapter(Platform):
676
709
  message.message_str = raw_text if raw_text else ""
677
710
  return message
678
711
 
679
- async def convert_room_message(self, raw_data: Dict[str, Any]) -> AstrBotMessage:
712
+ async def convert_room_message(self, raw_data: dict[str, Any]) -> AstrBotMessage:
680
713
  """将 Misskey 群聊消息数据转换为 AstrBotMessage 对象"""
681
714
  sender_info = extract_sender_info(raw_data, is_chat=True)
682
715
  room_id = raw_data.get("toRoomId", "")
@@ -690,7 +723,11 @@ class MisskeyPlatformAdapter(Platform):
690
723
  )
691
724
 
692
725
  cache_user_info(
693
- self._user_cache, sender_info, raw_data, self.client_self_id, is_chat=False
726
+ self._user_cache,
727
+ sender_info,
728
+ raw_data,
729
+ self.client_self_id,
730
+ is_chat=False,
694
731
  )
695
732
  cache_room_info(self._user_cache, raw_data, self.client_self_id)
696
733
 
@@ -700,7 +737,10 @@ class MisskeyPlatformAdapter(Platform):
700
737
  if raw_text:
701
738
  if self._bot_username and f"@{self._bot_username}" in raw_text:
702
739
  text_parts, processed_text = process_at_mention(
703
- message, raw_text, self._bot_username, self.client_self_id
740
+ message,
741
+ raw_text,
742
+ self._bot_username,
743
+ self.client_self_id,
704
744
  )
705
745
  message_parts.extend(text_parts)
706
746
  else: