dominds 1.23.5 → 1.23.7
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-display-state.js +151 -35
- package/dist/dialog-interruption.js +2 -0
- package/dist/llm/api-quirks.d.ts +1 -0
- package/dist/llm/api-quirks.js +74 -1
- package/dist/llm/gen/openai-compatible.js +2 -3
- package/dist/llm/kernel-driver/drive.js +16 -0
- package/dist/llm/kernel-driver/flow.js +162 -33
- package/dist/llm/kernel-driver/runtime.js +3 -1
- package/dist/llm/kernel-driver/types.d.ts +1 -0
- package/dist/minds/system-prompt.js +4 -4
- package/dist/persistence.js +106 -14
- package/dist/runtime/inter-dialog-format.js +4 -4
- package/dist/runtime/reply-prompt-copy.js +4 -4
- package/dist/tools/prompts/control/en/principles.md +1 -1
- package/dist/tools/prompts/control/en/scenarios.md +1 -1
- package/dist/tools/prompts/control/en/tools.md +1 -1
- package/dist/tools/prompts/control/zh/principles.md +1 -1
- package/dist/tools/prompts/control/zh/scenarios.md +1 -1
- package/dist/tools/prompts/control/zh/tools.md +1 -1
- package/package.json +3 -3
- package/webapp/dist/assets/{_basePickBy-DMD1UhXs.js → _basePickBy-528dB5Tu.js} +3 -3
- package/webapp/dist/assets/{_basePickBy-DMD1UhXs.js.map → _basePickBy-528dB5Tu.js.map} +1 -1
- package/webapp/dist/assets/{_baseUniq-CsE8Qvwt.js → _baseUniq-DkdKmFUs.js} +2 -2
- package/webapp/dist/assets/{_baseUniq-CsE8Qvwt.js.map → _baseUniq-DkdKmFUs.js.map} +1 -1
- package/webapp/dist/assets/{arc-0h8sV6e1.js → arc-BXvXVeL_.js} +2 -2
- package/webapp/dist/assets/{arc-0h8sV6e1.js.map → arc-BXvXVeL_.js.map} +1 -1
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-BbMESECO.js → architectureDiagram-2XIMDMQ5-Ck1IMDXl.js} +7 -7
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-BbMESECO.js.map → architectureDiagram-2XIMDMQ5-Ck1IMDXl.js.map} +1 -1
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-DwkN-9a4.js → blockDiagram-WCTKOSBZ-DLRhkTKE.js} +7 -7
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-DwkN-9a4.js.map → blockDiagram-WCTKOSBZ-DLRhkTKE.js.map} +1 -1
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-CGYONEh1.js → c4Diagram-IC4MRINW-D2Hc1l7q.js} +3 -3
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-CGYONEh1.js.map → c4Diagram-IC4MRINW-D2Hc1l7q.js.map} +1 -1
- package/webapp/dist/assets/{channel-DbSJhm5-.js → channel-DuagLVFr.js} +2 -2
- package/webapp/dist/assets/{channel-DbSJhm5-.js.map → channel-DuagLVFr.js.map} +1 -1
- package/webapp/dist/assets/{chunk-4BX2VUAB-D1inRfgf.js → chunk-4BX2VUAB-BVowxdVQ.js} +2 -2
- package/webapp/dist/assets/{chunk-4BX2VUAB-D1inRfgf.js.map → chunk-4BX2VUAB-BVowxdVQ.js.map} +1 -1
- package/webapp/dist/assets/{chunk-55IACEB6-DL1IDg_h.js → chunk-55IACEB6-DOqixome.js} +2 -2
- package/webapp/dist/assets/{chunk-55IACEB6-DL1IDg_h.js.map → chunk-55IACEB6-DOqixome.js.map} +1 -1
- package/webapp/dist/assets/{chunk-FMBD7UC4-CugIlRDV.js → chunk-FMBD7UC4-BQE3IRbI.js} +2 -2
- package/webapp/dist/assets/{chunk-FMBD7UC4-CugIlRDV.js.map → chunk-FMBD7UC4-BQE3IRbI.js.map} +1 -1
- package/webapp/dist/assets/{chunk-JSJVCQXG-DKHSdeu1.js → chunk-JSJVCQXG-BWvy_u2h.js} +2 -2
- package/webapp/dist/assets/{chunk-JSJVCQXG-DKHSdeu1.js.map → chunk-JSJVCQXG-BWvy_u2h.js.map} +1 -1
- package/webapp/dist/assets/{chunk-KX2RTZJC-DCU9tkq6.js → chunk-KX2RTZJC-DsSmqNSf.js} +2 -2
- package/webapp/dist/assets/{chunk-KX2RTZJC-DCU9tkq6.js.map → chunk-KX2RTZJC-DsSmqNSf.js.map} +1 -1
- package/webapp/dist/assets/{chunk-NQ4KR5QH-DN3O2s2M.js → chunk-NQ4KR5QH-B3jQt0DX.js} +4 -4
- package/webapp/dist/assets/{chunk-NQ4KR5QH-DN3O2s2M.js.map → chunk-NQ4KR5QH-B3jQt0DX.js.map} +1 -1
- package/webapp/dist/assets/{chunk-QZHKN3VN-e3ztIJg0.js → chunk-QZHKN3VN-CWST9WcY.js} +2 -2
- package/webapp/dist/assets/{chunk-QZHKN3VN-e3ztIJg0.js.map → chunk-QZHKN3VN-CWST9WcY.js.map} +1 -1
- package/webapp/dist/assets/{chunk-WL4C6EOR-Dv907NPM.js → chunk-WL4C6EOR-DjGCVqJN.js} +6 -6
- package/webapp/dist/assets/{chunk-WL4C6EOR-Dv907NPM.js.map → chunk-WL4C6EOR-DjGCVqJN.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-DOTXtxYZ.js → classDiagram-VBA2DB6C-BnjkPcus.js} +7 -7
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-DOTXtxYZ.js.map → classDiagram-VBA2DB6C-BnjkPcus.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-DOTXtxYZ.js → classDiagram-v2-RAHNMMFH-BnjkPcus.js} +7 -7
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-DOTXtxYZ.js.map → classDiagram-v2-RAHNMMFH-BnjkPcus.js.map} +1 -1
- package/webapp/dist/assets/{clone-6lYQMWpu.js → clone-BlToIURl.js} +2 -2
- package/webapp/dist/assets/{clone-6lYQMWpu.js.map → clone-BlToIURl.js.map} +1 -1
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-DoJeDXV0.js → cose-bilkent-S5V4N54A-BDVnPWt2.js} +2 -2
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-DoJeDXV0.js.map → cose-bilkent-S5V4N54A-BDVnPWt2.js.map} +1 -1
- package/webapp/dist/assets/{dagre-KLK3FWXG-F_n_vhV9.js → dagre-KLK3FWXG-aEZUtpHt.js} +7 -7
- package/webapp/dist/assets/{dagre-KLK3FWXG-F_n_vhV9.js.map → dagre-KLK3FWXG-aEZUtpHt.js.map} +1 -1
- package/webapp/dist/assets/{diagram-E7M64L7V-Crwhgyjv.js → diagram-E7M64L7V-CvNVSxxk.js} +8 -8
- package/webapp/dist/assets/{diagram-E7M64L7V-Crwhgyjv.js.map → diagram-E7M64L7V-CvNVSxxk.js.map} +1 -1
- package/webapp/dist/assets/{diagram-IFDJBPK2-CIt1nnn5.js → diagram-IFDJBPK2-Cvwaoava.js} +7 -7
- package/webapp/dist/assets/{diagram-IFDJBPK2-CIt1nnn5.js.map → diagram-IFDJBPK2-Cvwaoava.js.map} +1 -1
- package/webapp/dist/assets/{diagram-P4PSJMXO-qowipEfV.js → diagram-P4PSJMXO-ffnT7Lr_.js} +7 -7
- package/webapp/dist/assets/{diagram-P4PSJMXO-qowipEfV.js.map → diagram-P4PSJMXO-ffnT7Lr_.js.map} +1 -1
- package/webapp/dist/assets/{erDiagram-INFDFZHY-DV2BcYNa.js → erDiagram-INFDFZHY-DvGIVeJS.js} +5 -5
- package/webapp/dist/assets/{erDiagram-INFDFZHY-DV2BcYNa.js.map → erDiagram-INFDFZHY-DvGIVeJS.js.map} +1 -1
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-CAbWV161.js → flowDiagram-PKNHOUZH-BkQUpSc9.js} +7 -7
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-CAbWV161.js.map → flowDiagram-PKNHOUZH-BkQUpSc9.js.map} +1 -1
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-CfdR7FRr.js → ganttDiagram-A5KZAMGK-BlG96EZZ.js} +3 -3
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-CfdR7FRr.js.map → ganttDiagram-A5KZAMGK-BlG96EZZ.js.map} +1 -1
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-DuJFTELz.js → gitGraphDiagram-K3NZZRJ6-CnyjUBR4.js} +8 -8
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-DuJFTELz.js.map → gitGraphDiagram-K3NZZRJ6-CnyjUBR4.js.map} +1 -1
- package/webapp/dist/assets/{graph-cjRyzujT.js → graph-D-OO7MVR.js} +3 -3
- package/webapp/dist/assets/{graph-cjRyzujT.js.map → graph-D-OO7MVR.js.map} +1 -1
- package/webapp/dist/assets/{index-DgfF56L4.js → index-DvqI98wY.js} +39 -33
- package/webapp/dist/assets/{index-DgfF56L4.js.map → index-DvqI98wY.js.map} +1 -1
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-3wx-7AdD.js → infoDiagram-LFFYTUFH-Bid564Un.js} +6 -6
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-3wx-7AdD.js.map → infoDiagram-LFFYTUFH-Bid564Un.js.map} +1 -1
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-g6CMb1Qc.js → ishikawaDiagram-PHBUUO56-BoU1GXkx.js} +2 -2
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-g6CMb1Qc.js.map → ishikawaDiagram-PHBUUO56-BoU1GXkx.js.map} +1 -1
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-DdCcmOBO.js → journeyDiagram-4ABVD52K-C-JJRe4y.js} +5 -5
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-DdCcmOBO.js.map → journeyDiagram-4ABVD52K-C-JJRe4y.js.map} +1 -1
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-BFw2emGl.js → kanban-definition-K7BYSVSG-BPGHC2fL.js} +3 -3
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-BFw2emGl.js.map → kanban-definition-K7BYSVSG-BPGHC2fL.js.map} +1 -1
- package/webapp/dist/assets/{layout-Clazq06r.js → layout-BFpoiNr0.js} +5 -5
- package/webapp/dist/assets/{layout-Clazq06r.js.map → layout-BFpoiNr0.js.map} +1 -1
- package/webapp/dist/assets/{linear-jdsBGgvD.js → linear-BwnDVwt9.js} +2 -2
- package/webapp/dist/assets/{linear-jdsBGgvD.js.map → linear-BwnDVwt9.js.map} +1 -1
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DLSZrW6l.js → mindmap-definition-YRQLILUH-D4aHh1Ye.js} +4 -4
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DLSZrW6l.js.map → mindmap-definition-YRQLILUH-D4aHh1Ye.js.map} +1 -1
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Uj-Zpci6.js → pieDiagram-SKSYHLDU-DIp7yy6V.js} +8 -8
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Uj-Zpci6.js.map → pieDiagram-SKSYHLDU-DIp7yy6V.js.map} +1 -1
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-DO7Sl1nV.js → quadrantDiagram-337W2JSQ-uKOhvCPR.js} +3 -3
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-DO7Sl1nV.js.map → quadrantDiagram-337W2JSQ-uKOhvCPR.js.map} +1 -1
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-WrurrDKQ.js → requirementDiagram-Z7DCOOCP-Da_5DlcQ.js} +4 -4
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-WrurrDKQ.js.map → requirementDiagram-Z7DCOOCP-Da_5DlcQ.js.map} +1 -1
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-gcxbxuZB.js → sankeyDiagram-WA2Y5GQK-P3UD1XYS.js} +2 -2
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-gcxbxuZB.js.map → sankeyDiagram-WA2Y5GQK-P3UD1XYS.js.map} +1 -1
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-B98U2Npa.js → sequenceDiagram-2WXFIKYE-jY-eNlAg.js} +4 -4
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-B98U2Npa.js.map → sequenceDiagram-2WXFIKYE-jY-eNlAg.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-BUgfHMbd.js → stateDiagram-RAJIS63D-HMXNbLUd.js} +9 -9
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-BUgfHMbd.js.map → stateDiagram-RAJIS63D-HMXNbLUd.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-C8gH0rSW.js → stateDiagram-v2-FVOUBMTO-C-50Qbn8.js} +5 -5
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-C8gH0rSW.js.map → stateDiagram-v2-FVOUBMTO-C-50Qbn8.js.map} +1 -1
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-DnVikX3B.js → timeline-definition-YZTLITO2-CkiLYjSG.js} +3 -3
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-DnVikX3B.js.map → timeline-definition-YZTLITO2-CkiLYjSG.js.map} +1 -1
- package/webapp/dist/assets/{treemap-KZPCXAKY-BjhjT1IM.js → treemap-KZPCXAKY-DKYYu8t-.js} +5 -5
- package/webapp/dist/assets/{treemap-KZPCXAKY-BjhjT1IM.js.map → treemap-KZPCXAKY-DKYYu8t-.js.map} +1 -1
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-CXjPMxrl.js → vennDiagram-LZ73GAT5-n9k6D3Up.js} +2 -2
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-CXjPMxrl.js.map → vennDiagram-LZ73GAT5-n9k6D3Up.js.map} +1 -1
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ByKmk3Cb.js → xychartDiagram-JWTSCODW-DJZb5SW1.js} +3 -3
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ByKmk3Cb.js.map → xychartDiagram-JWTSCODW-DJZb5SW1.js.map} +1 -1
- package/webapp/dist/index.html +1 -1
|
@@ -23,6 +23,26 @@ const idle_reminder_wake_1 = require("./idle-reminder-wake");
|
|
|
23
23
|
const reply_guidance_1 = require("./reply-guidance");
|
|
24
24
|
const sideDialog_1 = require("./sideDialog");
|
|
25
25
|
const tellask_special_1 = require("./tellask-special");
|
|
26
|
+
function buildRuntimeReplyReminderFollowUp(args) {
|
|
27
|
+
const common = {
|
|
28
|
+
prompt: args.prompt,
|
|
29
|
+
msgId: (0, id_1.generateShortId)(),
|
|
30
|
+
grammar: 'markdown',
|
|
31
|
+
origin: 'runtime',
|
|
32
|
+
userLanguageCode: args.language,
|
|
33
|
+
tellaskReplyDirective: args.directive,
|
|
34
|
+
};
|
|
35
|
+
return args.sideDialogReplyTarget === undefined
|
|
36
|
+
? {
|
|
37
|
+
kind: 'runtime_reply_reminder',
|
|
38
|
+
...common,
|
|
39
|
+
}
|
|
40
|
+
: {
|
|
41
|
+
kind: 'runtime_sideDialog_reply_reminder',
|
|
42
|
+
...common,
|
|
43
|
+
sideDialogReplyTarget: args.sideDialogReplyTarget,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
26
46
|
async function queueReplyReminderFollowUp(args) {
|
|
27
47
|
if (args.followUp.kind === 'runtime_sideDialog_reply_reminder') {
|
|
28
48
|
await args.dialog.queueRuntimeSideDialogPrompt({
|
|
@@ -74,6 +94,10 @@ function resolveDirectFallbackResponse(args) {
|
|
|
74
94
|
source: 'saying',
|
|
75
95
|
};
|
|
76
96
|
}
|
|
97
|
+
// Thinking-only output is intentionally a fallback candidate: some providers/models can finish a
|
|
98
|
+
// Side Dialog with useful content in thinking and no public saying. This helper only extracts the
|
|
99
|
+
// candidate; callers below must still reject it when a same-round function/tellask call needs
|
|
100
|
+
// auto-continuation, when the dialog is suspended, or when another follow-up prompt is queued.
|
|
77
101
|
if (args.driveResult.lastAssistantThinkingContent !== null &&
|
|
78
102
|
args.driveResult.lastAssistantThinkingContent.trim() !== '') {
|
|
79
103
|
if (typeof args.driveResult.lastAssistantThinkingGenseq !== 'number' ||
|
|
@@ -185,6 +209,79 @@ async function loadPendingDiagnosticsSnapshot(args) {
|
|
|
185
209
|
};
|
|
186
210
|
}
|
|
187
211
|
}
|
|
212
|
+
async function hasAssistantOutputAfterAssignmentAnchor(args) {
|
|
213
|
+
const events = await persistence_1.DialogPersistence.loadCourseEvents(args.dialog.id, args.dialog.currentCourse, args.dialog.status);
|
|
214
|
+
let assignmentGenseq;
|
|
215
|
+
for (const event of events) {
|
|
216
|
+
if (event.type === 'tellask_anchor_record' &&
|
|
217
|
+
event.anchorRole === 'assignment' &&
|
|
218
|
+
event.callId === args.callId) {
|
|
219
|
+
assignmentGenseq = event.genseq;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (assignmentGenseq !== undefined &&
|
|
223
|
+
(event.type === 'agent_thought_record' || event.type === 'agent_words_record') &&
|
|
224
|
+
event.genseq >= assignmentGenseq &&
|
|
225
|
+
event.content.trim() !== '') {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
async function resolveStrandedSideDialogReplyReminderFollowUp(args) {
|
|
232
|
+
const latest = await persistence_1.DialogPersistence.loadDialogLatest(args.dialog.id, args.dialog.status);
|
|
233
|
+
const displayState = latest?.displayState;
|
|
234
|
+
const isRecoverableProjection = displayState?.kind === 'idle_waiting_user' ||
|
|
235
|
+
(displayState?.kind === 'stopped' && displayState.reason.kind === 'pending_reply_obligation');
|
|
236
|
+
if (!latest ||
|
|
237
|
+
!isRecoverableProjection ||
|
|
238
|
+
latest.pendingCourseStartPrompt !== undefined ||
|
|
239
|
+
latest.executionMarker?.kind === 'dead') {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
const directive = await (0, tellask_special_1.loadActiveTellaskReplyDirective)(args.dialog);
|
|
243
|
+
if (!directive) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
const ownerDialogId = directive.targetDialogId.trim();
|
|
247
|
+
if (ownerDialogId === '') {
|
|
248
|
+
throw new Error(`stranded sideDialog reply recovery invariant violation: empty targetDialogId ` +
|
|
249
|
+
`(dialogId=${args.dialog.id.valueOf()}, targetCallId=${directive.targetCallId})`);
|
|
250
|
+
}
|
|
251
|
+
const pending = await persistence_1.DialogPersistence.loadPendingSideDialogs(new dialog_1.DialogID(ownerDialogId, args.dialog.id.rootId), args.dialog.status);
|
|
252
|
+
const pendingRecord = pending.find((record) => record.sideDialogId === args.dialog.id.selfId && record.callId === directive.targetCallId);
|
|
253
|
+
if (!pendingRecord) {
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
if (!(await hasAssistantOutputAfterAssignmentAnchor({
|
|
257
|
+
dialog: args.dialog,
|
|
258
|
+
callId: pendingRecord.callId,
|
|
259
|
+
}))) {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
const language = (0, work_language_1.getWorkLanguage)();
|
|
263
|
+
const sideDialogReplyTarget = {
|
|
264
|
+
ownerDialogId,
|
|
265
|
+
callType: pendingRecord.callType,
|
|
266
|
+
callId: pendingRecord.callId,
|
|
267
|
+
callSiteCourse: pendingRecord.callSiteCourse,
|
|
268
|
+
callSiteGenseq: pendingRecord.callSiteGenseq,
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
kind: 'runtime_sideDialog_reply_reminder',
|
|
272
|
+
prompt: await buildReplyToolReminderPrompt({
|
|
273
|
+
dlg: args.dialog,
|
|
274
|
+
directive,
|
|
275
|
+
language,
|
|
276
|
+
}),
|
|
277
|
+
msgId: (0, id_1.generateShortId)(),
|
|
278
|
+
grammar: 'markdown',
|
|
279
|
+
origin: 'runtime',
|
|
280
|
+
userLanguageCode: language,
|
|
281
|
+
tellaskReplyDirective: directive,
|
|
282
|
+
sideDialogReplyTarget,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
188
285
|
async function clearConsumedDeferredRootQueueIfIdle(dialog) {
|
|
189
286
|
if (dialog.id.selfId !== dialog.id.rootId) {
|
|
190
287
|
return;
|
|
@@ -366,6 +463,8 @@ async function inspectNoPromptSideDialogDrive(args) {
|
|
|
366
463
|
const inProgressGenerationResumeAllowed = args.driveOptions?.resumeInProgressGeneration === true;
|
|
367
464
|
const supplyResponseParentReviveAllowed = source === 'kernel_driver_supply_response_parent_revive' &&
|
|
368
465
|
hasNoPromptSideDialogResumeEntitlement(args.dialog, args.driveOptions);
|
|
466
|
+
const pendingReplyObligationResumeAllowed = latest?.executionMarker?.kind === 'interrupted' &&
|
|
467
|
+
latest.executionMarker.reason.kind === 'pending_reply_obligation';
|
|
369
468
|
if (lastEvent?.type === 'tellask_anchor_record' && lastEvent.anchorRole === 'response') {
|
|
370
469
|
return {
|
|
371
470
|
shouldReject: true,
|
|
@@ -378,7 +477,8 @@ async function inspectNoPromptSideDialogDrive(args) {
|
|
|
378
477
|
}
|
|
379
478
|
if (!explicitInterruptedResumeAllowed &&
|
|
380
479
|
!inProgressGenerationResumeAllowed &&
|
|
381
|
-
!supplyResponseParentReviveAllowed
|
|
480
|
+
!supplyResponseParentReviveAllowed &&
|
|
481
|
+
!pendingReplyObligationResumeAllowed) {
|
|
382
482
|
return {
|
|
383
483
|
shouldReject: true,
|
|
384
484
|
source,
|
|
@@ -558,6 +658,7 @@ async function executeDriveRound(args) {
|
|
|
558
658
|
let activeRunPrimed = false;
|
|
559
659
|
let ownsActiveRun = false;
|
|
560
660
|
let interruptedBySignal = false;
|
|
661
|
+
let shouldRefreshDisplayStateAfterActiveRunCleared = false;
|
|
561
662
|
let followUp;
|
|
562
663
|
let driveResult;
|
|
563
664
|
let sideDialogReplyTarget;
|
|
@@ -640,6 +741,29 @@ async function executeDriveRound(args) {
|
|
|
640
741
|
// suspended by pending Q4H or sideDialogs. This prevents duplicate generations when
|
|
641
742
|
// multiple wake-ups race around the same sideDialog completion boundary.
|
|
642
743
|
if (!humanPrompt) {
|
|
744
|
+
if (dialog instanceof dialog_1.SideDialog && !dialog.hasUpNext()) {
|
|
745
|
+
const strandedReplyReminder = await resolveStrandedSideDialogReplyReminderFollowUp({
|
|
746
|
+
dialog,
|
|
747
|
+
});
|
|
748
|
+
if (strandedReplyReminder !== undefined) {
|
|
749
|
+
await queueReplyReminderFollowUp({ dialog, followUp: strandedReplyReminder });
|
|
750
|
+
args.scheduleDrive(dialog, {
|
|
751
|
+
waitInQue: true,
|
|
752
|
+
driveOptions: {
|
|
753
|
+
source: 'kernel_driver_follow_up',
|
|
754
|
+
reason: 'follow_up_prompt',
|
|
755
|
+
},
|
|
756
|
+
});
|
|
757
|
+
log_1.log.warn('kernel-driver recovered stranded sideDialog reply obligation by queueing reply reminder', undefined, {
|
|
758
|
+
dialogId: dialog.id.valueOf(),
|
|
759
|
+
rootId: dialog.id.rootId,
|
|
760
|
+
selfId: dialog.id.selfId,
|
|
761
|
+
targetCallId: strandedReplyReminder.tellaskReplyDirective.targetCallId,
|
|
762
|
+
targetOwnerDialogId: strandedReplyReminder.sideDialogReplyTarget.ownerDialogId,
|
|
763
|
+
});
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
643
767
|
if (dialog instanceof dialog_1.SideDialog && !dialog.hasUpNext()) {
|
|
644
768
|
try {
|
|
645
769
|
const inspection = await inspectNoPromptSideDialogDrive({ dialog, driveOptions });
|
|
@@ -899,12 +1023,20 @@ async function executeDriveRound(args) {
|
|
|
899
1023
|
(driveResult.fbrConclusion !== undefined ||
|
|
900
1024
|
resolveDirectFallbackResponse({ driveResult, dialog }) !== undefined)) {
|
|
901
1025
|
if (driveResult.fbrConclusion) {
|
|
902
|
-
await (0, sideDialog_1.supplySideDialogResponseToAssignedAskerIfPendingV2)({
|
|
1026
|
+
const suppliedFbrConclusion = await (0, sideDialog_1.supplySideDialogResponseToAssignedAskerIfPendingV2)({
|
|
903
1027
|
sideDialog: dialog,
|
|
904
1028
|
responseText: driveResult.fbrConclusion.responseText,
|
|
905
1029
|
responseGenseq: driveResult.fbrConclusion.responseGenseq,
|
|
1030
|
+
replyResolution: {
|
|
1031
|
+
callId: driveResult.fbrConclusion.replyResolutionCallId,
|
|
1032
|
+
replyCallName: 'replyTellaskSessionless',
|
|
1033
|
+
},
|
|
906
1034
|
scheduleDrive: args.scheduleDrive,
|
|
907
1035
|
});
|
|
1036
|
+
if (!suppliedFbrConclusion) {
|
|
1037
|
+
throw new Error(`FBR conclusion delivery invariant violation: no pending asker target for dialog=${dialog.id.valueOf()}`);
|
|
1038
|
+
}
|
|
1039
|
+
shouldRefreshDisplayStateAfterActiveRunCleared = true;
|
|
908
1040
|
}
|
|
909
1041
|
else {
|
|
910
1042
|
const directFallbackResponse = resolveDirectFallbackResponse({ driveResult, dialog });
|
|
@@ -916,8 +1048,10 @@ async function executeDriveRound(args) {
|
|
|
916
1048
|
driveResult.lastFunctionCallGenseq > 0 &&
|
|
917
1049
|
directFallbackResponse.responseGenseq <= driveResult.lastFunctionCallGenseq;
|
|
918
1050
|
if (hasInProgressFunctionCall) {
|
|
919
|
-
//
|
|
920
|
-
//
|
|
1051
|
+
// A candidate direct fallback, including thinking-only output, must be newer than the
|
|
1052
|
+
// latest same-round function/tellask call. Otherwise the call is still the active move
|
|
1053
|
+
// and may auto-continue; the candidate is merely pre-tool reasoning/progress, not final
|
|
1054
|
+
// tellasker delivery.
|
|
921
1055
|
log_1.log.debug('kernel-driver skip sideDialog response supply because latest assistant output is not after function calls', undefined, {
|
|
922
1056
|
rootId: dialog.id.rootId,
|
|
923
1057
|
selfId: dialog.id.selfId,
|
|
@@ -948,35 +1082,16 @@ async function executeDriveRound(args) {
|
|
|
948
1082
|
else {
|
|
949
1083
|
if (!activePromptWasReplyToolReminder) {
|
|
950
1084
|
const language = (0, work_language_1.getWorkLanguage)();
|
|
951
|
-
followUp =
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
grammar: 'markdown',
|
|
962
|
-
origin: 'runtime',
|
|
963
|
-
userLanguageCode: language,
|
|
964
|
-
tellaskReplyDirective: activeTellaskReplyDirective,
|
|
965
|
-
}
|
|
966
|
-
: {
|
|
967
|
-
kind: 'runtime_sideDialog_reply_reminder',
|
|
968
|
-
prompt: await buildReplyToolReminderPrompt({
|
|
969
|
-
dlg: dialog,
|
|
970
|
-
directive: activeTellaskReplyDirective,
|
|
971
|
-
language,
|
|
972
|
-
}),
|
|
973
|
-
msgId: (0, id_1.generateShortId)(),
|
|
974
|
-
grammar: 'markdown',
|
|
975
|
-
origin: 'runtime',
|
|
976
|
-
userLanguageCode: language,
|
|
977
|
-
tellaskReplyDirective: activeTellaskReplyDirective,
|
|
978
|
-
sideDialogReplyTarget,
|
|
979
|
-
};
|
|
1085
|
+
followUp = buildRuntimeReplyReminderFollowUp({
|
|
1086
|
+
directive: activeTellaskReplyDirective,
|
|
1087
|
+
prompt: await buildReplyToolReminderPrompt({
|
|
1088
|
+
dlg: dialog,
|
|
1089
|
+
directive: activeTellaskReplyDirective,
|
|
1090
|
+
language,
|
|
1091
|
+
}),
|
|
1092
|
+
language,
|
|
1093
|
+
sideDialogReplyTarget,
|
|
1094
|
+
});
|
|
980
1095
|
log_1.log.debug('kernel-driver queued sideDialog replyTellask reminder after plain reply', undefined, {
|
|
981
1096
|
dialogId: dialog.id.valueOf(),
|
|
982
1097
|
targetCallId: activeTellaskReplyDirective.targetCallId,
|
|
@@ -1064,6 +1179,8 @@ async function executeDriveRound(args) {
|
|
|
1064
1179
|
Number.isFinite(driveResult.lastFunctionCallGenseq) &&
|
|
1065
1180
|
driveResult.lastFunctionCallGenseq > 0 &&
|
|
1066
1181
|
directFallbackResponse.responseGenseq <= driveResult.lastFunctionCallGenseq;
|
|
1182
|
+
// Same rule as Side Dialog final delivery: direct fallback is allowed only after the
|
|
1183
|
+
// candidate content is known to be post-tool and no same-round call is waiting to continue.
|
|
1067
1184
|
if (!hasInProgressFunctionCall) {
|
|
1068
1185
|
if (!activePromptWasReplyToolReminder) {
|
|
1069
1186
|
const language = (0, work_language_1.getWorkLanguage)();
|
|
@@ -1226,6 +1343,18 @@ async function executeDriveRound(args) {
|
|
|
1226
1343
|
if (activeRunPrimed && ownsActiveRun) {
|
|
1227
1344
|
(0, dialog_display_state_1.clearActiveRun)(dialog.id);
|
|
1228
1345
|
}
|
|
1346
|
+
if (shouldRefreshDisplayStateAfterActiveRunCleared && !(0, dialog_display_state_1.hasActiveRun)(dialog.id)) {
|
|
1347
|
+
try {
|
|
1348
|
+
await (0, dialog_display_state_1.setDialogDisplayState)(dialog.id, await (0, dialog_display_state_1.computeIdleDisplayState)(dialog));
|
|
1349
|
+
}
|
|
1350
|
+
catch (error) {
|
|
1351
|
+
log_1.log.warn('kernel-driver failed to refresh display state after FBR auto-delivery', error, {
|
|
1352
|
+
dialogId: dialog.id.valueOf(),
|
|
1353
|
+
rootId: dialog.id.rootId,
|
|
1354
|
+
selfId: dialog.id.selfId,
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1229
1358
|
release();
|
|
1230
1359
|
(0, idle_reminder_wake_1.maybeStartIdleReminderWake)(dialog, {
|
|
1231
1360
|
scheduleDrive: args.scheduleDrive,
|
|
@@ -867,6 +867,8 @@ async function runLlmRequestWithRetry(params) {
|
|
|
867
867
|
errorText: detail,
|
|
868
868
|
},
|
|
869
869
|
});
|
|
870
|
+
}
|
|
871
|
+
if (failure.kind === 'rejected' && handledFailure.handling.kind !== 'give_up') {
|
|
870
872
|
let streamErrorEmitted = false;
|
|
871
873
|
try {
|
|
872
874
|
await params.dlg.streamError(detail);
|
|
@@ -941,7 +943,7 @@ async function runLlmRequestWithRetry(params) {
|
|
|
941
943
|
reason: interruptionReason,
|
|
942
944
|
});
|
|
943
945
|
}
|
|
944
|
-
log_1.log.warn('LLM
|
|
946
|
+
log_1.log.warn('LLM failure stopped retry flow', undefined, {
|
|
945
947
|
provider: params.provider,
|
|
946
948
|
dialogId: params.dlg.id.valueOf(),
|
|
947
949
|
rootId: params.dlg.id.rootId,
|
|
@@ -130,7 +130,7 @@ function buildSideDialogTellaskerReplyMarkerRules(language) {
|
|
|
130
130
|
'- 当前支线未完成时,不要默认直接 `tellaskBack`。先判断当前团队规程/SOP/职责卡能否明确负责人:若能明确且属于执行性处理,直接 `tellask` / `tellaskSessionless` 对应负责人;只有当必须向诉请者补充需求、做业务裁决、澄清验收口径、提供缺失输入,或现有规程无法明确判责时,才发起 `tellaskBack({ tellaskContent: "..." })`,并在 `tellaskContent` 中给出具体问题。',
|
|
131
131
|
'- 是否存在“待你收口的跨对话回复义务”、以及精确该调用哪个 reply 函数,均由运行时程序化判断;运行时会在 assignment 或最新 runtime/user 提示里直接点名。',
|
|
132
132
|
'- 若运行时点名了精确 reply 函数名,你只需调用那个被点名的函数;不要自己判断 `reply*` 变体。禁止调用 `tellaskBack` 发送最终结果,也禁止用 `tellask` 向诉请者发送最终结果。',
|
|
133
|
-
`-
|
|
133
|
+
`- 正式完成路径:只有在运行时当前明确点名了某个精确 reply 函数,且你通过那个函数回复时,运行时才会把该回复作为完成结果投递给诉请者,并在传递正文中添加 ${runtimeMarkers.finalCompleted}。不要依赖 direct-reply fallback;它只是运行时临时过渡兜底,不是正式回复机制。`,
|
|
134
134
|
'- 若运行时当前明确提示“没有待完成的跨对话回复义务”,就直接继续当前本地对话;不要凭记忆再次调用 `reply*`。',
|
|
135
135
|
'- "不得发普通文本中间汇报"只针对未完成态;若你已经完成任务并能给出最终交付,就应使用运行时当前点名的精确 reply 函数,不要使用 `tellaskBack` 或 `tellask`。',
|
|
136
136
|
'- 例外:FBR 支线为工具禁用模式(不得调用 `tellaskBack`);其回贴标记(`' +
|
|
@@ -145,7 +145,7 @@ function buildSideDialogTellaskerReplyMarkerRules(language) {
|
|
|
145
145
|
'- If the current Side Dialog is unfinished, do not default to `tellaskBack`. First judge whether current team SOP / role ownership already identifies the responsible executor: if yes and the issue is execution work, directly use `tellask` / `tellaskSessionless` for that owner; use `tellaskBack({ tellaskContent: "..." })` only when the tellasker must provide clarification, business decision, acceptance-criteria confirmation, missing input, or when existing SOP cannot determine ownership. Put concrete questions in `tellaskContent`.',
|
|
146
146
|
'- Runtime programmatically decides whether there is an active inter-dialog reply obligation for you, and which exact reply function name applies; runtime will state that directly in the assignment or the latest runtime/user prompt.',
|
|
147
147
|
'- If runtime names an exact reply function, call that named function and do not choose a `reply*` variant by yourself. Do not use `tellaskBack` or `tellask` to send final delivery.',
|
|
148
|
-
`-
|
|
148
|
+
`- Formal completion path: only replies sent through the exact reply function currently named by runtime are delivered to the tellasker as completion results and marked with ${runtimeMarkers.finalCompleted}. Do not rely on direct-reply fallback; it is only a temporary runtime transition safeguard, not the formal reply mechanism.`,
|
|
149
149
|
'- If runtime explicitly tells you there is no active inter-dialog reply obligation right now, just continue the current local conversation; do not call `reply*` again from memory.',
|
|
150
150
|
'- "Do not post a plain-text progress update" only applies to unfinished states; if the task is done and you can deliver the final result, use the exact reply function currently named by runtime instead of `tellaskBack` or `tellask`.',
|
|
151
151
|
'- Exception: FBR Side Dialog is tool-less (no \`tellaskBack\`); its reply markers (`' +
|
|
@@ -169,7 +169,7 @@ function buildTellaskReplyMarkerScopePolicy(language, dialogScope) {
|
|
|
169
169
|
'- `tellaskBack` 只允许用于回问诉请者;仅当必须向诉请者补需求/澄清/裁决/缺失输入,或现有团队规程无法明确判责时才使用。禁止用 `tellaskBack` 发送最终结果。',
|
|
170
170
|
'- 当前支线未完成时,不得把“阻塞/不确定”机械等同于 `tellaskBack`;若团队规程/SOP/职责卡已明确负责人,应直接 `tellask` / `tellaskSessionless` 对应负责人,不得发普通文本中间汇报。',
|
|
171
171
|
`- ${(0, reply_prompt_copy_1.buildSideDialogCompletionRule)('zh')}`,
|
|
172
|
-
`-
|
|
172
|
+
`- 正式完成路径中,仅当运行时当前明确点名了某个精确 reply 函数,且你通过那个函数回复时,运行时才会把该回复投递给诉请者并标注 ${runtimeMarkers.finalCompleted};不要依赖 direct-reply fallback,它只是运行时临时过渡兜底,不是正式回复机制。`,
|
|
173
173
|
'- 若运行时当前明确提示“没有待完成的跨对话回复义务”,说明这轮不是待你收口的跨对话回复义务;不要重复调用 `reply*`。',
|
|
174
174
|
],
|
|
175
175
|
en: [
|
|
@@ -178,7 +178,7 @@ function buildTellaskReplyMarkerScopePolicy(language, dialogScope) {
|
|
|
178
178
|
'- `tellaskBack` is only for asking the tellasker back; use it only when tellasker clarification / decision / missing input is required, or current team SOP cannot determine ownership. Do not use `tellaskBack` to send final results.',
|
|
179
179
|
'- If the current Side Dialog is unfinished, do not mechanically map “blocked / uncertain” to `tellaskBack`; when team SOP / role ownership already identifies the responsible owner, directly use `tellask` / `tellaskSessionless` for that owner instead of posting a plain-text progress update.',
|
|
180
180
|
`- ${(0, reply_prompt_copy_1.buildSideDialogCompletionRule)('en')}`,
|
|
181
|
-
`-
|
|
181
|
+
`- In the formal completion path, runtime marks ${runtimeMarkers.finalCompleted} and delivers to the tellasker only when runtime currently names an exact reply function and you reply through that named function; do not rely on direct-reply fallback, which is only a temporary runtime transition safeguard, not the formal reply mechanism.`,
|
|
182
182
|
'- If runtime currently tells you there is no active inter-dialog reply obligation, then this turn is not awaiting another inter-dialog closure from you; do not call `reply*` again.',
|
|
183
183
|
],
|
|
184
184
|
}),
|
package/dist/persistence.js
CHANGED
|
@@ -220,6 +220,67 @@ function normalizeGeneratingDisplayStateMismatch(dialogId, status, previous, lat
|
|
|
220
220
|
executionMarker: hasInterruptedExecutionMarker ? undefined : latest.executionMarker,
|
|
221
221
|
};
|
|
222
222
|
}
|
|
223
|
+
function hasActiveReplyObligationInAskerStackState(state) {
|
|
224
|
+
const top = state?.askerStack[state.askerStack.length - 1];
|
|
225
|
+
return top?.tellaskReplyObligation !== undefined;
|
|
226
|
+
}
|
|
227
|
+
function blockerDisplayState(args) {
|
|
228
|
+
if (args.hasQ4H && args.hasSideDialogs) {
|
|
229
|
+
return { kind: 'blocked', reason: { kind: 'needs_human_input_and_sideDialogs' } };
|
|
230
|
+
}
|
|
231
|
+
if (args.hasQ4H) {
|
|
232
|
+
return { kind: 'blocked', reason: { kind: 'needs_human_input' } };
|
|
233
|
+
}
|
|
234
|
+
if (args.hasSideDialogs) {
|
|
235
|
+
return { kind: 'blocked', reason: { kind: 'waiting_for_sideDialogs' } };
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
async function normalizeSideDialogIdleWhileReplyObligationPending(dialogId, status, previous, latest, askerStackState, context) {
|
|
240
|
+
if (status !== 'running' || dialogId.selfId === dialogId.rootId) {
|
|
241
|
+
return latest;
|
|
242
|
+
}
|
|
243
|
+
if (latest.displayState?.kind !== 'idle_waiting_user') {
|
|
244
|
+
return latest;
|
|
245
|
+
}
|
|
246
|
+
if (!hasActiveReplyObligationInAskerStackState(askerStackState)) {
|
|
247
|
+
return latest;
|
|
248
|
+
}
|
|
249
|
+
const blockerState = blockerDisplayState({
|
|
250
|
+
hasQ4H: (await DialogPersistence.loadQuestions4HumanState(dialogId, status)).length > 0,
|
|
251
|
+
hasSideDialogs: (await DialogPersistence.loadPendingSideDialogs(dialogId, status)).length > 0,
|
|
252
|
+
});
|
|
253
|
+
const top = askerStackState?.askerStack[askerStackState.askerStack.length - 1];
|
|
254
|
+
const healedDisplayState = blockerState ?? pendingReplyObligationDisplayState();
|
|
255
|
+
const healedExecutionMarker = healedDisplayState.kind === 'stopped' ? pendingReplyObligationExecutionMarker() : undefined;
|
|
256
|
+
emitInvariantWarning('Dialog latest projection invariant warning: sideDialog with active reply obligation attempted to enter idle displayState; healing from persistence facts', {
|
|
257
|
+
trigger: context.trigger,
|
|
258
|
+
mutationKind: context.mutationKind,
|
|
259
|
+
latestSource: context.latestSource,
|
|
260
|
+
latestWriteBackKey: context.latestWriteBackKey,
|
|
261
|
+
patchSummary: context.patchSummary,
|
|
262
|
+
dialogId: dialogId.valueOf(),
|
|
263
|
+
rootId: dialogId.rootId,
|
|
264
|
+
selfId: dialogId.selfId,
|
|
265
|
+
status,
|
|
266
|
+
targetCallId: top?.tellaskReplyObligation?.targetCallId ?? null,
|
|
267
|
+
blockedByQ4H: blockerState?.kind === 'blocked' && blockerState.reason.kind !== 'waiting_for_sideDialogs',
|
|
268
|
+
blockedBySideDialogs: blockerState?.kind === 'blocked' && blockerState.reason.kind !== 'needs_human_input',
|
|
269
|
+
before: summarizeLatestProjectionState(previous),
|
|
270
|
+
afterBeforeHealing: summarizeLatestProjectionState(latest),
|
|
271
|
+
healedTo: {
|
|
272
|
+
displayState: healedDisplayState,
|
|
273
|
+
executionMarker: healedExecutionMarker,
|
|
274
|
+
},
|
|
275
|
+
callStack: captureInvariantWarningStack(),
|
|
276
|
+
});
|
|
277
|
+
return {
|
|
278
|
+
...latest,
|
|
279
|
+
lastModified: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
280
|
+
displayState: healedDisplayState,
|
|
281
|
+
executionMarker: healedDisplayState.kind === 'stopped' ? healedExecutionMarker : undefined,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
223
284
|
const quarantiningMainDialogs = new Set();
|
|
224
285
|
const PERSISTABLE_DIALOG_STATUSES = ['running', 'completed', 'archived'];
|
|
225
286
|
const RUN_STATUS_DIR = 'run';
|
|
@@ -459,6 +520,12 @@ function parseDialogLlmRetryRecoveryAction(value) {
|
|
|
459
520
|
return { kind: 'none' };
|
|
460
521
|
case 'diligence_push_once':
|
|
461
522
|
return { kind: 'diligence_push_once' };
|
|
523
|
+
case 'runtime_prompt_once': {
|
|
524
|
+
const content = value.content;
|
|
525
|
+
if (typeof content !== 'string' || content.trim() === '')
|
|
526
|
+
return null;
|
|
527
|
+
return { kind: 'runtime_prompt_once', content };
|
|
528
|
+
}
|
|
462
529
|
default:
|
|
463
530
|
return null;
|
|
464
531
|
}
|
|
@@ -475,6 +542,8 @@ function parseDialogInterruptionReason(value) {
|
|
|
475
542
|
return { kind: 'server_restart' };
|
|
476
543
|
case 'pending_course_start':
|
|
477
544
|
return { kind: 'pending_course_start' };
|
|
545
|
+
case 'pending_reply_obligation':
|
|
546
|
+
return { kind: 'pending_reply_obligation' };
|
|
478
547
|
case 'fork_continue_ready':
|
|
479
548
|
return { kind: 'fork_continue_ready' };
|
|
480
549
|
case 'system_stop': {
|
|
@@ -509,6 +578,19 @@ function parseDialogInterruptionReason(value) {
|
|
|
509
578
|
return null;
|
|
510
579
|
}
|
|
511
580
|
}
|
|
581
|
+
function pendingReplyObligationDisplayState() {
|
|
582
|
+
return {
|
|
583
|
+
kind: 'stopped',
|
|
584
|
+
reason: { kind: 'pending_reply_obligation' },
|
|
585
|
+
continueEnabled: true,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
function pendingReplyObligationExecutionMarker() {
|
|
589
|
+
return {
|
|
590
|
+
kind: 'interrupted',
|
|
591
|
+
reason: { kind: 'pending_reply_obligation' },
|
|
592
|
+
};
|
|
593
|
+
}
|
|
512
594
|
function resolveStoppedContinueEnabled(reason) {
|
|
513
595
|
return (0, dialog_interruption_1.isInterruptionReasonManualResumeEligible)(reason);
|
|
514
596
|
}
|
|
@@ -1810,6 +1892,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
1810
1892
|
},
|
|
1811
1893
|
};
|
|
1812
1894
|
await this.appendEvent(askerDialog, parentCourse, sideDialogCreatedRecord);
|
|
1895
|
+
const initialSideDialogDisplayState = pendingReplyObligationDisplayState();
|
|
1813
1896
|
// Initialize latest.yaml via the mutation API (write-back will flush).
|
|
1814
1897
|
await DialogPersistence.mutateDialogLatest(sideDialogId, () => ({
|
|
1815
1898
|
kind: 'replace',
|
|
@@ -1820,7 +1903,8 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
1820
1903
|
messageCount: 0,
|
|
1821
1904
|
functionCallCount: 0,
|
|
1822
1905
|
sideDialogCount: 0,
|
|
1823
|
-
displayState:
|
|
1906
|
+
displayState: initialSideDialogDisplayState,
|
|
1907
|
+
executionMarker: pendingReplyObligationExecutionMarker(),
|
|
1824
1908
|
disableDiligencePush: false,
|
|
1825
1909
|
},
|
|
1826
1910
|
}));
|
|
@@ -1857,7 +1941,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
1857
1941
|
currentCourse: 1,
|
|
1858
1942
|
createdAt: nowTs,
|
|
1859
1943
|
lastModified: nowTs,
|
|
1860
|
-
displayState:
|
|
1944
|
+
displayState: initialSideDialogDisplayState,
|
|
1861
1945
|
sessionSlug: options.sessionSlug,
|
|
1862
1946
|
assignmentFromAsker: {
|
|
1863
1947
|
callName: options.callName,
|
|
@@ -6469,10 +6553,27 @@ class DialogPersistence {
|
|
|
6469
6553
|
lastModified: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
6470
6554
|
status: 'active',
|
|
6471
6555
|
};
|
|
6556
|
+
const askerStackState = status === 'running' && dialogId.selfId !== dialogId.rootId
|
|
6557
|
+
? await this.loadSideDialogAskerStackState(dialogId, status)
|
|
6558
|
+
: null;
|
|
6472
6559
|
const mutation = mutator(existing);
|
|
6560
|
+
const mutationContext = {
|
|
6561
|
+
trigger: 'mutateDialogLatest',
|
|
6562
|
+
mutationKind: mutation.kind,
|
|
6563
|
+
patchSummary: mutation.kind === 'patch'
|
|
6564
|
+
? summarizeLatestMutationPatch(mutation.patch)
|
|
6565
|
+
: mutation.kind === 'replace'
|
|
6566
|
+
? summarizeLatestProjectionState(mutation.next)
|
|
6567
|
+
: null,
|
|
6568
|
+
latestSource: staged ? 'staged' : latestFromDisk ? 'disk' : 'default_bootstrap',
|
|
6569
|
+
latestWriteBackKey: key,
|
|
6570
|
+
};
|
|
6473
6571
|
let updated;
|
|
6474
6572
|
if (mutation.kind === 'noop') {
|
|
6475
|
-
|
|
6573
|
+
updated = await normalizeSideDialogIdleWhileReplyObligationPending(dialogId, status, existing, existing, askerStackState, mutationContext);
|
|
6574
|
+
if (updated === existing) {
|
|
6575
|
+
return existing;
|
|
6576
|
+
}
|
|
6476
6577
|
}
|
|
6477
6578
|
else if (mutation.kind === 'replace') {
|
|
6478
6579
|
updated = {
|
|
@@ -6491,17 +6592,8 @@ class DialogPersistence {
|
|
|
6491
6592
|
const _exhaustive = mutation;
|
|
6492
6593
|
throw new Error(`Unhandled dialog latest mutation: ${String(_exhaustive)}`);
|
|
6493
6594
|
}
|
|
6494
|
-
updated = normalizeGeneratingDisplayStateMismatch(dialogId, status, existing, updated,
|
|
6495
|
-
|
|
6496
|
-
mutationKind: mutation.kind,
|
|
6497
|
-
patchSummary: mutation.kind === 'patch'
|
|
6498
|
-
? summarizeLatestMutationPatch(mutation.patch)
|
|
6499
|
-
: mutation.kind === 'replace'
|
|
6500
|
-
? summarizeLatestProjectionState(mutation.next)
|
|
6501
|
-
: null,
|
|
6502
|
-
latestSource: staged ? 'staged' : latestFromDisk ? 'disk' : 'default_bootstrap',
|
|
6503
|
-
latestWriteBackKey: key,
|
|
6504
|
-
});
|
|
6595
|
+
updated = normalizeGeneratingDisplayStateMismatch(dialogId, status, existing, updated, mutationContext);
|
|
6596
|
+
updated = await normalizeSideDialogIdleWhileReplyObligationPending(dialogId, status, existing, updated, askerStackState, mutationContext);
|
|
6505
6597
|
this.assertMainDialogWriteBackNotCanceled(effectiveCancellationToken, 'mutateDialogLatest:before-stage');
|
|
6506
6598
|
const pending = this.latestWriteBack.get(key);
|
|
6507
6599
|
if (!pending) {
|
|
@@ -263,11 +263,11 @@ function formatTellaskResponseContent(input) {
|
|
|
263
263
|
const deliveryNotice = input.deliveryMode === 'direct_fallback'
|
|
264
264
|
? input.directFallbackSource === 'thinking_only'
|
|
265
265
|
? language === 'zh'
|
|
266
|
-
? '> 系统提示:本次回贴未调用 replyTellask* 工具,且模型仅产出 thinking
|
|
267
|
-
: '> System note: this reply did not use a replyTellask* tool, and the model only produced thinking. Dominds delivered that thinking content
|
|
266
|
+
? '> 系统提示:本次回贴未调用 replyTellask* 工具,且模型仅产出 thinking;在确认本轮没有待续推工具调用后,Dominds 已通过 direct-reply fallback 临时过渡兜底投递该 thinking 内容。此路径不是正式回复机制,保留本标记仅用于追踪。\n\n'
|
|
267
|
+
: '> System note: this reply did not use a replyTellask* tool, and the model only produced thinking. After confirming that no tool call in this round was waiting for auto-continuation, Dominds delivered that thinking content through direct-reply fallback as a temporary transition safeguard. This path is not the formal reply mechanism; this marker is kept only for traceability.\n\n'
|
|
268
268
|
: language === 'zh'
|
|
269
|
-
? '> 系统提示:本次回贴未调用 replyTellask*
|
|
270
|
-
: '> System note: this reply did not use a replyTellask* tool. Dominds delivered it
|
|
269
|
+
? '> 系统提示:本次回贴未调用 replyTellask* 工具;在确认本轮没有待续推工具调用后,Dominds 已通过 direct-reply fallback 临时过渡兜底投递。此路径不是正式回复机制,保留本标记仅用于追踪。\n\n'
|
|
270
|
+
: '> System note: this reply did not use a replyTellask* tool. After confirming that no tool call in this round was waiting for auto-continuation, Dominds delivered it through direct-reply fallback as a temporary transition safeguard. This path is not the formal reply mechanism; this marker is kept only for traceability.\n\n'
|
|
271
271
|
: '';
|
|
272
272
|
if (isFbr) {
|
|
273
273
|
const title = language === 'zh' ? '【扪心自问(FBR)支线对话回贴】' : '[FBR Side Dialog response]';
|
|
@@ -149,18 +149,18 @@ function buildReplyToolReminderText(args) {
|
|
|
149
149
|
? [
|
|
150
150
|
prefix,
|
|
151
151
|
'',
|
|
152
|
-
|
|
152
|
+
`你刚才已经产出了可作为回贴的内容,但还没调用 \`${args.directive.expectedReplyCallName}\`。`,
|
|
153
153
|
'',
|
|
154
154
|
buildReplyToolReminderLine(args),
|
|
155
|
-
'
|
|
155
|
+
'不要依赖 direct-reply fallback;它只是运行时临时过渡兜底,不是正式回复机制。请现在调用正确的 reply 工具完成回复。',
|
|
156
156
|
].join('\n')
|
|
157
157
|
: [
|
|
158
158
|
prefix,
|
|
159
159
|
'',
|
|
160
|
-
`You already
|
|
160
|
+
`You already produced content that can be delivered as the reply, but you still have not called \`${args.directive.expectedReplyCallName}\`.`,
|
|
161
161
|
'',
|
|
162
162
|
buildReplyToolReminderLine(args),
|
|
163
|
-
'
|
|
163
|
+
'Do not rely on direct-reply fallback; it is only a temporary runtime transition safeguard, not the formal reply mechanism. Call the correct reply tool now.',
|
|
164
164
|
].join('\n');
|
|
165
165
|
}
|
|
166
166
|
function isReplyToolReminderPromptContent(content) {
|
|
@@ -103,7 +103,7 @@ Taskdoc is a **task contract** and the task's **team-shared source of current tr
|
|
|
103
103
|
- If the current Side Dialog is complete and the assignment header says `replyTellask`: call `replyTellask({ replyContent })`
|
|
104
104
|
- If the current Side Dialog is complete and the assignment header says `replyTellaskSessionless`: call `replyTellaskSessionless({ replyContent })`
|
|
105
105
|
- If you are answering a tellasker `tellaskBack` follow-up and runtime exposes `replyTellaskBack`: call `replyTellaskBack({ replyContent })`
|
|
106
|
-
- Plain text is not the
|
|
106
|
+
- Plain text is not the completion channel for inter-dialog delivery; if you produce final deliverable content instead of the reply tool, runtime may temporarily inject a `role=user` reminder telling you to use the correct reply function. Do not rely on direct-reply fallback; it is only a temporary runtime transition safeguard, not the formal reply mechanism
|
|
107
107
|
|
|
108
108
|
### Low-Burden Rule
|
|
109
109
|
|
|
@@ -68,7 +68,7 @@ replyTellask({
|
|
|
68
68
|
|
|
69
69
|
### Key Points
|
|
70
70
|
|
|
71
|
-
- Do not replace this with a plain final message
|
|
71
|
+
- Do not replace this with a plain final message; direct-reply fallback is only a temporary runtime transition safeguard, not a valid planned completion method
|
|
72
72
|
- Put the final deliverable body directly in `replyContent`
|
|
73
73
|
- If the header says `replyTellaskSessionless`, use the same shape with that exact function name
|
|
74
74
|
|
|
@@ -36,7 +36,7 @@ The **tool descriptions themselves** for these functions intentionally stay mini
|
|
|
36
36
|
- Call whichever `reply*` runtime currently exposes; do not switch to another reply variant by yourself
|
|
37
37
|
- If the assignment header explicitly names a reply function, follow that exact name
|
|
38
38
|
- Put only the final deliverable body in `replyContent`; do not wrap it in meta-explanations like "I am now calling replyTellask"
|
|
39
|
-
- If you
|
|
39
|
+
- If you produce final deliverable content instead of the reply tool, runtime may inject a temporary `role=user` reminder telling you to use the correct reply function; do not rely on direct-reply fallback, which is only a temporary runtime transition safeguard, not the formal reply mechanism
|
|
40
40
|
|
|
41
41
|
### 1. add_reminder
|
|
42
42
|
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
- 当前支线已经完成,且当前 assignment 明确要求 `replyTellask`:调用 `replyTellask({ replyContent })`
|
|
104
104
|
- 当前支线已经完成,且当前 assignment 明确要求 `replyTellaskSessionless`:调用 `replyTellaskSessionless({ replyContent })`
|
|
105
105
|
- 当前是在回复一条诉请者发来的 `tellaskBack` 续诉请,且 runtime 暴露了 `replyTellaskBack`:调用 `replyTellaskBack({ replyContent })`
|
|
106
|
-
-
|
|
106
|
+
- 普通文本不是跨对话完成交付通道;如果你直接产出可作为最终回贴的内容而没调 reply 工具,runtime 可能临时插入一条 `role=user` 的提醒要求你改用正确的 reply 函数。不要依赖 direct-reply fallback;它只是运行时临时过渡兜底,不是正式回复机制
|
|
107
107
|
|
|
108
108
|
### 心智负担最小化规则
|
|
109
109
|
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
- 看见哪一个 `reply*` 被 runtime 暴露,就调用哪一个;不要自行改选别的 reply 变体
|
|
37
37
|
- assignment 头部若已点名 reply 函数名,以那个名字为准
|
|
38
38
|
- `replyContent` 只放最终交付正文,不要再包一层“我现在调用了 replyXXX”
|
|
39
|
-
-
|
|
39
|
+
- 如果你直接产出最终回贴内容而没调 reply 工具,runtime 可能插入一条 `role=user` 的 runtime reminder 纠正你;不要依赖 direct-reply fallback,它只是运行时临时过渡兜底,不是正式回复机制
|
|
40
40
|
|
|
41
41
|
### 1. add_reminder
|
|
42
42
|
|