This commit is contained in:
Windpicker-owo
2025-09-30 21:17:47 +08:00
6 changed files with 83 additions and 18 deletions

View File

@@ -34,8 +34,8 @@ class StreamLoopManager:
}
# 配置参数
self.max_concurrent_streams = max_concurrent_streams or getattr(
global_config.chat, "max_concurrent_distributions", 10
self.max_concurrent_streams = (
max_concurrent_streams or global_config.chat.max_concurrent_distributions
)
# 强制分发策略

View File

@@ -145,6 +145,7 @@ class ChatterActionManager:
action_data: Optional[dict] = None,
thinking_id: Optional[str] = None,
log_prefix: str = "",
clear_unread_messages: bool = True,
) -> Any:
"""
执行单个动作的通用函数
@@ -217,7 +218,8 @@ class ChatterActionManager:
if success:
await self._record_action_to_message(chat_stream, action_name, target_message, action_data)
# 自动清空所有未读消息
await self._clear_all_unread_messages(chat_stream.stream_id, action_name)
if clear_unread_messages:
await self._clear_all_unread_messages(chat_stream.stream_id, action_name)
# 重置打断计数
await self._reset_interruption_count_after_action(chat_stream.stream_id)
@@ -262,8 +264,8 @@ class ChatterActionManager:
# 记录回复动作到目标消息
await self._record_action_to_message(chat_stream, "reply", target_message, action_data)
# 自动清空所有未读消息
await self._clear_all_unread_messages(chat_stream.stream_id, "reply")
if clear_unread_messages:
await self._clear_all_unread_messages(chat_stream.stream_id, "reply")
# 回复成功,重置打断计数
await self._reset_interruption_count_after_action(chat_stream.stream_id)

View File

@@ -158,6 +158,9 @@ class ChatConfig(ValidatedConfigBase):
dynamic_distribution_jitter_factor: float = Field(
default=0.2, ge=0.0, le=0.5, description="分发间隔随机扰动因子"
)
max_concurrent_distributions: int = Field(
default=10, ge=1, le=100, description="最大并发处理的消息流数量"
)
def get_current_talk_frequency(self, chat_stream_id: Optional[str] = None) -> float:
"""

View File

@@ -111,16 +111,26 @@ class ChatterPlanExecutor:
}
async def _execute_reply_actions(self, reply_actions: List[ActionPlannerInfo], plan: Plan) -> Dict[str, any]:
"""执行回复动作"""
"""串行执行所有回复动作"""
results = []
total_actions = len(reply_actions)
if total_actions > 1:
logger.info(f"[多重回复] 开始执行 {total_actions} 个回复任务。")
for action_info in reply_actions:
result = await self._execute_single_reply_action(action_info, plan)
for i, action_info in enumerate(reply_actions):
is_last_action = i == total_actions - 1
if total_actions > 1:
logger.info(f"[多重回复] 正在执行第 {i+1}/{total_actions} 个回复...")
# 传递 clear_unread 参数
result = await self._execute_single_reply_action(action_info, plan, clear_unread=is_last_action)
results.append(result)
if total_actions > 1:
logger.info(f"[多重回复] 所有回复任务执行完毕。")
return {"results": results}
async def _execute_single_reply_action(self, action_info: ActionPlannerInfo, plan: Plan) -> Dict[str, any]:
async def _execute_single_reply_action(self, action_info: ActionPlannerInfo, plan: Plan, clear_unread: bool = True) -> Dict[str, any]:
"""执行单个回复动作"""
start_time = time.time()
success = False
@@ -152,17 +162,29 @@ class ChatterPlanExecutor:
"target_message": action_info.action_message,
"reasoning": action_info.reasoning,
"action_data": action_info.action_data or {},
"clear_unread_messages": clear_unread,
}
logger.debug(f"📬 [PlanExecutor] 准备调用 ActionManagertarget_message: {action_info.action_message}")
# 通过动作管理器执行回复
reply_content = await self.action_manager.execute_action(
execution_result = await self.action_manager.execute_action(
action_name=action_info.action_type, **action_params
)
# 从返回结果中提取真正的回复文本
if isinstance(execution_result, dict):
reply_content = execution_result.get("reply_text", "")
success = execution_result.get("success", False)
else:
# 兼容旧的返回值(虽然可能性不大)
reply_content = str(execution_result) if execution_result else ""
success = bool(reply_content)
success = True
logger.info(f"回复动作 '{action_info.action_type}' 执行成功。")
if success:
logger.info(f"回复动作 '{action_info.action_type}' 执行成功。")
else:
raise Exception(execution_result.get("error", "未知错误"))
except Exception as e:
error_message = str(e)
@@ -181,7 +203,7 @@ class ChatterPlanExecutor:
"error_message": error_message,
"execution_time": execution_time,
"reasoning": action_info.reasoning,
"reply_content": reply_content[:200] + "..." if len(reply_content) > 200 else reply_content,
"reply_content": reply_content[:200] + "..." if reply_content and len(reply_content) > 200 else reply_content,
}
async def _execute_other_actions(self, other_actions: List[ActionPlannerInfo], plan: Plan) -> Dict[str, any]:
@@ -251,6 +273,7 @@ class ChatterPlanExecutor:
"target_message": action_info.action_message,
"reasoning": action_info.reasoning,
"action_data": action_data,
"clear_unread_messages": False, # 其他动作不应清除未读消息
}
# 通过动作管理器执行动作

View File

@@ -44,10 +44,11 @@ def init_prompts():
1. **重要:已读历史消息仅作为当前聊天情景的参考,帮助你理解对话上下文。**
2. **重要:所有动作的执行对象只能是未读历史消息中的消息,不能对已读消息执行动作。**
3. 在未读历史消息中,优先对兴趣值高的消息做出动作(兴趣值标注在消息末尾)。
4. 首先,决定是否要对未读消息进行 `reply`(如果有)。
5. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格
6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合
7. 如果用户明确要求了某个动作,请务必优先满足
4. **核心:如果有多条未读消息都需要回应(例如多人@你),你应该并行处理,在`actions`列表中生成多个`reply`动作。**
5. 首先,决定是否要对未读消息进行 `reply`(如果有)
6. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格
7. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合
8. 如果用户明确要求了某个动作,请务必优先满足。
**重要提醒:**
- **回复消息时必须遵循对话的流程,不要重复已经说过的话。**
@@ -70,6 +71,7 @@ def init_prompts():
## 可用动作列表
{action_options_text}
### 单动作示例:
```json
{{
"thinking": "在这里写下你的思绪流...",
@@ -86,6 +88,40 @@ def init_prompts():
}}
```
### **多重回复示例 (核心功能)**
当有多人与你互动时,你需要同时回应他们,甚至可以同时处理三个!
```json
{{
"thinking": "哇,群里好热闹呀!张三、李四、王五都在@我!让我看看...张三在问我昨天推荐的电影好不好看,这个得好好分享一下观后感。李四在说他家的猫咪学会了新技能,好可爱,得夸夸他!王五好像遇到点麻烦,在问我一个技术问题,这个得优先、详细地解答一下!得一个个来!",
"actions": [
{{
"action_type": "reply",
"reasoning": "回应张三关于电影的提问,并分享我的看法。",
"action_data": {{
"target_message_id": "m124",
"content": "张三!你问的那部电影我昨天也看啦,真的超赞!特别是最后那个反转,简直让人意想不到!"
}}
}},
{{
"action_type": "reply",
"reasoning": "回应李四分享的趣事,表达赞美和羡慕。",
"action_data": {{
"target_message_id": "m125",
"content": "哇,李四你家猫咪也太聪明了吧!居然会握手了!好羡慕呀!"
}}
}},
{{
"action_type": "reply",
"reasoning": "优先回应王五的技术求助,并提供详细的解答。",
"action_data": {{
"target_message_id": "m126",
"content": "王五别急,你说的那个问题我之前也遇到过。你试试看是不是配置文件里的`enable_magic`选项没有设置成`true`?如果还不行你再把错误截图发我看看。"
}}
}}
]
}}
```
**强制规则**:
- 对于每一个需要目标消息的动作(如`reply`, `poke_user`, `set_emoji_like`),你 **必须** 在`action_data`中提供准确的`target_message_id`这个ID来源于`## 未读历史消息`中消息前的`<m...>`标签。
- 当你选择的动作需要参数时(例如 `set_emoji_like` 需要 `emoji` 参数),你 **必须** 在 `action_data` 中提供所有必需的参数及其对应的值。

View File

@@ -1,5 +1,5 @@
[inner]
version = "7.0.2"
version = "7.0.3"
#----以下是给开发人员阅读的如果你只是部署了MoFox-Bot不需要阅读----
#如果你想要修改配置文件请递增version的值
@@ -131,6 +131,7 @@ dynamic_distribution_base_interval = 5.0 # 基础分发间隔(秒)
dynamic_distribution_min_interval = 1.0 # 最小分发间隔(秒)
dynamic_distribution_max_interval = 30.0 # 最大分发间隔(秒)
dynamic_distribution_jitter_factor = 0.2 # 分发间隔随机扰动因子
max_concurrent_distributions = 10 # 最大并发处理的消息流数量可以根据API性能和服务器负载调整
talk_frequency_adjust = [
["", "8:00,1", "12:00,1.2", "18:00,1.5", "01:00,0.6"],