myagent-ai 1.15.43 → 1.15.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/main_agent.py +63 -46
- package/package.json +1 -1
package/agents/main_agent.py
CHANGED
|
@@ -462,6 +462,8 @@ class MainAgent(BaseAgent):
|
|
|
462
462
|
_v2_reasoning_collected: List[str] = []
|
|
463
463
|
# XML 解析失败时的 LLM 修正重试计数
|
|
464
464
|
_xml_correction_retries: int = 0
|
|
465
|
+
# 连续无工具调用计数(防止模型一直不调用工具导致死循环)
|
|
466
|
+
_consecutive_no_tool_count: int = 0
|
|
465
467
|
|
|
466
468
|
conversation_history = list(context.conversation_history or [])
|
|
467
469
|
|
|
@@ -905,27 +907,68 @@ class MainAgent(BaseAgent):
|
|
|
905
907
|
)
|
|
906
908
|
break
|
|
907
909
|
|
|
908
|
-
# Step 10:
|
|
910
|
+
# Step 10: 执行工具调用
|
|
909
911
|
if not parsed.tools_to_call:
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
912
|
+
_consecutive_no_tool_count += 1
|
|
913
|
+
# 如果 finish=true 且无工具,任务完成
|
|
914
|
+
if parsed.finish:
|
|
915
|
+
logger.info(f"[{task_id}] finish=true 且无工具调用,任务完成")
|
|
916
|
+
if _v2_reasoning_collected:
|
|
917
|
+
final_text = "\n".join(_v2_reasoning_collected)
|
|
918
|
+
else:
|
|
919
|
+
before, after = extract_surrounding_text(llm_raw)
|
|
920
|
+
final_text = (before + "\n" + after).strip() if (before.strip() or after.strip()) else "已完成所有操作。"
|
|
921
|
+
context.working_memory["final_response"] = final_text
|
|
922
|
+
if not _emitted_reasoning_this_iter:
|
|
923
|
+
await self._emit_v2_event("v2_reasoning", {"content": truncate_str(final_text, 3000)}, stream_callback)
|
|
924
|
+
if self.memory:
|
|
925
|
+
self.memory.add_session(
|
|
926
|
+
session_id=context.session_id,
|
|
927
|
+
role="assistant",
|
|
928
|
+
content=final_text,
|
|
929
|
+
)
|
|
930
|
+
break
|
|
931
|
+
elif _consecutive_no_tool_count >= 2:
|
|
932
|
+
# 连续 2 轮无工具调用,视为模型无意继续执行任务
|
|
933
|
+
logger.warning(
|
|
934
|
+
f"[{task_id}] 连续 {_consecutive_no_tool_count} 轮无工具调用且未 finish,"
|
|
935
|
+
f"视为任务结束"
|
|
936
|
+
)
|
|
937
|
+
if _v2_reasoning_collected:
|
|
938
|
+
final_text = "\n".join(_v2_reasoning_collected)
|
|
939
|
+
else:
|
|
940
|
+
before, after = extract_surrounding_text(llm_raw)
|
|
941
|
+
final_text = (before + "\n" + after).strip() if (before.strip() or after.strip()) else "任务已完成。"
|
|
942
|
+
context.working_memory["final_response"] = final_text
|
|
943
|
+
if not _emitted_reasoning_this_iter:
|
|
944
|
+
await self._emit_v2_event("v2_reasoning", {"content": truncate_str(final_text, 3000)}, stream_callback)
|
|
945
|
+
if self.memory:
|
|
946
|
+
self.memory.add_session(
|
|
947
|
+
session_id=context.session_id,
|
|
948
|
+
role="assistant",
|
|
949
|
+
content=final_text,
|
|
950
|
+
)
|
|
951
|
+
break
|
|
913
952
|
else:
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
await self._emit_v2_event("v2_reasoning", {"content": truncate_str(final_text, 3000)}, stream_callback)
|
|
920
|
-
if self.memory:
|
|
921
|
-
self.memory.add_session(
|
|
922
|
-
session_id=context.session_id,
|
|
923
|
-
role="assistant",
|
|
924
|
-
content=final_text,
|
|
953
|
+
# 未 finish 且未达到连续无工具阈值,继续回调 LLM
|
|
954
|
+
# 模型可能只是在中间步骤输出说明文字,下一轮才调用工具
|
|
955
|
+
logger.info(
|
|
956
|
+
f"[{task_id}] 无工具调用且未 finish(连续第 {_consecutive_no_tool_count} 轮),"
|
|
957
|
+
f"继续回调 LLM"
|
|
925
958
|
)
|
|
926
|
-
|
|
959
|
+
# 将当前输出作为对话历史,回调 LLM 继续执行
|
|
960
|
+
if llm_raw.strip():
|
|
961
|
+
conversation_history.append(Message(role="assistant", content=llm_raw))
|
|
962
|
+
conversation_history.append(Message(
|
|
963
|
+
role="user",
|
|
964
|
+
content="[系统提示] 你上一轮输出没有包含任何工具调用,也没有设置 finish=true。"
|
|
965
|
+
"如果任务尚未完成,请继续执行必要的工具调用。"
|
|
966
|
+
"如果任务已完成,请在输出中设置 <finish>true</finish>。",
|
|
967
|
+
))
|
|
968
|
+
continue
|
|
927
969
|
|
|
928
970
|
# Step 11: 有工具调用 — 先执行所有工具,再根据 finish 决定回调
|
|
971
|
+
_consecutive_no_tool_count = 0 # 有工具调用,重置计数器
|
|
929
972
|
need_callback = False
|
|
930
973
|
tool_outputs_parts = []
|
|
931
974
|
_reasoning_len_before_round = len(_v2_reasoning_collected) # 记录本轮开始时的长度
|
|
@@ -1206,36 +1249,10 @@ class MainAgent(BaseAgent):
|
|
|
1206
1249
|
)
|
|
1207
1250
|
break
|
|
1208
1251
|
|
|
1209
|
-
# finish=false:
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
_current_round = _v2_reasoning_collected[_reasoning_len_before_round:]
|
|
1214
|
-
if _current_round:
|
|
1215
|
-
final_text = "\n".join(_current_round)
|
|
1216
|
-
if current_task_plan:
|
|
1217
|
-
final_text += f"\n\n{current_task_plan}"
|
|
1218
|
-
elif _v2_reasoning_collected:
|
|
1219
|
-
final_text = "\n".join(_v2_reasoning_collected)
|
|
1220
|
-
if current_task_plan:
|
|
1221
|
-
final_text += f"\n\n{current_task_plan}"
|
|
1222
|
-
else:
|
|
1223
|
-
final_text = "已完成所有操作。"
|
|
1224
|
-
if current_task_plan:
|
|
1225
|
-
final_text += f"\n\n任务计划:\n{current_task_plan}"
|
|
1226
|
-
context.working_memory["final_response"] = final_text
|
|
1227
|
-
# [v1.15.8] 跳过已发送的 reasoning 文本,避免 TTS 重复播报
|
|
1228
|
-
if not _emitted_reasoning_this_iter:
|
|
1229
|
-
await self._emit_v2_event("v2_reasoning", {"content": truncate_str(final_text, 3000)}, stream_callback)
|
|
1230
|
-
if self.memory:
|
|
1231
|
-
self.memory.add_session(
|
|
1232
|
-
session_id=context.session_id,
|
|
1233
|
-
role="assistant",
|
|
1234
|
-
content=final_text,
|
|
1235
|
-
)
|
|
1236
|
-
break
|
|
1237
|
-
|
|
1238
|
-
logger.info(f"[{task_id}] finish=false 且 need_callback=true,回调 LLM...")
|
|
1252
|
+
# finish=false: 必须继续回调 LLM,无论工具 callback 设置如何
|
|
1253
|
+
# callback 只控制工具结果是否喂回 LLM,不控制循环是否继续
|
|
1254
|
+
# 只有 finish=true 才应该终止循环
|
|
1255
|
+
logger.info(f"[{task_id}] finish=false,继续回调 LLM...")
|
|
1239
1256
|
|
|
1240
1257
|
# 回调前,保存当前轮次的 LLM 输出到会话记忆
|
|
1241
1258
|
# 这样每轮工具调用都有对应的 assistant 消息记录
|