dominds 1.16.8 → 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.
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/docs/app-constitution.md +2 -2
- package/dist/docs/app-constitution.zh.md +2 -2
- package/dist/docs/dialog-system.md +4 -0
- package/dist/docs/dialog-system.zh.md +4 -0
- package/dist/docs/team_mgmt-toolset.md +1 -1
- package/dist/docs/team_mgmt-toolset.zh.md +1 -1
- package/dist/llm/gen/codex.d.ts +1 -9
- package/dist/llm/gen/codex.js +3 -29
- package/dist/llm/kernel-driver/drive.js +22 -81
- package/dist/llm/kernel-driver/flow.js +61 -0
- package/dist/llm/kernel-driver/reply-guidance.d.ts +1 -0
- package/dist/llm/kernel-driver/reply-guidance.js +15 -5
- package/dist/llm/stop-reason-i18n.d.ts +1 -1
- package/dist/llm/stop-reason-i18n.js +0 -4
- package/dist/persistence.js +13 -3
- package/dist/runtime/interjection-pause-stop.js +4 -0
- package/dist/runtime/reply-prompt-copy.js +2 -2
- package/dist/tools/apply-patch.js +5 -5
- package/dist/tools/builtins.js +11 -12
- package/dist/tools/prompts/codex_inspect_and_patch_tools/en/errors.md +45 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/en/index.md +37 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/en/principles.md +41 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/en/scenarios.md +40 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/en/tools.md +47 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/errors.md +45 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/index.md +37 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/principles.md +41 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/scenarios.md +40 -0
- package/dist/tools/prompts/codex_inspect_and_patch_tools/zh/tools.md +47 -0
- package/dist/tools/team_mgmt.js +13 -21
- package/package.json +4 -4
- package/webapp/dist/assets/{_basePickBy-B7FV6Gnn.js → _basePickBy-BKgfg72Q.js} +3 -3
- package/webapp/dist/assets/{_basePickBy-B7FV6Gnn.js.map → _basePickBy-BKgfg72Q.js.map} +1 -1
- package/webapp/dist/assets/{_baseUniq-CmVnLJpw.js → _baseUniq-DKhs7H5s.js} +2 -2
- package/webapp/dist/assets/{_baseUniq-CmVnLJpw.js.map → _baseUniq-DKhs7H5s.js.map} +1 -1
- package/webapp/dist/assets/{arc-DSJlh9AU.js → arc-Tykg3Fx4.js} +2 -2
- package/webapp/dist/assets/{arc-DSJlh9AU.js.map → arc-Tykg3Fx4.js.map} +1 -1
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-Cd2cTHzo.js → architectureDiagram-2XIMDMQ5-BAyn6_in.js} +7 -7
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-Cd2cTHzo.js.map → architectureDiagram-2XIMDMQ5-BAyn6_in.js.map} +1 -1
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-C0uEp_Tz.js → blockDiagram-WCTKOSBZ-CGbo6x6_.js} +7 -7
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-C0uEp_Tz.js.map → blockDiagram-WCTKOSBZ-CGbo6x6_.js.map} +1 -1
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-B37U92JK.js → c4Diagram-IC4MRINW-CUizxwo0.js} +3 -3
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-B37U92JK.js.map → c4Diagram-IC4MRINW-CUizxwo0.js.map} +1 -1
- package/webapp/dist/assets/{channel-DLHnjnQf.js → channel-DvP7WrjO.js} +2 -2
- package/webapp/dist/assets/{channel-DLHnjnQf.js.map → channel-DvP7WrjO.js.map} +1 -1
- package/webapp/dist/assets/{chunk-4BX2VUAB-DnZvfQyp.js → chunk-4BX2VUAB-cgnNaqgV.js} +2 -2
- package/webapp/dist/assets/{chunk-4BX2VUAB-DnZvfQyp.js.map → chunk-4BX2VUAB-cgnNaqgV.js.map} +1 -1
- package/webapp/dist/assets/{chunk-55IACEB6-BG-cjz3M.js → chunk-55IACEB6-BEUsguTg.js} +2 -2
- package/webapp/dist/assets/{chunk-55IACEB6-BG-cjz3M.js.map → chunk-55IACEB6-BEUsguTg.js.map} +1 -1
- package/webapp/dist/assets/{chunk-FMBD7UC4-B1L8cPfl.js → chunk-FMBD7UC4-B2p0efxm.js} +2 -2
- package/webapp/dist/assets/{chunk-FMBD7UC4-B1L8cPfl.js.map → chunk-FMBD7UC4-B2p0efxm.js.map} +1 -1
- package/webapp/dist/assets/{chunk-JSJVCQXG-C65w23ZF.js → chunk-JSJVCQXG-Bd09WM0B.js} +2 -2
- package/webapp/dist/assets/{chunk-JSJVCQXG-C65w23ZF.js.map → chunk-JSJVCQXG-Bd09WM0B.js.map} +1 -1
- package/webapp/dist/assets/{chunk-KX2RTZJC-_4YSMrEL.js → chunk-KX2RTZJC-DaLNbvSI.js} +2 -2
- package/webapp/dist/assets/{chunk-KX2RTZJC-_4YSMrEL.js.map → chunk-KX2RTZJC-DaLNbvSI.js.map} +1 -1
- package/webapp/dist/assets/{chunk-NQ4KR5QH-ComURSQb.js → chunk-NQ4KR5QH-6dsWbn61.js} +4 -4
- package/webapp/dist/assets/{chunk-NQ4KR5QH-ComURSQb.js.map → chunk-NQ4KR5QH-6dsWbn61.js.map} +1 -1
- package/webapp/dist/assets/{chunk-QZHKN3VN-BrxvuRI6.js → chunk-QZHKN3VN-C0e1qWr4.js} +2 -2
- package/webapp/dist/assets/{chunk-QZHKN3VN-BrxvuRI6.js.map → chunk-QZHKN3VN-C0e1qWr4.js.map} +1 -1
- package/webapp/dist/assets/{chunk-WL4C6EOR-CW7tAF_z.js → chunk-WL4C6EOR-ChheG0OU.js} +6 -6
- package/webapp/dist/assets/{chunk-WL4C6EOR-CW7tAF_z.js.map → chunk-WL4C6EOR-ChheG0OU.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-BWrPbwfd.js → classDiagram-VBA2DB6C-uUAnWHsS.js} +7 -7
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-BWrPbwfd.js.map → classDiagram-VBA2DB6C-uUAnWHsS.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BWrPbwfd.js → classDiagram-v2-RAHNMMFH-uUAnWHsS.js} +7 -7
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BWrPbwfd.js.map → classDiagram-v2-RAHNMMFH-uUAnWHsS.js.map} +1 -1
- package/webapp/dist/assets/{clone-B-TYPsxN.js → clone-BiXgC0aE.js} +2 -2
- package/webapp/dist/assets/{clone-B-TYPsxN.js.map → clone-BiXgC0aE.js.map} +1 -1
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-C1bfZcVY.js → cose-bilkent-S5V4N54A-C-h7F7gA.js} +2 -2
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-C1bfZcVY.js.map → cose-bilkent-S5V4N54A-C-h7F7gA.js.map} +1 -1
- package/webapp/dist/assets/{dagre-KLK3FWXG-BfD08d2e.js → dagre-KLK3FWXG-5B3k91Lo.js} +7 -7
- package/webapp/dist/assets/{dagre-KLK3FWXG-BfD08d2e.js.map → dagre-KLK3FWXG-5B3k91Lo.js.map} +1 -1
- package/webapp/dist/assets/{diagram-E7M64L7V-Dyd9OucT.js → diagram-E7M64L7V-CFtPXaNS.js} +8 -8
- package/webapp/dist/assets/{diagram-E7M64L7V-Dyd9OucT.js.map → diagram-E7M64L7V-CFtPXaNS.js.map} +1 -1
- package/webapp/dist/assets/{diagram-IFDJBPK2-BN-JCceb.js → diagram-IFDJBPK2-CUuPPDwe.js} +7 -7
- package/webapp/dist/assets/{diagram-IFDJBPK2-BN-JCceb.js.map → diagram-IFDJBPK2-CUuPPDwe.js.map} +1 -1
- package/webapp/dist/assets/{diagram-P4PSJMXO-C2jh_Kry.js → diagram-P4PSJMXO-D7oYhsVm.js} +7 -7
- package/webapp/dist/assets/{diagram-P4PSJMXO-C2jh_Kry.js.map → diagram-P4PSJMXO-D7oYhsVm.js.map} +1 -1
- package/webapp/dist/assets/{erDiagram-INFDFZHY-C3Pj10OJ.js → erDiagram-INFDFZHY-DUDHdT_e.js} +5 -5
- package/webapp/dist/assets/{erDiagram-INFDFZHY-C3Pj10OJ.js.map → erDiagram-INFDFZHY-DUDHdT_e.js.map} +1 -1
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-a5vzSSCo.js → flowDiagram-PKNHOUZH-CT7lC5J1.js} +7 -7
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-a5vzSSCo.js.map → flowDiagram-PKNHOUZH-CT7lC5J1.js.map} +1 -1
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-DIua0Qjr.js → ganttDiagram-A5KZAMGK-BhlcqqDR.js} +3 -3
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-DIua0Qjr.js.map → ganttDiagram-A5KZAMGK-BhlcqqDR.js.map} +1 -1
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CJt16FXK.js → gitGraphDiagram-K3NZZRJ6-CYLYfqiB.js} +8 -8
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CJt16FXK.js.map → gitGraphDiagram-K3NZZRJ6-CYLYfqiB.js.map} +1 -1
- package/webapp/dist/assets/{graph-lQSuHjYm.js → graph-twAxd7MO.js} +3 -3
- package/webapp/dist/assets/{graph-lQSuHjYm.js.map → graph-twAxd7MO.js.map} +1 -1
- package/webapp/dist/assets/{index-B7llu28V.js → index-Bc1jJvgU.js} +36 -175
- package/webapp/dist/assets/{index-B7llu28V.js.map → index-Bc1jJvgU.js.map} +1 -1
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-DzJuXz5H.js → infoDiagram-LFFYTUFH-BAA1VoC0.js} +6 -6
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-DzJuXz5H.js.map → infoDiagram-LFFYTUFH-BAA1VoC0.js.map} +1 -1
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-BP_s17vw.js → ishikawaDiagram-PHBUUO56-CyPvSx5W.js} +2 -2
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-BP_s17vw.js.map → ishikawaDiagram-PHBUUO56-CyPvSx5W.js.map} +1 -1
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-Lic1mhBM.js → journeyDiagram-4ABVD52K-CbOLT63I.js} +5 -5
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-Lic1mhBM.js.map → journeyDiagram-4ABVD52K-CbOLT63I.js.map} +1 -1
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-Baf2kCwQ.js → kanban-definition-K7BYSVSG-CUS-wMLR.js} +3 -3
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-Baf2kCwQ.js.map → kanban-definition-K7BYSVSG-CUS-wMLR.js.map} +1 -1
- package/webapp/dist/assets/{layout-DUMDc8rv.js → layout-C0HW4ZHi.js} +5 -5
- package/webapp/dist/assets/{layout-DUMDc8rv.js.map → layout-C0HW4ZHi.js.map} +1 -1
- package/webapp/dist/assets/{linear-CZMoHeVH.js → linear-DNEgfkh6.js} +2 -2
- package/webapp/dist/assets/{linear-CZMoHeVH.js.map → linear-DNEgfkh6.js.map} +1 -1
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DB2sQ--_.js → mindmap-definition-YRQLILUH-D5URwhNx.js} +4 -4
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DB2sQ--_.js.map → mindmap-definition-YRQLILUH-D5URwhNx.js.map} +1 -1
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Dgdrlric.js → pieDiagram-SKSYHLDU-BQbBOUPk.js} +8 -8
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Dgdrlric.js.map → pieDiagram-SKSYHLDU-BQbBOUPk.js.map} +1 -1
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-CJcFYfqf.js → quadrantDiagram-337W2JSQ-B_dFbPid.js} +3 -3
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-CJcFYfqf.js.map → quadrantDiagram-337W2JSQ-B_dFbPid.js.map} +1 -1
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-CDsT-ac7.js → requirementDiagram-Z7DCOOCP-CtWDUSB3.js} +4 -4
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-CDsT-ac7.js.map → requirementDiagram-Z7DCOOCP-CtWDUSB3.js.map} +1 -1
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-DiO55skm.js → sankeyDiagram-WA2Y5GQK-CqRH7yj4.js} +2 -2
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-DiO55skm.js.map → sankeyDiagram-WA2Y5GQK-CqRH7yj4.js.map} +1 -1
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-CNHjdBNC.js → sequenceDiagram-2WXFIKYE-B1-5-5Qx.js} +4 -4
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-CNHjdBNC.js.map → sequenceDiagram-2WXFIKYE-B1-5-5Qx.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-CtS3TXEd.js → stateDiagram-RAJIS63D-9krZSpaD.js} +9 -9
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-CtS3TXEd.js.map → stateDiagram-RAJIS63D-9krZSpaD.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-BdjJA1de.js → stateDiagram-v2-FVOUBMTO-DDLC-q0s.js} +5 -5
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-BdjJA1de.js.map → stateDiagram-v2-FVOUBMTO-DDLC-q0s.js.map} +1 -1
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-D3AiTIhK.js → timeline-definition-YZTLITO2-C64HbHNO.js} +3 -3
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-D3AiTIhK.js.map → timeline-definition-YZTLITO2-C64HbHNO.js.map} +1 -1
- package/webapp/dist/assets/{treemap-KZPCXAKY-F6nRvLGK.js → treemap-KZPCXAKY-TEywEA7B.js} +5 -5
- package/webapp/dist/assets/{treemap-KZPCXAKY-F6nRvLGK.js.map → treemap-KZPCXAKY-TEywEA7B.js.map} +1 -1
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BoukZEuo.js → vennDiagram-LZ73GAT5-CT9sZ6ft.js} +2 -2
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BoukZEuo.js.map → vennDiagram-LZ73GAT5-CT9sZ6ft.js.map} +1 -1
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ByfGkhZz.js → xychartDiagram-JWTSCODW-CEAg_tiv.js} +3 -3
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ByfGkhZz.js.map → xychartDiagram-JWTSCODW-CEAg_tiv.js.map} +1 -1
- package/webapp/dist/index.html +1 -1
- package/dist/tools/plan.d.ts +0 -2
- package/dist/tools/plan.js +0 -171
- package/dist/tools/prompts/codex_style_tools/en/errors.md +0 -102
- package/dist/tools/prompts/codex_style_tools/en/index.md +0 -59
- package/dist/tools/prompts/codex_style_tools/en/principles.md +0 -87
- package/dist/tools/prompts/codex_style_tools/en/scenarios.md +0 -88
- package/dist/tools/prompts/codex_style_tools/en/tools.md +0 -119
- package/dist/tools/prompts/codex_style_tools/zh/errors.md +0 -102
- package/dist/tools/prompts/codex_style_tools/zh/index.md +0 -59
- package/dist/tools/prompts/codex_style_tools/zh/principles.md +0 -87
- package/dist/tools/prompts/codex_style_tools/zh/scenarios.md +0 -88
- 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 `
|
|
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 运行时不会注册 `
|
|
145
|
+
- Windows 运行时不会注册 `codex_inspect_and_patch_tools` 工具集。在 Windows 主机上的 `.minds/team.yaml` 中不要授予 `codex_inspect_and_patch_tools`。
|
|
146
146
|
|
|
147
147
|
## 从零开始(空文件夹启动)
|
|
148
148
|
|
|
@@ -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 `
|
|
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
|
-
-
|
|
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
|
-
- 默认工具集:代码修改/检索工具(如 `
|
|
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
|
-
-
|
|
465
|
+
- codex_inspect_and_patch_tools
|
|
466
466
|
```
|
|
467
467
|
|
|
468
468
|
关于 `playwright_interactive` 工具集的设计要求:
|
|
@@ -168,6 +168,8 @@ When a dialog still carries an inter-dialog reply obligation, but the user tempo
|
|
|
168
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
169
|
6. Only an explicit UI `Continue` attempts to restore the original task.
|
|
170
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
|
+
|
|
171
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.
|
|
172
174
|
|
|
173
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`:
|
|
@@ -183,6 +185,7 @@ After the user clicks `Continue`, the backend MUST re-evaluate fresh persistence
|
|
|
183
185
|
|
|
184
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.
|
|
185
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.
|
|
186
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".
|
|
187
190
|
|
|
188
191
|
**Mental-model warning**:
|
|
@@ -190,6 +193,7 @@ After the user clicks `Continue`, the backend MUST re-evaluate fresh persistence
|
|
|
190
193
|
- Do not reason about this flow from `displayState.kind === 'stopped'` alone.
|
|
191
194
|
- Do not reason about it from blocker facts alone and then wonder why the UI still shows `stopped`.
|
|
192
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.
|
|
193
197
|
|
|
194
198
|
You need all of the following together to understand the behavior correctly:
|
|
195
199
|
|
|
@@ -167,6 +167,8 @@
|
|
|
167
167
|
5. 只要用户继续发送新消息,就继续作为插话临时对话处理;这个 paused projection 仅在它已被建立时持续保持。
|
|
168
168
|
6. 只有用户显式点击 UI `Continue`,系统才尝试恢复原任务。
|
|
169
169
|
|
|
170
|
+
**严格边界**:`askHuman` 的正式回答不属于这里的“用户插话”。只要一条 prompt 带着真实的 `q4hAnswerCallId`,它就属于 askHuman 回复通道,语义上是在继续已 materialize 的提问/应答链路,绝不能被压入“本地临时插话聊天”。
|
|
171
|
+
|
|
170
172
|
**关键点**:这里的 `stopped` 只是一个临时 run-control / UI 投影,不等于普通 system-stop 失败,也不是最终的业务真源;并且它不是所有插话都会出现,只在“确有一个待恢复的原任务被临时停靠”时出现。
|
|
171
173
|
|
|
172
174
|
点击 `Continue` 后,后端必须重新从 persistence 真源判定当前对话属于哪一种情况,而不能只根据表面的 `displayState` 做静态推断:
|
|
@@ -182,6 +184,7 @@
|
|
|
182
184
|
|
|
183
185
|
- `refreshRunControlProjectionFromPersistenceFacts()` 在用户尚未点击 `Continue` 前,必须保留这层“插话已处理;原任务已暂停”的 `stopped` 投影;否则 UI 会过早塌回普通 `blocked`,破坏多轮插话体验。反过来,如果当前其实没有待恢复原任务,则根本不应建立这层 paused projection。
|
|
184
186
|
- 真正决定 `Continue` 结果的逻辑,必须在恢复驱动路径中重新读取 fresh persistence facts;不能把“可点 Continue”误解为“必然立即 proceeding”。
|
|
187
|
+
- 若 `Continue` 后真源仍是 `blocked`,回复责任重申文案应当立即作为 runtime guide 同时进入 `dlg.msgs` 与持久化课程历史,并同步发前端气泡;这样后面真正恢复 drive 时只需正常读取上下文,不应再额外补发一条重复的 runtime prompt。
|
|
185
188
|
- run-control 工具栏中的 `resumable` 计数,应与“是否允许手动 Continue 尝试”保持一致。因此,处于 interjection-paused `stopped` 的对话即便底层仍有 blocker,也应计入 `resumable`;因为 `Continue` 的业务语义正是“退出这层临时 paused projection,并从真源重判下一步”。
|
|
186
189
|
|
|
187
190
|
**心智模型提醒**:
|
|
@@ -189,6 +192,7 @@
|
|
|
189
192
|
- 不能只看 `displayState.kind === 'stopped'` 就理解这条链路。
|
|
190
193
|
- 不能只看 blocker facts 就理解为什么 UI 仍显示 `stopped`。
|
|
191
194
|
- 也不能只看 `resume_dialog` eligibility 就推断恢复后一定马上运行。
|
|
195
|
+
- 更不能把所有 `origin === 'user'` 的输入都笼统视作“用户插话”;`q4hAnswerCallId` 非空的 prompt 是 askHuman answer continuation,必须按另一条语义链处理。
|
|
192
196
|
|
|
193
197
|
必须把以下几块一起看,才能形成完整且精确的理解:
|
|
194
198
|
|
|
@@ -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 `
|
|
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 运行时不会注册 `
|
|
455
|
+
- 平台说明:Windows 运行时不会注册 `codex_inspect_and_patch_tools`;在 Windows 主机上的 `.minds/team.yaml` 中不要授予该工具集
|
|
456
456
|
- 保持 `.minds/team.yaml` 的所有权严格;只有团队管理者应该能够编辑它
|
|
457
457
|
- 避免在 `team.yaml` 中重复内置约束:
|
|
458
458
|
- `*.tsk/**`(封装的差遣牒任务包)对所有通用文件工具被硬性拒绝
|
package/dist/llm/gen/codex.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/llm/gen/codex.js
CHANGED
|
@@ -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
|
|
120
|
-
|
|
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: '
|
|
1395
|
+
reason: 'user_interjection_with_parked_original_task',
|
|
1423
1396
|
directive: replyGuidance.deferredReplyReassertionDirective,
|
|
1424
1397
|
};
|
|
1425
|
-
|
|
1426
|
-
|
|
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 (
|
|
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
|
|
@@ -6,6 +6,7 @@ const run_control_1 = require("../../apps/run-control");
|
|
|
6
6
|
const dialog_1 = require("../../dialog");
|
|
7
7
|
const dialog_display_state_1 = require("../../dialog-display-state");
|
|
8
8
|
const dialog_global_registry_1 = require("../../dialog-global-registry");
|
|
9
|
+
const evt_registry_1 = require("../../evt-registry");
|
|
9
10
|
const log_1 = require("../../log");
|
|
10
11
|
const load_1 = require("../../minds/load");
|
|
11
12
|
const persistence_1 = require("../../persistence");
|
|
@@ -271,6 +272,15 @@ async function maybeResolveDeferredReplyReassertionPrompt(dialog) {
|
|
|
271
272
|
await persistence_1.DialogPersistence.setDeferredReplyReassertion(dialog.id, undefined, dialog.status);
|
|
272
273
|
return undefined;
|
|
273
274
|
}
|
|
275
|
+
// WARNING:
|
|
276
|
+
// `resumeGuideSurfaced` means the reply-obligation reassertion has already been materialized as a
|
|
277
|
+
// runtime guide and injected into both dialog.msgs and persisted course history at blocked
|
|
278
|
+
// Continue time. Once that has happened, later real resume must not emit a second visible prompt:
|
|
279
|
+
// normal context replay is now the source of truth for the model-facing reminder.
|
|
280
|
+
if (deferredReplyReassertion.resumeGuideSurfaced === true) {
|
|
281
|
+
await persistence_1.DialogPersistence.setDeferredReplyReassertion(dialog.id, undefined, dialog.status);
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
274
284
|
await persistence_1.DialogPersistence.setDeferredReplyReassertion(dialog.id, undefined, dialog.status);
|
|
275
285
|
const language = (0, work_language_1.getWorkLanguage)();
|
|
276
286
|
return {
|
|
@@ -286,6 +296,51 @@ async function maybeResolveDeferredReplyReassertionPrompt(dialog) {
|
|
|
286
296
|
tellaskReplyDirective: deferredReplyReassertion.directive,
|
|
287
297
|
};
|
|
288
298
|
}
|
|
299
|
+
async function maybeSurfaceDeferredReplyReassertionGuideForBlockedContinue(dialog) {
|
|
300
|
+
const deferredReplyReassertion = await persistence_1.DialogPersistence.getDeferredReplyReassertion(dialog.id, dialog.status);
|
|
301
|
+
if (!deferredReplyReassertion || deferredReplyReassertion.resumeGuideSurfaced === true) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const activeDirective = await (0, tellask_special_1.loadLatestActiveTellaskReplyDirective)(dialog);
|
|
305
|
+
if (!activeDirective ||
|
|
306
|
+
activeDirective.targetCallId !== deferredReplyReassertion.directive.targetCallId) {
|
|
307
|
+
await persistence_1.DialogPersistence.setDeferredReplyReassertion(dialog.id, undefined, dialog.status);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const language = (0, work_language_1.getWorkLanguage)();
|
|
311
|
+
const content = await (0, reply_guidance_1.buildReplyObligationReassertionPrompt)({
|
|
312
|
+
dlg: dialog,
|
|
313
|
+
directive: deferredReplyReassertion.directive,
|
|
314
|
+
language,
|
|
315
|
+
});
|
|
316
|
+
const genseq = dialog.activeGenSeqOrUndefined ?? 1;
|
|
317
|
+
// WARNING:
|
|
318
|
+
// This helper intentionally does three things at once:
|
|
319
|
+
// 1. append the guide into dialog.msgs so an in-memory later resume sees it naturally;
|
|
320
|
+
// 2. persist a runtime_guide_record so reload/replay reconstructs the same context;
|
|
321
|
+
// 3. emit runtime_guide_evt so the user immediately sees the reassertion bubble after Continue.
|
|
322
|
+
//
|
|
323
|
+
// Do not "optimize" this into only an event or only a deferred prompt. The whole point is that
|
|
324
|
+
// once blocked Continue is clicked, the guide becomes a first-class historical context fact and
|
|
325
|
+
// later real driving should need no special duplicate reassertion path.
|
|
326
|
+
await dialog.addChatMessages({
|
|
327
|
+
type: 'transient_guide_msg',
|
|
328
|
+
role: 'assistant',
|
|
329
|
+
content,
|
|
330
|
+
});
|
|
331
|
+
await persistence_1.DialogPersistence.persistRuntimeGuide(dialog, content, genseq);
|
|
332
|
+
(0, evt_registry_1.postDialogEvent)(dialog, {
|
|
333
|
+
type: 'runtime_guide_evt',
|
|
334
|
+
course: dialog.currentCourse,
|
|
335
|
+
genseq,
|
|
336
|
+
content,
|
|
337
|
+
});
|
|
338
|
+
await persistence_1.DialogPersistence.setDeferredReplyReassertion(dialog.id, {
|
|
339
|
+
reason: 'user_interjection_with_parked_original_task',
|
|
340
|
+
directive: deferredReplyReassertion.directive,
|
|
341
|
+
resumeGuideSurfaced: true,
|
|
342
|
+
}, dialog.status);
|
|
343
|
+
}
|
|
289
344
|
async function resolveEffectivePrompt(dialog, humanPrompt) {
|
|
290
345
|
if (humanPrompt) {
|
|
291
346
|
return { prompt: humanPrompt, fromUpNext: false };
|
|
@@ -439,6 +494,7 @@ async function executeDriveRound(args) {
|
|
|
439
494
|
subdialogs: suspension.subdialogs,
|
|
440
495
|
});
|
|
441
496
|
await (0, dialog_display_state_1.setDialogDisplayState)(dialog.id, restoredState);
|
|
497
|
+
await maybeSurfaceDeferredReplyReassertionGuideForBlockedContinue(dialog);
|
|
442
498
|
log_1.log.debug('kernel-driver continue after interjection pause restored true suspended state from fresh persistence facts', undefined, {
|
|
443
499
|
dialogId: dialog.id.valueOf(),
|
|
444
500
|
restoredState,
|
|
@@ -582,8 +638,13 @@ async function executeDriveRound(args) {
|
|
|
582
638
|
// suppressed a still-pending inter-dialog reply obligation that must be reasserted later.
|
|
583
639
|
// User interjections without a parked original task should simply finish and fall back to the
|
|
584
640
|
// dialog's true underlying state, without showing the special stopped panel.
|
|
641
|
+
//
|
|
642
|
+
// Q4H answers are explicitly outside this branch even though they also come from the human.
|
|
643
|
+
// They belong to the askHuman reply channel and must continue the suspended askHuman round,
|
|
644
|
+
// never be mistaken for ad hoc interjection chat.
|
|
585
645
|
shouldPauseAfterLocalUserInterjection =
|
|
586
646
|
effectivePrompt?.origin === 'user' &&
|
|
647
|
+
!replyGuidance.isQ4HAnswerPrompt &&
|
|
587
648
|
replyGuidance.suppressInterDialogReplyGuidance &&
|
|
588
649
|
replyGuidance.deferredReplyReassertionDirective !== undefined;
|
|
589
650
|
activeTellaskReplyDirective = replyGuidance.activeReplyDirective;
|
|
@@ -12,6 +12,7 @@ export declare function resolvePromptReplyGuidance(args: {
|
|
|
12
12
|
}): Promise<{
|
|
13
13
|
activeReplyDirective: KernelDriverHumanPrompt['tellaskReplyDirective'];
|
|
14
14
|
deferredReplyReassertionDirective: KernelDriverHumanPrompt['tellaskReplyDirective'];
|
|
15
|
+
isQ4HAnswerPrompt: boolean;
|
|
15
16
|
promptContent: string | undefined;
|
|
16
17
|
persistedTellaskReplyDirective: KernelDriverHumanPrompt['tellaskReplyDirective'];
|
|
17
18
|
suppressInterDialogReplyGuidance: boolean;
|
|
@@ -92,6 +92,8 @@ async function shouldSuppressInterDialogReplyGuidanceForUserInterjection(args) {
|
|
|
92
92
|
// blocked or resume real driving.
|
|
93
93
|
//
|
|
94
94
|
// Do not "simplify" this into a pure display-state check or a pure pending-subdialog check.
|
|
95
|
+
// Proceeding dialogs with a still-active reply obligation are part of the same rule: a fresh
|
|
96
|
+
// user interjection should still suppress the live reply obligation and answer locally first.
|
|
95
97
|
// The business anchor is the deferred reply reassertion, while the paused execution marker keeps
|
|
96
98
|
// repeated interjection turns behaving as local side conversation until explicit Continue.
|
|
97
99
|
const prompt = args.prompt;
|
|
@@ -105,13 +107,17 @@ async function shouldSuppressInterDialogReplyGuidanceForUserInterjection(args) {
|
|
|
105
107
|
return false;
|
|
106
108
|
}
|
|
107
109
|
const latest = await persistence_1.DialogPersistence.loadDialogLatest(args.dlg.id, args.dlg.status);
|
|
108
|
-
if (latest?.deferredReplyReassertion?.reason === '
|
|
110
|
+
if (latest?.deferredReplyReassertion?.reason === 'user_interjection_with_parked_original_task') {
|
|
109
111
|
return true;
|
|
110
112
|
}
|
|
111
113
|
if (latest?.executionMarker?.kind === 'interrupted' &&
|
|
112
114
|
(0, interjection_pause_stop_1.isUserInterjectionPauseStopReason)(latest.executionMarker.reason)) {
|
|
113
115
|
return true;
|
|
114
116
|
}
|
|
117
|
+
const activeReplyDirective = await (0, tellask_special_1.loadLatestActiveTellaskReplyDirective)(args.dlg);
|
|
118
|
+
if (activeReplyDirective) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
115
121
|
// Use strict persistence reads here. This branch changes business behavior, so a read failure
|
|
116
122
|
// must loud-fail the round instead of being silently treated as "pending subdialogs exist".
|
|
117
123
|
const pendingSubdialogs = await persistence_1.DialogPersistence.loadPendingSubdialogs(args.dlg.id, args.dlg.status);
|
|
@@ -119,10 +125,13 @@ async function shouldSuppressInterDialogReplyGuidanceForUserInterjection(args) {
|
|
|
119
125
|
}
|
|
120
126
|
async function resolvePromptReplyGuidance(args) {
|
|
121
127
|
const prompt = args.prompt;
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
const isQ4HAnswerPrompt = typeof prompt?.q4hAnswerCallId === 'string' && prompt.q4hAnswerCallId.trim() !== '';
|
|
129
|
+
const suppressInterDialogReplyGuidance = isQ4HAnswerPrompt
|
|
130
|
+
? false
|
|
131
|
+
: await shouldSuppressInterDialogReplyGuidanceForUserInterjection({
|
|
132
|
+
dlg: args.dlg,
|
|
133
|
+
prompt,
|
|
134
|
+
});
|
|
126
135
|
const availableReplyDirective = prompt?.tellaskReplyDirective ?? (await (0, tellask_special_1.loadLatestActiveTellaskReplyDirective)(args.dlg));
|
|
127
136
|
const activeReplyDirective = suppressInterDialogReplyGuidance
|
|
128
137
|
? undefined
|
|
@@ -142,6 +151,7 @@ async function resolvePromptReplyGuidance(args) {
|
|
|
142
151
|
deferredReplyReassertionDirective: suppressInterDialogReplyGuidance
|
|
143
152
|
? availableReplyDirective
|
|
144
153
|
: undefined,
|
|
154
|
+
isQ4HAnswerPrompt,
|
|
145
155
|
promptContent,
|
|
146
156
|
persistedTellaskReplyDirective: prompt?.tellaskReplyDirective ?? activeReplyDirective,
|
|
147
157
|
suppressInterDialogReplyGuidance,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DialogDisplayTextI18n } from '@longrun-ai/kernel/types/display-state';
|
|
2
|
-
type HumanStopReasonKind = 'aborted' | 'transport_interrupted' | 'malformed_stream' | 'conflicting_stream' | 'invalid_tool_call' | 'incomplete_tool_call_stream' | 'invalid_tool_context' | 'provider_rejected' | 'request_failed' | '
|
|
2
|
+
type HumanStopReasonKind = 'aborted' | 'transport_interrupted' | 'malformed_stream' | 'conflicting_stream' | 'invalid_tool_call' | 'incomplete_tool_call_stream' | 'invalid_tool_context' | 'provider_rejected' | 'request_failed' | 'generic';
|
|
3
3
|
export declare function buildHumanSystemStopReasonTextI18n(args: {
|
|
4
4
|
detail: string;
|
|
5
5
|
providerName?: string;
|
|
@@ -82,10 +82,6 @@ function renderHumanStopReason(args) {
|
|
|
82
82
|
return args.language === 'zh'
|
|
83
83
|
? `本次生成因上游报错而停止。${formatUpstreamRawMessage(args.detail, 'zh')}`
|
|
84
84
|
: `This generation was stopped because the upstream service returned an error. ${formatUpstreamRawMessage(args.detail, 'en')}`;
|
|
85
|
-
case 'identical_update_plan_loop':
|
|
86
|
-
return args.language === 'zh'
|
|
87
|
-
? '模型连续重复相同的 update_plan 结果,本次生成已停止。'
|
|
88
|
-
: 'The model repeated the same update_plan result multiple times. This generation was stopped.';
|
|
89
85
|
case 'generic':
|
|
90
86
|
return args.language === 'zh'
|
|
91
87
|
? `本次生成已因系统错误停止。${formatUpstreamRawMessage(args.detail, 'zh')}`
|
package/dist/persistence.js
CHANGED
|
@@ -1003,12 +1003,16 @@ function parseDialogLatestFile(value) {
|
|
|
1003
1003
|
return undefined;
|
|
1004
1004
|
if (!isRecord(deferredReplyReassertionRaw))
|
|
1005
1005
|
return null;
|
|
1006
|
-
if (deferredReplyReassertionRaw.reason !== '
|
|
1006
|
+
if (deferredReplyReassertionRaw.reason !== 'user_interjection_with_parked_original_task') {
|
|
1007
1007
|
return null;
|
|
1008
1008
|
}
|
|
1009
1009
|
const directiveRaw = deferredReplyReassertionRaw.directive;
|
|
1010
1010
|
if (!isRecord(directiveRaw))
|
|
1011
1011
|
return null;
|
|
1012
|
+
const resumeGuideSurfacedRaw = deferredReplyReassertionRaw.resumeGuideSurfaced;
|
|
1013
|
+
if (resumeGuideSurfacedRaw !== undefined && typeof resumeGuideSurfacedRaw !== 'boolean') {
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
1012
1016
|
const expectedReplyCallName = directiveRaw.expectedReplyCallName;
|
|
1013
1017
|
const targetCallId = directiveRaw.targetCallId;
|
|
1014
1018
|
const tellaskContent = directiveRaw.tellaskContent;
|
|
@@ -1025,22 +1029,28 @@ function parseDialogLatestFile(value) {
|
|
|
1025
1029
|
if (typeof targetDialogId !== 'string')
|
|
1026
1030
|
return null;
|
|
1027
1031
|
return {
|
|
1028
|
-
reason: '
|
|
1032
|
+
reason: 'user_interjection_with_parked_original_task',
|
|
1029
1033
|
directive: {
|
|
1030
1034
|
expectedReplyCallName,
|
|
1031
1035
|
targetCallId,
|
|
1032
1036
|
targetDialogId,
|
|
1033
1037
|
tellaskContent,
|
|
1034
1038
|
},
|
|
1039
|
+
...(resumeGuideSurfacedRaw === undefined
|
|
1040
|
+
? {}
|
|
1041
|
+
: { resumeGuideSurfaced: resumeGuideSurfacedRaw }),
|
|
1035
1042
|
};
|
|
1036
1043
|
}
|
|
1037
1044
|
return {
|
|
1038
|
-
reason: '
|
|
1045
|
+
reason: 'user_interjection_with_parked_original_task',
|
|
1039
1046
|
directive: {
|
|
1040
1047
|
expectedReplyCallName,
|
|
1041
1048
|
targetCallId,
|
|
1042
1049
|
tellaskContent,
|
|
1043
1050
|
},
|
|
1051
|
+
...(resumeGuideSurfacedRaw === undefined
|
|
1052
|
+
? {}
|
|
1053
|
+
: { resumeGuideSurfaced: resumeGuideSurfacedRaw }),
|
|
1044
1054
|
};
|
|
1045
1055
|
})();
|
|
1046
1056
|
if (deferredReplyReassertion === null)
|
|
@@ -12,6 +12,10 @@ const USER_INTERJECTION_PAUSE_STOP_DETAIL = 'user_interjection_pause_resume_orig
|
|
|
12
12
|
// resume afterwards, the interjection should simply complete and the dialog should fall back to
|
|
13
13
|
// its true underlying state without showing this stopped panel.
|
|
14
14
|
//
|
|
15
|
+
// In particular, askHuman answers are NOT "user interjections" for this purpose. A prompt carrying
|
|
16
|
+
// a real `q4hAnswerCallId` belongs to the askHuman reply channel and must never be routed through
|
|
17
|
+
// this paused-original-task stop semantics.
|
|
18
|
+
//
|
|
15
19
|
// Do not change this file in isolation. The complete behavior depends on coordinated logic across:
|
|
16
20
|
// - `reply-guidance.ts` suppressing upstream reply obligation during interjection chat
|
|
17
21
|
// - `flow.ts` parking after the local reply, then re-running fresh-fact resume
|