Merge pull request #1129 from MaiM-with-u/dev

别conflict别conflict别conflict别conflict别conflict别conflict
This commit is contained in:
墨梓柒
2025-07-25 13:51:54 +08:00
committed by GitHub
9 changed files with 35 additions and 134 deletions

View File

@@ -20,6 +20,7 @@ class HelloAction(BaseAction):
# === 基本信息(必须填写)===
action_name = "hello_greeting"
action_description = "向用户发送问候消息"
activation_type = ActionActivationType.ALWAYS # 始终激活
# === 功能描述(必须填写)===
action_parameters = {"greeting_message": "要发送的问候消息"}
@@ -44,8 +45,7 @@ class ByeAction(BaseAction):
action_description = "向用户发送告别消息"
# 使用关键词激活
focus_activation_type = ActionActivationType.KEYWORD
normal_activation_type = ActionActivationType.KEYWORD
activation_type = ActionActivationType.KEYWORD
# 关键词设置
activation_keywords = ["再见", "bye", "88", "拜拜"]
@@ -75,8 +75,6 @@ class TimeCommand(BaseCommand):
# === 命令设置(必须填写)===
command_pattern = r"^/time$" # 精确匹配 "/time" 命令
command_help = "查询当前时间"
command_examples = ["/time"]
async def execute(self) -> Tuple[bool, str, bool]:
"""执行时间查询"""

View File

@@ -3,10 +3,10 @@ import sys
import os
from typing import Dict, List, Tuple, Optional
from datetime import datetime
from src.common.database.database_model import Messages, ChatStreams
# Add project root to Python path
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, project_root)
from src.common.database.database_model import Messages, ChatStreams #noqa

View File

@@ -439,93 +439,3 @@ class ActionModifier:
else:
logger.debug(f"{self.log_prefix}动作 {action_name} 未匹配到任何关键词: {activation_keywords}")
return False
# async def analyze_loop_actions(self, history_loop: List[CycleDetail]) -> List[tuple[str, str]]:
# """分析最近的循环内容并决定动作的移除
# Returns:
# List[Tuple[str, str]]: 包含要删除的动作及原因的元组列表
# [("action3", "some reason")]
# """
# removals = []
# # 获取最近10次循环
# recent_cycles = history_loop[-10:] if len(history_loop) > 10 else history_loop
# if not recent_cycles:
# return removals
# reply_sequence = [] # 记录最近的动作序列
# for cycle in recent_cycles:
# action_result = cycle.loop_plan_info.get("action_result", {})
# action_type = action_result.get("action_type", "unknown")
# reply_sequence.append(action_type == "reply")
# # 计算连续回复的相关阈值
# max_reply_num = int(global_config.focus_chat.consecutive_replies * 3.2)
# sec_thres_reply_num = int(global_config.focus_chat.consecutive_replies * 2)
# one_thres_reply_num = int(global_config.focus_chat.consecutive_replies * 1.5)
# # 获取最近max_reply_num次的reply状态
# if len(reply_sequence) >= max_reply_num:
# last_max_reply_num = reply_sequence[-max_reply_num:]
# else:
# last_max_reply_num = reply_sequence[:]
# # 详细打印阈值和序列信息,便于调试
# logger.info(
# f"连续回复阈值: max={max_reply_num}, sec={sec_thres_reply_num}, one={one_thres_reply_num}"
# f"最近reply序列: {last_max_reply_num}"
# )
# # print(f"consecutive_replies: {consecutive_replies}")
# # 根据最近的reply情况决定是否移除reply动作
# if len(last_max_reply_num) >= max_reply_num and all(last_max_reply_num):
# # 如果最近max_reply_num次都是reply直接移除
# reason = f"连续回复过多(最近{len(last_max_reply_num)}次全是reply超过阈值{max_reply_num}"
# removals.append(("reply", reason))
# # reply_count = len(last_max_reply_num) - no_reply_count
# elif len(last_max_reply_num) >= sec_thres_reply_num and all(last_max_reply_num[-sec_thres_reply_num:]):
# # 如果最近sec_thres_reply_num次都是reply40%概率移除
# removal_probability = 0.4 / global_config.focus_chat.consecutive_replies
# if random.random() < removal_probability:
# reason = (
# f"连续回复较多(最近{sec_thres_reply_num}次全是reply{removal_probability:.2f}概率移除,触发移除)"
# )
# removals.append(("reply", reason))
# elif len(last_max_reply_num) >= one_thres_reply_num and all(last_max_reply_num[-one_thres_reply_num:]):
# # 如果最近one_thres_reply_num次都是reply20%概率移除
# removal_probability = 0.2 / global_config.focus_chat.consecutive_replies
# if random.random() < removal_probability:
# reason = (
# f"连续回复检测(最近{one_thres_reply_num}次全是reply{removal_probability:.2f}概率移除,触发移除)"
# )
# removals.append(("reply", reason))
# else:
# logger.debug(f"{self.log_prefix}连续回复检测无需移除reply动作最近回复模式正常")
# return removals
# def get_available_actions_count(self, mode: str = "focus") -> int:
# """获取当前可用动作数量排除默认的no_action"""
# current_actions = self.action_manager.get_using_actions_for_mode(mode)
# # 排除no_action如果存在
# filtered_actions = {k: v for k, v in current_actions.items() if k != "no_action"}
# return len(filtered_actions)
# def should_skip_planning_for_no_reply(self) -> bool:
# """判断是否应该跳过规划过程"""
# current_actions = self.action_manager.get_using_actions_for_mode("focus")
# # 排除no_action如果存在
# if len(current_actions) == 1 and "no_reply" in current_actions:
# return True
# return False
# def should_skip_planning_for_no_action(self) -> bool:
# """判断是否应该跳过规划过程"""
# available_count = self.action_manager.get_using_actions_for_mode("normal")
# if available_count == 0:
# logger.debug(f"{self.log_prefix} 没有可用动作,跳过规划")
# return True
# return False

View File

@@ -40,7 +40,6 @@ def init_prompt():
{moderation_prompt}
现在请你根据{by_what}选择合适的action和触发action的消息:
你刚刚选择并执行过的action是
{actions_before_now_block}
{no_action_block}
@@ -130,17 +129,18 @@ class ActionPlanner:
logger.warning(f"{self.log_prefix}使用中的动作 {action_name} 未在已注册动作中找到")
# 如果没有可用动作或只有no_reply动作直接返回no_reply
if not current_available_actions:
action = "no_reply" if mode == ChatMode.FOCUS else "no_action"
reasoning = "没有可用的动作"
logger.info(f"{self.log_prefix}{reasoning}")
return {
"action_result": {
"action_type": action,
"action_data": action_data,
"reasoning": reasoning,
},
}, None
# 因为现在reply是永远激活所以不需要空跳判定
# if not current_available_actions:
# action = "no_reply" if mode == ChatMode.FOCUS else "no_action"
# reasoning = "没有可用的动作"
# logger.info(f"{self.log_prefix}{reasoning}")
# return {
# "action_result": {
# "action_type": action,
# "action_data": action_data,
# "reasoning": reasoning,
# },
# }, None
# --- 构建提示词 (调用修改后的 PromptBuilder 方法) ---
prompt, message_id_list = await self.build_planner_prompt(
@@ -268,6 +268,7 @@ class ActionPlanner:
actions_before_now = get_actions_by_timestamp_with_chat(
chat_id=self.chat_id,
timestamp_start=time.time()-3600,
timestamp_end=time.time(),
limit=5,
)
@@ -276,6 +277,8 @@ class ActionPlanner:
actions=actions_before_now,
)
actions_before_now_block = f"你刚刚选择并执行过的action是\n{actions_before_now_block}"
self.last_obs_time_mark = time.time()
if mode == ChatMode.FOCUS:
@@ -288,7 +291,7 @@ class ActionPlanner:
by_what = "聊天内容"
target_prompt = '\n "target_message_id":"触发action的消息id"'
no_action_block = f"""重要说明1
no_action_block = f"""重要说明:
- 'no_reply' 表示只进行不进行回复,等待合适的回复时机
- 当你刚刚发送了消息没有人回复时选择no_reply
- 当你一次发送了太多消息为了避免打扰聊天节奏选择no_reply

View File

@@ -419,7 +419,7 @@ class RelationshipBuilder:
async def update_impression_on_segments(self, person_id: str, chat_id: str, segments: List[Dict[str, Any]]):
"""基于消息段更新用户印象"""
original_segment_count = len(segments)
logger.info(f"开始为 {person_id} 基于 {original_segment_count} 个消息段更新印象")
logger.debug(f"开始为 {person_id} 基于 {original_segment_count} 个消息段更新印象")
try:
# 筛选要处理的消息段每个消息段有10%的概率被丢弃
segments_to_process = [s for s in segments if random.random() >= 0.1]
@@ -432,7 +432,7 @@ class RelationshipBuilder:
dropped_count = original_segment_count - len(segments_to_process)
if dropped_count > 0:
logger.info(f"{person_id} 随机丢弃了 {dropped_count} / {original_segment_count} 个消息段")
logger.debug(f"{person_id} 随机丢弃了 {dropped_count} / {original_segment_count} 个消息段")
processed_messages = []

View File

@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
from typing import Dict, Tuple, Optional, List
from typing import Dict, Tuple, Optional
from src.common.logger import get_logger
from src.plugin_system.base.component_types import CommandInfo, ComponentType
from src.chat.message_receive.message import MessageRecv
@@ -26,9 +26,6 @@ class BaseCommand(ABC):
# 默认命令设置
command_pattern: str = r""
"""命令匹配的正则表达式"""
command_help: str = ""
"""命令帮助信息"""
command_examples: List[str] = []
def __init__(self, message: MessageRecv, plugin_config: Optional[dict] = None):
"""初始化Command组件
@@ -228,6 +225,4 @@ class BaseCommand(ABC):
component_type=ComponentType.COMMAND,
description=cls.command_description,
command_pattern=cls.command_pattern,
command_help=cls.command_help,
command_examples=cls.command_examples.copy() if cls.command_examples else [],
)

View File

@@ -140,13 +140,9 @@ class CommandInfo(ComponentInfo):
"""命令组件信息"""
command_pattern: str = "" # 命令匹配模式(正则表达式)
command_help: str = "" # 命令帮助信息
command_examples: List[str] = field(default_factory=list) # 命令使用示例
def __post_init__(self):
super().__post_init__()
if self.command_examples is None:
self.command_examples = []
self.component_type = ComponentType.COMMAND

View File

@@ -182,17 +182,17 @@ class EventsManager:
async def cancel_handler_tasks(self, handler_name: str) -> None:
tasks_to_be_cancelled = self._handler_tasks.get(handler_name, [])
remaining_tasks = [task for task in tasks_to_be_cancelled if not task.done()]
for task in remaining_tasks:
task.cancel()
try:
await asyncio.wait_for(asyncio.gather(*remaining_tasks, return_exceptions=True), timeout=5)
logger.info(f"已取消事件处理器 {handler_name} 的所有任务")
except asyncio.TimeoutError:
logger.warning(f"取消事件处理器 {handler_name} 的任务超时,开始强制取消")
except Exception as e:
logger.error(f"取消事件处理器 {handler_name} 的任务时发生异常: {e}")
finally:
if remaining_tasks := [task for task in tasks_to_be_cancelled if not task.done()]:
for task in remaining_tasks:
task.cancel()
try:
await asyncio.wait_for(asyncio.gather(*remaining_tasks, return_exceptions=True), timeout=5)
logger.info(f"已取消事件处理器 {handler_name} 的所有任务")
except asyncio.TimeoutError:
logger.warning(f"取消事件处理器 {handler_name} 的任务超时,开始强制取消")
except Exception as e:
logger.error(f"取消事件处理器 {handler_name} 的任务时发生异常: {e}")
if handler_name in self._handler_tasks:
del self._handler_tasks[handler_name]
async def unregister_event_subscriber(self, handler_name: str) -> bool:

View File

@@ -20,8 +20,7 @@ class EmojiAction(BaseAction):
"""表情动作 - 发送表情包"""
# 激活设置
focus_activation_type = ActionActivationType.RANDOM
normal_activation_type = ActionActivationType.RANDOM
activation_type = ActionActivationType.RANDOM
mode_enable = ChatMode.ALL
parallel_action = True
random_activation_probability = 0.2 # 默认值,可通过配置覆盖