Compare commits

..

18 Commits

Author SHA1 Message Date
Soulter d1759ca2ed docs: revise description for AstrBot in README.md 2026-02-05 13:35:49 +08:00
Soulter 912e40e7f0 chore: delete unused file 2026-02-05 10:40:53 +08:00
Xican 2876c43387 fix: 修复特定提供商导致的定时任务执行失败的问题 (#4872)
* fix: 修复特定提供商导致的定时任务执行失败的问题

* ruff format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-05 10:14:31 +08:00
Soulter 464882f206 chore: bump version to 4.14.4 2026-02-04 23:21:08 +08:00
Soulter 6736fb85c2 fix: conversation token usage calculate wrongly and fix tool call infinitely (#4869) 2026-02-04 23:18:32 +08:00
Soulter 1f75255950 chore: bump version to 4.14.3 2026-02-04 20:31:19 +08:00
Soulter a954e75547 fix: add apply_reset parameter to build_main_agent and handle coroutine reset in InternalAgentSubStage 2026-02-04 20:25:31 +08:00
advent259141 d2b9997620 chore: bump version to 4.14.2 2026-02-04 17:42:41 +08:00
Gao Jinzhe 36432c4361 fix: 修复插件热重载时平台适配器未清理导致注册冲突的问题 (#4859) 2026-02-04 15:06:03 +08:00
圣达生物多 36f0d1f0f9 feat: add debug hint to console page and localization files (#4852) 2026-02-04 15:02:15 +08:00
Anima-IGCenter f65b268bb2 chore: create robots.txt (#4847) 2026-02-04 15:00:08 +08:00
Raven95676 fe06dfcca3 fix: update ruff version to 0.15.0 and add ASYNC240 to ignore list 2026-02-04 11:45:59 +08:00
Soulter bc9043bc3f fix: update ruff exclude list to include tests directory 2026-02-04 10:08:48 +08:00
Soulter 430694aae9 chore: update readme 2026-02-04 10:05:35 +08:00
Soulter c643e3c093 chore: ruff format 2026-02-03 23:40:23 +08:00
Soulter ff46eef3b2 chore: bump version to 4.14.1 2026-02-03 23:35:21 +08:00
Soulter a0c364aa81 fix: active reply function does not work caused by event.request_llm() outdated 2026-02-03 23:34:42 +08:00
Anima-IGCenter 0e0f923a49 chore(seo): prevent indexing with noindex, nofollow (#4844) 2026-02-03 23:19:25 +08:00
24 changed files with 148 additions and 40 deletions
-18
View File
@@ -1,18 +0,0 @@
我需要让 Agent 能够在未来提醒自己去做某些事情,这样 Agent 能够主动地去完成一些任务,而不是等用户主动来下达命令。
你需要实现一个 CronJob 系统,允许 Agent 创建未来任务,并且在未来的某个时间点自动触发这些任务的执行.
CronJob 系统分为 BasicCronJob 和 ActiveAgentCronJob 两种类型。前者只是简单的提供一个定时任务功能(给插件用),而后者则允许 Agent 主动地去完成一些任务。BasicCronJob 不必多说,就是定时执行某个函数。对于 ActiveAgentCronJobAgent 应该可以主动管理(比如通过Tool来管理)这些 CronJobs,当添加的时候,Agent 可以给 CronJob 捎一段文字,以说明未来的自己需要做什么事情。比如说,Agent 在听到用户 “每天早上都给我整理一份今日早报” 之后,应该可以创建 Cron Job,并且自己写脚本来完成这个任务,并且注册 cron job。Agent 给未来的自己捎去的信息应该只是呈现为一段文字,这样可以保持设计简约。当触发后, CronJobManager 会调用 MainAgent 的一轮循环,MainAgent 通过上下文知道这是一个定时任务触发的循环,从而执行相应的操作。
此外,我还有一个需求,后台长任务。需要给当前的 FunctionTool 类增加一个属性,is_background_task: bool = False,插件可以通过这个属性来声明这是一个异步任务。这是为了解决一些 Tool 需要长时间运行的问题,比如 Deep Search tool 需要长时间搜索网页内容、Sub Agent 需要长时间运行来完成一个复杂任务。
基于上面的讨论,我觉得,应该:
1. 需要给当前的 FunctionTool 类增加一个属性is_background_task: bool = Falsetool runner 在执行这个 tool 的时候,如果发现是后台任务,就不等待结果返回,而是直接返回一个任务 ID (已经创建成功提示)的结果,tool runner 在后台继续执行这个任务。当任务完成之后,任务的结果回传给 MainAgent(其实就是再执行一次 main agent loop,但是上下文应该是最新的),并且 MainAgent 此时应该有 send_message_to_user 的工具,通过这个工具可以选择是否主动通知用户任务完成的结果。
2. 增加一个 CronJobManager 类,负责管理所有的定时任务。Agent 可以通过调用这个类的方法来创建、删除、修改定时任务。通过 cron expression 来定义触发条件。
3. CronJobManager 除了管理普通的定时任务(比如插件可能有一些自己的定时任务),还有一种特殊的任务类型,就是上面提到的主动型 Agent 任务。用户提需求,MainAgent 选择性地调用 CronJobManager 的方法来创建这些任务,并且在任务触发时,CronJobManager 的回调就是执行 MainAgent 的一轮循环(需要加 send_message_to_user tool),MainAgent 通过上下文知道这是一个定时任务触发的循环,从而执行相应的操作。
4. WebUI 需要增加 Cron Job 管理界面,用户可以在界面上查看、创建、修改、删除定时任务。对于主动型 Agent 任务,用户可以看到任务的描述、触发条件等信息。
5. 除此之外,现在的代码中已经有了 subagent 的管理。WebUI 可以创建 SubAgent,但是还没写完。除了结合上面我说的之外,你还需要将 SubAgent 与 Persona 结合起来——因为 Persona 是一个包含了 tool、skills、name、description 的完整体,所以 SubAgent 应该直接继承 Persona 的定义,而不是单独定义 SubAgent。SubAgent 本质上就是一个有特定角色和能力的 Persona!多么美妙的设计啊!
6. 为了实现大一统,is_background_task = True 的时候,后台任务也挂到 CronJobManager 上去管理,只不过这个是立即触发的任务,不需要等到未来某个时间点才触发罢了。
我希望设计尽可能简单,但是强大。
+3 -5
View File
@@ -34,7 +34,7 @@
<a href="https://github.com/AstrBotDevs/AstrBot/issues">问题提交</a> <a href="https://github.com/AstrBotDevs/AstrBot/issues">问题提交</a>
</div> </div>
AstrBot 是一个开源的一站式 Agentic 个人群聊助手可在 QQ、Telegram、企业微信、飞书、钉钉、Slack、等数十款主流即时通讯软件上部署,此外还内置类似 OpenWebUI 的轻量化 ChatUI,为个人、开发者和团队打造可靠、可扩展的对话式智能基础设施。无论是个人 AI 伙伴、智能客服、自动化助手,还是企业知识库,AstrBot 都能在你的即时通讯软件平台的工作流中快速构建 AI 应用。 AstrBot 是一个易用、高性能的 AI Agentic 个人 / 群聊助手可在 QQ、Telegram、企业微信、飞书、钉钉、Slack、等数十款主流即时通讯软件上部署,此外还内置类似 OpenWebUI 的轻量化 ChatUI,为个人、开发者和团队打造可靠、可扩展的对话式智能基础设施。无论是个人 AI 伙伴、智能客服、自动化助手,还是企业知识库,AstrBot 都能在你的即时通讯软件平台的工作流中快速构建 AI 应用。
![521771166-00782c4c-4437-4d97-aabc-605e3738da5c (1)](https://github.com/user-attachments/assets/61e7b505-f7db-41aa-a75f-4ef8f079b8ba) ![521771166-00782c4c-4437-4d97-aabc-605e3738da5c (1)](https://github.com/user-attachments/assets/61e7b505-f7db-41aa-a75f-4ef8f079b8ba)
@@ -67,8 +67,6 @@ AstrBot 是一个开源的一站式 Agentic 个人和群聊助手,可在 QQ、
</tr> </tr>
</table> </table>
陪伴与能力**从来不应该是**对立面。我们希望创造的是一个既能理解情绪、给予陪伴,也能可靠完成工作的机器人——致敬[ATRI](https://zh.wikipedia.org/zh-cn/ATRI_-My_Dear_Moments-)。
## 快速开始 ## 快速开始
#### Docker 部署(推荐 🥳) #### Docker 部署(推荐 🥳)
@@ -268,6 +266,6 @@ pre-commit install
_私は、高性能ですから!_ _私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/> 陪伴与能力从来不应该是对立面。我们希望创造的是一个既能理解情绪、给予陪伴,也能可靠完成工作的机器人。
</div
-1
View File
@@ -77,7 +77,6 @@ class Main(star.Star):
yield event.request_llm( yield event.request_llm(
prompt=prompt, prompt=prompt,
func_tool_manager=self.context.get_llm_tool_manager(),
session_id=event.session_id, session_id=event.session_id,
conversation=conv, conversation=conv,
) )
@@ -49,7 +49,7 @@ class Main(Star):
if p_settings.get("empty_mention_waiting_need_reply", True): if p_settings.get("empty_mention_waiting_need_reply", True):
try: try:
# 尝试使用 LLM 生成更生动的回复 # 尝试使用 LLM 生成更生动的回复
func_tools_mgr = self.context.get_llm_tool_manager() # func_tools_mgr = self.context.get_llm_tool_manager()
# 获取用户当前的对话信息 # 获取用户当前的对话信息
curr_cid = await self.context.conversation_manager.get_curr_conversation_id( curr_cid = await self.context.conversation_manager.get_curr_conversation_id(
@@ -76,7 +76,6 @@ class Main(Star):
"你友好地询问用户想要聊些什么或者需要什么帮助,回复要符合人设,不要太过机械化。" "你友好地询问用户想要聊些什么或者需要什么帮助,回复要符合人设,不要太过机械化。"
"请注意,你仅需要输出要回复用户的内容,不要输出其他任何东西" "请注意,你仅需要输出要回复用户的内容,不要输出其他任何东西"
), ),
func_tool_manager=func_tools_mgr,
session_id=curr_cid, session_id=curr_cid,
contexts=[], contexts=[],
system_prompt="", system_prompt="",
+1 -1
View File
@@ -1 +1 @@
__version__ = "4.14.0" __version__ = "4.14.4"
@@ -213,6 +213,8 @@ class ToolLoopAgentRunner(BaseAgentRunner[TContext]):
if not llm_response.is_chunk and llm_response.usage: if not llm_response.is_chunk and llm_response.usage:
# only count the token usage of the final response for computation purpose # only count the token usage of the final response for computation purpose
self.stats.token_usage += llm_response.usage self.stats.token_usage += llm_response.usage
if self.req.conversation:
self.req.conversation.token_usage = llm_response.usage.total
break # got final response break # got final response
if not llm_resp_result: if not llm_resp_result:
+12 -2
View File
@@ -7,6 +7,7 @@ import datetime
import json import json
import os import os
import zoneinfo import zoneinfo
from collections.abc import Coroutine
from dataclasses import dataclass, field from dataclasses import dataclass, field
from astrbot.api import sp from astrbot.api import sp
@@ -114,6 +115,7 @@ class MainAgentBuildResult:
agent_runner: AgentRunner agent_runner: AgentRunner
provider_request: ProviderRequest provider_request: ProviderRequest
provider: Provider provider: Provider
reset_coro: Coroutine | None = None
def _select_provider( def _select_provider(
@@ -837,8 +839,12 @@ async def build_main_agent(
config: MainAgentBuildConfig, config: MainAgentBuildConfig,
provider: Provider | None = None, provider: Provider | None = None,
req: ProviderRequest | None = None, req: ProviderRequest | None = None,
apply_reset: bool = True,
) -> MainAgentBuildResult | None: ) -> MainAgentBuildResult | None:
"""构建主对话代理(Main Agent),并且自动 reset。""" """构建主对话代理(Main Agent),并且自动 reset。
If apply_reset is False, will not call reset on the agent runner.
"""
provider = provider or _select_provider(event, plugin_context) provider = provider or _select_provider(event, plugin_context)
if provider is None: if provider is None:
logger.info("未找到任何对话模型(提供商),跳过 LLM 请求处理。") logger.info("未找到任何对话模型(提供商),跳过 LLM 请求处理。")
@@ -955,7 +961,7 @@ async def build_main_agent(
if action_type == "live": if action_type == "live":
req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n" req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n"
await agent_runner.reset( reset_coro = agent_runner.reset(
provider=provider, provider=provider,
request=req, request=req,
run_context=AgentContextWrapper( run_context=AgentContextWrapper(
@@ -973,8 +979,12 @@ async def build_main_agent(
tool_schema_mode=config.tool_schema_mode, tool_schema_mode=config.tool_schema_mode,
) )
if apply_reset:
await reset_coro
return MainAgentBuildResult( return MainAgentBuildResult(
agent_runner=agent_runner, agent_runner=agent_runner,
provider_request=req, provider_request=req,
provider=provider, provider=provider,
reset_coro=reset_coro if not apply_reset else None,
) )
+1 -1
View File
@@ -5,7 +5,7 @@ from typing import Any, TypedDict
from astrbot.core.utils.astrbot_path import get_astrbot_data_path from astrbot.core.utils.astrbot_path import get_astrbot_data_path
VERSION = "4.14.0" VERSION = "4.14.4"
DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db") DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
WEBHOOK_SUPPORTED_PLATFORMS = [ WEBHOOK_SUPPORTED_PLATFORMS = [
+1
View File
@@ -310,6 +310,7 @@ class CronJobManager:
config = MainAgentBuildConfig( config = MainAgentBuildConfig(
tool_call_timeout=3600, tool_call_timeout=3600,
llm_safety_mode=False, llm_safety_mode=False,
streaming_response=False,
) )
req = ProviderRequest() req = ProviderRequest()
conv = await _get_session_conv(event=cron_event, plugin_context=self.ctx) conv = await _get_session_conv(event=cron_event, plugin_context=self.ctx)
@@ -164,6 +164,7 @@ class InternalAgentSubStage(Stage):
event=event, event=event,
plugin_context=self.ctx.plugin_manager.context, plugin_context=self.ctx.plugin_manager.context,
config=build_cfg, config=build_cfg,
apply_reset=False,
) )
if build_result is None: if build_result is None:
@@ -172,6 +173,7 @@ class InternalAgentSubStage(Stage):
agent_runner = build_result.agent_runner agent_runner = build_result.agent_runner
req = build_result.provider_request req = build_result.provider_request
provider = build_result.provider provider = build_result.provider
reset_coro = build_result.reset_coro
api_base = provider.provider_config.get("api_base", "") api_base = provider.provider_config.get("api_base", "")
for host in decoded_blocked: for host in decoded_blocked:
@@ -190,6 +192,10 @@ class InternalAgentSubStage(Stage):
if await call_event_hook(event, EventType.OnLLMRequestEvent, req): if await call_event_hook(event, EventType.OnLLMRequestEvent, req):
return return
# apply reset
if reset_coro:
await reset_coro
action_type = event.get_extra("action_type") action_type = event.get_extra("action_type")
event.trace.record( event.trace.record(
@@ -357,7 +363,8 @@ class InternalAgentSubStage(Stage):
token_usage = None token_usage = None
if runner_stats: if runner_stats:
token_usage = runner_stats.token_usage.total # token_usage = runner_stats.token_usage.total
token_usage = llm_response.usage.total if llm_response.usage else None
await self.conv_manager.update_conversation( await self.conv_manager.update_conversation(
event.unified_msg_origin, event.unified_msg_origin,
+5 -2
View File
@@ -8,6 +8,7 @@ from time import time
from typing import Any from typing import Any
from astrbot import logger from astrbot import logger
from astrbot.core.agent.tool import ToolSet
from astrbot.core.db.po import Conversation from astrbot.core.db.po import Conversation
from astrbot.core.message.components import ( from astrbot.core.message.components import (
At, At,
@@ -355,6 +356,7 @@ class AstrMessageEvent(abc.ABC):
self, self,
prompt: str, prompt: str,
func_tool_manager=None, func_tool_manager=None,
tool_set: ToolSet | None = None,
session_id: str = "", session_id: str = "",
image_urls: list[str] | None = None, image_urls: list[str] | None = None,
contexts: list | None = None, contexts: list | None = None,
@@ -377,7 +379,7 @@ class AstrMessageEvent(abc.ABC):
contexts: 当指定 contexts 将会使用 contexts 作为上下文如果同时传入了 conversation将会忽略 conversation contexts: 当指定 contexts 将会使用 contexts 作为上下文如果同时传入了 conversation将会忽略 conversation
func_tool_manager: 函数工具管理器用于调用函数工具 self.context.get_llm_tool_manager() 获取 func_tool_manager: [Deprecated] 函数工具管理器用于调用函数工具 self.context.get_llm_tool_manager() 获取已过时请使用 tool_set 参数代替
conversation: 可选如果指定将在指定的对话中进行 LLM 请求对话的人格会被用于 LLM 请求并且结果将会被记录到对话中 conversation: 可选如果指定将在指定的对话中进行 LLM 请求对话的人格会被用于 LLM 请求并且结果将会被记录到对话中
@@ -393,7 +395,8 @@ class AstrMessageEvent(abc.ABC):
prompt=prompt, prompt=prompt,
session_id=session_id, session_id=session_id,
image_urls=image_urls, image_urls=image_urls,
func_tool=func_tool_manager, # func_tool=func_tool_manager,
func_tool=tool_set,
contexts=contexts, contexts=contexts,
system_prompt=system_prompt, system_prompt=system_prompt,
conversation=conversation, conversation=conversation,
@@ -21,3 +21,6 @@ class PlatformMetadata:
"""平台是否支持真实流式传输""" """平台是否支持真实流式传输"""
support_proactive_message: bool = True support_proactive_message: bool = True
"""平台是否支持主动消息推送(非用户触发)""" """平台是否支持主动消息推送(非用户触发)"""
module_path: str | None = None
"""注册该适配器的模块路径,用于插件热重载时清理"""
+32
View File
@@ -37,6 +37,9 @@ def register_platform_adapter(
if "id" not in default_config_tmpl: if "id" not in default_config_tmpl:
default_config_tmpl["id"] = adapter_name default_config_tmpl["id"] = adapter_name
# Get the module path of the class being decorated
module_path = cls.__module__
pm = PlatformMetadata( pm = PlatformMetadata(
name=adapter_name, name=adapter_name,
description=desc, description=desc,
@@ -45,6 +48,7 @@ def register_platform_adapter(
adapter_display_name=adapter_display_name, adapter_display_name=adapter_display_name,
logo_path=logo_path, logo_path=logo_path,
support_streaming_message=support_streaming_message, support_streaming_message=support_streaming_message,
module_path=module_path,
) )
platform_registry.append(pm) platform_registry.append(pm)
platform_cls_map[adapter_name] = cls platform_cls_map[adapter_name] = cls
@@ -52,3 +56,31 @@ def register_platform_adapter(
return cls return cls
return decorator return decorator
def unregister_platform_adapters_by_module(module_path_prefix: str) -> list[str]:
"""根据模块路径前缀注销平台适配器。
在插件热重载时调用用于清理该插件注册的所有平台适配器
Args:
module_path_prefix: 模块路径前缀 "data.plugins.my_plugin"
Returns:
被注销的平台适配器名称列表
"""
unregistered = []
to_remove = []
for pm in platform_registry:
if pm.module_path and pm.module_path.startswith(module_path_prefix):
to_remove.append(pm)
unregistered.append(pm.name)
for pm in to_remove:
platform_registry.remove(pm)
if pm.name in platform_cls_map:
del platform_cls_map[pm.name]
logger.debug(f"平台适配器 {pm.name} 已注销 (来自模块 {pm.module_path})")
return unregistered
+13
View File
@@ -15,6 +15,7 @@ import yaml
from astrbot.core import logger, pip_installer, sp from astrbot.core import logger, pip_installer, sp
from astrbot.core.agent.handoff import FunctionTool, HandoffTool from astrbot.core.agent.handoff import FunctionTool, HandoffTool
from astrbot.core.config.astrbot_config import AstrBotConfig from astrbot.core.config.astrbot_config import AstrBotConfig
from astrbot.core.platform.register import unregister_platform_adapters_by_module
from astrbot.core.provider.register import llm_tools from astrbot.core.provider.register import llm_tools
from astrbot.core.utils.astrbot_path import ( from astrbot.core.utils.astrbot_path import (
get_astrbot_config_path, get_astrbot_config_path,
@@ -842,6 +843,18 @@ class PluginManager:
for func_tool in to_remove: for func_tool in to_remove:
llm_tools.func_list.remove(func_tool) llm_tools.func_list.remove(func_tool)
# Unregister platform adapters registered by this plugin
# module_path is like "data.plugins.my_plugin.main", extract prefix like "data.plugins.my_plugin"
module_prefix = ".".join(plugin_module_path.split(".")[:-1])
if module_prefix:
unregistered_adapters = unregister_platform_adapters_by_module(
module_prefix
)
for adapter_name in unregistered_adapters:
logger.info(
f"移除了插件 {plugin_name} 的平台适配器 {adapter_name}",
)
if plugin is None: if plugin is None:
return return
+7
View File
@@ -0,0 +1,7 @@
## What's Changed - BIG AND BEAUTIFUL VERSION
hotfix of v4.14.0
fixes:
- 由 `event.request_llm()` 过时导致的群聊上下文感知-主动回复功能可能不可用的问题
+23
View File
@@ -0,0 +1,23 @@
## What's Changed
### 新增
- 控制台页面新增调试提示和本地化文件 ([#4852](https://github.com/AstrBotDevs/AstrBot/pull/4852))
### 修复
- 修复插件热重载时平台适配器未清理导致注册冲突的问题 ([#4859](https://github.com/AstrBotDevs/AstrBot/pull/4859))
### 其他
- 更新 ruff 版本至 0.15.0
- 新增 robots.txt ([#4847](https://github.com/AstrBotDevs/AstrBot/pull/4847))
## What's Changed (EN)
### New Features
- Add debug hint to console page and localization files ([#4852](https://github.com/AstrBotDevs/AstrBot/pull/4852))
### Bug Fixes
- Fix platform adapter not being cleaned up during plugin hot reload, causing registration conflicts ([#4859](https://github.com/AstrBotDevs/AstrBot/pull/4859))
### Others
- Update ruff version to 0.15.0
- Add robots.txt ([#4847](https://github.com/AstrBotDevs/AstrBot/pull/4847))
+4
View File
@@ -0,0 +1,4 @@
## What's Changed
### 修复
- 修复 `on_llm_request` 钩子可能无法应用效果的问题
+4
View File
@@ -0,0 +1,4 @@
## What's Changed
### 修复
- 修复 token 统计错误的问题,修复在多轮 tool call 情况下或者其他极端情况下可能造成 tool 无限调用的问题。
+1
View File
@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="keywords" content="AstrBot Soulter" /> <meta name="keywords" content="AstrBot Soulter" />
<meta name="description" content="AstrBot Dashboard" /> <meta name="description" content="AstrBot Dashboard" />
<meta name="robots" content="noindex, nofollow" />
<link <link
rel="stylesheet" rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Outfit&family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap" href="https://fonts.googleapis.com/css2?family=Outfit&family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap"
+2
View File
@@ -0,0 +1,2 @@
User-agent: *
Disallow: /
@@ -11,5 +11,8 @@
"mirrorLabel": "Force PyPI repository URL (optional)", "mirrorLabel": "Force PyPI repository URL (optional)",
"mirrorHint": "Force PyPI repository URL > Config item `PyPI Repository Address`", "mirrorHint": "Force PyPI repository URL > Config item `PyPI Repository Address`",
"installButton": "Install" "installButton": "Install"
},
"debugHint": {
"text": "Debug logs can be enabled in \"Configuration File → System → Console Log Level\""
} }
} }
@@ -11,5 +11,8 @@
"mirrorLabel": "强制 PyPI 软件仓库链接(可选)", "mirrorLabel": "强制 PyPI 软件仓库链接(可选)",
"mirrorHint": "强制 PyPI 软件仓库链接 > 配置项 `PyPI 软件仓库地址`", "mirrorHint": "强制 PyPI 软件仓库链接 > 配置项 `PyPI 软件仓库地址`",
"installButton": "安装" "installButton": "安装"
},
"debugHint": {
"text": "Debug 日志需要在「配置文件 → 系统 → 控制台日志级别」中开启"
} }
} }
+13 -2
View File
@@ -10,7 +10,18 @@ const { tm } = useModuleI18n('features/console');
<div style="height: 100%;"> <div style="height: 100%;">
<div <div
style="background-color: var(--v-theme-surface); padding: 8px; padding-left: 16px; border-radius: 8px; margin-bottom: 16px; display: flex; flex-direction: row; align-items: center; justify-content: space-between;"> style="background-color: var(--v-theme-surface); padding: 8px; padding-left: 16px; border-radius: 8px; margin-bottom: 16px; display: flex; flex-direction: row; align-items: center; justify-content: space-between;">
<h4>{{ tm('title') }}</h4> <div>
<h4>{{ tm('title') }}</h4>
<v-alert
type="info"
variant="tonal"
density="compact"
class="mt-2"
style="max-width: 600px;"
>
{{ tm('debugHint.text') }}
</v-alert>
</div>
<div class="d-flex align-center"> <div class="d-flex align-center">
<v-switch <v-switch
v-model="autoScrollEnabled" v-model="autoScrollEnabled"
@@ -111,4 +122,4 @@ export default {
.fade-in { .fade-in {
animation: fadeIn 0.2s ease-in-out; animation: fadeIn 0.2s ease-in-out;
} }
</style> </style>
+4 -3
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "AstrBot" name = "AstrBot"
version = "4.14.0" version = "4.14.4"
description = "Easy-to-use multi-platform LLM chatbot and development framework" description = "Easy-to-use multi-platform LLM chatbot and development framework"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
@@ -69,14 +69,14 @@ dev = [
"pytest>=8.4.1", "pytest>=8.4.1",
"pytest-asyncio>=1.1.0", "pytest-asyncio>=1.1.0",
"pytest-cov>=6.2.1", "pytest-cov>=6.2.1",
"ruff>=0.12.8", "ruff>=0.15.0",
] ]
[project.scripts] [project.scripts]
astrbot = "astrbot.cli.__main__:cli" astrbot = "astrbot.cli.__main__:cli"
[tool.ruff] [tool.ruff]
exclude = ["astrbot/core/utils/t2i/local_strategy.py", "astrbot/api/all.py"] exclude = ["astrbot/core/utils/t2i/local_strategy.py", "astrbot/api/all.py", "tests"]
line-length = 88 line-length = 88
target-version = "py310" target-version = "py310"
@@ -97,6 +97,7 @@ ignore = [
"F405", "F405",
"E501", "E501",
"ASYNC230", # TODO: handle ASYNC230 in AstrBot "ASYNC230", # TODO: handle ASYNC230 in AstrBot
"ASYNC240", # TODO: handle ASYNC240 in AstrBot
] ]
[tool.pyright] [tool.pyright]