AstrBot 4.5.0__py3-none-any.whl → 4.5.2__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 +44 -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 +18 -13
  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 +47 -29
  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 +40 -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 +102 -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 +116 -0
  181. astrbot/core/provider/sources/xinference_stt_provider.py +197 -0
  182. astrbot/core/star/__init__.py +16 -11
  183. astrbot/core/star/config.py +10 -15
  184. astrbot/core/star/context.py +109 -84
  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 +47 -52
  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.0.dist-info → astrbot-4.5.2.dist-info}/METADATA +4 -2
  240. astrbot-4.5.2.dist-info/RECORD +261 -0
  241. astrbot-4.5.0.dist-info/RECORD +0 -258
  242. {astrbot-4.5.0.dist-info → astrbot-4.5.2.dist-info}/WHEEL +0 -0
  243. {astrbot-4.5.0.dist-info → astrbot-4.5.2.dist-info}/entry_points.txt +0 -0
  244. {astrbot-4.5.0.dist-info → astrbot-4.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,23 +1,20 @@
1
- """
2
- 此功能已过时,参考 https://astrbot.app/dev/plugin.html#%E6%B3%A8%E5%86%8C%E6%8F%92%E4%BB%B6%E9%85%8D%E7%BD%AE-beta
3
- """
1
+ """此功能已过时,参考 https://astrbot.app/dev/plugin.html#%E6%B3%A8%E5%86%8C%E6%8F%92%E4%BB%B6%E9%85%8D%E7%BD%AE-beta"""
4
2
 
5
- from typing import Union
6
- import os
7
3
  import json
4
+ import os
5
+
8
6
  from astrbot.core.utils.astrbot_path import get_astrbot_data_path
9
7
 
10
8
 
11
- def load_config(namespace: str) -> Union[dict, bool]:
12
- """
13
- 从配置文件中加载配置。
9
+ def load_config(namespace: str) -> dict | bool:
10
+ """从配置文件中加载配置。
14
11
  namespace: str, 配置的唯一识别符,也就是配置文件的名字。
15
12
  返回值: 当配置文件存在时,返回 namespace 对应配置文件的内容dict,否则返回 False。
16
13
  """
17
14
  path = os.path.join(get_astrbot_data_path(), "config", f"{namespace}.json")
18
15
  if not os.path.exists(path):
19
16
  return False
20
- with open(path, "r", encoding="utf-8-sig") as f:
17
+ with open(path, encoding="utf-8-sig") as f:
21
18
  ret = {}
22
19
  data = json.load(f)
23
20
  for k in data:
@@ -26,8 +23,7 @@ def load_config(namespace: str) -> Union[dict, bool]:
26
23
 
27
24
 
28
25
  def put_config(namespace: str, name: str, key: str, value, description: str):
29
- """
30
- 将配置项写入以namespace为名字的配置文件,如果key不存在于目标配置文件中。当前 value 仅支持 str, int, float, bool, list 类型(暂不支持 dict)。
26
+ """将配置项写入以namespace为名字的配置文件,如果key不存在于目标配置文件中。当前 value 仅支持 str, int, float, bool, list 类型(暂不支持 dict)。
31
27
  namespace: str, 配置的唯一识别符,也就是配置文件的名字。
32
28
  name: str, 配置项的显示名字。
33
29
  key: str, 配置项的键。
@@ -51,7 +47,7 @@ def put_config(namespace: str, name: str, key: str, value, description: str):
51
47
  if not os.path.exists(path):
52
48
  with open(path, "w", encoding="utf-8-sig") as f:
53
49
  f.write("{}")
54
- with open(path, "r", encoding="utf-8-sig") as f:
50
+ with open(path, encoding="utf-8-sig") as f:
55
51
  d = json.load(f)
56
52
  assert isinstance(d, dict)
57
53
  if key not in d:
@@ -69,8 +65,7 @@ def put_config(namespace: str, name: str, key: str, value, description: str):
69
65
 
70
66
 
71
67
  def update_config(namespace: str, key: str, value):
72
- """
73
- 更新配置文件中的配置项。
68
+ """更新配置文件中的配置项。
74
69
  namespace: str, 配置的唯一识别符,也就是配置文件的名字。
75
70
  key: str, 配置项的键。
76
71
  value: str, int, float, bool, list, 配置项的值。
@@ -78,7 +73,7 @@ def update_config(namespace: str, key: str, value):
78
73
  path = os.path.join(get_astrbot_data_path(), "config", f"{namespace}.json")
79
74
  if not os.path.exists(path):
80
75
  raise FileNotFoundError(f"配置文件 {namespace}.json 不存在。")
81
- with open(path, "r", encoding="utf-8-sig") as f:
76
+ with open(path, encoding="utf-8-sig") as f:
82
77
  d = json.load(f)
83
78
  assert isinstance(d, dict)
84
79
  if key not in d:
@@ -1,48 +1,51 @@
1
+ import logging
1
2
  from asyncio import Queue
2
- from typing import List, Union
3
+ from collections.abc import Awaitable, Callable
4
+ from typing import Any
3
5
 
4
- from astrbot.core.provider.provider import (
5
- Provider,
6
- TTSProvider,
7
- STTProvider,
8
- EmbeddingProvider,
9
- RerankProvider,
10
- )
11
- from astrbot.core.provider.entities import ProviderType
12
- from astrbot.core.db import BaseDatabase
6
+ from deprecated import deprecated
7
+
8
+ from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
13
9
  from astrbot.core.config.astrbot_config import AstrBotConfig
14
- from astrbot.core.provider.func_tool_manager import FunctionToolManager
15
- from astrbot.core.platform.astr_message_event import MessageSesion
10
+ from astrbot.core.conversation_mgr import ConversationManager
11
+ from astrbot.core.db import BaseDatabase
12
+ from astrbot.core.knowledge_base.kb_mgr import KnowledgeBaseManager
16
13
  from astrbot.core.message.message_event_result import MessageChain
17
- from astrbot.core.provider.manager import ProviderManager
14
+ from astrbot.core.persona_mgr import PersonaManager
18
15
  from astrbot.core.platform import Platform
16
+ from astrbot.core.platform.astr_message_event import MessageSesion
19
17
  from astrbot.core.platform.manager import PlatformManager
20
18
  from astrbot.core.platform_message_history_mgr import PlatformMessageHistoryManager
21
- from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
22
- from astrbot.core.knowledge_base.kb_mgr import KnowledgeBaseManager
23
- from astrbot.core.persona_mgr import PersonaManager
24
- from .star import star_registry, StarMetadata, star_map
25
- from .star_handler import star_handlers_registry, StarHandlerMetadata, EventType
26
- from .filter.command import CommandFilter
27
- from .filter.regex import RegexFilter
28
- from typing import Awaitable, Any, Callable
29
- from astrbot.core.conversation_mgr import ConversationManager
19
+ from astrbot.core.provider.entities import ProviderType
20
+ from astrbot.core.provider.func_tool_manager import FunctionTool, FunctionToolManager
21
+ from astrbot.core.provider.manager import ProviderManager
22
+ from astrbot.core.provider.provider import (
23
+ EmbeddingProvider,
24
+ Provider,
25
+ RerankProvider,
26
+ STTProvider,
27
+ TTSProvider,
28
+ )
30
29
  from astrbot.core.star.filter.platform_adapter_type import (
31
- PlatformAdapterType,
32
30
  ADAPTER_NAME_2_TYPE,
31
+ PlatformAdapterType,
33
32
  )
34
- from deprecated import deprecated
33
+
34
+ from .filter.command import CommandFilter
35
+ from .filter.regex import RegexFilter
36
+ from .star import StarMetadata, star_map, star_registry
37
+ from .star_handler import EventType, StarHandlerMetadata, star_handlers_registry
38
+
39
+ logger = logging.getLogger("astrbot")
35
40
 
36
41
 
37
42
  class Context:
38
- """
39
- 暴露给插件的接口上下文。
40
- """
43
+ """暴露给插件的接口上下文。"""
41
44
 
42
45
  registered_web_apis: list = []
43
46
 
44
47
  # back compatibility
45
- _register_tasks: List[Awaitable] = []
48
+ _register_tasks: list[Awaitable] = []
46
49
  _star_manager = None
47
50
 
48
51
  def __init__(
@@ -78,7 +81,7 @@ class Context:
78
81
  if star.name == star_name:
79
82
  return star
80
83
 
81
- def get_all_stars(self) -> List[StarMetadata]:
84
+ def get_all_stars(self) -> list[StarMetadata]:
82
85
  """获取当前载入的所有插件 Metadata 的列表"""
83
86
  return star_registry
84
87
 
@@ -91,6 +94,7 @@ class Context:
91
94
 
92
95
  Returns:
93
96
  如果没找到,会返回 False
97
+
94
98
  """
95
99
  return self.provider_manager.llm_tools.activate_llm_tool(name, star_map)
96
100
 
@@ -98,17 +102,18 @@ class Context:
98
102
  """停用一个已经注册的函数调用工具。
99
103
 
100
104
  Returns:
101
- 如果没找到,会返回 False"""
105
+ 如果没找到,会返回 False
106
+
107
+ """
102
108
  return self.provider_manager.llm_tools.deactivate_llm_tool(name)
103
109
 
104
110
  def register_provider(self, provider: Provider):
105
- """
106
- 注册一个 LLM Provider(Chat_Completion 类型)。
107
- """
111
+ """注册一个 LLM Provider(Chat_Completion 类型)。"""
108
112
  self.provider_manager.provider_insts.append(provider)
109
113
 
110
114
  def get_provider_by_id(
111
- self, provider_id: str
115
+ self,
116
+ provider_id: str,
112
117
  ) -> (
113
118
  Provider | TTSProvider | STTProvider | EmbeddingProvider | RerankProvider | None
114
119
  ):
@@ -116,28 +121,28 @@ class Context:
116
121
  prov = self.provider_manager.inst_map.get(provider_id)
117
122
  return prov
118
123
 
119
- def get_all_providers(self) -> List[Provider]:
124
+ def get_all_providers(self) -> list[Provider]:
120
125
  """获取所有用于文本生成任务的 LLM Provider(Chat_Completion 类型)。"""
121
126
  return self.provider_manager.provider_insts
122
127
 
123
- def get_all_tts_providers(self) -> List[TTSProvider]:
128
+ def get_all_tts_providers(self) -> list[TTSProvider]:
124
129
  """获取所有用于 TTS 任务的 Provider。"""
125
130
  return self.provider_manager.tts_provider_insts
126
131
 
127
- def get_all_stt_providers(self) -> List[STTProvider]:
132
+ def get_all_stt_providers(self) -> list[STTProvider]:
128
133
  """获取所有用于 STT 任务的 Provider。"""
129
134
  return self.provider_manager.stt_provider_insts
130
135
 
131
- def get_all_embedding_providers(self) -> List[EmbeddingProvider]:
136
+ def get_all_embedding_providers(self) -> list[EmbeddingProvider]:
132
137
  """获取所有用于 Embedding 任务的 Provider。"""
133
138
  return self.provider_manager.embedding_provider_insts
134
139
 
135
140
  def get_using_provider(self, umo: str | None = None) -> Provider | None:
136
- """
137
- 获取当前使用的用于文本生成任务的 LLM Provider(Chat_Completion 类型)。通过 /provider 指令切换。
141
+ """获取当前使用的用于文本生成任务的 LLM Provider(Chat_Completion 类型)。通过 /provider 指令切换。
138
142
 
139
143
  Args:
140
144
  umo(str): unified_message_origin 值,如果传入并且用户启用了提供商会话隔离,则使用该会话偏好的提供商。
145
+
141
146
  """
142
147
  prov = self.provider_manager.get_using_provider(
143
148
  provider_type=ProviderType.CHAT_COMPLETION,
@@ -148,11 +153,11 @@ class Context:
148
153
  return prov
149
154
 
150
155
  def get_using_tts_provider(self, umo: str | None = None) -> TTSProvider | None:
151
- """
152
- 获取当前使用的用于 TTS 任务的 Provider。
156
+ """获取当前使用的用于 TTS 任务的 Provider。
153
157
 
154
158
  Args:
155
159
  umo(str): unified_message_origin 值,如果传入,则使用该会话偏好的提供商。
160
+
156
161
  """
157
162
  prov = self.provider_manager.get_using_provider(
158
163
  provider_type=ProviderType.TEXT_TO_SPEECH,
@@ -163,11 +168,11 @@ class Context:
163
168
  return prov
164
169
 
165
170
  def get_using_stt_provider(self, umo: str | None = None) -> STTProvider | None:
166
- """
167
- 获取当前使用的用于 STT 任务的 Provider。
171
+ """获取当前使用的用于 STT 任务的 Provider。
168
172
 
169
173
  Args:
170
174
  umo(str): unified_message_origin 值,如果传入,则使用该会话偏好的提供商。
175
+
171
176
  """
172
177
  prov = self.provider_manager.get_using_provider(
173
178
  provider_type=ProviderType.SPEECH_TO_TEXT,
@@ -182,25 +187,19 @@ class Context:
182
187
  if not umo:
183
188
  # using default config
184
189
  return self._config
185
- else:
186
- return self.astrbot_config_mgr.get_conf(umo)
190
+ return self.astrbot_config_mgr.get_conf(umo)
187
191
 
188
192
  def get_db(self) -> BaseDatabase:
189
193
  """获取 AstrBot 数据库。"""
190
194
  return self._db
191
195
 
192
196
  def get_event_queue(self) -> Queue:
193
- """
194
- 获取事件队列。
195
- """
197
+ """获取事件队列。"""
196
198
  return self._event_queue
197
199
 
198
200
  @deprecated(version="4.0.0", reason="Use get_platform_inst instead")
199
- def get_platform(
200
- self, platform_type: Union[PlatformAdapterType, str]
201
- ) -> Platform | None:
202
- """
203
- 获取指定类型的平台适配器。
201
+ def get_platform(self, platform_type: PlatformAdapterType | str) -> Platform | None:
202
+ """获取指定类型的平台适配器。
204
203
 
205
204
  该方法已经过时,请使用 get_platform_inst 方法。(>= AstrBot v4.0.0)
206
205
  """
@@ -209,32 +208,32 @@ class Context:
209
208
  if isinstance(platform_type, str):
210
209
  if name == platform_type:
211
210
  return platform
212
- else:
213
- if (
214
- name in ADAPTER_NAME_2_TYPE
215
- and ADAPTER_NAME_2_TYPE[name] & platform_type
216
- ):
217
- return platform
211
+ elif (
212
+ name in ADAPTER_NAME_2_TYPE
213
+ and ADAPTER_NAME_2_TYPE[name] & platform_type
214
+ ):
215
+ return platform
218
216
 
219
217
  def get_platform_inst(self, platform_id: str) -> Platform | None:
220
- """
221
- 获取指定 ID 的平台适配器实例。
218
+ """获取指定 ID 的平台适配器实例。
222
219
 
223
220
  Args:
224
221
  platform_id (str): 平台适配器的唯一标识符。你可以通过 event.get_platform_id() 获取。
225
222
 
226
223
  Returns:
227
224
  Platform: 平台适配器实例,如果未找到则返回 None。
225
+
228
226
  """
229
227
  for platform in self.platform_manager.platform_insts:
230
228
  if platform.meta().id == platform_id:
231
229
  return platform
232
230
 
233
231
  async def send_message(
234
- self, session: Union[str, MessageSesion], message_chain: MessageChain
232
+ self,
233
+ session: str | MessageSesion,
234
+ message_chain: MessageChain,
235
235
  ) -> bool:
236
- """
237
- 根据 session(unified_msg_origin) 主动发送消息。
236
+ """根据 session(unified_msg_origin) 主动发送消息。
238
237
 
239
238
  @param session: 消息会话。通过 event.session 或者 event.unified_msg_origin 获取。
240
239
  @param message_chain: 消息链。
@@ -245,7 +244,6 @@ class Context:
245
244
 
246
245
  NOTE: qq_official(QQ 官方 API 平台) 不支持此方法
247
246
  """
248
-
249
247
  if isinstance(session, str):
250
248
  try:
251
249
  session = MessageSesion.from_str(session)
@@ -258,6 +256,46 @@ class Context:
258
256
  return True
259
257
  return False
260
258
 
259
+ def add_llm_tools(self, *tools: FunctionTool) -> None:
260
+ """添加 LLM 工具。"""
261
+ tool_name = {tool.name for tool in self.provider_manager.llm_tools.func_list}
262
+ module_path = ""
263
+ for tool in tools:
264
+ if not module_path:
265
+ _parts = []
266
+ module_part = tool.__module__.split(".")
267
+ flags = ["packages", "plugins"]
268
+ for i, part in enumerate(module_part):
269
+ _parts.append(part)
270
+ if part in flags and i + 1 < len(module_part):
271
+ _parts.append(module_part[i + 1])
272
+ break
273
+ tool.handler_module_path = ".".join(_parts)
274
+ module_path = tool.handler_module_path
275
+ else:
276
+ tool.handler_module_path = module_path
277
+ logger.info(
278
+ f"plugin(module_path {module_path}) added LLM tool: {tool.name}"
279
+ )
280
+
281
+ if tool.name in tool_name:
282
+ logger.warning("替换已存在的 LLM 工具: " + tool.name)
283
+ self.provider_manager.llm_tools.remove_func(tool.name)
284
+ self.provider_manager.llm_tools.func_list.append(tool)
285
+
286
+ def register_web_api(
287
+ self,
288
+ route: str,
289
+ view_handler: Awaitable,
290
+ methods: list,
291
+ desc: str,
292
+ ):
293
+ for idx, api in enumerate(self.registered_web_apis):
294
+ if api[0] == route and methods == api[2]:
295
+ self.registered_web_apis[idx] = (route, view_handler, methods, desc)
296
+ return
297
+ self.registered_web_apis.append((route, view_handler, methods, desc))
298
+
261
299
  """
262
300
  以下的方法已经不推荐使用。请从 AstrBot 文档查看更好的注册方式。
263
301
  """
@@ -269,8 +307,7 @@ class Context:
269
307
  desc: str,
270
308
  func_obj: Callable[..., Awaitable[Any]],
271
309
  ) -> None:
272
- """
273
- 为函数调用(function-calling / tools-use)添加工具。
310
+ """[DEPRECATED]为函数调用(function-calling / tools-use)添加工具。
274
311
 
275
312
  @param name: 函数名
276
313
  @param func_args: 函数参数列表,格式为 [{"type": "string", "name": "arg_name", "description": "arg_description"}, ...]
@@ -292,7 +329,7 @@ class Context:
292
329
  self.provider_manager.llm_tools.add_func(name, func_args, desc, func_obj)
293
330
 
294
331
  def unregister_llm_tool(self, name: str) -> None:
295
- """删除一个函数调用工具。如果再要启用,需要重新注册。"""
332
+ """[DEPRECATED]删除一个函数调用工具。如果再要启用,需要重新注册。"""
296
333
  self.provider_manager.llm_tools.remove_func(name)
297
334
 
298
335
  def register_commands(
@@ -305,8 +342,7 @@ class Context:
305
342
  use_regex=False,
306
343
  ignore_prefix=False,
307
344
  ):
308
- """
309
- 注册一个命令。
345
+ """注册一个命令。
310
346
 
311
347
  [Deprecated] 推荐使用装饰器注册指令。该方法将在未来的版本中被移除。
312
348
 
@@ -330,21 +366,10 @@ class Context:
330
366
  md.event_filters.append(RegexFilter(regex=command_name))
331
367
  else:
332
368
  md.event_filters.append(
333
- CommandFilter(command_name=command_name, handler_md=md)
369
+ CommandFilter(command_name=command_name, handler_md=md),
334
370
  )
335
371
  star_handlers_registry.append(md)
336
372
 
337
373
  def register_task(self, task: Awaitable, desc: str):
338
- """
339
- 注册一个异步任务。
340
- """
374
+ """[DEPRECATED]注册一个异步任务。"""
341
375
  self._register_tasks.append(task)
342
-
343
- def register_web_api(
344
- self, route: str, view_handler: Awaitable, methods: list, desc: str
345
- ):
346
- for idx, api in enumerate(self.registered_web_apis):
347
- if api[0] == route and methods == api[2]:
348
- self.registered_web_apis[idx] = (route, view_handler, methods, desc)
349
- return
350
- self.registered_web_apis.append((route, view_handler, methods, desc))
@@ -1,7 +1,8 @@
1
1
  import abc
2
- from astrbot.core.platform.message_type import MessageType
3
- from astrbot.core.platform.astr_message_event import AstrMessageEvent
2
+
4
3
  from astrbot.core.config import AstrBotConfig
4
+ from astrbot.core.platform.astr_message_event import AstrMessageEvent
5
+ from astrbot.core.platform.message_type import MessageType
5
6
 
6
7
 
7
8
  class HandlerFilter(abc.ABC):
@@ -11,4 +12,4 @@ class HandlerFilter(abc.ABC):
11
12
  raise NotImplementedError
12
13
 
13
14
 
14
- __all__ = ["HandlerFilter", "MessageType", "AstrMessageEvent", "AstrBotConfig"]
15
+ __all__ = ["AstrBotConfig", "AstrMessageEvent", "HandlerFilter", "MessageType"]
@@ -1,20 +1,20 @@
1
- import re
2
1
  import inspect
2
+ import re
3
3
  import types
4
4
  import typing
5
- from typing import List, Any, Type, Dict
6
- from . import HandlerFilter
7
- from astrbot.core.platform.astr_message_event import AstrMessageEvent
5
+ from typing import Any
6
+
8
7
  from astrbot.core.config import AstrBotConfig
9
- from .custom_filter import CustomFilter
8
+ from astrbot.core.platform.astr_message_event import AstrMessageEvent
9
+
10
10
  from ..star_handler import StarHandlerMetadata
11
+ from . import HandlerFilter
12
+ from .custom_filter import CustomFilter
11
13
 
12
14
 
13
15
  class GreedyStr(str):
14
16
  """标记指令完成其他参数接收后的所有剩余文本。"""
15
17
 
16
- pass
17
-
18
18
 
19
19
  def unwrap_optional(annotation) -> tuple:
20
20
  """去掉 Optional[T] / Union[T, None] / T|None,返回 T"""
@@ -22,10 +22,9 @@ def unwrap_optional(annotation) -> tuple:
22
22
  non_none_args = [a for a in args if a is not type(None)]
23
23
  if len(non_none_args) == 1:
24
24
  return (non_none_args[0],)
25
- elif len(non_none_args) > 1:
25
+ if len(non_none_args) > 1:
26
26
  return tuple(non_none_args)
27
- else:
28
- return ()
27
+ return ()
29
28
 
30
29
 
31
30
  # 标准指令受到 wake_prefix 的制约。
@@ -37,28 +36,30 @@ class CommandFilter(HandlerFilter):
37
36
  command_name: str,
38
37
  alias: set | None = None,
39
38
  handler_md: StarHandlerMetadata | None = None,
40
- parent_command_names: List[str] = [""],
39
+ parent_command_names: list[str] | None = None,
41
40
  ):
42
41
  self.command_name = command_name
43
42
  self.alias = alias if alias else set()
44
- self.parent_command_names = parent_command_names
43
+ self.parent_command_names = (
44
+ parent_command_names if parent_command_names is not None else [""]
45
+ )
45
46
  if handler_md:
46
47
  self.init_handler_md(handler_md)
47
- self.custom_filter_list: List[CustomFilter] = []
48
+ self.custom_filter_list: list[CustomFilter] = []
48
49
 
49
50
  # Cache for complete command names list
50
51
  self._cmpl_cmd_names: list | None = None
51
52
 
52
53
  def print_types(self):
53
- result = ""
54
+ parts = []
54
55
  for k, v in self.handler_params.items():
55
56
  if isinstance(v, type):
56
- result += f"{k}({v.__name__}),"
57
+ parts.append(f"{k}({v.__name__}),")
57
58
  elif isinstance(v, types.UnionType) or typing.get_origin(v) is typing.Union:
58
- result += f"{k}({v}),"
59
+ parts.append(f"{k}({v}),")
59
60
  else:
60
- result += f"{k}({type(v).__name__})={v},"
61
- result = result.rstrip(",")
61
+ parts.append(f"{k}({type(v).__name__})={v},")
62
+ result = "".join(parts).rstrip(",")
62
63
  return result
63
64
 
64
65
  def init_handler_md(self, handle_md: StarHandlerMetadata):
@@ -89,8 +90,10 @@ class CommandFilter(HandlerFilter):
89
90
  return True
90
91
 
91
92
  def validate_and_convert_params(
92
- self, params: List[Any], param_type: Dict[str, Type]
93
- ) -> Dict[str, Any]:
93
+ self,
94
+ params: list[Any],
95
+ param_type: dict[str, type],
96
+ ) -> dict[str, Any]:
94
97
  """将参数列表 params 根据 param_type 转换为参数字典。"""
95
98
  result = {}
96
99
  param_items = list(param_type.items())
@@ -101,7 +104,7 @@ class CommandFilter(HandlerFilter):
101
104
  # GreedyStr 必须是最后一个参数
102
105
  if i != len(param_items) - 1:
103
106
  raise ValueError(
104
- f"参数 '{param_name}' (GreedyStr) 必须是最后一个参数。"
107
+ f"参数 '{param_name}' (GreedyStr) 必须是最后一个参数。",
105
108
  )
106
109
 
107
110
  # 将剩余的所有部分合并成一个字符串
@@ -111,17 +114,16 @@ class CommandFilter(HandlerFilter):
111
114
  # 没有 GreedyStr 的情况
112
115
  if i >= len(params):
113
116
  if (
114
- isinstance(param_type_or_default_val, (Type, types.UnionType))
117
+ isinstance(param_type_or_default_val, (type, types.UnionType))
115
118
  or typing.get_origin(param_type_or_default_val) is typing.Union
116
119
  or param_type_or_default_val is inspect.Parameter.empty
117
120
  ):
118
121
  # 是类型
119
122
  raise ValueError(
120
- f"必要参数缺失。该指令完整参数: {self.print_types()}"
123
+ f"必要参数缺失。该指令完整参数: {self.print_types()}",
121
124
  )
122
- else:
123
- # 是默认值
124
- result[param_name] = param_type_or_default_val
125
+ # 是默认值
126
+ result[param_name] = param_type_or_default_val
125
127
  else:
126
128
  # 尝试强制转换
127
129
  try:
@@ -142,7 +144,7 @@ class CommandFilter(HandlerFilter):
142
144
  result[param_name] = False
143
145
  else:
144
146
  raise ValueError(
145
- f"参数 {param_name} 必须是布尔值(true/false, yes/no, 1/0)。"
147
+ f"参数 {param_name} 必须是布尔值(true/false, yes/no, 1/0)。",
146
148
  )
147
149
  elif isinstance(param_type_or_default_val, int):
148
150
  result[param_name] = int(params[i])
@@ -165,7 +167,7 @@ class CommandFilter(HandlerFilter):
165
167
  result[param_name] = param_type_or_default_val(params[i])
166
168
  except ValueError:
167
169
  raise ValueError(
168
- f"参数 {param_name} 类型错误。完整参数: {self.print_types()}"
170
+ f"参数 {param_name} 类型错误。完整参数: {self.print_types()}",
169
171
  )
170
172
  return result
171
173