@myassis/gateway 1.0.103 → 1.0.105
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/dist/config/index.js
CHANGED
|
@@ -108,7 +108,7 @@ exports.appConfig = {
|
|
|
108
108
|
/** 超出 toolPairKeep 的旧工具调用内容截断长度 */
|
|
109
109
|
oldToolContentLimit: parseInt(process.env.OLD_TOOL_CONTENT_LIMIT || '200', 10),
|
|
110
110
|
/** 单次请求内最大工具调用轮数 */
|
|
111
|
-
maxToolRounds: parseInt(process.env.MAX_TOOL_ROUNDS || '
|
|
111
|
+
maxToolRounds: parseInt(process.env.MAX_TOOL_ROUNDS || '50', 10),
|
|
112
112
|
/**
|
|
113
113
|
* 轮内压缩触发阈值(字符)。
|
|
114
114
|
*
|
|
@@ -947,6 +947,12 @@ class Session {
|
|
|
947
947
|
let finalizeStatus = 'completed';
|
|
948
948
|
// 当前裁剪级别,遇到上下文超限时逐级加重
|
|
949
949
|
let trimLevel = ContextBuilder_js_1.TrimLevel.OldToolPayload;
|
|
950
|
+
// ========== 轮内工具调用重复检测 ==========
|
|
951
|
+
// 模型陷入死循环时会反复用完全相同的参数调用同一个工具。
|
|
952
|
+
// 这里记录每个 工具名+规范化参数 的调用次数,超过阈值后不再真实执行,
|
|
953
|
+
// 而是返回一条明确的提示,迫使模型换思路或直接收尾。
|
|
954
|
+
const toolCallCount = new Map();
|
|
955
|
+
const MAX_SAME_TOOL_REPEAT = 3;
|
|
950
956
|
/** 判断错误是否为上下文超限 */
|
|
951
957
|
const isContextOverflow = (error) => {
|
|
952
958
|
const text = String(error?.message || error);
|
|
@@ -1140,6 +1146,22 @@ class Session {
|
|
|
1140
1146
|
// 执行工具调用并收集结果
|
|
1141
1147
|
const toolResults = [];
|
|
1142
1148
|
const startToolCall = async (pendingToolCall) => {
|
|
1149
|
+
// 重复检测:相同工具+参数在本轮内被反复调用说明模型陷入了死循环
|
|
1150
|
+
const callKey = pendingToolCall.toolName + String.fromCharCode(58) + String(pendingToolCall.input || String()).trim();
|
|
1151
|
+
const prevCount = toolCallCount.get(callKey) || 0;
|
|
1152
|
+
toolCallCount.set(callKey, prevCount + 1);
|
|
1153
|
+
if (prevCount >= MAX_SAME_TOOL_REPEAT) {
|
|
1154
|
+
const repeatMsg = '[重复调用] 此工具在本轮中已用相同参数调用多次,请停止重复调用,换方式或直接汇报。';
|
|
1155
|
+
logger.warn('[工具重复调用] ' + pendingToolCall.toolName);
|
|
1156
|
+
toolResults.push({ id: pendingToolCall.id, name: pendingToolCall.toolName, output: repeatMsg, success: false });
|
|
1157
|
+
toolCall.toolCalls.push({ id: pendingToolCall.id, toolName: pendingToolCall.toolName, input: pendingToolCall.input, output: repeatMsg, status: 'error', actionName: pendingToolCall.actionName });
|
|
1158
|
+
sendSSE(res, { type: 'tool_call_result', id: pendingToolCall.id, toolName: pendingToolCall.toolName, output: repeatMsg, status: 'error', toolCallId: toolCall.id, actionName: pendingToolCall.actionName, modelName });
|
|
1159
|
+
if (prevCount >= MAX_SAME_TOOL_REPEAT + 2) {
|
|
1160
|
+
forceFinalize = true;
|
|
1161
|
+
finalizeStatus = 'error';
|
|
1162
|
+
}
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1143
1165
|
// 发送工具开始执行事件
|
|
1144
1166
|
const toolStartEvent = {
|
|
1145
1167
|
type: 'tool_call_execute',
|
|
@@ -1347,6 +1369,12 @@ class Session {
|
|
|
1347
1369
|
};
|
|
1348
1370
|
await Promise.all(llmResult.toolCalls.map(x => startToolCall(x)));
|
|
1349
1371
|
toolCalls.push(toolCall);
|
|
1372
|
+
// 重置 toolCall:下一轮工具调用必须开启新的分组。
|
|
1373
|
+
// 否则模型连续多轮只返回工具调用(无正文)时,所有轮次的结果会
|
|
1374
|
+
// 累积进同一个 toolCall 对象,并被重复 push 到 toolCalls 数组,
|
|
1375
|
+
// 导致持久化消息出现重复的工具调用组,历史回放时模型看到重复
|
|
1376
|
+
// 的 tool_calls/tool 结果对,进而重复执行工具。
|
|
1377
|
+
toolCall = null;
|
|
1350
1378
|
// 本轮工具已执行完,增量落库一次。工具轮次可能很多且每轮都耗时,
|
|
1351
1379
|
// 这里保存能让崩溃后仍保留已完成的工具调用记录。
|
|
1352
1380
|
if (!childAgent) {
|
|
@@ -1374,7 +1402,7 @@ class Session {
|
|
|
1374
1402
|
const reminder = this.buildPlanReminder(roundsSincePlanUpdate, forceFinalize);
|
|
1375
1403
|
if (reminder) {
|
|
1376
1404
|
messages.push({
|
|
1377
|
-
role: '
|
|
1405
|
+
role: 'user',
|
|
1378
1406
|
content: reminder,
|
|
1379
1407
|
attachments: []
|
|
1380
1408
|
});
|