dominds 1.27.1 → 1.27.3
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/apps/runtime.js +3 -1
- package/dist/dialog-global-registry.d.ts +11 -1
- package/dist/dialog-global-registry.js +45 -0
- package/dist/dialog.d.ts +13 -3
- package/dist/dialog.js +108 -17
- package/dist/docs/daemon-cmd-runner.md +5 -0
- package/dist/docs/daemon-cmd-runner.zh.md +5 -0
- package/dist/llm/kernel-driver/drive.js +382 -12
- package/dist/llm/kernel-driver/fbr.d.ts +9 -0
- package/dist/llm/kernel-driver/fbr.js +186 -59
- package/dist/llm/kernel-driver/flow.js +58 -56
- package/dist/llm/kernel-driver/reply-guidance.d.ts +3 -0
- package/dist/llm/kernel-driver/reply-guidance.js +15 -31
- package/dist/minds/load.js +1 -0
- package/dist/persistence.js +22 -1
- package/dist/runtime/driver-messages.d.ts +9 -0
- package/dist/runtime/driver-messages.js +61 -5
- package/dist/runtime/shared-reminder-update-impact.d.ts +20 -0
- package/dist/runtime/shared-reminder-update-impact.js +110 -0
- package/dist/server/dominds-runtime-status.js +23 -0
- package/dist/server/static-server.js +20 -5
- package/dist/tool-availability.js +1 -0
- package/dist/tools/builtins.js +2 -0
- package/dist/tools/cmd-runner-protocol.d.ts +6 -0
- package/dist/tools/cmd-runner-protocol.js +57 -2
- package/dist/tools/cmd-runner.js +83 -2
- package/dist/tools/ctrl.d.ts +2 -0
- package/dist/tools/ctrl.js +179 -5
- package/dist/tools/os.js +115 -14
- package/dist/tools/process-kill.js +49 -0
- package/dist/tools/prompts/control/en/errors.md +1 -1
- package/dist/tools/prompts/control/en/index.md +1 -1
- package/dist/tools/prompts/control/en/principles.md +18 -17
- package/dist/tools/prompts/control/en/tools.md +24 -1
- package/dist/tools/prompts/control/zh/errors.md +1 -1
- package/dist/tools/prompts/control/zh/index.md +1 -1
- package/dist/tools/prompts/control/zh/principles.md +17 -16
- package/dist/tools/prompts/control/zh/tools.md +24 -1
- package/dist/tools/prompts/os/en/tools.md +2 -0
- package/dist/tools/prompts/os/zh/tools.md +2 -0
- package/package.json +3 -3
- package/webapp/dist/assets/{main-APO6XREZ.js → main-NXVX2KTO.js} +24 -5
- package/webapp/dist/assets/{main-APO6XREZ.js.map → main-NXVX2KTO.js.map} +3 -3
- package/webapp/dist/index.html +1 -1
|
@@ -46,6 +46,7 @@ const KERNEL_DRIVER_DEFAULT_RETRY_POLICY = {
|
|
|
46
46
|
backoffMultiplier: 1.5,
|
|
47
47
|
maxDelayMs: 30 * 60 * 1000, // 30 minutes
|
|
48
48
|
};
|
|
49
|
+
const CLEAR_MIND_TOOL_NAME = 'clear_mind';
|
|
49
50
|
const KERNEL_DRIVER_EMPTY_LLM_RESPONSE_ERROR_CODE = 'DOMINDS_LLM_EMPTY_RESPONSE';
|
|
50
51
|
// Wrapper isolation boundary:
|
|
51
52
|
// - Wrappers emit provider-native web-search events.
|
|
@@ -246,6 +247,35 @@ function buildKernelDriverFbrPrompt(dlg, state) {
|
|
|
246
247
|
origin: 'runtime',
|
|
247
248
|
};
|
|
248
249
|
}
|
|
250
|
+
function resolveLatestModelOutputGenseq(dlg) {
|
|
251
|
+
for (let index = dlg.msgs.length - 1; index >= 0; index -= 1) {
|
|
252
|
+
const msg = dlg.msgs[index];
|
|
253
|
+
if (msg === undefined) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
switch (msg.type) {
|
|
257
|
+
case 'saying_msg':
|
|
258
|
+
case 'thinking_msg':
|
|
259
|
+
case 'func_call_msg': {
|
|
260
|
+
const genseq = Math.floor(msg.genseq);
|
|
261
|
+
if (Number.isFinite(genseq) && genseq > 0) {
|
|
262
|
+
return genseq;
|
|
263
|
+
}
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
default:
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
function resolveProgrammaticFbrConclusionGenseq(args) {
|
|
273
|
+
return (args.lastAssistantSayingGenseq ??
|
|
274
|
+
args.lastFunctionCallGenseq ??
|
|
275
|
+
resolveLatestModelOutputGenseq(args.dlg) ??
|
|
276
|
+
args.dlg.activeGenSeqOrUndefined ??
|
|
277
|
+
1);
|
|
278
|
+
}
|
|
249
279
|
function normalizeQ4HAnswerCallId(raw) {
|
|
250
280
|
if (typeof raw !== 'string')
|
|
251
281
|
return undefined;
|
|
@@ -750,7 +780,7 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
|
|
|
750
780
|
'1. 把需要回传给主线对话的结论、证据定位和风险整理清楚。',
|
|
751
781
|
'2. 对于下一程恢复工作需要的信息,写入提醒项。',
|
|
752
782
|
'',
|
|
753
|
-
'
|
|
783
|
+
'然后调用 clear_mind({}) 开启新一程,并尽快完成当前支线回复。',
|
|
754
784
|
'',
|
|
755
785
|
`详情:本次返回约 ${approxBytes} 字节。`,
|
|
756
786
|
].join('\n');
|
|
@@ -775,7 +805,7 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
|
|
|
775
805
|
'1. Organize the conclusions, evidence pointers, and risks that need to go back to the Mainline dialog.',
|
|
776
806
|
'2. Write any details needed to resume the next course into reminders.',
|
|
777
807
|
'',
|
|
778
|
-
'Then finish the current Sideline dialog reply as soon as possible
|
|
808
|
+
'Then call clear_mind({}) to start a new course, and finish the current Sideline dialog reply as soon as possible.',
|
|
779
809
|
'',
|
|
780
810
|
`Detail: this return was about ${approxBytes} bytes.`,
|
|
781
811
|
].join('\n');
|
|
@@ -814,6 +844,9 @@ function countToolResultVisibleBytes(output) {
|
|
|
814
844
|
return bytes;
|
|
815
845
|
}
|
|
816
846
|
function applyContextHealthToolResultVisibilityLimit(args) {
|
|
847
|
+
if (isFbrSideDialog(args.dlg)) {
|
|
848
|
+
return { output: args.output, largeReturnUnavailable: false };
|
|
849
|
+
}
|
|
817
850
|
if ((0, context_health_1.getContextHealthRemediationLevel)(args.contextHealth) === undefined) {
|
|
818
851
|
return { output: args.output, largeReturnUnavailable: false };
|
|
819
852
|
}
|
|
@@ -1381,6 +1414,161 @@ function formatInvalidFuncCallRuntimeGuide(language, call) {
|
|
|
1381
1414
|
.filter((line) => line.length > 0)
|
|
1382
1415
|
.join('\n');
|
|
1383
1416
|
}
|
|
1417
|
+
function stableJsonStringify(value) {
|
|
1418
|
+
if (value === null)
|
|
1419
|
+
return 'null';
|
|
1420
|
+
if (typeof value === 'string')
|
|
1421
|
+
return JSON.stringify(value);
|
|
1422
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
1423
|
+
return JSON.stringify(value);
|
|
1424
|
+
if (Array.isArray(value)) {
|
|
1425
|
+
return `[${value.map((entry) => stableJsonStringify(entry)).join(',')}]`;
|
|
1426
|
+
}
|
|
1427
|
+
if (typeof value === 'object') {
|
|
1428
|
+
const record = value;
|
|
1429
|
+
return `{${Object.keys(record)
|
|
1430
|
+
.sort()
|
|
1431
|
+
.map((key) => `${JSON.stringify(key)}:${stableJsonStringify(record[key])}`)
|
|
1432
|
+
.join(',')}}`;
|
|
1433
|
+
}
|
|
1434
|
+
return JSON.stringify(String(value));
|
|
1435
|
+
}
|
|
1436
|
+
function canonicalizeToolCallArguments(rawArguments) {
|
|
1437
|
+
try {
|
|
1438
|
+
return stableJsonStringify(JSON.parse(rawArguments));
|
|
1439
|
+
}
|
|
1440
|
+
catch {
|
|
1441
|
+
return rawArguments;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
function canonicalizeToolResult(result) {
|
|
1445
|
+
return stableJsonStringify({
|
|
1446
|
+
content: result.content,
|
|
1447
|
+
contentItems: result.contentItems ?? null,
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
function buildToolResultFingerprint(call, result) {
|
|
1451
|
+
return {
|
|
1452
|
+
toolName: call.name,
|
|
1453
|
+
argumentsFingerprint: canonicalizeToolCallArguments(call.arguments),
|
|
1454
|
+
resultFingerprint: canonicalizeToolResult(result),
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
function sameToolResultFingerprint(left, right) {
|
|
1458
|
+
return (left.toolName === right.toolName &&
|
|
1459
|
+
left.argumentsFingerprint === right.argumentsFingerprint &&
|
|
1460
|
+
left.resultFingerprint === right.resultFingerprint);
|
|
1461
|
+
}
|
|
1462
|
+
function formatRepeatedToolCallRuntimeGuide(args) {
|
|
1463
|
+
const resultPreview = args.resultContent.length > 800
|
|
1464
|
+
? `${args.resultContent.slice(0, 800)}\n...`
|
|
1465
|
+
: args.resultContent;
|
|
1466
|
+
if (args.language === 'en') {
|
|
1467
|
+
return [
|
|
1468
|
+
'[Runtime notice] You have just made the same tool call three times, with identical arguments, and Dominds observed the exact same tool result each time.',
|
|
1469
|
+
'',
|
|
1470
|
+
`- tool: ${args.toolName}`,
|
|
1471
|
+
`- callIds: ${args.callIds.join(', ')}`,
|
|
1472
|
+
'- arguments:',
|
|
1473
|
+
'```json',
|
|
1474
|
+
args.argumentsFingerprint,
|
|
1475
|
+
'```',
|
|
1476
|
+
'- repeated result:',
|
|
1477
|
+
'```text',
|
|
1478
|
+
resultPreview,
|
|
1479
|
+
'```',
|
|
1480
|
+
'',
|
|
1481
|
+
'Question this behavior before calling tools again. The repeated result strongly suggests the same call will not produce new information. Re-read the user request and the tool result, then correct course: answer from the available information, choose a different action, or explain what is blocked.',
|
|
1482
|
+
].join('\n');
|
|
1483
|
+
}
|
|
1484
|
+
return [
|
|
1485
|
+
'[Dominds 提示] 你刚才连续三次调用了同一个工具,参数完全相同,Dominds 观察到三次工具返回值也完全相同。',
|
|
1486
|
+
'',
|
|
1487
|
+
`- 工具: ${args.toolName}`,
|
|
1488
|
+
`- callIds: ${args.callIds.join(', ')}`,
|
|
1489
|
+
'- 参数:',
|
|
1490
|
+
'```json',
|
|
1491
|
+
args.argumentsFingerprint,
|
|
1492
|
+
'```',
|
|
1493
|
+
'- 重复返回值:',
|
|
1494
|
+
'```text',
|
|
1495
|
+
resultPreview,
|
|
1496
|
+
'```',
|
|
1497
|
+
'',
|
|
1498
|
+
'请先质疑这个行为,不要机械地再次调用同一个工具。同样的调用大概率不会产生新信息。请重新阅读用户诉求和工具返回值,然后自行纠正:基于已有信息作答、换一种行动,或明确说明当前阻塞点。',
|
|
1499
|
+
].join('\n');
|
|
1500
|
+
}
|
|
1501
|
+
function formatRepeatedToolCallStoppedDetail(args) {
|
|
1502
|
+
if (args.language === 'en') {
|
|
1503
|
+
return (`Stopped because the LLM ignored Dominds' repeated-tool-call correction notice and again made ` +
|
|
1504
|
+
`the same tool call three times with identical results. This indicates an LLM behavior/personality problem: ` +
|
|
1505
|
+
`it is looping on ${args.toolName} instead of reconsidering the task. callIds=${args.callIds.join(', ')}`);
|
|
1506
|
+
}
|
|
1507
|
+
return (`已停止:LLM 已收到 Dominds 的重复工具调用纠正提醒,但仍然再次连续三次调用同一个工具并得到完全相同的结果。` +
|
|
1508
|
+
`这说明当前 LLM 存在行为/个性问题:它在 ${args.toolName} 上机械循环,而不是重新判断任务。` +
|
|
1509
|
+
`callIds=${args.callIds.join(', ')}`);
|
|
1510
|
+
}
|
|
1511
|
+
const REPEATED_TOOL_CALL_STOP_WINDOW_GENSEQS = 5;
|
|
1512
|
+
function inspectRepeatedToolCallRound(args) {
|
|
1513
|
+
ensureRepeatedToolCallMonitorCourse(args.state, args.currentCourse);
|
|
1514
|
+
const recentPairs = [];
|
|
1515
|
+
for (let index = 0; index < args.pairedMessages.length - 1; index += 1) {
|
|
1516
|
+
const call = args.pairedMessages[index];
|
|
1517
|
+
const result = args.pairedMessages[index + 1];
|
|
1518
|
+
if (call?.type !== 'func_call_msg' || result?.type !== 'func_result_msg') {
|
|
1519
|
+
continue;
|
|
1520
|
+
}
|
|
1521
|
+
if (result.id !== call.id) {
|
|
1522
|
+
continue;
|
|
1523
|
+
}
|
|
1524
|
+
recentPairs.push({
|
|
1525
|
+
call,
|
|
1526
|
+
result,
|
|
1527
|
+
fingerprint: buildToolResultFingerprint(call, result),
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
for (const pair of recentPairs) {
|
|
1531
|
+
const currentSequence = args.state.sequence;
|
|
1532
|
+
if (currentSequence !== undefined &&
|
|
1533
|
+
sameToolResultFingerprint(currentSequence.fingerprint, pair.fingerprint)) {
|
|
1534
|
+
currentSequence.callIds.push(pair.call.id);
|
|
1535
|
+
if (currentSequence.callIds.length > 3) {
|
|
1536
|
+
currentSequence.callIds.splice(0, currentSequence.callIds.length - 3);
|
|
1537
|
+
}
|
|
1538
|
+
currentSequence.resultContent = pair.result.content;
|
|
1539
|
+
}
|
|
1540
|
+
else {
|
|
1541
|
+
args.state.sequence = {
|
|
1542
|
+
fingerprint: pair.fingerprint,
|
|
1543
|
+
callIds: [pair.call.id],
|
|
1544
|
+
resultContent: pair.result.content,
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
const sequence = args.state.sequence;
|
|
1548
|
+
if (sequence === undefined || sequence.callIds.length < 3) {
|
|
1549
|
+
continue;
|
|
1550
|
+
}
|
|
1551
|
+
const recentReminder = args.state.lastReminderGenseq !== undefined &&
|
|
1552
|
+
pair.call.genseq > args.state.lastReminderGenseq &&
|
|
1553
|
+
pair.call.genseq - args.state.lastReminderGenseq <= REPEATED_TOOL_CALL_STOP_WINDOW_GENSEQS;
|
|
1554
|
+
const callIds = [...sequence.callIds];
|
|
1555
|
+
return {
|
|
1556
|
+
toolName: pair.call.name,
|
|
1557
|
+
callIds,
|
|
1558
|
+
argumentsFingerprint: pair.fingerprint.argumentsFingerprint,
|
|
1559
|
+
resultContent: sequence.resultContent,
|
|
1560
|
+
reminderContent: formatRepeatedToolCallRuntimeGuide({
|
|
1561
|
+
language: args.language,
|
|
1562
|
+
toolName: pair.call.name,
|
|
1563
|
+
callIds,
|
|
1564
|
+
argumentsFingerprint: pair.fingerprint.argumentsFingerprint,
|
|
1565
|
+
resultContent: sequence.resultContent,
|
|
1566
|
+
}),
|
|
1567
|
+
repeatedAfterReminder: recentReminder,
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
return undefined;
|
|
1571
|
+
}
|
|
1384
1572
|
async function persistInvalidFuncCallRuntimeGuide(args) {
|
|
1385
1573
|
const { dlg, call } = args;
|
|
1386
1574
|
const sourceText = args.source === 'streamed' ? 'streamed' : 'batch';
|
|
@@ -1405,6 +1593,17 @@ async function persistInvalidFuncCallRuntimeGuide(args) {
|
|
|
1405
1593
|
});
|
|
1406
1594
|
await persistAndPostRuntimeGuide(dlg, content);
|
|
1407
1595
|
}
|
|
1596
|
+
function resetRepeatedToolCallMonitor(state) {
|
|
1597
|
+
state.sequence = undefined;
|
|
1598
|
+
state.lastReminderGenseq = undefined;
|
|
1599
|
+
}
|
|
1600
|
+
function ensureRepeatedToolCallMonitorCourse(state, course) {
|
|
1601
|
+
if (state.course === course) {
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
resetRepeatedToolCallMonitor(state);
|
|
1605
|
+
state.course = course;
|
|
1606
|
+
}
|
|
1408
1607
|
function isQueuedNewCourseRuntimePrompt(prompt) {
|
|
1409
1608
|
return (prompt?.kind === 'new_course_runtime_guide' ||
|
|
1410
1609
|
prompt?.kind === 'new_course_runtime_reply' ||
|
|
@@ -1458,6 +1657,7 @@ function summarizeRoutedFunctionResult(routed) {
|
|
|
1458
1657
|
immediateFollowupCallIds: routed.immediateFollowupCallIds,
|
|
1459
1658
|
immediateTellaskOutputCallIds: routed.immediateTellaskOutputCallIds,
|
|
1460
1659
|
invalidTellaskCallIds: routed.invalidTellaskCallIds,
|
|
1660
|
+
repeatedToolCallReminderCallIds: routed.repeatedToolCallReminderCallIds,
|
|
1461
1661
|
shouldStopAfterReplyTool: routed.shouldStopAfterReplyTool,
|
|
1462
1662
|
shouldStopAfterPendingTellaskWait: routed.shouldStopAfterPendingTellaskWait,
|
|
1463
1663
|
pairedMessageTypes: routed.pairedMessages.map((msg) => msg.type),
|
|
@@ -1511,6 +1711,8 @@ function shouldCaptureUnexpectedIdleAfterToolRound(args) {
|
|
|
1511
1711
|
return true;
|
|
1512
1712
|
if (diagnostics.routed.immediateTellaskOutputCallIds.length > 0)
|
|
1513
1713
|
return true;
|
|
1714
|
+
if (diagnostics.routed.repeatedToolCallReminderCallIds.length > 0)
|
|
1715
|
+
return true;
|
|
1514
1716
|
return false;
|
|
1515
1717
|
}
|
|
1516
1718
|
function sanitizeDebugFileSegment(value) {
|
|
@@ -1694,6 +1896,12 @@ function buildImmediateFollowupTriggerExpectation(args) {
|
|
|
1694
1896
|
callIds: [...invalidRecoveryCallIds],
|
|
1695
1897
|
});
|
|
1696
1898
|
}
|
|
1899
|
+
if (args.routed.repeatedToolCallReminderCallIds.length > 0) {
|
|
1900
|
+
reasons.push({
|
|
1901
|
+
kind: 'repeated_tool_call_reminder',
|
|
1902
|
+
callIds: args.routed.repeatedToolCallReminderCallIds,
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1697
1905
|
if (reasons.length === 0) {
|
|
1698
1906
|
return undefined;
|
|
1699
1907
|
}
|
|
@@ -1786,6 +1994,30 @@ function shouldImmediatelyFollowUpToolOutcome(tool, outcome) {
|
|
|
1786
1994
|
}
|
|
1787
1995
|
return shouldImmediatelyFollowUpSuccessfulToolResult(tool);
|
|
1788
1996
|
}
|
|
1997
|
+
function isFailedToolOutcome(outcome) {
|
|
1998
|
+
return outcome === 'failure' || outcome === 'partial_failure';
|
|
1999
|
+
}
|
|
2000
|
+
function formatClearMindBlockedByFailedSiblingTools(failedTools) {
|
|
2001
|
+
const language = (0, work_language_1.getWorkLanguage)();
|
|
2002
|
+
const details = failedTools
|
|
2003
|
+
.map((tool) => `- ${tool.toolName} (callId=${tool.callId}, outcome=${String(tool.outcome)})`)
|
|
2004
|
+
.join('\n');
|
|
2005
|
+
return language === 'zh'
|
|
2006
|
+
? [
|
|
2007
|
+
'错误:本轮 clear_mind 与其它工具一起调用,但其它工具返回了失败结果。',
|
|
2008
|
+
'',
|
|
2009
|
+
details,
|
|
2010
|
+
'',
|
|
2011
|
+
'clear_mind 已拒绝开启新一程。请先确保其它工具调用正常完成(必要时修正参数、重试或处理失败),然后再次调用 clear_mind。',
|
|
2012
|
+
].join('\n')
|
|
2013
|
+
: [
|
|
2014
|
+
'Error: clear_mind was called in the same round as other tools, and at least one other tool returned a failure result.',
|
|
2015
|
+
'',
|
|
2016
|
+
details,
|
|
2017
|
+
'',
|
|
2018
|
+
'clear_mind refused to start a new course. Ensure the other tool calls complete normally first (fix arguments, retry, or handle the failure), then call clear_mind again.',
|
|
2019
|
+
].join('\n');
|
|
2020
|
+
}
|
|
1789
2021
|
function trimOptionalCallId(value) {
|
|
1790
2022
|
if (typeof value !== 'string')
|
|
1791
2023
|
return undefined;
|
|
@@ -1958,7 +2190,7 @@ async function executeFunctionCalls(args) {
|
|
|
1958
2190
|
throwIfAborted(args.abortSignal, args.dlg);
|
|
1959
2191
|
await args.dlg.persistFunctionCall(prepared.func.id, prepared.func.name, prepared.argsStr, prepared.callGenseq, prepared.func.rawId);
|
|
1960
2192
|
}
|
|
1961
|
-
const
|
|
2193
|
+
const executePreparedCall = async ({ func, originalFunc, callGenseq, argsStr, tool, preparedInvocationArgs, }) => {
|
|
1962
2194
|
let result;
|
|
1963
2195
|
let outcome = 'success';
|
|
1964
2196
|
let forceImmediateFollowup = false;
|
|
@@ -2051,8 +2283,54 @@ async function executeFunctionCalls(args) {
|
|
|
2051
2283
|
throw rethrowError;
|
|
2052
2284
|
}
|
|
2053
2285
|
return { func, originalFunc, outcome, forceImmediateFollowup, result };
|
|
2054
|
-
}
|
|
2055
|
-
|
|
2286
|
+
};
|
|
2287
|
+
const blockClearMindCall = async (prepared, failedTools) => {
|
|
2288
|
+
const output = (0, tool_1.toolFailure)(formatClearMindBlockedByFailedSiblingTools(failedTools));
|
|
2289
|
+
const result = {
|
|
2290
|
+
type: 'func_result_msg',
|
|
2291
|
+
id: prepared.func.id,
|
|
2292
|
+
rawId: prepared.func.rawId,
|
|
2293
|
+
effectiveId: prepared.func.effectiveId,
|
|
2294
|
+
name: prepared.func.name,
|
|
2295
|
+
content: output.content,
|
|
2296
|
+
role: 'tool',
|
|
2297
|
+
genseq: prepared.callGenseq,
|
|
2298
|
+
};
|
|
2299
|
+
await args.dlg.receiveFuncResult(result);
|
|
2300
|
+
return {
|
|
2301
|
+
func: prepared.func,
|
|
2302
|
+
originalFunc: prepared.originalFunc,
|
|
2303
|
+
outcome: output.outcome,
|
|
2304
|
+
forceImmediateFollowup: false,
|
|
2305
|
+
result,
|
|
2306
|
+
};
|
|
2307
|
+
};
|
|
2308
|
+
const clearMindCalls = preparedCalls.filter((call) => call.func.name === CLEAR_MIND_TOOL_NAME);
|
|
2309
|
+
const siblingCalls = preparedCalls.filter((call) => call.func.name !== CLEAR_MIND_TOOL_NAME);
|
|
2310
|
+
const failedPriorToolResults = args.failedPriorToolResults ?? [];
|
|
2311
|
+
if (clearMindCalls.length === 0 || siblingCalls.length === 0) {
|
|
2312
|
+
if (clearMindCalls.length > 0 && failedPriorToolResults.length > 0) {
|
|
2313
|
+
return await Promise.all(clearMindCalls.map((call) => blockClearMindCall(call, failedPriorToolResults)));
|
|
2314
|
+
}
|
|
2315
|
+
return await Promise.all(preparedCalls.map((call) => executePreparedCall(call)));
|
|
2316
|
+
}
|
|
2317
|
+
const siblingExecutions = await Promise.all(siblingCalls.map((call) => executePreparedCall(call)));
|
|
2318
|
+
const failedSiblingToolResults = [
|
|
2319
|
+
...failedPriorToolResults,
|
|
2320
|
+
...siblingExecutions
|
|
2321
|
+
.filter((execution) => isFailedToolOutcome(execution.outcome))
|
|
2322
|
+
.map((execution) => ({
|
|
2323
|
+
callId: execution.result.id,
|
|
2324
|
+
toolName: execution.result.name,
|
|
2325
|
+
outcome: execution.outcome,
|
|
2326
|
+
})),
|
|
2327
|
+
];
|
|
2328
|
+
if (failedSiblingToolResults.length > 0) {
|
|
2329
|
+
const clearMindExecutions = await Promise.all(clearMindCalls.map((call) => blockClearMindCall(call, failedSiblingToolResults)));
|
|
2330
|
+
return [...siblingExecutions, ...clearMindExecutions];
|
|
2331
|
+
}
|
|
2332
|
+
const clearMindExecutions = await Promise.all(clearMindCalls.map((call) => executePreparedCall(call)));
|
|
2333
|
+
return [...siblingExecutions, ...clearMindExecutions];
|
|
2056
2334
|
}
|
|
2057
2335
|
async function executeFunctionRound(args) {
|
|
2058
2336
|
if (args.funcCalls.length === 0) {
|
|
@@ -2062,6 +2340,7 @@ async function executeFunctionRound(args) {
|
|
|
2062
2340
|
immediateFollowupCallIds: [],
|
|
2063
2341
|
immediateTellaskOutputCallIds: [],
|
|
2064
2342
|
invalidTellaskCallIds: [],
|
|
2343
|
+
repeatedToolCallReminderCallIds: [],
|
|
2065
2344
|
shouldStopAfterReplyTool: false,
|
|
2066
2345
|
shouldStopAfterPendingTellaskWait: false,
|
|
2067
2346
|
pairedMessages: [],
|
|
@@ -2094,6 +2373,17 @@ async function executeFunctionRound(args) {
|
|
|
2094
2373
|
activePromptReplyDirective: args.activePromptReplyDirective,
|
|
2095
2374
|
});
|
|
2096
2375
|
throwIfAborted(args.abortSignal, args.dlg);
|
|
2376
|
+
const failedTellaskToolResults = tellaskRound.invalidTellaskCallIds.map((callId) => {
|
|
2377
|
+
const call = args.funcCalls.find((candidate) => candidate.id === callId);
|
|
2378
|
+
if (call === undefined) {
|
|
2379
|
+
throw new Error(`kernel-driver tellask result invariant violation: missing invalid tellask call '${callId}'`);
|
|
2380
|
+
}
|
|
2381
|
+
return {
|
|
2382
|
+
callId,
|
|
2383
|
+
toolName: call.name,
|
|
2384
|
+
outcome: 'failure',
|
|
2385
|
+
};
|
|
2386
|
+
});
|
|
2097
2387
|
const genericExecutions = await executeFunctionCalls({
|
|
2098
2388
|
dlg: args.dlg,
|
|
2099
2389
|
agent: args.agent,
|
|
@@ -2101,6 +2391,7 @@ async function executeFunctionRound(args) {
|
|
|
2101
2391
|
funcCalls: tellaskRound.normalCalls,
|
|
2102
2392
|
abortSignal: args.abortSignal,
|
|
2103
2393
|
contextHealthForToolResultVisibility: args.contextHealthForToolResultVisibility,
|
|
2394
|
+
failedPriorToolResults: failedTellaskToolResults,
|
|
2104
2395
|
});
|
|
2105
2396
|
const genericExecutionByOriginalCall = new Map(genericExecutions.map((execution) => [execution.originalFunc, execution]));
|
|
2106
2397
|
const funcToolByName = new Map(args.agentTools
|
|
@@ -2180,6 +2471,7 @@ async function executeFunctionRound(args) {
|
|
|
2180
2471
|
immediateFollowupCallIds,
|
|
2181
2472
|
immediateTellaskOutputCallIds: tellaskRound.immediateTellaskOutputCallIds,
|
|
2182
2473
|
invalidTellaskCallIds: tellaskRound.invalidTellaskCallIds,
|
|
2474
|
+
repeatedToolCallReminderCallIds: [],
|
|
2183
2475
|
shouldStopAfterReplyTool: tellaskRound.shouldStopAfterReplyTool,
|
|
2184
2476
|
shouldStopAfterPendingTellaskWait: tellaskRound.shouldStopAfterPendingTellaskWait,
|
|
2185
2477
|
pairedMessages,
|
|
@@ -2390,6 +2682,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
2390
2682
|
let fbrConclusion;
|
|
2391
2683
|
let pubRemindersVer = dlg.remindersVer;
|
|
2392
2684
|
let lastToolRoundStopDiagnostics;
|
|
2685
|
+
const repeatedToolCallMonitor = {};
|
|
2393
2686
|
let pendingPrompt = humanPrompt;
|
|
2394
2687
|
let resolvingImmediateToolResultForUserPrompt = false;
|
|
2395
2688
|
let resolvingImmediateToolResultUserPromptMsgId;
|
|
@@ -2424,8 +2717,41 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
2424
2717
|
for (;;) {
|
|
2425
2718
|
genIterNo += 1;
|
|
2426
2719
|
throwIfAborted(abortSignal, dlg);
|
|
2427
|
-
|
|
2720
|
+
let activeFbrState = await loadDialogFbrState(dlg);
|
|
2428
2721
|
if (isFbrSideDialog(dlg)) {
|
|
2722
|
+
const fbrContextHealthLevel = (0, context_health_1.getContextHealthRemediationLevel)(dlg.getLastContextHealth());
|
|
2723
|
+
if (activeFbrState !== undefined && fbrContextHealthLevel === 'critical') {
|
|
2724
|
+
log_1.log.warn('kernel-driver ending FBR with critical context fixed conclusion', undefined, {
|
|
2725
|
+
rootId: dlg.id.rootId,
|
|
2726
|
+
selfId: dlg.id.selfId,
|
|
2727
|
+
course: dlg.currentCourse,
|
|
2728
|
+
phase: activeFbrState.phase,
|
|
2729
|
+
iteration: activeFbrState.iteration,
|
|
2730
|
+
});
|
|
2731
|
+
fbrConclusion = {
|
|
2732
|
+
responseText: (0, fbr_1.buildProgrammaticFbrContextCriticalContent)({
|
|
2733
|
+
language: (0, work_language_1.getWorkLanguage)(),
|
|
2734
|
+
}),
|
|
2735
|
+
responseGenseq: resolveProgrammaticFbrConclusionGenseq({
|
|
2736
|
+
dlg,
|
|
2737
|
+
lastAssistantSayingGenseq,
|
|
2738
|
+
lastFunctionCallGenseq,
|
|
2739
|
+
}),
|
|
2740
|
+
replyResolutionCallId: `fbr-context-critical-${(0, id_1.generateShortId)()}`,
|
|
2741
|
+
};
|
|
2742
|
+
await persistDialogFbrState(dlg, undefined);
|
|
2743
|
+
dlg.setFbrConclusionToolsEnabled(false);
|
|
2744
|
+
finalDisplayState = await (0, dialog_display_state_1.computeIdleDisplayState)(dlg);
|
|
2745
|
+
break driveCoreLoop;
|
|
2746
|
+
}
|
|
2747
|
+
if (activeFbrState !== undefined &&
|
|
2748
|
+
fbrContextHealthLevel === 'caution' &&
|
|
2749
|
+
!(0, fbr_1.isFbrContextCautionFinalizationState)(activeFbrState) &&
|
|
2750
|
+
(pendingPrompt === undefined || pendingPrompt.origin === 'runtime')) {
|
|
2751
|
+
activeFbrState = (0, fbr_1.forceFbrContextCautionFinalizationState)(activeFbrState);
|
|
2752
|
+
await persistDialogFbrState(dlg, activeFbrState);
|
|
2753
|
+
pendingPrompt = buildKernelDriverFbrPrompt(dlg, activeFbrState);
|
|
2754
|
+
}
|
|
2429
2755
|
dlg.setFbrConclusionToolsEnabled(activeFbrState !== undefined && (0, fbr_1.isFbrFinalizationState)(activeFbrState));
|
|
2430
2756
|
if (pendingPrompt === undefined &&
|
|
2431
2757
|
activeFbrState &&
|
|
@@ -2591,6 +2917,9 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
2591
2917
|
let llmGenModelForGen = model;
|
|
2592
2918
|
const currentPrompt = pendingPrompt;
|
|
2593
2919
|
const currentReplyTarget = currentPrompt?.calleeDialogReplyTarget;
|
|
2920
|
+
if (currentGenerationBelongsToUserPrompt) {
|
|
2921
|
+
resetRepeatedToolCallMonitor(repeatedToolCallMonitor);
|
|
2922
|
+
}
|
|
2594
2923
|
let currentBusinessContinuation = driveOptions?.businessContinuation ?? { kind: 'none' };
|
|
2595
2924
|
if (currentPrompt?.tellaskReplyDirective !== undefined) {
|
|
2596
2925
|
currentBusinessContinuation = {
|
|
@@ -2605,7 +2934,10 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
2605
2934
|
let currentRuntimeGuideMsg;
|
|
2606
2935
|
const currentPromptFromFbrState = currentPrompt !== undefined &&
|
|
2607
2936
|
currentFbrState !== undefined &&
|
|
2608
|
-
currentFbrState.promptDelivered !== true
|
|
2937
|
+
currentFbrState.promptDelivered !== true &&
|
|
2938
|
+
isFbrSideDialog(dlg) &&
|
|
2939
|
+
currentPrompt.origin === 'runtime' &&
|
|
2940
|
+
currentPrompt.content === buildKernelDriverFbrPrompt(dlg, currentFbrState).content;
|
|
2609
2941
|
pendingPrompt = undefined;
|
|
2610
2942
|
if (currentPrompt) {
|
|
2611
2943
|
const diligenceSkipReason = await shouldSkipDiligencePromptBeforeGeneration({
|
|
@@ -3472,7 +3804,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3472
3804
|
: currentGenerationBelongsToUserToolChain
|
|
3473
3805
|
? currentUserPromptMsgId
|
|
3474
3806
|
: undefined;
|
|
3475
|
-
|
|
3807
|
+
let routed = await executeFunctionRound({
|
|
3476
3808
|
dlg,
|
|
3477
3809
|
agent,
|
|
3478
3810
|
agentTools,
|
|
@@ -3518,6 +3850,41 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3518
3850
|
newMsgs.push(...routed.pairedMessages);
|
|
3519
3851
|
}
|
|
3520
3852
|
await dlg.addChatMessages(...newMsgs);
|
|
3853
|
+
const repeatedToolCallInspection = inspectRepeatedToolCallRound({
|
|
3854
|
+
state: repeatedToolCallMonitor,
|
|
3855
|
+
currentCourse: dlg.activeGenCourseOrUndefined ?? dlg.currentCourse,
|
|
3856
|
+
pairedMessages: routed.pairedMessages,
|
|
3857
|
+
language: (0, work_language_1.getWorkLanguage)(),
|
|
3858
|
+
});
|
|
3859
|
+
if (repeatedToolCallInspection !== undefined) {
|
|
3860
|
+
if (repeatedToolCallInspection.repeatedAfterReminder) {
|
|
3861
|
+
const detail = formatRepeatedToolCallStoppedDetail({
|
|
3862
|
+
language: (0, work_language_1.getWorkLanguage)(),
|
|
3863
|
+
toolName: repeatedToolCallInspection.toolName,
|
|
3864
|
+
callIds: repeatedToolCallInspection.callIds,
|
|
3865
|
+
});
|
|
3866
|
+
log_1.log.error('kernel-driver stopped after repeated identical tool calls ignored guidance', undefined, {
|
|
3867
|
+
rootId: dlg.id.rootId,
|
|
3868
|
+
selfId: dlg.id.selfId,
|
|
3869
|
+
course: dlg.activeGenCourseOrUndefined ?? dlg.currentCourse,
|
|
3870
|
+
genseq: dlg.activeGenSeq,
|
|
3871
|
+
toolName: repeatedToolCallInspection.toolName,
|
|
3872
|
+
callIds: repeatedToolCallInspection.callIds,
|
|
3873
|
+
});
|
|
3874
|
+
await dlg.streamError(detail);
|
|
3875
|
+
throw new gen_1.LlmStreamErrorEmittedError({
|
|
3876
|
+
detail,
|
|
3877
|
+
i18nStopReason: (0, stop_reason_i18n_1.buildHumanSystemStopReasonTextI18n)({ detail }),
|
|
3878
|
+
});
|
|
3879
|
+
}
|
|
3880
|
+
await persistAndEmitRuntimeGuide(dlg, repeatedToolCallInspection.reminderContent);
|
|
3881
|
+
repeatedToolCallMonitor.lastReminderGenseq = dlg.activeGenSeq;
|
|
3882
|
+
repeatedToolCallMonitor.sequence = undefined;
|
|
3883
|
+
routed = {
|
|
3884
|
+
...routed,
|
|
3885
|
+
repeatedToolCallReminderCallIds: repeatedToolCallInspection.callIds,
|
|
3886
|
+
};
|
|
3887
|
+
}
|
|
3521
3888
|
const persistedFbrState = await loadDialogFbrState(dlg);
|
|
3522
3889
|
if (persistedFbrState) {
|
|
3523
3890
|
if (persistedFbrState.phase === 'finalization') {
|
|
@@ -3564,10 +3931,11 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3564
3931
|
language: (0, work_language_1.getWorkLanguage)(),
|
|
3565
3932
|
finalizationAttempts: persistedFbrState.effort,
|
|
3566
3933
|
}),
|
|
3567
|
-
responseGenseq:
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3934
|
+
responseGenseq: resolveProgrammaticFbrConclusionGenseq({
|
|
3935
|
+
dlg,
|
|
3936
|
+
lastAssistantSayingGenseq,
|
|
3937
|
+
lastFunctionCallGenseq,
|
|
3938
|
+
}),
|
|
3571
3939
|
replyResolutionCallId: `fbr-conclusion-${(0, id_1.generateShortId)()}`,
|
|
3572
3940
|
};
|
|
3573
3941
|
if (!isFbrSideDialog(dlg)) {
|
|
@@ -3608,6 +3976,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3608
3976
|
// trigger another immediate generation round by themselves.
|
|
3609
3977
|
const shouldStartImmediatePostToolGeneration = routed.hasImmediateFollowupToolCalls ||
|
|
3610
3978
|
routed.hasImmediateTellaskOutputs ||
|
|
3979
|
+
routed.repeatedToolCallReminderCallIds.length > 0 ||
|
|
3611
3980
|
invalidFuncCallCount > 0;
|
|
3612
3981
|
if (shouldStartImmediatePostToolGeneration) {
|
|
3613
3982
|
const expectation = buildImmediateFollowupTriggerExpectation({
|
|
@@ -3622,6 +3991,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3622
3991
|
`(dialog=${dlg.id.valueOf()}, course=${String(dlg.activeGenCourseOrUndefined ?? dlg.currentCourse)}, ` +
|
|
3623
3992
|
`genseq=${String(dlg.activeGenSeq)}, immediateToolCalls=${String(routed.hasImmediateFollowupToolCalls)}, ` +
|
|
3624
3993
|
`immediateTellaskOutputs=${String(routed.hasImmediateTellaskOutputs)}, ` +
|
|
3994
|
+
`repeatedToolCallReminderCallIds=${routed.repeatedToolCallReminderCallIds.join('+')}, ` +
|
|
3625
3995
|
`invalidFuncCallCount=${String(invalidFuncCallCount)})`);
|
|
3626
3996
|
}
|
|
3627
3997
|
immediateFollowupTriggerExpectation = expectation;
|
|
@@ -32,6 +32,13 @@ export declare function buildFbrFinalizationPrompt(args: {
|
|
|
32
32
|
total: number;
|
|
33
33
|
language: LanguageCode;
|
|
34
34
|
}): string;
|
|
35
|
+
export declare function buildFbrContextCautionFinalizationPrompt(args: {
|
|
36
|
+
attempt: number;
|
|
37
|
+
language: LanguageCode;
|
|
38
|
+
}): string;
|
|
39
|
+
export declare function buildProgrammaticFbrContextCriticalContent(args: {
|
|
40
|
+
language: LanguageCode;
|
|
41
|
+
}): string;
|
|
35
42
|
export declare function buildProgrammaticFbrUnreasonableSituationContent(args: {
|
|
36
43
|
language: LanguageCode;
|
|
37
44
|
finalizationAttempts: number;
|
|
@@ -40,6 +47,8 @@ export declare function inspectFbrConclusionAttempt(messages: readonly ChatMessa
|
|
|
40
47
|
export declare function createInitialFbrState(effort: number): DialogFbrState;
|
|
41
48
|
export declare function markFbrPromptDelivered(state: DialogFbrState): DialogFbrState;
|
|
42
49
|
export declare function isFbrFinalizationState(state: DialogFbrState): boolean;
|
|
50
|
+
export declare function isFbrContextCautionFinalizationState(state: DialogFbrState): boolean;
|
|
51
|
+
export declare function forceFbrContextCautionFinalizationState(state: DialogFbrState): DialogFbrState;
|
|
43
52
|
export declare function advanceFbrState(state: DialogFbrState): DialogFbrState | undefined;
|
|
44
53
|
export declare function buildFbrPromptForState(args: {
|
|
45
54
|
state: DialogFbrState;
|