AstrBot 4.5.1__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.
- astrbot/api/__init__.py +10 -11
- astrbot/api/event/__init__.py +5 -6
- astrbot/api/event/filter/__init__.py +37 -36
- astrbot/api/platform/__init__.py +7 -8
- astrbot/api/provider/__init__.py +7 -7
- astrbot/api/star/__init__.py +3 -4
- astrbot/api/util/__init__.py +2 -2
- astrbot/cli/__main__.py +5 -5
- astrbot/cli/commands/__init__.py +3 -3
- astrbot/cli/commands/cmd_conf.py +19 -16
- astrbot/cli/commands/cmd_init.py +3 -2
- astrbot/cli/commands/cmd_plug.py +8 -10
- astrbot/cli/commands/cmd_run.py +5 -6
- astrbot/cli/utils/__init__.py +6 -6
- astrbot/cli/utils/basic.py +14 -14
- astrbot/cli/utils/plugin.py +24 -15
- astrbot/cli/utils/version_comparator.py +10 -12
- astrbot/core/__init__.py +8 -6
- astrbot/core/agent/agent.py +3 -2
- astrbot/core/agent/handoff.py +6 -2
- astrbot/core/agent/hooks.py +9 -6
- astrbot/core/agent/mcp_client.py +50 -15
- astrbot/core/agent/message.py +168 -0
- astrbot/core/agent/response.py +2 -1
- astrbot/core/agent/run_context.py +2 -3
- astrbot/core/agent/runners/base.py +10 -13
- astrbot/core/agent/runners/tool_loop_agent_runner.py +52 -51
- astrbot/core/agent/tool.py +60 -41
- astrbot/core/agent/tool_executor.py +9 -3
- astrbot/core/astr_agent_context.py +3 -1
- astrbot/core/astrbot_config_mgr.py +29 -9
- astrbot/core/config/__init__.py +2 -2
- astrbot/core/config/astrbot_config.py +28 -26
- astrbot/core/config/default.py +4 -6
- astrbot/core/conversation_mgr.py +105 -36
- astrbot/core/core_lifecycle.py +68 -54
- astrbot/core/db/__init__.py +33 -18
- astrbot/core/db/migration/helper.py +12 -10
- astrbot/core/db/migration/migra_3_to_4.py +53 -34
- astrbot/core/db/migration/migra_45_to_46.py +1 -1
- astrbot/core/db/migration/shared_preferences_v3.py +2 -1
- astrbot/core/db/migration/sqlite_v3.py +26 -23
- astrbot/core/db/po.py +27 -18
- astrbot/core/db/sqlite.py +74 -45
- astrbot/core/db/vec_db/base.py +10 -14
- astrbot/core/db/vec_db/faiss_impl/document_storage.py +90 -77
- astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +9 -3
- astrbot/core/db/vec_db/faiss_impl/vec_db.py +36 -31
- astrbot/core/event_bus.py +8 -6
- astrbot/core/file_token_service.py +6 -5
- astrbot/core/initial_loader.py +7 -5
- astrbot/core/knowledge_base/chunking/__init__.py +1 -3
- astrbot/core/knowledge_base/chunking/base.py +1 -0
- astrbot/core/knowledge_base/chunking/fixed_size.py +2 -0
- astrbot/core/knowledge_base/chunking/recursive.py +16 -10
- astrbot/core/knowledge_base/kb_db_sqlite.py +50 -48
- astrbot/core/knowledge_base/kb_helper.py +30 -17
- astrbot/core/knowledge_base/kb_mgr.py +6 -7
- astrbot/core/knowledge_base/models.py +10 -4
- astrbot/core/knowledge_base/parsers/__init__.py +3 -5
- astrbot/core/knowledge_base/parsers/base.py +1 -0
- astrbot/core/knowledge_base/parsers/markitdown_parser.py +2 -1
- astrbot/core/knowledge_base/parsers/pdf_parser.py +2 -1
- astrbot/core/knowledge_base/parsers/text_parser.py +1 -0
- astrbot/core/knowledge_base/parsers/util.py +1 -1
- astrbot/core/knowledge_base/retrieval/__init__.py +6 -8
- astrbot/core/knowledge_base/retrieval/manager.py +17 -14
- astrbot/core/knowledge_base/retrieval/rank_fusion.py +7 -3
- astrbot/core/knowledge_base/retrieval/sparse_retriever.py +11 -5
- astrbot/core/log.py +21 -13
- astrbot/core/message/components.py +123 -217
- astrbot/core/message/message_event_result.py +24 -24
- astrbot/core/persona_mgr.py +20 -11
- astrbot/core/pipeline/__init__.py +7 -7
- astrbot/core/pipeline/content_safety_check/stage.py +13 -9
- astrbot/core/pipeline/content_safety_check/strategies/__init__.py +1 -2
- astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +12 -13
- astrbot/core/pipeline/content_safety_check/strategies/keywords.py +1 -0
- astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
- astrbot/core/pipeline/context.py +4 -1
- astrbot/core/pipeline/context_utils.py +77 -7
- astrbot/core/pipeline/preprocess_stage/stage.py +12 -9
- astrbot/core/pipeline/process_stage/method/llm_request.py +125 -72
- astrbot/core/pipeline/process_stage/method/star_request.py +19 -17
- astrbot/core/pipeline/process_stage/stage.py +13 -10
- astrbot/core/pipeline/process_stage/utils.py +6 -5
- astrbot/core/pipeline/rate_limit_check/stage.py +37 -36
- astrbot/core/pipeline/respond/stage.py +23 -20
- astrbot/core/pipeline/result_decorate/stage.py +31 -23
- astrbot/core/pipeline/scheduler.py +12 -8
- astrbot/core/pipeline/session_status_check/stage.py +12 -8
- astrbot/core/pipeline/stage.py +10 -4
- astrbot/core/pipeline/waking_check/stage.py +24 -18
- astrbot/core/pipeline/whitelist_check/stage.py +10 -7
- astrbot/core/platform/__init__.py +6 -6
- astrbot/core/platform/astr_message_event.py +76 -110
- astrbot/core/platform/astrbot_message.py +11 -13
- astrbot/core/platform/manager.py +16 -15
- astrbot/core/platform/message_session.py +5 -3
- astrbot/core/platform/platform.py +16 -24
- astrbot/core/platform/platform_metadata.py +4 -4
- astrbot/core/platform/register.py +8 -8
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +23 -15
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +51 -33
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +42 -27
- astrbot/core/platform/sources/dingtalk/dingtalk_event.py +7 -3
- astrbot/core/platform/sources/discord/client.py +9 -6
- astrbot/core/platform/sources/discord/components.py +18 -14
- astrbot/core/platform/sources/discord/discord_platform_adapter.py +45 -30
- astrbot/core/platform/sources/discord/discord_platform_event.py +38 -30
- astrbot/core/platform/sources/lark/lark_adapter.py +23 -17
- astrbot/core/platform/sources/lark/lark_event.py +21 -14
- astrbot/core/platform/sources/misskey/misskey_adapter.py +107 -67
- astrbot/core/platform/sources/misskey/misskey_api.py +153 -129
- astrbot/core/platform/sources/misskey/misskey_event.py +20 -15
- astrbot/core/platform/sources/misskey/misskey_utils.py +74 -62
- astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +63 -44
- astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +41 -26
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +36 -17
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +3 -1
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +12 -7
- astrbot/core/platform/sources/satori/satori_adapter.py +56 -38
- astrbot/core/platform/sources/satori/satori_event.py +34 -25
- astrbot/core/platform/sources/slack/client.py +11 -9
- astrbot/core/platform/sources/slack/slack_adapter.py +52 -36
- astrbot/core/platform/sources/slack/slack_event.py +34 -24
- astrbot/core/platform/sources/telegram/tg_adapter.py +38 -18
- astrbot/core/platform/sources/telegram/tg_event.py +32 -18
- astrbot/core/platform/sources/webchat/webchat_adapter.py +27 -17
- astrbot/core/platform/sources/webchat/webchat_event.py +14 -10
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +115 -120
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +9 -8
- astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +15 -16
- astrbot/core/platform/sources/wecom/wecom_adapter.py +35 -18
- astrbot/core/platform/sources/wecom/wecom_event.py +55 -48
- astrbot/core/platform/sources/wecom/wecom_kf.py +34 -44
- astrbot/core/platform/sources/wecom/wecom_kf_message.py +26 -10
- astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +18 -10
- astrbot/core/platform/sources/wecom_ai_bot/__init__.py +3 -5
- astrbot/core/platform/sources/wecom_ai_bot/ierror.py +0 -1
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +61 -37
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +67 -28
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +8 -9
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +18 -9
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +14 -12
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +22 -12
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +40 -26
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +47 -45
- astrbot/core/platform_message_history_mgr.py +5 -3
- astrbot/core/provider/__init__.py +2 -3
- astrbot/core/provider/entites.py +8 -8
- astrbot/core/provider/entities.py +61 -75
- astrbot/core/provider/func_tool_manager.py +59 -55
- astrbot/core/provider/manager.py +32 -22
- astrbot/core/provider/provider.py +72 -46
- astrbot/core/provider/register.py +7 -7
- astrbot/core/provider/sources/anthropic_source.py +48 -30
- astrbot/core/provider/sources/azure_tts_source.py +17 -13
- astrbot/core/provider/sources/coze_api_client.py +27 -17
- astrbot/core/provider/sources/coze_source.py +104 -87
- astrbot/core/provider/sources/dashscope_source.py +18 -11
- astrbot/core/provider/sources/dashscope_tts.py +36 -23
- astrbot/core/provider/sources/dify_source.py +25 -20
- astrbot/core/provider/sources/edge_tts_source.py +21 -17
- astrbot/core/provider/sources/fishaudio_tts_api_source.py +22 -14
- astrbot/core/provider/sources/gemini_embedding_source.py +12 -13
- astrbot/core/provider/sources/gemini_source.py +72 -58
- astrbot/core/provider/sources/gemini_tts_source.py +8 -6
- astrbot/core/provider/sources/gsv_selfhosted_source.py +17 -14
- astrbot/core/provider/sources/gsvi_tts_source.py +11 -7
- astrbot/core/provider/sources/minimax_tts_api_source.py +50 -40
- astrbot/core/provider/sources/openai_embedding_source.py +6 -8
- astrbot/core/provider/sources/openai_source.py +77 -69
- astrbot/core/provider/sources/openai_tts_api_source.py +14 -6
- astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
- astrbot/core/provider/sources/vllm_rerank_source.py +10 -4
- astrbot/core/provider/sources/volcengine_tts.py +38 -31
- astrbot/core/provider/sources/whisper_api_source.py +14 -12
- astrbot/core/provider/sources/whisper_selfhosted_source.py +15 -11
- astrbot/core/provider/sources/xinference_rerank_source.py +16 -8
- astrbot/core/provider/sources/xinference_stt_provider.py +35 -25
- astrbot/core/star/__init__.py +16 -11
- astrbot/core/star/config.py +10 -15
- astrbot/core/star/context.py +97 -75
- astrbot/core/star/filter/__init__.py +4 -3
- astrbot/core/star/filter/command.py +30 -28
- astrbot/core/star/filter/command_group.py +27 -24
- astrbot/core/star/filter/custom_filter.py +6 -5
- astrbot/core/star/filter/event_message_type.py +4 -2
- astrbot/core/star/filter/permission.py +4 -2
- astrbot/core/star/filter/platform_adapter_type.py +4 -2
- astrbot/core/star/filter/regex.py +4 -2
- astrbot/core/star/register/__init__.py +19 -19
- astrbot/core/star/register/star.py +6 -2
- astrbot/core/star/register/star_handler.py +96 -73
- astrbot/core/star/session_llm_manager.py +48 -14
- astrbot/core/star/session_plugin_manager.py +29 -15
- astrbot/core/star/star.py +1 -2
- astrbot/core/star/star_handler.py +13 -8
- astrbot/core/star/star_manager.py +151 -59
- astrbot/core/star/star_tools.py +44 -37
- astrbot/core/star/updator.py +10 -10
- astrbot/core/umop_config_router.py +10 -4
- astrbot/core/updator.py +13 -5
- astrbot/core/utils/astrbot_path.py +3 -5
- astrbot/core/utils/dify_api_client.py +33 -15
- astrbot/core/utils/io.py +66 -42
- astrbot/core/utils/log_pipe.py +1 -1
- astrbot/core/utils/metrics.py +7 -7
- astrbot/core/utils/path_util.py +15 -16
- astrbot/core/utils/pip_installer.py +5 -5
- astrbot/core/utils/session_waiter.py +19 -20
- astrbot/core/utils/shared_preferences.py +45 -20
- astrbot/core/utils/t2i/__init__.py +4 -1
- astrbot/core/utils/t2i/network_strategy.py +35 -26
- astrbot/core/utils/t2i/renderer.py +11 -5
- astrbot/core/utils/t2i/template_manager.py +14 -15
- astrbot/core/utils/tencent_record_helper.py +19 -13
- astrbot/core/utils/version_comparator.py +10 -13
- astrbot/core/zip_updator.py +43 -40
- astrbot/dashboard/routes/__init__.py +18 -18
- astrbot/dashboard/routes/auth.py +10 -8
- astrbot/dashboard/routes/chat.py +30 -21
- astrbot/dashboard/routes/config.py +92 -75
- astrbot/dashboard/routes/conversation.py +46 -39
- astrbot/dashboard/routes/file.py +4 -2
- astrbot/dashboard/routes/knowledge_base.py +47 -40
- astrbot/dashboard/routes/log.py +9 -4
- astrbot/dashboard/routes/persona.py +19 -16
- astrbot/dashboard/routes/plugin.py +69 -55
- astrbot/dashboard/routes/route.py +3 -1
- astrbot/dashboard/routes/session_management.py +130 -116
- astrbot/dashboard/routes/stat.py +34 -34
- astrbot/dashboard/routes/t2i.py +15 -12
- astrbot/dashboard/routes/tools.py +47 -52
- astrbot/dashboard/routes/update.py +32 -28
- astrbot/dashboard/server.py +30 -26
- astrbot/dashboard/utils.py +8 -4
- {astrbot-4.5.1.dist-info → astrbot-4.5.2.dist-info}/METADATA +2 -1
- astrbot-4.5.2.dist-info/RECORD +261 -0
- astrbot-4.5.1.dist-info/RECORD +0 -260
- {astrbot-4.5.1.dist-info → astrbot-4.5.2.dist-info}/WHEEL +0 -0
- {astrbot-4.5.1.dist-info → astrbot-4.5.2.dist-info}/entry_points.txt +0 -0
- {astrbot-4.5.1.dist-info → astrbot-4.5.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import enum
|
|
2
|
-
|
|
3
|
-
from typing import List, Optional, Union, AsyncGenerator
|
|
2
|
+
from collections.abc import AsyncGenerator
|
|
4
3
|
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from typing_extensions import deprecated
|
|
6
|
+
|
|
5
7
|
from astrbot.core.message.components import (
|
|
6
|
-
BaseMessageComponent,
|
|
7
|
-
Plain,
|
|
8
|
-
Image,
|
|
9
8
|
At,
|
|
10
9
|
AtAll,
|
|
10
|
+
BaseMessageComponent,
|
|
11
|
+
Image,
|
|
12
|
+
Plain,
|
|
11
13
|
)
|
|
12
|
-
from typing_extensions import deprecated
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@dataclass
|
|
@@ -20,18 +21,18 @@ class MessageChain:
|
|
|
20
21
|
Attributes:
|
|
21
22
|
`chain` (list): 用于顺序存储各个组件。
|
|
22
23
|
`use_t2i_` (bool): 用于标记是否使用文本转图片服务。默认为 None,即跟随用户的设置。当设置为 True 时,将会使用文本转图片服务。
|
|
24
|
+
|
|
23
25
|
"""
|
|
24
26
|
|
|
25
|
-
chain:
|
|
26
|
-
use_t2i_:
|
|
27
|
-
type:
|
|
27
|
+
chain: list[BaseMessageComponent] = field(default_factory=list)
|
|
28
|
+
use_t2i_: bool | None = None # None 为跟随用户设置
|
|
29
|
+
type: str | None = None
|
|
28
30
|
"""消息链承载的消息的类型。可选,用于让消息平台区分不同业务场景的消息链。"""
|
|
29
31
|
|
|
30
32
|
def message(self, message: str):
|
|
31
33
|
"""添加一条文本消息到消息链 `chain` 中。
|
|
32
34
|
|
|
33
35
|
Example:
|
|
34
|
-
|
|
35
36
|
CommandResult().message("Hello ").message("world!")
|
|
36
37
|
# 输出 Hello world!
|
|
37
38
|
|
|
@@ -39,11 +40,10 @@ class MessageChain:
|
|
|
39
40
|
self.chain.append(Plain(message))
|
|
40
41
|
return self
|
|
41
42
|
|
|
42
|
-
def at(self, name: str, qq:
|
|
43
|
+
def at(self, name: str, qq: str | int):
|
|
43
44
|
"""添加一条 At 消息到消息链 `chain` 中。
|
|
44
45
|
|
|
45
46
|
Example:
|
|
46
|
-
|
|
47
47
|
CommandResult().at("张三", "12345678910")
|
|
48
48
|
# 输出 @张三
|
|
49
49
|
|
|
@@ -55,7 +55,6 @@ class MessageChain:
|
|
|
55
55
|
"""添加一条 AtAll 消息到消息链 `chain` 中。
|
|
56
56
|
|
|
57
57
|
Example:
|
|
58
|
-
|
|
59
58
|
CommandResult().at_all()
|
|
60
59
|
# 输出 @所有人
|
|
61
60
|
|
|
@@ -68,7 +67,6 @@ class MessageChain:
|
|
|
68
67
|
"""添加一条错误消息到消息链 `chain` 中
|
|
69
68
|
|
|
70
69
|
Example:
|
|
71
|
-
|
|
72
70
|
CommandResult().error("解析失败")
|
|
73
71
|
|
|
74
72
|
"""
|
|
@@ -82,7 +80,6 @@ class MessageChain:
|
|
|
82
80
|
如果需要发送本地图片,请使用 `file_image` 方法。
|
|
83
81
|
|
|
84
82
|
Example:
|
|
85
|
-
|
|
86
83
|
CommandResult().image("https://example.com/image.jpg")
|
|
87
84
|
|
|
88
85
|
"""
|
|
@@ -96,6 +93,7 @@ class MessageChain:
|
|
|
96
93
|
如果需要发送网络图片,请使用 `url_image` 方法。
|
|
97
94
|
|
|
98
95
|
CommandResult().image("image.jpg")
|
|
96
|
+
|
|
99
97
|
"""
|
|
100
98
|
self.chain.append(Image.fromFileSystem(path))
|
|
101
99
|
return self
|
|
@@ -114,6 +112,7 @@ class MessageChain:
|
|
|
114
112
|
|
|
115
113
|
Args:
|
|
116
114
|
use_t2i (bool): 是否使用文本转图片服务。默认为 None,即跟随用户的设置。当设置为 True 时,将会使用文本转图片服务。
|
|
115
|
+
|
|
117
116
|
"""
|
|
118
117
|
self.use_t2i_ = use_t2i
|
|
119
118
|
return self
|
|
@@ -125,7 +124,7 @@ class MessageChain:
|
|
|
125
124
|
def squash_plain(self):
|
|
126
125
|
"""将消息链中的所有 Plain 消息段聚合到第一个 Plain 消息段中。"""
|
|
127
126
|
if not self.chain:
|
|
128
|
-
return
|
|
127
|
+
return None
|
|
129
128
|
|
|
130
129
|
new_chain = []
|
|
131
130
|
first_plain = None
|
|
@@ -153,6 +152,7 @@ class EventResultType(enum.Enum):
|
|
|
153
152
|
Attributes:
|
|
154
153
|
CONTINUE: 事件将会继续传播
|
|
155
154
|
STOP: 事件将会终止传播
|
|
155
|
+
|
|
156
156
|
"""
|
|
157
157
|
|
|
158
158
|
CONTINUE = enum.auto()
|
|
@@ -181,17 +181,18 @@ class MessageEventResult(MessageChain):
|
|
|
181
181
|
`chain` (list): 用于顺序存储各个组件。
|
|
182
182
|
`use_t2i_` (bool): 用于标记是否使用文本转图片服务。默认为 None,即跟随用户的设置。当设置为 True 时,将会使用文本转图片服务。
|
|
183
183
|
`result_type` (EventResultType): 事件处理的结果类型。
|
|
184
|
+
|
|
184
185
|
"""
|
|
185
186
|
|
|
186
|
-
result_type:
|
|
187
|
-
default_factory=lambda: EventResultType.CONTINUE
|
|
187
|
+
result_type: EventResultType | None = field(
|
|
188
|
+
default_factory=lambda: EventResultType.CONTINUE,
|
|
188
189
|
)
|
|
189
190
|
|
|
190
|
-
result_content_type:
|
|
191
|
-
default_factory=lambda: ResultContentType.GENERAL_RESULT
|
|
191
|
+
result_content_type: ResultContentType | None = field(
|
|
192
|
+
default_factory=lambda: ResultContentType.GENERAL_RESULT,
|
|
192
193
|
)
|
|
193
194
|
|
|
194
|
-
async_stream:
|
|
195
|
+
async_stream: AsyncGenerator | None = None
|
|
195
196
|
"""异步流"""
|
|
196
197
|
|
|
197
198
|
def stop_event(self) -> "MessageEventResult":
|
|
@@ -205,9 +206,7 @@ class MessageEventResult(MessageChain):
|
|
|
205
206
|
return self
|
|
206
207
|
|
|
207
208
|
def is_stopped(self) -> bool:
|
|
208
|
-
"""
|
|
209
|
-
是否终止事件传播。
|
|
210
|
-
"""
|
|
209
|
+
"""是否终止事件传播。"""
|
|
211
210
|
return self.result_type == EventResultType.STOP
|
|
212
211
|
|
|
213
212
|
def set_async_stream(self, stream: AsyncGenerator) -> "MessageEventResult":
|
|
@@ -220,6 +219,7 @@ class MessageEventResult(MessageChain):
|
|
|
220
219
|
|
|
221
220
|
Args:
|
|
222
221
|
result_type (EventResultType): 事件处理的结果类型。
|
|
222
|
+
|
|
223
223
|
"""
|
|
224
224
|
self.result_content_type = typ
|
|
225
225
|
return self
|
astrbot/core/persona_mgr.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
from astrbot import logger
|
|
2
|
+
from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
|
|
1
3
|
from astrbot.core.db import BaseDatabase
|
|
2
4
|
from astrbot.core.db.po import Persona, Personality
|
|
3
|
-
from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
|
|
4
5
|
from astrbot.core.platform.message_session import MessageSession
|
|
5
|
-
from astrbot import logger
|
|
6
6
|
|
|
7
7
|
DEFAULT_PERSONALITY = Personality(
|
|
8
8
|
prompt="You are a helpful and friendly assistant.",
|
|
@@ -41,12 +41,14 @@ class PersonaManager:
|
|
|
41
41
|
return persona
|
|
42
42
|
|
|
43
43
|
async def get_default_persona_v3(
|
|
44
|
-
self,
|
|
44
|
+
self,
|
|
45
|
+
umo: str | MessageSession | None = None,
|
|
45
46
|
) -> Personality:
|
|
46
47
|
"""获取默认 persona"""
|
|
47
48
|
cfg = self.acm.get_conf(umo)
|
|
48
49
|
default_persona_id = cfg.get("provider_settings", {}).get(
|
|
49
|
-
"default_personality",
|
|
50
|
+
"default_personality",
|
|
51
|
+
"default",
|
|
50
52
|
)
|
|
51
53
|
if not default_persona_id or default_persona_id == "default":
|
|
52
54
|
return DEFAULT_PERSONALITY
|
|
@@ -66,16 +68,19 @@ class PersonaManager:
|
|
|
66
68
|
async def update_persona(
|
|
67
69
|
self,
|
|
68
70
|
persona_id: str,
|
|
69
|
-
system_prompt: str = None,
|
|
70
|
-
begin_dialogs: list[str] = None,
|
|
71
|
-
tools: list[str] = None,
|
|
71
|
+
system_prompt: str | None = None,
|
|
72
|
+
begin_dialogs: list[str] | None = None,
|
|
73
|
+
tools: list[str] | None = None,
|
|
72
74
|
):
|
|
73
75
|
"""更新指定 persona 的信息。tools 参数为 None 时表示使用所有工具,空列表表示不使用任何工具"""
|
|
74
76
|
existing_persona = await self.db.get_persona_by_id(persona_id)
|
|
75
77
|
if not existing_persona:
|
|
76
78
|
raise ValueError(f"Persona with ID {persona_id} does not exist.")
|
|
77
79
|
persona = await self.db.update_persona(
|
|
78
|
-
persona_id,
|
|
80
|
+
persona_id,
|
|
81
|
+
system_prompt,
|
|
82
|
+
begin_dialogs,
|
|
83
|
+
tools=tools,
|
|
79
84
|
)
|
|
80
85
|
if persona:
|
|
81
86
|
for i, p in enumerate(self.personas):
|
|
@@ -100,7 +105,10 @@ class PersonaManager:
|
|
|
100
105
|
if await self.db.get_persona_by_id(persona_id):
|
|
101
106
|
raise ValueError(f"Persona with ID {persona_id} already exists.")
|
|
102
107
|
new_persona = await self.db.insert_persona(
|
|
103
|
-
persona_id,
|
|
108
|
+
persona_id,
|
|
109
|
+
system_prompt,
|
|
110
|
+
begin_dialogs,
|
|
111
|
+
tools=tools,
|
|
104
112
|
)
|
|
105
113
|
self.personas.append(new_persona)
|
|
106
114
|
self.get_v3_persona_data()
|
|
@@ -115,6 +123,7 @@ class PersonaManager:
|
|
|
115
123
|
- list[dict]: 包含 persona 配置的字典列表。
|
|
116
124
|
- list[Personality]: 包含 Personality 对象的列表。
|
|
117
125
|
- Personality: 默认选择的 Personality 对象。
|
|
126
|
+
|
|
118
127
|
"""
|
|
119
128
|
v3_persona_config = [
|
|
120
129
|
{
|
|
@@ -136,7 +145,7 @@ class PersonaManager:
|
|
|
136
145
|
if begin_dialogs:
|
|
137
146
|
if len(begin_dialogs) % 2 != 0:
|
|
138
147
|
logger.error(
|
|
139
|
-
f"{persona_cfg['name']} 人格情景预设对话格式不对,条数应该为偶数。"
|
|
148
|
+
f"{persona_cfg['name']} 人格情景预设对话格式不对,条数应该为偶数。",
|
|
140
149
|
)
|
|
141
150
|
begin_dialogs = []
|
|
142
151
|
user_turn = True
|
|
@@ -146,7 +155,7 @@ class PersonaManager:
|
|
|
146
155
|
"role": "user" if user_turn else "assistant",
|
|
147
156
|
"content": dialog,
|
|
148
157
|
"_no_save": None, # 不持久化到 db
|
|
149
|
-
}
|
|
158
|
+
},
|
|
150
159
|
)
|
|
151
160
|
user_turn = not user_turn
|
|
152
161
|
|
|
@@ -27,15 +27,15 @@ STAGES_ORDER = [
|
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
__all__ = [
|
|
30
|
-
"WakingCheckStage",
|
|
31
|
-
"WhitelistCheckStage",
|
|
32
|
-
"SessionStatusCheckStage",
|
|
33
|
-
"RateLimitStage",
|
|
34
30
|
"ContentSafetyCheckStage",
|
|
31
|
+
"EventResultType",
|
|
32
|
+
"MessageEventResult",
|
|
35
33
|
"PreProcessStage",
|
|
36
34
|
"ProcessStage",
|
|
37
|
-
"
|
|
35
|
+
"RateLimitStage",
|
|
38
36
|
"RespondStage",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
37
|
+
"ResultDecorateStage",
|
|
38
|
+
"SessionStatusCheckStage",
|
|
39
|
+
"WakingCheckStage",
|
|
40
|
+
"WhitelistCheckStage",
|
|
41
41
|
]
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from ..context import PipelineContext
|
|
4
|
-
from astrbot.core.platform.astr_message_event import AstrMessageEvent
|
|
5
|
-
from astrbot.core.message.message_event_result import MessageEventResult
|
|
1
|
+
from collections.abc import AsyncGenerator
|
|
2
|
+
|
|
6
3
|
from astrbot.core import logger
|
|
4
|
+
from astrbot.core.message.message_event_result import MessageEventResult
|
|
5
|
+
from astrbot.core.platform.astr_message_event import AstrMessageEvent
|
|
6
|
+
|
|
7
|
+
from ..context import PipelineContext
|
|
8
|
+
from ..stage import Stage, register_stage
|
|
7
9
|
from .strategies.strategy import StrategySelector
|
|
8
10
|
|
|
9
11
|
|
|
@@ -19,8 +21,10 @@ class ContentSafetyCheckStage(Stage):
|
|
|
19
21
|
self.strategy_selector = StrategySelector(config)
|
|
20
22
|
|
|
21
23
|
async def process(
|
|
22
|
-
self,
|
|
23
|
-
|
|
24
|
+
self,
|
|
25
|
+
event: AstrMessageEvent,
|
|
26
|
+
check_text: str | None = None,
|
|
27
|
+
) -> None | AsyncGenerator[None, None]:
|
|
24
28
|
"""检查内容安全"""
|
|
25
29
|
text = check_text if check_text else event.get_message_str()
|
|
26
30
|
ok, info = self.strategy_selector.check(text)
|
|
@@ -28,8 +32,8 @@ class ContentSafetyCheckStage(Stage):
|
|
|
28
32
|
if event.is_at_or_wake_command:
|
|
29
33
|
event.set_result(
|
|
30
34
|
MessageEventResult().message(
|
|
31
|
-
"你的消息或者大模型的响应中包含不适当的内容,已被屏蔽。"
|
|
32
|
-
)
|
|
35
|
+
"你的消息或者大模型的响应中包含不适当的内容,已被屏蔽。",
|
|
36
|
+
),
|
|
33
37
|
)
|
|
34
38
|
yield
|
|
35
39
|
event.stop_event()
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
"""
|
|
2
|
-
使用此功能应该先 pip install baidu-aip
|
|
3
|
-
"""
|
|
1
|
+
"""使用此功能应该先 pip install baidu-aip"""
|
|
4
2
|
|
|
5
|
-
from . import ContentSafetyStrategy
|
|
6
3
|
from aip import AipContentCensor
|
|
7
4
|
|
|
5
|
+
from . import ContentSafetyStrategy
|
|
6
|
+
|
|
8
7
|
|
|
9
8
|
class BaiduAipStrategy(ContentSafetyStrategy):
|
|
10
9
|
def __init__(self, appid: str, ak: str, sk: str) -> None:
|
|
@@ -19,12 +18,12 @@ class BaiduAipStrategy(ContentSafetyStrategy):
|
|
|
19
18
|
return False, ""
|
|
20
19
|
if res["conclusionType"] == 1:
|
|
21
20
|
return True, ""
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
if "data" not in res:
|
|
22
|
+
return False, ""
|
|
23
|
+
count = len(res["data"])
|
|
24
|
+
parts = [f"百度审核服务发现 {count} 处违规:\n"]
|
|
25
|
+
for i in res["data"]:
|
|
26
|
+
parts.append(f"{i['msg']};\n")
|
|
27
|
+
parts.append("\n判断结果:" + res["conclusion"])
|
|
28
|
+
info = "".join(parts)
|
|
29
|
+
return False, info
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
from . import ContentSafetyStrategy
|
|
2
|
-
from typing import List, Tuple
|
|
3
1
|
from astrbot import logger
|
|
4
2
|
|
|
3
|
+
from . import ContentSafetyStrategy
|
|
4
|
+
|
|
5
5
|
|
|
6
6
|
class StrategySelector:
|
|
7
7
|
def __init__(self, config: dict) -> None:
|
|
8
|
-
self.enabled_strategies:
|
|
8
|
+
self.enabled_strategies: list[ContentSafetyStrategy] = []
|
|
9
9
|
if config["internal_keywords"]["enable"]:
|
|
10
10
|
from .keywords import KeywordsStrategy
|
|
11
11
|
|
|
12
12
|
self.enabled_strategies.append(
|
|
13
|
-
KeywordsStrategy(config["internal_keywords"]["extra_keywords"])
|
|
13
|
+
KeywordsStrategy(config["internal_keywords"]["extra_keywords"]),
|
|
14
14
|
)
|
|
15
15
|
if config["baidu_aip"]["enable"]:
|
|
16
16
|
try:
|
|
@@ -23,10 +23,10 @@ class StrategySelector:
|
|
|
23
23
|
config["baidu_aip"]["app_id"],
|
|
24
24
|
config["baidu_aip"]["api_key"],
|
|
25
25
|
config["baidu_aip"]["secret_key"],
|
|
26
|
-
)
|
|
26
|
+
),
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
def check(self, content: str) ->
|
|
29
|
+
def check(self, content: str) -> tuple[bool, str]:
|
|
30
30
|
for strategy in self.enabled_strategies:
|
|
31
31
|
ok, info = strategy.check(content)
|
|
32
32
|
if not ok:
|
astrbot/core/pipeline/context.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
+
|
|
2
3
|
from astrbot.core.config import AstrBotConfig
|
|
3
4
|
from astrbot.core.star import PluginManager
|
|
4
|
-
|
|
5
|
+
|
|
6
|
+
from .context_utils import call_event_hook, call_handler, call_local_llm_tool
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
@dataclass
|
|
@@ -13,3 +15,4 @@ class PipelineContext:
|
|
|
13
15
|
astrbot_config_id: str
|
|
14
16
|
call_handler = call_handler
|
|
15
17
|
call_event_hook = call_event_hook
|
|
18
|
+
call_local_llm_tool = call_local_llm_tool
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import traceback
|
|
3
3
|
import typing as T
|
|
4
|
+
|
|
4
5
|
from astrbot import logger
|
|
5
|
-
from astrbot.core.
|
|
6
|
-
from astrbot.core.
|
|
7
|
-
from astrbot.core.message.message_event_result import
|
|
6
|
+
from astrbot.core.agent.run_context import ContextWrapper
|
|
7
|
+
from astrbot.core.astr_agent_context import AstrAgentContext
|
|
8
|
+
from astrbot.core.message.message_event_result import CommandResult, MessageEventResult
|
|
8
9
|
from astrbot.core.platform.astr_message_event import AstrMessageEvent
|
|
10
|
+
from astrbot.core.star.star import star_map
|
|
11
|
+
from astrbot.core.star.star_handler import EventType, star_handlers_registry
|
|
9
12
|
|
|
10
13
|
|
|
11
14
|
async def call_handler(
|
|
@@ -26,6 +29,7 @@ async def call_handler(
|
|
|
26
29
|
|
|
27
30
|
Returns:
|
|
28
31
|
AsyncGenerator[None, None]: 异步生成器,用于在管道中传递控制流
|
|
32
|
+
|
|
29
33
|
"""
|
|
30
34
|
ready_to_call = None # 一个协程或者异步生成器
|
|
31
35
|
|
|
@@ -80,14 +84,17 @@ async def call_event_hook(
|
|
|
80
84
|
|
|
81
85
|
Returns:
|
|
82
86
|
bool: 如果事件被终止,返回 True
|
|
83
|
-
#
|
|
87
|
+
#
|
|
88
|
+
|
|
89
|
+
"""
|
|
84
90
|
handlers = star_handlers_registry.get_handlers_by_event_type(
|
|
85
|
-
hook_type,
|
|
91
|
+
hook_type,
|
|
92
|
+
plugins_name=event.plugins_name,
|
|
86
93
|
)
|
|
87
94
|
for handler in handlers:
|
|
88
95
|
try:
|
|
89
96
|
logger.debug(
|
|
90
|
-
f"hook({hook_type.name}) -> {star_map[handler.handler_module_path].name} - {handler.handler_name}"
|
|
97
|
+
f"hook({hook_type.name}) -> {star_map[handler.handler_module_path].name} - {handler.handler_name}",
|
|
91
98
|
)
|
|
92
99
|
await handler.handler(event, *args, **kwargs)
|
|
93
100
|
except BaseException:
|
|
@@ -95,8 +102,71 @@ async def call_event_hook(
|
|
|
95
102
|
|
|
96
103
|
if event.is_stopped():
|
|
97
104
|
logger.info(
|
|
98
|
-
f"{star_map[handler.handler_module_path].name} - {handler.handler_name} 终止了事件传播。"
|
|
105
|
+
f"{star_map[handler.handler_module_path].name} - {handler.handler_name} 终止了事件传播。",
|
|
99
106
|
)
|
|
100
107
|
return True
|
|
101
108
|
|
|
102
109
|
return event.is_stopped()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
async def call_local_llm_tool(
|
|
113
|
+
context: ContextWrapper[AstrAgentContext],
|
|
114
|
+
handler: T.Callable[..., T.Awaitable[T.Any]],
|
|
115
|
+
method_name: str,
|
|
116
|
+
*args,
|
|
117
|
+
**kwargs,
|
|
118
|
+
) -> T.AsyncGenerator[T.Any, None]:
|
|
119
|
+
"""执行本地 LLM 工具的处理函数并处理其返回结果"""
|
|
120
|
+
ready_to_call = None # 一个协程或者异步生成器
|
|
121
|
+
|
|
122
|
+
trace_ = None
|
|
123
|
+
|
|
124
|
+
event = context.context.event
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
if method_name == "run" or method_name == "decorator_handler":
|
|
128
|
+
ready_to_call = handler(event, *args, **kwargs)
|
|
129
|
+
elif method_name == "call":
|
|
130
|
+
ready_to_call = handler(context, *args, **kwargs)
|
|
131
|
+
else:
|
|
132
|
+
raise ValueError(f"未知的方法名: {method_name}")
|
|
133
|
+
except ValueError as e:
|
|
134
|
+
logger.error(f"调用本地 LLM 工具时出错: {e}", exc_info=True)
|
|
135
|
+
except TypeError:
|
|
136
|
+
logger.error("处理函数参数不匹配,请检查 handler 的定义。", exc_info=True)
|
|
137
|
+
except Exception as e:
|
|
138
|
+
trace_ = traceback.format_exc()
|
|
139
|
+
logger.error(f"调用本地 LLM 工具时出错: {e}\n{trace_}")
|
|
140
|
+
|
|
141
|
+
if not ready_to_call:
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
if inspect.isasyncgen(ready_to_call):
|
|
145
|
+
_has_yielded = False
|
|
146
|
+
try:
|
|
147
|
+
async for ret in ready_to_call:
|
|
148
|
+
# 这里逐步执行异步生成器, 对于每个 yield 返回的 ret, 执行下面的代码
|
|
149
|
+
# 返回值只能是 MessageEventResult 或者 None(无返回值)
|
|
150
|
+
_has_yielded = True
|
|
151
|
+
if isinstance(ret, (MessageEventResult, CommandResult)):
|
|
152
|
+
# 如果返回值是 MessageEventResult, 设置结果并继续
|
|
153
|
+
event.set_result(ret)
|
|
154
|
+
yield
|
|
155
|
+
else:
|
|
156
|
+
# 如果返回值是 None, 则不设置结果并继续
|
|
157
|
+
# 继续执行后续阶段
|
|
158
|
+
yield ret
|
|
159
|
+
if not _has_yielded:
|
|
160
|
+
# 如果这个异步生成器没有执行到 yield 分支
|
|
161
|
+
yield
|
|
162
|
+
except Exception as e:
|
|
163
|
+
logger.error(f"Previous Error: {trace_}")
|
|
164
|
+
raise e
|
|
165
|
+
elif inspect.iscoroutine(ready_to_call):
|
|
166
|
+
# 如果只是一个协程, 直接执行
|
|
167
|
+
ret = await ready_to_call
|
|
168
|
+
if isinstance(ret, (MessageEventResult, CommandResult)):
|
|
169
|
+
event.set_result(ret)
|
|
170
|
+
yield
|
|
171
|
+
else:
|
|
172
|
+
yield ret
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import traceback
|
|
2
1
|
import asyncio
|
|
3
2
|
import random
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
from astrbot.core.platform.astr_message_event import AstrMessageEvent
|
|
3
|
+
import traceback
|
|
4
|
+
from collections.abc import AsyncGenerator
|
|
5
|
+
|
|
8
6
|
from astrbot.core import logger
|
|
9
|
-
from astrbot.core.message.components import Plain, Record
|
|
7
|
+
from astrbot.core.message.components import Image, Plain, Record
|
|
8
|
+
from astrbot.core.platform.astr_message_event import AstrMessageEvent
|
|
9
|
+
|
|
10
|
+
from ..context import PipelineContext
|
|
11
|
+
from ..stage import Stage, register_stage
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
@register_stage
|
|
@@ -20,8 +22,9 @@ class PreProcessStage(Stage):
|
|
|
20
22
|
self.platform_settings: dict = self.config.get("platform_settings", {})
|
|
21
23
|
|
|
22
24
|
async def process(
|
|
23
|
-
self,
|
|
24
|
-
|
|
25
|
+
self,
|
|
26
|
+
event: AstrMessageEvent,
|
|
27
|
+
) -> None | AsyncGenerator[None, None]:
|
|
25
28
|
"""在处理事件之前的预处理"""
|
|
26
29
|
# 平台特异配置:platform_specific.<platform>.pre_ack_emoji
|
|
27
30
|
supported = {"telegram", "lark"}
|
|
@@ -68,7 +71,7 @@ class PreProcessStage(Stage):
|
|
|
68
71
|
stt_provider = ctx.get_using_stt_provider(event.unified_msg_origin)
|
|
69
72
|
if not stt_provider:
|
|
70
73
|
logger.warning(
|
|
71
|
-
f"会话 {event.unified_msg_origin} 未配置语音转文本模型。"
|
|
74
|
+
f"会话 {event.unified_msg_origin} 未配置语音转文本模型。",
|
|
72
75
|
)
|
|
73
76
|
return
|
|
74
77
|
message_chain = event.get_messages()
|