From 3931423e8e2b4b777fcbf5a3c710f9f7bbea25c3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 26 Apr 2025 13:49:24 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heart_flow/background_tasks.py | 2 -- src/heart_flow/sub_heartflow.py | 6 ++-- src/heart_flow/subheartflow_manager.py | 44 +++++++++++------------- src/plugins/heartFC_chat/heartFC_chat.py | 33 ++++++++++-------- 4 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/heart_flow/background_tasks.py b/src/heart_flow/background_tasks.py index 076f441c9..d2bd93213 100644 --- a/src/heart_flow/background_tasks.py +++ b/src/heart_flow/background_tasks.py @@ -255,7 +255,6 @@ class BackgroundTaskManager: # --- 结束新增 --- - # --- 结束新增 --- # --- Specific Task Runners --- # @@ -286,4 +285,3 @@ class BackgroundTaskManager: interval=self.interest_eval_interval, task_func=self._perform_interest_eval_work, ) - diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index 63d4b4a0e..ead07f53c 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -243,7 +243,7 @@ class SubHeartflow: self, subheartflow_id, mai_states: MaiStateInfo, - hfc_no_reply_callback: Callable[[], Coroutine[None, None, None]] + hfc_no_reply_callback: Callable[[], Coroutine[None, None, None]], ): """子心流初始化函数 @@ -380,8 +380,8 @@ class SubHeartflow: self.heart_fc_instance = HeartFChatting( chat_id=self.subheartflow_id, sub_mind=self.sub_mind, - observations=self.observations, # 传递所有观察者 - on_consecutive_no_reply_callback=self.hfc_no_reply_callback # <-- Use stored callback + observations=self.observations, # 传递所有观察者 + on_consecutive_no_reply_callback=self.hfc_no_reply_callback, # <-- Use stored callback ) # 初始化并启动 HeartFChatting diff --git a/src/heart_flow/subheartflow_manager.py b/src/heart_flow/subheartflow_manager.py index cf6e01b6a..50cf38b03 100644 --- a/src/heart_flow/subheartflow_manager.py +++ b/src/heart_flow/subheartflow_manager.py @@ -2,8 +2,8 @@ import asyncio import time import random from typing import Dict, Any, Optional, List -import json # 导入 json 模块 -import functools # <-- 新增导入 +import json # 导入 json 模块 +import functools # <-- 新增导入 # 导入日志模块 from src.common.logger import get_module_logger, LogConfig, SUBHEARTFLOW_MANAGER_STYLE_CONFIG @@ -88,7 +88,7 @@ class SubHeartflowManager: new_subflow = SubHeartflow( subheartflow_id, self.mai_state_info, - hfc_callback # <-- 传递 partial 创建的回调 + hfc_callback, # <-- 传递 partial 创建的回调 ) # 异步初始化 @@ -134,20 +134,23 @@ class SubHeartflowManager: if subflow.chat_state.chat_status == ChatState.ABSENT: return True else: - logger.warning(f"{log_prefix} 调用 change_chat_state 后,{stream_name} 状态仍为 {subflow.chat_state.chat_status.value}") + logger.warning( + f"{log_prefix} 调用 change_chat_state 后,{stream_name} 状态仍为 {subflow.chat_state.chat_status.value}" + ) return False except Exception as e: logger.error(f"{log_prefix} 设置 {stream_name} 状态为 ABSENT 时失败: {e}", exc_info=True) return False else: logger.debug(f"{log_prefix} {stream_name} 已是 ABSENT 状态") - return True # 已经是目标状态,视为成功 + return True # 已经是目标状态,视为成功 + # --- 结束新增 --- async def sleep_subheartflow(self, subheartflow_id: Any, reason: str) -> bool: """停止指定的子心流并将其状态设置为 ABSENT""" log_prefix = "[子心流管理]" - async with self._lock: # 加锁以安全访问字典 + async with self._lock: # 加锁以安全访问字典 subheartflow = self.subheartflows.get(subheartflow_id) stream_name = chat_manager.get_stream_name(subheartflow_id) or subheartflow_id @@ -229,7 +232,7 @@ class SubHeartflowManager: changed_count = 0 processed_count = 0 - async with self._lock: # 获取锁以安全迭代 + async with self._lock: # 获取锁以安全迭代 # 使用 list() 创建一个当前值的快照,防止在迭代时修改字典 flows_to_update = list(self.subheartflows.values()) processed_count = len(flows_to_update) @@ -239,8 +242,7 @@ class SubHeartflowManager: for subflow in flows_to_update: # 记录原始状态,以便统计实际改变的数量 - original_state_was_absent = (subflow.chat_state.chat_status == ChatState.ABSENT) - + original_state_was_absent = subflow.chat_state.chat_status == ChatState.ABSENT success = await self._try_set_subflow_absent_internal(subflow, log_prefix) @@ -345,7 +347,6 @@ class SubHeartflowManager: log_prefix = f"[{stream_name}]" current_subflow_state = sub_hf.chat_state.chat_status - _observation_summary = "没有可用的观察信息。" # 默认值 first_observation = sub_hf.observations[0] @@ -357,12 +358,10 @@ class SubHeartflowManager: else: logger.warning(f"{log_prefix} [{stream_name}] 第一个观察者不是 ChattingObservation 类型。") - - # --- 获取麦麦状态 --- mai_state_description = f"你当前状态: {current_mai_state.value}。" - - # 获取个性化信息 + + # 获取个性化信息 individuality = Individuality.get_instance() # 构建个性部分 @@ -378,7 +377,6 @@ class SubHeartflowManager: if individuality.identity.identity_detail: random_detail = random.choice(individuality.identity.identity_detail) prompt_personality += f",{random_detail}" - # --- 针对 ABSENT 状态 --- if current_subflow_state == ChatState.ABSENT: @@ -392,14 +390,14 @@ class SubHeartflowManager: f"进入常规聊天(CHAT)状态?\n" f"给出你的判断,和理由,然后以 JSON 格式回答" f"包含键 'decision',如果要开始聊天,值为 true ,否则为 false.\n" - f"包含键 'reason',其值为你的理由。\n" - f"例如:{{\"decision\": true, \"reason\": \"因为我想聊天\"}}\n" + f"包含键 'reason',其值为你的理由。\n" + f'例如:{{"decision": true, "reason": "因为我想聊天"}}\n' f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 should_activate = await self._llm_evaluate_state_transition(prompt) - if should_activate is None: # 处理解析失败或意外情况 + if should_activate is None: # 处理解析失败或意外情况 logger.warning(f"{log_prefix}LLM评估返回无效结果,跳过。") continue @@ -435,14 +433,14 @@ class SubHeartflowManager: f"还是暂时离开聊天,进入休眠状态?\n" f"给出你的判断,和理由,然后以 JSON 格式回答" f"包含键 'decision',如果要离开聊天,值为 true ,否则为 false.\n" - f"包含键 'reason',其值为你的理由。\n" - f"例如:{{\"decision\": true, \"reason\": \"因为我想休息\"}}\n" + f"包含键 'reason',其值为你的理由。\n" + f'例如:{{"decision": true, "reason": "因为我想休息"}}\n' f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 should_deactivate = await self._llm_evaluate_state_transition(prompt) - if should_deactivate is None: # 处理解析失败或意外情况 + if should_deactivate is None: # 处理解析失败或意外情况 logger.warning(f"{log_prefix}LLM评估返回无效结果,跳过。") continue @@ -453,8 +451,6 @@ class SubHeartflowManager: transitioned_to_absent += 1 else: logger.info(f"{log_prefix}LLM建议不进入ABSENT状态。") - - async def _llm_evaluate_state_transition(self, prompt: str) -> Optional[bool]: """ @@ -573,6 +569,7 @@ class SubHeartflowManager: # 注意:这里不需要再获取锁,因为 request_absent_transition 内部会处理锁 logger.debug(f"[管理器 HFC 处理器] 接收到来自 {subheartflow_id} 的 HFC 无回复信号") await self.request_absent_transition(subheartflow_id) + # --- 结束新增 --- # # --- 新增:处理来自 HeartFChatting 的状态转换请求 --- # @@ -608,4 +605,5 @@ class SubHeartflowManager: logger.warning( f"[状态转换请求] 收到对 {stream_name} 的请求,但其状态为 {current_state.value} (非 FOCUSED),不执行转换" ) + # --- 结束新增 --- # diff --git a/src/plugins/heartFC_chat/heartFC_chat.py b/src/plugins/heartFC_chat/heartFC_chat.py index 9a2862adb..8f376b37f 100644 --- a/src/plugins/heartFC_chat/heartFC_chat.py +++ b/src/plugins/heartFC_chat/heartFC_chat.py @@ -154,14 +154,14 @@ class HeartFChatting: 其生命周期现在由其关联的 SubHeartflow 的 FOCUSED 状态控制。 """ - CONSECUTIVE_NO_REPLY_THRESHOLD = 4 # 连续不回复的阈值 + CONSECUTIVE_NO_REPLY_THRESHOLD = 4 # 连续不回复的阈值 def __init__( self, chat_id: str, sub_mind: SubMind, observations: Observation, - on_consecutive_no_reply_callback: Callable[[], Coroutine[None, None, None]] + on_consecutive_no_reply_callback: Callable[[], Coroutine[None, None, None]], ): """ HeartFChatting 初始化函数 @@ -209,8 +209,8 @@ class HeartFChatting: self._cycle_counter = 0 self._cycle_history: Deque[CycleInfo] = deque(maxlen=10) # 保留最近10个循环的信息 self._current_cycle: Optional[CycleInfo] = None - self._lian_xu_bu_hui_fu_ci_shu: int = 0 # <--- 新增:连续不回复计数器 - self._shutting_down: bool = False # <--- 新增:关闭标志位 + self._lian_xu_bu_hui_fu_ci_shu: int = 0 # <--- 新增:连续不回复计数器 + self._shutting_down: bool = False # <--- 新增:关闭标志位 async def _initialize(self) -> bool: """ @@ -309,9 +309,9 @@ class HeartFChatting: # 如果未能获取锁(理论上不太可能,除非 shutdown 过程中释放了但又被抢了?) # 或者也可以在这里再次检查 self._shutting_down if self._shutting_down: - break # 再次检查,确保退出 + break # 再次检查,确保退出 logger.warning(f"{self.log_prefix} 未能获取循环处理锁,跳过本次循环。") - await asyncio.sleep(0.1) # 短暂等待避免空转 + await asyncio.sleep(0.1) # 短暂等待避免空转 continue # 记录规划开始时间点 @@ -600,27 +600,30 @@ class HeartFChatting: if not self._shutting_down: self._lian_xu_bu_hui_fu_ci_shu += 1 - logger.debug(f"{self.log_prefix} 连续不回复计数增加: {self._lian_xu_bu_hui_fu_ci_shu}/{self.CONSECUTIVE_NO_REPLY_THRESHOLD}") + logger.debug( + f"{self.log_prefix} 连续不回复计数增加: {self._lian_xu_bu_hui_fu_ci_shu}/{self.CONSECUTIVE_NO_REPLY_THRESHOLD}" + ) # 检查是否达到阈值 if self._lian_xu_bu_hui_fu_ci_shu >= self.CONSECUTIVE_NO_REPLY_THRESHOLD: - logger.info(f"{self.log_prefix} 连续不回复达到阈值 ({self._lian_xu_bu_hui_fu_ci_shu}次),调用回调请求状态转换") + logger.info( + f"{self.log_prefix} 连续不回复达到阈值 ({self._lian_xu_bu_hui_fu_ci_shu}次),调用回调请求状态转换" + ) # 调用回调。注意:这里不重置计数器,依赖回调函数成功改变状态来隐式重置上下文。 await self.on_consecutive_no_reply_callback() - - return True + return True except asyncio.CancelledError: # 如果在等待过程中任务被取消(可能是因为 shutdown) logger.info(f"{self.log_prefix} 处理 'no_reply' 时等待被中断 (CancelledError)") # 让异常向上传播,由 _hfc_loop 的异常处理逻辑接管 raise - except Exception as e: # 捕获调用管理器或其他地方可能发生的错误 + except Exception as e: # 捕获调用管理器或其他地方可能发生的错误 logger.error(f"{self.log_prefix} 处理 'no_reply' 时发生错误: {e}") logger.error(traceback.format_exc()) # 发生意外错误时,可以选择是否重置计数器,这里选择不重置 - return False # 表示动作未成功 + return False # 表示动作未成功 async def _wait_for_new_message(self, observation, planner_start_db_time: float, log_prefix: str) -> bool: """ @@ -639,7 +642,7 @@ class HeartFChatting: # --- 在每次循环开始时检查关闭标志 --- if self._shutting_down: logger.info(f"{log_prefix} 等待新消息时检测到关闭信号,中断等待。") - return False # 表示因为关闭而退出 + return False # 表示因为关闭而退出 # ----------------------------------- # 检查新消息 @@ -654,7 +657,7 @@ class HeartFChatting: try: # 短暂休眠,让其他任务有机会运行,并能更快响应取消或关闭 - await asyncio.sleep(0.5) # 缩短休眠时间 + await asyncio.sleep(0.5) # 缩短休眠时间 except asyncio.CancelledError: # 如果在休眠时被取消,再次检查关闭标志 # 如果是正常关闭,则不需要警告 @@ -910,7 +913,7 @@ class HeartFChatting: async def shutdown(self): """优雅关闭HeartFChatting实例,取消活动循环任务""" logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...") - self._shutting_down = True # <-- 在开始关闭时设置标志位 + self._shutting_down = True # <-- 在开始关闭时设置标志位 # 取消循环任务 if self._loop_task and not self._loop_task.done():