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.
- 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 +56 -53
- 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.3.dist-info}/METADATA +2 -1
- astrbot-4.5.3.dist-info/RECORD +261 -0
- astrbot-4.5.1.dist-info/RECORD +0 -260
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/WHEEL +0 -0
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/entry_points.txt +0 -0
- {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
|
|
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
|
-
|
|
32
|
-
|
|
30
|
+
cache_room_info,
|
|
31
|
+
cache_user_info,
|
|
33
32
|
create_base_message,
|
|
34
|
-
|
|
33
|
+
extract_sender_info,
|
|
35
34
|
format_poll,
|
|
36
|
-
|
|
37
|
-
|
|
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,
|
|
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",
|
|
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:
|
|
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",
|
|
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,
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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) ->
|
|
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"] =
|
|
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),
|
|
223
|
+
getattr(session, "extra_data", None),
|
|
224
|
+
dict,
|
|
210
225
|
):
|
|
211
|
-
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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:
|
|
404
|
-
fallback_urls:
|
|
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,
|
|
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",
|
|
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) ->
|
|
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,
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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,
|
|
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:
|
|
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,
|
|
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:
|
|
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,
|
|
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,
|
|
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:
|