feat:提供方法让HFC结束,当等待过久no_reply,会回到ABSENT模式
This commit is contained in:
@@ -337,7 +337,7 @@ REMOTE_STYLE_CONFIG = {
|
|||||||
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}",
|
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}",
|
||||||
},
|
},
|
||||||
"simple": {
|
"simple": {
|
||||||
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-yellow>远程</light-yellow> | {message}",
|
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #00788A>远程| {message}</fg #00788A>",
|
||||||
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}",
|
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ c HeartFChatting工作方式
|
|||||||
c.5.2.2 通过 HeartFCSender 直接发送匹配查询 (emoji_query) 的表情。
|
c.5.2.2 通过 HeartFCSender 直接发送匹配查询 (emoji_query) 的表情。
|
||||||
c.5.3 如果决策是 no_reply:
|
c.5.3 如果决策是 no_reply:
|
||||||
c.5.3.1 进入等待状态,直到检测到新消息或超时。
|
c.5.3.1 进入等待状态,直到检测到新消息或超时。
|
||||||
|
c.5.3.2 同时,增加内部连续不回复计数器。如果该计数器达到预设阈值(例如 5 次),则调用初始化时由 `SubHeartflowManager` 提供的回调函数。此回调函数会通知 `SubHeartflowManager` 请求将对应的 `SubHeartflow` 状态转换为 `ABSENT`。如果执行了其他动作(如 `text_reply` 或 `emoji_reply`),则此计数器会被重置。
|
||||||
c.6 循环结束后,记录周期信息 (CycleInfo),并根据情况进行短暂休眠,防止CPU空转。
|
c.6 循环结束后,记录周期信息 (CycleInfo),并根据情况进行短暂休眠,防止CPU空转。
|
||||||
|
|
||||||
|
|
||||||
@@ -152,7 +153,7 @@ c HeartFChatting工作方式
|
|||||||
- **状态转换机制** (由 `SubHeartflowManager` 驱动):
|
- **状态转换机制** (由 `SubHeartflowManager` 驱动):
|
||||||
- **激活 `CHAT`**: 当 `Heartflow` 状态从 `OFFLINE` 变为允许聊天的状态时,`SubHeartflowManager` 会根据限制(通过 `self.mai_state_info` 获取),选择部分 `ABSENT` 状态的子心流,**检查当前 CHAT 状态数量是否达到上限**,如果未达上限,则调用其 `change_chat_state` 方法将其转换为 `CHAT`。此外,`evaluate_and_transition_subflows_by_llm` 方法也会根据 LLM 的判断,在未达上限时将 `ABSENT` 状态的子心流激活为 `CHAT`。
|
- **激活 `CHAT`**: 当 `Heartflow` 状态从 `OFFLINE` 变为允许聊天的状态时,`SubHeartflowManager` 会根据限制(通过 `self.mai_state_info` 获取),选择部分 `ABSENT` 状态的子心流,**检查当前 CHAT 状态数量是否达到上限**,如果未达上限,则调用其 `change_chat_state` 方法将其转换为 `CHAT`。此外,`evaluate_and_transition_subflows_by_llm` 方法也会根据 LLM 的判断,在未达上限时将 `ABSENT` 状态的子心流激活为 `CHAT`。
|
||||||
- **激活 `FOCUSED`**: `SubHeartflowManager` 会定期评估处于 `CHAT` 状态的子心流的兴趣度 (`InterestChatting.start_hfc_probability`),若满足条件且**检查当前 FOCUSED 状态数量未达上限**(通过 `self.mai_state_info` 获取限制),则调用 `change_chat_state` 将其提升为 `FOCUSED`。
|
- **激活 `FOCUSED`**: `SubHeartflowManager` 会定期评估处于 `CHAT` 状态的子心流的兴趣度 (`InterestChatting.start_hfc_probability`),若满足条件且**检查当前 FOCUSED 状态数量未达上限**(通过 `self.mai_state_info` 获取限制),则调用 `change_chat_state` 将其提升为 `FOCUSED`。
|
||||||
- **停用/回退**: `SubHeartflowManager` 可能因 `Heartflow` 状态变化、达到数量限制、长时间不活跃、随机概率 (`randomly_deactivate_subflows`) 或 LLM 评估 (`evaluate_and_transition_subflows_by_llm` 判断 `CHAT` 状态子心流应休眠) 等原因,调用 `change_chat_state` 将子心流状态设置为 `ABSENT` 或从 `FOCUSED` 回退到 `CHAT`。当子心流进入 `ABSENT` 状态后,如果持续一小时不活跃,才会被后台清理任务删除。
|
- **停用/回退**: `SubHeartflowManager` 可能因 `Heartflow` 状态变化、达到数量限制、长时间不活跃、随机概率 (`randomly_deactivate_subflows`)、LLM 评估 (`evaluate_and_transition_subflows_by_llm` 判断 `CHAT` 状态子心流应休眠) 或收到来自 `HeartFChatting` 的连续不回复回调信号 (`request_absent_transition`) 等原因,调用 `change_chat_state` 将子心流状态设置为 `ABSENT` 或从 `FOCUSED` 回退到 `CHAT`。当子心流进入 `ABSENT` 状态后,如果持续一小时不活跃,才会被后台清理任务删除。
|
||||||
- **注意**: `change_chat_state` 方法本身只负责执行状态转换和管理内部聊天实例(`NormalChatInstance`/`HeartFlowChatInstance`),不再进行限额检查。限额检查的责任完全由调用方(即 `SubHeartflowManager` 中的相关方法,这些方法会使用内部存储的 `mai_state_info` 来获取限制)承担。
|
- **注意**: `change_chat_state` 方法本身只负责执行状态转换和管理内部聊天实例(`NormalChatInstance`/`HeartFlowChatInstance`),不再进行限额检查。限额检查的责任完全由调用方(即 `SubHeartflowManager` 中的相关方法,这些方法会使用内部存储的 `mai_state_info` 来获取限制)承担。
|
||||||
|
|
||||||
## 3. 聊天实例详解 (Chat Instances Explained)
|
## 3. 聊天实例详解 (Chat Instances Explained)
|
||||||
|
|||||||
@@ -112,15 +112,6 @@ class BackgroundTaskManager:
|
|||||||
f"兴趣评估任务已启动 间隔:{self.interest_eval_interval}s",
|
f"兴趣评估任务已启动 间隔:{self.interest_eval_interval}s",
|
||||||
"_interest_eval_task",
|
"_interest_eval_task",
|
||||||
),
|
),
|
||||||
# 新增随机停用任务配置
|
|
||||||
(
|
|
||||||
self._random_deactivation_task,
|
|
||||||
self._run_random_deactivation_cycle,
|
|
||||||
"hf_random_deactivation",
|
|
||||||
"debug", # 设为debug,避免过多日志
|
|
||||||
f"随机停用任务已启动 间隔:{self.random_deactivation_interval}s",
|
|
||||||
"_random_deactivation_task",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# 统一启动所有任务
|
# 统一启动所有任务
|
||||||
@@ -264,10 +255,6 @@ class BackgroundTaskManager:
|
|||||||
|
|
||||||
# --- 结束新增 ---
|
# --- 结束新增 ---
|
||||||
|
|
||||||
# --- 新增随机停用工作函数 ---
|
|
||||||
async def _perform_random_deactivation_work(self):
|
|
||||||
"""执行一轮子心流随机停用检查。"""
|
|
||||||
await self.subheartflow_manager.randomly_deactivate_subflows()
|
|
||||||
|
|
||||||
# --- 结束新增 ---
|
# --- 结束新增 ---
|
||||||
|
|
||||||
@@ -300,15 +287,3 @@ class BackgroundTaskManager:
|
|||||||
task_func=self._perform_interest_eval_work,
|
task_func=self._perform_interest_eval_work,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- 结束新增 ---
|
|
||||||
|
|
||||||
# --- 新增随机停用任务运行器 ---
|
|
||||||
async def _run_random_deactivation_cycle(self):
|
|
||||||
"""运行随机停用循环。"""
|
|
||||||
await self._run_periodic_loop(
|
|
||||||
task_name="Random Deactivation",
|
|
||||||
interval=self.random_deactivation_interval,
|
|
||||||
task_func=self._perform_random_deactivation_work,
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- 结束新增 ---
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from .observation import Observation, ChattingObservation
|
|||||||
import asyncio
|
import asyncio
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
import time
|
import time
|
||||||
from typing import Optional, List, Dict, Tuple
|
from typing import Optional, List, Dict, Tuple, TYPE_CHECKING, Callable, Coroutine
|
||||||
import traceback
|
import traceback
|
||||||
from src.common.logger import get_module_logger, LogConfig, SUB_HEARTFLOW_STYLE_CONFIG # noqa: E402
|
from src.common.logger import get_module_logger, LogConfig, SUB_HEARTFLOW_STYLE_CONFIG # noqa: E402
|
||||||
import random
|
import random
|
||||||
@@ -15,6 +15,11 @@ from src.heart_flow.mai_state_manager import MaiStateInfo
|
|||||||
from src.heart_flow.chat_state_info import ChatState, ChatStateInfo
|
from src.heart_flow.chat_state_info import ChatState, ChatStateInfo
|
||||||
from src.heart_flow.sub_mind import SubMind
|
from src.heart_flow.sub_mind import SubMind
|
||||||
|
|
||||||
|
# # --- REMOVE: Conditional import --- #
|
||||||
|
# if TYPE_CHECKING:
|
||||||
|
# from src.heart_flow.subheartflow_manager import SubHeartflowManager
|
||||||
|
# # --- END REMOVE --- #
|
||||||
|
|
||||||
|
|
||||||
# 定义常量 (从 interest.py 移动过来)
|
# 定义常量 (从 interest.py 移动过来)
|
||||||
MAX_INTEREST = 15.0
|
MAX_INTEREST = 15.0
|
||||||
@@ -234,16 +239,23 @@ class InterestChatting:
|
|||||||
|
|
||||||
|
|
||||||
class SubHeartflow:
|
class SubHeartflow:
|
||||||
def __init__(self, subheartflow_id, mai_states: MaiStateInfo):
|
def __init__(
|
||||||
|
self,
|
||||||
|
subheartflow_id,
|
||||||
|
mai_states: MaiStateInfo,
|
||||||
|
hfc_no_reply_callback: Callable[[], Coroutine[None, None, None]]
|
||||||
|
):
|
||||||
"""子心流初始化函数
|
"""子心流初始化函数
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
subheartflow_id: 子心流唯一标识符
|
subheartflow_id: 子心流唯一标识符
|
||||||
parent_heartflow: 父级心流实例
|
mai_states: 麦麦状态信息实例
|
||||||
|
hfc_no_reply_callback: HFChatting 连续不回复时触发的回调
|
||||||
"""
|
"""
|
||||||
# 基础属性,两个值是一样的
|
# 基础属性,两个值是一样的
|
||||||
self.subheartflow_id = subheartflow_id
|
self.subheartflow_id = subheartflow_id
|
||||||
self.chat_id = subheartflow_id
|
self.chat_id = subheartflow_id
|
||||||
|
self.hfc_no_reply_callback = hfc_no_reply_callback
|
||||||
|
|
||||||
# 麦麦的状态
|
# 麦麦的状态
|
||||||
self.mai_states = mai_states
|
self.mai_states = mai_states
|
||||||
@@ -364,11 +376,17 @@ class SubHeartflow:
|
|||||||
# 如果实例不存在,则创建并启动
|
# 如果实例不存在,则创建并启动
|
||||||
logger.info(f"{log_prefix} 麦麦准备开始专注聊天 (创建新实例)...")
|
logger.info(f"{log_prefix} 麦麦准备开始专注聊天 (创建新实例)...")
|
||||||
try:
|
try:
|
||||||
|
# 创建 HeartFChatting 实例,并传递 从构造函数传入的 回调函数
|
||||||
self.heart_fc_instance = HeartFChatting(
|
self.heart_fc_instance = HeartFChatting(
|
||||||
chat_id=self.chat_id, sub_mind=self.sub_mind, observations=self.observations
|
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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 初始化并启动 HeartFChatting
|
||||||
if await self.heart_fc_instance._initialize():
|
if await self.heart_fc_instance._initialize():
|
||||||
await self.heart_fc_instance.start() # 初始化成功后启动循环
|
await self.heart_fc_instance.start()
|
||||||
logger.info(f"{log_prefix} 麦麦已成功进入专注聊天模式 (新实例已启动)。")
|
logger.info(f"{log_prefix} 麦麦已成功进入专注聊天模式 (新实例已启动)。")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import time
|
|||||||
import random
|
import random
|
||||||
from typing import Dict, Any, Optional, List
|
from typing import Dict, Any, Optional, List
|
||||||
import json # 导入 json 模块
|
import json # 导入 json 模块
|
||||||
|
import functools # <-- 新增导入
|
||||||
|
|
||||||
# 导入日志模块
|
# 导入日志模块
|
||||||
from src.common.logger import get_module_logger, LogConfig, SUBHEARTFLOW_MANAGER_STYLE_CONFIG
|
from src.common.logger import get_module_logger, LogConfig, SUBHEARTFLOW_MANAGER_STYLE_CONFIG
|
||||||
@@ -77,8 +78,17 @@ class SubHeartflowManager:
|
|||||||
return subflow
|
return subflow
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 初始化子心流, 传入存储的 mai_state_info
|
# --- 使用 functools.partial 创建 HFC 回调 --- #
|
||||||
new_subflow = SubHeartflow(subheartflow_id, self.mai_state_info)
|
# 将 manager 的 _handle_hfc_no_reply 方法与当前的 subheartflow_id 绑定
|
||||||
|
hfc_callback = functools.partial(self._handle_hfc_no_reply, subheartflow_id)
|
||||||
|
# --- 结束创建回调 --- #
|
||||||
|
|
||||||
|
# 初始化子心流, 传入 mai_state_info 和 partial 创建的回调
|
||||||
|
new_subflow = SubHeartflow(
|
||||||
|
subheartflow_id,
|
||||||
|
self.mai_state_info,
|
||||||
|
hfc_callback # <-- 传递 partial 创建的回调
|
||||||
|
)
|
||||||
|
|
||||||
# 异步初始化
|
# 异步初始化
|
||||||
await new_subflow.initialize()
|
await new_subflow.initialize()
|
||||||
@@ -285,74 +295,11 @@ class SubHeartflowManager:
|
|||||||
) and final_subflow.chat_state.chat_status == ChatState.FOCUSED:
|
) and final_subflow.chat_state.chat_status == ChatState.FOCUSED:
|
||||||
current_focused_count += 1
|
current_focused_count += 1
|
||||||
|
|
||||||
async def randomly_deactivate_subflows(self, deactivation_probability: float = 0.1):
|
|
||||||
"""以一定概率将 FOCUSED 或 CHAT 状态的子心流回退到 ABSENT 状态。"""
|
|
||||||
log_prefix_manager = "[子心流管理器-随机停用]"
|
|
||||||
logger.debug(f"{log_prefix_manager} 开始随机停用检查... (概率: {deactivation_probability:.0%})")
|
|
||||||
|
|
||||||
# 使用快照安全遍历
|
|
||||||
subflows_snapshot = list(self.subheartflows.values())
|
|
||||||
deactivated_count = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
for sub_hf in subflows_snapshot:
|
|
||||||
flow_id = sub_hf.subheartflow_id
|
|
||||||
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
|
||||||
log_prefix_flow = f"[{stream_name}]"
|
|
||||||
current_state = sub_hf.chat_state.chat_status
|
|
||||||
|
|
||||||
# 只处理 FOCUSED 或 CHAT 状态
|
|
||||||
if current_state not in [ChatState.FOCUSED, ChatState.CHAT]:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 检查随机概率
|
|
||||||
if random.random() < deactivation_probability:
|
|
||||||
logger.info(
|
|
||||||
f"{log_prefix_manager} {log_prefix_flow} 随机触发停用 (从 {current_state.value}) -> ABSENT"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 获取当前实例以检查最新状态
|
|
||||||
current_subflow = self.subheartflows.get(flow_id)
|
|
||||||
if not current_subflow or current_subflow.chat_state.chat_status != current_state:
|
|
||||||
logger.warning(f"{log_prefix_manager} {log_prefix_flow} 尝试停用时状态已改变或实例消失,跳过。")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# --- 状态设置 --- #
|
|
||||||
# 注意:这里传递的状态数量是 *停用前* 的状态数量
|
|
||||||
await current_subflow.change_chat_state(ChatState.ABSENT)
|
|
||||||
|
|
||||||
# --- 状态验证 (可选) ---
|
|
||||||
final_subflow = self.subheartflows.get(flow_id)
|
|
||||||
if final_subflow:
|
|
||||||
final_state = final_subflow.chat_state.chat_status
|
|
||||||
if final_state == ChatState.ABSENT:
|
|
||||||
logger.debug(
|
|
||||||
f"{log_prefix_manager} {log_prefix_flow} 成功从 {current_state.value} 停用到 ABSENT 状态"
|
|
||||||
)
|
|
||||||
deactivated_count += 1
|
|
||||||
else:
|
|
||||||
logger.warning(
|
|
||||||
f"{log_prefix_manager} {log_prefix_flow} 尝试停用到 ABSENT 后状态仍为 {final_state.value}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.warning(f"{log_prefix_manager} {log_prefix_flow} 停用后验证时子心流 {flow_id} 消失")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"{log_prefix_manager} 随机停用周期出错: {e}", exc_info=True)
|
|
||||||
|
|
||||||
if deactivated_count > 0:
|
|
||||||
logger.info(f"{log_prefix_manager} 随机停用周期结束, 成功停用 {deactivated_count} 个子心流。")
|
|
||||||
else:
|
|
||||||
logger.debug(f"{log_prefix_manager} 随机停用周期结束, 未停用任何子心流。")
|
|
||||||
|
|
||||||
async def evaluate_and_transition_subflows_by_llm(self):
|
async def evaluate_and_transition_subflows_by_llm(self):
|
||||||
"""
|
"""
|
||||||
使用LLM评估每个子心流的状态,并根据LLM的判断执行状态转换(ABSENT <-> CHAT)。
|
使用LLM评估每个子心流的状态,并根据LLM的判断执行状态转换(ABSENT <-> CHAT)。
|
||||||
注意:此函数包含对假设的LLM函数的调用。
|
注意:此函数包含对假设的LLM函数的调用。
|
||||||
"""
|
"""
|
||||||
log_prefix = "[LLM状态评估]"
|
|
||||||
logger.info(f"{log_prefix} 开始基于LLM评估子心流状态...")
|
|
||||||
|
|
||||||
# 获取当前状态和限制,用于CHAT激活检查
|
# 获取当前状态和限制,用于CHAT激活检查
|
||||||
current_mai_state = self.mai_state_info.get_current_state()
|
current_mai_state = self.mai_state_info.get_current_state()
|
||||||
chat_limit = current_mai_state.get_normal_chat_max_num()
|
chat_limit = current_mai_state.get_normal_chat_max_num()
|
||||||
@@ -366,33 +313,27 @@ class SubHeartflowManager:
|
|||||||
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
||||||
|
|
||||||
if not subflows_snapshot:
|
if not subflows_snapshot:
|
||||||
logger.info(f"{log_prefix} 当前没有子心流需要评估。")
|
logger.info("当前没有子心流需要评估。")
|
||||||
return
|
return
|
||||||
|
|
||||||
for sub_hf in subflows_snapshot:
|
for sub_hf in subflows_snapshot:
|
||||||
flow_id = sub_hf.subheartflow_id
|
flow_id = sub_hf.subheartflow_id
|
||||||
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
||||||
|
log_prefix = f"[{stream_name}]"
|
||||||
current_subflow_state = sub_hf.chat_state.chat_status
|
current_subflow_state = sub_hf.chat_state.chat_status
|
||||||
|
|
||||||
# --- 获取观察内容 ---
|
|
||||||
# 从 sub_hf.observations 获取 ChattingObservation 并提取信息
|
|
||||||
_observation_summary = "没有可用的观察信息。" # 默认值
|
_observation_summary = "没有可用的观察信息。" # 默认值
|
||||||
try:
|
|
||||||
# 检查 observations 列表是否存在且不为空
|
|
||||||
|
|
||||||
# 假设第一个观察者是 ChattingObservation
|
first_observation = sub_hf.observations[0]
|
||||||
first_observation = sub_hf.observations[0]
|
if isinstance(first_observation, ChattingObservation):
|
||||||
if isinstance(first_observation, ChattingObservation):
|
# 组合中期记忆和当前聊天内容
|
||||||
# 组合中期记忆和当前聊天内容
|
current_chat = first_observation.talking_message_str or "当前无聊天内容。"
|
||||||
current_chat = first_observation.talking_message_str or "当前无聊天内容。"
|
combined_summary = f"当前聊天内容:\n{current_chat}"
|
||||||
combined_summary = f"当前聊天内容:\n{current_chat}"
|
else:
|
||||||
else:
|
logger.warning(f"{log_prefix} [{stream_name}] 第一个观察者不是 ChattingObservation 类型。")
|
||||||
logger.warning(f"{log_prefix} [{stream_name}] 第一个观察者不是 ChattingObservation 类型。")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"{log_prefix} [{stream_name}] 获取观察信息失败: {e}", exc_info=True)
|
|
||||||
# 保留默认值或错误信息
|
|
||||||
combined_summary = f"获取观察信息时出错: {e}"
|
|
||||||
|
|
||||||
# --- 获取麦麦状态 ---
|
# --- 获取麦麦状态 ---
|
||||||
mai_state_description = f"麦麦当前状态: {current_mai_state.value}。"
|
mai_state_description = f"麦麦当前状态: {current_mai_state.value}。"
|
||||||
@@ -414,7 +355,7 @@ class SubHeartflowManager:
|
|||||||
# 调用LLM评估
|
# 调用LLM评估
|
||||||
should_activate = await self._llm_evaluate_state_transition(prompt)
|
should_activate = await self._llm_evaluate_state_transition(prompt)
|
||||||
if should_activate is None: # 处理解析失败或意外情况
|
if should_activate is None: # 处理解析失败或意外情况
|
||||||
logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。")
|
logger.warning(f"{log_prefix}LLM评估返回无效结果,跳过。")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if should_activate:
|
if should_activate:
|
||||||
@@ -423,17 +364,19 @@ class SubHeartflowManager:
|
|||||||
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
||||||
if current_chat_count < chat_limit:
|
if current_chat_count < chat_limit:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换..."
|
f"{log_prefix}LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换..."
|
||||||
)
|
)
|
||||||
await sub_hf.change_chat_state(ChatState.CHAT)
|
await sub_hf.change_chat_state(ChatState.CHAT)
|
||||||
if sub_hf.chat_state.chat_status == ChatState.CHAT:
|
if sub_hf.chat_state.chat_status == ChatState.CHAT:
|
||||||
transitioned_to_chat += 1
|
transitioned_to_chat += 1
|
||||||
else:
|
else:
|
||||||
logger.warning(f"{log_prefix} [{stream_name}] 尝试激活到CHAT失败。")
|
logger.warning(f"{log_prefix}尝试激活到CHAT失败。")
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。"
|
f"{log_prefix}LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。"
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
logger.info(f"{log_prefix}LLM建议不激活到CHAT状态。")
|
||||||
|
|
||||||
# --- 针对 CHAT 状态 ---
|
# --- 针对 CHAT 状态 ---
|
||||||
elif current_subflow_state == ChatState.CHAT:
|
elif current_subflow_state == ChatState.CHAT:
|
||||||
@@ -452,20 +395,18 @@ class SubHeartflowManager:
|
|||||||
# 调用LLM评估
|
# 调用LLM评估
|
||||||
should_deactivate = await self._llm_evaluate_state_transition(prompt)
|
should_deactivate = await self._llm_evaluate_state_transition(prompt)
|
||||||
if should_deactivate is None: # 处理解析失败或意外情况
|
if should_deactivate is None: # 处理解析失败或意外情况
|
||||||
logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。")
|
logger.warning(f"{log_prefix}LLM评估返回无效结果,跳过。")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if should_deactivate:
|
if should_deactivate:
|
||||||
logger.info(f"{log_prefix} [{stream_name}] LLM建议进入ABSENT状态。正在尝试转换...")
|
logger.info(f"{log_prefix}LLM建议进入ABSENT状态。正在尝试转换...")
|
||||||
await sub_hf.change_chat_state(ChatState.ABSENT)
|
await sub_hf.change_chat_state(ChatState.ABSENT)
|
||||||
if sub_hf.chat_state.chat_status == ChatState.ABSENT:
|
if sub_hf.chat_state.chat_status == ChatState.ABSENT:
|
||||||
transitioned_to_absent += 1
|
transitioned_to_absent += 1
|
||||||
|
else:
|
||||||
|
logger.info(f"{log_prefix}LLM建议不进入ABSENT状态。")
|
||||||
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"{log_prefix} LLM评估周期结束。"
|
|
||||||
f" 成功转换到CHAT: {transitioned_to_chat}."
|
|
||||||
f" 成功转换到ABSENT: {transitioned_to_absent}."
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _llm_evaluate_state_transition(self, prompt: str) -> Optional[bool]:
|
async def _llm_evaluate_state_transition(self, prompt: str) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
@@ -482,7 +423,8 @@ class SubHeartflowManager:
|
|||||||
try:
|
try:
|
||||||
# --- 真实的 LLM 调用 ---
|
# --- 真实的 LLM 调用 ---
|
||||||
response_text, _ = await self.llm_state_evaluator.generate_response_async(prompt)
|
response_text, _ = await self.llm_state_evaluator.generate_response_async(prompt)
|
||||||
logger.debug(f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估,原始响应: ```{response_text}```")
|
logger.debug(f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估")
|
||||||
|
logger.debug(f"{log_prefix} 原始响应: {response_text}")
|
||||||
|
|
||||||
# --- 解析 JSON 响应 ---
|
# --- 解析 JSON 响应 ---
|
||||||
try:
|
try:
|
||||||
@@ -573,3 +515,46 @@ class SubHeartflowManager:
|
|||||||
logger.error(f"删除 SubHeartflow {subheartflow_id} 时出错: {e}", exc_info=True)
|
logger.error(f"删除 SubHeartflow {subheartflow_id} 时出错: {e}", exc_info=True)
|
||||||
else:
|
else:
|
||||||
logger.warning(f"尝试删除不存在的 SubHeartflow: {subheartflow_id}")
|
logger.warning(f"尝试删除不存在的 SubHeartflow: {subheartflow_id}")
|
||||||
|
|
||||||
|
# --- 新增:处理 HFC 无回复回调的专用方法 --- #
|
||||||
|
async def _handle_hfc_no_reply(self, subheartflow_id: Any):
|
||||||
|
"""处理来自 HeartFChatting 的连续无回复信号 (通过 partial 绑定 ID)"""
|
||||||
|
# 注意:这里不需要再获取锁,因为 request_absent_transition 内部会处理锁
|
||||||
|
logger.debug(f"[管理器 HFC 处理器] 接收到来自 {subheartflow_id} 的 HFC 无回复信号")
|
||||||
|
await self.request_absent_transition(subheartflow_id)
|
||||||
|
# --- 结束新增 --- #
|
||||||
|
|
||||||
|
# --- 新增:处理来自 HeartFChatting 的状态转换请求 --- #
|
||||||
|
async def request_absent_transition(self, subflow_id: Any):
|
||||||
|
"""
|
||||||
|
接收来自 HeartFChatting 的请求,将特定子心流的状态转换为 ABSENT。
|
||||||
|
通常在连续多次 "no_reply" 后被调用。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subflow_id: 需要转换状态的子心流 ID。
|
||||||
|
"""
|
||||||
|
async with self._lock:
|
||||||
|
subflow = self.subheartflows.get(subflow_id)
|
||||||
|
if not subflow:
|
||||||
|
logger.warning(f"[状态转换请求] 尝试转换不存在的子心流 {subflow_id} 到 ABSENT")
|
||||||
|
return
|
||||||
|
|
||||||
|
stream_name = chat_manager.get_stream_name(subflow_id) or subflow_id
|
||||||
|
current_state = subflow.chat_state.chat_status
|
||||||
|
|
||||||
|
# 仅当子心流处于 FOCUSED 状态时才进行转换
|
||||||
|
# 因为 HeartFChatting 只在 FOCUSED 状态下运行
|
||||||
|
if current_state == ChatState.FOCUSED:
|
||||||
|
logger.info(f"[状态转换请求] 接收到请求,将 {stream_name} (当前: {current_state.value}) 转换为 ABSENT")
|
||||||
|
try:
|
||||||
|
await subflow.change_chat_state(ChatState.ABSENT)
|
||||||
|
logger.info(f"[状态转换请求] {stream_name} 状态已成功转换为 ABSENT")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[状态转换请求] 转换 {stream_name} 到 ABSENT 时出错: {e}", exc_info=True)
|
||||||
|
elif current_state == ChatState.ABSENT:
|
||||||
|
logger.debug(f"[状态转换请求] {stream_name} 已处于 ABSENT 状态,无需转换")
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"[状态转换请求] 收到对 {stream_name} 的请求,但其状态为 {current_state.value} (非 FOCUSED),不执行转换"
|
||||||
|
)
|
||||||
|
# --- 结束新增 --- #
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import asyncio
|
|||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import random # <-- 添加导入
|
import random # <-- 添加导入
|
||||||
from typing import List, Optional, Dict, Any, Deque
|
from typing import List, Optional, Dict, Any, Deque, Callable, Coroutine
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from src.plugins.chat.message import MessageRecv, BaseMessageInfo, MessageThinking, MessageSending
|
from src.plugins.chat.message import MessageRecv, BaseMessageInfo, MessageThinking, MessageSending
|
||||||
from src.plugins.chat.message import Seg # Local import needed after move
|
from src.plugins.chat.message import Seg # Local import needed after move
|
||||||
@@ -25,7 +25,6 @@ import contextlib
|
|||||||
from src.plugins.utils.chat_message_builder import num_new_messages_since
|
from src.plugins.utils.chat_message_builder import num_new_messages_since
|
||||||
from src.plugins.heartFC_chat.heartFC_Cycleinfo import CycleInfo
|
from src.plugins.heartFC_chat.heartFC_Cycleinfo import CycleInfo
|
||||||
from .heartFC_sender import HeartFCSender
|
from .heartFC_sender import HeartFCSender
|
||||||
# --- End import ---
|
|
||||||
|
|
||||||
|
|
||||||
INITIAL_DURATION = 60.0
|
INITIAL_DURATION = 60.0
|
||||||
@@ -155,18 +154,30 @@ class HeartFChatting:
|
|||||||
其生命周期现在由其关联的 SubHeartflow 的 FOCUSED 状态控制。
|
其生命周期现在由其关联的 SubHeartflow 的 FOCUSED 状态控制。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, chat_id: str, sub_mind: SubMind, observations: Observation):
|
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]]
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
HeartFChatting 初始化函数
|
HeartFChatting 初始化函数
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
chat_id: 聊天流唯一标识符(如stream_id)
|
chat_id: 聊天流唯一标识符(如stream_id)
|
||||||
|
sub_mind: 关联的子思维
|
||||||
|
observations: 关联的观察列表
|
||||||
|
on_consecutive_no_reply_callback: 连续不回复达到阈值时调用的异步回调函数
|
||||||
"""
|
"""
|
||||||
# 基础属性
|
# 基础属性
|
||||||
self.stream_id: str = chat_id # 聊天流ID
|
self.stream_id: str = chat_id # 聊天流ID
|
||||||
self.chat_stream: Optional[ChatStream] = None # 关联的聊天流
|
self.chat_stream: Optional[ChatStream] = None # 关联的聊天流
|
||||||
self.sub_mind: SubMind = sub_mind # 关联的子思维
|
self.sub_mind: SubMind = sub_mind # 关联的子思维
|
||||||
self.observations: List[Observation] = observations # 关联的观察列表,用于监控聊天流状态
|
self.observations: List[Observation] = observations # 关联的观察列表,用于监控聊天流状态
|
||||||
|
self.on_consecutive_no_reply_callback = on_consecutive_no_reply_callback
|
||||||
|
|
||||||
# 日志前缀
|
# 日志前缀
|
||||||
self.log_prefix: str = f"[{chat_manager.get_stream_name(chat_id) or chat_id}]"
|
self.log_prefix: str = f"[{chat_manager.get_stream_name(chat_id) or chat_id}]"
|
||||||
@@ -198,6 +209,8 @@ class HeartFChatting:
|
|||||||
self._cycle_counter = 0
|
self._cycle_counter = 0
|
||||||
self._cycle_history: Deque[CycleInfo] = deque(maxlen=10) # 保留最近10个循环的信息
|
self._cycle_history: Deque[CycleInfo] = deque(maxlen=10) # 保留最近10个循环的信息
|
||||||
self._current_cycle: Optional[CycleInfo] = None
|
self._current_cycle: Optional[CycleInfo] = None
|
||||||
|
self._lian_xu_bu_hui_fu_ci_shu: int = 0 # <--- 新增:连续不回复计数器
|
||||||
|
self._shutting_down: bool = False # <--- 新增:关闭标志位
|
||||||
|
|
||||||
async def _initialize(self) -> bool:
|
async def _initialize(self) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -276,6 +289,12 @@ class HeartFChatting:
|
|||||||
"""主循环,持续进行计划并可能回复消息,直到被外部取消。"""
|
"""主循环,持续进行计划并可能回复消息,直到被外部取消。"""
|
||||||
try:
|
try:
|
||||||
while True: # 主循环
|
while True: # 主循环
|
||||||
|
# --- 在循环开始处检查关闭标志 ---
|
||||||
|
if self._shutting_down:
|
||||||
|
logger.info(f"{self.log_prefix} 检测到关闭标志,退出 HFC 循环。")
|
||||||
|
break
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
# 创建新的循环信息
|
# 创建新的循环信息
|
||||||
self._cycle_counter += 1
|
self._cycle_counter += 1
|
||||||
self._current_cycle = CycleInfo(self._cycle_counter)
|
self._current_cycle = CycleInfo(self._cycle_counter)
|
||||||
@@ -287,6 +306,12 @@ class HeartFChatting:
|
|||||||
# 执行规划和处理阶段
|
# 执行规划和处理阶段
|
||||||
async with self._get_cycle_context() as acquired_lock:
|
async with self._get_cycle_context() as acquired_lock:
|
||||||
if not acquired_lock:
|
if not acquired_lock:
|
||||||
|
# 如果未能获取锁(理论上不太可能,除非 shutdown 过程中释放了但又被抢了?)
|
||||||
|
# 或者也可以在这里再次检查 self._shutting_down
|
||||||
|
if self._shutting_down:
|
||||||
|
break # 再次检查,确保退出
|
||||||
|
logger.warning(f"{self.log_prefix} 未能获取循环处理锁,跳过本次循环。")
|
||||||
|
await asyncio.sleep(0.1) # 短暂等待避免空转
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 记录规划开始时间点
|
# 记录规划开始时间点
|
||||||
@@ -320,7 +345,11 @@ class HeartFChatting:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦的认真水群(HFC)被取消了")
|
# 设置了关闭标志位后被取消是正常流程
|
||||||
|
if not self._shutting_down:
|
||||||
|
logger.warning(f"{self.log_prefix} HeartFChatting: 麦麦的认真水群(HFC)循环意外被取消")
|
||||||
|
else:
|
||||||
|
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦的认真水群(HFC)循环已取消 (正常关闭)")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.log_prefix} HeartFChatting: 意外错误: {e}")
|
logger.error(f"{self.log_prefix} HeartFChatting: 意外错误: {e}")
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
@@ -451,6 +480,8 @@ class HeartFChatting:
|
|||||||
return await handler(reasoning, planner_start_db_time, cycle_timers), ""
|
return await handler(reasoning, planner_start_db_time, cycle_timers), ""
|
||||||
except HeartFCError as e:
|
except HeartFCError as e:
|
||||||
logger.error(f"{self.log_prefix} 处理{action}时出错: {e}")
|
logger.error(f"{self.log_prefix} 处理{action}时出错: {e}")
|
||||||
|
# 出错时也重置计数器
|
||||||
|
self._lian_xu_bu_hui_fu_ci_shu = 0
|
||||||
return False, ""
|
return False, ""
|
||||||
|
|
||||||
async def _handle_text_reply(self, reasoning: str, emoji_query: str, cycle_timers: dict) -> tuple[bool, str]:
|
async def _handle_text_reply(self, reasoning: str, emoji_query: str, cycle_timers: dict) -> tuple[bool, str]:
|
||||||
@@ -471,6 +502,8 @@ class HeartFChatting:
|
|||||||
返回:
|
返回:
|
||||||
tuple[bool, str]: (是否回复成功, 思考消息ID)
|
tuple[bool, str]: (是否回复成功, 思考消息ID)
|
||||||
"""
|
"""
|
||||||
|
# 重置连续不回复计数器
|
||||||
|
self._lian_xu_bu_hui_fu_ci_shu = 0
|
||||||
|
|
||||||
# 获取锚点消息
|
# 获取锚点消息
|
||||||
anchor_message = await self._get_anchor_message()
|
anchor_message = await self._get_anchor_message()
|
||||||
@@ -544,8 +577,9 @@ class HeartFChatting:
|
|||||||
处理不回复的情况
|
处理不回复的情况
|
||||||
|
|
||||||
工作流程:
|
工作流程:
|
||||||
1. 等待新消息
|
1. 等待新消息、超时或关闭信号
|
||||||
2. 超时或收到新消息时返回
|
2. 根据等待结果更新连续不回复计数
|
||||||
|
3. 如果达到阈值,触发回调
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
reasoning: 不回复的原因
|
reasoning: 不回复的原因
|
||||||
@@ -561,14 +595,36 @@ class HeartFChatting:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with Timer("等待新消息", cycle_timers):
|
with Timer("等待新消息", cycle_timers):
|
||||||
return await self._wait_for_new_message(observation, planner_start_db_time, self.log_prefix)
|
# 等待新消息、超时或关闭信号,并获取结果
|
||||||
|
await self._wait_for_new_message(observation, planner_start_db_time, self.log_prefix)
|
||||||
|
|
||||||
|
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}")
|
||||||
|
|
||||||
|
# 检查是否达到阈值
|
||||||
|
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}次),调用回调请求状态转换")
|
||||||
|
# 调用回调。注意:这里不重置计数器,依赖回调函数成功改变状态来隐式重置上下文。
|
||||||
|
await self.on_consecutive_no_reply_callback()
|
||||||
|
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logger.info(f"{self.log_prefix} 等待被中断")
|
# 如果在等待过程中任务被取消(可能是因为 shutdown)
|
||||||
|
logger.info(f"{self.log_prefix} 处理 'no_reply' 时等待被中断 (CancelledError)")
|
||||||
|
# 让异常向上传播,由 _hfc_loop 的异常处理逻辑接管
|
||||||
raise
|
raise
|
||||||
|
except Exception as e: # 捕获调用管理器或其他地方可能发生的错误
|
||||||
|
logger.error(f"{self.log_prefix} 处理 'no_reply' 时发生错误: {e}")
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
# 发生意外错误时,可以选择是否重置计数器,这里选择不重置
|
||||||
|
return False # 表示动作未成功
|
||||||
|
|
||||||
async def _wait_for_new_message(self, observation, planner_start_db_time: float, log_prefix: str) -> bool:
|
async def _wait_for_new_message(self, observation, planner_start_db_time: float, log_prefix: str) -> bool:
|
||||||
"""
|
"""
|
||||||
等待新消息
|
等待新消息 或 检测到关闭信号
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
observation: 观察实例
|
observation: 观察实例
|
||||||
@@ -576,19 +632,36 @@ class HeartFChatting:
|
|||||||
log_prefix: 日志前缀
|
log_prefix: 日志前缀
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否检测到新消息
|
bool: 是否检测到新消息 (如果因关闭信号退出则返回 False)
|
||||||
"""
|
"""
|
||||||
wait_start_time = time.monotonic()
|
wait_start_time = time.monotonic()
|
||||||
while True:
|
while True:
|
||||||
|
# --- 在每次循环开始时检查关闭标志 ---
|
||||||
|
if self._shutting_down:
|
||||||
|
logger.info(f"{log_prefix} 等待新消息时检测到关闭信号,中断等待。")
|
||||||
|
return False # 表示因为关闭而退出
|
||||||
|
# -----------------------------------
|
||||||
|
|
||||||
|
# 检查新消息
|
||||||
if await observation.has_new_messages_since(planner_start_db_time):
|
if await observation.has_new_messages_since(planner_start_db_time):
|
||||||
logger.info(f"{log_prefix} 检测到新消息")
|
logger.info(f"{log_prefix} 检测到新消息")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# 检查超时 (放在检查新消息和关闭之后)
|
||||||
if time.monotonic() - wait_start_time > 120:
|
if time.monotonic() - wait_start_time > 120:
|
||||||
logger.warning(f"{log_prefix} 等待超时(120秒)")
|
logger.warning(f"{log_prefix} 等待新消息超时(20秒)")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
await asyncio.sleep(1.5)
|
try:
|
||||||
|
# 短暂休眠,让其他任务有机会运行,并能更快响应取消或关闭
|
||||||
|
await asyncio.sleep(0.5) # 缩短休眠时间
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
# 如果在休眠时被取消,再次检查关闭标志
|
||||||
|
# 如果是正常关闭,则不需要警告
|
||||||
|
if not self._shutting_down:
|
||||||
|
logger.warning(f"{log_prefix} _wait_for_new_message 的休眠被意外取消")
|
||||||
|
# 无论如何,重新抛出异常,让上层处理
|
||||||
|
raise
|
||||||
|
|
||||||
async def _log_cycle_timers(self, cycle_timers: dict, log_prefix: str):
|
async def _log_cycle_timers(self, cycle_timers: dict, log_prefix: str):
|
||||||
"""记录循环周期的计时器结果"""
|
"""记录循环周期的计时器结果"""
|
||||||
@@ -599,7 +672,9 @@ class HeartFChatting:
|
|||||||
timer_strings.append(f"{name}: {formatted_time}")
|
timer_strings.append(f"{name}: {formatted_time}")
|
||||||
|
|
||||||
if timer_strings:
|
if timer_strings:
|
||||||
logger.debug(f"{log_prefix} 该次决策耗时: {'; '.join(timer_strings)}")
|
# 在记录前检查关闭标志
|
||||||
|
if not self._shutting_down:
|
||||||
|
logger.debug(f"{log_prefix} 该次决策耗时: {'; '.join(timer_strings)}")
|
||||||
|
|
||||||
async def _handle_cycle_delay(self, action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str):
|
async def _handle_cycle_delay(self, action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str):
|
||||||
"""处理循环延迟"""
|
"""处理循环延迟"""
|
||||||
@@ -835,6 +910,7 @@ class HeartFChatting:
|
|||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
"""优雅关闭HeartFChatting实例,取消活动循环任务"""
|
"""优雅关闭HeartFChatting实例,取消活动循环任务"""
|
||||||
logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...")
|
logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...")
|
||||||
|
self._shutting_down = True # <-- 在开始关闭时设置标志位
|
||||||
|
|
||||||
# 取消循环任务
|
# 取消循环任务
|
||||||
if self._loop_task and not self._loop_task.done():
|
if self._loop_task and not self._loop_task.done():
|
||||||
@@ -865,6 +941,25 @@ class HeartFChatting:
|
|||||||
action=action,
|
action=action,
|
||||||
reasoning=reasoning,
|
reasoning=reasoning,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 在记录循环日志前检查关闭标志
|
||||||
|
if not self._shutting_down:
|
||||||
|
self._current_cycle.complete_cycle()
|
||||||
|
self._cycle_history.append(self._current_cycle)
|
||||||
|
|
||||||
|
# 记录循环信息和计时器结果
|
||||||
|
timer_strings = []
|
||||||
|
for name, elapsed in self._current_cycle.timers.items():
|
||||||
|
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒"
|
||||||
|
timer_strings.append(f"{name}: {formatted_time}")
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
f"{self.log_prefix} 第 #{self._current_cycle.cycle_id}次思考完成,"
|
||||||
|
f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.2f}秒, "
|
||||||
|
f"动作: {self._current_cycle.action_type}"
|
||||||
|
+ (f"\n计时器详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
||||||
|
)
|
||||||
|
|
||||||
return prompt
|
return prompt
|
||||||
|
|
||||||
async def _build_planner_prompt(
|
async def _build_planner_prompt(
|
||||||
|
|||||||
Reference in New Issue
Block a user