From a1172c9a8227072700e44c28f358e93dd282618a Mon Sep 17 00:00:00 2001
From: Soulter <905617992@qq.com>
Date: Tue, 11 Mar 2025 23:27:10 +0800
Subject: [PATCH 01/17] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=9B=9E=E5=A4=8D=E6=B6=88=E6=81=AF=20#783?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/message/components.py | 18 ++++++++-
astrbot/core/platform/astr_message_event.py | 8 ++++
.../aiocqhttp/aiocqhttp_platform_adapter.py | 38 ++++++++++++++++++-
3 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/astrbot/core/message/components.py b/astrbot/core/message/components.py
index 44caa2075..389f0088a 100644
--- a/astrbot/core/message/components.py
+++ b/astrbot/core/message/components.py
@@ -311,10 +311,24 @@ class Image(BaseMessageComponent):
class Reply(BaseMessageComponent):
type: ComponentType = "Reply"
id: T.Union[str, int]
- text: T.Optional[str] = ""
- qq: T.Optional[int] = 0
+ """所引用的消息 ID"""
+ chain: T.Optional[T.List["BaseMessageComponent"]] = []
+ """引用的消息段列表"""
+ sender_id: T.Optional[int] | T.Optional[str] = 0
+ """引用的消息发送者 ID"""
+ sender_nickname: T.Optional[str] = ""
+ """引用的消息发送者昵称"""
time: T.Optional[int] = 0
+ """引用的消息发送时间"""
+ message_str: T.Optional[str] = ""
+ """解析后的纯文本消息字符串"""
+
+ text: T.Optional[str] = ""
+ """deprecated"""
+ qq: T.Optional[int] = 0
+ """deprecated"""
seq: T.Optional[int] = 0
+ """deprecated"""
def __init__(self, **_):
super().__init__(**_)
diff --git a/astrbot/core/platform/astr_message_event.py b/astrbot/core/platform/astr_message_event.py
index 72e4414b6..9ae3c99f7 100644
--- a/astrbot/core/platform/astr_message_event.py
+++ b/astrbot/core/platform/astr_message_event.py
@@ -14,6 +14,7 @@ from astrbot.core.message.components import (
At,
AtAll,
Forward,
+ Reply
)
from astrbot.core.utils.metrics import Metric
from astrbot.core.provider.entites import ProviderRequest
@@ -101,8 +102,15 @@ class AstrMessageEvent(abc.ABC):
elif isinstance(i, Forward):
# 转发消息
outline += "[转发消息]"
+ elif isinstance(i, Reply):
+ # 引用回复
+ if i.message_str:
+ outline += f"[引用消息({i.sender_nickname}: {i.message_str})]"
+ else:
+ outline += "[引用消息]"
else:
outline += f"[{i.type}]"
+ outline += " "
return outline
def get_message_outline(self) -> str:
diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py
index 0a2e8d430..e81e7153f 100644
--- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py
+++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py
@@ -160,8 +160,14 @@ class AiocqhttpAdapter(Platform):
return abm
- async def _convert_handle_message_event(self, event: Event) -> AstrBotMessage:
- """OneBot V11 消息类事件"""
+ async def _convert_handle_message_event(
+ self, event: Event, get_reply=True
+ ) -> AstrBotMessage:
+ """OneBot V11 消息类事件
+
+ @param event: 事件对象
+ @param get_reply: 是否获取回复消息。这个参数是为了防止多个回复嵌套。
+ """
abm = AstrBotMessage()
abm.self_id = str(event.self_id)
abm.sender = MessageMember(
@@ -240,6 +246,34 @@ class AiocqhttpAdapter(Platform):
except BaseException as e:
logger.error(f"获取文件失败: {e},此消息段将被忽略。")
+ elif t == "reply":
+ if not get_reply:
+ a = ComponentTypes[t](**m["data"]) # noqa: F405
+ abm.message.append(a)
+ else:
+ try:
+ reply_event_data = await self.bot.call_action(
+ action="get_msg",
+ message_id=int(m["data"]["id"]),
+ )
+ abm_reply = await self._convert_handle_message_event(
+ Event.from_payload(reply_event_data), get_reply=False
+ )
+
+ reply_seg = Reply(
+ id=abm_reply.message_id,
+ chain=abm_reply.message,
+ sender_id=abm_reply.sender.user_id,
+ sender_nickname=abm_reply.sender.nickname,
+ time=abm_reply.timestamp,
+ message_str=abm_reply.message_str,
+ text=abm_reply.message_str, # for compatibility
+ qq=abm_reply.sender.user_id, # for compatibility
+ )
+
+ abm.message.append(reply_seg)
+ except BaseException as e:
+ logger.error(f"获取消息失败: {e},此消息段将被忽略。")
else:
a = ComponentTypes[t](**m["data"]) # noqa: F405
abm.message.append(a)
From f9ec97e0260098857518e89ab5ea9c15740ba3cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com>
Date: Wed, 12 Mar 2025 08:39:54 +0900
Subject: [PATCH 02/17] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=B5=8C=E5=A5=97?=
=?UTF-8?q?=E8=BD=AC=E5=8F=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/message/components.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/astrbot/core/message/components.py b/astrbot/core/message/components.py
index 389f0088a..4c62cc30f 100644
--- a/astrbot/core/message/components.py
+++ b/astrbot/core/message/components.py
@@ -367,16 +367,20 @@ class Node(BaseMessageComponent):
id: T.Optional[int] = 0 # 忽略
name: T.Optional[str] = "" # qq昵称
uin: T.Optional[int] = 0 # qq号
- content: T.Optional[T.Union[str, list]] = "" # 子消息段列表
+ content: T.Optional[T.Union[str, list, dict]] = "" # 子消息段列表
seq: T.Optional[T.Union[str, list]] = "" # 忽略
time: T.Optional[int] = 0
- def __init__(self, content: T.Union[str, list], **_):
+ def __init__(self, content: T.Union[str, list, dict, "Node"], **_):
if isinstance(content, list):
_content = ""
for chain in content:
_content += chain.toString()
content = _content
+ elif isinstance(content, Node):
+ content = content.toDict()
+ else:
+ content = content
super().__init__(content=content, **_)
def toString(self):
From 9d0ad35403075bf5b766eaa923f810c718420ab3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com>
Date: Wed, 12 Mar 2025 11:14:54 +0900
Subject: [PATCH 03/17] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=B5=8C=E5=A5=97?=
=?UTF-8?q?=E8=BD=AC=E5=8F=91=EF=BC=8C=E9=87=8C=E5=B1=82=E5=8C=85=E5=90=AB?=
=?UTF-8?q?=E5=A4=9A=E6=9D=A1=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/message/components.py | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/astrbot/core/message/components.py b/astrbot/core/message/components.py
index 4c62cc30f..19fdb89e2 100644
--- a/astrbot/core/message/components.py
+++ b/astrbot/core/message/components.py
@@ -371,16 +371,14 @@ class Node(BaseMessageComponent):
seq: T.Optional[T.Union[str, list]] = "" # 忽略
time: T.Optional[int] = 0
- def __init__(self, content: T.Union[str, list, dict, "Node"], **_):
+ def __init__(self, content: T.Union[str, list, dict, "Node", T.List["Node"]], **_):
if isinstance(content, list):
- _content = ""
- for chain in content:
- _content += chain.toString()
- content = _content
+ if all(isinstance(item, str) for item in content):
+ content = "".join(content)
+ elif all(isinstance(item, Node) for item in content):
+ content = [node.toDict() for node in content]
elif isinstance(content, Node):
content = content.toDict()
- else:
- content = content
super().__init__(content=content, **_)
def toString(self):
From 122fccc041c7fc5a5deea3375191d925928e2b9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com>
Date: Wed, 12 Mar 2025 11:59:53 +0900
Subject: [PATCH 04/17] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?=
=?UTF-8?q?=E5=8F=91=E9=80=81=E9=9D=9E=E5=B5=8C=E5=A5=97=E7=9A=84=E8=BD=AC?=
=?UTF-8?q?=E5=8F=91=E6=B6=88=E6=81=AF=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/message/components.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/astrbot/core/message/components.py b/astrbot/core/message/components.py
index 19fdb89e2..7f73e5d91 100644
--- a/astrbot/core/message/components.py
+++ b/astrbot/core/message/components.py
@@ -373,10 +373,14 @@ class Node(BaseMessageComponent):
def __init__(self, content: T.Union[str, list, dict, "Node", T.List["Node"]], **_):
if isinstance(content, list):
- if all(isinstance(item, str) for item in content):
- content = "".join(content)
- elif all(isinstance(item, Node) for item in content):
- content = [node.toDict() for node in content]
+ _content = None
+ if all(isinstance(item, Node) for item in content):
+ _content = [node.toDict() for node in content]
+ else:
+ _content = ""
+ for chain in content:
+ _content += chain.toString()
+ content = _content
elif isinstance(content, Node):
content = content.toDict()
super().__init__(content=content, **_)
From 16488506e8507fd4ab3e6a3b2f17c15a4950d4f6 Mon Sep 17 00:00:00 2001
From: Soulter <905617992@qq.com>
Date: Wed, 12 Mar 2025 14:14:45 +0800
Subject: [PATCH 05/17] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=E4=BF=AE=E5=A4=8D?=
=?UTF-8?q?=E9=83=A8=E5=88=86=E6=83=85=E5=86=B5=E4=B8=8B=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E6=97=A0=E6=B3=95=E4=B8=8A=E4=BC=A0=E5=88=B0=20Telegram=20?=
=?UTF-8?q?=E7=BE=A4=E7=BB=84=E7=9A=84=E9=97=AE=E9=A2=98=20#601?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/platform/sources/telegram/tg_event.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/astrbot/core/platform/sources/telegram/tg_event.py b/astrbot/core/platform/sources/telegram/tg_event.py
index de0f9a58e..7708732b4 100644
--- a/astrbot/core/platform/sources/telegram/tg_event.py
+++ b/astrbot/core/platform/sources/telegram/tg_event.py
@@ -2,6 +2,7 @@ from astrbot.api.event import AstrMessageEvent, MessageChain
from astrbot.api.platform import AstrBotMessage, PlatformMetadata, MessageType
from astrbot.api.message_components import Plain, Image, Reply, At, File, Record
from telegram.ext import ExtBot
+from astrbot.core.utils.io import download_file
class TelegramPlatformEvent(AstrMessageEvent):
@@ -58,6 +59,11 @@ class TelegramPlatformEvent(AstrMessageEvent):
else:
await client.send_photo(photo=image_path, **payload)
elif isinstance(i, File):
+ if i.file.startswith("https://"):
+ path = "data/temp/" + i.name
+ await download_file(i.file, path)
+ i.file = path
+
await client.send_document(document=i.file, filename=i.name, **payload)
elif isinstance(i, Record):
await client.send_voice(voice=i.file, **payload)
From 681940d4665d190fffbb980ddcfdd0b55c8fb7cb Mon Sep 17 00:00:00 2001
From: Soulter <905617992@qq.com>
Date: Wed, 12 Mar 2025 23:37:24 +0800
Subject: [PATCH 06/17] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=E4=BF=AE=E5=A4=8D?=
=?UTF-8?q?=E9=87=8D=E8=BD=BD=E6=8F=92=E4=BB=B6=E6=97=B6=E5=87=BD=E6=95=B0?=
=?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=8F=AF=E8=83=BD=E5=A4=9A=E6=AC=A1=E5=AE=B6?=
=?UTF-8?q?=E5=9C=A8=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/provider/func_tool_manager.py | 11 +++++++----
astrbot/core/star/register/star_handler.py | 2 --
astrbot/core/star/star_manager.py | 4 +---
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/astrbot/core/provider/func_tool_manager.py b/astrbot/core/provider/func_tool_manager.py
index 0022d2773..42b88cae2 100644
--- a/astrbot/core/provider/func_tool_manager.py
+++ b/astrbot/core/provider/func_tool_manager.py
@@ -2,7 +2,7 @@ import json
import textwrap
from typing import Dict, List, Awaitable
from dataclasses import dataclass
-
+from astrbot import logger
@dataclass
class FuncTool:
@@ -46,14 +46,16 @@ class FuncCall:
desc: str,
handler: Awaitable,
) -> None:
- """
- 为函数调用(function-calling / tools-use)添加工具。
+ """添加函数调用工具
@param name: 函数名
@param func_args: 函数参数列表,格式为 [{"type": "string", "name": "arg_name", "description": "arg_description"}, ...]
@param desc: 函数描述
@param func_obj: 处理函数
"""
+ # check if the tool has been added before
+ self.remove_func(name)
+
params = {
"type": "object", # hard-coded here
"properties": {},
@@ -70,13 +72,14 @@ class FuncCall:
handler=handler,
)
self.func_list.append(_func)
+ logger.info(f"添加了函数调用工具({len(self.func_list)}): {name} - {desc}")
def remove_func(self, name: str) -> None:
"""
删除一个函数调用工具。
"""
for i, f in enumerate(self.func_list):
- if f["name"] == name:
+ if f.name == name:
self.func_list.pop(i)
break
diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py
index 4e2f9d176..86620cae6 100644
--- a/astrbot/core/star/register/star_handler.py
+++ b/astrbot/core/star/register/star_handler.py
@@ -360,8 +360,6 @@ def register_llm_tool(name: str = None):
)
md = get_handler_or_create(awaitable, EventType.OnCallingFuncToolEvent)
llm_tools.add_func(llm_tool_name, args, docstring.description, md.handler)
-
- logger.debug(f"LLM 函数工具 {llm_tool_name} 已注册")
return awaitable
return decorator
diff --git a/astrbot/core/star/star_manager.py b/astrbot/core/star/star_manager.py
index 4a7938605..9fa27798b 100644
--- a/astrbot/core/star/star_manager.py
+++ b/astrbot/core/star/star_manager.py
@@ -485,7 +485,7 @@ class PluginManager:
for handler in star_handlers_registry.get_handlers_by_module_name(
plugin_module_path
):
- logger.debug(f"unbind handler {handler.handler_name} from {plugin_name}")
+ logger.info(f"移除了插件 {plugin_name} 的处理函数 {handler.handler_name} ({len(star_handlers_registry)})")
star_handlers_registry.remove(handler)
keys_to_delete = [
k
@@ -493,8 +493,6 @@ class PluginManager:
if k.startswith(plugin_module_path)
]
for k in keys_to_delete:
- v = star_handlers_registry.star_handlers_map[k]
- logger.debug(f"unbind handler {v.handler_name} from {plugin_name} (map)")
try:
del star_handlers_registry.star_handlers_map[k]
except KeyError:
From 8136ad8287f0af5009658cead0a1f577024de5c1 Mon Sep 17 00:00:00 2001
From: shuiping233 <1944680304@qq.com>
Date: Wed, 12 Mar 2025 18:09:25 +0800
Subject: [PATCH 07/17] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=91=BD=E4=BB=A4?=
=?UTF-8?q?=E5=8F=82=E6=95=B0=E6=8A=A5=E9=94=99=E4=BF=A1=E6=81=AF=E6=97=A0?=
=?UTF-8?q?=E6=B3=95=E5=8F=91=E9=80=81=E8=87=B3qq=E5=AE=98=E6=96=B9?=
=?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BA=E5=B9=B3=E5=8F=B0=E7=9A=84bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/pipeline/waking_check/stage.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/astrbot/core/pipeline/waking_check/stage.py b/astrbot/core/pipeline/waking_check/stage.py
index 6bb5f814d..9b2b20155 100644
--- a/astrbot/core/pipeline/waking_check/stage.py
+++ b/astrbot/core/pipeline/waking_check/stage.py
@@ -106,6 +106,7 @@ class WakingCheckStage(Stage):
f"插件 {star_map[handler.handler_module_path].name}: {e}"
)
)
+ await event._post_send()
event.stop_event()
passed = False
break
@@ -117,6 +118,7 @@ class WakingCheckStage(Stage):
f"ID {event.get_sender_id()} 权限不足。通过 /sid 获取 ID 并请管理员添加。"
)
)
+ await event._post_send()
event.stop_event()
return
From 0034474219b609f1d401f15993a07c2f0acfc5ae Mon Sep 17 00:00:00 2001
From: Soulter <905617992@qq.com>
Date: Thu, 13 Mar 2025 13:01:44 +0800
Subject: [PATCH 08/17] =?UTF-8?q?=F0=9F=90=9B=20fix:=20sent=20message=20to?=
=?UTF-8?q?=20wrong=20topic=20in=20topic=20group=20#801?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
astrbot/core/platform/sources/telegram/tg_adapter.py | 6 +++++-
astrbot/core/platform/sources/telegram/tg_event.py | 6 ++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/astrbot/core/platform/sources/telegram/tg_adapter.py b/astrbot/core/platform/sources/telegram/tg_adapter.py
index dfb882328..b7d7a6e7e 100644
--- a/astrbot/core/platform/sources/telegram/tg_adapter.py
+++ b/astrbot/core/platform/sources/telegram/tg_adapter.py
@@ -113,7 +113,11 @@ class TelegramPlatformAdapter(Platform):
message.type = MessageType.FRIEND_MESSAGE
else:
message.type = MessageType.GROUP_MESSAGE
- message.group_id = update.effective_chat.id
+ message.group_id = str(update.effective_chat.id)
+ if update.message.message_thread_id:
+ # Topic Group
+ message.group_id += "#" + str(update.message.message_thread_id)
+
message.message_id = str(update.message.message_id)
message.session_id = str(update.effective_chat.id)
message.sender = MessageMember(
diff --git a/astrbot/core/platform/sources/telegram/tg_event.py b/astrbot/core/platform/sources/telegram/tg_event.py
index 7708732b4..a8a04e2e1 100644
--- a/astrbot/core/platform/sources/telegram/tg_event.py
+++ b/astrbot/core/platform/sources/telegram/tg_event.py
@@ -32,12 +32,18 @@ class TelegramPlatformEvent(AstrMessageEvent):
at_user_id = i.name
at_flag = False
+ message_thread_id = None
+ if "#" in user_name:
+ # it's a supergroup chat with message_thread_id
+ user_name, message_thread_id = user_name.split("#")
for i in message.chain:
payload = {
"chat_id": user_name,
}
if has_reply:
payload["reply_to_message_id"] = reply_message_id
+ if message_thread_id:
+ payload["reply_to_message_id"] = message_thread_id
if isinstance(i, Plain):
if at_user_id and not at_flag:
From 0c396181f78dff33800e33b923cbfb27aabd0ff1 Mon Sep 17 00:00:00 2001
From: Soulter <905617992@qq.com>
Date: Thu, 13 Mar 2025 15:37:53 +0800
Subject: [PATCH 09/17] =?UTF-8?q?=F0=9F=8F=97=20refactor:=20=E9=85=8D?=
=?UTF-8?q?=E7=BD=AE=E9=A1=B5=E6=A0=B7=E5=BC=8F=E9=87=8D=E5=86=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/shared/AstrBotConfig.vue | 227 +++++++++---------
.../src/components/shared/ListConfigItem.vue | 166 ++++++-------
dashboard/src/views/ConfigPage.vue | 110 +++++----
3 files changed, 253 insertions(+), 250 deletions(-)
diff --git a/dashboard/src/components/shared/AstrBotConfig.vue b/dashboard/src/components/shared/AstrBotConfig.vue
index 6ace849ef..38d3f3c27 100644
--- a/dashboard/src/components/shared/AstrBotConfig.vue
+++ b/dashboard/src/components/shared/AstrBotConfig.vue
@@ -1,130 +1,135 @@
-
- {{ metadata[metadataKey]?.description }}
-
- {{metadata[key]['metadata'][key2]['description']}}
-