Skip to content

feat: 😽对reset在不同情况下的权限特殊处理, 使其兼容alter_cmd 🤠为new指令增加清理上下文选项, 默认为清理, 更符合直觉 #1362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 23, 2025
132 changes: 125 additions & 7 deletions packages/astrbot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,32 @@
from astrbot.core import logger
from astrbot.api.message_components import Plain, Image, Reply
from typing import Union
from enum import Enum


class RstScene(Enum):
GROUP_UNIQUE_ON = ("group_unique_on", "群聊+会话隔离开启")
GROUP_UNIQUE_OFF = ("group_unique_off", "群聊+会话隔离关闭")
PRIVATE = ("private", "私聊")

@property
def key(self) -> str:
return self.value[0]

@property
def name(self) -> str:
return self.value[1]

@classmethod
def from_index(cls, index: int) -> "RstScene":
mapping = {1: cls.GROUP_UNIQUE_ON, 2: cls.GROUP_UNIQUE_OFF, 3: cls.PRIVATE}
return mapping[index]

@classmethod
def get_scene(cls, is_group: bool, is_unique_session: bool) -> "RstScene":
if is_group:
return cls.GROUP_UNIQUE_ON if is_unique_session else cls.GROUP_UNIQUE_OFF
return cls.PRIVATE


@star.register(
Expand All @@ -33,6 +59,7 @@
version="4.0.0",
)
class Main(star.Star):

def __init__(self, context: star.Context) -> None:
self.context = context
cfg = context.get_config()
Expand Down Expand Up @@ -479,14 +506,30 @@ async def provider(
@filter.command("reset")
async def reset(self, message: AstrMessageEvent):
"""重置 LLM 会话"""

# ==============================
# 读取当前情况和配置
# ==============================
is_unique_session = self.context.get_config()["platform_settings"][
"unique_session"
]
if message.get_group_id() and not is_unique_session and message.role != "admin":
# 群聊,没开独立会话,发送人不是管理员
is_group = bool(message.get_group_id())

scene = RstScene.get_scene(is_group, is_unique_session)

alter_cmd_cfg = sp.get("alter_cmd", {})
plugin_config = alter_cmd_cfg.get("astrbot", {})
reset_cfg = plugin_config.get("reset", {})

required_perm = reset_cfg.get(
scene.key, "admin" if is_group and not is_unique_session else "member"
)

if required_perm == "admin" and message.role != "admin":
message.set_result(
MessageEventResult().message(
f"会话处于群聊,并且未开启独立会话,并且您 (ID {message.get_sender_id()}) 不是管理员,因此没有权限重置当前对话。"
f"在{scene.name}场景下,reset命令需要管理员权限,"
f"您 (ID {message.get_sender_id()}) 不是管理员,无法执行此操作。"
)
)
return
Expand Down Expand Up @@ -733,7 +776,9 @@ async def convs(self, message: AstrMessageEvent, page: int = 1):

@filter.command("new")
async def new_conv(self, message: AstrMessageEvent):
"""创建新对话"""
"""
创建新对话
"""
provider = self.context.get_using_provider()
if provider and provider.meta().type == "dify":
assert isinstance(provider, ProviderDify)
Expand All @@ -746,6 +791,14 @@ async def new_conv(self, message: AstrMessageEvent):
cid = await self.context.conversation_manager.new_conversation(
message.unified_msg_origin
)

# 长期记忆
if self.ltm:
try:
await self.ltm.remove_session(event=message)
except Exception as e:
logger.error(f"清理聊天增强记录失败: {e}")

message.set_result(
MessageEventResult().message(f"切换到新对话: 新对话({cid[:4]})。")
)
Expand Down Expand Up @@ -882,7 +935,9 @@ async def del_conv(self, message: AstrMessageEvent):
assert isinstance(provider, ProviderDify)
dify_cid = provider.conversation_ids.pop(message.unified_msg_origin, None)
if dify_cid:
await provider.api_client.delete_chat_conv(message.unified_msg_origin, dify_cid)
await provider.api_client.delete_chat_conv(
message.unified_msg_origin, dify_cid
)
message.set_result(
MessageEventResult().message(
"删除当前对话成功。不再处于对话状态,使用 /switch 序号 切换到其他对话或 /new 创建。"
Expand Down Expand Up @@ -1233,7 +1288,9 @@ async def decorate_llm_req(self, event: AstrMessageEvent, req: ProviderRequest):
if mood_dialogs := persona["_mood_imitation_dialogs_processed"]:
req.system_prompt += "\nHere are few shots of dialogs, you need to imitate the tone of 'B' in the following dialogs to respond:\n"
req.system_prompt += mood_dialogs
if (begin_dialogs := persona["_begin_dialogs_processed"]) and not req.contexts:
if (
begin_dialogs := persona["_begin_dialogs_processed"]
) and not req.contexts:
req.contexts[:0] = begin_dialogs

if quote and quote.message_str:
Expand Down Expand Up @@ -1265,13 +1322,59 @@ async def alter_cmd(self, event: AstrMessageEvent):
token = self.parse_commands(event.message_str)
if token.len < 2:
yield event.plain_result(
"可设置所有其他指令是否需要管理员权限。\n格式: /alter_cmd <cmd_name> <admin/member>\n 例如: /alter_cmd provider admin 将 provider 设置为管理员指令"
"可设置所有其他指令是否需要管理员权限。\n格式: /alter_cmd <cmd_name> <admin/member>\n 例如: /alter_cmd provider admin 将 provider 设置为管理员指令\n /alter_cmd reset config 打开reset权限配置"
)
return

cmd_name = token.get(1)
cmd_type = token.get(2)

# ============================
# 对reset权限进行特殊处理
# ============================
if cmd_name == "reset" and cmd_type == "config":
alter_cmd_cfg = sp.get("alter_cmd", {})
plugin_ = alter_cmd_cfg.get("astrbot", {})
reset_cfg = plugin_.get("reset", {})

group_unique_on = reset_cfg.get("group_unique_on", "admin")
group_unique_off = reset_cfg.get("group_unique_off", "admin")
private = reset_cfg.get("private", "member")

config_menu = f"""reset命令权限细粒度配置
当前配置:
1. 群聊+会话隔离开: {group_unique_on}
2. 群聊+会话隔离关: {group_unique_off}
3. 私聊: {private}
修改指令格式:
/alter_cmd reset scene <场景编号> <admin/member>
例如: /alter_cmd reset scene 2 member"""
yield event.plain_result(config_menu)
return

if cmd_name == "reset" and cmd_type == "scene" and token.len >= 4:
scene_num = token.get(3)
perm_type = token.get(4)

if not scene_num.isdigit() or int(scene_num) < 1 or int(scene_num) > 3:
yield event.plain_result("场景编号必须是1-3之间的数字")
return

if perm_type not in ["admin", "member"]:
yield event.plain_result("权限类型错误,只能是admin或member")
return

scene_num = int(scene_num)
scene = RstScene.from_index(scene_num)
scene_key = scene.key

self.update_reset_permission(scene_key, perm_type)

yield event.plain_result(
f"已将 reset 命令在{scene.name}场景下的权限设为{perm_type}"
)
return

if cmd_type not in ["admin", "member"]:
yield event.plain_result("指令类型错误,可选类型有 admin, member")
return
Expand Down Expand Up @@ -1326,3 +1429,18 @@ async def alter_cmd(self, event: AstrMessageEvent):
)

yield event.plain_result(f"已将 {cmd_name} 设置为 {cmd_type} 指令")

def update_reset_permission(self, scene_key: str, perm_type: str):
"""更新reset命令在特定场景下的权限设置

Args:
scene_key (str): 场景编号,1-3
perm_type (str): 权限类型,admin或member
"""
alter_cmd_cfg = sp.get("alter_cmd", {})
plugin_cfg = alter_cmd_cfg.get("astrbot", {})
reset_cfg = plugin_cfg.get("reset", {})
reset_cfg[scene_key] = perm_type
plugin_cfg["reset"] = reset_cfg
alter_cmd_cfg["astrbot"] = plugin_cfg
sp.put("alter_cmd", alter_cmd_cfg)