Merge branch 'v0.10.0' into dev to update

This commit is contained in:
UnCLAS-Prommer
2025-08-18 11:32:05 +08:00
24 changed files with 818 additions and 271 deletions

View File

@@ -24,7 +24,7 @@ from src.plugin_system.apis import generator_api, send_api, message_api, databas
from src.mais4u.mai_think import mai_thinking_manager
import math
from src.mais4u.s4u_config import s4u_config
# no_reply逻辑已集成到heartFC_chat.py中不再需要导入
# no_action逻辑已集成到heartFC_chat.py中不再需要导入
from src.chat.chat_loop.hfc_utils import send_typing, stop_typing
# 导入记忆系统
from src.chat.memory_system.Hippocampus import hippocampus_manager
@@ -47,16 +47,6 @@ ERROR_LOOP_INFO = {
},
}
NO_ACTION = {
"action_result": {
"action_type": "no_action",
"action_data": {},
"reasoning": "规划器初始化默认",
"is_parallel": True,
},
"chat_context": "",
"action_prompt": "",
}
install(extra_lines=3)
@@ -116,8 +106,8 @@ class HeartFChatting:
self.last_read_time = time.time() - 1
self.focus_energy = 1
self.no_reply_consecutive = 0
# 最近三次no_reply的新消息兴趣度记录
self.no_action_consecutive = 0
# 最近三次no_action的新消息兴趣度记录
self.recent_interest_records: deque = deque(maxlen=3)
async def start(self):
@@ -198,9 +188,9 @@ class HeartFChatting:
)
def _determine_form_type(self) -> None:
"""判断使用哪种形式的no_reply"""
# 如果连续no_reply次数少于3次使用waiting形式
if self.no_reply_consecutive <= 3:
"""判断使用哪种形式的no_action"""
# 如果连续no_action次数少于3次使用waiting形式
if self.no_action_consecutive <= 3:
self.focus_energy = 1
else:
# 计算最近三次记录的兴趣度总和
@@ -403,7 +393,7 @@ class HeartFChatting:
#如果激活度没有激活并且聊天活跃度低有可能不进行plan相当于不在电脑前不进行认真思考
actions = [
{
"action_type": "no_reply",
"action_type": "no_action",
"reasoning": "专注不足",
"action_data": {},
}
@@ -442,12 +432,12 @@ class HeartFChatting:
async def execute_action(action_info,actions):
"""执行单个动作的通用函数"""
try:
if action_info["action_type"] == "no_reply":
# 直接处理no_reply逻辑,不再通过动作系统
if action_info["action_type"] == "no_action":
# 直接处理no_action逻辑,不再通过动作系统
reason = action_info.get("reasoning", "选择不回复")
logger.info(f"{self.log_prefix} 选择不回复,原因: {reason}")
# 存储no_reply信息到数据库
# 存储no_action信息到数据库
await database_api.store_action_info(
chat_stream=self.chat_stream,
action_build_into_prompt=False,
@@ -455,11 +445,11 @@ class HeartFChatting:
action_done=True,
thinking_id=thinking_id,
action_data={"reason": reason},
action_name="no_reply",
action_name="no_action",
)
return {
"action_type": "no_reply",
"action_type": "no_action",
"success": True,
"reply_text": "",
"command": ""
@@ -613,16 +603,16 @@ class HeartFChatting:
action_type = actions[0]["action_type"] if actions else "no_action"
# 管理no_reply计数器当执行了非no_reply动作时,重置计数器
if action_type != "no_reply":
# no_reply逻辑已集成到heartFC_chat.py中直接重置计数器
# 管理no_action计数器当执行了非no_action动作时,重置计数器
if action_type != "no_action":
# no_action逻辑已集成到heartFC_chat.py中直接重置计数器
self.recent_interest_records.clear()
self.no_reply_consecutive = 0
logger.debug(f"{self.log_prefix} 执行了{action_type}动作重置no_reply计数器")
self.no_action_consecutive = 0
logger.debug(f"{self.log_prefix} 执行了{action_type}动作重置no_action计数器")
return True
if action_type == "no_reply":
self.no_reply_consecutive += 1
if action_type == "no_action":
self.no_action_consecutive += 1
self._determine_form_type()
return True

View File

@@ -1367,8 +1367,11 @@ class HippocampusManager:
logger.info(f"{chat_id} 构建记忆")
if memory_segment_manager.check_and_build_memory_for_chat(chat_id):
logger.info(f"{chat_id} 构建记忆,需要构建记忆")
messages = memory_segment_manager.get_messages_for_memory_build(chat_id, 30 / global_config.memory.memory_build_frequency)
if messages:
messages = memory_segment_manager.get_messages_for_memory_build(chat_id, 50)
build_probability = 0.3 * global_config.memory.memory_build_frequency
if messages and random.random() < build_probability:
logger.info(f"{chat_id} 构建记忆,消息数量: {len(messages)}")
# 调用记忆压缩和构建

View File

@@ -133,7 +133,7 @@ class ActionPlanner:
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
"""
action = "no_reply" # 默认动作
action = "no_action" # 默认动作
reasoning = "规划器初始化默认"
action_data = {}
current_available_actions: Dict[str, ActionInfo] = {}
@@ -172,7 +172,7 @@ class ActionPlanner:
except Exception as req_e:
logger.error(f"{self.log_prefix}LLM 请求执行失败: {req_e}")
reasoning = f"LLM 请求失败,模型出现问题: {req_e}"
action = "no_reply"
action = "no_action"
if llm_content:
try:
@@ -189,7 +189,7 @@ class ActionPlanner:
logger.error(f"{self.log_prefix}解析后的JSON不是字典类型: {type(parsed_json)}")
parsed_json = {}
action = parsed_json.get("action", "no_reply")
action = parsed_json.get("action", "no_action")
reasoning = parsed_json.get("reason", "未提供原因")
# 将所有其他属性添加到action_data
@@ -197,8 +197,8 @@ class ActionPlanner:
if key not in ["action", "reasoning"]:
action_data[key] = value
# 非no_reply动作需要target_message_id
if action != "no_reply":
# 非no_action动作需要target_message_id
if action != "no_action":
if target_message_id := parsed_json.get("target_message_id"):
# 根据target_message_id查找原始消息
target_message = self.find_message_by_id(target_message_id, message_id_list)
@@ -218,23 +218,23 @@ class ActionPlanner:
if action != "no_reply" and action != "reply" and action not in current_available_actions:
if action != "no_action" and action != "reply" and action not in current_available_actions:
logger.warning(
f"{self.log_prefix}LLM 返回了当前不可用或无效的动作: '{action}' (可用: {list(current_available_actions.keys())}),将强制使用 'no_reply'"
f"{self.log_prefix}LLM 返回了当前不可用或无效的动作: '{action}' (可用: {list(current_available_actions.keys())}),将强制使用 'no_action'"
)
reasoning = f"LLM 返回了当前不可用的动作 '{action}' (可用: {list(current_available_actions.keys())})。原始理由: {reasoning}"
action = "no_reply"
action = "no_action"
except Exception as json_e:
logger.warning(f"{self.log_prefix}解析LLM响应JSON失败 {json_e}. LLM原始输出: '{llm_content}'")
traceback.print_exc()
reasoning = f"解析LLM响应JSON失败: {json_e}. 将使用默认动作 'no_reply'."
action = "no_reply"
reasoning = f"解析LLM响应JSON失败: {json_e}. 将使用默认动作 'no_action'."
action = "no_action"
except Exception as outer_e:
logger.error(f"{self.log_prefix}Planner 处理过程中发生意外错误,规划失败,将执行 no_reply: {outer_e}")
logger.error(f"{self.log_prefix}Planner 处理过程中发生意外错误,规划失败,将执行 no_action: {outer_e}")
traceback.print_exc()
action = "no_reply"
action = "no_action"
reasoning = f"Planner 内部处理错误: {outer_e}"
is_parallel = False
@@ -315,14 +315,15 @@ class ActionPlanner:
if mode == ChatMode.FOCUS:
no_action_block = """
动作no_reply
动作描述:不进行回复,等待合适的回复时机
- 当你刚刚发送了消息没有人回复时选择no_reply
- 当你一次发送了太多消息为了避免打扰聊天节奏选择no_reply
{{
"action": "no_reply",
"reason":"不回复的原因"
}}
动作no_action
动作描述:不进行动作,等待合适的时机
- 当你刚刚发送了消息没有人回复时选择no_action
- 如果有别的动作非回复满足条件可以不用no_action
- 当你一次发送了太多消息为了避免打扰聊天节奏选择no_action
{
"action": "no_action",
"reason":"不动作的原因"
}
"""
else:
no_action_block = """重要说明:

View File

@@ -57,7 +57,7 @@ def init_prompt():
{reply_style},你可以完全重组回复,保留最基本的表达含义就好,但重组后保持语意通顺。
{keywords_reaction_prompt}
{moderation_prompt}
不要输出多余内容(包括前后缀冒号和引号括号表情包at或 @等 ),只输出一条回复就好。
不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,emoji,at或 @等 ),只输出一条回复就好。
现在,你说:
""",
"default_expressor_prompt",
@@ -86,7 +86,7 @@ def init_prompt():
{keywords_reaction_prompt}
请注意不要输出多余内容(包括前后缀冒号和引号at或 @等 )。只输出回复内容。
{moderation_prompt}
不要输出多余内容(包括前后缀,冒号和引号,括号()表情包at或 @等 )。只输出一条回复就好
不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,emoji,at或 @等 )。只输出一条回复就好
现在,你说:
""",
"replyer_prompt",
@@ -111,7 +111,7 @@ def init_prompt():
{keywords_reaction_prompt}
请注意不要输出多余内容(包括前后缀冒号和引号at或 @等 )。只输出回复内容。
{moderation_prompt}
不要输出多余内容(包括前后缀,冒号和引号,括号()表情包at或 @等 )。只输出一条回复就好
不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,emoji,at或 @等 )。只输出一条回复就好
现在,你说:
""",
"replyer_self_prompt",
@@ -294,6 +294,9 @@ class DefaultReplyer:
if not global_config.relationship.enable_relationship:
return ""
if not sender:
return ""
if sender == global_config.bot.nickname:
return ""
@@ -303,7 +306,7 @@ class DefaultReplyer:
logger.warning(f"未找到用户 {sender} 的ID跳过信息提取")
return f"你完全不认识{sender}不理解ta的相关信息。"
return person.build_relationship(points_num=5)
return person.build_relationship()
async def build_expression_habits(self, chat_history: str, target: str) -> Tuple[str, List[int]]:
# sourcery skip: for-append-to-extend

View File

@@ -735,7 +735,7 @@ def build_readable_actions(actions: List[Dict[str, Any]]) -> str:
for action in actions:
action_time = action.get("time", current_time)
action_name = action.get("action_name", "未知动作")
if action_name in ["no_action", "no_reply"]:
if action_name in ["no_action", "no_action"]:
continue
action_prompt_display = action.get("action_prompt_display", "无具体内容")