dominds 1.16.1 → 1.16.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.
Files changed (175) hide show
  1. package/dist/dialog-display-state.d.ts +4 -0
  2. package/dist/dialog-display-state.js +138 -19
  3. package/dist/dialog-fork.js +13 -5
  4. package/dist/dialog-interruption.d.ts +18 -0
  5. package/dist/dialog-interruption.js +34 -0
  6. package/dist/docs/dominds-agent-collaboration.zh.md +401 -0
  7. package/dist/llm/api-quirks.d.ts +11 -0
  8. package/dist/llm/api-quirks.js +322 -24
  9. package/dist/llm/defaults.yaml +2 -1
  10. package/dist/llm/gen/mock.d.ts +1 -1
  11. package/dist/llm/gen/mock.js +12 -0
  12. package/dist/llm/gen/openai-compatible.d.ts +1 -1
  13. package/dist/llm/gen/openai-compatible.js +9 -1
  14. package/dist/llm/gen/openai.d.ts +1 -1
  15. package/dist/llm/gen/openai.js +16 -2
  16. package/dist/llm/gen.d.ts +10 -0
  17. package/dist/llm/gen.js +10 -0
  18. package/dist/llm/kernel-driver/drive.js +994 -866
  19. package/dist/llm/kernel-driver/runtime.d.ts +16 -2
  20. package/dist/llm/kernel-driver/runtime.js +75 -10
  21. package/dist/llm/stop-reason-i18n.d.ts +9 -0
  22. package/dist/llm/stop-reason-i18n.js +114 -0
  23. package/dist/persistence-errors.d.ts +26 -0
  24. package/dist/persistence-errors.js +68 -0
  25. package/dist/persistence.d.ts +119 -82
  26. package/dist/persistence.js +1055 -426
  27. package/dist/server/api-routes.js +174 -58
  28. package/dist/server/websocket-handler.js +125 -21
  29. package/dist/tools/team_mgmt.js +2 -2
  30. package/package.json +3 -3
  31. package/webapp/dist/assets/{_basePickBy-C0MXVhMo.js → _basePickBy-BJWCmtUm.js} +3 -3
  32. package/webapp/dist/assets/_basePickBy-BJWCmtUm.js.map +1 -0
  33. package/webapp/dist/assets/{_baseUniq-CRygl41M.js → _baseUniq-D6k_lGfs.js} +2 -2
  34. package/webapp/dist/assets/_baseUniq-D6k_lGfs.js.map +1 -0
  35. package/webapp/dist/assets/{arc-BeHJtnt2.js → arc-DYDaESgj.js} +2 -2
  36. package/webapp/dist/assets/arc-DYDaESgj.js.map +1 -0
  37. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-CGdo5TVi.js → architectureDiagram-VXUJARFQ-DZMT7dqc.js} +8 -26
  38. package/webapp/dist/assets/architectureDiagram-VXUJARFQ-DZMT7dqc.js.map +1 -0
  39. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-C59VaSGw.js → blockDiagram-VD42YOAC-CABpgVAa.js} +170 -187
  40. package/webapp/dist/assets/blockDiagram-VD42YOAC-CABpgVAa.js.map +1 -0
  41. package/webapp/dist/assets/{c4Diagram-IC4MRINW-B3YCBmTx.js → c4Diagram-YG6GDRKO-COLZS8Ul.js} +4 -4
  42. package/webapp/dist/assets/c4Diagram-YG6GDRKO-COLZS8Ul.js.map +1 -0
  43. package/webapp/dist/assets/{channel-Dn4i8EAY.js → channel-CYFm9Cri.js} +2 -2
  44. package/webapp/dist/assets/channel-CYFm9Cri.js.map +1 -0
  45. package/webapp/dist/assets/{chunk-4BX2VUAB-CQbB3HlW.js → chunk-4BX2VUAB-CX_-XbaN.js} +2 -2
  46. package/webapp/dist/assets/chunk-4BX2VUAB-CX_-XbaN.js.map +1 -0
  47. package/webapp/dist/assets/{chunk-55IACEB6-CkQR_Qu9.js → chunk-55IACEB6-ByD-NdBC.js} +2 -2
  48. package/webapp/dist/assets/chunk-55IACEB6-ByD-NdBC.js.map +1 -0
  49. package/webapp/dist/assets/{chunk-WL4C6EOR-Bjl-j3bf.js → chunk-B4BG7PRW-BANemsDD.js} +121 -171
  50. package/webapp/dist/assets/chunk-B4BG7PRW-BANemsDD.js.map +1 -0
  51. package/webapp/dist/assets/{chunk-NQ4KR5QH-DBxY8LL2.js → chunk-DI55MBZ5-DV7sdJmQ.js} +7 -9
  52. package/webapp/dist/assets/chunk-DI55MBZ5-DV7sdJmQ.js.map +1 -0
  53. package/webapp/dist/assets/{chunk-FMBD7UC4-YSIOuaST.js → chunk-FMBD7UC4-DYGviJnf.js} +2 -2
  54. package/webapp/dist/assets/chunk-FMBD7UC4-DYGviJnf.js.map +1 -0
  55. package/webapp/dist/assets/{chunk-KX2RTZJC-DFiwgnFf.js → chunk-QN33PNHL-B8DWRL9f.js} +2 -2
  56. package/webapp/dist/assets/chunk-QN33PNHL-B8DWRL9f.js.map +1 -0
  57. package/webapp/dist/assets/{chunk-QZHKN3VN-BAdR6lLc.js → chunk-QZHKN3VN-B1aYIzMR.js} +2 -2
  58. package/webapp/dist/assets/chunk-QZHKN3VN-B1aYIzMR.js.map +1 -0
  59. package/webapp/dist/assets/{chunk-JSJVCQXG-CWDLRawz.js → chunk-TZMSLE5B-_HISzxl3.js} +6 -14
  60. package/webapp/dist/assets/chunk-TZMSLE5B-_HISzxl3.js.map +1 -0
  61. package/webapp/dist/assets/{classDiagram-VBA2DB6C-KBeS6WXD.js → classDiagram-2ON5EDUG-CpyYj1Rc.js} +6 -7
  62. package/webapp/dist/assets/classDiagram-2ON5EDUG-CpyYj1Rc.js.map +1 -0
  63. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-KBeS6WXD.js → classDiagram-v2-WZHVMYZB-CpyYj1Rc.js} +6 -7
  64. package/webapp/dist/assets/classDiagram-v2-WZHVMYZB-CpyYj1Rc.js.map +1 -0
  65. package/webapp/dist/assets/{clone-C7-aS2vm.js → clone-B_9AxWIU.js} +2 -2
  66. package/webapp/dist/assets/clone-B_9AxWIU.js.map +1 -0
  67. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-Bo5IsL-5.js → cose-bilkent-S5V4N54A-17ECLfPR.js} +2 -2
  68. package/webapp/dist/assets/cose-bilkent-S5V4N54A-17ECLfPR.js.map +1 -0
  69. package/webapp/dist/assets/cytoscape.esm-Bm8DJGmZ.js.map +1 -1
  70. package/webapp/dist/assets/{dagre-KLK3FWXG-C3FeHj7D.js → dagre-6UL2VRFP-DhRqcF1o.js} +7 -7
  71. package/webapp/dist/assets/dagre-6UL2VRFP-DhRqcF1o.js.map +1 -0
  72. package/webapp/dist/assets/defaultLocale-B2RvLBDe.js.map +1 -1
  73. package/webapp/dist/assets/{diagram-E7M64L7V-0HfiRW0u.js → diagram-PSM6KHXK-lpDT6Wwb.js} +10 -10
  74. package/webapp/dist/assets/diagram-PSM6KHXK-lpDT6Wwb.js.map +1 -0
  75. package/webapp/dist/assets/{diagram-IFDJBPK2-DJwh7SMO.js → diagram-QEK2KX5R-ohxbPpDH.js} +8 -9
  76. package/webapp/dist/assets/diagram-QEK2KX5R-ohxbPpDH.js.map +1 -0
  77. package/webapp/dist/assets/{diagram-P4PSJMXO-Y0RbvUZX.js → diagram-S2PKOQOG-DAFFGfch.js} +8 -8
  78. package/webapp/dist/assets/diagram-S2PKOQOG-DAFFGfch.js.map +1 -0
  79. package/webapp/dist/assets/{erDiagram-INFDFZHY-B183xyLa.js → erDiagram-Q2GNP2WA-BH-7rI43.js} +75 -96
  80. package/webapp/dist/assets/erDiagram-Q2GNP2WA-BH-7rI43.js.map +1 -0
  81. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-C_BR3Y3J.js → flowDiagram-NV44I4VS-CdEjFbz4.js} +81 -98
  82. package/webapp/dist/assets/flowDiagram-NV44I4VS-CdEjFbz4.js.map +1 -0
  83. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-CHLgkuJT.js → ganttDiagram-JELNMOA3-Cju2t-lK.js} +3 -28
  84. package/webapp/dist/assets/ganttDiagram-JELNMOA3-Cju2t-lK.js.map +1 -0
  85. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-D6C_HU1q.js → gitGraphDiagram-V2S2FVAM-CUJ5oxCg.js} +46 -38
  86. package/webapp/dist/assets/gitGraphDiagram-V2S2FVAM-CUJ5oxCg.js.map +1 -0
  87. package/webapp/dist/assets/graph-mhcc7ldf.js +425 -0
  88. package/webapp/dist/assets/graph-mhcc7ldf.js.map +1 -0
  89. package/webapp/dist/assets/{index-CLoNHmSQ.js → index-BLnM-uON.js} +2098 -1841
  90. package/webapp/dist/assets/{index-CLoNHmSQ.js.map → index-BLnM-uON.js.map} +1 -1
  91. package/webapp/dist/assets/{index-YaxF76or.css → index-xvYYeHuy.css} +1 -1
  92. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-mnMS61NO.js → infoDiagram-HS3SLOUP-Df8p0okQ.js} +7 -7
  93. package/webapp/dist/assets/infoDiagram-HS3SLOUP-Df8p0okQ.js.map +1 -0
  94. package/webapp/dist/assets/init-ZxktEp_H.js.map +1 -1
  95. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-BdeERn0r.js → journeyDiagram-XKPGCS4Q-BXMl8H-d.js} +5 -5
  96. package/webapp/dist/assets/journeyDiagram-XKPGCS4Q-BXMl8H-d.js.map +1 -0
  97. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-MLeCGcYg.js → kanban-definition-3W4ZIXB7-Cc5RwCEh.js} +3 -5
  98. package/webapp/dist/assets/kanban-definition-3W4ZIXB7-Cc5RwCEh.js.map +1 -0
  99. package/webapp/dist/assets/{layout-DY9VEQ9M.js → layout-BB2SvQcE.js} +5 -5
  100. package/webapp/dist/assets/layout-BB2SvQcE.js.map +1 -0
  101. package/webapp/dist/assets/{linear-D-T1xRsr.js → linear-Cj50lA0a.js} +2 -2
  102. package/webapp/dist/assets/linear-Cj50lA0a.js.map +1 -0
  103. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-CrVm8vj2.js → mindmap-definition-VGOIOE7T-BLBklJVX.js} +5 -7
  104. package/webapp/dist/assets/mindmap-definition-VGOIOE7T-BLBklJVX.js.map +1 -0
  105. package/webapp/dist/assets/ordinal-CxptdPJm.js.map +1 -1
  106. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-GtLLV0r1.js → pieDiagram-ADFJNKIX-BQrOgSc-.js} +8 -8
  107. package/webapp/dist/assets/pieDiagram-ADFJNKIX-BQrOgSc-.js.map +1 -0
  108. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-BCgk_2LP.js → quadrantDiagram-AYHSOK5B-C62TxtsO.js} +3 -3
  109. package/webapp/dist/assets/quadrantDiagram-AYHSOK5B-C62TxtsO.js.map +1 -0
  110. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-DYUKHWKR.js → requirementDiagram-UZGBJVZJ-Is6Q3osM.js} +6 -16
  111. package/webapp/dist/assets/requirementDiagram-UZGBJVZJ-Is6Q3osM.js.map +1 -0
  112. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-CFAH8OaY.js → sankeyDiagram-TZEHDZUN-CCAW8Dr2.js} +2 -2
  113. package/webapp/dist/assets/sankeyDiagram-TZEHDZUN-CCAW8Dr2.js.map +1 -0
  114. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-BTnhbv6w.js → sequenceDiagram-WL72ISMW-DpODpbl6.js} +201 -601
  115. package/webapp/dist/assets/sequenceDiagram-WL72ISMW-DpODpbl6.js.map +1 -0
  116. package/webapp/dist/assets/{stateDiagram-RAJIS63D-DWUnJTwO.js → stateDiagram-FKZM4ZOC-B8LHaf5T.js} +9 -9
  117. package/webapp/dist/assets/stateDiagram-FKZM4ZOC-B8LHaf5T.js.map +1 -0
  118. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-B-fc52bp.js → stateDiagram-v2-4FDKWEC3-4FzTkpgz.js} +5 -5
  119. package/webapp/dist/assets/stateDiagram-v2-4FDKWEC3-4FzTkpgz.js.map +1 -0
  120. package/webapp/dist/assets/{timeline-definition-YZTLITO2-BMZ52QaG.js → timeline-definition-IT6M3QCI-Ckxc4qZe.js} +3 -3
  121. package/webapp/dist/assets/timeline-definition-IT6M3QCI-Ckxc4qZe.js.map +1 -0
  122. package/webapp/dist/assets/{treemap-KZPCXAKY-fgSrze0S.js → treemap-GDKQZRPO-QQa4vKMv.js} +24 -37
  123. package/webapp/dist/assets/treemap-GDKQZRPO-QQa4vKMv.js.map +1 -0
  124. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-D6aviLtC.js → xychartDiagram-PRI3JC2R-Ba2uJcs6.js} +4 -4
  125. package/webapp/dist/assets/xychartDiagram-PRI3JC2R-Ba2uJcs6.js.map +1 -0
  126. package/webapp/dist/index.html +2 -2
  127. package/webapp/dist/assets/_basePickBy-C0MXVhMo.js.map +0 -1
  128. package/webapp/dist/assets/_baseUniq-CRygl41M.js.map +0 -1
  129. package/webapp/dist/assets/arc-BeHJtnt2.js.map +0 -1
  130. package/webapp/dist/assets/architectureDiagram-2XIMDMQ5-CGdo5TVi.js.map +0 -1
  131. package/webapp/dist/assets/blockDiagram-WCTKOSBZ-C59VaSGw.js.map +0 -1
  132. package/webapp/dist/assets/c4Diagram-IC4MRINW-B3YCBmTx.js.map +0 -1
  133. package/webapp/dist/assets/channel-Dn4i8EAY.js.map +0 -1
  134. package/webapp/dist/assets/chunk-4BX2VUAB-CQbB3HlW.js.map +0 -1
  135. package/webapp/dist/assets/chunk-55IACEB6-CkQR_Qu9.js.map +0 -1
  136. package/webapp/dist/assets/chunk-FMBD7UC4-YSIOuaST.js.map +0 -1
  137. package/webapp/dist/assets/chunk-JSJVCQXG-CWDLRawz.js.map +0 -1
  138. package/webapp/dist/assets/chunk-KX2RTZJC-DFiwgnFf.js.map +0 -1
  139. package/webapp/dist/assets/chunk-NQ4KR5QH-DBxY8LL2.js.map +0 -1
  140. package/webapp/dist/assets/chunk-QZHKN3VN-BAdR6lLc.js.map +0 -1
  141. package/webapp/dist/assets/chunk-WL4C6EOR-Bjl-j3bf.js.map +0 -1
  142. package/webapp/dist/assets/classDiagram-VBA2DB6C-KBeS6WXD.js.map +0 -1
  143. package/webapp/dist/assets/classDiagram-v2-RAHNMMFH-KBeS6WXD.js.map +0 -1
  144. package/webapp/dist/assets/clone-C7-aS2vm.js.map +0 -1
  145. package/webapp/dist/assets/cose-bilkent-S5V4N54A-Bo5IsL-5.js.map +0 -1
  146. package/webapp/dist/assets/dagre-KLK3FWXG-C3FeHj7D.js.map +0 -1
  147. package/webapp/dist/assets/diagram-E7M64L7V-0HfiRW0u.js.map +0 -1
  148. package/webapp/dist/assets/diagram-IFDJBPK2-DJwh7SMO.js.map +0 -1
  149. package/webapp/dist/assets/diagram-P4PSJMXO-Y0RbvUZX.js.map +0 -1
  150. package/webapp/dist/assets/erDiagram-INFDFZHY-B183xyLa.js.map +0 -1
  151. package/webapp/dist/assets/flowDiagram-PKNHOUZH-C_BR3Y3J.js.map +0 -1
  152. package/webapp/dist/assets/ganttDiagram-A5KZAMGK-CHLgkuJT.js.map +0 -1
  153. package/webapp/dist/assets/gitGraphDiagram-K3NZZRJ6-D6C_HU1q.js.map +0 -1
  154. package/webapp/dist/assets/graph-D0hgB-X8.js +0 -782
  155. package/webapp/dist/assets/graph-D0hgB-X8.js.map +0 -1
  156. package/webapp/dist/assets/infoDiagram-LFFYTUFH-mnMS61NO.js.map +0 -1
  157. package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-XFIJsnJj.js +0 -966
  158. package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-XFIJsnJj.js.map +0 -1
  159. package/webapp/dist/assets/journeyDiagram-4ABVD52K-BdeERn0r.js.map +0 -1
  160. package/webapp/dist/assets/kanban-definition-K7BYSVSG-MLeCGcYg.js.map +0 -1
  161. package/webapp/dist/assets/layout-DY9VEQ9M.js.map +0 -1
  162. package/webapp/dist/assets/linear-D-T1xRsr.js.map +0 -1
  163. package/webapp/dist/assets/mindmap-definition-YRQLILUH-CrVm8vj2.js.map +0 -1
  164. package/webapp/dist/assets/pieDiagram-SKSYHLDU-GtLLV0r1.js.map +0 -1
  165. package/webapp/dist/assets/quadrantDiagram-337W2JSQ-BCgk_2LP.js.map +0 -1
  166. package/webapp/dist/assets/requirementDiagram-Z7DCOOCP-DYUKHWKR.js.map +0 -1
  167. package/webapp/dist/assets/sankeyDiagram-WA2Y5GQK-CFAH8OaY.js.map +0 -1
  168. package/webapp/dist/assets/sequenceDiagram-2WXFIKYE-BTnhbv6w.js.map +0 -1
  169. package/webapp/dist/assets/stateDiagram-RAJIS63D-DWUnJTwO.js.map +0 -1
  170. package/webapp/dist/assets/stateDiagram-v2-FVOUBMTO-B-fc52bp.js.map +0 -1
  171. package/webapp/dist/assets/timeline-definition-YZTLITO2-BMZ52QaG.js.map +0 -1
  172. package/webapp/dist/assets/treemap-KZPCXAKY-fgSrze0S.js.map +0 -1
  173. package/webapp/dist/assets/vennDiagram-LZ73GAT5-D5DmDY9l.js +0 -2487
  174. package/webapp/dist/assets/vennDiagram-LZ73GAT5-D5DmDY9l.js.map +0 -1
  175. package/webapp/dist/assets/xychartDiagram-JWTSCODW-D6aviLtC.js.map +0 -1
@@ -35,6 +35,10 @@ export declare function hasActiveRun(dialogId: DialogID): boolean;
35
35
  export declare function getActiveRunSignal(dialogId: DialogID): AbortSignal | undefined;
36
36
  export declare function createActiveRun(dialogId: DialogID): AbortSignal;
37
37
  export declare function clearActiveRun(dialogId: DialogID): void;
38
+ export declare function clearRootDialogQuarantiningIfIdle(rootDialogId: DialogID): void;
39
+ export declare function markRootDialogQuarantining(rootDialogId: DialogID): void;
40
+ export declare function clearRootDialogQuarantining(rootDialogId: DialogID): void;
41
+ export declare function forceStopActiveRunsForRootDialog(rootDialogId: DialogID): Promise<void>;
38
42
  export declare function getStopRequestedReason(dialogId: DialogID): StopRequestedReason | undefined;
39
43
  export declare function loadDialogExecutionMarker(dialogId: DialogID, status?: 'running' | 'completed' | 'archived'): Promise<DialogExecutionMarker | undefined>;
40
44
  export declare function setDialogExecutionMarker(dialogId: DialogID, executionMarker: DialogExecutionMarker | undefined): Promise<void>;
@@ -28,6 +28,10 @@ exports.hasActiveRun = hasActiveRun;
28
28
  exports.getActiveRunSignal = getActiveRunSignal;
29
29
  exports.createActiveRun = createActiveRun;
30
30
  exports.clearActiveRun = clearActiveRun;
31
+ exports.clearRootDialogQuarantiningIfIdle = clearRootDialogQuarantiningIfIdle;
32
+ exports.markRootDialogQuarantining = markRootDialogQuarantining;
33
+ exports.clearRootDialogQuarantining = clearRootDialogQuarantining;
34
+ exports.forceStopActiveRunsForRootDialog = forceStopActiveRunsForRootDialog;
31
35
  exports.getStopRequestedReason = getStopRequestedReason;
32
36
  exports.loadDialogExecutionMarker = loadDialogExecutionMarker;
33
37
  exports.setDialogExecutionMarker = setDialogExecutionMarker;
@@ -40,12 +44,15 @@ exports.requestInterruptDialog = requestInterruptDialog;
40
44
  exports.requestEmergencyStopAll = requestEmergencyStopAll;
41
45
  const time_1 = require("@longrun-ai/kernel/utils/time");
42
46
  const dialog_1 = require("./dialog");
47
+ const dialog_interruption_1 = require("./dialog-interruption");
43
48
  const evt_registry_1 = require("./evt-registry");
44
49
  const log_1 = require("./log");
45
50
  const persistence_1 = require("./persistence");
51
+ const persistence_errors_1 = require("./persistence-errors");
46
52
  const log = (0, log_1.createLogger)('dialog-display-state');
47
53
  let broadcastToClients;
48
54
  const activeRunsByDialogKey = new Map();
55
+ const quarantiningRootDialogIds = new Set();
49
56
  function setDisplayStateBroadcaster(fn) {
50
57
  broadcastToClients = fn;
51
58
  }
@@ -63,7 +70,7 @@ function syncRunControlCountsAfterActiveRunChange(trigger, dialogId) {
63
70
  })();
64
71
  }
65
72
  function isStoppedReasonResumable(reason) {
66
- return reason.kind !== 'llm_retry_stopped';
73
+ return (0, dialog_interruption_1.isInterruptionReasonManualResumeEligible)(reason);
67
74
  }
68
75
  function isDisplayStateResumable(state) {
69
76
  return state?.kind === 'stopped' && state.continueEnabled;
@@ -93,27 +100,49 @@ function shouldBroadcastRunControlCounts(previous, next) {
93
100
  async function getRunControlCountsSnapshot() {
94
101
  let proceeding = 0;
95
102
  let resumable = 0;
96
- const activeRunDialogKeys = new Set(activeRunsByDialogKey.keys());
103
+ const activeRunKeysByDialogKey = new Map(activeRunsByDialogKey.entries());
97
104
  const seenDialogKeys = new Set();
98
105
  const dialogIds = await persistence_1.DialogPersistence.listAllDialogIds('running');
99
106
  for (const dialogId of dialogIds) {
100
- const dialogKey = dialogId.key();
101
- seenDialogKeys.add(dialogKey);
102
- // Active in-memory drives are authoritative for "proceeding". This avoids transient
103
- // under-count windows when displayState persistence lags behind an already started drive.
104
- if (activeRunDialogKeys.has(dialogKey)) {
105
- proceeding++;
107
+ try {
108
+ const dialogKey = dialogId.key();
109
+ seenDialogKeys.add(dialogKey);
110
+ if (quarantiningRootDialogIds.has(dialogId.rootId)) {
111
+ continue;
112
+ }
113
+ // listAllDialogIds() is intentionally a candidate scan. Per-dialog latest reads below may
114
+ // still quarantine one malformed dialog without invalidating the rest of the snapshot.
115
+ const activeRun = activeRunKeysByDialogKey.get(dialogKey);
116
+ if (activeRun) {
117
+ proceeding++;
118
+ continue;
119
+ }
120
+ const latest = await persistence_1.DialogPersistence.loadDialogLatest(dialogId, 'running');
121
+ if (latest?.generating === true) {
122
+ proceeding++;
123
+ }
124
+ else if (isDialogLatestResumable(latest)) {
125
+ resumable++;
126
+ }
127
+ }
128
+ catch (error) {
129
+ if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
130
+ throw error;
131
+ }
132
+ log.warn('Skipping malformed dialog during run-control snapshot rebuild', error, {
133
+ dialogId: dialogId.valueOf(),
134
+ });
106
135
  continue;
107
136
  }
108
- const latest = await persistence_1.DialogPersistence.loadDialogLatest(dialogId, 'running');
109
- if (latest?.generating === true) {
110
- proceeding++;
137
+ }
138
+ for (const [dialogKey, activeRun] of activeRunKeysByDialogKey.entries()) {
139
+ if (!activeRun) {
140
+ continue;
111
141
  }
112
- else if (isDialogLatestResumable(latest)) {
113
- resumable++;
142
+ const [rootId] = dialogKey.includes('#') ? dialogKey.split('#') : [dialogKey];
143
+ if (!rootId || quarantiningRootDialogIds.has(rootId)) {
144
+ continue;
114
145
  }
115
- }
116
- for (const dialogKey of activeRunDialogKeys) {
117
146
  if (!seenDialogKeys.has(dialogKey)) {
118
147
  proceeding++;
119
148
  }
@@ -151,10 +180,68 @@ function createActiveRun(dialogId) {
151
180
  }
152
181
  function clearActiveRun(dialogId) {
153
182
  const deleted = activeRunsByDialogKey.delete(dialogId.key());
154
- if (!deleted)
183
+ if (!deleted) {
184
+ clearQuarantiningRootDialogIfIdle(dialogId.rootId);
155
185
  return;
186
+ }
187
+ clearQuarantiningRootDialogIfIdle(dialogId.rootId);
156
188
  syncRunControlCountsAfterActiveRunChange('clear_active_run', dialogId);
157
189
  }
190
+ function clearQuarantiningRootDialogIfIdle(rootId) {
191
+ for (const key of activeRunsByDialogKey.keys()) {
192
+ const [candidateRootId] = key.includes('#') ? key.split('#') : [key];
193
+ if (candidateRootId === rootId) {
194
+ return;
195
+ }
196
+ }
197
+ quarantiningRootDialogIds.delete(rootId);
198
+ }
199
+ function clearRootDialogQuarantiningIfIdle(rootDialogId) {
200
+ clearQuarantiningRootDialogIfIdle(rootDialogId.selfId);
201
+ }
202
+ function markRootDialogQuarantining(rootDialogId) {
203
+ quarantiningRootDialogIds.add(rootDialogId.selfId);
204
+ }
205
+ function clearRootDialogQuarantining(rootDialogId) {
206
+ quarantiningRootDialogIds.delete(rootDialogId.selfId);
207
+ }
208
+ async function forceStopActiveRunsForRootDialog(rootDialogId) {
209
+ for (const key of Array.from(activeRunsByDialogKey.keys())) {
210
+ const [rootId, selfId] = key.includes('#') ? key.split('#') : [key, key];
211
+ if (!rootId || !selfId)
212
+ continue;
213
+ if (rootId !== rootDialogId.selfId)
214
+ continue;
215
+ const dialogId = new dialog_1.DialogID(selfId, rootId);
216
+ const run = activeRunsByDialogKey.get(key);
217
+ if (!run)
218
+ continue;
219
+ if (!run.stopRequested) {
220
+ run.stopRequested = 'emergency_stop';
221
+ try {
222
+ await setDialogDisplayState(dialogId, {
223
+ kind: 'proceeding_stop_requested',
224
+ reason: 'emergency_stop',
225
+ });
226
+ }
227
+ catch (error) {
228
+ log.warn('Failed to persist stop-requested state while forcing root dialog stop', error, {
229
+ dialogId: dialogId.valueOf(),
230
+ rootDialogId: rootDialogId.valueOf(),
231
+ });
232
+ }
233
+ }
234
+ try {
235
+ run.abortController.abort();
236
+ }
237
+ catch (error) {
238
+ log.warn('Failed to abort active run while forcing root dialog stop', error, {
239
+ dialogId: dialogId.valueOf(),
240
+ rootDialogId: rootDialogId.valueOf(),
241
+ });
242
+ }
243
+ }
244
+ }
158
245
  function getStopRequestedReason(dialogId) {
159
246
  return activeRunsByDialogKey.get(dialogId.key())?.stopRequested;
160
247
  }
@@ -350,10 +437,36 @@ async function computeIdleDisplayStateFromPersistence(dialogId) {
350
437
  }
351
438
  return { kind: 'idle_waiting_user' };
352
439
  }
440
+ async function computeIdleDisplayStateForReconciliation(dialogId) {
441
+ try {
442
+ return await computeIdleDisplayStateFromPersistence(dialogId);
443
+ }
444
+ catch (error) {
445
+ if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
446
+ throw error;
447
+ }
448
+ log.warn('Skipping malformed dialog during display-state idle reconstruction', error, {
449
+ dialogId: dialogId.valueOf(),
450
+ });
451
+ return null;
452
+ }
453
+ }
353
454
  async function reconcileDisplayStatesAfterRestart() {
354
455
  const dialogIds = await persistence_1.DialogPersistence.listAllDialogIds('running');
355
456
  for (const dialogId of dialogIds) {
356
- const latest = await persistence_1.DialogPersistence.loadDialogLatest(dialogId, 'running');
457
+ let latest;
458
+ try {
459
+ latest = await persistence_1.DialogPersistence.loadDialogLatest(dialogId, 'running');
460
+ }
461
+ catch (error) {
462
+ if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
463
+ throw error;
464
+ }
465
+ log.warn('Skipping malformed dialog during display-state restart reconciliation', error, {
466
+ dialogId: dialogId.valueOf(),
467
+ });
468
+ continue;
469
+ }
357
470
  const existing = latest?.displayState;
358
471
  const existingMarker = latest?.executionMarker;
359
472
  if (existingMarker && existingMarker.kind === 'dead' && dialogId.selfId !== dialogId.rootId) {
@@ -380,7 +493,10 @@ async function reconcileDisplayStatesAfterRestart() {
380
493
  (existing !== undefined &&
381
494
  (existing.kind === 'proceeding' || existing.kind === 'proceeding_stop_requested'));
382
495
  if (wasProceeding) {
383
- const nextIdle = await computeIdleDisplayStateFromPersistence(dialogId);
496
+ const nextIdle = await computeIdleDisplayStateForReconciliation(dialogId);
497
+ if (!nextIdle) {
498
+ continue;
499
+ }
384
500
  const next = nextIdle.kind === 'blocked'
385
501
  ? nextIdle
386
502
  : {
@@ -406,7 +522,10 @@ async function reconcileDisplayStatesAfterRestart() {
406
522
  continue;
407
523
  }
408
524
  if (!existing) {
409
- const inferred = await computeIdleDisplayStateFromPersistence(dialogId);
525
+ const inferred = await computeIdleDisplayStateForReconciliation(dialogId);
526
+ if (!inferred) {
527
+ continue;
528
+ }
410
529
  try {
411
530
  await persistence_1.DialogPersistence.mutateDialogLatest(dialogId, () => ({
412
531
  kind: 'patch',
@@ -473,21 +473,29 @@ async function appendForkBaselineState(plan, baselineSubdialogCreatedRecords) {
473
473
  }
474
474
  async function persistForkPlan(args) {
475
475
  const { plan } = args;
476
- let rewrittenMetadata;
477
476
  if (plan.targetId.selfId === plan.targetId.rootId) {
478
- rewrittenMetadata = {
479
- ...plan.metadata,
477
+ if (plan.metadata.supdialogId !== undefined ||
478
+ plan.metadata.sessionSlug !== undefined ||
479
+ plan.metadata.assignmentFromSup !== undefined) {
480
+ throw new Error(`fork root plan received subdialog metadata: ${plan.targetId.valueOf()}`);
481
+ }
482
+ const rewrittenMetadata = {
480
483
  id: plan.targetId.selfId,
484
+ agentId: plan.metadata.agentId,
485
+ taskDocPath: plan.metadata.taskDocPath,
481
486
  createdAt: args.now,
487
+ ...(plan.metadata.priming ? { priming: plan.metadata.priming } : {}),
482
488
  };
489
+ await persistence_1.DialogPersistence.saveRootDialogMetadata(plan.targetId, rewrittenMetadata, 'running');
483
490
  }
484
491
  else {
485
492
  if (plan.metadata.supdialogId === undefined) {
486
493
  throw new Error(`fork subdialog plan missing supdialog metadata: ${plan.targetId.valueOf()}`);
487
494
  }
488
- rewrittenMetadata = rewriteSubdialogMetadataForFork(plan.metadata, plan.sourceId.rootId, plan.targetId.rootId);
495
+ const rewrittenMetadata = rewriteSubdialogMetadataForFork(plan.metadata, plan.sourceId.rootId, plan.targetId.rootId);
496
+ await persistence_1.DialogPersistence.ensureSubdialogDirectory(plan.targetId, 'running');
497
+ await persistence_1.DialogPersistence.saveSubdialogMetadata(plan.targetId, rewrittenMetadata, 'running');
489
498
  }
490
- await persistence_1.DialogPersistence.saveDialogMetadata(plan.targetId, rewrittenMetadata, 'running');
491
499
  for (const course of plan.retainedCourses) {
492
500
  for (const event of course.events) {
493
501
  await persistence_1.DialogPersistence.appendEvent(plan.targetId, course.course, rewriteRecordForFork(event, plan.targetId.rootId), 'running');
@@ -0,0 +1,18 @@
1
+ import type { DialogInterruptionReason } from '@longrun-ai/kernel/types/display-state';
2
+ /**
3
+ * Decides whether a finalized stopped dialog should expose manual Continue.
4
+ *
5
+ * This only applies to the persisted/broadcast final stopped state after the driver has fully
6
+ * unwound and confirmed an interrupted terminal projection. Transient interruption markers and
7
+ * retry-stop progress events must stay disabled until that final stopped state is written. Do not
8
+ * "simplify" this by enabling Continue earlier: that would let the UI offer a resume action before
9
+ * the dialog is actually resumable again, reintroducing exactly the class of race/false-positive
10
+ * bugs this split is here to prevent.
11
+ *
12
+ * `llm_retry_stopped` is intentionally resumable here:
13
+ * - manual Continue starts a fresh drive invocation, which naturally resets per-run retry state
14
+ * and provider-quirk tracking state;
15
+ * - it does NOT reset process-wide adaptive smart-rate backoff, which is shared by
16
+ * provider/model and should keep protecting the system.
17
+ */
18
+ export declare function isInterruptionReasonManualResumeEligible(reason: DialogInterruptionReason): boolean;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isInterruptionReasonManualResumeEligible = isInterruptionReasonManualResumeEligible;
4
+ /**
5
+ * Decides whether a finalized stopped dialog should expose manual Continue.
6
+ *
7
+ * This only applies to the persisted/broadcast final stopped state after the driver has fully
8
+ * unwound and confirmed an interrupted terminal projection. Transient interruption markers and
9
+ * retry-stop progress events must stay disabled until that final stopped state is written. Do not
10
+ * "simplify" this by enabling Continue earlier: that would let the UI offer a resume action before
11
+ * the dialog is actually resumable again, reintroducing exactly the class of race/false-positive
12
+ * bugs this split is here to prevent.
13
+ *
14
+ * `llm_retry_stopped` is intentionally resumable here:
15
+ * - manual Continue starts a fresh drive invocation, which naturally resets per-run retry state
16
+ * and provider-quirk tracking state;
17
+ * - it does NOT reset process-wide adaptive smart-rate backoff, which is shared by
18
+ * provider/model and should keep protecting the system.
19
+ */
20
+ function isInterruptionReasonManualResumeEligible(reason) {
21
+ switch (reason.kind) {
22
+ case 'user_stop':
23
+ case 'emergency_stop':
24
+ case 'server_restart':
25
+ case 'fork_continue_ready':
26
+ case 'system_stop':
27
+ case 'llm_retry_stopped':
28
+ return true;
29
+ default: {
30
+ const _exhaustive = reason;
31
+ return _exhaustive;
32
+ }
33
+ }
34
+ }