dominds 0.7.3 → 0.7.5
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-global-registry.js +8 -2
- package/dist/evt-registry.js +46 -16
- package/dist/llm/driver-v2/context-health.js +55 -0
- package/dist/llm/driver-v2/core.js +65 -0
- package/dist/llm/driver-v2/orchestrator.js +38 -2
- package/dist/llm/driver-v2/round.js +19 -56
- package/dist/llm/driver-v2/supdialog-response.js +21 -6
- package/dist/persistence.js +72 -9
- package/dist/server/websocket-handler.js +5 -3
- package/dist/static/assets/{_baseUniq-zV3pyJ-s.js → _baseUniq-Dv0SNM-n.js} +2 -2
- package/dist/static/assets/{_baseUniq-zV3pyJ-s.js.map → _baseUniq-Dv0SNM-n.js.map} +1 -1
- package/dist/static/assets/{arc-Ctgmrh71.js → arc-nblUuKKs.js} +2 -2
- package/dist/static/assets/{arc-Ctgmrh71.js.map → arc-nblUuKKs.js.map} +1 -1
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-CAH1Zinn.js → architectureDiagram-VXUJARFQ-Q49jOqLH.js} +6 -6
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-CAH1Zinn.js.map → architectureDiagram-VXUJARFQ-Q49jOqLH.js.map} +1 -1
- package/dist/static/assets/{blockDiagram-VD42YOAC-Djz6JdD2.js → blockDiagram-VD42YOAC-DOz0byeQ.js} +7 -7
- package/dist/static/assets/{blockDiagram-VD42YOAC-Djz6JdD2.js.map → blockDiagram-VD42YOAC-DOz0byeQ.js.map} +1 -1
- package/dist/static/assets/{c4Diagram-YG6GDRKO-CSuskOyq.js → c4Diagram-YG6GDRKO-CuE9ekBX.js} +3 -3
- package/dist/static/assets/{c4Diagram-YG6GDRKO-CSuskOyq.js.map → c4Diagram-YG6GDRKO-CuE9ekBX.js.map} +1 -1
- package/dist/static/assets/{channel-Ym6U59Kh.js → channel-C6JhcfrE.js} +2 -2
- package/dist/static/assets/{channel-Ym6U59Kh.js.map → channel-C6JhcfrE.js.map} +1 -1
- package/dist/static/assets/{chunk-4BX2VUAB-CqbVylSz.js → chunk-4BX2VUAB-D9HNI-Q6.js} +2 -2
- package/dist/static/assets/{chunk-4BX2VUAB-CqbVylSz.js.map → chunk-4BX2VUAB-D9HNI-Q6.js.map} +1 -1
- package/dist/static/assets/{chunk-55IACEB6-CeWj8Jm_.js → chunk-55IACEB6-D_Pczcp6.js} +2 -2
- package/dist/static/assets/{chunk-55IACEB6-CeWj8Jm_.js.map → chunk-55IACEB6-D_Pczcp6.js.map} +1 -1
- package/dist/static/assets/{chunk-B4BG7PRW-BjxJkuhq.js → chunk-B4BG7PRW-CPzaEhe0.js} +5 -5
- package/dist/static/assets/{chunk-B4BG7PRW-BjxJkuhq.js.map → chunk-B4BG7PRW-CPzaEhe0.js.map} +1 -1
- package/dist/static/assets/{chunk-DI55MBZ5-9kxfXB4B.js → chunk-DI55MBZ5-CZ3yprSl.js} +4 -4
- package/dist/static/assets/{chunk-DI55MBZ5-9kxfXB4B.js.map → chunk-DI55MBZ5-CZ3yprSl.js.map} +1 -1
- package/dist/static/assets/{chunk-FMBD7UC4-DyM3IVWB.js → chunk-FMBD7UC4-DgRX4mC9.js} +2 -2
- package/dist/static/assets/{chunk-FMBD7UC4-DyM3IVWB.js.map → chunk-FMBD7UC4-DgRX4mC9.js.map} +1 -1
- package/dist/static/assets/{chunk-QN33PNHL-DGU21aEB.js → chunk-QN33PNHL-Czn5ZbJU.js} +2 -2
- package/dist/static/assets/{chunk-QN33PNHL-DGU21aEB.js.map → chunk-QN33PNHL-Czn5ZbJU.js.map} +1 -1
- package/dist/static/assets/{chunk-QZHKN3VN-Cw9Hpt-y.js → chunk-QZHKN3VN-CNl9lQSy.js} +2 -2
- package/dist/static/assets/{chunk-QZHKN3VN-Cw9Hpt-y.js.map → chunk-QZHKN3VN-CNl9lQSy.js.map} +1 -1
- package/dist/static/assets/{chunk-TZMSLE5B-J-eTCnFj.js → chunk-TZMSLE5B-B4SsArOO.js} +2 -2
- package/dist/static/assets/{chunk-TZMSLE5B-J-eTCnFj.js.map → chunk-TZMSLE5B-B4SsArOO.js.map} +1 -1
- package/dist/static/assets/{classDiagram-2ON5EDUG-BvoDAd8E.js → classDiagram-2ON5EDUG-D96Cleku.js} +6 -6
- package/dist/static/assets/{classDiagram-2ON5EDUG-BvoDAd8E.js.map → classDiagram-2ON5EDUG-D96Cleku.js.map} +1 -1
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-BvoDAd8E.js → classDiagram-v2-WZHVMYZB-D96Cleku.js} +6 -6
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-BvoDAd8E.js.map → classDiagram-v2-WZHVMYZB-D96Cleku.js.map} +1 -1
- package/dist/static/assets/{clone-CojsCkky.js → clone-FxJrYcZB.js} +2 -2
- package/dist/static/assets/{clone-CojsCkky.js.map → clone-FxJrYcZB.js.map} +1 -1
- package/dist/static/assets/{cose-bilkent-S5V4N54A-BEtK3OcG.js → cose-bilkent-S5V4N54A-BbEE6cnq.js} +2 -2
- package/dist/static/assets/{cose-bilkent-S5V4N54A-BEtK3OcG.js.map → cose-bilkent-S5V4N54A-BbEE6cnq.js.map} +1 -1
- package/dist/static/assets/{dagre-6UL2VRFP-C5DMaVj0.js → dagre-6UL2VRFP-CGR7eURR.js} +7 -7
- package/dist/static/assets/{dagre-6UL2VRFP-C5DMaVj0.js.map → dagre-6UL2VRFP-CGR7eURR.js.map} +1 -1
- package/dist/static/assets/{diagram-PSM6KHXK-kVP0dZ6K.js → diagram-PSM6KHXK-WWLa68Lv.js} +7 -7
- package/dist/static/assets/{diagram-PSM6KHXK-kVP0dZ6K.js.map → diagram-PSM6KHXK-WWLa68Lv.js.map} +1 -1
- package/dist/static/assets/{diagram-QEK2KX5R-C4p2yibe.js → diagram-QEK2KX5R-Cb0ZJQOH.js} +6 -6
- package/dist/static/assets/{diagram-QEK2KX5R-C4p2yibe.js.map → diagram-QEK2KX5R-Cb0ZJQOH.js.map} +1 -1
- package/dist/static/assets/{diagram-S2PKOQOG-B3vObsYY.js → diagram-S2PKOQOG-zqkdDUKQ.js} +6 -6
- package/dist/static/assets/{diagram-S2PKOQOG-B3vObsYY.js.map → diagram-S2PKOQOG-zqkdDUKQ.js.map} +1 -1
- package/dist/static/assets/{erDiagram-Q2GNP2WA-AKQItpVu.js → erDiagram-Q2GNP2WA-BmPf0wOM.js} +5 -5
- package/dist/static/assets/{erDiagram-Q2GNP2WA-AKQItpVu.js.map → erDiagram-Q2GNP2WA-BmPf0wOM.js.map} +1 -1
- package/dist/static/assets/{flowDiagram-NV44I4VS-2dalJoL3.js → flowDiagram-NV44I4VS-DXrfnkgV.js} +6 -6
- package/dist/static/assets/{flowDiagram-NV44I4VS-2dalJoL3.js.map → flowDiagram-NV44I4VS-DXrfnkgV.js.map} +1 -1
- package/dist/static/assets/{ganttDiagram-JELNMOA3-DUw98Lbz.js → ganttDiagram-JELNMOA3-bfZ5tWX_.js} +3 -3
- package/dist/static/assets/{ganttDiagram-JELNMOA3-DUw98Lbz.js.map → ganttDiagram-JELNMOA3-bfZ5tWX_.js.map} +1 -1
- package/dist/static/assets/{gitGraphDiagram-NY62KEGX-DdwIFk8M.js → gitGraphDiagram-NY62KEGX-DXitZi7r.js} +7 -7
- package/dist/static/assets/{gitGraphDiagram-NY62KEGX-DdwIFk8M.js.map → gitGraphDiagram-NY62KEGX-DXitZi7r.js.map} +1 -1
- package/dist/static/assets/{graph-BBEAP9Z9.js → graph-mjLq--Ga.js} +3 -3
- package/dist/static/assets/{graph-BBEAP9Z9.js.map → graph-mjLq--Ga.js.map} +1 -1
- package/dist/static/assets/{index-CqMOe9zt.js → index-DRzDnV-j.js} +199 -159
- package/dist/static/assets/{index-CqMOe9zt.js.map → index-DRzDnV-j.js.map} +1 -1
- package/dist/static/assets/{infoDiagram-WHAUD3N6-Cep11ST9.js → infoDiagram-WHAUD3N6-Ba9c7MOp.js} +5 -5
- package/dist/static/assets/{infoDiagram-WHAUD3N6-Cep11ST9.js.map → infoDiagram-WHAUD3N6-Ba9c7MOp.js.map} +1 -1
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Ba8wkBNB.js → journeyDiagram-XKPGCS4Q-5Wkm5er9.js} +5 -5
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Ba8wkBNB.js.map → journeyDiagram-XKPGCS4Q-5Wkm5er9.js.map} +1 -1
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-DhxNBORX.js → kanban-definition-3W4ZIXB7-CeARk6gJ.js} +3 -3
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-DhxNBORX.js.map → kanban-definition-3W4ZIXB7-CeARk6gJ.js.map} +1 -1
- package/dist/static/assets/{layout-Ckbr6Zyz.js → layout-CHbcpbOV.js} +5 -5
- package/dist/static/assets/{layout-Ckbr6Zyz.js.map → layout-CHbcpbOV.js.map} +1 -1
- package/dist/static/assets/{linear-BrSsI51I.js → linear-DPPAqhrM.js} +2 -2
- package/dist/static/assets/{linear-BrSsI51I.js.map → linear-DPPAqhrM.js.map} +1 -1
- package/dist/static/assets/{min-CeEvLc8D.js → min-JoIHYtgB.js} +3 -3
- package/dist/static/assets/{min-CeEvLc8D.js.map → min-JoIHYtgB.js.map} +1 -1
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-7ctLd3o3.js → mindmap-definition-VGOIOE7T-DKkSIiut.js} +4 -4
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-7ctLd3o3.js.map → mindmap-definition-VGOIOE7T-DKkSIiut.js.map} +1 -1
- package/dist/static/assets/{pieDiagram-ADFJNKIX-CqyILziW.js → pieDiagram-ADFJNKIX-QjFxhjCK.js} +7 -7
- package/dist/static/assets/{pieDiagram-ADFJNKIX-CqyILziW.js.map → pieDiagram-ADFJNKIX-QjFxhjCK.js.map} +1 -1
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-Byi_xYum.js → quadrantDiagram-AYHSOK5B-D8rsSvFI.js} +3 -3
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-Byi_xYum.js.map → quadrantDiagram-AYHSOK5B-D8rsSvFI.js.map} +1 -1
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Boj5vxiZ.js → requirementDiagram-UZGBJVZJ-C1x_1vZ2.js} +4 -4
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Boj5vxiZ.js.map → requirementDiagram-UZGBJVZJ-C1x_1vZ2.js.map} +1 -1
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DzoUAdfa.js → sankeyDiagram-TZEHDZUN-C3Ou5-Sj.js} +2 -2
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DzoUAdfa.js.map → sankeyDiagram-TZEHDZUN-C3Ou5-Sj.js.map} +1 -1
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-BKKxpG1m.js → sequenceDiagram-WL72ISMW-CRVq_Rpl.js} +4 -4
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-BKKxpG1m.js.map → sequenceDiagram-WL72ISMW-CRVq_Rpl.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-B-J7uRZT.js → stateDiagram-FKZM4ZOC-DAp-SG30.js} +9 -9
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-B-J7uRZT.js.map → stateDiagram-FKZM4ZOC-DAp-SG30.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-BOzmoUba.js → stateDiagram-v2-4FDKWEC3-BLi0n8xt.js} +5 -5
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-BOzmoUba.js.map → stateDiagram-v2-4FDKWEC3-BLi0n8xt.js.map} +1 -1
- package/dist/static/assets/{timeline-definition-IT6M3QCI-zu1Rojx9.js → timeline-definition-IT6M3QCI-DaJrX5LR.js} +3 -3
- package/dist/static/assets/{timeline-definition-IT6M3QCI-zu1Rojx9.js.map → timeline-definition-IT6M3QCI-DaJrX5LR.js.map} +1 -1
- package/dist/static/assets/{treemap-KMMF4GRG-C4D91awC.js → treemap-KMMF4GRG-WuFw4QSO.js} +4 -4
- package/dist/static/assets/{treemap-KMMF4GRG-C4D91awC.js.map → treemap-KMMF4GRG-WuFw4QSO.js.map} +1 -1
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-YvLKaPZ-.js → xychartDiagram-PRI3JC2R-B8iG9ezA.js} +3 -3
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-YvLKaPZ-.js.map → xychartDiagram-PRI3JC2R-B8iG9ezA.js.map} +1 -1
- package/dist/static/index.html +1 -1
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ const evt_1 = require("./shared/evt");
|
|
|
6
6
|
class GlobalDialogRegistry {
|
|
7
7
|
constructor() {
|
|
8
8
|
this.entries = new Map();
|
|
9
|
+
this.lastDriveTriggerByRootId = new Map();
|
|
9
10
|
this.driveTriggerPubChan = (0, evt_1.createPubChan)();
|
|
10
11
|
this.driveTriggerSubChan = (0, evt_1.createSubChan)(this.driveTriggerPubChan);
|
|
11
12
|
}
|
|
@@ -48,7 +49,7 @@ class GlobalDialogRegistry {
|
|
|
48
49
|
this.entries.delete(rootId);
|
|
49
50
|
}
|
|
50
51
|
publishDriveTrigger(args) {
|
|
51
|
-
|
|
52
|
+
const trigger = {
|
|
52
53
|
type: 'drive_trigger_evt',
|
|
53
54
|
action: args.action,
|
|
54
55
|
rootId: args.rootId,
|
|
@@ -58,7 +59,9 @@ class GlobalDialogRegistry {
|
|
|
58
59
|
source: args.meta.source,
|
|
59
60
|
reason: args.meta.reason,
|
|
60
61
|
emittedAtMs: Date.now(),
|
|
61
|
-
}
|
|
62
|
+
};
|
|
63
|
+
this.lastDriveTriggerByRootId.set(args.rootId, trigger);
|
|
64
|
+
this.driveTriggerPubChan.write(trigger);
|
|
62
65
|
}
|
|
63
66
|
async waitForDriveTrigger() {
|
|
64
67
|
for (;;) {
|
|
@@ -113,6 +116,9 @@ class GlobalDialogRegistry {
|
|
|
113
116
|
.filter((entry) => entry.needsDrive)
|
|
114
117
|
.map((entry) => entry.rootDialog);
|
|
115
118
|
}
|
|
119
|
+
getLastDriveTrigger(rootId) {
|
|
120
|
+
return this.lastDriveTriggerByRootId.get(rootId);
|
|
121
|
+
}
|
|
116
122
|
getAll() {
|
|
117
123
|
return Array.from(this.entries.values()).map((entry) => entry.rootDialog);
|
|
118
124
|
}
|
package/dist/evt-registry.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.dialogEventRegistry = void 0;
|
|
10
|
+
exports.setGlobalDialogEventBroadcaster = setGlobalDialogEventBroadcaster;
|
|
10
11
|
exports.setQ4HBroadcaster = setQ4HBroadcaster;
|
|
11
12
|
exports.postDialogEvent = postDialogEvent;
|
|
12
13
|
exports.postDialogEventById = postDialogEventById;
|
|
@@ -18,22 +19,45 @@ class DialogEventRegistryImpl {
|
|
|
18
19
|
constructor() {
|
|
19
20
|
this.pubChans = new Map();
|
|
20
21
|
this.log = (0, log_1.createLogger)('evt-registry');
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
this.
|
|
22
|
+
// Some dialog events are global UI state updates. They must reach ALL connected clients,
|
|
23
|
+
// not only those subscribed to a specific dialog stream.
|
|
24
|
+
this.globalDialogEventBroadcaster = null;
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
this.
|
|
26
|
+
setGlobalDialogEventBroadcaster(fn) {
|
|
27
|
+
this.globalDialogEventBroadcaster = fn;
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
broadcastGlobalEvent(evt) {
|
|
30
|
+
const fn = this.globalDialogEventBroadcaster;
|
|
31
|
+
if (!fn)
|
|
32
|
+
return;
|
|
33
|
+
fn(evt);
|
|
34
|
+
}
|
|
35
|
+
emitDialogTouched(source) {
|
|
36
|
+
if (source.type === 'dlg_touched_evt')
|
|
37
|
+
return;
|
|
38
|
+
const touchedEvt = {
|
|
39
|
+
dialog: source.dialog,
|
|
40
|
+
timestamp: source.timestamp,
|
|
41
|
+
type: 'dlg_touched_evt',
|
|
42
|
+
sourceType: source.type,
|
|
43
|
+
};
|
|
44
|
+
this.broadcastGlobalEvent(touchedEvt);
|
|
45
|
+
}
|
|
46
|
+
dispatchGloballyIfNeeded(evt) {
|
|
47
|
+
// Global-only delivery prevents duplicate deliveries from two independent paths
|
|
48
|
+
// (global broadcaster + dialog-scoped stream).
|
|
49
|
+
switch (evt.type) {
|
|
50
|
+
case 'new_q4h_asked':
|
|
51
|
+
case 'q4h_answered':
|
|
52
|
+
case 'subdialog_created_evt':
|
|
53
|
+
case 'dlg_touched_evt':
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const fn = this.globalDialogEventBroadcaster;
|
|
35
59
|
if (!fn) {
|
|
36
|
-
throw new Error(`
|
|
60
|
+
throw new Error(`Global dialog event broadcaster missing: cannot publish ${evt.type} for dialog=${evt.dialog.selfId}`);
|
|
37
61
|
}
|
|
38
62
|
fn(evt);
|
|
39
63
|
return true;
|
|
@@ -80,7 +104,8 @@ class DialogEventRegistryImpl {
|
|
|
80
104
|
*/
|
|
81
105
|
postEvent(dlg, event) {
|
|
82
106
|
const typedEvent = this.createTypedEvent(dlg.id, event);
|
|
83
|
-
|
|
107
|
+
this.emitDialogTouched(typedEvent);
|
|
108
|
+
if (this.dispatchGloballyIfNeeded(typedEvent)) {
|
|
84
109
|
return;
|
|
85
110
|
}
|
|
86
111
|
const chan = this.getPubChan(dlg.id);
|
|
@@ -88,7 +113,8 @@ class DialogEventRegistryImpl {
|
|
|
88
113
|
}
|
|
89
114
|
postEventById(dialogId, event) {
|
|
90
115
|
const typedEvent = this.createTypedEvent(dialogId, event);
|
|
91
|
-
|
|
116
|
+
this.emitDialogTouched(typedEvent);
|
|
117
|
+
if (this.dispatchGloballyIfNeeded(typedEvent)) {
|
|
92
118
|
return;
|
|
93
119
|
}
|
|
94
120
|
const chan = this.getPubChan(dialogId);
|
|
@@ -115,8 +141,12 @@ class DialogEventRegistryImpl {
|
|
|
115
141
|
}
|
|
116
142
|
// Export singleton instance
|
|
117
143
|
exports.dialogEventRegistry = new DialogEventRegistryImpl();
|
|
144
|
+
function setGlobalDialogEventBroadcaster(fn) {
|
|
145
|
+
exports.dialogEventRegistry.setGlobalDialogEventBroadcaster(fn);
|
|
146
|
+
}
|
|
147
|
+
// Backward-compatible alias used by existing tests/callers.
|
|
118
148
|
function setQ4HBroadcaster(fn) {
|
|
119
|
-
|
|
149
|
+
setGlobalDialogEventBroadcaster(fn);
|
|
120
150
|
}
|
|
121
151
|
// Export helper function to import in other modules
|
|
122
152
|
function postDialogEvent(dlg, event) {
|
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = void 0;
|
|
4
|
+
exports.resetContextHealthRoundState = resetContextHealthRoundState;
|
|
5
|
+
exports.resolveCriticalCountdownRemaining = resolveCriticalCountdownRemaining;
|
|
6
|
+
exports.consumeCriticalCountdown = consumeCriticalCountdown;
|
|
3
7
|
exports.decideDriverV2ContextHealth = decideDriverV2ContextHealth;
|
|
8
|
+
exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = 5;
|
|
9
|
+
const contextHealthRoundStateByDialogKey = new Map();
|
|
10
|
+
function getContextHealthRoundState(dialogKey) {
|
|
11
|
+
const existing = contextHealthRoundStateByDialogKey.get(dialogKey);
|
|
12
|
+
if (existing) {
|
|
13
|
+
return existing;
|
|
14
|
+
}
|
|
15
|
+
const created = {};
|
|
16
|
+
contextHealthRoundStateByDialogKey.set(dialogKey, created);
|
|
17
|
+
return created;
|
|
18
|
+
}
|
|
19
|
+
function resetContextHealthRoundState(dialogKey) {
|
|
20
|
+
contextHealthRoundStateByDialogKey.delete(dialogKey);
|
|
21
|
+
}
|
|
22
|
+
function resolveCriticalCountdownRemaining(dialogKey, snapshot) {
|
|
23
|
+
if (!snapshot || snapshot.kind !== 'available') {
|
|
24
|
+
resetContextHealthRoundState(dialogKey);
|
|
25
|
+
return exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS;
|
|
26
|
+
}
|
|
27
|
+
if (snapshot.level !== 'critical') {
|
|
28
|
+
if (snapshot.level === 'healthy') {
|
|
29
|
+
resetContextHealthRoundState(dialogKey);
|
|
30
|
+
return exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS;
|
|
31
|
+
}
|
|
32
|
+
const state = getContextHealthRoundState(dialogKey);
|
|
33
|
+
state.lastSeenLevel = snapshot.level;
|
|
34
|
+
state.criticalCountdownRemaining = undefined;
|
|
35
|
+
return exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS;
|
|
36
|
+
}
|
|
37
|
+
const state = getContextHealthRoundState(dialogKey);
|
|
38
|
+
if (state.lastSeenLevel !== 'critical' ||
|
|
39
|
+
typeof state.criticalCountdownRemaining !== 'number' ||
|
|
40
|
+
!Number.isFinite(state.criticalCountdownRemaining)) {
|
|
41
|
+
state.lastSeenLevel = 'critical';
|
|
42
|
+
state.criticalCountdownRemaining = exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS;
|
|
43
|
+
}
|
|
44
|
+
const remaining = Math.floor(state.criticalCountdownRemaining);
|
|
45
|
+
return remaining > 0 ? remaining : 0;
|
|
46
|
+
}
|
|
47
|
+
function consumeCriticalCountdown(dialogKey) {
|
|
48
|
+
const state = getContextHealthRoundState(dialogKey);
|
|
49
|
+
const currentRaw = typeof state.criticalCountdownRemaining === 'number' &&
|
|
50
|
+
Number.isFinite(state.criticalCountdownRemaining)
|
|
51
|
+
? Math.floor(state.criticalCountdownRemaining)
|
|
52
|
+
: exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS;
|
|
53
|
+
const current = currentRaw > 0 ? currentRaw : 0;
|
|
54
|
+
const next = Math.max(0, current - 1);
|
|
55
|
+
state.lastSeenLevel = 'critical';
|
|
56
|
+
state.criticalCountdownRemaining = next;
|
|
57
|
+
return next;
|
|
58
|
+
}
|
|
4
59
|
function decideDriverV2ContextHealth(args) {
|
|
5
60
|
const { snapshot } = args;
|
|
6
61
|
if (!snapshot || snapshot.kind !== 'available') {
|
|
@@ -10,12 +10,14 @@ const persistence_1 = require("../../persistence");
|
|
|
10
10
|
const diligence_1 = require("../../shared/diligence");
|
|
11
11
|
const driver_messages_1 = require("../../shared/i18n/driver-messages");
|
|
12
12
|
const runtime_language_1 = require("../../shared/runtime-language");
|
|
13
|
+
const id_1 = require("../../shared/utils/id");
|
|
13
14
|
const tellask_1 = require("../../tellask");
|
|
14
15
|
const taskdoc_1 = require("../../utils/taskdoc");
|
|
15
16
|
const client_1 = require("../client");
|
|
16
17
|
const registry_1 = require("../gen/registry");
|
|
17
18
|
const tools_projection_1 = require("../tools-projection");
|
|
18
19
|
const context_1 = require("./context");
|
|
20
|
+
const context_health_1 = require("./context-health");
|
|
19
21
|
const policy_1 = require("./policy");
|
|
20
22
|
const runtime_utils_1 = require("./runtime-utils");
|
|
21
23
|
const saying_events_1 = require("./saying-events");
|
|
@@ -58,6 +60,12 @@ function resolveUpNextPrompt(dlg) {
|
|
|
58
60
|
userLanguageCode: upNext.userLanguageCode,
|
|
59
61
|
};
|
|
60
62
|
}
|
|
63
|
+
function isUserOriginPrompt(prompt) {
|
|
64
|
+
if (!prompt) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return (prompt.origin ?? 'user') === 'user';
|
|
68
|
+
}
|
|
61
69
|
async function emitUserMarkdown(dlg, content) {
|
|
62
70
|
if (!content.trim()) {
|
|
63
71
|
return;
|
|
@@ -428,6 +436,63 @@ async function driveDialogStreamCoreV2(dlg, humanPrompt, driveOptions, callbacks
|
|
|
428
436
|
const canonicalFuncTools = agentTools.filter((t) => t.type === 'func');
|
|
429
437
|
const projected = (0, tools_projection_1.projectFuncToolsForProvider)(providerCfg.apiType, canonicalFuncTools);
|
|
430
438
|
const funcTools = projected.tools;
|
|
439
|
+
if (genIterNo > 1) {
|
|
440
|
+
const snapshot = dlg.getLastContextHealth();
|
|
441
|
+
const hasQueuedUpNext = dlg.hasUpNext() || pendingPrompt !== undefined;
|
|
442
|
+
const criticalCountdownRemaining = (0, context_health_1.resolveCriticalCountdownRemaining)(dlg.id.key(), snapshot);
|
|
443
|
+
const healthDecision = (0, context_health_1.decideDriverV2ContextHealth)({
|
|
444
|
+
snapshot,
|
|
445
|
+
hadUserPromptThisGen: isUserOriginPrompt(pendingPrompt),
|
|
446
|
+
criticalCountdownRemaining,
|
|
447
|
+
});
|
|
448
|
+
if (healthDecision.kind === 'suspend') {
|
|
449
|
+
log_1.log.info('driver-v2 suspend iterative generation due to critical context while waiting for human prompt', undefined, {
|
|
450
|
+
dialogId: dlg.id.valueOf(),
|
|
451
|
+
rootId: dlg.id.rootId,
|
|
452
|
+
selfId: dlg.id.selfId,
|
|
453
|
+
genIterNo,
|
|
454
|
+
pendingPromptOrigin: pendingPrompt?.origin ?? null,
|
|
455
|
+
});
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
if (healthDecision.kind === 'continue') {
|
|
459
|
+
if (healthDecision.reason === 'critical_force_new_course') {
|
|
460
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
461
|
+
const newCoursePrompt = language === 'zh'
|
|
462
|
+
? '系统因上下文已告急(critical)而自动开启新一程对话,请继续推进任务。'
|
|
463
|
+
: 'System auto-started a new dialog course because context health is critical. Please continue the task.';
|
|
464
|
+
await dlg.startNewCourse(newCoursePrompt);
|
|
465
|
+
dlg.setLastContextHealth({ kind: 'unavailable', reason: 'usage_unavailable' });
|
|
466
|
+
(0, context_health_1.resetContextHealthRoundState)(dlg.id.key());
|
|
467
|
+
const nextPrompt = resolveUpNextPrompt(dlg);
|
|
468
|
+
if (!nextPrompt) {
|
|
469
|
+
throw new Error(`driver-v2 critical force-new-course invariant violation: missing upNext prompt after startNewCourse for dialog=${dlg.id.valueOf()}`);
|
|
470
|
+
}
|
|
471
|
+
pendingPrompt = nextPrompt;
|
|
472
|
+
skipTaskdocForThisDrive = false;
|
|
473
|
+
}
|
|
474
|
+
else if (!hasQueuedUpNext) {
|
|
475
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
476
|
+
const guideText = healthDecision.reason === 'caution_soft_remediation'
|
|
477
|
+
? (0, driver_messages_1.formatUserFacingContextHealthV3RemediationGuide)(language, {
|
|
478
|
+
kind: 'caution',
|
|
479
|
+
mode: 'soft',
|
|
480
|
+
})
|
|
481
|
+
: (0, driver_messages_1.formatUserFacingContextHealthV3RemediationGuide)(language, {
|
|
482
|
+
kind: 'critical',
|
|
483
|
+
mode: 'countdown',
|
|
484
|
+
promptsRemainingAfterThis: (0, context_health_1.consumeCriticalCountdown)(dlg.id.key()),
|
|
485
|
+
promptsTotal: context_health_1.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS,
|
|
486
|
+
});
|
|
487
|
+
pendingPrompt = {
|
|
488
|
+
content: guideText,
|
|
489
|
+
msgId: (0, id_1.generateShortId)(),
|
|
490
|
+
grammar: 'markdown',
|
|
491
|
+
userLanguageCode: language,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
431
496
|
let suspendForHuman = false;
|
|
432
497
|
let llmGenModelForGen = model;
|
|
433
498
|
let contextHealthForGen;
|
|
@@ -88,11 +88,47 @@ async function driveQueuedDialogsOnce() {
|
|
|
88
88
|
});
|
|
89
89
|
await persistence_1.DialogPersistence.setNeedsDrive(rootDialog.id, false, rootDialog.status);
|
|
90
90
|
}
|
|
91
|
+
const lastTrigger = dialog_global_registry_1.globalDialogRegistry.getLastDriveTrigger(rootDialog.id.rootId);
|
|
92
|
+
const lastTriggerAgeMs = lastTrigger !== undefined ? Math.max(0, Date.now() - lastTrigger.emittedAtMs) : undefined;
|
|
91
93
|
if (status.subdialogs) {
|
|
92
|
-
log_1.log.info(`Dialog ${rootDialog.id.rootId} suspended, waiting for subdialogs
|
|
94
|
+
log_1.log.info(`Dialog ${rootDialog.id.rootId} suspended, waiting for subdialogs`, {
|
|
95
|
+
rootId: rootDialog.id.rootId,
|
|
96
|
+
waitingQ4H: status.q4h,
|
|
97
|
+
waitingSubdialogs: status.subdialogs,
|
|
98
|
+
hasQueuedUpNext: rootDialog.hasUpNext(),
|
|
99
|
+
lastDriveTrigger: lastTrigger
|
|
100
|
+
? {
|
|
101
|
+
action: lastTrigger.action,
|
|
102
|
+
source: lastTrigger.source,
|
|
103
|
+
reason: lastTrigger.reason,
|
|
104
|
+
emittedAtMs: lastTrigger.emittedAtMs,
|
|
105
|
+
ageMs: lastTriggerAgeMs,
|
|
106
|
+
entryFound: lastTrigger.entryFound,
|
|
107
|
+
previousNeedsDrive: lastTrigger.previousNeedsDrive,
|
|
108
|
+
nextNeedsDrive: lastTrigger.nextNeedsDrive,
|
|
109
|
+
}
|
|
110
|
+
: null,
|
|
111
|
+
});
|
|
93
112
|
}
|
|
94
113
|
if (status.q4h) {
|
|
95
|
-
log_1.log.info(`Dialog ${rootDialog.id.rootId} awaiting Q4H answer
|
|
114
|
+
log_1.log.info(`Dialog ${rootDialog.id.rootId} awaiting Q4H answer`, {
|
|
115
|
+
rootId: rootDialog.id.rootId,
|
|
116
|
+
waitingQ4H: status.q4h,
|
|
117
|
+
waitingSubdialogs: status.subdialogs,
|
|
118
|
+
hasQueuedUpNext: rootDialog.hasUpNext(),
|
|
119
|
+
lastDriveTrigger: lastTrigger
|
|
120
|
+
? {
|
|
121
|
+
action: lastTrigger.action,
|
|
122
|
+
source: lastTrigger.source,
|
|
123
|
+
reason: lastTrigger.reason,
|
|
124
|
+
emittedAtMs: lastTrigger.emittedAtMs,
|
|
125
|
+
ageMs: lastTriggerAgeMs,
|
|
126
|
+
entryFound: lastTrigger.entryFound,
|
|
127
|
+
previousNeedsDrive: lastTrigger.previousNeedsDrive,
|
|
128
|
+
nextNeedsDrive: lastTrigger.nextNeedsDrive,
|
|
129
|
+
}
|
|
130
|
+
: null,
|
|
131
|
+
});
|
|
96
132
|
}
|
|
97
133
|
}
|
|
98
134
|
catch (err) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.executeDriveRound = executeDriveRound;
|
|
4
4
|
const dialog_1 = require("../../dialog");
|
|
5
|
+
const dialog_global_registry_1 = require("../../dialog-global-registry");
|
|
5
6
|
const dialog_run_state_1 = require("../../dialog-run-state");
|
|
6
7
|
const log_1 = require("../../log");
|
|
7
8
|
const load_1 = require("../../minds/load");
|
|
@@ -13,7 +14,6 @@ const context_health_1 = require("./context-health");
|
|
|
13
14
|
const core_1 = require("./core");
|
|
14
15
|
const policy_1 = require("./policy");
|
|
15
16
|
const supdialog_response_1 = require("./supdialog-response");
|
|
16
|
-
const defaultCriticalCountdownGenerations = 5;
|
|
17
17
|
async function loadPendingDiagnosticsSnapshot(args) {
|
|
18
18
|
const ownerDialogIdObj = new dialog_1.DialogID(args.ownerDialogId, args.rootId);
|
|
19
19
|
try {
|
|
@@ -44,57 +44,6 @@ async function loadPendingDiagnosticsSnapshot(args) {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
const contextHealthRoundStateByDialogKey = new Map();
|
|
48
|
-
function getContextHealthRoundState(dialog) {
|
|
49
|
-
const key = dialog.id.key();
|
|
50
|
-
const existing = contextHealthRoundStateByDialogKey.get(key);
|
|
51
|
-
if (existing) {
|
|
52
|
-
return existing;
|
|
53
|
-
}
|
|
54
|
-
const created = {};
|
|
55
|
-
contextHealthRoundStateByDialogKey.set(key, created);
|
|
56
|
-
return created;
|
|
57
|
-
}
|
|
58
|
-
function resetContextHealthRoundState(dialog) {
|
|
59
|
-
contextHealthRoundStateByDialogKey.delete(dialog.id.key());
|
|
60
|
-
}
|
|
61
|
-
function resolveCriticalCountdownRemaining(dialog, snapshot) {
|
|
62
|
-
if (!snapshot || snapshot.kind !== 'available') {
|
|
63
|
-
resetContextHealthRoundState(dialog);
|
|
64
|
-
return defaultCriticalCountdownGenerations;
|
|
65
|
-
}
|
|
66
|
-
if (snapshot.level !== 'critical') {
|
|
67
|
-
if (snapshot.level === 'healthy') {
|
|
68
|
-
resetContextHealthRoundState(dialog);
|
|
69
|
-
return defaultCriticalCountdownGenerations;
|
|
70
|
-
}
|
|
71
|
-
const state = getContextHealthRoundState(dialog);
|
|
72
|
-
state.lastSeenLevel = snapshot.level;
|
|
73
|
-
state.criticalCountdownRemaining = undefined;
|
|
74
|
-
return defaultCriticalCountdownGenerations;
|
|
75
|
-
}
|
|
76
|
-
const state = getContextHealthRoundState(dialog);
|
|
77
|
-
if (state.lastSeenLevel !== 'critical' ||
|
|
78
|
-
typeof state.criticalCountdownRemaining !== 'number' ||
|
|
79
|
-
!Number.isFinite(state.criticalCountdownRemaining)) {
|
|
80
|
-
state.lastSeenLevel = 'critical';
|
|
81
|
-
state.criticalCountdownRemaining = defaultCriticalCountdownGenerations;
|
|
82
|
-
}
|
|
83
|
-
const remaining = Math.floor(state.criticalCountdownRemaining);
|
|
84
|
-
return remaining > 0 ? remaining : 0;
|
|
85
|
-
}
|
|
86
|
-
function consumeCriticalCountdown(dialog) {
|
|
87
|
-
const state = getContextHealthRoundState(dialog);
|
|
88
|
-
const currentRaw = typeof state.criticalCountdownRemaining === 'number' &&
|
|
89
|
-
Number.isFinite(state.criticalCountdownRemaining)
|
|
90
|
-
? Math.floor(state.criticalCountdownRemaining)
|
|
91
|
-
: defaultCriticalCountdownGenerations;
|
|
92
|
-
const current = currentRaw > 0 ? currentRaw : 0;
|
|
93
|
-
const next = Math.max(0, current - 1);
|
|
94
|
-
state.lastSeenLevel = 'critical';
|
|
95
|
-
state.criticalCountdownRemaining = next;
|
|
96
|
-
return next;
|
|
97
|
-
}
|
|
98
47
|
function resolveEffectivePrompt(dialog, humanPrompt) {
|
|
99
48
|
if (humanPrompt) {
|
|
100
49
|
return humanPrompt;
|
|
@@ -167,6 +116,8 @@ async function executeDriveRound(args) {
|
|
|
167
116
|
if (!humanPrompt) {
|
|
168
117
|
const suspension = await dialog.getSuspensionStatus();
|
|
169
118
|
if (!suspension.canDrive) {
|
|
119
|
+
const lastTrigger = dialog_global_registry_1.globalDialogRegistry.getLastDriveTrigger(dialog.id.rootId);
|
|
120
|
+
const lastTriggerAgeMs = lastTrigger !== undefined ? Math.max(0, Date.now() - lastTrigger.emittedAtMs) : undefined;
|
|
170
121
|
log_1.log.info('driver-v2 skip queued auto-drive while dialog is suspended', {
|
|
171
122
|
dialogId: dialog.id.valueOf(),
|
|
172
123
|
rootId: dialog.id.rootId,
|
|
@@ -175,6 +126,18 @@ async function executeDriveRound(args) {
|
|
|
175
126
|
hasQueuedUpNext: dialog.hasUpNext(),
|
|
176
127
|
waitingQ4H: suspension.q4h,
|
|
177
128
|
waitingSubdialogs: suspension.subdialogs,
|
|
129
|
+
lastDriveTrigger: lastTrigger
|
|
130
|
+
? {
|
|
131
|
+
action: lastTrigger.action,
|
|
132
|
+
source: lastTrigger.source,
|
|
133
|
+
reason: lastTrigger.reason,
|
|
134
|
+
emittedAtMs: lastTrigger.emittedAtMs,
|
|
135
|
+
ageMs: lastTriggerAgeMs,
|
|
136
|
+
entryFound: lastTrigger.entryFound,
|
|
137
|
+
previousNeedsDrive: lastTrigger.previousNeedsDrive,
|
|
138
|
+
nextNeedsDrive: lastTrigger.nextNeedsDrive,
|
|
139
|
+
}
|
|
140
|
+
: null,
|
|
178
141
|
});
|
|
179
142
|
return;
|
|
180
143
|
}
|
|
@@ -193,7 +156,7 @@ async function executeDriveRound(args) {
|
|
|
193
156
|
}
|
|
194
157
|
const snapshot = dialog.getLastContextHealth();
|
|
195
158
|
const hasQueuedUpNext = dialog.hasUpNext();
|
|
196
|
-
const criticalCountdownRemaining = resolveCriticalCountdownRemaining(dialog, snapshot);
|
|
159
|
+
const criticalCountdownRemaining = (0, context_health_1.resolveCriticalCountdownRemaining)(dialog.id.key(), snapshot);
|
|
197
160
|
const healthDecision = (0, context_health_1.decideDriverV2ContextHealth)({
|
|
198
161
|
snapshot,
|
|
199
162
|
hadUserPromptThisGen: humanPrompt !== undefined,
|
|
@@ -211,7 +174,7 @@ async function executeDriveRound(args) {
|
|
|
211
174
|
: 'System auto-started a new dialog course because context health is critical. Please continue the task.';
|
|
212
175
|
await dialog.startNewCourse(newCoursePrompt);
|
|
213
176
|
dialog.setLastContextHealth({ kind: 'unavailable', reason: 'usage_unavailable' });
|
|
214
|
-
resetContextHealthRoundState(dialog);
|
|
177
|
+
(0, context_health_1.resetContextHealthRoundState)(dialog.id.key());
|
|
215
178
|
}
|
|
216
179
|
else if (!hasQueuedUpNext) {
|
|
217
180
|
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
@@ -223,8 +186,8 @@ async function executeDriveRound(args) {
|
|
|
223
186
|
: (0, driver_messages_1.formatUserFacingContextHealthV3RemediationGuide)(language, {
|
|
224
187
|
kind: 'critical',
|
|
225
188
|
mode: 'countdown',
|
|
226
|
-
promptsRemainingAfterThis: consumeCriticalCountdown(dialog),
|
|
227
|
-
promptsTotal:
|
|
189
|
+
promptsRemainingAfterThis: (0, context_health_1.consumeCriticalCountdown)(dialog.id.key()),
|
|
190
|
+
promptsTotal: context_health_1.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS,
|
|
228
191
|
});
|
|
229
192
|
healthPrompt = {
|
|
230
193
|
content: guideText,
|
|
@@ -135,17 +135,32 @@ async function supplyResponseToSupdialogV2(args) {
|
|
|
135
135
|
};
|
|
136
136
|
await parentDialog.addChatMessages(immediateMirror);
|
|
137
137
|
if (result.shouldRevive) {
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
const isRoot = parentDialog instanceof dialog_1.RootDialog;
|
|
139
|
+
const hasRegistryEntry = isRoot
|
|
140
|
+
? dialog_global_registry_1.globalDialogRegistry.get(parentDialog.id.rootId) !== undefined
|
|
141
|
+
: false;
|
|
142
|
+
log_1.log.info(`All Type ${callType} subdialogs complete, parent ${parentDialog.id.selfId} scheduling auto-revive`, {
|
|
143
|
+
rootId: parentDialog.id.rootId,
|
|
144
|
+
selfId: parentDialog.id.selfId,
|
|
145
|
+
via: isRoot && hasRegistryEntry ? 'backend_loop_trigger' : 'direct_schedule_drive',
|
|
146
|
+
isRoot,
|
|
147
|
+
hasRegistryEntry,
|
|
148
|
+
});
|
|
149
|
+
if (isRoot) {
|
|
140
150
|
dialog_global_registry_1.globalDialogRegistry.markNeedsDrive(parentDialog.id.rootId, {
|
|
141
151
|
source: 'driver_v2_supply_response',
|
|
142
152
|
reason: `all_pending_subdialogs_resolved:type_${callType}`,
|
|
143
153
|
});
|
|
144
154
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
// Root dialogs should normally be resumed by backend loop drive-trigger.
|
|
156
|
+
// Direct schedule is kept only as fallback for non-root callers or when registry
|
|
157
|
+
// entry is not available yet (e.g., transient bootstrap windows).
|
|
158
|
+
if (!isRoot || !hasRegistryEntry) {
|
|
159
|
+
scheduleDrive(parentDialog, {
|
|
160
|
+
waitInQue: true,
|
|
161
|
+
driveOptions: { suppressDiligencePush: parentDialog.disableDiligencePush },
|
|
162
|
+
});
|
|
163
|
+
}
|
|
149
164
|
}
|
|
150
165
|
}
|
|
151
166
|
catch (error) {
|
package/dist/persistence.js
CHANGED
|
@@ -298,6 +298,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
298
298
|
*/
|
|
299
299
|
async createSubDialog(supdialog, targetAgentId, tellaskHead, tellaskBody, options) {
|
|
300
300
|
const generatedId = (0, id_1.generateDialogID)();
|
|
301
|
+
const nowTs = (0, time_1.formatUnifiedTimestamp)(new Date());
|
|
301
302
|
// For subdialogs, use the supdialog's root dialog ID as the root
|
|
302
303
|
const subdialogId = new dialog_1.DialogID(generatedId, supdialog.id.rootId);
|
|
303
304
|
// Prepare subdialog store
|
|
@@ -316,7 +317,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
316
317
|
id: subdialogId.selfId,
|
|
317
318
|
agentId: targetAgentId,
|
|
318
319
|
taskDocPath: supdialog.taskDocPath,
|
|
319
|
-
createdAt:
|
|
320
|
+
createdAt: nowTs,
|
|
320
321
|
supdialogId: supdialog.id.selfId,
|
|
321
322
|
tellaskSession: options.tellaskSession,
|
|
322
323
|
assignmentFromSup: {
|
|
@@ -334,7 +335,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
334
335
|
kind: 'replace',
|
|
335
336
|
next: {
|
|
336
337
|
currentCourse: 1,
|
|
337
|
-
lastModified:
|
|
338
|
+
lastModified: nowTs,
|
|
338
339
|
status: 'active',
|
|
339
340
|
messageCount: 0,
|
|
340
341
|
functionCallCount: 0,
|
|
@@ -364,6 +365,26 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
364
365
|
targetAgentId,
|
|
365
366
|
tellaskHead,
|
|
366
367
|
tellaskBody,
|
|
368
|
+
subDialogNode: {
|
|
369
|
+
selfId: subdialogId.selfId,
|
|
370
|
+
rootId: subdialogId.rootId,
|
|
371
|
+
supdialogId: supdialog.id.selfId,
|
|
372
|
+
agentId: targetAgentId,
|
|
373
|
+
taskDocPath: supdialog.taskDocPath,
|
|
374
|
+
status: 'running',
|
|
375
|
+
currentCourse: 1,
|
|
376
|
+
createdAt: nowTs,
|
|
377
|
+
lastModified: nowTs,
|
|
378
|
+
runState: { kind: 'idle_waiting_user' },
|
|
379
|
+
tellaskSession: options.tellaskSession,
|
|
380
|
+
assignmentFromSup: {
|
|
381
|
+
tellaskHead,
|
|
382
|
+
tellaskBody,
|
|
383
|
+
originMemberId: options.originMemberId,
|
|
384
|
+
callerDialogId: options.callerDialogId,
|
|
385
|
+
callId: options.callId,
|
|
386
|
+
},
|
|
387
|
+
},
|
|
367
388
|
};
|
|
368
389
|
// Post subdialog_created_evt to PARENT's PubChan so frontend can receive it
|
|
369
390
|
// The frontend subscribes to the parent's events, not the subdialog's
|
|
@@ -1052,7 +1073,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
1052
1073
|
// Events are already in chronological order from JSONL file (append-only pattern)
|
|
1053
1074
|
// Send each persistence event directly to the requesting WebSocket
|
|
1054
1075
|
for (const event of persistenceEvents) {
|
|
1055
|
-
await this.sendEventDirectlyToWebSocket(ws, dialog, currentCourse, event);
|
|
1076
|
+
await this.sendEventDirectlyToWebSocket(ws, dialog, currentCourse, event, status);
|
|
1056
1077
|
}
|
|
1057
1078
|
// Rehydrate reminders from dialog state
|
|
1058
1079
|
const dialogState = await DialogPersistence.restoreDialog(dialog.id, status);
|
|
@@ -1071,7 +1092,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
1071
1092
|
* Send a single persistence event directly to a WebSocket connection
|
|
1072
1093
|
* CRITICAL: Avoid PubChan completely for dialog restoration to the single client's display_dialog request
|
|
1073
1094
|
*/
|
|
1074
|
-
async sendEventDirectlyToWebSocket(ws, dialog, course, event) {
|
|
1095
|
+
async sendEventDirectlyToWebSocket(ws, dialog, course, event, status) {
|
|
1075
1096
|
switch (event.type) {
|
|
1076
1097
|
case 'human_text_record': {
|
|
1077
1098
|
const genseq = event.genseq;
|
|
@@ -1604,25 +1625,67 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
|
|
|
1604
1625
|
}
|
|
1605
1626
|
case 'quest_for_sup_record': {
|
|
1606
1627
|
// Handle subdialog creation requests
|
|
1628
|
+
const subdialogId = new dialog_1.DialogID(event.subDialogId, dialog.id.rootId);
|
|
1629
|
+
const loadOrder = [
|
|
1630
|
+
status,
|
|
1631
|
+
'running',
|
|
1632
|
+
'completed',
|
|
1633
|
+
'archived',
|
|
1634
|
+
].filter((candidate, index, arr) => arr.indexOf(candidate) === index);
|
|
1635
|
+
let foundStatus = null;
|
|
1636
|
+
let subMeta = null;
|
|
1637
|
+
let subLatest = null;
|
|
1638
|
+
for (const candidateStatus of loadOrder) {
|
|
1639
|
+
const candidateMeta = await DialogPersistence.loadDialogMetadata(subdialogId, candidateStatus);
|
|
1640
|
+
if (!candidateMeta || !isSubdialogMetadataFile(candidateMeta))
|
|
1641
|
+
continue;
|
|
1642
|
+
foundStatus = candidateStatus;
|
|
1643
|
+
subMeta = candidateMeta;
|
|
1644
|
+
subLatest = await DialogPersistence.loadDialogLatest(subdialogId, candidateStatus);
|
|
1645
|
+
break;
|
|
1646
|
+
}
|
|
1647
|
+
if (!foundStatus || !subMeta) {
|
|
1648
|
+
throw new Error(`subdialog_created_evt replay invariant violation: metadata missing for ${subdialogId.valueOf()}`);
|
|
1649
|
+
}
|
|
1650
|
+
const derivedSupdialogId = subMeta.assignmentFromSup?.callerDialogId &&
|
|
1651
|
+
subMeta.assignmentFromSup.callerDialogId.trim() !== ''
|
|
1652
|
+
? subMeta.assignmentFromSup.callerDialogId
|
|
1653
|
+
: typeof subMeta.supdialogId === 'string' && subMeta.supdialogId.trim() !== ''
|
|
1654
|
+
? subMeta.supdialogId
|
|
1655
|
+
: dialog.id.selfId;
|
|
1607
1656
|
const subdialogCreatedEvent = {
|
|
1608
1657
|
type: 'subdialog_created_evt',
|
|
1609
1658
|
course,
|
|
1610
1659
|
dialog: {
|
|
1611
1660
|
// Add dialog field for proper event routing
|
|
1612
|
-
selfId:
|
|
1613
|
-
rootId:
|
|
1661
|
+
selfId: subdialogId.selfId,
|
|
1662
|
+
rootId: subdialogId.rootId,
|
|
1614
1663
|
},
|
|
1615
1664
|
parentDialog: {
|
|
1616
1665
|
selfId: dialog.id.selfId,
|
|
1617
1666
|
rootId: dialog.id.rootId,
|
|
1618
1667
|
},
|
|
1619
1668
|
subDialog: {
|
|
1620
|
-
selfId:
|
|
1621
|
-
rootId:
|
|
1669
|
+
selfId: subdialogId.selfId,
|
|
1670
|
+
rootId: subdialogId.rootId,
|
|
1622
1671
|
},
|
|
1623
|
-
targetAgentId:
|
|
1672
|
+
targetAgentId: subMeta.agentId,
|
|
1624
1673
|
tellaskHead: event.tellaskHead,
|
|
1625
1674
|
tellaskBody: event.tellaskBody,
|
|
1675
|
+
subDialogNode: {
|
|
1676
|
+
selfId: subMeta.id,
|
|
1677
|
+
rootId: subdialogId.rootId,
|
|
1678
|
+
supdialogId: derivedSupdialogId,
|
|
1679
|
+
agentId: subMeta.agentId,
|
|
1680
|
+
taskDocPath: subMeta.taskDocPath,
|
|
1681
|
+
status: foundStatus,
|
|
1682
|
+
currentCourse: subLatest?.currentCourse || 1,
|
|
1683
|
+
createdAt: subMeta.createdAt,
|
|
1684
|
+
lastModified: subLatest?.lastModified || subMeta.createdAt,
|
|
1685
|
+
runState: subLatest?.runState,
|
|
1686
|
+
tellaskSession: subMeta.tellaskSession,
|
|
1687
|
+
assignmentFromSup: subMeta.assignmentFromSup,
|
|
1688
|
+
},
|
|
1626
1689
|
timestamp: event.ts,
|
|
1627
1690
|
};
|
|
1628
1691
|
if (ws.readyState === 1) {
|