From a410fa335196d2757760f576b0dbe36888490e15 Mon Sep 17 00:00:00 2001 From: LIghtJUNction Date: Wed, 18 Mar 2026 21:20:11 +0800 Subject: [PATCH] fix: path --- astrbot/core/__init__.py | 24 ++- .../method/agent_sub_stages/internal.py | 7 +- .../discord/discord_platform_adapter.py | 37 +++-- astrbot/core/utils/astrbot_path.py | 137 +++++++++--------- 4 files changed, 109 insertions(+), 96 deletions(-) diff --git a/astrbot/core/__init__.py b/astrbot/core/__init__.py index fdffa73c2..68d978c9a 100644 --- a/astrbot/core/__init__.py +++ b/astrbot/core/__init__.py @@ -23,10 +23,28 @@ from astrbot.core.utils.shared_preferences import SharedPreferences from astrbot.core.utils.t2i.renderer import HtmlRenderer from .log import LogBroker, LogManager -from .utils.astrbot_path import get_astrbot_data_path +from .utils.astrbot_path import ( + get_astrbot_config_path, + get_astrbot_data_path, + get_astrbot_knowledge_base_path, + get_astrbot_plugin_path, + get_astrbot_site_packages_path, + get_astrbot_skills_path, + get_astrbot_temp_path, +) -# 初始化数据存储文件夹 -os.makedirs(get_astrbot_data_path(), exist_ok=True) +# Initialize required data directories eagerly so later agent/tool flows do not +# fail on missing paths when the runtime root resolves to a fresh location. +for required_dir in ( + get_astrbot_data_path(), + get_astrbot_config_path(), + get_astrbot_plugin_path(), + get_astrbot_temp_path(), + get_astrbot_knowledge_base_path(), + get_astrbot_skills_path(), + get_astrbot_site_packages_path(), +): + os.makedirs(required_dir, exist_ok=True) DEMO_MODE = os.getenv("DEMO_MODE", "False").strip().lower() in ("true", "1", "t") diff --git a/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py b/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py index 52fa3e8d4..aab11b402 100644 --- a/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +++ b/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py @@ -29,6 +29,7 @@ from astrbot.core.provider.entities import ( ProviderRequest, ) from astrbot.core.star.star_handler import EventType +from astrbot.core.utils.astrbot_path import get_astrbot_root, get_astrbot_skills_path from astrbot.core.utils.metrics import Metric from astrbot.core.utils.session_lock import session_lock_manager @@ -379,7 +380,11 @@ class InternalAgentSubStage(Stage): unregister_active_runner(event.unified_msg_origin, agent_runner) except Exception as e: - logger.error(f"Error occurred while processing agent: {e}") + logger.exception( + "Error occurred while processing agent. root=%s skills=%s", + get_astrbot_root(), + get_astrbot_skills_path(), + ) custom_error_message = extract_persona_custom_error_message_from_event( event ) diff --git a/astrbot/core/platform/sources/discord/discord_platform_adapter.py b/astrbot/core/platform/sources/discord/discord_platform_adapter.py index 1640e8e40..1a09294e6 100644 --- a/astrbot/core/platform/sources/discord/discord_platform_adapter.py +++ b/astrbot/core/platform/sources/discord/discord_platform_adapter.py @@ -6,6 +6,7 @@ from typing import Any, cast import discord from discord.abc import GuildChannel, Messageable, PrivateChannel from discord.channel import DMChannel +from discord.errors import HTTPException from astrbot import logger from astrbot.api.event import MessageChain @@ -22,7 +23,10 @@ from astrbot.core.platform.astr_message_event import MessageSesion from astrbot.core.star.filter.command import CommandFilter from astrbot.core.star.filter.command_group import CommandGroupFilter from astrbot.core.star.star import star_map -from astrbot.core.star.star_handler import StarHandlerMetadata, star_handlers_registry +from astrbot.core.star.star_handler import ( + StarHandlerMetadata, + star_handlers_registry, +) from .client import DiscordBotClient from .discord_platform_event import DiscordPlatformEvent @@ -336,23 +340,8 @@ class DiscordPlatformAdapter(Platform): logger.info("[Discord] polling_task 已取消。") except Exception as e: logger.warning(f"[Discord] polling_task 取消异常: {e}") - logger.info("[Discord] 正在清理已注册的斜杠指令... (step 2)") - # 清理指令 - if self.enable_command_register and self.client: - try: - await asyncio.wait_for( - self.client.sync_commands( - commands=[], - guild_ids=[self.guild_id] if self.guild_id else None, - ), - timeout=10, - ) - logger.info("[Discord] 指令清理完成。") - except asyncio.TimeoutError: - logger.warning("[Discord] 清理指令超时,跳过。") - except Exception as e: - logger.error(f"[Discord] 清理指令时发生错误: {e}", exc_info=True) - logger.info("[Discord] 正在关闭 Discord 客户端... (step 3)") + logger.info("[Discord] 跳过斜杠指令清理,避免重启时重复创建命令。") + logger.info("[Discord] 正在关闭 Discord 客户端... (step 2)") if self.client and hasattr(self.client, "close"): try: await asyncio.wait_for(self.client.close(), timeout=10) @@ -414,8 +403,16 @@ class DiscordPlatformAdapter(Platform): # 使用 Pycord 的方法同步指令 # 注意:这可能需要一些时间,并且有频率限制 - await self.client.sync_commands() - logger.info("[Discord] 指令同步完成。") + try: + await self.client.sync_commands() + logger.info("[Discord] 指令同步完成。") + except HTTPException as exc: + if getattr(exc, "code", None) == 30034: + logger.warning( + "[Discord] 跳过指令同步:已达到 Discord 每日 application command create 限额。" + ) + return + raise def _create_dynamic_callback(self, cmd_name: str): """为每个指令动态创建一个异步回调函数""" diff --git a/astrbot/core/utils/astrbot_path.py b/astrbot/core/utils/astrbot_path.py index 9f5e711ca..da5b08498 100644 --- a/astrbot/core/utils/astrbot_path.py +++ b/astrbot/core/utils/astrbot_path.py @@ -20,78 +20,6 @@ from pathlib import Path from astrbot.core.utils.runtime_env import is_packaged_desktop_runtime -def get_astrbot_path() -> str: - """获取Astrbot项目路径""" - return os.path.realpath( - os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../"), - ) - - -def get_astrbot_root() -> str: - """获取Astrbot根目录路径""" - if path := os.environ.get("ASTRBOT_ROOT"): - return os.path.realpath(path) - if is_packaged_desktop_runtime(): - return os.path.realpath(os.path.join(os.path.expanduser("~"), ".astrbot")) - - return os.path.realpath(os.getcwd()) - - -def get_astrbot_data_path() -> str: - """获取Astrbot数据目录路径""" - return os.path.realpath(os.path.join(get_astrbot_root(), "data")) - - -def get_astrbot_config_path() -> str: - """获取Astrbot配置文件路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "config")) - - -def get_astrbot_plugin_path() -> str: - """获取Astrbot插件目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "plugins")) - - -def get_astrbot_plugin_data_path() -> str: - """获取Astrbot插件数据目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "plugin_data")) - - -def get_astrbot_t2i_templates_path() -> str: - """获取Astrbot T2I 模板目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "t2i_templates")) - - -def get_astrbot_webchat_path() -> str: - """获取Astrbot WebChat 数据目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "webchat")) - - -def get_astrbot_temp_path() -> str: - """获取Astrbot临时文件目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "temp")) - - -def get_astrbot_skills_path() -> str: - """获取Astrbot Skills 目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "skills")) - - -def get_astrbot_site_packages_path() -> str: - """获取Astrbot第三方依赖目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "site-packages")) - - -def get_astrbot_knowledge_base_path() -> str: - """获取Astrbot知识库根目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "knowledge_base")) - - -def get_astrbot_backups_path() -> str: - """获取Astrbot备份目录路径""" - return os.path.realpath(os.path.join(get_astrbot_data_path(), "backups")) - - class AstrbotPaths: """Astrbot 项目路径管理类""" @@ -156,3 +84,68 @@ class AstrbotPaths: astrbot_paths = AstrbotPaths() + + +def get_astrbot_path() -> str: + """获取Astrbot项目路径""" + return str(astrbot_paths.project_root) + + +def get_astrbot_root() -> str: + """获取Astrbot根目录路径""" + return str(astrbot_paths.root) + + +def get_astrbot_data_path() -> str: + """获取Astrbot数据目录路径""" + return os.path.realpath(os.path.join(get_astrbot_root(), "data")) + + +def get_astrbot_config_path() -> str: + """获取Astrbot配置文件路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "config")) + + +def get_astrbot_plugin_path() -> str: + """获取Astrbot插件目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "plugins")) + + +def get_astrbot_plugin_data_path() -> str: + """获取Astrbot插件数据目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "plugin_data")) + + +def get_astrbot_t2i_templates_path() -> str: + """获取Astrbot T2I 模板目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "t2i_templates")) + + +def get_astrbot_webchat_path() -> str: + """获取Astrbot WebChat 数据目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "webchat")) + + +def get_astrbot_temp_path() -> str: + """获取Astrbot临时文件目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "temp")) + + +def get_astrbot_skills_path() -> str: + """获取Astrbot Skills 目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "skills")) + + +def get_astrbot_site_packages_path() -> str: + """获取Astrbot第三方依赖目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "site-packages")) + + +def get_astrbot_knowledge_base_path() -> str: + """获取Astrbot知识库根目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "knowledge_base")) + + +def get_astrbot_backups_path() -> str: + """获取Astrbot备份目录路径""" + return os.path.realpath(os.path.join(get_astrbot_data_path(), "backups"))