@myassis/gateway 1.0.95 → 1.0.96
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.
|
@@ -577,10 +577,14 @@ class Session {
|
|
|
577
577
|
* 因此当会话已有计划、且连续 roundsSincePlanUpdate 轮工具调用都没有同步进度时,
|
|
578
578
|
* 返回一条提醒文案注入上下文;无需提醒时返回 null。
|
|
579
579
|
*/
|
|
580
|
-
buildPlanReminder(roundsSincePlanUpdate) {
|
|
580
|
+
buildPlanReminder(roundsSincePlanUpdate, finalizing) {
|
|
581
581
|
// 没有计划或计划已完成,无需提醒
|
|
582
582
|
if (this.plan.length === 0 || this.isPlanCompleted())
|
|
583
583
|
return null;
|
|
584
|
+
if (finalizing) {
|
|
585
|
+
// Tools are stripped when finalizing, so skip the reminder instead of telling the model to continue
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
584
588
|
// 允许模型连续做 1 轮工具调用后再要求同步,避免过于频繁地打断
|
|
585
589
|
if (roundsSincePlanUpdate < 2)
|
|
586
590
|
return null;
|
|
@@ -928,6 +932,8 @@ class Session {
|
|
|
928
932
|
let roundsSincePlanUpdate = 0;
|
|
929
933
|
// 计划模式:收尾时提醒模型补完计划的次数,避免反复提醒导致死循环
|
|
930
934
|
let planFinalizeNudges = 0;
|
|
935
|
+
let pseudoToolCallRetries = 0;
|
|
936
|
+
let finalizeStatus = 'completed';
|
|
931
937
|
// 当前裁剪级别,遇到上下文超限时逐级加重
|
|
932
938
|
let trimLevel = ContextBuilder_js_1.TrimLevel.OldToolPayload;
|
|
933
939
|
/** 判断错误是否为上下文超限 */
|
|
@@ -1070,6 +1076,7 @@ class Session {
|
|
|
1070
1076
|
// 还没入队,插进去会破坏配对,被严格校验的厂商判为非法请求。
|
|
1071
1077
|
logger.warn(`工具调用轮次超过上限 ${index_js_2.appConfig.maxToolRounds},转入收尾`);
|
|
1072
1078
|
forceFinalize = true;
|
|
1079
|
+
finalizeStatus = 'error';
|
|
1073
1080
|
}
|
|
1074
1081
|
messages.push({
|
|
1075
1082
|
role: 'assistant',
|
|
@@ -1356,7 +1363,7 @@ class Session {
|
|
|
1356
1363
|
}
|
|
1357
1364
|
// 计划模式:模型常常只在开头和结尾调用 updatePlan,中间过程不同步进度。
|
|
1358
1365
|
// 这里在已有计划且连续多轮未同步时,主动注入一条提醒,迫使模型推进计划状态。
|
|
1359
|
-
const reminder = this.buildPlanReminder(roundsSincePlanUpdate);
|
|
1366
|
+
const reminder = this.buildPlanReminder(roundsSincePlanUpdate, forceFinalize);
|
|
1360
1367
|
if (reminder) {
|
|
1361
1368
|
messages.push({
|
|
1362
1369
|
role: 'assistant',
|
|
@@ -1381,7 +1388,7 @@ class Session {
|
|
|
1381
1388
|
else {
|
|
1382
1389
|
// ========== 没有工具调用,准备结束本轮 ==========
|
|
1383
1390
|
// 计划模式:计划还没收尾时,先提醒模型补完状态(最多提醒一次,避免死循环)
|
|
1384
|
-
if (planFinalizeNudges < 1) {
|
|
1391
|
+
if (!forceFinalize && planFinalizeNudges < 1) {
|
|
1385
1392
|
const finalizeReminder = this.buildPlanFinalizeReminder();
|
|
1386
1393
|
if (finalizeReminder) {
|
|
1387
1394
|
planFinalizeNudges++;
|
|
@@ -1398,6 +1405,34 @@ class Session {
|
|
|
1398
1405
|
return await processModelResponse();
|
|
1399
1406
|
}
|
|
1400
1407
|
}
|
|
1408
|
+
const _rawText = llmResult.content || llmResult.reasoningContent || '';
|
|
1409
|
+
const PSEUDO_TOOL_RE = /<\/?(exec|edit|file|search|fetch|webfetch|screenshot|keyboard|mouse|skill|task|model|sessionsspawn|setsessiontitle|updateplan|tool|tool_call|function)\b|exec\s+command=|\btoolname\b/i;
|
|
1410
|
+
if (_rawText && PSEUDO_TOOL_RE.test(_rawText)) {
|
|
1411
|
+
if (forceFinalize === false && pseudoToolCallRetries < 1) {
|
|
1412
|
+
pseudoToolCallRetries = 1;
|
|
1413
|
+
messages.push({
|
|
1414
|
+
role: 'user',
|
|
1415
|
+
content: 'Your previous reply wrote a tool call as text (e.g. an exec tag, exec command=, or a tool_call block). Such text is NOT executed. Call tools only through the function-calling tool_calls field. Never write tool-call tags in prose. If tools are unavailable, reply in plain language about progress and emit no tool-call tags. Retry using the correct format.',
|
|
1416
|
+
attachments: []
|
|
1417
|
+
});
|
|
1418
|
+
return await processModelResponse();
|
|
1419
|
+
}
|
|
1420
|
+
const _m = _rawText.match(PSEUDO_TOOL_RE);
|
|
1421
|
+
const _idx = _m && _m.index ? _m.index : 0;
|
|
1422
|
+
let _cleaned = _m ? _rawText.slice(0, _idx) : _rawText;
|
|
1423
|
+
_cleaned = _cleaned.trimEnd();
|
|
1424
|
+
if (!_cleaned.trim()) {
|
|
1425
|
+
_cleaned = '[Reached the tool-call limit for this turn. Partial progress is shown above; please continue remaining steps in a new message.]';
|
|
1426
|
+
}
|
|
1427
|
+
else {
|
|
1428
|
+
_cleaned = _cleaned + '\n\n[Reached the tool-call limit; partial progress above. Continue remaining steps in a new message.]';
|
|
1429
|
+
}
|
|
1430
|
+
finalizeStatus = 'error';
|
|
1431
|
+
if (llmResult.content)
|
|
1432
|
+
llmResult.content = _cleaned;
|
|
1433
|
+
else
|
|
1434
|
+
llmResult.reasoningContent = _cleaned;
|
|
1435
|
+
}
|
|
1401
1436
|
if (llmResult.content || llmResult.reasoningContent) {
|
|
1402
1437
|
// 分段发送内容,每段约50个字符
|
|
1403
1438
|
const chunkSize = 1;
|
|
@@ -1412,12 +1447,13 @@ class Session {
|
|
|
1412
1447
|
}
|
|
1413
1448
|
}
|
|
1414
1449
|
if (!childAgent) {
|
|
1415
|
-
this.addAssistantMessage(llmResult.content || llmResult.reasoningContent, toolCalls, [...new Set(modelNames)].join(','), this.currentMessageId);
|
|
1450
|
+
const assistantMessage = this.addAssistantMessage(llmResult.content || llmResult.reasoningContent, toolCalls, [...new Set(modelNames)].join(','), this.currentMessageId);
|
|
1451
|
+
assistantMessage.status = finalizeStatus;
|
|
1416
1452
|
// 正文已完整产出,先落库再发 complete:
|
|
1417
1453
|
// 客户端收到 complete 后就认为这条消息定稿了,此时库里必须已经有它。
|
|
1418
1454
|
await this.saveMessage();
|
|
1419
1455
|
}
|
|
1420
|
-
sendSSE(res, { type: 'complete', modelName: [...new Set(modelNames)].join(",") });
|
|
1456
|
+
sendSSE(res, { type: 'complete', modelName: [...new Set(modelNames)].join(","), status: finalizeStatus });
|
|
1421
1457
|
sendSSE(res, { type: '[DONE]' });
|
|
1422
1458
|
return llmResult.content;
|
|
1423
1459
|
}
|
|
@@ -1432,7 +1468,8 @@ class Session {
|
|
|
1432
1468
|
if (toolCalls) {
|
|
1433
1469
|
// 用 '' 覆盖会把已经增量保存的正文清空,这里保留已有内容
|
|
1434
1470
|
const saved = this.messages.find(m => m.id === this.currentMessageId && m.role === 'assistant');
|
|
1435
|
-
this.addAssistantMessage(saved?.content || '', toolCalls, [...new Set(modelNames)].join(','), this.currentMessageId);
|
|
1471
|
+
const assistantMessage = this.addAssistantMessage(saved?.content || '', toolCalls, [...new Set(modelNames)].join(','), this.currentMessageId);
|
|
1472
|
+
assistantMessage.status = 'error';
|
|
1436
1473
|
}
|
|
1437
1474
|
if (error.message !== 'aborted') {
|
|
1438
1475
|
try {
|