From 1a7e8456abc018eb650df4841ba881e08ed3c747 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Fri, 16 Jan 2026 17:57:49 +0800 Subject: [PATCH 01/12] chore: update readme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added '自动压缩对话' feature and updated features list. --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7e451c910..2c3e9767b 100644 --- a/README.md +++ b/README.md @@ -41,12 +41,14 @@ AstrBot 是一个开源的一站式 Agent 聊天机器人平台,可接入主 ## 主要功能 1. 💯 免费 & 开源。 -1. ✨ AI 大模型对话,多模态,Agent,MCP,知识库,人格设定。 +1. ✨ AI 大模型对话,多模态,Agent,MCP,知识库,人格设定,自动压缩对话。 2. 🤖 支持接入 Dify、阿里云百炼、Coze 等智能体平台。 2. 🌐 多平台,支持 QQ、企业微信、飞书、钉钉、微信公众号、Telegram、Slack 以及[更多](#支持的消息平台)。 3. 📦 插件扩展,已有近 800 个插件可一键安装。 -5. 💻 WebUI 支持。 -6. 🌐 国际化(i18n)支持。 +5. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html) 隔离化环境,安全地执行任何代码、调用 Shell、会话级资源复用。 +6. 💻 WebUI 支持。 +7. 🌈 Web ChatUI 支持,ChatUI 内置代理沙盒、网页搜索等。 +8. 🌐 国际化(i18n)支持。 ## 快速开始 From 844773a73590ae8741ff5bfaf1c641c619edc044 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Sat, 17 Jan 2026 17:57:11 +0800 Subject: [PATCH 02/12] feat: skip saving head system messages in history (#4538) * feat: skip saving the first system message in history * fix: rename variable for clarity in system message handling * fix: update logic to skip all system messages until the first non-system message --- .../process_stage/method/agent_sub_stages/internal.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 43d88c5ad..6d43a78ec 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 @@ -414,10 +414,11 @@ class InternalAgentSubStage(Stage): # using agent context messages to save to history message_to_save = [] + skipped_initial_system = False for message in all_messages: - if message.role == "system": - # we do not save system messages to history - continue + if message.role == "system" and not skipped_initial_system: + continue # skip all system messages until the first non-system message + skipped_initial_system = True if message.role in ["assistant", "user"] and getattr( message, "_no_save", None ): From 73fca5d1a2d7353e2fa05daf909a28febff3a429 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sat, 17 Jan 2026 18:02:31 +0800 Subject: [PATCH 03/12] fix: clarify logic for skipping initial system messages in conversation --- .../process_stage/method/agent_sub_stages/internal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6d43a78ec..b571f2ba5 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 @@ -417,8 +417,8 @@ class InternalAgentSubStage(Stage): skipped_initial_system = False for message in all_messages: if message.role == "system" and not skipped_initial_system: - continue # skip all system messages until the first non-system message - skipped_initial_system = True + skipped_initial_system = True + continue # skip first system message if message.role in ["assistant", "user"] and getattr( message, "_no_save", None ): From 776c9ebfdd1a86f11e1a1e9bfc316d4f03a8f30b Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sat, 17 Jan 2026 18:07:54 +0800 Subject: [PATCH 04/12] chore: bump version to 4.12.2 --- astrbot/cli/__init__.py | 2 +- astrbot/core/config/default.py | 2 +- changelogs/v4.12.2.md | 6 ++++++ pyproject.toml | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 changelogs/v4.12.2.md diff --git a/astrbot/cli/__init__.py b/astrbot/cli/__init__.py index 33111828c..b92125204 100644 --- a/astrbot/cli/__init__.py +++ b/astrbot/cli/__init__.py @@ -1 +1 @@ -__version__ = "4.12.1" +__version__ = "4.12.2" diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 510b162a7..cfd177243 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -5,7 +5,7 @@ from typing import Any, TypedDict from astrbot.core.utils.astrbot_path import get_astrbot_data_path -VERSION = "4.12.1" +VERSION = "4.12.2" DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db") WEBHOOK_SUPPORTED_PLATFORMS = [ diff --git a/changelogs/v4.12.2.md b/changelogs/v4.12.2.md new file mode 100644 index 000000000..c65215461 --- /dev/null +++ b/changelogs/v4.12.2.md @@ -0,0 +1,6 @@ +## What's Changed + +hotfix of v4.12.0 + +fix: 修复会话隔离功能失效的问题。 +fix: 只跳过 AstrBot 预设的位于开头的 System Message,防止一些非预期行为。 diff --git a/pyproject.toml b/pyproject.toml index 1fa8e056c..172ddf5b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "AstrBot" -version = "4.12.1" +version = "4.12.2" description = "Easy-to-use multi-platform LLM chatbot and development framework" readme = "README.md" requires-python = ">=3.10" From 8199c830722f2855b76cb6c13f176adff75c32ca Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sat, 17 Jan 2026 18:12:08 +0800 Subject: [PATCH 05/12] docs: update 4.12.2 changelog --- changelogs/v4.12.2.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/changelogs/v4.12.2.md b/changelogs/v4.12.2.md index c65215461..702ef3eb1 100644 --- a/changelogs/v4.12.2.md +++ b/changelogs/v4.12.2.md @@ -1,6 +1,6 @@ ## What's Changed -hotfix of v4.12.0 - -fix: 修复会话隔离功能失效的问题。 -fix: 只跳过 AstrBot 预设的位于开头的 System Message,防止一些非预期行为。 +- fix: 只跳过 AstrBot 预设的位于开头的 System Message,防止一些非预期行为。 +- feat: 优化 ChatUI 默认的 System Message +- feat: 新增 tool 调用时 `on_using_llm_tool`、tool 调用后 `on_llm_tool_respond` 的事件钩子。 +- feat: 优化 ChatUI 对 Tavily 网页搜索工具的渲染,支持内联搜索引用、引用网页。 From 317b6fa475168c3901416528fe2840ae981e8d2f Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sat, 17 Jan 2026 19:09:49 +0800 Subject: [PATCH 06/12] refactor: update event types for LLM tool usage and response --- astrbot/core/astr_agent_hooks.py | 4 ++-- astrbot/core/star/register/star_handler.py | 4 ++-- astrbot/core/star/star_handler.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/astrbot/core/astr_agent_hooks.py b/astrbot/core/astr_agent_hooks.py index 64523383f..fa0bb02a9 100644 --- a/astrbot/core/astr_agent_hooks.py +++ b/astrbot/core/astr_agent_hooks.py @@ -34,7 +34,7 @@ class MainAgentHooks(BaseAgentRunHooks[AstrAgentContext]): ): await call_event_hook( run_context.context.event, - EventType.OnCallingFuncToolEvent, + EventType.OnUsingLLMToolEvent, tool, tool_args, ) @@ -49,7 +49,7 @@ class MainAgentHooks(BaseAgentRunHooks[AstrAgentContext]): run_context.context.event.clear_result() await call_event_hook( run_context.context.event, - EventType.OnAfterCallingFuncToolEvent, + EventType.OnLLMToolRespondEvent, tool, tool_args, tool_result, diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index a2644feef..779144b40 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -427,7 +427,7 @@ def register_on_using_llm_tool(**kwargs): """ def decorator(awaitable): - _ = get_handler_or_create(awaitable, EventType.OnCallingFuncToolEvent, **kwargs) + _ = get_handler_or_create(awaitable, EventType.OnUsingLLMToolEvent, **kwargs) return awaitable return decorator @@ -453,7 +453,7 @@ def register_on_llm_tool_respond(**kwargs): def decorator(awaitable): _ = get_handler_or_create( - awaitable, EventType.OnAfterCallingFuncToolEvent, **kwargs + awaitable, EventType.OnLLMToolRespondEvent, **kwargs ) return awaitable diff --git a/astrbot/core/star/star_handler.py b/astrbot/core/star/star_handler.py index 7b2e9f4bf..6f5ce6090 100644 --- a/astrbot/core/star/star_handler.py +++ b/astrbot/core/star/star_handler.py @@ -189,7 +189,8 @@ class EventType(enum.Enum): OnLLMResponseEvent = enum.auto() # LLM 响应后 OnDecoratingResultEvent = enum.auto() # 发送消息前 OnCallingFuncToolEvent = enum.auto() # 调用函数工具 - OnAfterCallingFuncToolEvent = enum.auto() # 调用函数工具后 + OnUsingLLMToolEvent = enum.auto() # 使用 LLM 工具 + OnLLMToolRespondEvent = enum.auto() # 调用函数工具后 OnAfterMessageSentEvent = enum.auto() # 发送消息后 From 5f54becbe27d8b6039c7b7297f17d6f18d6fce1c Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sat, 17 Jan 2026 19:11:05 +0800 Subject: [PATCH 07/12] chore: bump version to 4.12.3 --- astrbot/cli/__init__.py | 2 +- astrbot/core/config/default.py | 2 +- changelogs/v4.12.3.md | 12 ++++++++++++ pyproject.toml | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 changelogs/v4.12.3.md diff --git a/astrbot/cli/__init__.py b/astrbot/cli/__init__.py index b92125204..c1e7d6e85 100644 --- a/astrbot/cli/__init__.py +++ b/astrbot/cli/__init__.py @@ -1 +1 @@ -__version__ = "4.12.2" +__version__ = "4.12.3" diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index cfd177243..fa370a4d8 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -5,7 +5,7 @@ from typing import Any, TypedDict from astrbot.core.utils.astrbot_path import get_astrbot_data_path -VERSION = "4.12.2" +VERSION = "4.12.3" DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db") WEBHOOK_SUPPORTED_PLATFORMS = [ diff --git a/changelogs/v4.12.3.md b/changelogs/v4.12.3.md new file mode 100644 index 000000000..255b1e3d9 --- /dev/null +++ b/changelogs/v4.12.3.md @@ -0,0 +1,12 @@ +## What's Changed + +- fix: 只跳过 AstrBot 预设的位于开头的 System Message,防止一些非预期行为。 +- feat: 优化 ChatUI 默认的 System Message +- feat: 新增 tool 调用时 `on_using_llm_tool`、tool 调用后 `on_llm_tool_respond` 的事件钩子。 +- feat: 优化 ChatUI 对 Tavily 网页搜索工具的渲染,支持内联搜索引用、引用网页。 + + +hotfix of 4.12.2 + +- fix: tool call error in some cases + diff --git a/pyproject.toml b/pyproject.toml index 172ddf5b9..8a430c259 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "AstrBot" -version = "4.12.2" +version = "4.12.3" description = "Easy-to-use multi-platform LLM chatbot and development framework" readme = "README.md" requires-python = ">=3.10" From cb3825bb00827dd764f6cd8f8048130446c31eb6 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Sun, 18 Jan 2026 17:09:25 +0800 Subject: [PATCH 08/12] fix: ensure embedding dimensions are returned as integers in providers (#4547) * fix: ensure embedding dimensions are returned as integers in providers * chore: ruff format --- astrbot/core/provider/sources/gemini_embedding_source.py | 2 +- astrbot/core/provider/sources/openai_embedding_source.py | 2 +- astrbot/core/star/register/star_handler.py | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/astrbot/core/provider/sources/gemini_embedding_source.py b/astrbot/core/provider/sources/gemini_embedding_source.py index 146b50a4e..01046bebb 100644 --- a/astrbot/core/provider/sources/gemini_embedding_source.py +++ b/astrbot/core/provider/sources/gemini_embedding_source.py @@ -68,4 +68,4 @@ class GeminiEmbeddingProvider(EmbeddingProvider): def get_dim(self) -> int: """获取向量的维度""" - return self.provider_config.get("embedding_dimensions", 768) + return int(self.provider_config.get("embedding_dimensions", 768)) diff --git a/astrbot/core/provider/sources/openai_embedding_source.py b/astrbot/core/provider/sources/openai_embedding_source.py index c9e03d7af..ad20dd3df 100644 --- a/astrbot/core/provider/sources/openai_embedding_source.py +++ b/astrbot/core/provider/sources/openai_embedding_source.py @@ -37,4 +37,4 @@ class OpenAIEmbeddingProvider(EmbeddingProvider): def get_dim(self) -> int: """获取向量的维度""" - return self.provider_config.get("embedding_dimensions", 1024) + return int(self.provider_config.get("embedding_dimensions", 1024)) diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index 779144b40..eefbcedb7 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -452,9 +452,7 @@ def register_on_llm_tool_respond(**kwargs): """ def decorator(awaitable): - _ = get_handler_or_create( - awaitable, EventType.OnLLMToolRespondEvent, **kwargs - ) + _ = get_handler_or_create(awaitable, EventType.OnLLMToolRespondEvent, **kwargs) return awaitable return decorator From 978d9cbb6abd439b1c46249b20e7150f136b45d3 Mon Sep 17 00:00:00 2001 From: Anima-IGCenter Date: Tue, 20 Jan 2026 10:23:37 +0800 Subject: [PATCH 09/12] perf: T2I template editor preview (#4574) --- .../components/shared/T2ITemplateEditor.vue | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/dashboard/src/components/shared/T2ITemplateEditor.vue b/dashboard/src/components/shared/T2ITemplateEditor.vue index d9e9e9ee4..feb0b50e1 100644 --- a/dashboard/src/components/shared/T2ITemplateEditor.vue +++ b/dashboard/src/components/shared/T2ITemplateEditor.vue @@ -283,15 +283,29 @@ const editorOptions = { } // --- 预览逻辑 --- -const previewData = { - text: '这是一个示例文本,用于预览模板效果。\n\n这里可以包含多行文本,支持换行和各种格式。', - version: 'v4.0.0' +const previewVersion = ref('v4.0.0') +const syncPreviewVersion = async () => { + try { + const res = await axios.get('/api/stat/version') + const rawVersion = res?.data?.data?.version || res?.data?.version + if (rawVersion) { + previewVersion.value = rawVersion.startsWith('v') ? rawVersion : `v${rawVersion}` + } + } catch (error) { + console.warn('Failed to fetch version:', error) + } } + +const previewData = computed(() => ({ + text: tm('t2iTemplateEditor.previewText') || '这是一个示例文本,用于预览模板效果。\n\n这里可以包含多行文本,支持换行和各种格式。', + version: previewVersion.value +})) + const previewContent = computed(() => { try { let content = templateContent.value - content = content.replace(/\{\{\s*text\s*\|\s*safe\s*\}\}/g, previewData.text) - content = content.replace(/\{\{\s*version\s*\}\}/g, previewData.version) + content = content.replace(/\{\{\s*text\s*\|\s*safe\s*\}\}/g, previewData.value.text) + content = content.replace(/\{\{\s*version\s*\}\}/g, previewData.value.version) return content } catch (error) { return `
模板渲染错误: ${error.message}
` @@ -299,7 +313,6 @@ const previewContent = computed(() => { }) // --- API 调用方法 --- - const loadInitialData = async () => { loading.value = true try { @@ -396,7 +409,7 @@ const confirmDelete = async () => { const nameToDelete = selectedTemplate.value await axios.delete(`/api/t2i/templates/${nameToDelete}`) deleteDialog.value = false - + // 如果删除的是当前活动模板,则将活动模板重置为base if (activeTemplate.value === nameToDelete) { await setActiveTemplate('base') @@ -475,6 +488,7 @@ const confirmApplyAndClose = async () => { const refreshPreview = () => { previewLoading.value = true + syncPreviewVersion() nextTick(() => { if (previewFrame.value) { previewFrame.value.contentWindow.location.reload() @@ -491,6 +505,7 @@ const closeDialog = () => { watch(dialog, (newVal) => { if (newVal) { + syncPreviewVersion() loadInitialData() } else { // 关闭时重置状态 From 02909c62abed8550504960b3f11487b825b36f7e Mon Sep 17 00:00:00 2001 From: Clhikari Date: Wed, 21 Jan 2026 12:37:18 +0800 Subject: [PATCH 10/12] feat: add file drag upload feature for ChatUI (#4583) * feat(chat): add drag-drop upload and fix batch file upload * style(chat): adjust drop overlay to only cover input container --- dashboard/src/components/chat/Chat.vue | 45 +++++----- dashboard/src/components/chat/ChatInput.vue | 89 ++++++++++++++++++- .../src/i18n/locales/en-US/features/chat.json | 3 +- .../src/i18n/locales/zh-CN/features/chat.json | 3 +- 4 files changed, 115 insertions(+), 25 deletions(-) diff --git a/dashboard/src/components/chat/Chat.vue b/dashboard/src/components/chat/Chat.vue index a2c85b946..9b869636d 100644 --- a/dashboard/src/components/chat/Chat.vue +++ b/dashboard/src/components/chat/Chat.vue @@ -3,7 +3,7 @@
- +
- - @@ -301,7 +301,7 @@ const prompt = ref(''); const projectDialog = ref(false); const editingProject = ref(null); const projectSessions = ref([]); -const currentProject = computed(() => +const currentProject = computed(() => projects.value.find(p => p.project_id === selectedProjectId.value) ); @@ -352,7 +352,7 @@ function openImagePreview(imageUrl: string) { async function handleSaveTitle() { await saveTitle(); - + // 如果在项目视图中,刷新项目会话列表 if (selectedProjectId.value) { const sessions = await getProjectSessions(selectedProjectId.value); @@ -367,7 +367,7 @@ function handleReplyMessage(msg: any, index: number) { console.warn('Message does not have an id'); return; } - + // 获取消息内容用于显示 let messageContent = ''; if (typeof msg.content.message === 'string') { @@ -379,12 +379,12 @@ function handleReplyMessage(msg: any, index: number) { .map((part: any) => part.text); messageContent = textParts.join(''); } - + // 截断过长的内容 if (messageContent.length > 100) { messageContent = messageContent.substring(0, 100) + '...'; } - + replyTo.value = { messageId, selectedText: messageContent || '[媒体内容]' @@ -398,12 +398,12 @@ function clearReply() { function handleReplyWithText(replyData: any) { // 处理选中文本的引用 const { messageId, selectedText, messageIndex } = replyData; - + if (!messageId) { console.warn('Message does not have an id'); return; } - + replyTo.value = { messageId, selectedText: selectedText // 保存原始的选中文本 @@ -449,16 +449,16 @@ async function handleSelectConversation(sessionIds: string[]) { // 清除引用状态 clearReply(); - + // 开始加载消息 isLoadingMessages.value = true; - + try { await getSessionMsg(sessionIds[0]); } finally { isLoadingMessages.value = false; } - + nextTick(() => { messageList.value?.scrollToBottom(); }); @@ -476,7 +476,7 @@ function handleNewChat() { async function handleDeleteConversation(sessionId: string) { await deleteSessionFn(sessionId); messages.value = []; - + // 如果在项目视图中,刷新项目会话列表 if (selectedProjectId.value) { const sessions = await getProjectSessions(selectedProjectId.value); @@ -489,11 +489,11 @@ async function handleSelectProject(projectId: string) { const sessions = await getProjectSessions(projectId); projectSessions.value = sessions; messages.value = []; - + // 清空当前会话ID,准备在项目中创建新对话 currSessionId.value = ''; selectedSessions.value = []; - + // 手机端关闭侧边栏 if (isMobile.value) { closeMobileSidebar(); @@ -542,7 +542,10 @@ async function handleStopRecording() { async function handleFileSelect(files: FileList) { const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; - for (const file of files) { + // 将 FileList 转换为数组,避免异步处理时 FileList 被清空 + const fileArray = Array.from(files); + for (let i = 0; i < fileArray.length; i++) { + const file = fileArray[i]; if (imageTypes.includes(file.type)) { await processAndUploadImage(file); } else { @@ -559,10 +562,10 @@ async function handleSendMessage() { const isCreatingNewSession = !currSessionId.value; const currentProjectId = selectedProjectId.value; // 保存当前项目ID - + if (isCreatingNewSession) { await newSession(); - + // 如果在项目视图中创建新会话,立即退出项目视图 if (currentProjectId) { selectedProjectId.value = null; @@ -821,7 +824,7 @@ onBeforeUnmount(() => { .chat-content-panel { width: 100%; } - + .chat-page-container { padding: 0 !important; } diff --git a/dashboard/src/components/chat/ChatInput.vue b/dashboard/src/components/chat/ChatInput.vue index b28e1edc1..6436ddae5 100644 --- a/dashboard/src/components/chat/ChatInput.vue +++ b/dashboard/src/components/chat/ChatInput.vue @@ -1,5 +1,8 @@