dominds 1.16.7 → 1.16.10

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 (144) hide show
  1. package/README.md +1 -1
  2. package/README.zh.md +1 -1
  3. package/dist/dialog-display-state.js +35 -3
  4. package/dist/docs/app-constitution.md +2 -2
  5. package/dist/docs/app-constitution.zh.md +2 -2
  6. package/dist/docs/dialog-system.md +49 -0
  7. package/dist/docs/dialog-system.zh.md +49 -0
  8. package/dist/docs/team_mgmt-toolset.md +1 -1
  9. package/dist/docs/team_mgmt-toolset.zh.md +1 -1
  10. package/dist/llm/gen/codex.d.ts +1 -9
  11. package/dist/llm/gen/codex.js +3 -29
  12. package/dist/llm/kernel-driver/drive.js +22 -81
  13. package/dist/llm/kernel-driver/flow.js +232 -51
  14. package/dist/llm/kernel-driver/reply-guidance.d.ts +1 -0
  15. package/dist/llm/kernel-driver/reply-guidance.js +39 -5
  16. package/dist/llm/kernel-driver/tellask-special.js +3 -5
  17. package/dist/llm/stop-reason-i18n.d.ts +1 -1
  18. package/dist/llm/stop-reason-i18n.js +0 -4
  19. package/dist/persistence.js +14 -4
  20. package/dist/runtime/interjection-pause-stop.d.ts +5 -0
  21. package/dist/runtime/interjection-pause-stop.js +39 -0
  22. package/dist/runtime/reply-prompt-copy.js +2 -2
  23. package/dist/server/websocket-handler.js +14 -0
  24. package/dist/tools/apply-patch.js +5 -5
  25. package/dist/tools/builtins.js +11 -12
  26. package/dist/tools/prompts/codex_inspect_and_patch_tools/en/errors.md +45 -0
  27. package/dist/tools/prompts/codex_inspect_and_patch_tools/en/index.md +37 -0
  28. package/dist/tools/prompts/codex_inspect_and_patch_tools/en/principles.md +41 -0
  29. package/dist/tools/prompts/codex_inspect_and_patch_tools/en/scenarios.md +40 -0
  30. package/dist/tools/prompts/codex_inspect_and_patch_tools/en/tools.md +47 -0
  31. package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/errors.md +45 -0
  32. package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/index.md +37 -0
  33. package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/principles.md +41 -0
  34. package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/scenarios.md +40 -0
  35. package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/tools.md +47 -0
  36. package/dist/tools/team_mgmt.js +13 -21
  37. package/package.json +4 -4
  38. package/webapp/dist/assets/{_basePickBy-B7FV6Gnn.js → _basePickBy-BKgfg72Q.js} +3 -3
  39. package/webapp/dist/assets/{_basePickBy-B7FV6Gnn.js.map → _basePickBy-BKgfg72Q.js.map} +1 -1
  40. package/webapp/dist/assets/{_baseUniq-CmVnLJpw.js → _baseUniq-DKhs7H5s.js} +2 -2
  41. package/webapp/dist/assets/{_baseUniq-CmVnLJpw.js.map → _baseUniq-DKhs7H5s.js.map} +1 -1
  42. package/webapp/dist/assets/{arc-DSJlh9AU.js → arc-Tykg3Fx4.js} +2 -2
  43. package/webapp/dist/assets/{arc-DSJlh9AU.js.map → arc-Tykg3Fx4.js.map} +1 -1
  44. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-Cd2cTHzo.js → architectureDiagram-2XIMDMQ5-BAyn6_in.js} +7 -7
  45. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-Cd2cTHzo.js.map → architectureDiagram-2XIMDMQ5-BAyn6_in.js.map} +1 -1
  46. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-C0uEp_Tz.js → blockDiagram-WCTKOSBZ-CGbo6x6_.js} +7 -7
  47. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-C0uEp_Tz.js.map → blockDiagram-WCTKOSBZ-CGbo6x6_.js.map} +1 -1
  48. package/webapp/dist/assets/{c4Diagram-IC4MRINW-B37U92JK.js → c4Diagram-IC4MRINW-CUizxwo0.js} +3 -3
  49. package/webapp/dist/assets/{c4Diagram-IC4MRINW-B37U92JK.js.map → c4Diagram-IC4MRINW-CUizxwo0.js.map} +1 -1
  50. package/webapp/dist/assets/{channel-DLHnjnQf.js → channel-DvP7WrjO.js} +2 -2
  51. package/webapp/dist/assets/{channel-DLHnjnQf.js.map → channel-DvP7WrjO.js.map} +1 -1
  52. package/webapp/dist/assets/{chunk-4BX2VUAB-DnZvfQyp.js → chunk-4BX2VUAB-cgnNaqgV.js} +2 -2
  53. package/webapp/dist/assets/{chunk-4BX2VUAB-DnZvfQyp.js.map → chunk-4BX2VUAB-cgnNaqgV.js.map} +1 -1
  54. package/webapp/dist/assets/{chunk-55IACEB6-BG-cjz3M.js → chunk-55IACEB6-BEUsguTg.js} +2 -2
  55. package/webapp/dist/assets/{chunk-55IACEB6-BG-cjz3M.js.map → chunk-55IACEB6-BEUsguTg.js.map} +1 -1
  56. package/webapp/dist/assets/{chunk-FMBD7UC4-B1L8cPfl.js → chunk-FMBD7UC4-B2p0efxm.js} +2 -2
  57. package/webapp/dist/assets/{chunk-FMBD7UC4-B1L8cPfl.js.map → chunk-FMBD7UC4-B2p0efxm.js.map} +1 -1
  58. package/webapp/dist/assets/{chunk-JSJVCQXG-C65w23ZF.js → chunk-JSJVCQXG-Bd09WM0B.js} +2 -2
  59. package/webapp/dist/assets/{chunk-JSJVCQXG-C65w23ZF.js.map → chunk-JSJVCQXG-Bd09WM0B.js.map} +1 -1
  60. package/webapp/dist/assets/{chunk-KX2RTZJC-_4YSMrEL.js → chunk-KX2RTZJC-DaLNbvSI.js} +2 -2
  61. package/webapp/dist/assets/{chunk-KX2RTZJC-_4YSMrEL.js.map → chunk-KX2RTZJC-DaLNbvSI.js.map} +1 -1
  62. package/webapp/dist/assets/{chunk-NQ4KR5QH-ComURSQb.js → chunk-NQ4KR5QH-6dsWbn61.js} +4 -4
  63. package/webapp/dist/assets/{chunk-NQ4KR5QH-ComURSQb.js.map → chunk-NQ4KR5QH-6dsWbn61.js.map} +1 -1
  64. package/webapp/dist/assets/{chunk-QZHKN3VN-BrxvuRI6.js → chunk-QZHKN3VN-C0e1qWr4.js} +2 -2
  65. package/webapp/dist/assets/{chunk-QZHKN3VN-BrxvuRI6.js.map → chunk-QZHKN3VN-C0e1qWr4.js.map} +1 -1
  66. package/webapp/dist/assets/{chunk-WL4C6EOR-CW7tAF_z.js → chunk-WL4C6EOR-ChheG0OU.js} +6 -6
  67. package/webapp/dist/assets/{chunk-WL4C6EOR-CW7tAF_z.js.map → chunk-WL4C6EOR-ChheG0OU.js.map} +1 -1
  68. package/webapp/dist/assets/{classDiagram-VBA2DB6C-BWrPbwfd.js → classDiagram-VBA2DB6C-uUAnWHsS.js} +7 -7
  69. package/webapp/dist/assets/{classDiagram-VBA2DB6C-BWrPbwfd.js.map → classDiagram-VBA2DB6C-uUAnWHsS.js.map} +1 -1
  70. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BWrPbwfd.js → classDiagram-v2-RAHNMMFH-uUAnWHsS.js} +7 -7
  71. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BWrPbwfd.js.map → classDiagram-v2-RAHNMMFH-uUAnWHsS.js.map} +1 -1
  72. package/webapp/dist/assets/{clone-B-TYPsxN.js → clone-BiXgC0aE.js} +2 -2
  73. package/webapp/dist/assets/{clone-B-TYPsxN.js.map → clone-BiXgC0aE.js.map} +1 -1
  74. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-C1bfZcVY.js → cose-bilkent-S5V4N54A-C-h7F7gA.js} +2 -2
  75. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-C1bfZcVY.js.map → cose-bilkent-S5V4N54A-C-h7F7gA.js.map} +1 -1
  76. package/webapp/dist/assets/{dagre-KLK3FWXG-BfD08d2e.js → dagre-KLK3FWXG-5B3k91Lo.js} +7 -7
  77. package/webapp/dist/assets/{dagre-KLK3FWXG-BfD08d2e.js.map → dagre-KLK3FWXG-5B3k91Lo.js.map} +1 -1
  78. package/webapp/dist/assets/{diagram-E7M64L7V-Dyd9OucT.js → diagram-E7M64L7V-CFtPXaNS.js} +8 -8
  79. package/webapp/dist/assets/{diagram-E7M64L7V-Dyd9OucT.js.map → diagram-E7M64L7V-CFtPXaNS.js.map} +1 -1
  80. package/webapp/dist/assets/{diagram-IFDJBPK2-BN-JCceb.js → diagram-IFDJBPK2-CUuPPDwe.js} +7 -7
  81. package/webapp/dist/assets/{diagram-IFDJBPK2-BN-JCceb.js.map → diagram-IFDJBPK2-CUuPPDwe.js.map} +1 -1
  82. package/webapp/dist/assets/{diagram-P4PSJMXO-C2jh_Kry.js → diagram-P4PSJMXO-D7oYhsVm.js} +7 -7
  83. package/webapp/dist/assets/{diagram-P4PSJMXO-C2jh_Kry.js.map → diagram-P4PSJMXO-D7oYhsVm.js.map} +1 -1
  84. package/webapp/dist/assets/{erDiagram-INFDFZHY-C3Pj10OJ.js → erDiagram-INFDFZHY-DUDHdT_e.js} +5 -5
  85. package/webapp/dist/assets/{erDiagram-INFDFZHY-C3Pj10OJ.js.map → erDiagram-INFDFZHY-DUDHdT_e.js.map} +1 -1
  86. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-a5vzSSCo.js → flowDiagram-PKNHOUZH-CT7lC5J1.js} +7 -7
  87. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-a5vzSSCo.js.map → flowDiagram-PKNHOUZH-CT7lC5J1.js.map} +1 -1
  88. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-DIua0Qjr.js → ganttDiagram-A5KZAMGK-BhlcqqDR.js} +3 -3
  89. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-DIua0Qjr.js.map → ganttDiagram-A5KZAMGK-BhlcqqDR.js.map} +1 -1
  90. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CJt16FXK.js → gitGraphDiagram-K3NZZRJ6-CYLYfqiB.js} +8 -8
  91. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CJt16FXK.js.map → gitGraphDiagram-K3NZZRJ6-CYLYfqiB.js.map} +1 -1
  92. package/webapp/dist/assets/{graph-lQSuHjYm.js → graph-twAxd7MO.js} +3 -3
  93. package/webapp/dist/assets/{graph-lQSuHjYm.js.map → graph-twAxd7MO.js.map} +1 -1
  94. package/webapp/dist/assets/{index-B7llu28V.js → index-Bc1jJvgU.js} +36 -175
  95. package/webapp/dist/assets/{index-B7llu28V.js.map → index-Bc1jJvgU.js.map} +1 -1
  96. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-DzJuXz5H.js → infoDiagram-LFFYTUFH-BAA1VoC0.js} +6 -6
  97. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-DzJuXz5H.js.map → infoDiagram-LFFYTUFH-BAA1VoC0.js.map} +1 -1
  98. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-BP_s17vw.js → ishikawaDiagram-PHBUUO56-CyPvSx5W.js} +2 -2
  99. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-BP_s17vw.js.map → ishikawaDiagram-PHBUUO56-CyPvSx5W.js.map} +1 -1
  100. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-Lic1mhBM.js → journeyDiagram-4ABVD52K-CbOLT63I.js} +5 -5
  101. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-Lic1mhBM.js.map → journeyDiagram-4ABVD52K-CbOLT63I.js.map} +1 -1
  102. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-Baf2kCwQ.js → kanban-definition-K7BYSVSG-CUS-wMLR.js} +3 -3
  103. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-Baf2kCwQ.js.map → kanban-definition-K7BYSVSG-CUS-wMLR.js.map} +1 -1
  104. package/webapp/dist/assets/{layout-DUMDc8rv.js → layout-C0HW4ZHi.js} +5 -5
  105. package/webapp/dist/assets/{layout-DUMDc8rv.js.map → layout-C0HW4ZHi.js.map} +1 -1
  106. package/webapp/dist/assets/{linear-CZMoHeVH.js → linear-DNEgfkh6.js} +2 -2
  107. package/webapp/dist/assets/{linear-CZMoHeVH.js.map → linear-DNEgfkh6.js.map} +1 -1
  108. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DB2sQ--_.js → mindmap-definition-YRQLILUH-D5URwhNx.js} +4 -4
  109. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DB2sQ--_.js.map → mindmap-definition-YRQLILUH-D5URwhNx.js.map} +1 -1
  110. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Dgdrlric.js → pieDiagram-SKSYHLDU-BQbBOUPk.js} +8 -8
  111. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Dgdrlric.js.map → pieDiagram-SKSYHLDU-BQbBOUPk.js.map} +1 -1
  112. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-CJcFYfqf.js → quadrantDiagram-337W2JSQ-B_dFbPid.js} +3 -3
  113. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-CJcFYfqf.js.map → quadrantDiagram-337W2JSQ-B_dFbPid.js.map} +1 -1
  114. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-CDsT-ac7.js → requirementDiagram-Z7DCOOCP-CtWDUSB3.js} +4 -4
  115. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-CDsT-ac7.js.map → requirementDiagram-Z7DCOOCP-CtWDUSB3.js.map} +1 -1
  116. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-DiO55skm.js → sankeyDiagram-WA2Y5GQK-CqRH7yj4.js} +2 -2
  117. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-DiO55skm.js.map → sankeyDiagram-WA2Y5GQK-CqRH7yj4.js.map} +1 -1
  118. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-CNHjdBNC.js → sequenceDiagram-2WXFIKYE-B1-5-5Qx.js} +4 -4
  119. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-CNHjdBNC.js.map → sequenceDiagram-2WXFIKYE-B1-5-5Qx.js.map} +1 -1
  120. package/webapp/dist/assets/{stateDiagram-RAJIS63D-CtS3TXEd.js → stateDiagram-RAJIS63D-9krZSpaD.js} +9 -9
  121. package/webapp/dist/assets/{stateDiagram-RAJIS63D-CtS3TXEd.js.map → stateDiagram-RAJIS63D-9krZSpaD.js.map} +1 -1
  122. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-BdjJA1de.js → stateDiagram-v2-FVOUBMTO-DDLC-q0s.js} +5 -5
  123. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-BdjJA1de.js.map → stateDiagram-v2-FVOUBMTO-DDLC-q0s.js.map} +1 -1
  124. package/webapp/dist/assets/{timeline-definition-YZTLITO2-D3AiTIhK.js → timeline-definition-YZTLITO2-C64HbHNO.js} +3 -3
  125. package/webapp/dist/assets/{timeline-definition-YZTLITO2-D3AiTIhK.js.map → timeline-definition-YZTLITO2-C64HbHNO.js.map} +1 -1
  126. package/webapp/dist/assets/{treemap-KZPCXAKY-F6nRvLGK.js → treemap-KZPCXAKY-TEywEA7B.js} +5 -5
  127. package/webapp/dist/assets/{treemap-KZPCXAKY-F6nRvLGK.js.map → treemap-KZPCXAKY-TEywEA7B.js.map} +1 -1
  128. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BoukZEuo.js → vennDiagram-LZ73GAT5-CT9sZ6ft.js} +2 -2
  129. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BoukZEuo.js.map → vennDiagram-LZ73GAT5-CT9sZ6ft.js.map} +1 -1
  130. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ByfGkhZz.js → xychartDiagram-JWTSCODW-CEAg_tiv.js} +3 -3
  131. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ByfGkhZz.js.map → xychartDiagram-JWTSCODW-CEAg_tiv.js.map} +1 -1
  132. package/webapp/dist/index.html +1 -1
  133. package/dist/tools/plan.d.ts +0 -2
  134. package/dist/tools/plan.js +0 -171
  135. package/dist/tools/prompts/codex_style_tools/en/errors.md +0 -102
  136. package/dist/tools/prompts/codex_style_tools/en/index.md +0 -59
  137. package/dist/tools/prompts/codex_style_tools/en/principles.md +0 -87
  138. package/dist/tools/prompts/codex_style_tools/en/scenarios.md +0 -88
  139. package/dist/tools/prompts/codex_style_tools/en/tools.md +0 -119
  140. package/dist/tools/prompts/codex_style_tools/zh/errors.md +0 -102
  141. package/dist/tools/prompts/codex_style_tools/zh/index.md +0 -59
  142. package/dist/tools/prompts/codex_style_tools/zh/principles.md +0 -87
  143. package/dist/tools/prompts/codex_style_tools/zh/scenarios.md +0 -88
  144. package/dist/tools/prompts/codex_style_tools/zh/tools.md +0 -119
package/README.md CHANGED
@@ -203,7 +203,7 @@ Then:
203
203
 
204
204
  Platform note:
205
205
 
206
- - On Windows, the runtime does not register the `codex_style_tools` toolset. Do not grant `codex_style_tools` in `.minds/team.yaml` for Windows hosts.
206
+ - On Windows, the runtime does not register the `codex_inspect_and_patch_tools` toolset. Do not grant `codex_inspect_and_patch_tools` in `.minds/team.yaml` for Windows hosts.
207
207
 
208
208
  ## Start from scratch
209
209
 
package/README.zh.md CHANGED
@@ -142,7 +142,7 @@ dominds
142
142
 
143
143
  平台说明:
144
144
 
145
- - Windows 运行时不会注册 `codex_style_tools` 工具集。在 Windows 主机上的 `.minds/team.yaml` 中不要授予 `codex_style_tools`。
145
+ - Windows 运行时不会注册 `codex_inspect_and_patch_tools` 工具集。在 Windows 主机上的 `.minds/team.yaml` 中不要授予 `codex_inspect_and_patch_tools`。
146
146
 
147
147
  ## 从零开始(空文件夹启动)
148
148
 
@@ -51,6 +51,7 @@ const evt_registry_1 = require("./evt-registry");
51
51
  const log_1 = require("./log");
52
52
  const persistence_1 = require("./persistence");
53
53
  const persistence_errors_1 = require("./persistence-errors");
54
+ const interjection_pause_stop_1 = require("./runtime/interjection-pause-stop");
54
55
  const log = (0, log_1.createLogger)('dialog-display-state');
55
56
  let broadcastToClients;
56
57
  const activeRunsByDialogKey = new Map();
@@ -128,11 +129,21 @@ async function getRunControlCountsSnapshot() {
128
129
  }
129
130
  else if (latest?.executionMarker?.kind === 'interrupted' &&
130
131
  isStoppedReasonResumable(latest.executionMarker.reason)) {
131
- const q4h = await persistence_1.DialogPersistence.loadQuestions4HumanState(dialogId, 'running');
132
- const pendingSubdialogs = await persistence_1.DialogPersistence.loadPendingSubdialogs(dialogId, 'running');
133
- if (q4h.length === 0 && pendingSubdialogs.length === 0) {
132
+ // Keep run-control counts aligned with actual Continue affordance:
133
+ // - ordinary interrupted dialogs count as resumable only when no blocker remains
134
+ // - interjection-paused dialogs still count as resumable even if blocker facts remain,
135
+ // because the intended UX is that Continue exits the temporary paused projection
136
+ // and re-evaluates the original task from fresh facts
137
+ if ((0, interjection_pause_stop_1.isUserInterjectionPauseStopReason)(latest.executionMarker.reason)) {
134
138
  resumable++;
135
139
  }
140
+ else {
141
+ const q4h = await persistence_1.DialogPersistence.loadQuestions4HumanState(dialogId, 'running');
142
+ const pendingSubdialogs = await persistence_1.DialogPersistence.loadPendingSubdialogs(dialogId, 'running');
143
+ if (q4h.length === 0 && pendingSubdialogs.length === 0) {
144
+ resumable++;
145
+ }
146
+ }
136
147
  }
137
148
  }
138
149
  catch (error) {
@@ -470,6 +481,27 @@ async function refreshRunControlProjectionFromPersistenceFacts(dialogId, trigger
470
481
  latest.executionMarker.kind === 'dead') {
471
482
  return { kind: 'dead', reason: latest.executionMarker.reason };
472
483
  }
484
+ if (latest.executionMarker?.kind === 'interrupted' &&
485
+ (0, interjection_pause_stop_1.isUserInterjectionPauseStopReason)(latest.executionMarker.reason)) {
486
+ // WARNING:
487
+ // This is the one place where the projection intentionally preserves the paused-interjection
488
+ // stopped state ahead of the current blocker facts. That is not a bug: after a user
489
+ // interjection we want the UI to keep showing "original task paused; click Continue" even if
490
+ // the underlying dialog is still waiting on Q4H/subdialogs.
491
+ //
492
+ // The true source-of-truth decision about what Continue should do next lives in
493
+ // `flow.ts`'s resume path, which performs a fresh fact scan at resume time and then either:
494
+ // - restores `blocked`, or
495
+ // - keeps driving immediately.
496
+ //
497
+ // Do not "heal" this branch away by prioritizing blocker facts here; that would collapse the
498
+ // temporary interjection UX and make repeated interjection turns revert too early.
499
+ return {
500
+ kind: 'stopped',
501
+ reason: latest.executionMarker.reason,
502
+ continueEnabled: isStoppedReasonResumable(latest.executionMarker.reason),
503
+ };
504
+ }
473
505
  const q4h = await persistence_1.DialogPersistence.loadQuestions4HumanState(dialogId, 'running');
474
506
  const pendingSubdialogs = await persistence_1.DialogPersistence.loadPendingSubdialogs(dialogId, 'running');
475
507
  const hasQ4H = q4h.length > 0;
@@ -444,7 +444,7 @@ Suggested team shape:
444
444
  - non-goal: does not directly edit product code or take over build/process management.
445
445
  - `web_developer`
446
446
  - primary responsibility: implement UI/interaction fixes, consume `web_tester` findings, and close the loop;
447
- - default toolsets: code-edit/search tools such as `codex_style_tools` (or equivalent) plus optional access to read tester evidence;
447
+ - default toolsets: code-edit/search tools such as `codex_inspect_and_patch_tools` (or equivalent) plus optional access to read tester evidence;
448
448
  - non-goal: should not blur browser acceptance into an implicit “I also tested it” posture; when acceptance is needed, it should explicitly tell/ask `web_tester`.
449
449
 
450
450
  Suggested `team.yaml` fragment:
@@ -463,7 +463,7 @@ members:
463
463
  icon: '🛠️'
464
464
  toolsets:
465
465
  - ws_read
466
- - codex_style_tools
466
+ - codex_inspect_and_patch_tools
467
467
  ```
468
468
 
469
469
  Requirements for the `playwright_interactive` toolset design:
@@ -443,7 +443,7 @@ Web Dev App 需要明确区分三套命名,避免再次漂移:
443
443
  - 非目标:不直接修改业务代码;不接管构建/进程管理。
444
444
  - `web_developer`
445
445
  - 主要职责:实现页面/UI/交互修复,消费 `web_tester` 的缺陷报告并完成闭环。
446
- - 默认工具集:代码修改/检索工具(如 `codex_style_tools` 或等价工具)+ 可选读取 `web_tester` 产出的证据。
446
+ - 默认工具集:代码修改/检索工具(如 `codex_inspect_and_patch_tools` 或等价工具)+ 可选读取 `web_tester` 产出的证据。
447
447
  - 非目标:不把浏览器验收职责模糊地“顺手做掉”;需要时应显式 tellask `web_tester` 做验收。
448
448
 
449
449
  建议的 `team.yaml` 片段:
@@ -462,7 +462,7 @@ members:
462
462
  icon: '🛠️'
463
463
  toolsets:
464
464
  - ws_read
465
- - codex_style_tools
465
+ - codex_inspect_and_patch_tools
466
466
  ```
467
467
 
468
468
  关于 `playwright_interactive` 工具集的设计要求:
@@ -155,6 +155,55 @@ Dialog state is persisted to storage at key points:
155
155
 
156
156
  This ensures crash recovery and enables the backend to resume from any persisted state without depending on frontend state.
157
157
 
158
+ ### User Interjection Pause And Continue Semantics
159
+
160
+ When a dialog still carries an inter-dialog reply obligation, but the user temporarily interjects and asks it to handle a local question first, the system must distinguish between the **UI projection** and the **true driving source state**.
161
+
162
+ **Normative semantics**:
163
+
164
+ 1. Every user interjection message is driven as a complete normal round.
165
+ 2. If that round needs tools, the system MUST finish the full tool round and any post-tool follow-up before pausing.
166
+ 3. The system only projects the original task as resumable `stopped` when this interjection has actually parked an original task that still needs explicit restoration.
167
+ 4. If there is no parked original task to resume afterwards (for example, no inter-dialog reply obligation needs reassertion), the interjection round should simply finish and return to the true underlying state without showing this special `stopped` panel.
168
+ 5. As long as the user keeps sending new messages, the dialog stays in temporary interjection-chat handling, and that paused projection remains in place only if it was established in the first place.
169
+ 6. Only an explicit UI `Continue` attempts to restore the original task.
170
+
171
+ **Strict boundary**: a formal `askHuman` answer is not part of this "user interjection" category. As soon as a prompt carries a real `q4hAnswerCallId`, it belongs to the askHuman reply channel and semantically continues an already-materialized question/answer chain; it must never be downgraded into temporary local side-chat.
172
+
173
+ **Key point**: this `stopped` state is only a temporary run-control / UI projection. It is not the same as an ordinary system-stop failure, and it is not the final business source of truth. It also does not apply to every interjection; it exists only when there really is a parked original task to resume.
174
+
175
+ After the user clicks `Continue`, the backend MUST re-evaluate fresh persistence facts and decide which true-source case now applies. It must not infer the result purely from the visible `displayState`:
176
+
177
+ - **Case 1: the dialog no longer has a reply obligation**
178
+ If there is also no blocker, the dialog should simply continue driving. If it has already become ordinary idle-waiting-user, then `resume_dialog` is no longer actually resumable.
179
+ - **Case 2: the dialog still has a reply obligation and is still suspended**
180
+ Typical examples are pending Q4H or pending subdialogs. In this case, `Continue` should exit the interjection-paused projection and restore the true `blocked` state.
181
+ - **Case 3: the dialog still has a reply obligation but is no longer suspended and is eligible to proceed**
182
+ For example, the blocker has disappeared, or a queued prompt provides a valid continuation path. In this case, `Continue` must not first fall back to an intermediate placeholder `blocked/idle` state; it should keep driving immediately.
183
+
184
+ **This leads to two implementation constraints**:
185
+
186
+ - `refreshRunControlProjectionFromPersistenceFacts()` MUST preserve the special "interjection handled; original task paused" `stopped` projection until the user explicitly clicks `Continue`; otherwise the UI collapses back to ordinary `blocked` too early and breaks multi-turn interjection UX. Conversely, when there is no parked original task, this paused projection should not be created at all.
187
+ - The actual outcome of `Continue` MUST be decided in the resume drive path by re-reading fresh persistence facts. "Continue is clickable" does not mean "the dialog will definitely enter proceeding immediately".
188
+ - If `Continue` reveals that the true state is still `blocked`, the reply-obligation reassertion copy should be materialized immediately as a runtime guide in both `dlg.msgs` and persisted course history, while also surfacing as a frontend bubble. That lets the later real resume path rely on ordinary context replay instead of synthesizing a second duplicate runtime prompt.
189
+ - The run-control toolbar's `resumable` count should align with "manual Continue attempt is meaningful". Therefore an interjection-paused `stopped` dialog still counts as resumable even when underlying blocker facts remain, because the business meaning of `Continue` there is "exit the temporary paused projection and re-evaluate from source-of-truth facts".
190
+
191
+ **Mental-model warning**:
192
+
193
+ - Do not reason about this flow from `displayState.kind === 'stopped'` alone.
194
+ - Do not reason about it from blocker facts alone and then wonder why the UI still shows `stopped`.
195
+ - Do not reason about it from `resume_dialog` eligibility alone and assume resumption always means immediate running.
196
+ - Do not flatten every `origin === 'user'` prompt into "interjection"; a non-empty `q4hAnswerCallId` means askHuman answer continuation and follows a different semantic path.
197
+
198
+ You need all of the following together to understand the behavior correctly:
199
+
200
+ - reply-guidance suppression / deferred reassertion for interjection turns
201
+ - flow logic for "pause after local interjection reply" plus "fresh-fact second decision after Continue"
202
+ - dialog-display-state projection preservation
203
+ - websocket resume entry semantics distinguishing "allowed to attempt Continue" from "actually re-entered driving"
204
+
205
+ This is an intentionally cross-module semantic contract. Do not locally "simplify" one piece based only on its surface meaning.
206
+
158
207
  ---
159
208
 
160
209
  ## 3-Type Teammate Tellask Taxonomy
@@ -154,6 +154,55 @@
154
154
 
155
155
  这确保了崩溃恢复,并使后端能够从任何持久化状态恢复,而不依赖于前端状态。
156
156
 
157
+ ### 用户插话暂停与 Continue 语义
158
+
159
+ 当某个对话仍带有跨对话回复义务,但用户临时插话要求它先处理本地问题时,系统必须区分**UI 投影**与**真实驱动源状态**。
160
+
161
+ **规范语义**:
162
+
163
+ 1. 每条用户插话消息都按正常驱动轮完整执行。
164
+ 2. 若该轮需要工具,则必须先完整跑完该工具轮及其 post-tool follow-up。
165
+ 3. 只有当这条插话确实打断了一个仍待恢复的“原任务”时,系统才把该原任务投影为可 `Continue` 的 `stopped`,让用户先看到最后一条回复。
166
+ 4. 若当前并不存在待恢复的原任务(例如没有待重申的跨对话回复义务),则插话轮结束后应直接回到真实 underlying state,而不显示这个特殊 `stopped` 面板。
167
+ 5. 只要用户继续发送新消息,就继续作为插话临时对话处理;这个 paused projection 仅在它已被建立时持续保持。
168
+ 6. 只有用户显式点击 UI `Continue`,系统才尝试恢复原任务。
169
+
170
+ **严格边界**:`askHuman` 的正式回答不属于这里的“用户插话”。只要一条 prompt 带着真实的 `q4hAnswerCallId`,它就属于 askHuman 回复通道,语义上是在继续已 materialize 的提问/应答链路,绝不能被压入“本地临时插话聊天”。
171
+
172
+ **关键点**:这里的 `stopped` 只是一个临时 run-control / UI 投影,不等于普通 system-stop 失败,也不是最终的业务真源;并且它不是所有插话都会出现,只在“确有一个待恢复的原任务被临时停靠”时出现。
173
+
174
+ 点击 `Continue` 后,后端必须重新从 persistence 真源判定当前对话属于哪一种情况,而不能只根据表面的 `displayState` 做静态推断:
175
+
176
+ - **情况 1:当前对话没有回复义务**
177
+ 这时若也没有其他 blocker,就应直接继续 drive;若已回到普通待用户输入态,则 `resume_dialog` 不应再被视为可继续。
178
+ - **情况 2:当前对话仍有回复义务,但处于 suspend 状态**
179
+ 常见于仍在等待 Q4H / pending subdialogs。此时 `Continue` 应退出插话 paused projection,并恢复成真实的 `blocked`。
180
+ - **情况 3:当前对话仍有回复义务,但已不再 suspend,具备继续推进条件**
181
+ 例如 blocker 已消失,或存在允许继续的 queued prompt。此时 `Continue` 不应先落一个中间 `blocked/idle` 占位态,而应直接继续 drive。
182
+
183
+ **因此有两个实现约束**:
184
+
185
+ - `refreshRunControlProjectionFromPersistenceFacts()` 在用户尚未点击 `Continue` 前,必须保留这层“插话已处理;原任务已暂停”的 `stopped` 投影;否则 UI 会过早塌回普通 `blocked`,破坏多轮插话体验。反过来,如果当前其实没有待恢复原任务,则根本不应建立这层 paused projection。
186
+ - 真正决定 `Continue` 结果的逻辑,必须在恢复驱动路径中重新读取 fresh persistence facts;不能把“可点 Continue”误解为“必然立即 proceeding”。
187
+ - 若 `Continue` 后真源仍是 `blocked`,回复责任重申文案应当立即作为 runtime guide 同时进入 `dlg.msgs` 与持久化课程历史,并同步发前端气泡;这样后面真正恢复 drive 时只需正常读取上下文,不应再额外补发一条重复的 runtime prompt。
188
+ - run-control 工具栏中的 `resumable` 计数,应与“是否允许手动 Continue 尝试”保持一致。因此,处于 interjection-paused `stopped` 的对话即便底层仍有 blocker,也应计入 `resumable`;因为 `Continue` 的业务语义正是“退出这层临时 paused projection,并从真源重判下一步”。
189
+
190
+ **心智模型提醒**:
191
+
192
+ - 不能只看 `displayState.kind === 'stopped'` 就理解这条链路。
193
+ - 不能只看 blocker facts 就理解为什么 UI 仍显示 `stopped`。
194
+ - 也不能只看 `resume_dialog` eligibility 就推断恢复后一定马上运行。
195
+ - 更不能把所有 `origin === 'user'` 的输入都笼统视作“用户插话”;`q4hAnswerCallId` 非空的 prompt 是 askHuman answer continuation,必须按另一条语义链处理。
196
+
197
+ 必须把以下几块一起看,才能形成完整且精确的理解:
198
+
199
+ - reply-guidance 中对插话轮的回复义务 suppression / deferred reassertion
200
+ - flow 中“插话回复后停车”与“Continue 后 fresh fact 二次判定”
201
+ - dialog-display-state 中 paused projection 的保留策略
202
+ - websocket resume 入口对“可尝试 Continue”与“实际已恢复 drive”的区分
203
+
204
+ 这是一条跨模块协同语义,不允许在单点上做“表面看起来更简单”的局部简化。
205
+
157
206
  ---
158
207
 
159
208
  ## 三类队友诉请分类
@@ -533,7 +533,7 @@ Best practices:
533
533
 
534
534
  - Make `member_defaults` conservative. Grant additional tools/dirs on a per-member basis.
535
535
  - Prefer toolsets over individually enumerating tools unless you need a one-off tool.
536
- - Platform note: Windows runtime intentionally does not register `codex_style_tools`; do not grant that toolset in `.minds/team.yaml` on Windows hosts.
536
+ - Platform note: Windows runtime intentionally does not register `codex_inspect_and_patch_tools`; do not grant that toolset in `.minds/team.yaml` on Windows hosts.
537
537
  - Keep `.minds/team.yaml` ownership tight; only the team manager should be able to edit it.
538
538
  - Avoid repeating built-in constraints in `team.yaml`:
539
539
  - `*.tsk/**` (encapsulated Taskdocs) are hard-denied for all general file tools.
@@ -452,7 +452,7 @@ members:
452
452
 
453
453
  - 使 `member_defaults` 保守。按成员授予额外的工具/目录
454
454
  - 优先使用工具集而不是单独枚举工具,除非你需要一次性工具
455
- - 平台说明:Windows 运行时不会注册 `codex_style_tools`;在 Windows 主机上的 `.minds/team.yaml` 中不要授予该工具集
455
+ - 平台说明:Windows 运行时不会注册 `codex_inspect_and_patch_tools`;在 Windows 主机上的 `.minds/team.yaml` 中不要授予该工具集
456
456
  - 保持 `.minds/team.yaml` 的所有权严格;只有团队管理者应该能够编辑它
457
457
  - 避免在 `team.yaml` 中重复内置约束:
458
458
  - `*.tsk/**`(封装的差遣牒任务包)对所有通用文件工具被硬性拒绝
@@ -11,15 +11,7 @@ import type { FuncTool } from '../../tool';
11
11
  import type { ChatMessage, ProviderConfig } from '../client';
12
12
  import type { LlmBatchResult, LlmFailureDisposition, LlmGenerator, LlmRequestContext, LlmStreamReceiver, LlmStreamResult } from '../gen';
13
13
  export declare function resolveCodexServiceTier(serviceTier: ChatGptResponsesRequest['service_tier'] | undefined): Exclude<NonNullable<ChatGptResponsesRequest['service_tier']>, 'default'> | undefined;
14
- export declare function spliceCodexBuiltinPrompt(params: {
15
- template: string;
16
- defaultModel: string;
17
- loadPrompt: (model: string) => string | null;
18
- }): string;
19
- export declare function resolveCodexInstructions(systemPrompt: string, options?: {
20
- defaultModel?: string;
21
- loadPrompt?: (model: string) => string | null;
22
- }): string;
14
+ export declare function resolveCodexInstructions(systemPrompt: string): string;
23
15
  export declare class CodexGen implements LlmGenerator {
24
16
  get apiType(): string;
25
17
  classifyFailure(error: unknown): LlmFailureDisposition | undefined;
@@ -35,7 +35,6 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.CodexGen = void 0;
37
37
  exports.resolveCodexServiceTier = resolveCodexServiceTier;
38
- exports.spliceCodexBuiltinPrompt = spliceCodexBuiltinPrompt;
39
38
  exports.resolveCodexInstructions = resolveCodexInstructions;
40
39
  const log_1 = require("../../log");
41
40
  const i18n_text_1 = require("../../runtime/i18n-text");
@@ -47,7 +46,6 @@ const tool_output_limit_1 = require("./tool-output-limit");
47
46
  const tool_result_image_ingest_1 = require("./tool-result-image-ingest");
48
47
  const log = (0, log_1.createLogger)('llm/codex');
49
48
  const codexFallbackInstructions = 'You are Codex CLI.';
50
- const CODEX_SYSTEM_PROMPT_DIRECTIVE_PATTERN = /^([ \t]*)@codex-system-prompt(?::([A-Za-z0-9._-]+))?([ \t]*)$/gm;
51
49
  function resolveCodexServiceTier(serviceTier) {
52
50
  // The ChatGPT codex backend rejects the literal `default` tier even though some SDK typings
53
51
  // still list it. Omitting the field preserves the standard tier semantics without a 400.
@@ -116,29 +114,8 @@ function tryExtractApiReturnedModel(value) {
116
114
  const trimmed = model.trim();
117
115
  return trimmed.length > 0 ? trimmed : undefined;
118
116
  }
119
- function spliceCodexBuiltinPrompt(params) {
120
- let replaced = false;
121
- const resolved = params.template.replace(CODEX_SYSTEM_PROMPT_DIRECTIVE_PATTERN, (_match, leading, overrideModel, trailing) => {
122
- const selectedModel = overrideModel ?? params.defaultModel;
123
- const prompt = params.loadPrompt(selectedModel);
124
- if (prompt === null) {
125
- throw new Error(`Bundled Codex prompt template not found for model: ${selectedModel}`);
126
- }
127
- replaced = true;
128
- return `${leading}${prompt}${trailing}`;
129
- });
130
- return replaced ? resolved : params.template;
131
- }
132
- function resolveCodexInstructions(systemPrompt, options) {
133
- const baseInstructions = systemPrompt.trim().length > 0 ? systemPrompt : codexFallbackInstructions;
134
- if (options?.defaultModel === undefined || options.loadPrompt === undefined) {
135
- return baseInstructions;
136
- }
137
- return spliceCodexBuiltinPrompt({
138
- template: baseInstructions,
139
- defaultModel: options.defaultModel,
140
- loadPrompt: options.loadPrompt,
141
- });
117
+ function resolveCodexInstructions(systemPrompt) {
118
+ return systemPrompt.trim().length > 0 ? systemPrompt : codexFallbackInstructions;
142
119
  }
143
120
  function funcToolToCodex(funcTool) {
144
121
  // MCP schemas are passed through to providers. Codex tool schema types are narrower; runtime
@@ -534,10 +511,7 @@ class CodexGen {
534
511
  if (!agent.model) {
535
512
  throw new Error(`Internal error: Model is undefined for agent '${agent.id}'`);
536
513
  }
537
- const instructions = resolveCodexInstructions(systemPrompt, {
538
- defaultModel: agent.model,
539
- loadPrompt: codexAuth.loadCodexPromptSync,
540
- });
514
+ const instructions = resolveCodexInstructions(systemPrompt);
541
515
  const payload = await buildCodexRequest(providerConfig, agent, instructions, funcTools, requestContext, context, receiver.toolResultImageIngest);
542
516
  let sayingStarted = false;
543
517
  let thinkingStarted = false;
@@ -807,7 +807,6 @@ async function emitAssistantSaying(dlg, content) {
807
807
  await dlg.sayingChunk(content);
808
808
  await dlg.sayingFinish();
809
809
  }
810
- const KERNEL_DRIVER_IDENTICAL_UPDATE_PLAN_ONLY_STOP_THRESHOLD = 3;
811
810
  function resolveFuncToolFollowupMode(tool) {
812
811
  return tool?.followupMode ?? 'immediate';
813
812
  }
@@ -820,20 +819,6 @@ function shouldImmediatelyFollowUpToolOutcome(tool, outcome) {
820
819
  }
821
820
  return shouldImmediatelyFollowUpSuccessfulToolResult(tool);
822
821
  }
823
- function formatIdenticalUpdatePlanLoopStopDetail(language) {
824
- return language === 'zh'
825
- ? `检测到连续 ${String(KERNEL_DRIVER_IDENTICAL_UPDATE_PLAN_ONLY_STOP_THRESHOLD)} 次完全相同的 update_plan 自动续跑,已停止本次自动执行以避免自激发循环。你可以点击“继续”人工观察,或先修改计划内容再继续。`
826
- : `Detected ${String(KERNEL_DRIVER_IDENTICAL_UPDATE_PLAN_ONLY_STOP_THRESHOLD)} consecutive identical update_plan auto-follow-up rounds. Stopped this automatic run to avoid a self-trigger loop. You can click Continue to inspect manually, or change the plan content before resuming.`;
827
- }
828
- function extractAssistantSayingRoundSignature(newMsgs) {
829
- const contents = newMsgs
830
- .filter((msg) => msg.type === 'saying_msg' && msg.role === 'assistant')
831
- .map((msg) => msg.content);
832
- if (contents.length === 0) {
833
- return undefined;
834
- }
835
- return JSON.stringify(contents);
836
- }
837
822
  async function executeFunctionCalls(args) {
838
823
  const functionPromises = args.funcCalls.map(async (func) => {
839
824
  throwIfAborted(args.abortSignal, args.dlg);
@@ -933,7 +918,6 @@ async function executeFunctionRound(args) {
933
918
  shouldStopAfterReplyTool: false,
934
919
  pairedMessages: [],
935
920
  tellaskToolOutputs: [],
936
- updatePlanOnlyRound: false,
937
921
  };
938
922
  }
939
923
  throwIfAborted(args.abortSignal, args.dlg);
@@ -977,24 +961,6 @@ async function executeFunctionRound(args) {
977
961
  }
978
962
  return shouldImmediatelyFollowUpToolOutcome(tool, outcome);
979
963
  });
980
- const updatePlanOnlyRound = (() => {
981
- if (tellaskRound.normalCalls.length === 0) {
982
- return false;
983
- }
984
- if (tellaskRound.handledCallIds.length > 0 || tellaskRound.toolOutputs.length > 0) {
985
- return false;
986
- }
987
- for (const call of tellaskRound.normalCalls) {
988
- if (call.name !== 'update_plan') {
989
- return false;
990
- }
991
- const outcome = genericOutcomeByCallId.get(call.id);
992
- if (outcome !== 'success') {
993
- return false;
994
- }
995
- }
996
- return true;
997
- })();
998
964
  const resultByCallId = new Map();
999
965
  const register = (result) => {
1000
966
  const existing = resultByCallId.get(result.id);
@@ -1043,7 +1009,6 @@ async function executeFunctionRound(args) {
1043
1009
  shouldStopAfterReplyTool: tellaskRound.shouldStopAfterReplyTool,
1044
1010
  pairedMessages,
1045
1011
  tellaskToolOutputs: [...tellaskRound.toolOutputs],
1046
- updatePlanOnlyRound,
1047
1012
  };
1048
1013
  }
1049
1014
  async function resetDiligenceBudgetAfterQ4H(dlg, team) {
@@ -1202,8 +1167,6 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
1202
1167
  let retryStoppedRecoveryPrompt;
1203
1168
  let skipTaskdocForThisDrive = humanPrompt?.skipTaskdoc === true;
1204
1169
  let genIterNo = 0;
1205
- let consecutiveIdenticalUpdatePlanOnlyRounds = 0;
1206
- let lastIdenticalUpdatePlanRoundSignature;
1207
1170
  // Quirk retry state intentionally spans multiple request invocations in the same driver run,
1208
1171
  // including course changes. Provider/API retry heuristics are tracked independently from
1209
1172
  // user-facing course boundaries.
@@ -1417,16 +1380,28 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
1417
1380
  if (currentPrompt.origin === 'user' &&
1418
1381
  replyGuidance.suppressInterDialogReplyGuidance &&
1419
1382
  replyGuidance.deferredReplyReassertionDirective !== undefined) {
1383
+ // WARNING:
1384
+ // User interjection suppression is a reversible state transition, not a one-shot
1385
+ // latch. The normal cycle is:
1386
+ // - user interjects -> suppress reply obligation
1387
+ // - operator clicks Continue -> restore reply obligation
1388
+ // - user interjects again -> suppress it again
1389
+ //
1390
+ // Therefore a repeated interjection after a blocked Continue MUST re-arm the deferred
1391
+ // state and re-materialize the suppression guide, even when the underlying reply
1392
+ // directive itself did not change.
1420
1393
  const existingDeferredReplyReassertion = await persistence_1.DialogPersistence.getDeferredReplyReassertion(dlg.id, dlg.status);
1421
1394
  const nextDeferredReplyReassertion = {
1422
- reason: 'user_interjection_while_pending_subdialog',
1395
+ reason: 'user_interjection_with_parked_original_task',
1423
1396
  directive: replyGuidance.deferredReplyReassertionDirective,
1424
1397
  };
1425
- if (existingDeferredReplyReassertion === undefined ||
1426
- !hasSameReplyDirective(existingDeferredReplyReassertion.directive, nextDeferredReplyReassertion.directive)) {
1398
+ const mustRearmDeferredReplyReassertion = existingDeferredReplyReassertion === undefined ||
1399
+ existingDeferredReplyReassertion.resumeGuideSurfaced === true ||
1400
+ !hasSameReplyDirective(existingDeferredReplyReassertion.directive, nextDeferredReplyReassertion.directive);
1401
+ if (mustRearmDeferredReplyReassertion) {
1427
1402
  await persistence_1.DialogPersistence.setDeferredReplyReassertion(dlg.id, nextDeferredReplyReassertion, dlg.status);
1428
1403
  }
1429
- if (existingDeferredReplyReassertion === undefined) {
1404
+ if (mustRearmDeferredReplyReassertion) {
1430
1405
  currentRuntimeGuideMsg = replyGuidance.transientGuideContent
1431
1406
  ? {
1432
1407
  type: 'transient_guide_msg',
@@ -1466,6 +1441,9 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
1466
1441
  currentRuntimeGuideMsg = undefined;
1467
1442
  }
1468
1443
  if (isQ4HAnswerPrompt) {
1444
+ if (!replyGuidance.isQ4HAnswerPrompt) {
1445
+ throw new Error(`kernel-driver q4h answer classification invariant violation: msgId=${currentPrompt.msgId} was parsed as q4h answer before reply-guidance but not after`);
1446
+ }
1469
1447
  // Record only the answered call correlation / user language for the resumed round.
1470
1448
  // The actual human answer fact was already persisted via askHuman tellask result flow.
1471
1449
  await dlg.receiveHumanReply({
@@ -1474,6 +1452,9 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
1474
1452
  q4hAnswerCallId,
1475
1453
  });
1476
1454
  }
1455
+ else if (replyGuidance.isQ4HAnswerPrompt) {
1456
+ throw new Error(`kernel-driver q4h answer classification invariant violation: msgId=${currentPrompt.msgId} was classified as q4h answer by reply-guidance without a normalized q4hAnswerCallId`);
1457
+ }
1477
1458
  else {
1478
1459
  await dlg.addChatMessages({
1479
1460
  type: 'prompting_msg',
@@ -1992,25 +1973,6 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
1992
1973
  newMsgs.push(...routed.pairedMessages);
1993
1974
  }
1994
1975
  await dlg.addChatMessages(...newMsgs);
1995
- const assistantSayingRoundSignature = extractAssistantSayingRoundSignature(newMsgs);
1996
- const identicalUpdatePlanRoundSignature = routed.updatePlanOnlyRound
1997
- ? JSON.stringify({
1998
- assistantSayingRoundSignature: assistantSayingRoundSignature ?? '',
1999
- })
2000
- : undefined;
2001
- if (identicalUpdatePlanRoundSignature !== undefined) {
2002
- if (identicalUpdatePlanRoundSignature === lastIdenticalUpdatePlanRoundSignature) {
2003
- consecutiveIdenticalUpdatePlanOnlyRounds += 1;
2004
- }
2005
- else {
2006
- consecutiveIdenticalUpdatePlanOnlyRounds = 1;
2007
- lastIdenticalUpdatePlanRoundSignature = identicalUpdatePlanRoundSignature;
2008
- }
2009
- }
2010
- else {
2011
- consecutiveIdenticalUpdatePlanOnlyRounds = 0;
2012
- lastIdenticalUpdatePlanRoundSignature = undefined;
2013
- }
2014
1976
  const persistedFbrState = await loadDialogFbrState(dlg);
2015
1977
  if (persistedFbrState) {
2016
1978
  if (persistedFbrState.phase === 'finalization') {
@@ -2096,27 +2058,6 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
2096
2058
  await resetDiligenceBudgetAfterQ4H(dlg, team);
2097
2059
  break;
2098
2060
  }
2099
- if (consecutiveIdenticalUpdatePlanOnlyRounds >=
2100
- KERNEL_DRIVER_IDENTICAL_UPDATE_PLAN_ONLY_STOP_THRESHOLD) {
2101
- const detail = formatIdenticalUpdatePlanLoopStopDetail((0, work_language_1.getWorkLanguage)());
2102
- log_1.log.error(detail, new Error('kernel_driver_identical_update_plan_loop_stopped'), {
2103
- dialogId: dlg.id.valueOf(),
2104
- rootId: dlg.id.rootId,
2105
- selfId: dlg.id.selfId,
2106
- course: dlg.currentCourse,
2107
- genseq: dlg.activeGenSeqOrUndefined ?? null,
2108
- consecutiveIdenticalUpdatePlanOnlyRounds,
2109
- identicalUpdatePlanRoundSignature,
2110
- });
2111
- throw new KernelDriverInterruptedError({
2112
- kind: 'system_stop',
2113
- detail,
2114
- i18nStopReason: (0, stop_reason_i18n_1.buildHumanSystemStopReasonTextI18n)({
2115
- detail,
2116
- kind: 'identical_update_plan_loop',
2117
- }),
2118
- });
2119
- }
2120
2061
  // Start an immediate post-tool generation only when this round produced tool outputs that
2121
2062
  // warrant same-drive LLM reaction right away. Provider-native side-channel UI events are
2122
2063
  // meaningful output, but they are not transcript/context inputs and therefore must not