dominds 1.27.1 → 1.27.2
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/dialog.d.ts +2 -1
- package/dist/dialog.js +1 -0
- package/dist/llm/kernel-driver/drive.js +219 -1
- 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/persistence.js +4 -0
- package/dist/server/dominds-runtime-status.js +23 -0
- package/dist/server/static-server.js +20 -5
- package/package.json +4 -4
- 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
package/dist/dialog.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { ContextHealthSnapshot } from '@longrun-ai/kernel/types/context-health';
|
|
16
16
|
import type { DialogEvent, NativeToolCallPayload, ReminderContent, WebSearchCallAction, WebSearchCallSource } from '@longrun-ai/kernel/types/dialog';
|
|
17
|
-
import type { DialogCalleeReplyTarget, DialogQueuedDeferredQ4HAnswerState, DialogQueuedPromptState, DialogQueuedUserGenerationBoundaryState, DialogRunControlSpec, DialogRuntimePrompt, DialogUserPrompt, DriveIntent } from '@longrun-ai/kernel/types/drive-intent';
|
|
17
|
+
import type { DialogCalleeReplyTarget, DialogQueuedDeferredQ4HAnswerState, DialogQueuedPromptState, DialogQueuedUserGenerationBoundaryState, DialogRunControlSpec, DialogRuntimePrompt, DialogRuntimeSideDialogPrompt, DialogUserPrompt, DriveIntent } from '@longrun-ai/kernel/types/drive-intent';
|
|
18
18
|
import type { LanguageCode } from '@longrun-ai/kernel/types/language';
|
|
19
19
|
import type { ActiveCalleesFile, CalleeCourseNumber, CalleeGenerationSeqNumber, CallSiteCourseNo, CallSiteGenseqNo, DialogAskerStackState, DialogLatestFile, DialogMetadataFile, DialogNextStepTrigger, HumanQuestion, ProviderData, ReasoningPayload, TellaskCallRecordName, TellaskReplyDirective } from '@longrun-ai/kernel/types/storage';
|
|
20
20
|
import { ChatMessage, FuncResultMsg, TellaskCarryoverMsg, TellaskResultMsg } from './llm/client';
|
|
@@ -130,6 +130,7 @@ export declare function buildSideDialogAskerStack(args: {
|
|
|
130
130
|
askerDialogId: string;
|
|
131
131
|
assignment: AssignmentFromAsker;
|
|
132
132
|
}): DialogAskerStackState;
|
|
133
|
+
export declare function buildSideDialogAssignmentPromptMeta(sideDialog: SideDialog): Pick<DialogRuntimeSideDialogPrompt, 'tellaskReplyDirective' | 'calleeDialogReplyTarget'>;
|
|
133
134
|
/**
|
|
134
135
|
* Abstract base class for all dialog types.
|
|
135
136
|
* Contains common properties and methods shared between MainDialog and SideDialog.
|
package/dist/dialog.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DialogStore = exports.MainDialog = exports.SideDialog = exports.Dialog = exports.DialogID = exports.InvalidReminderIndexError = void 0;
|
|
4
4
|
exports.scheduleGlobalDialogMutexCleanupForRoot = scheduleGlobalDialogMutexCleanupForRoot;
|
|
5
5
|
exports.buildSideDialogAskerStack = buildSideDialogAskerStack;
|
|
6
|
+
exports.buildSideDialogAssignmentPromptMeta = buildSideDialogAssignmentPromptMeta;
|
|
6
7
|
const id_1 = require("@longrun-ai/kernel/utils/id");
|
|
7
8
|
const time_1 = require("@longrun-ai/kernel/utils/time");
|
|
8
9
|
const util_1 = require("util");
|
|
@@ -1381,6 +1381,161 @@ function formatInvalidFuncCallRuntimeGuide(language, call) {
|
|
|
1381
1381
|
.filter((line) => line.length > 0)
|
|
1382
1382
|
.join('\n');
|
|
1383
1383
|
}
|
|
1384
|
+
function stableJsonStringify(value) {
|
|
1385
|
+
if (value === null)
|
|
1386
|
+
return 'null';
|
|
1387
|
+
if (typeof value === 'string')
|
|
1388
|
+
return JSON.stringify(value);
|
|
1389
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
1390
|
+
return JSON.stringify(value);
|
|
1391
|
+
if (Array.isArray(value)) {
|
|
1392
|
+
return `[${value.map((entry) => stableJsonStringify(entry)).join(',')}]`;
|
|
1393
|
+
}
|
|
1394
|
+
if (typeof value === 'object') {
|
|
1395
|
+
const record = value;
|
|
1396
|
+
return `{${Object.keys(record)
|
|
1397
|
+
.sort()
|
|
1398
|
+
.map((key) => `${JSON.stringify(key)}:${stableJsonStringify(record[key])}`)
|
|
1399
|
+
.join(',')}}`;
|
|
1400
|
+
}
|
|
1401
|
+
return JSON.stringify(String(value));
|
|
1402
|
+
}
|
|
1403
|
+
function canonicalizeToolCallArguments(rawArguments) {
|
|
1404
|
+
try {
|
|
1405
|
+
return stableJsonStringify(JSON.parse(rawArguments));
|
|
1406
|
+
}
|
|
1407
|
+
catch {
|
|
1408
|
+
return rawArguments;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
function canonicalizeToolResult(result) {
|
|
1412
|
+
return stableJsonStringify({
|
|
1413
|
+
content: result.content,
|
|
1414
|
+
contentItems: result.contentItems ?? null,
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
function buildToolResultFingerprint(call, result) {
|
|
1418
|
+
return {
|
|
1419
|
+
toolName: call.name,
|
|
1420
|
+
argumentsFingerprint: canonicalizeToolCallArguments(call.arguments),
|
|
1421
|
+
resultFingerprint: canonicalizeToolResult(result),
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
function sameToolResultFingerprint(left, right) {
|
|
1425
|
+
return (left.toolName === right.toolName &&
|
|
1426
|
+
left.argumentsFingerprint === right.argumentsFingerprint &&
|
|
1427
|
+
left.resultFingerprint === right.resultFingerprint);
|
|
1428
|
+
}
|
|
1429
|
+
function formatRepeatedToolCallRuntimeGuide(args) {
|
|
1430
|
+
const resultPreview = args.resultContent.length > 800
|
|
1431
|
+
? `${args.resultContent.slice(0, 800)}\n...`
|
|
1432
|
+
: args.resultContent;
|
|
1433
|
+
if (args.language === 'en') {
|
|
1434
|
+
return [
|
|
1435
|
+
'[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.',
|
|
1436
|
+
'',
|
|
1437
|
+
`- tool: ${args.toolName}`,
|
|
1438
|
+
`- callIds: ${args.callIds.join(', ')}`,
|
|
1439
|
+
'- arguments:',
|
|
1440
|
+
'```json',
|
|
1441
|
+
args.argumentsFingerprint,
|
|
1442
|
+
'```',
|
|
1443
|
+
'- repeated result:',
|
|
1444
|
+
'```text',
|
|
1445
|
+
resultPreview,
|
|
1446
|
+
'```',
|
|
1447
|
+
'',
|
|
1448
|
+
'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.',
|
|
1449
|
+
].join('\n');
|
|
1450
|
+
}
|
|
1451
|
+
return [
|
|
1452
|
+
'[Dominds 提示] 你刚才连续三次调用了同一个工具,参数完全相同,Dominds 观察到三次工具返回值也完全相同。',
|
|
1453
|
+
'',
|
|
1454
|
+
`- 工具: ${args.toolName}`,
|
|
1455
|
+
`- callIds: ${args.callIds.join(', ')}`,
|
|
1456
|
+
'- 参数:',
|
|
1457
|
+
'```json',
|
|
1458
|
+
args.argumentsFingerprint,
|
|
1459
|
+
'```',
|
|
1460
|
+
'- 重复返回值:',
|
|
1461
|
+
'```text',
|
|
1462
|
+
resultPreview,
|
|
1463
|
+
'```',
|
|
1464
|
+
'',
|
|
1465
|
+
'请先质疑这个行为,不要机械地再次调用同一个工具。同样的调用大概率不会产生新信息。请重新阅读用户诉求和工具返回值,然后自行纠正:基于已有信息作答、换一种行动,或明确说明当前阻塞点。',
|
|
1466
|
+
].join('\n');
|
|
1467
|
+
}
|
|
1468
|
+
function formatRepeatedToolCallStoppedDetail(args) {
|
|
1469
|
+
if (args.language === 'en') {
|
|
1470
|
+
return (`Stopped because the LLM ignored Dominds' repeated-tool-call correction notice and again made ` +
|
|
1471
|
+
`the same tool call three times with identical results. This indicates an LLM behavior/personality problem: ` +
|
|
1472
|
+
`it is looping on ${args.toolName} instead of reconsidering the task. callIds=${args.callIds.join(', ')}`);
|
|
1473
|
+
}
|
|
1474
|
+
return (`已停止:LLM 已收到 Dominds 的重复工具调用纠正提醒,但仍然再次连续三次调用同一个工具并得到完全相同的结果。` +
|
|
1475
|
+
`这说明当前 LLM 存在行为/个性问题:它在 ${args.toolName} 上机械循环,而不是重新判断任务。` +
|
|
1476
|
+
`callIds=${args.callIds.join(', ')}`);
|
|
1477
|
+
}
|
|
1478
|
+
const REPEATED_TOOL_CALL_STOP_WINDOW_GENSEQS = 5;
|
|
1479
|
+
function inspectRepeatedToolCallRound(args) {
|
|
1480
|
+
ensureRepeatedToolCallMonitorCourse(args.state, args.currentCourse);
|
|
1481
|
+
const recentPairs = [];
|
|
1482
|
+
for (let index = 0; index < args.pairedMessages.length - 1; index += 1) {
|
|
1483
|
+
const call = args.pairedMessages[index];
|
|
1484
|
+
const result = args.pairedMessages[index + 1];
|
|
1485
|
+
if (call?.type !== 'func_call_msg' || result?.type !== 'func_result_msg') {
|
|
1486
|
+
continue;
|
|
1487
|
+
}
|
|
1488
|
+
if (result.id !== call.id) {
|
|
1489
|
+
continue;
|
|
1490
|
+
}
|
|
1491
|
+
recentPairs.push({
|
|
1492
|
+
call,
|
|
1493
|
+
result,
|
|
1494
|
+
fingerprint: buildToolResultFingerprint(call, result),
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
for (const pair of recentPairs) {
|
|
1498
|
+
const currentSequence = args.state.sequence;
|
|
1499
|
+
if (currentSequence !== undefined &&
|
|
1500
|
+
sameToolResultFingerprint(currentSequence.fingerprint, pair.fingerprint)) {
|
|
1501
|
+
currentSequence.callIds.push(pair.call.id);
|
|
1502
|
+
if (currentSequence.callIds.length > 3) {
|
|
1503
|
+
currentSequence.callIds.splice(0, currentSequence.callIds.length - 3);
|
|
1504
|
+
}
|
|
1505
|
+
currentSequence.resultContent = pair.result.content;
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
args.state.sequence = {
|
|
1509
|
+
fingerprint: pair.fingerprint,
|
|
1510
|
+
callIds: [pair.call.id],
|
|
1511
|
+
resultContent: pair.result.content,
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
const sequence = args.state.sequence;
|
|
1515
|
+
if (sequence === undefined || sequence.callIds.length < 3) {
|
|
1516
|
+
continue;
|
|
1517
|
+
}
|
|
1518
|
+
const recentReminder = args.state.lastReminderGenseq !== undefined &&
|
|
1519
|
+
pair.call.genseq > args.state.lastReminderGenseq &&
|
|
1520
|
+
pair.call.genseq - args.state.lastReminderGenseq <= REPEATED_TOOL_CALL_STOP_WINDOW_GENSEQS;
|
|
1521
|
+
const callIds = [...sequence.callIds];
|
|
1522
|
+
return {
|
|
1523
|
+
toolName: pair.call.name,
|
|
1524
|
+
callIds,
|
|
1525
|
+
argumentsFingerprint: pair.fingerprint.argumentsFingerprint,
|
|
1526
|
+
resultContent: sequence.resultContent,
|
|
1527
|
+
reminderContent: formatRepeatedToolCallRuntimeGuide({
|
|
1528
|
+
language: args.language,
|
|
1529
|
+
toolName: pair.call.name,
|
|
1530
|
+
callIds,
|
|
1531
|
+
argumentsFingerprint: pair.fingerprint.argumentsFingerprint,
|
|
1532
|
+
resultContent: sequence.resultContent,
|
|
1533
|
+
}),
|
|
1534
|
+
repeatedAfterReminder: recentReminder,
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
return undefined;
|
|
1538
|
+
}
|
|
1384
1539
|
async function persistInvalidFuncCallRuntimeGuide(args) {
|
|
1385
1540
|
const { dlg, call } = args;
|
|
1386
1541
|
const sourceText = args.source === 'streamed' ? 'streamed' : 'batch';
|
|
@@ -1405,6 +1560,17 @@ async function persistInvalidFuncCallRuntimeGuide(args) {
|
|
|
1405
1560
|
});
|
|
1406
1561
|
await persistAndPostRuntimeGuide(dlg, content);
|
|
1407
1562
|
}
|
|
1563
|
+
function resetRepeatedToolCallMonitor(state) {
|
|
1564
|
+
state.sequence = undefined;
|
|
1565
|
+
state.lastReminderGenseq = undefined;
|
|
1566
|
+
}
|
|
1567
|
+
function ensureRepeatedToolCallMonitorCourse(state, course) {
|
|
1568
|
+
if (state.course === course) {
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
resetRepeatedToolCallMonitor(state);
|
|
1572
|
+
state.course = course;
|
|
1573
|
+
}
|
|
1408
1574
|
function isQueuedNewCourseRuntimePrompt(prompt) {
|
|
1409
1575
|
return (prompt?.kind === 'new_course_runtime_guide' ||
|
|
1410
1576
|
prompt?.kind === 'new_course_runtime_reply' ||
|
|
@@ -1458,6 +1624,7 @@ function summarizeRoutedFunctionResult(routed) {
|
|
|
1458
1624
|
immediateFollowupCallIds: routed.immediateFollowupCallIds,
|
|
1459
1625
|
immediateTellaskOutputCallIds: routed.immediateTellaskOutputCallIds,
|
|
1460
1626
|
invalidTellaskCallIds: routed.invalidTellaskCallIds,
|
|
1627
|
+
repeatedToolCallReminderCallIds: routed.repeatedToolCallReminderCallIds,
|
|
1461
1628
|
shouldStopAfterReplyTool: routed.shouldStopAfterReplyTool,
|
|
1462
1629
|
shouldStopAfterPendingTellaskWait: routed.shouldStopAfterPendingTellaskWait,
|
|
1463
1630
|
pairedMessageTypes: routed.pairedMessages.map((msg) => msg.type),
|
|
@@ -1511,6 +1678,8 @@ function shouldCaptureUnexpectedIdleAfterToolRound(args) {
|
|
|
1511
1678
|
return true;
|
|
1512
1679
|
if (diagnostics.routed.immediateTellaskOutputCallIds.length > 0)
|
|
1513
1680
|
return true;
|
|
1681
|
+
if (diagnostics.routed.repeatedToolCallReminderCallIds.length > 0)
|
|
1682
|
+
return true;
|
|
1514
1683
|
return false;
|
|
1515
1684
|
}
|
|
1516
1685
|
function sanitizeDebugFileSegment(value) {
|
|
@@ -1694,6 +1863,12 @@ function buildImmediateFollowupTriggerExpectation(args) {
|
|
|
1694
1863
|
callIds: [...invalidRecoveryCallIds],
|
|
1695
1864
|
});
|
|
1696
1865
|
}
|
|
1866
|
+
if (args.routed.repeatedToolCallReminderCallIds.length > 0) {
|
|
1867
|
+
reasons.push({
|
|
1868
|
+
kind: 'repeated_tool_call_reminder',
|
|
1869
|
+
callIds: args.routed.repeatedToolCallReminderCallIds,
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1697
1872
|
if (reasons.length === 0) {
|
|
1698
1873
|
return undefined;
|
|
1699
1874
|
}
|
|
@@ -2062,6 +2237,7 @@ async function executeFunctionRound(args) {
|
|
|
2062
2237
|
immediateFollowupCallIds: [],
|
|
2063
2238
|
immediateTellaskOutputCallIds: [],
|
|
2064
2239
|
invalidTellaskCallIds: [],
|
|
2240
|
+
repeatedToolCallReminderCallIds: [],
|
|
2065
2241
|
shouldStopAfterReplyTool: false,
|
|
2066
2242
|
shouldStopAfterPendingTellaskWait: false,
|
|
2067
2243
|
pairedMessages: [],
|
|
@@ -2180,6 +2356,7 @@ async function executeFunctionRound(args) {
|
|
|
2180
2356
|
immediateFollowupCallIds,
|
|
2181
2357
|
immediateTellaskOutputCallIds: tellaskRound.immediateTellaskOutputCallIds,
|
|
2182
2358
|
invalidTellaskCallIds: tellaskRound.invalidTellaskCallIds,
|
|
2359
|
+
repeatedToolCallReminderCallIds: [],
|
|
2183
2360
|
shouldStopAfterReplyTool: tellaskRound.shouldStopAfterReplyTool,
|
|
2184
2361
|
shouldStopAfterPendingTellaskWait: tellaskRound.shouldStopAfterPendingTellaskWait,
|
|
2185
2362
|
pairedMessages,
|
|
@@ -2390,6 +2567,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
2390
2567
|
let fbrConclusion;
|
|
2391
2568
|
let pubRemindersVer = dlg.remindersVer;
|
|
2392
2569
|
let lastToolRoundStopDiagnostics;
|
|
2570
|
+
const repeatedToolCallMonitor = {};
|
|
2393
2571
|
let pendingPrompt = humanPrompt;
|
|
2394
2572
|
let resolvingImmediateToolResultForUserPrompt = false;
|
|
2395
2573
|
let resolvingImmediateToolResultUserPromptMsgId;
|
|
@@ -2591,6 +2769,9 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
2591
2769
|
let llmGenModelForGen = model;
|
|
2592
2770
|
const currentPrompt = pendingPrompt;
|
|
2593
2771
|
const currentReplyTarget = currentPrompt?.calleeDialogReplyTarget;
|
|
2772
|
+
if (currentGenerationBelongsToUserPrompt) {
|
|
2773
|
+
resetRepeatedToolCallMonitor(repeatedToolCallMonitor);
|
|
2774
|
+
}
|
|
2594
2775
|
let currentBusinessContinuation = driveOptions?.businessContinuation ?? { kind: 'none' };
|
|
2595
2776
|
if (currentPrompt?.tellaskReplyDirective !== undefined) {
|
|
2596
2777
|
currentBusinessContinuation = {
|
|
@@ -3472,7 +3653,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3472
3653
|
: currentGenerationBelongsToUserToolChain
|
|
3473
3654
|
? currentUserPromptMsgId
|
|
3474
3655
|
: undefined;
|
|
3475
|
-
|
|
3656
|
+
let routed = await executeFunctionRound({
|
|
3476
3657
|
dlg,
|
|
3477
3658
|
agent,
|
|
3478
3659
|
agentTools,
|
|
@@ -3518,6 +3699,41 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3518
3699
|
newMsgs.push(...routed.pairedMessages);
|
|
3519
3700
|
}
|
|
3520
3701
|
await dlg.addChatMessages(...newMsgs);
|
|
3702
|
+
const repeatedToolCallInspection = inspectRepeatedToolCallRound({
|
|
3703
|
+
state: repeatedToolCallMonitor,
|
|
3704
|
+
currentCourse: dlg.activeGenCourseOrUndefined ?? dlg.currentCourse,
|
|
3705
|
+
pairedMessages: routed.pairedMessages,
|
|
3706
|
+
language: (0, work_language_1.getWorkLanguage)(),
|
|
3707
|
+
});
|
|
3708
|
+
if (repeatedToolCallInspection !== undefined) {
|
|
3709
|
+
if (repeatedToolCallInspection.repeatedAfterReminder) {
|
|
3710
|
+
const detail = formatRepeatedToolCallStoppedDetail({
|
|
3711
|
+
language: (0, work_language_1.getWorkLanguage)(),
|
|
3712
|
+
toolName: repeatedToolCallInspection.toolName,
|
|
3713
|
+
callIds: repeatedToolCallInspection.callIds,
|
|
3714
|
+
});
|
|
3715
|
+
log_1.log.error('kernel-driver stopped after repeated identical tool calls ignored guidance', undefined, {
|
|
3716
|
+
rootId: dlg.id.rootId,
|
|
3717
|
+
selfId: dlg.id.selfId,
|
|
3718
|
+
course: dlg.activeGenCourseOrUndefined ?? dlg.currentCourse,
|
|
3719
|
+
genseq: dlg.activeGenSeq,
|
|
3720
|
+
toolName: repeatedToolCallInspection.toolName,
|
|
3721
|
+
callIds: repeatedToolCallInspection.callIds,
|
|
3722
|
+
});
|
|
3723
|
+
await dlg.streamError(detail);
|
|
3724
|
+
throw new gen_1.LlmStreamErrorEmittedError({
|
|
3725
|
+
detail,
|
|
3726
|
+
i18nStopReason: (0, stop_reason_i18n_1.buildHumanSystemStopReasonTextI18n)({ detail }),
|
|
3727
|
+
});
|
|
3728
|
+
}
|
|
3729
|
+
await persistAndEmitRuntimeGuide(dlg, repeatedToolCallInspection.reminderContent);
|
|
3730
|
+
repeatedToolCallMonitor.lastReminderGenseq = dlg.activeGenSeq;
|
|
3731
|
+
repeatedToolCallMonitor.sequence = undefined;
|
|
3732
|
+
routed = {
|
|
3733
|
+
...routed,
|
|
3734
|
+
repeatedToolCallReminderCallIds: repeatedToolCallInspection.callIds,
|
|
3735
|
+
};
|
|
3736
|
+
}
|
|
3521
3737
|
const persistedFbrState = await loadDialogFbrState(dlg);
|
|
3522
3738
|
if (persistedFbrState) {
|
|
3523
3739
|
if (persistedFbrState.phase === 'finalization') {
|
|
@@ -3608,6 +3824,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3608
3824
|
// trigger another immediate generation round by themselves.
|
|
3609
3825
|
const shouldStartImmediatePostToolGeneration = routed.hasImmediateFollowupToolCalls ||
|
|
3610
3826
|
routed.hasImmediateTellaskOutputs ||
|
|
3827
|
+
routed.repeatedToolCallReminderCallIds.length > 0 ||
|
|
3611
3828
|
invalidFuncCallCount > 0;
|
|
3612
3829
|
if (shouldStartImmediatePostToolGeneration) {
|
|
3613
3830
|
const expectation = buildImmediateFollowupTriggerExpectation({
|
|
@@ -3622,6 +3839,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
3622
3839
|
`(dialog=${dlg.id.valueOf()}, course=${String(dlg.activeGenCourseOrUndefined ?? dlg.currentCourse)}, ` +
|
|
3623
3840
|
`genseq=${String(dlg.activeGenSeq)}, immediateToolCalls=${String(routed.hasImmediateFollowupToolCalls)}, ` +
|
|
3624
3841
|
`immediateTellaskOutputs=${String(routed.hasImmediateTellaskOutputs)}, ` +
|
|
3842
|
+
`repeatedToolCallReminderCallIds=${routed.repeatedToolCallReminderCallIds.join('+')}, ` +
|
|
3625
3843
|
`invalidFuncCallCount=${String(invalidFuncCallCount)})`);
|
|
3626
3844
|
}
|
|
3627
3845
|
immediateFollowupTriggerExpectation = expectation;
|
|
@@ -69,12 +69,6 @@ async function queueReplyReminderFollowUp(args) {
|
|
|
69
69
|
function isReplyToolReminderPrompt(prompt) {
|
|
70
70
|
return typeof prompt?.content === 'string' && (0, reply_prompt_copy_1.isReplyToolReminderPromptContent)(prompt.content);
|
|
71
71
|
}
|
|
72
|
-
function hasSameReplyDirective(left, right) {
|
|
73
|
-
return (left.expectedReplyCallName === right.expectedReplyCallName &&
|
|
74
|
-
left.targetDialogId === right.targetDialogId &&
|
|
75
|
-
left.targetCallId === right.targetCallId &&
|
|
76
|
-
left.tellaskContent === right.tellaskContent);
|
|
77
|
-
}
|
|
78
72
|
function hasSameCalleeReplyTarget(left, right) {
|
|
79
73
|
return (left.callerDialogId === right.callerDialogId &&
|
|
80
74
|
left.callId === right.callId &&
|
|
@@ -82,29 +76,6 @@ function hasSameCalleeReplyTarget(left, right) {
|
|
|
82
76
|
left.callSiteCourse === right.callSiteCourse &&
|
|
83
77
|
left.callSiteGenseq === right.callSiteGenseq);
|
|
84
78
|
}
|
|
85
|
-
function buildCurrentSideDialogAssignmentReplyDirective(dialog) {
|
|
86
|
-
switch (dialog.assignmentFromAsker.callName) {
|
|
87
|
-
case 'tellask':
|
|
88
|
-
return {
|
|
89
|
-
expectedReplyCallName: 'replyTellask',
|
|
90
|
-
targetDialogId: dialog.assignmentFromAsker.askerDialogId,
|
|
91
|
-
targetCallId: dialog.assignmentFromAsker.callId,
|
|
92
|
-
tellaskContent: dialog.assignmentFromAsker.tellaskContent,
|
|
93
|
-
};
|
|
94
|
-
case 'tellaskSessionless':
|
|
95
|
-
case 'freshBootsReasoning':
|
|
96
|
-
return {
|
|
97
|
-
expectedReplyCallName: 'replyTellaskSessionless',
|
|
98
|
-
targetDialogId: dialog.assignmentFromAsker.askerDialogId,
|
|
99
|
-
targetCallId: dialog.assignmentFromAsker.callId,
|
|
100
|
-
tellaskContent: dialog.assignmentFromAsker.tellaskContent,
|
|
101
|
-
};
|
|
102
|
-
default: {
|
|
103
|
-
const _exhaustive = dialog.assignmentFromAsker.callName;
|
|
104
|
-
throw new Error(`Unsupported sideDialog assignment callName: ${_exhaustive}`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
79
|
function isQueuedReplyObligationContinuation(prompt) {
|
|
109
80
|
return ((prompt.kind === 'new_course_runtime_reply' ||
|
|
110
81
|
prompt.kind === 'new_course_runtime_sideDialog') &&
|
|
@@ -151,8 +122,8 @@ async function claimQueuedReplyObligationContinuation(args) {
|
|
|
151
122
|
return 'stale';
|
|
152
123
|
}
|
|
153
124
|
if (args.dialog instanceof dialog_1.SideDialog) {
|
|
154
|
-
const assignmentDirective =
|
|
155
|
-
if (hasSameReplyDirective(assignmentDirective, directive)) {
|
|
125
|
+
const assignmentDirective = (0, dialog_1.buildSideDialogAssignmentPromptMeta)(args.dialog).tellaskReplyDirective;
|
|
126
|
+
if ((0, reply_guidance_1.hasSameReplyDirective)(assignmentDirective, directive)) {
|
|
156
127
|
return 'claimed';
|
|
157
128
|
}
|
|
158
129
|
}
|
|
@@ -163,7 +134,7 @@ async function claimQueuedReplyObligationContinuation(args) {
|
|
|
163
134
|
if (activeDirective.targetCallId !== directive.targetCallId) {
|
|
164
135
|
return 'stale';
|
|
165
136
|
}
|
|
166
|
-
if (!hasSameReplyDirective(activeDirective, directive)) {
|
|
137
|
+
if (!(0, reply_guidance_1.hasSameReplyDirective)(activeDirective, directive)) {
|
|
167
138
|
throw new Error(`reply obligation continuation invariant violation: active obligation changed for callId=${directive.targetCallId} ` +
|
|
168
139
|
`(dialog=${args.dialog.id.valueOf()}, expectedReplyCallName=${directive.expectedReplyCallName}, ` +
|
|
169
140
|
`activeReplyCallName=${activeDirective.expectedReplyCallName}, targetDialogId=${directive.targetDialogId}, ` +
|
|
@@ -190,7 +161,7 @@ async function resolveSideDialogReplyDirectiveForAssistantOutput(args) {
|
|
|
190
161
|
if (latestHasTellaskResultForCallId(latest, targetCallId)) {
|
|
191
162
|
return args.currentDirective;
|
|
192
163
|
}
|
|
193
|
-
const assignmentDirective =
|
|
164
|
+
const assignmentDirective = (0, dialog_1.buildSideDialogAssignmentPromptMeta)(args.dialog).tellaskReplyDirective;
|
|
194
165
|
if (assignmentDirective.targetCallId !== targetCallId) {
|
|
195
166
|
return args.currentDirective;
|
|
196
167
|
}
|
|
@@ -204,7 +175,7 @@ async function resolveSideDialogReplyDirectiveForAssistantOutput(args) {
|
|
|
204
175
|
return args.currentDirective;
|
|
205
176
|
}
|
|
206
177
|
const activeDirective = await (0, tellask_special_1.loadActiveTellaskReplyDirective)(args.dialog);
|
|
207
|
-
if (activeDirective && !hasSameReplyDirective(activeDirective, assignmentDirective)) {
|
|
178
|
+
if (activeDirective && !(0, reply_guidance_1.hasSameReplyDirective)(activeDirective, assignmentDirective)) {
|
|
208
179
|
throw new Error(`sideDialog assistant output reply directive invariant violation: active obligation does not match latest assignment ` +
|
|
209
180
|
`(dialog=${args.dialog.id.valueOf()}, targetCallId=${targetCallId}, ` +
|
|
210
181
|
`activeTargetCallId=${activeDirective.targetCallId}, assignmentTargetCallId=${assignmentDirective.targetCallId})`);
|
|
@@ -796,7 +767,7 @@ function pendingRuntimePromptMatchesQueuePrompt(args) {
|
|
|
796
767
|
return args.prompt.kind === 'new_course_runtime_guide';
|
|
797
768
|
}
|
|
798
769
|
if (args.prompt.kind === 'new_course_runtime_guide' ||
|
|
799
|
-
!hasSameReplyDirective(args.pendingRuntimePrompt.tellaskReplyDirective, args.prompt.tellaskReplyDirective)) {
|
|
770
|
+
!(0, reply_guidance_1.hasSameReplyDirective)(args.pendingRuntimePrompt.tellaskReplyDirective, args.prompt.tellaskReplyDirective)) {
|
|
800
771
|
return false;
|
|
801
772
|
}
|
|
802
773
|
if (args.pendingRuntimePrompt.calleeDialogReplyTarget === undefined) {
|
|
@@ -1135,6 +1106,8 @@ async function executeDriveRound(args) {
|
|
|
1135
1106
|
};
|
|
1136
1107
|
let calleeDialogReplyTarget = replyContinuationScope.target();
|
|
1137
1108
|
let activeTellaskReplyDirective = replyContinuationScope.directive();
|
|
1109
|
+
let suppressedCalleeDialogReplyTargetAfterUserInterjection;
|
|
1110
|
+
let suppressedTellaskReplyDirectiveAfterUserInterjection;
|
|
1138
1111
|
let activePromptWasReplyToolReminder = false;
|
|
1139
1112
|
let shouldPauseAfterLocalUserInterjection = false;
|
|
1140
1113
|
let resumeFromInterjectionPause = false;
|
|
@@ -1559,6 +1532,14 @@ async function executeDriveRound(args) {
|
|
|
1559
1532
|
replyGuidance.suppressInterDialogReplyGuidance;
|
|
1560
1533
|
activeTellaskReplyDirective =
|
|
1561
1534
|
replyGuidance.activeReplyDirective ?? replyContinuationScope.directive();
|
|
1535
|
+
suppressedTellaskReplyDirectiveAfterUserInterjection =
|
|
1536
|
+
replyGuidance.suppressInterDialogReplyGuidance
|
|
1537
|
+
? replyGuidance.suppressedTellaskReplyDirective
|
|
1538
|
+
: undefined;
|
|
1539
|
+
suppressedCalleeDialogReplyTargetAfterUserInterjection =
|
|
1540
|
+
replyGuidance.suppressInterDialogReplyGuidance
|
|
1541
|
+
? replyGuidance.suppressedCalleeDialogReplyTarget
|
|
1542
|
+
: undefined;
|
|
1562
1543
|
activePromptWasReplyToolReminder = isReplyToolReminderPrompt(effectivePrompt);
|
|
1563
1544
|
let activePromptCarriesReplyDirective = effectivePrompt?.tellaskReplyDirective !== undefined &&
|
|
1564
1545
|
activeTellaskReplyDirective !== undefined &&
|
|
@@ -1666,29 +1647,50 @@ async function executeDriveRound(args) {
|
|
|
1666
1647
|
backgroundCalleeBlocksImplicitReply,
|
|
1667
1648
|
});
|
|
1668
1649
|
}
|
|
1669
|
-
else if (activeTellaskReplyDirective === undefined) {
|
|
1670
|
-
log_1.log.debug('kernel-driver skip sideDialog answering reminder because no active tellask reply directive is bound to this drive', undefined, {
|
|
1671
|
-
rootId: dialog.id.rootId,
|
|
1672
|
-
selfId: dialog.id.selfId,
|
|
1673
|
-
});
|
|
1674
|
-
}
|
|
1675
1650
|
else {
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
directive
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1651
|
+
const replyDirectiveForAnswering = activeTellaskReplyDirective ?? suppressedTellaskReplyDirectiveAfterUserInterjection;
|
|
1652
|
+
if (replyDirectiveForAnswering === undefined) {
|
|
1653
|
+
log_1.log.debug('kernel-driver skip sideDialog answering reminder because no active tellask reply directive is bound to this drive', undefined, {
|
|
1654
|
+
rootId: dialog.id.rootId,
|
|
1655
|
+
selfId: dialog.id.selfId,
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
else {
|
|
1659
|
+
if (calleeDialogReplyTarget !== undefined &&
|
|
1660
|
+
calleeDialogReplyTarget.callId !== replyDirectiveForAnswering.targetCallId) {
|
|
1661
|
+
throw new Error(`sideDialog answering reminder invariant violation: reply target callId does not match directive ` +
|
|
1662
|
+
`(dialog=${dialog.id.valueOf()}, targetCallId=${calleeDialogReplyTarget.callId}, ` +
|
|
1663
|
+
`directiveTargetCallId=${replyDirectiveForAnswering.targetCallId})`);
|
|
1664
|
+
}
|
|
1665
|
+
const currentAssignmentPromptMeta = (0, dialog_1.buildSideDialogAssignmentPromptMeta)(dialog);
|
|
1666
|
+
const currentAssignmentReplyTarget = (0, reply_guidance_1.hasSameReplyDirective)(replyDirectiveForAnswering, currentAssignmentPromptMeta.tellaskReplyDirective)
|
|
1667
|
+
? currentAssignmentPromptMeta.calleeDialogReplyTarget
|
|
1668
|
+
: undefined;
|
|
1669
|
+
const replyTargetForAnswering = calleeDialogReplyTarget ??
|
|
1670
|
+
(suppressedTellaskReplyDirectiveAfterUserInterjection !== undefined &&
|
|
1671
|
+
(0, reply_guidance_1.hasSameReplyDirective)(replyDirectiveForAnswering, suppressedTellaskReplyDirectiveAfterUserInterjection)
|
|
1672
|
+
? suppressedCalleeDialogReplyTargetAfterUserInterjection
|
|
1673
|
+
: undefined) ??
|
|
1674
|
+
currentAssignmentReplyTarget;
|
|
1675
|
+
const language = (0, work_language_1.getWorkLanguage)();
|
|
1676
|
+
followUp = buildRuntimeReplyReminderFollowUp({
|
|
1677
|
+
directive: replyDirectiveForAnswering,
|
|
1678
|
+
prompt: await buildAnsweringReplyReminderPrompt({
|
|
1679
|
+
dlg: dialog,
|
|
1680
|
+
directive: replyDirectiveForAnswering,
|
|
1681
|
+
language,
|
|
1682
|
+
}),
|
|
1682
1683
|
language,
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1684
|
+
calleeDialogReplyTarget: replyTargetForAnswering,
|
|
1685
|
+
});
|
|
1686
|
+
log_1.log.debug('kernel-driver queued sideDialog replyTellask reminder after answering-only output', undefined, {
|
|
1687
|
+
dialogId: dialog.id.valueOf(),
|
|
1688
|
+
targetCallId: replyDirectiveForAnswering.targetCallId,
|
|
1689
|
+
targetCallerDialogId: replyTargetForAnswering?.callerDialogId,
|
|
1690
|
+
resumedAfterUserInterjection: activeTellaskReplyDirective === undefined &&
|
|
1691
|
+
suppressedTellaskReplyDirectiveAfterUserInterjection !== undefined,
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1692
1694
|
}
|
|
1693
1695
|
}
|
|
1694
1696
|
if (dialog instanceof dialog_1.SideDialog &&
|
|
@@ -5,6 +5,7 @@ export declare function resolveReplyTargetAgentId(args: {
|
|
|
5
5
|
dlg: Dialog;
|
|
6
6
|
directive: TellaskReplyDirective;
|
|
7
7
|
}): Promise<string | undefined>;
|
|
8
|
+
export declare function hasSameReplyDirective(left: TellaskReplyDirective | undefined, right: TellaskReplyDirective | undefined): boolean;
|
|
8
9
|
export declare function resolvePromptReplyGuidance(args: {
|
|
9
10
|
dlg: Dialog;
|
|
10
11
|
prompt: KernelDriverPrompt | undefined;
|
|
@@ -14,6 +15,8 @@ export declare function resolvePromptReplyGuidance(args: {
|
|
|
14
15
|
isQ4HAnswerPrompt: boolean;
|
|
15
16
|
promptContent: string | undefined;
|
|
16
17
|
persistedTellaskReplyDirective: KernelDriverPrompt['tellaskReplyDirective'];
|
|
18
|
+
suppressedCalleeDialogReplyTarget: KernelDriverPrompt['calleeDialogReplyTarget'];
|
|
19
|
+
suppressedTellaskReplyDirective: KernelDriverPrompt['tellaskReplyDirective'];
|
|
17
20
|
suppressInterDialogReplyGuidance: boolean;
|
|
18
21
|
transientGuideContent: string | undefined;
|
|
19
22
|
}>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveReplyTargetAgentId = resolveReplyTargetAgentId;
|
|
4
|
+
exports.hasSameReplyDirective = hasSameReplyDirective;
|
|
4
5
|
exports.resolvePromptReplyGuidance = resolvePromptReplyGuidance;
|
|
5
6
|
exports.buildReplyObligationSuppressionGuide = buildReplyObligationSuppressionGuide;
|
|
6
7
|
const dialog_1 = require("../../dialog");
|
|
@@ -91,40 +92,17 @@ function hasSameReplyDirective(left, right) {
|
|
|
91
92
|
}
|
|
92
93
|
return true;
|
|
93
94
|
}
|
|
94
|
-
function
|
|
95
|
-
switch (dlg.assignmentFromAsker.callName) {
|
|
96
|
-
case 'tellask':
|
|
97
|
-
return {
|
|
98
|
-
expectedReplyCallName: 'replyTellask',
|
|
99
|
-
targetDialogId: dlg.assignmentFromAsker.askerDialogId,
|
|
100
|
-
targetCallId: dlg.assignmentFromAsker.callId,
|
|
101
|
-
tellaskContent: dlg.assignmentFromAsker.tellaskContent,
|
|
102
|
-
};
|
|
103
|
-
case 'tellaskSessionless':
|
|
104
|
-
case 'freshBootsReasoning':
|
|
105
|
-
return {
|
|
106
|
-
expectedReplyCallName: 'replyTellaskSessionless',
|
|
107
|
-
targetDialogId: dlg.assignmentFromAsker.askerDialogId,
|
|
108
|
-
targetCallId: dlg.assignmentFromAsker.callId,
|
|
109
|
-
tellaskContent: dlg.assignmentFromAsker.tellaskContent,
|
|
110
|
-
};
|
|
111
|
-
default: {
|
|
112
|
-
const _exhaustive = dlg.assignmentFromAsker.callName;
|
|
113
|
-
throw new Error(`Unsupported sideDialog assignment callName: ${_exhaustive}`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
async function resolveFreshCurrentSideDialogAssignmentDirective(args) {
|
|
95
|
+
async function resolveFreshCurrentSideDialogAssignmentPromptMeta(args) {
|
|
118
96
|
if (!(args.dlg instanceof dialog_1.SideDialog)) {
|
|
119
97
|
return undefined;
|
|
120
98
|
}
|
|
121
|
-
const
|
|
99
|
+
const currentAssignmentPromptMeta = (0, dialog_1.buildSideDialogAssignmentPromptMeta)(args.dlg);
|
|
122
100
|
if (args.prompt?.origin === 'runtime') {
|
|
123
101
|
const promptDirective = args.prompt.tellaskReplyDirective;
|
|
124
102
|
if (!promptDirective) {
|
|
125
103
|
return undefined;
|
|
126
104
|
}
|
|
127
|
-
if (!hasSameReplyDirective(promptDirective,
|
|
105
|
+
if (!hasSameReplyDirective(promptDirective, currentAssignmentPromptMeta.tellaskReplyDirective)) {
|
|
128
106
|
return undefined;
|
|
129
107
|
}
|
|
130
108
|
}
|
|
@@ -135,14 +113,14 @@ async function resolveFreshCurrentSideDialogAssignmentDirective(args) {
|
|
|
135
113
|
if (!latest) {
|
|
136
114
|
return undefined;
|
|
137
115
|
}
|
|
138
|
-
|
|
116
|
+
const targetCallId = currentAssignmentPromptMeta.tellaskReplyDirective.targetCallId.trim();
|
|
117
|
+
if (latest.sideDialogFinalResponse?.callId === targetCallId) {
|
|
139
118
|
return undefined;
|
|
140
119
|
}
|
|
141
|
-
const targetCallId = currentAssignmentDirective.targetCallId.trim();
|
|
142
120
|
if (latest.tellaskResults.results.some((entry) => entry.callId.trim() === targetCallId)) {
|
|
143
121
|
return undefined;
|
|
144
122
|
}
|
|
145
|
-
return
|
|
123
|
+
return currentAssignmentPromptMeta;
|
|
146
124
|
}
|
|
147
125
|
async function resolveFreshPendingAskBackReplyDirective(args) {
|
|
148
126
|
const prompt = args.prompt;
|
|
@@ -241,7 +219,7 @@ async function resolvePromptReplyGuidance(args) {
|
|
|
241
219
|
const prompt = args.prompt;
|
|
242
220
|
const isQ4HAnswerPrompt = typeof prompt?.q4hAnswerCallId === 'string' && prompt.q4hAnswerCallId.trim() !== '';
|
|
243
221
|
const latest = await persistence_1.DialogPersistence.loadDialogLatest(args.dlg.id, args.dlg.status);
|
|
244
|
-
const
|
|
222
|
+
const persistedCurrentSideDialogAssignmentPromptMeta = await resolveFreshCurrentSideDialogAssignmentPromptMeta({
|
|
245
223
|
dlg: args.dlg,
|
|
246
224
|
prompt,
|
|
247
225
|
});
|
|
@@ -255,7 +233,7 @@ async function resolvePromptReplyGuidance(args) {
|
|
|
255
233
|
? latest.pendingRuntimePrompt.tellaskReplyDirective
|
|
256
234
|
: undefined;
|
|
257
235
|
const persistedActiveReplyObligation = await (0, tellask_special_1.loadActiveTellaskReplyDirective)(args.dlg);
|
|
258
|
-
const persistedActiveReplyDirective =
|
|
236
|
+
const persistedActiveReplyDirective = persistedCurrentSideDialogAssignmentPromptMeta?.tellaskReplyDirective ??
|
|
259
237
|
persistedPendingAskBackReplyDirective ??
|
|
260
238
|
persistedPendingRuntimePromptDirective ??
|
|
261
239
|
persistedActiveReplyObligation;
|
|
@@ -290,6 +268,12 @@ async function resolvePromptReplyGuidance(args) {
|
|
|
290
268
|
promptDirective: prompt?.tellaskReplyDirective,
|
|
291
269
|
persistedDirective: persistedActiveReplyDirective,
|
|
292
270
|
}),
|
|
271
|
+
suppressedCalleeDialogReplyTarget: suppressInterDialogReplyGuidance
|
|
272
|
+
? persistedCurrentSideDialogAssignmentPromptMeta?.calleeDialogReplyTarget
|
|
273
|
+
: undefined,
|
|
274
|
+
suppressedTellaskReplyDirective: suppressInterDialogReplyGuidance
|
|
275
|
+
? persistedActiveReplyDirective
|
|
276
|
+
: undefined,
|
|
293
277
|
suppressInterDialogReplyGuidance,
|
|
294
278
|
transientGuideContent: suppressInterDialogReplyGuidance && prompt !== undefined
|
|
295
279
|
? buildReplyObligationSuppressionGuide({
|
package/dist/persistence.js
CHANGED
|
@@ -1564,6 +1564,10 @@ function parseDialogFollowupReason(value) {
|
|
|
1564
1564
|
const callIds = parseStringArrayField(value.callIds);
|
|
1565
1565
|
return callIds === null ? null : { kind: 'invalid_tool_recovery', callIds };
|
|
1566
1566
|
}
|
|
1567
|
+
case 'repeated_tool_call_reminder': {
|
|
1568
|
+
const callIds = parseStringArrayField(value.callIds);
|
|
1569
|
+
return callIds === null ? null : { kind: 'repeated_tool_call_reminder', callIds };
|
|
1570
|
+
}
|
|
1567
1571
|
case 'reply_delivery_result':
|
|
1568
1572
|
if (typeof value.replyDeliveryId !== 'string' ||
|
|
1569
1573
|
value.replyDeliveryId.trim() === '' ||
|