@myassis/gateway 1.0.104 → 1.0.106
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
|
*
|
|
@@ -406,7 +406,7 @@ function foldPairsToLedger(messages, originals, pairs, foldCount, protectFrom, s
|
|
|
406
406
|
}
|
|
407
407
|
const kept = messages.filter((_, index) => !foldIndexes.has(index));
|
|
408
408
|
if (!ledgerContent)
|
|
409
|
-
return
|
|
409
|
+
return messages;
|
|
410
410
|
// 并入首条 system 消息:部分厂商只允许 system 位于首位
|
|
411
411
|
if (kept[0]?.role === 'system' && typeof kept[0].content === 'string') {
|
|
412
412
|
kept[0] = { ...kept[0], content: `${kept[0].content}\n\n${ledgerContent}` };
|
|
@@ -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',
|
|
@@ -1380,7 +1402,7 @@ class Session {
|
|
|
1380
1402
|
const reminder = this.buildPlanReminder(roundsSincePlanUpdate, forceFinalize);
|
|
1381
1403
|
if (reminder) {
|
|
1382
1404
|
messages.push({
|
|
1383
|
-
role: '
|
|
1405
|
+
role: 'user',
|
|
1384
1406
|
content: reminder,
|
|
1385
1407
|
attachments: []
|
|
1386
1408
|
});
|