From cef0c22f52a2e80694432e09ae8f77c815d666e2 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 2 Oct 2025 14:20:52 +0800 Subject: [PATCH 1/8] feat: update prompt prefix handling to support placeholder replacement --- astrbot/core/config/default.py | 6 ++++-- packages/astrbot/process_llm_request.py | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index e1b25a92..3b6be866 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -64,7 +64,7 @@ DEFAULT_CONFIG = { "datetime_system_prompt": True, "default_personality": "default", "persona_pool": ["*"], - "prompt_prefix": "", + "prompt_prefix": "{{prompt}}", "max_context_length": -1, "dequeue_context_length": 1, "streaming_response": False, @@ -2118,10 +2118,12 @@ CONFIG_METADATA_3 = { "provider_settings.wake_prefix": { "description": "LLM 聊天额外唤醒前缀 ", "type": "string", + "hint": "例子: 如果唤醒前缀为 `/`, 额外聊天唤醒前缀为 `chat`,则需要 `/chat` 才会触发 LLM 请求。默认为空。", }, "provider_settings.prompt_prefix": { - "description": "额外前缀提示词", + "description": "用户提示词", "type": "string", + "hint": "可使用 {{prompt}} 作为用户输入的占位符。如果不输入占位符则代表添加在用户输入的前面。", }, "provider_tts_settings.dual_output": { "description": "开启 TTS 时同时输出语音和文字内容", diff --git a/packages/astrbot/process_llm_request.py b/packages/astrbot/process_llm_request.py index e1d7ab42..2b785fd4 100644 --- a/packages/astrbot/process_llm_request.py +++ b/packages/astrbot/process_llm_request.py @@ -106,7 +106,11 @@ class ProcessLLMRequest: # prompt prefix if prefix := cfg.get("prompt_prefix"): - req.prompt = prefix + req.prompt + # 支持 {{prompt}} 作为用户输入的占位符 + if "{{prompt}}" in prefix: + req.prompt = prefix.replace("{{prompt}}", req.prompt) + else: + req.prompt = prefix + req.prompt # user identifier if cfg.get("identifier"): From 8bdd748aec2371ce7f70a02a92d50a57fcfd9042 Mon Sep 17 00:00:00 2001 From: kterna <2569244273@qq.com> Date: Thu, 2 Oct 2025 14:36:15 +0800 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E6=B6=88=E6=81=AF=E5=B9=B3=E5=8F=B0=E9=80=82=E9=85=8D?= =?UTF-8?q?=E5=99=A8=E7=9A=84=20logo=20(#2109)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 添加平台适配器 logo 支持 * 优化平台logo注册逻辑,增加缓存机制并支持并行处理 * 去除判断绝对路径 --------- Co-authored-by: Soulter <905617992@qq.com> --- astrbot/core/platform/platform_metadata.py | 2 + astrbot/core/platform/register.py | 3 + astrbot/dashboard/routes/config.py | 90 +++++++++++++++++++++- dashboard/src/views/PlatformPage.vue | 12 ++- 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/astrbot/core/platform/platform_metadata.py b/astrbot/core/platform/platform_metadata.py index 7fb7f9d3..37f8527a 100644 --- a/astrbot/core/platform/platform_metadata.py +++ b/astrbot/core/platform/platform_metadata.py @@ -14,3 +14,5 @@ class PlatformMetadata: """平台的默认配置模板""" adapter_display_name: str = None """显示在 WebUI 配置页中的平台名称,如空则是 name""" + logo_path: str = None + """平台适配器的 logo 文件路径(相对于插件目录)""" diff --git a/astrbot/core/platform/register.py b/astrbot/core/platform/register.py index fa65392a..97c33a43 100644 --- a/astrbot/core/platform/register.py +++ b/astrbot/core/platform/register.py @@ -13,10 +13,12 @@ def register_platform_adapter( desc: str, default_config_tmpl: dict = None, adapter_display_name: str = None, + logo_path: str = None, ): """用于注册平台适配器的带参装饰器。 default_config_tmpl 指定了平台适配器的默认配置模板。用户填写好后将会作为 platform_config 传入你的 Platform 类的实现类。 + logo_path 指定了平台适配器的 logo 文件路径,是相对于插件目录的路径。 """ def decorator(cls): @@ -39,6 +41,7 @@ def register_platform_adapter( description=desc, default_config_tmpl=default_config_tmpl, adapter_display_name=adapter_display_name, + logo_path=logo_path, ) platform_registry.append(pm) platform_cls_map[adapter_name] = cls diff --git a/astrbot/dashboard/routes/config.py b/astrbot/dashboard/routes/config.py index 1cc2319a..bb0b723b 100644 --- a/astrbot/dashboard/routes/config.py +++ b/astrbot/dashboard/routes/config.py @@ -1,6 +1,7 @@ import typing import traceback import os +import inspect from .route import Route, Response, RouteContext from astrbot.core.provider.entities import ProviderType from quart import request @@ -13,10 +14,10 @@ from astrbot.core.config.default import ( from astrbot.core.utils.astrbot_path import get_astrbot_path from astrbot.core.config.astrbot_config import AstrBotConfig from astrbot.core.core_lifecycle import AstrBotCoreLifecycle -from astrbot.core.platform.register import platform_registry +from astrbot.core.platform.register import platform_registry, platform_cls_map from astrbot.core.provider.register import provider_registry from astrbot.core.star.star import star_registry -from astrbot.core import logger +from astrbot.core import logger, file_token_service from astrbot.core.provider import Provider from astrbot.core.provider.provider import RerankProvider import asyncio @@ -149,6 +150,7 @@ class ConfigRoute(Route): super().__init__(context) self.core_lifecycle = core_lifecycle self.config: AstrBotConfig = core_lifecycle.astrbot_config + self._logo_token_cache = {} # 缓存logo token,避免重复注册 self.acm = core_lifecycle.astrbot_config_mgr self.routes = { "/config/abconf/new": ("POST", self.create_abconf), @@ -655,6 +657,78 @@ class ConfigRoute(Route): return Response().error(str(e)).__dict__ return Response().ok(None, "删除成功,已经实时生效~").__dict__ + async def get_llm_tools(self): + """获取函数调用工具。包含了本地加载的以及 MCP 服务的工具""" + tool_mgr = self.core_lifecycle.provider_manager.llm_tools + tools = tool_mgr.get_func_desc_openai_style() + return Response().ok(tools).__dict__ + + async def _register_platform_logo(self, platform, platform_default_tmpl): + """注册平台logo文件并生成访问令牌""" + if not platform.logo_path: + return + + try: + # 检查缓存 + cache_key = f"{platform.name}:{platform.logo_path}" + if cache_key in self._logo_token_cache: + cached_token = self._logo_token_cache[cache_key] + # 确保platform_default_tmpl[platform.name]存在且为字典 + if platform.name not in platform_default_tmpl: + platform_default_tmpl[platform.name] = {} + elif not isinstance(platform_default_tmpl[platform.name], dict): + platform_default_tmpl[platform.name] = {} + platform_default_tmpl[platform.name]["logo_token"] = cached_token + logger.debug(f"Using cached logo token for platform {platform.name}") + return + + # 获取平台适配器类 + platform_cls = platform_cls_map.get(platform.name) + if not platform_cls: + logger.warning(f"Platform class not found for {platform.name}") + return + + # 获取插件目录路径 + module_file = inspect.getfile(platform_cls) + plugin_dir = os.path.dirname(module_file) + + # 解析logo文件路径 + logo_file_path = os.path.join(plugin_dir, platform.logo_path) + + # 检查文件是否存在并注册令牌 + if os.path.exists(logo_file_path): + logo_token = await file_token_service.register_file( + logo_file_path, timeout=3600 + ) + + # 确保platform_default_tmpl[platform.name]存在且为字典 + if platform.name not in platform_default_tmpl: + platform_default_tmpl[platform.name] = {} + elif not isinstance(platform_default_tmpl[platform.name], dict): + platform_default_tmpl[platform.name] = {} + + platform_default_tmpl[platform.name]["logo_token"] = logo_token + + # 缓存token + self._logo_token_cache[cache_key] = logo_token + + logger.debug(f"Logo token registered for platform {platform.name}") + else: + logger.warning( + f"Platform {platform.name} logo file not found: {logo_file_path}" + ) + + except (ImportError, AttributeError) as e: + logger.warning( + f"Failed to import required modules for platform {platform.name}: {e}" + ) + except (OSError, IOError) as e: + logger.warning(f"File system error for platform {platform.name} logo: {e}") + except Exception as e: + logger.warning( + f"Unexpected error registering logo for platform {platform.name}: {e}" + ) + async def _get_astrbot_config(self): config = self.config @@ -662,9 +736,21 @@ class ConfigRoute(Route): platform_default_tmpl = CONFIG_METADATA_2["platform_group"]["metadata"][ "platform" ]["config_template"] + + # 收集需要注册logo的平台 + logo_registration_tasks = [] for platform in platform_registry: if platform.default_config_tmpl: platform_default_tmpl[platform.name] = platform.default_config_tmpl + # 收集logo注册任务 + if platform.logo_path: + logo_registration_tasks.append( + self._register_platform_logo(platform, platform_default_tmpl) + ) + + # 并行执行logo注册 + if logo_registration_tasks: + await asyncio.gather(*logo_registration_tasks, return_exceptions=True) # 服务提供商的默认配置模板注入 provider_default_tmpl = CONFIG_METADATA_2["provider_group"]["metadata"][ diff --git a/dashboard/src/views/PlatformPage.vue b/dashboard/src/views/PlatformPage.vue index e135908e..1d14b3ff 100644 --- a/dashboard/src/views/PlatformPage.vue +++ b/dashboard/src/views/PlatformPage.vue @@ -114,7 +114,7 @@ {{ tm('dialog.idConflict.confirm') - }} + }} @@ -241,7 +241,15 @@ export default { methods: { // 从工具函数导入 - getPlatformIcon, + getPlatformIcon(platform_id) { + // 首先检查是否有来自插件的 logo_token + const template = this.metadata['platform_group']?.metadata?.platform?.config_template?.[platform_id]; + if (template && template.logo_token) { + // 通过文件服务访问插件提供的 logo + return `/api/file/${template.logo_token}`; + } + return getPlatformIcon(platform_id); + }, openTutorial() { const tutorialUrl = getTutorialLink(this.newSelectedPlatformConfig.type); From baf5ad0fab16f981461ff30b45165c31152f46ff Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Thu, 2 Oct 2025 16:03:24 +0800 Subject: [PATCH 3/8] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E6=99=BA=E8=B0=B1=E6=8F=90=E4=BE=9B=E5=95=86=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E8=B0=83=E7=94=A8=E6=97=A0=E9=99=90=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E5=B9=B6=E5=81=9C?= =?UTF-8?q?=E6=AD=A2=E6=94=AF=E6=8C=81=20glm-4v-flash=20(#2931)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes: #2912 --- astrbot/core/provider/sources/zhipu_source.py | 70 ++----------------- 1 file changed, 5 insertions(+), 65 deletions(-) diff --git a/astrbot/core/provider/sources/zhipu_source.py b/astrbot/core/provider/sources/zhipu_source.py index cf52e95f..e7b6ee4f 100644 --- a/astrbot/core/provider/sources/zhipu_source.py +++ b/astrbot/core/provider/sources/zhipu_source.py @@ -1,12 +1,12 @@ -from astrbot import logger -from astrbot.core.provider.func_tool_manager import FuncCall -from typing import List +# This file was originally created to adapt to glm-4v-flash, which only supports one image in the context. +# It is no longer specifically adapted to Zhipu's models. To ensure compatibility, this + + from ..register import register_provider_adapter -from astrbot.core.provider.entities import LLMResponse from .openai_source import ProviderOpenAIOfficial -@register_provider_adapter("zhipu_chat_completion", "智浦 Chat Completion 提供商适配器") +@register_provider_adapter("zhipu_chat_completion", "智谱 Chat Completion 提供商适配器") class ProviderZhipu(ProviderOpenAIOfficial): def __init__( self, @@ -19,63 +19,3 @@ class ProviderZhipu(ProviderOpenAIOfficial): provider_settings, default_persona, ) - - async def text_chat( - self, - prompt: str, - session_id: str = None, - image_urls: List[str] = None, - func_tool: FuncCall = None, - contexts=None, - system_prompt=None, - model=None, - **kwargs, - ) -> LLMResponse: - if contexts is None: - contexts = [] - new_record = await self.assemble_context(prompt, image_urls) - context_query = [] - - context_query = [*contexts, new_record] - - model_cfgs: dict = self.provider_config.get("model_config", {}) - model = model or self.get_model() - # glm-4v-flash 只支持一张图片 - if model.lower() == "glm-4v-flash" and image_urls and len(context_query) > 1: - logger.debug("glm-4v-flash 只支持一张图片,将只保留最后一张图片") - logger.debug(context_query) - new_context_query_ = [] - for i in range(0, len(context_query) - 1, 2): - if isinstance(context_query[i].get("content", ""), list): - continue - new_context_query_.append(context_query[i]) - new_context_query_.append(context_query[i + 1]) - new_context_query_.append(context_query[-1]) # 保留最后一条记录 - context_query = new_context_query_ - logger.debug(context_query) - - if system_prompt: - context_query.insert(0, {"role": "system", "content": system_prompt}) - - payloads = {"messages": context_query, **model_cfgs} - try: - llm_response = await self._query(payloads, func_tool) - return llm_response - except Exception as e: - if "maximum context length" in str(e): - retry_cnt = 10 - while retry_cnt > 0: - logger.warning( - f"请求失败:{e}。上下文长度超过限制。尝试弹出最早的记录然后重试。" - ) - try: - self.pop_record(session_id) - llm_response = await self._query(payloads, func_tool) - break - except Exception as e: - if "maximum context length" in str(e): - retry_cnt -= 1 - else: - raise e - else: - raise e From ee08659f0131c336d72113bb9317529644a08fca Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 2 Oct 2025 16:37:54 +0800 Subject: [PATCH 4/8] chore: bump version to 4.3.0 --- astrbot/core/config/default.py | 2 +- changelogs/v4.3.0.md | 14 ++++++++++++++ pyproject.toml | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 changelogs/v4.3.0.md diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 3b6be866..9f6d2339 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -6,7 +6,7 @@ import os from astrbot.core.utils.astrbot_path import get_astrbot_data_path -VERSION = "4.2.1" +VERSION = "4.3.0" DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db") # 默认配置 diff --git a/changelogs/v4.3.0.md b/changelogs/v4.3.0.md new file mode 100644 index 00000000..7f906599 --- /dev/null +++ b/changelogs/v4.3.0.md @@ -0,0 +1,14 @@ +# What's Changed + +1. fix: 修复"开启 TTS 时同时输出语音和文字内容"功能不可用的问题 ([#2900](https://github.com/AstrBotDevs/AstrBot/issues/2900)) +2. feat: 优化了会话管理页的数据查询逻辑,添加分页和搜索功能,大幅度提高响应速度 ([#2906](https://github.com/AstrBotDevs/AstrBot/issues/2906)) +3. fix: 用 mi-googlesearch-python 库代替失效的 googlesearch-python 库 ([#2909](https://github.com/AstrBotDevs/AstrBot/issues/2909)) +4. feat: 支持在 Telegram 和飞书下请求 LLM 前预表态功能 ([#2737](https://github.com/AstrBotDevs/AstrBot/issues/2737)) +5. perf: 对于 Telegram 群聊,将回复机器人的消息视为唤醒机器人 ([#2926](https://github.com/AstrBotDevs/AstrBot/issues/2926)) +6. feat: 提示词前缀配置项升级为“用户提示词”,支持 `{{prompt}}` 作为用户输入的占位符。 +7. fix: 增加知识库插件的启用检查,避免部分情况下导致知识库页面白屏的问题。 +8. fix: 修复接入智谱提供商后,工具调用无限循环的问题,并停止支持 glm-4v-flash ([#2931](https://github.com/AstrBotDevs/AstrBot/issues/2931)) +9. fix: 修复注册指令组指令时的 Pyright 类型检查提示 ([#2923](https://github.com/AstrBotDevs/AstrBot/issues/2923)) +10. refactor: 优化 packages/astrbot 内置插件的代码结构以提高可维护性和可读性 ([#2924](https://github.com/AstrBotDevs/AstrBot/issues/2924)) +11. fix: 修复插件指令注解为联合类型时处理异常的问题 ([#2925](https://github.com/AstrBotDevs/AstrBot/issues/2925)) +12. feat: 支持注册消息平台适配器的 logo ([#2109](https://github.com/AstrBotDevs/AstrBot/issues/2109)) diff --git a/pyproject.toml b/pyproject.toml index 64f0c926..ec4687ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "AstrBot" -version = "4.2.1" +version = "4.3.0" description = "易上手的多平台 LLM 聊天机器人及开发框架" readme = "README.md" requires-python = ">=3.10" From 3007f67cabbcc670a350bd3e54443479b48264d4 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 2 Oct 2025 16:59:11 +0800 Subject: [PATCH 5/8] fix: update Dockerfile to remove npm installation and streamline package setup closes: #2284 --- .gitignore | 4 +++- Dockerfile | 21 ++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 14e6bf8c..8006fef8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,6 @@ packages/python_interpreter/workplace .conda/ .idea pytest.ini -.astrbot \ No newline at end of file +.astrbot + +uv.lock \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0430be00..df48b2be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,6 @@ WORKDIR /AstrBot COPY . /AstrBot/ RUN apt-get update && apt-get install -y --no-install-recommends \ - nodejs \ - npm \ gcc \ build-essential \ python3-dev \ @@ -13,23 +11,20 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ ca-certificates \ bash \ + ffmpeg \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y curl gnupg && \ + curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ + apt-get install -y nodejs && \ + rm -rf /var/lib/apt/lists/* + RUN python -m pip install uv RUN uv pip install -r requirements.txt --no-cache-dir --system -RUN uv pip install socksio uv pyffmpeg pilk --no-cache-dir --system +RUN uv pip install socksio uv pilk --no-cache-dir --system -# 释出 ffmpeg -RUN python -c "from pyffmpeg import FFmpeg; ff = FFmpeg();" - -# add /root/.pyffmpeg/bin/ffmpeg to PATH, inorder to use ffmpeg -RUN echo 'export PATH=$PATH:/root/.pyffmpeg/bin' >> ~/.bashrc - -EXPOSE 6185 +EXPOSE 6185 EXPOSE 6186 CMD [ "python", "main.py" ] - - - From 1b50c5404df047c0df2cfdc5b2fd270ce7686f42 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 2 Oct 2025 17:25:00 +0800 Subject: [PATCH 6/8] fix: enhance knowledge base plugin status check to handle empty data response --- dashboard/src/views/alkaid/KnowledgeBase.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashboard/src/views/alkaid/KnowledgeBase.vue b/dashboard/src/views/alkaid/KnowledgeBase.vue index 89616a21..c9aa3a9d 100644 --- a/dashboard/src/views/alkaid/KnowledgeBase.vue +++ b/dashboard/src/views/alkaid/KnowledgeBase.vue @@ -601,11 +601,11 @@ export default { checkPlugin() { axios.get('/api/plugin/get?name=astrbot_plugin_knowledge_base') .then(response => { - if (response.data.status !== 'ok') { + if (response.data.status !== 'ok' || response.data.data.length === 0) { this.showSnackbar(this.tm('messages.pluginNotAvailable'), 'error'); return } - if (!response.data.data.activated) { + if (!response.data.data[0].activated) { this.showSnackbar(this.tm('messages.pluginNotActivated'), 'error'); return } From 0ad87209e54e435b8e654b114b3e2ab1fcad3736 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 2 Oct 2025 17:25:09 +0800 Subject: [PATCH 7/8] chore: bump version to 4.3.1 --- astrbot/core/config/default.py | 2 +- changelogs/v4.3.1.md | 1 + pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelogs/v4.3.1.md diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 9f6d2339..0e464362 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -6,7 +6,7 @@ import os from astrbot.core.utils.astrbot_path import get_astrbot_data_path -VERSION = "4.3.0" +VERSION = "4.3.1" DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db") # 默认配置 diff --git a/changelogs/v4.3.1.md b/changelogs/v4.3.1.md new file mode 100644 index 00000000..b4b53ef4 --- /dev/null +++ b/changelogs/v4.3.1.md @@ -0,0 +1 @@ +# What's Changed diff --git a/pyproject.toml b/pyproject.toml index ec4687ea..3d5eb3d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "AstrBot" -version = "4.3.0" +version = "4.3.1" description = "易上手的多平台 LLM 聊天机器人及开发框架" readme = "README.md" requires-python = ">=3.10" From d951b997189649c747b809922767ef7cfa47bf91 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Fri, 3 Oct 2025 00:45:07 +0800 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20=E5=8F=91=E9=80=81=E9=98=B6=E6=AE=B5?= =?UTF-8?q?=E5=B0=86=20Plain=20=E4=B8=BA=E7=A9=BA=E7=9A=84=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=AE=B5=E7=A7=BB=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/pipeline/respond/stage.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/astrbot/core/pipeline/respond/stage.py b/astrbot/core/pipeline/respond/stage.py index a674be31..dc6a67e2 100644 --- a/astrbot/core/pipeline/respond/stage.py +++ b/astrbot/core/pipeline/respond/stage.py @@ -190,6 +190,16 @@ class RespondStage(Stage): except Exception as e: logger.warning(f"空内容检查异常: {e}") + # 将 Plain 为空的消息段移除 + result.chain = [ + comp + for comp in result.chain + if not ( + isinstance(comp, Comp.Plain) + and (not comp.text or not comp.text.strip()) + ) + ] + # 发送消息链 # Record 需要强制单独发送 need_separately = {ComponentType.Record}