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,9 @@
|
|
|
1
1
|
import re
|
|
2
|
-
|
|
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
|
+
|
|
6
|
+
from . import HandlerFilter
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
# 正则表达式过滤器不会受到 wake_prefix 的制约。
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
from .star import register_star
|
|
2
2
|
from .star_handler import (
|
|
3
|
+
register_after_message_sent,
|
|
4
|
+
register_agent,
|
|
3
5
|
register_command,
|
|
4
6
|
register_command_group,
|
|
5
|
-
register_event_message_type,
|
|
6
|
-
register_platform_adapter_type,
|
|
7
|
-
register_regex,
|
|
8
|
-
register_permission_type,
|
|
9
7
|
register_custom_filter,
|
|
8
|
+
register_event_message_type,
|
|
9
|
+
register_llm_tool,
|
|
10
10
|
register_on_astrbot_loaded,
|
|
11
|
-
|
|
11
|
+
register_on_decorating_result,
|
|
12
12
|
register_on_llm_request,
|
|
13
13
|
register_on_llm_response,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
register_on_platform_loaded,
|
|
15
|
+
register_permission_type,
|
|
16
|
+
register_platform_adapter_type,
|
|
17
|
+
register_regex,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
__all__ = [
|
|
21
|
-
"
|
|
21
|
+
"register_after_message_sent",
|
|
22
|
+
"register_agent",
|
|
22
23
|
"register_command",
|
|
23
24
|
"register_command_group",
|
|
24
|
-
"register_event_message_type",
|
|
25
|
-
"register_platform_adapter_type",
|
|
26
|
-
"register_regex",
|
|
27
|
-
"register_permission_type",
|
|
28
25
|
"register_custom_filter",
|
|
26
|
+
"register_event_message_type",
|
|
27
|
+
"register_llm_tool",
|
|
29
28
|
"register_on_astrbot_loaded",
|
|
30
|
-
"
|
|
29
|
+
"register_on_decorating_result",
|
|
31
30
|
"register_on_llm_request",
|
|
32
31
|
"register_on_llm_response",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
32
|
+
"register_on_platform_loaded",
|
|
33
|
+
"register_permission_type",
|
|
34
|
+
"register_platform_adapter_type",
|
|
35
|
+
"register_regex",
|
|
36
|
+
"register_star",
|
|
37
37
|
]
|
|
@@ -6,7 +6,11 @@ _warned_register_star = False
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def register_star(
|
|
9
|
-
name: str,
|
|
9
|
+
name: str,
|
|
10
|
+
author: str,
|
|
11
|
+
desc: str,
|
|
12
|
+
version: str,
|
|
13
|
+
repo: str | None = None,
|
|
10
14
|
):
|
|
11
15
|
"""注册一个插件(Star)。
|
|
12
16
|
|
|
@@ -29,8 +33,8 @@ def register_star(
|
|
|
29
33
|
...
|
|
30
34
|
|
|
31
35
|
帮助信息会被自动提取。使用 `/plugin <插件名> 可以查看帮助信息。`
|
|
32
|
-
"""
|
|
33
36
|
|
|
37
|
+
"""
|
|
34
38
|
global _warned_register_star
|
|
35
39
|
if not _warned_register_star:
|
|
36
40
|
_warned_register_star = True
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Awaitable, Callable
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
2
6
|
import docstring_parser
|
|
3
7
|
|
|
4
|
-
from
|
|
8
|
+
from astrbot.core import logger
|
|
9
|
+
from astrbot.core.agent.agent import Agent
|
|
10
|
+
from astrbot.core.agent.handoff import HandoffTool
|
|
11
|
+
from astrbot.core.agent.hooks import BaseAgentRunHooks
|
|
12
|
+
from astrbot.core.agent.tool import FunctionTool
|
|
13
|
+
from astrbot.core.astr_agent_context import AstrAgentContext
|
|
14
|
+
from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES
|
|
15
|
+
from astrbot.core.provider.register import llm_tools
|
|
16
|
+
|
|
5
17
|
from ..filter.command import CommandFilter
|
|
6
18
|
from ..filter.command_group import CommandGroupFilter
|
|
7
|
-
from ..filter.
|
|
19
|
+
from ..filter.custom_filter import CustomFilterAnd, CustomFilterOr
|
|
20
|
+
from ..filter.event_message_type import EventMessageType, EventMessageTypeFilter
|
|
21
|
+
from ..filter.permission import PermissionType, PermissionTypeFilter
|
|
8
22
|
from ..filter.platform_adapter_type import (
|
|
9
|
-
PlatformAdapterTypeFilter,
|
|
10
23
|
PlatformAdapterType,
|
|
24
|
+
PlatformAdapterTypeFilter,
|
|
11
25
|
)
|
|
12
|
-
from ..filter.permission import PermissionTypeFilter, PermissionType
|
|
13
|
-
from ..filter.custom_filter import CustomFilterAnd, CustomFilterOr
|
|
14
26
|
from ..filter.regex import RegexFilter
|
|
15
|
-
from
|
|
16
|
-
from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES
|
|
17
|
-
from astrbot.core.provider.register import llm_tools
|
|
18
|
-
from astrbot.core.agent.agent import Agent
|
|
19
|
-
from astrbot.core.agent.tool import FunctionTool
|
|
20
|
-
from astrbot.core.agent.handoff import HandoffTool
|
|
21
|
-
from astrbot.core.agent.hooks import BaseAgentRunHooks
|
|
22
|
-
from astrbot.core.astr_agent_context import AstrAgentContext
|
|
23
|
-
from astrbot.core import logger
|
|
27
|
+
from ..star_handler import EventType, StarHandlerMetadata, star_handlers_registry
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
def get_handler_full_name(awaitable: Callable[..., Awaitable[Any]]) -> str:
|
|
@@ -39,27 +43,26 @@ def get_handler_or_create(
|
|
|
39
43
|
md = star_handlers_registry.get_handler_by_full_name(handler_full_name)
|
|
40
44
|
if md:
|
|
41
45
|
return md
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
46
|
+
md = StarHandlerMetadata(
|
|
47
|
+
event_type=event_type,
|
|
48
|
+
handler_full_name=handler_full_name,
|
|
49
|
+
handler_name=handler.__name__,
|
|
50
|
+
handler_module_path=handler.__module__,
|
|
51
|
+
handler=handler,
|
|
52
|
+
event_filters=[],
|
|
53
|
+
)
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
# 插件handler的附加额外信息
|
|
56
|
+
if handler.__doc__:
|
|
57
|
+
md.desc = handler.__doc__.strip()
|
|
58
|
+
if "desc" in kwargs:
|
|
59
|
+
md.desc = kwargs["desc"]
|
|
60
|
+
del kwargs["desc"]
|
|
61
|
+
md.extras_configs = kwargs
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
if not dont_add:
|
|
64
|
+
star_handlers_registry.append(md)
|
|
65
|
+
return md
|
|
63
66
|
|
|
64
67
|
|
|
65
68
|
def register_command(
|
|
@@ -78,20 +81,22 @@ def register_command(
|
|
|
78
81
|
command_name.parent_group.get_complete_command_names()
|
|
79
82
|
)
|
|
80
83
|
new_command = CommandFilter(
|
|
81
|
-
sub_command,
|
|
84
|
+
sub_command,
|
|
85
|
+
alias,
|
|
86
|
+
None,
|
|
87
|
+
parent_command_names=parent_command_names,
|
|
82
88
|
)
|
|
83
89
|
command_name.parent_group.add_sub_command_filter(new_command)
|
|
84
90
|
else:
|
|
85
91
|
logger.warning(
|
|
86
|
-
f"注册指令{command_name} 的子指令时未提供 sub_command 参数。"
|
|
92
|
+
f"注册指令{command_name} 的子指令时未提供 sub_command 参数。",
|
|
87
93
|
)
|
|
94
|
+
# 裸指令
|
|
95
|
+
elif command_name is None:
|
|
96
|
+
logger.warning("注册裸指令时未提供 command_name 参数。")
|
|
88
97
|
else:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
logger.warning("注册裸指令时未提供 command_name 参数。")
|
|
92
|
-
else:
|
|
93
|
-
new_command = CommandFilter(command_name, alias, None)
|
|
94
|
-
add_to_event_filters = True
|
|
98
|
+
new_command = CommandFilter(command_name, alias, None)
|
|
99
|
+
add_to_event_filters = True
|
|
95
100
|
|
|
96
101
|
def decorator(awaitable):
|
|
97
102
|
if not add_to_event_filters:
|
|
@@ -99,7 +104,9 @@ def register_command(
|
|
|
99
104
|
True # 打一个标记,表示这是一个子指令,再 wakingstage 阶段这个 handler 将会直接被跳过(其父指令会接管)
|
|
100
105
|
)
|
|
101
106
|
handler_md = get_handler_or_create(
|
|
102
|
-
awaitable,
|
|
107
|
+
awaitable,
|
|
108
|
+
EventType.AdapterMessageEvent,
|
|
109
|
+
**kwargs,
|
|
103
110
|
)
|
|
104
111
|
if new_command:
|
|
105
112
|
new_command.init_handler_md(handler_md)
|
|
@@ -116,6 +123,7 @@ def register_custom_filter(custom_type_filter, *args, **kwargs):
|
|
|
116
123
|
custom_type_filter: 在裸指令时为CustomFilter对象
|
|
117
124
|
在指令组时为父指令的RegisteringCommandable对象,即self或者command_group的返回
|
|
118
125
|
raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True
|
|
126
|
+
|
|
119
127
|
"""
|
|
120
128
|
add_to_event_filters = False
|
|
121
129
|
raise_error = True
|
|
@@ -140,19 +148,20 @@ def register_custom_filter(custom_type_filter, *args, **kwargs):
|
|
|
140
148
|
def decorator(awaitable):
|
|
141
149
|
# 裸指令,子指令与指令组的区分,指令组会因为标记跳过wake。
|
|
142
150
|
if (
|
|
143
|
-
not add_to_event_filters
|
|
144
|
-
|
|
145
|
-
or (add_to_event_filters and isinstance(awaitable, RegisteringCommandable))
|
|
146
|
-
):
|
|
151
|
+
not add_to_event_filters and isinstance(awaitable, RegisteringCommandable)
|
|
152
|
+
) or (add_to_event_filters and isinstance(awaitable, RegisteringCommandable)):
|
|
147
153
|
# 指令组 与 根指令组,添加到本层的grouphandle中一起判断
|
|
148
154
|
awaitable.parent_group.add_custom_filter(custom_filter)
|
|
149
155
|
else:
|
|
150
156
|
handler_md = get_handler_or_create(
|
|
151
|
-
awaitable,
|
|
157
|
+
awaitable,
|
|
158
|
+
EventType.AdapterMessageEvent,
|
|
159
|
+
**kwargs,
|
|
152
160
|
)
|
|
153
161
|
|
|
154
162
|
if not add_to_event_filters and not isinstance(
|
|
155
|
-
awaitable,
|
|
163
|
+
awaitable,
|
|
164
|
+
RegisteringCommandable,
|
|
156
165
|
):
|
|
157
166
|
# 底层子指令
|
|
158
167
|
handle_full_name = get_handler_full_name(awaitable)
|
|
@@ -171,7 +180,9 @@ def register_custom_filter(custom_type_filter, *args, **kwargs):
|
|
|
171
180
|
else:
|
|
172
181
|
# 裸指令
|
|
173
182
|
handler_md = get_handler_or_create(
|
|
174
|
-
awaitable,
|
|
183
|
+
awaitable,
|
|
184
|
+
EventType.AdapterMessageEvent,
|
|
185
|
+
**kwargs,
|
|
175
186
|
)
|
|
176
187
|
handler_md.event_filters.append(custom_filter)
|
|
177
188
|
|
|
@@ -194,20 +205,23 @@ def register_command_group(
|
|
|
194
205
|
logger.warning(f"{command_group_name} 指令组的子指令组 sub_command 未指定")
|
|
195
206
|
else:
|
|
196
207
|
new_group = CommandGroupFilter(
|
|
197
|
-
sub_command,
|
|
208
|
+
sub_command,
|
|
209
|
+
alias,
|
|
210
|
+
parent_group=command_group_name.parent_group,
|
|
198
211
|
)
|
|
199
212
|
command_group_name.parent_group.add_sub_command_filter(new_group)
|
|
213
|
+
# 根指令组
|
|
214
|
+
elif command_group_name is None:
|
|
215
|
+
logger.warning("根指令组的名称未指定")
|
|
200
216
|
else:
|
|
201
|
-
|
|
202
|
-
if command_group_name is None:
|
|
203
|
-
logger.warning("根指令组的名称未指定")
|
|
204
|
-
else:
|
|
205
|
-
new_group = CommandGroupFilter(command_group_name, alias)
|
|
217
|
+
new_group = CommandGroupFilter(command_group_name, alias)
|
|
206
218
|
|
|
207
219
|
def decorator(obj):
|
|
208
220
|
if new_group:
|
|
209
221
|
handler_md = get_handler_or_create(
|
|
210
|
-
obj,
|
|
222
|
+
obj,
|
|
223
|
+
EventType.AdapterMessageEvent,
|
|
224
|
+
**kwargs,
|
|
211
225
|
)
|
|
212
226
|
handler_md.event_filters.append(new_group)
|
|
213
227
|
|
|
@@ -220,9 +234,7 @@ def register_command_group(
|
|
|
220
234
|
class RegisteringCommandable:
|
|
221
235
|
"""用于指令组级联注册"""
|
|
222
236
|
|
|
223
|
-
group: Callable[..., Callable[...,
|
|
224
|
-
register_command_group
|
|
225
|
-
)
|
|
237
|
+
group: Callable[..., Callable[..., RegisteringCommandable]] = register_command_group
|
|
226
238
|
command: Callable[..., Callable[..., None]] = register_command
|
|
227
239
|
custom_filter: Callable[..., Callable[..., None]] = register_custom_filter
|
|
228
240
|
|
|
@@ -235,7 +247,9 @@ def register_event_message_type(event_message_type: EventMessageType, **kwargs):
|
|
|
235
247
|
|
|
236
248
|
def decorator(awaitable):
|
|
237
249
|
handler_md = get_handler_or_create(
|
|
238
|
-
awaitable,
|
|
250
|
+
awaitable,
|
|
251
|
+
EventType.AdapterMessageEvent,
|
|
252
|
+
**kwargs,
|
|
239
253
|
)
|
|
240
254
|
handler_md.event_filters.append(EventMessageTypeFilter(event_message_type))
|
|
241
255
|
return awaitable
|
|
@@ -244,14 +258,15 @@ def register_event_message_type(event_message_type: EventMessageType, **kwargs):
|
|
|
244
258
|
|
|
245
259
|
|
|
246
260
|
def register_platform_adapter_type(
|
|
247
|
-
platform_adapter_type: PlatformAdapterType,
|
|
261
|
+
platform_adapter_type: PlatformAdapterType,
|
|
262
|
+
**kwargs,
|
|
248
263
|
):
|
|
249
264
|
"""注册一个 PlatformAdapterType"""
|
|
250
265
|
|
|
251
266
|
def decorator(awaitable):
|
|
252
267
|
handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent)
|
|
253
268
|
handler_md.event_filters.append(
|
|
254
|
-
PlatformAdapterTypeFilter(platform_adapter_type)
|
|
269
|
+
PlatformAdapterTypeFilter(platform_adapter_type),
|
|
255
270
|
)
|
|
256
271
|
return awaitable
|
|
257
272
|
|
|
@@ -263,7 +278,9 @@ def register_regex(regex: str, **kwargs):
|
|
|
263
278
|
|
|
264
279
|
def decorator(awaitable):
|
|
265
280
|
handler_md = get_handler_or_create(
|
|
266
|
-
awaitable,
|
|
281
|
+
awaitable,
|
|
282
|
+
EventType.AdapterMessageEvent,
|
|
283
|
+
**kwargs,
|
|
267
284
|
)
|
|
268
285
|
handler_md.event_filters.append(RegexFilter(regex))
|
|
269
286
|
return awaitable
|
|
@@ -277,12 +294,13 @@ def register_permission_type(permission_type: PermissionType, raise_error: bool
|
|
|
277
294
|
Args:
|
|
278
295
|
permission_type: PermissionType
|
|
279
296
|
raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True
|
|
297
|
+
|
|
280
298
|
"""
|
|
281
299
|
|
|
282
300
|
def decorator(awaitable):
|
|
283
301
|
handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent)
|
|
284
302
|
handler_md.event_filters.append(
|
|
285
|
-
PermissionTypeFilter(permission_type, raise_error)
|
|
303
|
+
PermissionTypeFilter(permission_type, raise_error),
|
|
286
304
|
)
|
|
287
305
|
return awaitable
|
|
288
306
|
|
|
@@ -300,9 +318,7 @@ def register_on_astrbot_loaded(**kwargs):
|
|
|
300
318
|
|
|
301
319
|
|
|
302
320
|
def register_on_platform_loaded(**kwargs):
|
|
303
|
-
"""
|
|
304
|
-
当平台加载完成时
|
|
305
|
-
"""
|
|
321
|
+
"""当平台加载完成时"""
|
|
306
322
|
|
|
307
323
|
def decorator(awaitable):
|
|
308
324
|
_ = get_handler_or_create(awaitable, EventType.OnPlatformLoadedEvent, **kwargs)
|
|
@@ -324,6 +340,7 @@ def register_on_llm_request(**kwargs):
|
|
|
324
340
|
```
|
|
325
341
|
|
|
326
342
|
请务必接收两个参数:event, request
|
|
343
|
+
|
|
327
344
|
"""
|
|
328
345
|
|
|
329
346
|
def decorator(awaitable):
|
|
@@ -346,6 +363,7 @@ def register_on_llm_response(**kwargs):
|
|
|
346
363
|
```
|
|
347
364
|
|
|
348
365
|
请务必接收两个参数:event, request
|
|
366
|
+
|
|
349
367
|
"""
|
|
350
368
|
|
|
351
369
|
def decorator(awaitable):
|
|
@@ -365,7 +383,7 @@ def register_llm_tool(name: str | None = None, **kwargs):
|
|
|
365
383
|
async def get_weather(event: AstrMessageEvent, location: str):
|
|
366
384
|
\'\'\'获取天气信息。
|
|
367
385
|
|
|
368
|
-
|
|
386
|
+
Args:
|
|
369
387
|
location(string): 地点
|
|
370
388
|
\'\'\'
|
|
371
389
|
# 处理逻辑
|
|
@@ -386,8 +404,8 @@ def register_llm_tool(name: str | None = None, **kwargs):
|
|
|
386
404
|
event.stop_event()
|
|
387
405
|
yield
|
|
388
406
|
```
|
|
389
|
-
"""
|
|
390
407
|
|
|
408
|
+
"""
|
|
391
409
|
name_ = name
|
|
392
410
|
registering_agent = None
|
|
393
411
|
if kwargs.get("registering_agent"):
|
|
@@ -401,14 +419,14 @@ def register_llm_tool(name: str | None = None, **kwargs):
|
|
|
401
419
|
for arg in docstring.params:
|
|
402
420
|
if arg.type_name not in SUPPORTED_TYPES:
|
|
403
421
|
raise ValueError(
|
|
404
|
-
f"LLM 函数工具 {awaitable.__module__}_{llm_tool_name} 不支持的参数类型:{arg.type_name}"
|
|
422
|
+
f"LLM 函数工具 {awaitable.__module__}_{llm_tool_name} 不支持的参数类型:{arg.type_name}",
|
|
405
423
|
)
|
|
406
424
|
args.append(
|
|
407
425
|
{
|
|
408
426
|
"type": arg.type_name,
|
|
409
427
|
"name": arg.arg_name,
|
|
410
428
|
"description": arg.description,
|
|
411
|
-
}
|
|
429
|
+
},
|
|
412
430
|
)
|
|
413
431
|
# print(llm_tool_name, registering_agent)
|
|
414
432
|
if not registering_agent:
|
|
@@ -454,6 +472,7 @@ def register_agent(
|
|
|
454
472
|
instruction: Agent 的指令
|
|
455
473
|
tools: Agent 使用的工具列表
|
|
456
474
|
run_hooks: Agent 运行时的钩子函数
|
|
475
|
+
|
|
457
476
|
"""
|
|
458
477
|
tools_ = tools or []
|
|
459
478
|
|
|
@@ -478,7 +497,9 @@ def register_on_decorating_result(**kwargs):
|
|
|
478
497
|
|
|
479
498
|
def decorator(awaitable):
|
|
480
499
|
_ = get_handler_or_create(
|
|
481
|
-
awaitable,
|
|
500
|
+
awaitable,
|
|
501
|
+
EventType.OnDecoratingResultEvent,
|
|
502
|
+
**kwargs,
|
|
482
503
|
)
|
|
483
504
|
return awaitable
|
|
484
505
|
|
|
@@ -490,7 +511,9 @@ def register_after_message_sent(**kwargs):
|
|
|
490
511
|
|
|
491
512
|
def decorator(awaitable):
|
|
492
513
|
_ = get_handler_or_create(
|
|
493
|
-
awaitable,
|
|
514
|
+
awaitable,
|
|
515
|
+
EventType.OnAfterMessageSentEvent,
|
|
516
|
+
**kwargs,
|
|
494
517
|
)
|
|
495
518
|
return awaitable
|
|
496
519
|
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
会话服务管理器 - 负责管理每个会话的LLM、TTS等服务的启停状态
|
|
3
|
-
"""
|
|
1
|
+
"""会话服务管理器 - 负责管理每个会话的LLM、TTS等服务的启停状态"""
|
|
4
2
|
|
|
5
3
|
from astrbot.core import logger, sp
|
|
6
4
|
from astrbot.core.platform.astr_message_event import AstrMessageEvent
|
|
@@ -22,10 +20,14 @@ class SessionServiceManager:
|
|
|
22
20
|
|
|
23
21
|
Returns:
|
|
24
22
|
bool: True表示启用,False表示禁用
|
|
23
|
+
|
|
25
24
|
"""
|
|
26
25
|
# 获取会话服务配置
|
|
27
26
|
session_services = sp.get(
|
|
28
|
-
"session_service_config",
|
|
27
|
+
"session_service_config",
|
|
28
|
+
{},
|
|
29
|
+
scope="umo",
|
|
30
|
+
scope_id=session_id,
|
|
29
31
|
)
|
|
30
32
|
|
|
31
33
|
# 如果配置了该会话的LLM状态,返回该状态
|
|
@@ -43,13 +45,17 @@ class SessionServiceManager:
|
|
|
43
45
|
Args:
|
|
44
46
|
session_id: 会话ID (unified_msg_origin)
|
|
45
47
|
enabled: True表示启用,False表示禁用
|
|
48
|
+
|
|
46
49
|
"""
|
|
47
50
|
session_config = (
|
|
48
51
|
sp.get("session_service_config", {}, scope="umo", scope_id=session_id) or {}
|
|
49
52
|
)
|
|
50
53
|
session_config["llm_enabled"] = enabled
|
|
51
54
|
sp.put(
|
|
52
|
-
"session_service_config",
|
|
55
|
+
"session_service_config",
|
|
56
|
+
session_config,
|
|
57
|
+
scope="umo",
|
|
58
|
+
scope_id=session_id,
|
|
53
59
|
)
|
|
54
60
|
|
|
55
61
|
@staticmethod
|
|
@@ -61,6 +67,7 @@ class SessionServiceManager:
|
|
|
61
67
|
|
|
62
68
|
Returns:
|
|
63
69
|
bool: True表示应该处理,False表示跳过
|
|
70
|
+
|
|
64
71
|
"""
|
|
65
72
|
session_id = event.unified_msg_origin
|
|
66
73
|
return SessionServiceManager.is_llm_enabled_for_session(session_id)
|
|
@@ -78,10 +85,14 @@ class SessionServiceManager:
|
|
|
78
85
|
|
|
79
86
|
Returns:
|
|
80
87
|
bool: True表示启用,False表示禁用
|
|
88
|
+
|
|
81
89
|
"""
|
|
82
90
|
# 获取会话服务配置
|
|
83
91
|
session_services = sp.get(
|
|
84
|
-
"session_service_config",
|
|
92
|
+
"session_service_config",
|
|
93
|
+
{},
|
|
94
|
+
scope="umo",
|
|
95
|
+
scope_id=session_id,
|
|
85
96
|
)
|
|
86
97
|
|
|
87
98
|
# 如果配置了该会话的TTS状态,返回该状态
|
|
@@ -99,17 +110,21 @@ class SessionServiceManager:
|
|
|
99
110
|
Args:
|
|
100
111
|
session_id: 会话ID (unified_msg_origin)
|
|
101
112
|
enabled: True表示启用,False表示禁用
|
|
113
|
+
|
|
102
114
|
"""
|
|
103
115
|
session_config = (
|
|
104
116
|
sp.get("session_service_config", {}, scope="umo", scope_id=session_id) or {}
|
|
105
117
|
)
|
|
106
118
|
session_config["tts_enabled"] = enabled
|
|
107
119
|
sp.put(
|
|
108
|
-
"session_service_config",
|
|
120
|
+
"session_service_config",
|
|
121
|
+
session_config,
|
|
122
|
+
scope="umo",
|
|
123
|
+
scope_id=session_id,
|
|
109
124
|
)
|
|
110
125
|
|
|
111
126
|
logger.info(
|
|
112
|
-
f"会话 {session_id} 的TTS状态已更新为: {'启用' if enabled else '禁用'}"
|
|
127
|
+
f"会话 {session_id} 的TTS状态已更新为: {'启用' if enabled else '禁用'}",
|
|
113
128
|
)
|
|
114
129
|
|
|
115
130
|
@staticmethod
|
|
@@ -121,6 +136,7 @@ class SessionServiceManager:
|
|
|
121
136
|
|
|
122
137
|
Returns:
|
|
123
138
|
bool: True表示应该处理,False表示跳过
|
|
139
|
+
|
|
124
140
|
"""
|
|
125
141
|
session_id = event.unified_msg_origin
|
|
126
142
|
return SessionServiceManager.is_tts_enabled_for_session(session_id)
|
|
@@ -138,10 +154,14 @@ class SessionServiceManager:
|
|
|
138
154
|
|
|
139
155
|
Returns:
|
|
140
156
|
bool: True表示启用,False表示禁用
|
|
157
|
+
|
|
141
158
|
"""
|
|
142
159
|
# 获取会话服务配置
|
|
143
160
|
session_services = sp.get(
|
|
144
|
-
"session_service_config",
|
|
161
|
+
"session_service_config",
|
|
162
|
+
{},
|
|
163
|
+
scope="umo",
|
|
164
|
+
scope_id=session_id,
|
|
145
165
|
)
|
|
146
166
|
|
|
147
167
|
# 如果配置了该会话的整体状态,返回该状态
|
|
@@ -159,17 +179,21 @@ class SessionServiceManager:
|
|
|
159
179
|
Args:
|
|
160
180
|
session_id: 会话ID (unified_msg_origin)
|
|
161
181
|
enabled: True表示启用,False表示禁用
|
|
182
|
+
|
|
162
183
|
"""
|
|
163
184
|
session_config = (
|
|
164
185
|
sp.get("session_service_config", {}, scope="umo", scope_id=session_id) or {}
|
|
165
186
|
)
|
|
166
187
|
session_config["session_enabled"] = enabled
|
|
167
188
|
sp.put(
|
|
168
|
-
"session_service_config",
|
|
189
|
+
"session_service_config",
|
|
190
|
+
session_config,
|
|
191
|
+
scope="umo",
|
|
192
|
+
scope_id=session_id,
|
|
169
193
|
)
|
|
170
194
|
|
|
171
195
|
logger.info(
|
|
172
|
-
f"会话 {session_id} 的整体状态已更新为: {'启用' if enabled else '禁用'}"
|
|
196
|
+
f"会话 {session_id} 的整体状态已更新为: {'启用' if enabled else '禁用'}",
|
|
173
197
|
)
|
|
174
198
|
|
|
175
199
|
@staticmethod
|
|
@@ -181,6 +205,7 @@ class SessionServiceManager:
|
|
|
181
205
|
|
|
182
206
|
Returns:
|
|
183
207
|
bool: True表示应该处理,False表示跳过
|
|
208
|
+
|
|
184
209
|
"""
|
|
185
210
|
session_id = event.unified_msg_origin
|
|
186
211
|
return SessionServiceManager.is_session_enabled(session_id)
|
|
@@ -198,9 +223,13 @@ class SessionServiceManager:
|
|
|
198
223
|
|
|
199
224
|
Returns:
|
|
200
225
|
str: 自定义名称,如果没有设置则返回None
|
|
226
|
+
|
|
201
227
|
"""
|
|
202
228
|
session_services = sp.get(
|
|
203
|
-
"session_service_config",
|
|
229
|
+
"session_service_config",
|
|
230
|
+
{},
|
|
231
|
+
scope="umo",
|
|
232
|
+
scope_id=session_id,
|
|
204
233
|
)
|
|
205
234
|
return session_services.get("custom_name")
|
|
206
235
|
|
|
@@ -211,6 +240,7 @@ class SessionServiceManager:
|
|
|
211
240
|
Args:
|
|
212
241
|
session_id: 会话ID (unified_msg_origin)
|
|
213
242
|
custom_name: 自定义名称,可以为空字符串来清除名称
|
|
243
|
+
|
|
214
244
|
"""
|
|
215
245
|
session_config = (
|
|
216
246
|
sp.get("session_service_config", {}, scope="umo", scope_id=session_id) or {}
|
|
@@ -221,11 +251,14 @@ class SessionServiceManager:
|
|
|
221
251
|
# 如果传入空名称,则删除自定义名称
|
|
222
252
|
session_config.pop("custom_name", None)
|
|
223
253
|
sp.put(
|
|
224
|
-
"session_service_config",
|
|
254
|
+
"session_service_config",
|
|
255
|
+
session_config,
|
|
256
|
+
scope="umo",
|
|
257
|
+
scope_id=session_id,
|
|
225
258
|
)
|
|
226
259
|
|
|
227
260
|
logger.info(
|
|
228
|
-
f"会话 {session_id} 的自定义名称已更新为: {custom_name.strip() if custom_name and custom_name.strip() else '已清除'}"
|
|
261
|
+
f"会话 {session_id} 的自定义名称已更新为: {custom_name.strip() if custom_name and custom_name.strip() else '已清除'}",
|
|
229
262
|
)
|
|
230
263
|
|
|
231
264
|
@staticmethod
|
|
@@ -237,6 +270,7 @@ class SessionServiceManager:
|
|
|
237
270
|
|
|
238
271
|
Returns:
|
|
239
272
|
str: 显示名称
|
|
273
|
+
|
|
240
274
|
"""
|
|
241
275
|
custom_name = SessionServiceManager.get_session_custom_name(session_id)
|
|
242
276
|
if custom_name:
|