From 96e61a4a92832c66fdb9bef636cf496fd2e68f2f Mon Sep 17 00:00:00 2001
From: Soulter <905617992@qq.com>
Date: Tue, 3 Feb 2026 22:08:29 +0800
Subject: [PATCH] chore: bump version to 4.14.0
---
astrbot/cli/__init__.py | 2 +-
astrbot/core/config/default.py | 2 +-
changelogs/v4.14.0.md | 72 +++++
.../src/i18n/locales/en-US/features/cron.json | 1 +
.../src/i18n/locales/zh-CN/features/cron.json | 1 +
.../i18n/locales/zh-CN/features/subagent.json | 4 +-
dashboard/src/views/CronJobPage.vue | 10 +-
pyproject.toml | 2 +-
scripts/generate_changelog.py | 253 ++++++++++++++++++
9 files changed, 341 insertions(+), 6 deletions(-)
create mode 100644 changelogs/v4.14.0.md
create mode 100755 scripts/generate_changelog.py
diff --git a/astrbot/cli/__init__.py b/astrbot/cli/__init__.py
index 13398e442..9c8b8e07d 100644
--- a/astrbot/cli/__init__.py
+++ b/astrbot/cli/__init__.py
@@ -1 +1 @@
-__version__ = "4.13.2"
+__version__ = "4.14.0"
diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py
index f421d2438..774cb97ce 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.13.2"
+VERSION = "4.14.0"
DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
WEBHOOK_SUPPORTED_PLATFORMS = [
diff --git a/changelogs/v4.14.0.md b/changelogs/v4.14.0.md
new file mode 100644
index 000000000..810247b61
--- /dev/null
+++ b/changelogs/v4.14.0.md
@@ -0,0 +1,72 @@
+## What's Changed - BIG AND BEAUTIFUL VERSION
+
+> 如果在之前版本使用了 Skill,这次更新之后**需要重新配置** Skill Runtime 相关选项。
+
+### 新增
+- 🔥 新增未来任务系统(Future Tasks)。给 AstrBot 布置的未来任务,让 AstrBot 能够在某一时刻自动唤醒,帮你完成任务。详见 [主动任务](https://docs.astrbot.app/use/proactive-agent.html) 。(实验性) ([#4697](https://github.com/AstrBotDevs/AstrBot/issues/4831))
+- 🔥 新增子代理(SubAgent)编排器。(实验性)([#4697](https://github.com/AstrBotDevs/AstrBot/issues/4831))
+- 🔥 AstrBot 目前可以直接通过调用 tool 将图片 / 文件推送给用户,大大提高交互效果。
+- 新增 Computer Use 运行时配置,以融合 Skill 和 Sandbox 配置 ([#4831](https://github.com/AstrBotDevs/AstrBot/issues/4831))
+- 新增主题自定义功能,可设置主色与辅色
+- 支持在配置页下人格对话框的编辑人格 ([#4826](https://github.com/AstrBotDevs/AstrBot/issues/4826))
+- 支持开关 “追踪” 功能;支持在系统配置中设置是否将日志写入 log 文件 ([#4822](https://github.com/AstrBotDevs/AstrBot/issues/4822))
+
+### 修复
+- ‼️ 修复 ChatUI 图片、思考等显示异常问题。
+- ‼️ 修复 Skill 上传到 Sandbox 后未自动解压导致 Agent 无法读取的问题。
+- ‼️ 修复配置特定插件集时 MCP 工具被过滤的问题 ([#4825](https://github.com/AstrBotDevs/AstrBot/issues/4825))
+- ‼️ 移除 ChatUI 自带的让 LLM 最后提出问题的 prompt ([#4824](https://github.com/AstrBotDevs/AstrBot/issues/4824))
+- ‼️ 修复 WebUI 在上传 Skill 失败后仍显示成功消息的 bug ([#4768](https://github.com/AstrBotDevs/AstrBot/issues/4768))
+- 修复 MCP 服务器无法重命名的问题 ([#4766](https://github.com/AstrBotDevs/AstrBot/issues/4766))
+- 修复插件的 tool 无法在 WebUI 管理行为中看到来源的问题 ([#4776](https://github.com/AstrBotDevs/AstrBot/issues/4776))
+- ‼️ 修复 skill-like 的 tool 模式下,调用 tool 失败的问题 ([#4775](https://github.com/AstrBotDevs/AstrBot/issues/4775))
+
+### 优化
+
+- WebUI 整体 UI 效果优化
+- 部分 Dialog 标题样式统一
+
+## What's Changed (EN)
+
+### New Features
+- Introduce CronJob system with one-time tasks and enhanced dashboard management
+- Add theme customization with primary & secondary color options
+- Add computer-use runtime config for skills sandbox execution ([#4831](https://github.com/AstrBotDevs/AstrBot/issues/4831))
+- Add edit button to persona selector dialog ([#4826](https://github.com/AstrBotDevs/AstrBot/issues/4826))
+- Add trace logging toggle and configuration UI ([#4822](https://github.com/AstrBotDevs/AstrBot/issues/4822))
+- Add proactive-messaging capability with cron-tool trigger
+- Implement SubAgent orchestrator with configurable tool-management policies
+- Support resolving sandbox file paths and auto-download when necessary
+- Add embedded image & audio styles in MessagePartsRenderer
+- Introduce i18n foundation
+- Persist agent-interaction history
+- Add user notifications for file-download success/removal
+
+### Bug Fixes
+- Improve ghost-plugin detection accuracy
+- Add error handling to prevent ghost-plugin crashes
+- Prevent skills bundle from overwriting existing files
+- Fix skills bundle unzip failure inside sandbox
+- Fix MCP tools being filtered when specific plugin set configured ([#4825](https://github.com/AstrBotDevs/AstrBot/issues/4825))
+- Merge ChatUI persona pop-up into default persona ([#4824](https://github.com/AstrBotDevs/AstrBot/issues/4824))
+- Fix reasoning block style
+- Add missing comma in truncate_and_compress hint
+- Fix frontend still showing success message ([#4768](https://github.com/AstrBotDevs/AstrBot/issues/4768))
+- Fix unable to rename MCP server ([#4766](https://github.com/AstrBotDevs/AstrBot/issues/4766))
+- Remove leftover sandbox runtime handling in skill upload ([#4798](https://github.com/AstrBotDevs/AstrBot/issues/4798))
+- Fix handler module path construction ([#4776](https://github.com/AstrBotDevs/AstrBot/issues/4776))
+- Fix skill-like tool invocation error ([#4775](https://github.com/AstrBotDevs/AstrBot/issues/4775))
+
+### Improvements
+- Runtime hints & refined UI in skills management
+- Performance and UX improvements on cron-job page
+- General WebUI performance boost
+- Group tools by plugin in dropdown
+- Consistent dialog titles with padding and text styles
+- Code formatting unified (ruff format)
+- Bump version to 4.13.2
+
+### Others
+- Remove obsolete reminder code
+- Extract main-agent module for better architecture
+- Merge AstrBot_skill branch changes
\ No newline at end of file
diff --git a/dashboard/src/i18n/locales/en-US/features/cron.json b/dashboard/src/i18n/locales/en-US/features/cron.json
index 5f1565812..fdb20243a 100644
--- a/dashboard/src/i18n/locales/en-US/features/cron.json
+++ b/dashboard/src/i18n/locales/en-US/features/cron.json
@@ -22,6 +22,7 @@
"name": "Name",
"type": "Type",
"cron": "Cron",
+ "session": "Session ID",
"nextRun": "Next Run",
"lastRun": "Last Run",
"note": "Note",
diff --git a/dashboard/src/i18n/locales/zh-CN/features/cron.json b/dashboard/src/i18n/locales/zh-CN/features/cron.json
index 1c73356ac..05df8aa63 100644
--- a/dashboard/src/i18n/locales/zh-CN/features/cron.json
+++ b/dashboard/src/i18n/locales/zh-CN/features/cron.json
@@ -22,6 +22,7 @@
"name": "名称",
"type": "类型",
"cron": "Cron",
+ "session": "会话 ID",
"nextRun": "下一次执行",
"lastRun": "最近执行",
"note": "说明",
diff --git a/dashboard/src/i18n/locales/zh-CN/features/subagent.json b/dashboard/src/i18n/locales/zh-CN/features/subagent.json
index a54a873bd..f9df1d000 100644
--- a/dashboard/src/i18n/locales/zh-CN/features/subagent.json
+++ b/dashboard/src/i18n/locales/zh-CN/features/subagent.json
@@ -35,8 +35,8 @@
"nameHint": "建议使用英文小写+下划线,且全局唯一",
"providerLabel": "Chat Provider(可选)",
"providerHint": "留空表示跟随全局默认 provider。",
- "personaLabel": "选择 Persona",
- "personaHint": "SubAgent 将直接继承所选 Persona 的系统设定与工具。",
+ "personaLabel": "选择人格设定",
+ "personaHint": "SubAgent 将直接继承所选 Persona 的系统设定与工具。在人格设定页管理和新建人格。",
"descriptionLabel": "对主 LLM 的描述(用于决定是否 handoff)",
"descriptionHint": "这段会作为 transfer_to_* 工具的描述给主 LLM 看,建议简短明确。"
},
diff --git a/dashboard/src/views/CronJobPage.vue b/dashboard/src/views/CronJobPage.vue
index 6d04d7721..1bc72b508 100644
--- a/dashboard/src/views/CronJobPage.vue
+++ b/dashboard/src/views/CronJobPage.vue
@@ -48,6 +48,9 @@
{{ item.timezone || tm('table.timezoneLocal') }}
+
+ {{ item.session || tm('table.notAvailable') }}
+
{{ formatTime(item.next_run_time) }}
{{ formatTime(item.last_run_at) }}
{{ item.note || tm('table.notAvailable') }}
@@ -129,6 +132,7 @@ const headers = computed(() => [
{ title: tm('table.headers.name'), key: 'name', minWidth: '200px' },
{ title: tm('table.headers.type'), key: 'type', width: 110 },
{ title: tm('table.headers.cron'), key: 'cron_expression', minWidth: '160px' },
+ { title: tm('table.headers.session'), key: 'session', minWidth: '200px' },
{ title: tm('table.headers.nextRun'), key: 'next_run_time', minWidth: '160px' },
{ title: tm('table.headers.lastRun'), key: 'last_run_at', minWidth: '160px' },
{ title: tm('table.headers.note'), key: 'note', minWidth: '220px' },
@@ -163,7 +167,11 @@ async function loadJobs() {
try {
const res = await axios.get('/api/cron/jobs')
if (res.data.status === 'ok') {
- jobs.value = Array.isArray(res.data.data) ? res.data.data : []
+ const data = Array.isArray(res.data.data) ? res.data.data : []
+ jobs.value = data.map((job: any) => ({
+ ...job,
+ session: job?.payload?.session || job?.session || ''
+ }))
} else {
toast(res.data.message || tm('messages.loadFailed'), 'error')
}
diff --git a/pyproject.toml b/pyproject.toml
index 530bd56cd..97b3b4cf6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "AstrBot"
-version = "4.13.2"
+version = "4.14.0"
description = "Easy-to-use multi-platform LLM chatbot and development framework"
readme = "README.md"
requires-python = ">=3.10"
diff --git a/scripts/generate_changelog.py b/scripts/generate_changelog.py
new file mode 100755
index 000000000..446e0bc56
--- /dev/null
+++ b/scripts/generate_changelog.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python3
+"""
+Auto-generate changelog from git commits using LLM.
+Usage: python scripts/generate_changelog.py [--version VERSION]
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+from pathlib import Path
+
+
+def get_latest_tag():
+ """Get the latest git tag."""
+ result = subprocess.run(
+ ["git", "describe", "--tags", "--abbrev=0"],
+ capture_output=True,
+ text=True,
+ check=True,
+ )
+ return result.stdout.strip()
+
+
+def get_commits_since_tag(tag):
+ """Get all commit messages since the specified tag."""
+ result = subprocess.run(
+ ["git", "log", f"{tag}..HEAD", "--pretty=format:%H|%s|%b"],
+ capture_output=True,
+ text=True,
+ check=True,
+ )
+ commits = []
+ for line in result.stdout.strip().split("\n"):
+ if not line:
+ continue
+ parts = line.split("|", 2)
+ if len(parts) >= 2:
+ commit_hash = parts[0]
+ subject = parts[1]
+ body = parts[2] if len(parts) > 2 else ""
+ commits.append({"hash": commit_hash[:7], "subject": subject, "body": body})
+ return commits
+
+
+def extract_issue_number(text):
+ """Extract issue number from commit message."""
+ # Match #1234 or (#1234)
+ match = re.search(r"#(\d+)", text)
+ return match.group(1) if match else None
+
+
+def call_llm_for_changelog(commits, version):
+ """Call LLM to generate changelog from commits."""
+ try:
+ # Try to use OpenAI API or other LLM providers
+ import openai
+
+ # Build prompt
+ commits_text = "\n".join([f"- {c['subject']}" for c in commits])
+
+ prompt = f"""Based on the following git commit messages, generate a changelog document in BOTH Chinese and English.
+
+Commit messages:
+{commits_text}
+
+Please organize the changes into these categories:
+- 新增 (New Features)
+- 修复 (Bug Fixes)
+- 优化 (Improvements)
+- 其他 (Others)
+
+Format requirements:
+1. Start with Chinese version under "## What's Changed"
+2. Follow with English version under "## What's Changed (EN)"
+3. Use markdown format with proper bullet points
+4. Keep descriptions concise and user-friendly
+5. If a commit mentions an issue number (#1234), include it in the format ([#1234](https://github.com/AstrBotDevs/AstrBot/issues/1234))
+
+Example format:
+## What's Changed
+
+### 新增
+- 支持某某功能 ([#1234](https://github.com/AstrBotDevs/AstrBot/issues/1234))
+
+### 修复
+- 修复某某问题
+
+## What's Changed (EN)
+
+### New Features
+- Add support for something ([#1234](https://github.com/AstrBotDevs/AstrBot/issues/1234))
+
+### Bug Fixes
+- Fix something
+"""
+
+ client = openai.OpenAI(
+ api_key=os.getenv("OPENAI_API_KEY"),
+ base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"),
+ )
+
+ response = client.chat.completions.create(
+ model=os.getenv("OPENAI_MODEL", "gpt-4"),
+ messages=[
+ {
+ "role": "system",
+ "content": "You are a helpful assistant that generates well-structured changelogs.",
+ },
+ {"role": "user", "content": prompt},
+ ],
+ temperature=0.3,
+ )
+
+ return response.choices[0].message.content
+
+ except ImportError:
+ print(
+ "Warning: openai package not installed. Install it with: pip install openai"
+ )
+ return generate_simple_changelog(commits)
+ except Exception as e:
+ print(f"Warning: Failed to call LLM API: {e}")
+ print("Falling back to simple changelog generation...")
+ return generate_simple_changelog(commits)
+
+
+def generate_simple_changelog(commits):
+ """Generate a simple changelog without LLM."""
+ sections = {
+ "feat": ("新增", "New Features", []),
+ "fix": ("修复", "Bug Fixes", []),
+ "perf": ("优化", "Improvements", []),
+ "docs": ("文档", "Documentation", []),
+ "refactor": ("重构", "Refactoring", []),
+ "test": ("测试", "Tests", []),
+ "chore": ("其他", "Chore", []),
+ "other": ("其他", "Others", []),
+ }
+
+ # Categorize commits by conventional commit type
+ for commit in commits:
+ subject = commit["subject"]
+ issue_num = extract_issue_number(subject)
+ issue_link = (
+ f" ([#{issue_num}](https://github.com/AstrBotDevs/AstrBot/issues/{issue_num}))"
+ if issue_num
+ else ""
+ )
+
+ # Detect conventional commit type
+ matched = False
+ for prefix in ["feat", "fix", "perf", "docs", "refactor", "test", "chore"]:
+ if subject.lower().startswith(f"{prefix}:") or subject.lower().startswith(
+ f"{prefix}("
+ ):
+ # Remove prefix for display
+ clean_subject = re.sub(
+ r"^[a-z]+(\([^)]+\))?:\s*", "", subject, flags=re.IGNORECASE
+ )
+ sections[prefix][2].append(f"- {clean_subject}{issue_link}")
+ matched = True
+ break
+
+ if not matched:
+ sections["other"][2].append(f"- {subject}{issue_link}")
+
+ # Build Chinese version
+ changelog_zh = "## What's Changed\n\n"
+ for section_key in ["feat", "fix", "perf", "docs", "refactor", "test", "other"]:
+ zh_title, _, items = sections[section_key]
+ if items:
+ changelog_zh += f"### {zh_title}\n\n"
+ changelog_zh += "\n".join(items) + "\n\n"
+
+ # Build English version
+ changelog_en = "## What's Changed (EN)\n\n"
+ for section_key in ["feat", "fix", "perf", "docs", "refactor", "test", "other"]:
+ _, en_title, items = sections[section_key]
+ if items:
+ changelog_en += f"### {en_title}\n\n"
+ changelog_en += "\n".join(items) + "\n\n"
+
+ return changelog_zh + changelog_en
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Generate changelog from git commits")
+ parser.add_argument(
+ "--version", help="Version number for the changelog (e.g., v4.13.3)"
+ )
+ parser.add_argument(
+ "--use-llm",
+ action="store_true",
+ help="Use LLM to generate changelog (requires OpenAI API key)",
+ )
+ args = parser.parse_args()
+
+ # Get latest tag
+ try:
+ latest_tag = get_latest_tag()
+ print(f"Latest tag: {latest_tag}")
+ except subprocess.CalledProcessError:
+ print("Error: No tags found in repository")
+ sys.exit(1)
+
+ # Get commits since tag
+ commits = get_commits_since_tag(latest_tag)
+ if not commits:
+ print(f"No commits found since {latest_tag}")
+ sys.exit(0)
+
+ print(f"Found {len(commits)} commits since {latest_tag}")
+
+ # Determine version
+ if args.version:
+ version = args.version
+ else:
+ # Auto-increment patch version
+ match = re.match(r"v(\d+)\.(\d+)\.(\d+)", latest_tag)
+ if match:
+ major, minor, patch = map(int, match.groups())
+ version = f"v{major}.{minor}.{patch + 1}"
+ else:
+ print(f"Warning: Could not parse version from tag {latest_tag}")
+ version = "vX.X.X"
+
+ print(f"Generating changelog for {version}...")
+
+ # Generate changelog
+ if args.use_llm:
+ changelog_content = call_llm_for_changelog(commits, version)
+ else:
+ changelog_content = generate_simple_changelog(commits)
+
+ # Save to file
+ changelog_dir = Path(__file__).parent.parent / "changelogs"
+ changelog_dir.mkdir(exist_ok=True)
+ changelog_file = changelog_dir / f"{version}.md"
+
+ with open(changelog_file, "w", encoding="utf-8") as f:
+ f.write(changelog_content)
+
+ print(f"\n✓ Changelog generated: {changelog_file}")
+ print("\nPreview:")
+ print("=" * 80)
+ print(changelog_content)
+ print("=" * 80)
+
+
+if __name__ == "__main__":
+ main()