dominds 0.6.5 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/docs/drive-logic-context-refactor-plan.zh.md +242 -0
  2. package/dist/llm/driver.js +71 -25
  3. package/dist/minds/builtin/cmdr/persona.md +3 -0
  4. package/dist/minds/builtin/dijiang/knowledge.md +287 -0
  5. package/dist/minds/builtin/dijiang/persona.md +7 -0
  6. package/dist/minds/system-prompt.js +6 -2
  7. package/dist/persistence.js +2 -0
  8. package/dist/server/api-routes.js +28 -71
  9. package/dist/server/websocket-handler.js +5 -1
  10. package/dist/showing-by-doing.js +31 -34
  11. package/dist/static/assets/{_baseUniq-B6S2Szf-.js → _baseUniq-DucuKHj3.js} +2 -2
  12. package/dist/static/assets/{_baseUniq-B6S2Szf-.js.map → _baseUniq-DucuKHj3.js.map} +1 -1
  13. package/dist/static/assets/{arc-BobaWfK6.js → arc-CNlZ9dTp.js} +2 -2
  14. package/dist/static/assets/{arc-BobaWfK6.js.map → arc-CNlZ9dTp.js.map} +1 -1
  15. package/dist/static/assets/{architectureDiagram-VXUJARFQ-ZgJq5aSW.js → architectureDiagram-VXUJARFQ-BXkEOfVt.js} +6 -6
  16. package/dist/static/assets/{architectureDiagram-VXUJARFQ-ZgJq5aSW.js.map → architectureDiagram-VXUJARFQ-BXkEOfVt.js.map} +1 -1
  17. package/dist/static/assets/{blockDiagram-VD42YOAC-BNbfk_nT.js → blockDiagram-VD42YOAC-CyxI2bRF.js} +7 -7
  18. package/dist/static/assets/{blockDiagram-VD42YOAC-BNbfk_nT.js.map → blockDiagram-VD42YOAC-CyxI2bRF.js.map} +1 -1
  19. package/dist/static/assets/{c4Diagram-YG6GDRKO-CvepUKza.js → c4Diagram-YG6GDRKO-sS8T1IDn.js} +3 -3
  20. package/dist/static/assets/{c4Diagram-YG6GDRKO-CvepUKza.js.map → c4Diagram-YG6GDRKO-sS8T1IDn.js.map} +1 -1
  21. package/dist/static/assets/{channel-C_JNHPnq.js → channel-DBu0JRwo.js} +2 -2
  22. package/dist/static/assets/{channel-C_JNHPnq.js.map → channel-DBu0JRwo.js.map} +1 -1
  23. package/dist/static/assets/{chunk-4BX2VUAB-DBOe1MUb.js → chunk-4BX2VUAB-D499BCnz.js} +2 -2
  24. package/dist/static/assets/{chunk-4BX2VUAB-DBOe1MUb.js.map → chunk-4BX2VUAB-D499BCnz.js.map} +1 -1
  25. package/dist/static/assets/{chunk-55IACEB6-HFCpWmno.js → chunk-55IACEB6-Dbe3sqC4.js} +2 -2
  26. package/dist/static/assets/{chunk-55IACEB6-HFCpWmno.js.map → chunk-55IACEB6-Dbe3sqC4.js.map} +1 -1
  27. package/dist/static/assets/{chunk-B4BG7PRW-CCfgfeSD.js → chunk-B4BG7PRW-BHkSNS9y.js} +5 -5
  28. package/dist/static/assets/{chunk-B4BG7PRW-CCfgfeSD.js.map → chunk-B4BG7PRW-BHkSNS9y.js.map} +1 -1
  29. package/dist/static/assets/{chunk-DI55MBZ5-JTCAsk7E.js → chunk-DI55MBZ5-idwTV08g.js} +4 -4
  30. package/dist/static/assets/{chunk-DI55MBZ5-JTCAsk7E.js.map → chunk-DI55MBZ5-idwTV08g.js.map} +1 -1
  31. package/dist/static/assets/{chunk-FMBD7UC4-DOOsbua1.js → chunk-FMBD7UC4-DLYv0YzD.js} +2 -2
  32. package/dist/static/assets/{chunk-FMBD7UC4-DOOsbua1.js.map → chunk-FMBD7UC4-DLYv0YzD.js.map} +1 -1
  33. package/dist/static/assets/{chunk-QN33PNHL-C9OxwmhO.js → chunk-QN33PNHL-DIC5_nYD.js} +2 -2
  34. package/dist/static/assets/{chunk-QN33PNHL-C9OxwmhO.js.map → chunk-QN33PNHL-DIC5_nYD.js.map} +1 -1
  35. package/dist/static/assets/{chunk-QZHKN3VN-r3c-cVI_.js → chunk-QZHKN3VN-DM_s2fcN.js} +2 -2
  36. package/dist/static/assets/{chunk-QZHKN3VN-r3c-cVI_.js.map → chunk-QZHKN3VN-DM_s2fcN.js.map} +1 -1
  37. package/dist/static/assets/{chunk-TZMSLE5B-BUEKhPxm.js → chunk-TZMSLE5B-BjrSLFBO.js} +2 -2
  38. package/dist/static/assets/{chunk-TZMSLE5B-BUEKhPxm.js.map → chunk-TZMSLE5B-BjrSLFBO.js.map} +1 -1
  39. package/dist/static/assets/{classDiagram-2ON5EDUG-COQwkaAL.js → classDiagram-2ON5EDUG-CSPkR9uh.js} +6 -6
  40. package/dist/static/assets/{classDiagram-2ON5EDUG-COQwkaAL.js.map → classDiagram-2ON5EDUG-CSPkR9uh.js.map} +1 -1
  41. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-COQwkaAL.js → classDiagram-v2-WZHVMYZB-CSPkR9uh.js} +6 -6
  42. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-COQwkaAL.js.map → classDiagram-v2-WZHVMYZB-CSPkR9uh.js.map} +1 -1
  43. package/dist/static/assets/{clone-CYu5kjkJ.js → clone-DO2rSUBP.js} +2 -2
  44. package/dist/static/assets/{clone-CYu5kjkJ.js.map → clone-DO2rSUBP.js.map} +1 -1
  45. package/dist/static/assets/{cose-bilkent-S5V4N54A-CSw8pwwN.js → cose-bilkent-S5V4N54A-CyS4z2hF.js} +2 -2
  46. package/dist/static/assets/{cose-bilkent-S5V4N54A-CSw8pwwN.js.map → cose-bilkent-S5V4N54A-CyS4z2hF.js.map} +1 -1
  47. package/dist/static/assets/{dagre-6UL2VRFP-BbGNBMsQ.js → dagre-6UL2VRFP-CvybKTFb.js} +7 -7
  48. package/dist/static/assets/{dagre-6UL2VRFP-BbGNBMsQ.js.map → dagre-6UL2VRFP-CvybKTFb.js.map} +1 -1
  49. package/dist/static/assets/{diagram-PSM6KHXK-CkJTRD5i.js → diagram-PSM6KHXK-Cl2rD6o-.js} +7 -7
  50. package/dist/static/assets/{diagram-PSM6KHXK-CkJTRD5i.js.map → diagram-PSM6KHXK-Cl2rD6o-.js.map} +1 -1
  51. package/dist/static/assets/{diagram-QEK2KX5R-C66826Tr.js → diagram-QEK2KX5R-RCrqu1G0.js} +6 -6
  52. package/dist/static/assets/{diagram-QEK2KX5R-C66826Tr.js.map → diagram-QEK2KX5R-RCrqu1G0.js.map} +1 -1
  53. package/dist/static/assets/{diagram-S2PKOQOG-C75tvMlR.js → diagram-S2PKOQOG-BeHOCxq7.js} +6 -6
  54. package/dist/static/assets/{diagram-S2PKOQOG-C75tvMlR.js.map → diagram-S2PKOQOG-BeHOCxq7.js.map} +1 -1
  55. package/dist/static/assets/{erDiagram-Q2GNP2WA-D42mH9Hf.js → erDiagram-Q2GNP2WA-MdKfm7lU.js} +5 -5
  56. package/dist/static/assets/{erDiagram-Q2GNP2WA-D42mH9Hf.js.map → erDiagram-Q2GNP2WA-MdKfm7lU.js.map} +1 -1
  57. package/dist/static/assets/{flowDiagram-NV44I4VS-DkuR_fBb.js → flowDiagram-NV44I4VS-DNo7ZxVC.js} +6 -6
  58. package/dist/static/assets/{flowDiagram-NV44I4VS-DkuR_fBb.js.map → flowDiagram-NV44I4VS-DNo7ZxVC.js.map} +1 -1
  59. package/dist/static/assets/{ganttDiagram-JELNMOA3-DZSt_dQ9.js → ganttDiagram-JELNMOA3-Bxs02jb2.js} +3 -3
  60. package/dist/static/assets/{ganttDiagram-JELNMOA3-DZSt_dQ9.js.map → ganttDiagram-JELNMOA3-Bxs02jb2.js.map} +1 -1
  61. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-tK78JYdV.js → gitGraphDiagram-NY62KEGX-BJsaVPOp.js} +7 -7
  62. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-tK78JYdV.js.map → gitGraphDiagram-NY62KEGX-BJsaVPOp.js.map} +1 -1
  63. package/dist/static/assets/{graph-Cby4rcD0.js → graph-DBSDya0j.js} +3 -3
  64. package/dist/static/assets/{graph-Cby4rcD0.js.map → graph-DBSDya0j.js.map} +1 -1
  65. package/dist/static/assets/{index-CbQiF1hF.js → index-gn-aSKfG.js} +59 -67
  66. package/dist/static/assets/{index-CbQiF1hF.js.map → index-gn-aSKfG.js.map} +1 -1
  67. package/dist/static/assets/{infoDiagram-WHAUD3N6-3QnrdyHa.js → infoDiagram-WHAUD3N6-D4Hvl0bK.js} +5 -5
  68. package/dist/static/assets/{infoDiagram-WHAUD3N6-3QnrdyHa.js.map → infoDiagram-WHAUD3N6-D4Hvl0bK.js.map} +1 -1
  69. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CvMiUhwC.js → journeyDiagram-XKPGCS4Q-B3YmIoCv.js} +5 -5
  70. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CvMiUhwC.js.map → journeyDiagram-XKPGCS4Q-B3YmIoCv.js.map} +1 -1
  71. package/dist/static/assets/{kanban-definition-3W4ZIXB7-kWGnHjKd.js → kanban-definition-3W4ZIXB7-dGCbR9Ty.js} +3 -3
  72. package/dist/static/assets/{kanban-definition-3W4ZIXB7-kWGnHjKd.js.map → kanban-definition-3W4ZIXB7-dGCbR9Ty.js.map} +1 -1
  73. package/dist/static/assets/{layout-DhLgvMyM.js → layout-D7y0xA6C.js} +5 -5
  74. package/dist/static/assets/{layout-DhLgvMyM.js.map → layout-D7y0xA6C.js.map} +1 -1
  75. package/dist/static/assets/{linear-BPVwP4Z5.js → linear-Cep1oHAS.js} +2 -2
  76. package/dist/static/assets/{linear-BPVwP4Z5.js.map → linear-Cep1oHAS.js.map} +1 -1
  77. package/dist/static/assets/{min-Cw8TUK_f.js → min-DWRXZ2qP.js} +3 -3
  78. package/dist/static/assets/{min-Cw8TUK_f.js.map → min-DWRXZ2qP.js.map} +1 -1
  79. package/dist/static/assets/{mindmap-definition-VGOIOE7T-Rfte1_cw.js → mindmap-definition-VGOIOE7T-FO6xgPgW.js} +4 -4
  80. package/dist/static/assets/{mindmap-definition-VGOIOE7T-Rfte1_cw.js.map → mindmap-definition-VGOIOE7T-FO6xgPgW.js.map} +1 -1
  81. package/dist/static/assets/{pieDiagram-ADFJNKIX-DCp0WpKz.js → pieDiagram-ADFJNKIX-ChJaCst9.js} +7 -7
  82. package/dist/static/assets/{pieDiagram-ADFJNKIX-DCp0WpKz.js.map → pieDiagram-ADFJNKIX-ChJaCst9.js.map} +1 -1
  83. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-DVYn8XbP.js → quadrantDiagram-AYHSOK5B-B8KuqHte.js} +3 -3
  84. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-DVYn8XbP.js.map → quadrantDiagram-AYHSOK5B-B8KuqHte.js.map} +1 -1
  85. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-OdD8esO6.js → requirementDiagram-UZGBJVZJ-DoJMxEmX.js} +4 -4
  86. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-OdD8esO6.js.map → requirementDiagram-UZGBJVZJ-DoJMxEmX.js.map} +1 -1
  87. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-Nb-HdiLl.js → sankeyDiagram-TZEHDZUN-CsLnys5W.js} +2 -2
  88. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-Nb-HdiLl.js.map → sankeyDiagram-TZEHDZUN-CsLnys5W.js.map} +1 -1
  89. package/dist/static/assets/{sequenceDiagram-WL72ISMW-DsNKFhn-.js → sequenceDiagram-WL72ISMW-CT4FY3X1.js} +4 -4
  90. package/dist/static/assets/{sequenceDiagram-WL72ISMW-DsNKFhn-.js.map → sequenceDiagram-WL72ISMW-CT4FY3X1.js.map} +1 -1
  91. package/dist/static/assets/{stateDiagram-FKZM4ZOC-DLVD0_56.js → stateDiagram-FKZM4ZOC-B3IXupz6.js} +9 -9
  92. package/dist/static/assets/{stateDiagram-FKZM4ZOC-DLVD0_56.js.map → stateDiagram-FKZM4ZOC-B3IXupz6.js.map} +1 -1
  93. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-zhzpPCLY.js → stateDiagram-v2-4FDKWEC3-C80vDn17.js} +5 -5
  94. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-zhzpPCLY.js.map → stateDiagram-v2-4FDKWEC3-C80vDn17.js.map} +1 -1
  95. package/dist/static/assets/{timeline-definition-IT6M3QCI-0G279y76.js → timeline-definition-IT6M3QCI-Bk2mvjhh.js} +3 -3
  96. package/dist/static/assets/{timeline-definition-IT6M3QCI-0G279y76.js.map → timeline-definition-IT6M3QCI-Bk2mvjhh.js.map} +1 -1
  97. package/dist/static/assets/{treemap-KMMF4GRG-CKoXag7A.js → treemap-KMMF4GRG-mWi2Ai-0.js} +4 -4
  98. package/dist/static/assets/{treemap-KMMF4GRG-CKoXag7A.js.map → treemap-KMMF4GRG-mWi2Ai-0.js.map} +1 -1
  99. package/dist/static/assets/{xychartDiagram-PRI3JC2R-BHQ4qaEg.js → xychartDiagram-PRI3JC2R-B5-7mQpW.js} +3 -3
  100. package/dist/static/assets/{xychartDiagram-PRI3JC2R-BHQ4qaEg.js.map → xychartDiagram-PRI3JC2R-B5-7mQpW.js.map} +1 -1
  101. package/dist/static/index.html +1 -1
  102. package/dist/tools/context-health.js +7 -7
  103. package/dist/utils/task-doc.js +16 -16
  104. package/package.json +2 -2
  105. package/dist/docs/keep-going.zh.md +0 -162
  106. package/dist/docs/showing-by-doing.md +0 -208
  107. package/dist/docs/showing-by-doing.zh.md +0 -177
  108. package/dist/minds/promptdocs.js +0 -263
  109. package/dist/snippets/README.en.md +0 -3
@@ -0,0 +1,242 @@
1
+ # Drive 逻辑上下文拼装现状与重构计划(2026-02)
2
+
3
+ 状态:Draft
4
+ 语义基线:以 `dominds/main/llm/driver.ts` 与 `dominds/main/persistence.ts` 当前实现为准。
5
+
6
+ ## 1. 背景与目标
7
+
8
+ 近期在对话 `@ux (39/12/417f4a49)` 中暴露出一个上下文一致性问题:同一主线对话内已经收到了 `@cmdr/@browser_tester` 的回贴并据此更新 Taskdoc,但后续回复仍声称“没看到原始回贴文本”。
9
+
10
+ 这类问题的根因不是单条提示词,而是 **drive 内多轮生成的上下文来源语义不统一**:有的上下文是持久消息(`dlg.msgs`),有的是一次性注入(仅首轮),还有的是消费队列(take/commit/rollback)。
11
+
12
+ 本文目标:
13
+
14
+ 1. 固化“当前代码结构现状”的可审计视图。
15
+ 2. 记录本轮已做的修补。
16
+ 3. 制定一次更大范围的 drive logic 重构计划,使后续维护更清晰、不易回归。
17
+
18
+ ## 2. 当前结构(代码现状)
19
+
20
+ ### 2.1 核心文件与职责
21
+
22
+ - `main/llm/driver.ts`
23
+ - `_driveDialogStream()`:单次 drive 主循环,负责 prompt 处理、上下文拼装、LLM 调用、工具调用、suspend/continue。
24
+ - `supplyResponseToSupdialog()`:子对话回贴写入父对话响应队列、更新 pending、触发 auto-revive。
25
+ - `main/persistence.ts`
26
+ - `takeSubdialogResponses()/commitTakenSubdialogResponses()/rollbackTakenSubdialogResponses()`:子对话回贴队列的“取走-提交/回滚”机制。
27
+ - `rebuildFromEvents()`:重建 `dlg.msgs`(包含 `teammate_response_record -> tellask_result_msg` 映射)。
28
+ - `main/dialog.ts`
29
+ - `addChatMessages()`:运行时消息容器(in-memory)。
30
+
31
+ ### 2.2 当前上下文来源(进入 LLM 的入口)
32
+
33
+ 在 `_driveDialogStream()` 中,每轮 gen 的 `ctxMsgs` 由以下部分拼装:
34
+
35
+ 1. `prependedContextMessages`(策略注入)
36
+ 2. `memories`
37
+ 3. `taskDocMsg`
38
+ 4. `coursePrefixMsgs`
39
+ 5. `dialogMsgsForContext`(来自 `dlg.msgs`)
40
+ 6. `subdialogResponseContextMsgs`(来自 `takeSubdialogResponses` 的注入)
41
+ 7. `internalDrivePromptMsg`(internal prompt 注入)
42
+ 8. reminders + language guide(末尾插入)
43
+
44
+ 要点:`dlg.msgs` 是“稳定上下文”;队列/内部 prompt 属于“drive 级上下文”。
45
+
46
+ ## 3. 本轮修补(已落地)
47
+
48
+ ### 3.1 已修问题
49
+
50
+ 1. **同一 drive 多轮丢失 teammate response 上下文**
51
+ - 修复:把 `takeSubdialogResponses` 生成的 `subdialogResponseContextMsgs` 在同一 drive 内跨迭代保留,而非仅 `genIterNo===1` 注入。
52
+
53
+ 2. **中断时误 commit 已 take 队列**
54
+ - 修复:在 interrupted 分支标记 `generationHadError = true`,确保 finally 走 rollback,不会把未稳定消费的队列当作已消费。
55
+
56
+ 3. **internal prompt 语义收敛为 drive 级 priming**
57
+ - 修复:移除生命周期分支;`persistMode='internal'` 统一为 drive-scoped priming 注入。
58
+ - 语义:仅在当前 drive 生效、不入 `dlg.msgs`、不持久化、不渲染 UI。
59
+ - 依据:当前唯一使用场景是 Agent Priming,且明确要求 loop 迭代中持续可见。
60
+
61
+ 4. **teammate response 稳定化到 `dlg.msgs`(与工具结果语义对齐)**
62
+ - 修复:当 take/commit 成功后,把该批回贴镜像为 `tellask_result_msg` 写入 `dlg.msgs`,让后续 drive 不依赖一次性队列注入。
63
+
64
+ 5. **队列记录补齐状态字段**
65
+ - 修复:`subdialog-responses` 记录新增可选 `status`(`completed|failed`),并在镜像消息时使用该状态(默认 `completed`)。
66
+
67
+ ## 4. 仍存在的结构债务
68
+
69
+ ### 4.1 状态语义分散
70
+
71
+ 同一类“队友回贴事实”同时存在于:
72
+
73
+ - `teammate_response_record`(事件持久层)
74
+ - `subdialog-responses.json`(消费队列)
75
+ - `dlg.msgs`(运行时上下文)
76
+
77
+ 缺少单一“源事实 -> 视图派生”的规范,维护成本高。
78
+
79
+ ### 4.2 拼装流程耦合过深
80
+
81
+ `_driveDialogStream()` 同时承担:
82
+
83
+ - prompt 生命周期管理
84
+ - 上下文装配
85
+ - policy 校验
86
+ - 流式/非流式分支
87
+ - 工具调用循环
88
+ - suspend/revive 与队列提交事务
89
+
90
+ 单函数职责过重,不利于做语义回归验证。
91
+
92
+ ### 4.3 缺少针对性回归测试矩阵
93
+
94
+ 现有 tellask 测试覆盖“auto-revive 能跑通”,但对以下关键边界覆盖不足:
95
+
96
+ - 同一 drive 的多轮迭代上下文一致性
97
+ - interrupted + take queue 的 rollback 语义
98
+ - committed queue 镜像到 `dlg.msgs` 后的去重/恢复语义
99
+
100
+ ## 5. 语义决策记录(本轮确认)
101
+
102
+ 1. `persistMode='internal'` 不是“下一轮临时补丁”,而是 **drive 级 priming 通道**。
103
+ 2. 当前无 `next_gen` 真实业务需求,先不保留该分支,避免语义包袱。
104
+ 3. 如未来出现单轮内部提示需求,新增能力应基于明确场景和回归测试,不提前抽象。
105
+
106
+ ## 6. 大重构计划(可执行蓝图)
107
+
108
+ ### 阶段 A:上下文装配纯函数化(不改行为)
109
+
110
+ 目标:把“怎么拼装 ctxMsgs”从 `_driveDialogStream()` 中剥离为可测试单元。
111
+
112
+ 交付物:
113
+
114
+ 1. 新建 `buildDriveContextSnapshot(...)`,输出不可变快照:
115
+ - `stableMessages`(来自 `dlg.msgs` + memories + taskdoc + coursePrefix)
116
+ - `transientMessages`(subdialog 注入、internal drive priming、reminder/language guide)
117
+ - `diagnostics`(各来源计数、关键 id、去重统计)
118
+ 2. 新建 `renderDriveContextMessages(snapshot)`,仅负责有序拼接,不负责业务决策。
119
+ 3. `_driveDialogStream()` 改为“准备输入 -> 调纯函数 -> 用输出”。
120
+
121
+ 验收:
122
+
123
+ 1. 对同一输入快照,render 结果稳定(可 snapshot test)。
124
+ 2. 现有行为不变(含 remind/language guide 插入顺序)。
125
+
126
+ ### 阶段 B:take/commit/rollback 事务边界显式化(核心)
127
+
128
+ 目标:把“队友回贴消费”从散落标志位改为单一事务状态机。
129
+
130
+ 交付物:
131
+
132
+ 1. 引入 `TakenResponsesTxn`(建议放在 `main/llm/driver-context-txn.ts`):
133
+ - `begin(dlgId)`:take queue
134
+ - `asInjectedMessages()`:生成注入消息
135
+ - `markGenerationAttempted()`:至少发起过有效 LLM 请求
136
+ - `finalize(outcome)`:`commit|rollback`
137
+ 2. 用显式 outcome 替代隐式 `generationHadError` 推断。
138
+ 3. 把 interrupted 与 error 的 finalize 语义统一。
139
+
140
+ 验收:
141
+
142
+ 1. interrupted/error 必 rollback。
143
+ 2. 成功且已尝试生成时 commit。
144
+ 3. finalize 幂等(重复调用不会破坏状态)。
145
+
146
+ ### 阶段 C:teammate response 单路径入上下文(减少双轨)
147
+
148
+ 目标:统一 live 路径与 restore 路径的同构转换,避免“看过但丢失”或重复。
149
+
150
+ 交付物:
151
+
152
+ 1. 新建 `toTellaskResultMsg(record)` 转换器,统一以下两处:
153
+ - live commit 后镜像到 `dlg.msgs`
154
+ - `rebuildFromEvents()` 的重建映射
155
+ 2. 显式去重键策略:
156
+ - 优先 `callId`
157
+ - 回退 `responseId`
158
+ - 再回退 `responderId + tellaskHead + completedAt`
159
+ 3. diagnostics 中输出“去重前后数量”和命中键类型。
160
+
161
+ 验收:
162
+
163
+ 1. restore 后不重复。
164
+ 2. live drive 与 restore drive 的输入上下文等价。
165
+
166
+ ### 阶段 D:\_driveDialogStream 职责分层(可维护性)
167
+
168
+ 目标:把巨函数拆成“稳定编排 + 可替换子模块”。
169
+
170
+ 建议拆分模块:
171
+
172
+ 1. `prepareDriveInputs(...)`
173
+ 2. `buildGenerationContext(...)`
174
+ 3. `runGenerationRound(...)`(流式/非流式统一返回形态)
175
+ 4. `applyRoundSideEffects(...)`(tool outputs / tellask outputs / upNext)
176
+ 5. `finalizeDrive(...)`
177
+
178
+ 验收:
179
+
180
+ 1. `_driveDialogStream` 主体降到“编排层”。
181
+ 2. 单模块改动不需触碰整个 while-loop。
182
+
183
+ ### 阶段 E:回归矩阵与复放样本
184
+
185
+ 新增最小回归:
186
+
187
+ 1. `drive-context:multi-iter-subdialog-response.ts`
188
+ 2. `drive-context:interrupt-rollback.ts`
189
+ 3. `drive-context:commit-mirror-msgs.ts`
190
+ 4. `drive-context:no-duplicate-after-restore.ts`
191
+ 5. `drive-context:internal-drive-priming-persists-across-iterations.ts`
192
+
193
+ 新增复放样本:
194
+
195
+ 1. 以 `39/12/417f4a49` 风格构造一条“多轮 + tellask + tool + continue”样本,断言模型能持续看到 teammate 原始回贴语义。
196
+
197
+ ## 7. 目标接口草案(供后续实现)
198
+
199
+ ```ts
200
+ type DriveTransientContext = {
201
+ subdialogResponseMsgs: ChatMessage[];
202
+ internalDrivePrimingMsg?: ChatMessage;
203
+ reminderMsgs: ChatMessage[];
204
+ languageGuideMsg: ChatMessage;
205
+ };
206
+
207
+ type DriveContextSnapshot = {
208
+ stableMessages: ChatMessage[];
209
+ transient: DriveTransientContext;
210
+ diagnostics: {
211
+ counts: Record<string, number>;
212
+ dedupe: { before: number; after: number; by: string[] };
213
+ genseq?: number;
214
+ callIds: string[];
215
+ };
216
+ };
217
+ ```
218
+
219
+ 说明:
220
+
221
+ 1. `internalDrivePrimingMsg` 仅允许 drive 级语义,不包含单轮模式。
222
+ 2. snapshot 不做副作用,不访问持久层。
223
+ 3. 所有副作用留在 driver 编排层执行。
224
+
225
+ ## 8. 重构约束(必须保持)
226
+
227
+ 1. 不改变现有 wire 协议事件名与基础语义(除非显式版本升级)。
228
+ 2. 不引入 silent fallback;上下文事务异常需 loud 日志与可见错误信号。
229
+ 3. 保持 TypeScript strict 与可静态验证属性;禁止 `any`。
230
+ 4. 重构每阶段都要求:
231
+ - `pnpm -C dominds run lint:types` 通过
232
+ - tellask 相关回归通过
233
+ - 至少 1 条真实对话复放样本通过(含 auto-revive 场景)
234
+
235
+ ## 9. 执行顺序建议
236
+
237
+ 1. 先做阶段 A,先把“可观察性”补齐。
238
+ 2. 再做阶段 B,这是一致性根基。
239
+ 3. 再做阶段 C,统一消息路径。
240
+ 4. 最后做阶段 D/E,收敛维护复杂度并补齐回归。
241
+
242
+ 该顺序允许在每阶段都可独立回滚,降低一次性大改风险。
@@ -956,6 +956,16 @@ async function driveDialogStream(dlg, humanPrompt, waitInQue = false, driveOptio
956
956
  driveResult &&
957
957
  !driveResult.interrupted &&
958
958
  driveResult.lastAssistantSayingContent !== null) {
959
+ const suspension = await dlg.getSuspensionStatus();
960
+ if (!suspension.canDrive) {
961
+ log_1.log.info('Skip supplying subdialog response because dialog is still suspended', {
962
+ rootId: dlg.id.rootId,
963
+ selfId: dlg.id.selfId,
964
+ waitingQ4H: suspension.q4h,
965
+ waitingSubdialogs: suspension.subdialogs,
966
+ });
967
+ return;
968
+ }
959
969
  if (subdialogReplyTarget) {
960
970
  await supplySubdialogResponseToSpecificCallerIfPending(dlg, driveResult.lastAssistantSayingContent, subdialogReplyTarget);
961
971
  }
@@ -1110,9 +1120,14 @@ async function _driveDialogStream(dlg, humanPrompt, driveOptions) {
1110
1120
  let generationHadError = false;
1111
1121
  let tookSubdialogResponses = false;
1112
1122
  let takenSubdialogResponses = [];
1123
+ // Keep injected subdialog replies visible across all gen iterations in the same drive.
1124
+ // Without this, iteration #2 (e.g. after a function call) can lose reply context from iteration #1.
1125
+ let subdialogResponseContextMsgs = [];
1126
+ // Internal prompt is drive-scoped priming context and never persisted.
1127
+ let internalDrivePromptMsg;
1128
+ let committedTakenSubdialogResponses = false;
1113
1129
  let genIterNo = 0;
1114
1130
  let pendingPrompt = humanPrompt;
1115
- let internalPromptForThisDrive;
1116
1131
  let skipTaskdocForThisDrive = humanPrompt?.skipTaskdoc === true;
1117
1132
  try {
1118
1133
  while (true) {
@@ -1254,7 +1269,14 @@ async function _driveDialogStream(dlg, humanPrompt, driveOptions) {
1254
1269
  });
1255
1270
  }
1256
1271
  if (persistMode === 'internal') {
1257
- internalPromptForThisDrive = currentPrompt;
1272
+ const injected = currentPrompt.content.trim();
1273
+ internalDrivePromptMsg = injected
1274
+ ? {
1275
+ type: 'environment_msg',
1276
+ role: 'user',
1277
+ content: injected,
1278
+ }
1279
+ : undefined;
1258
1280
  }
1259
1281
  else {
1260
1282
  await dlg.addChatMessages({
@@ -1355,31 +1377,25 @@ async function _driveDialogStream(dlg, humanPrompt, driveOptions) {
1355
1377
  dialogMsgsForContext,
1356
1378
  });
1357
1379
  if (genIterNo === 1 && takenSubdialogResponses.length > 0) {
1358
- for (const response of takenSubdialogResponses) {
1359
- ctxMsgs.push({
1360
- type: 'environment_msg',
1361
- role: 'user',
1362
- content: (0, inter_dialog_format_1.formatTeammateResponseContent)({
1363
- responderId: response.responderId,
1364
- requesterId: response.originMemberId,
1365
- originalCallHeadLine: response.tellaskHead,
1366
- responseBody: response.response,
1367
- language: (0, runtime_language_1.getWorkLanguage)(),
1368
- }),
1369
- });
1370
- }
1380
+ subdialogResponseContextMsgs = takenSubdialogResponses.map((response) => ({
1381
+ type: 'environment_msg',
1382
+ role: 'user',
1383
+ content: (0, inter_dialog_format_1.formatTeammateResponseContent)({
1384
+ responderId: response.responderId,
1385
+ requesterId: response.originMemberId,
1386
+ originalCallHeadLine: response.tellaskHead,
1387
+ responseBody: response.response,
1388
+ language: (0, runtime_language_1.getWorkLanguage)(),
1389
+ }),
1390
+ }));
1391
+ }
1392
+ if (subdialogResponseContextMsgs.length > 0) {
1393
+ ctxMsgs.push(...subdialogResponseContextMsgs);
1371
1394
  }
1372
1395
  // Inject the internal (non-persisted) prompt at the end of the fresh user context
1373
- // so it can steer the next response without polluting dialog history.
1374
- if (genIterNo === 1 && internalPromptForThisDrive) {
1375
- const injected = internalPromptForThisDrive.content.trim();
1376
- if (injected) {
1377
- ctxMsgs.push({
1378
- type: 'environment_msg',
1379
- role: 'user',
1380
- content: injected,
1381
- });
1382
- }
1396
+ // so it can steer this drive without polluting dialog history.
1397
+ if (internalDrivePromptMsg) {
1398
+ ctxMsgs.push(internalDrivePromptMsg);
1383
1399
  }
1384
1400
  await dlg.processReminderUpdates();
1385
1401
  const renderedReminders = dlg.reminders.length > 0
@@ -2253,6 +2269,9 @@ async function _driveDialogStream(dlg, humanPrompt, driveOptions) {
2253
2269
  : { kind: 'system_stop', detail: 'Aborted.' }
2254
2270
  : undefined;
2255
2271
  if (interruptedReason) {
2272
+ // If subdialog responses were taken during this drive, interruption means they
2273
+ // should be rolled back for retry instead of being committed as consumed.
2274
+ generationHadError = true;
2256
2275
  finalRunState = { kind: 'interrupted', reason: interruptedReason };
2257
2276
  (0, dialog_run_state_1.broadcastRunStateMarker)(dlg.id, { kind: 'interrupted', reason: interruptedReason });
2258
2277
  return { lastAssistantSayingContent, interrupted: true };
@@ -2310,6 +2329,7 @@ async function _driveDialogStream(dlg, humanPrompt, driveOptions) {
2310
2329
  }
2311
2330
  else {
2312
2331
  await persistence_1.DialogPersistence.commitTakenSubdialogResponses(dlg.id);
2332
+ committedTakenSubdialogResponses = true;
2313
2333
  }
2314
2334
  });
2315
2335
  }
@@ -2320,6 +2340,31 @@ async function _driveDialogStream(dlg, humanPrompt, driveOptions) {
2320
2340
  });
2321
2341
  }
2322
2342
  }
2343
+ if (committedTakenSubdialogResponses && takenSubdialogResponses.length > 0) {
2344
+ try {
2345
+ const mirroredMsgs = takenSubdialogResponses.map((response) => ({
2346
+ type: 'tellask_result_msg',
2347
+ role: 'tool',
2348
+ responderId: response.responderId,
2349
+ tellaskHead: response.tellaskHead,
2350
+ status: response.status ?? 'completed',
2351
+ content: (0, inter_dialog_format_1.formatTeammateResponseContent)({
2352
+ responderId: response.responderId,
2353
+ requesterId: response.originMemberId,
2354
+ originalCallHeadLine: response.tellaskHead,
2355
+ responseBody: response.response,
2356
+ language: (0, runtime_language_1.getWorkLanguage)(),
2357
+ }),
2358
+ }));
2359
+ await dlg.addChatMessages(...mirroredMsgs);
2360
+ }
2361
+ catch (err) {
2362
+ log_1.log.warn('Failed to mirror committed subdialog responses into dialog msgs', {
2363
+ dialogId: dlg.id.selfId,
2364
+ error: err,
2365
+ });
2366
+ }
2367
+ }
2323
2368
  }
2324
2369
  } // Close while loop
2325
2370
  // Dialog stream has completed - no need to mark queue as complete since we're using receivers
@@ -2994,6 +3039,7 @@ async function supplyResponseToSupdialog(parentDialog, subdialogId, responseText
2994
3039
  subdialogId: subdialogId.selfId,
2995
3040
  response: responseText,
2996
3041
  completedAt,
3042
+ status,
2997
3043
  callType,
2998
3044
  tellaskHead,
2999
3045
  responderId,
@@ -0,0 +1,3 @@
1
+ You are the commander, in charge of os shell command execution.
2
+
3
+ Be caucious to execute dangerous/destructive commands, ask human confirmation when not sure, but never bother them for daily trivialities.
@@ -0,0 +1,287 @@
1
+ ## Team Definition
2
+
3
+ The team definition lives in `.minds/team.yaml`. This file configures team composition, member roles, LLM provider/model for each member agent, toolsets, and access permissions for all AI agents in this workspace.
4
+
5
+ ### Structure Overview
6
+
7
+ The `team.yaml` file has three main sections:
8
+
9
+ ```yaml
10
+ member_defaults: { ... } # Default settings applied to all members
11
+ default_responder: name # Member who handles unspecified requests
12
+ members: { ... } # Individual member configurations
13
+ ```
14
+
15
+ ### Member Configuration Properties
16
+
17
+ Each member supports these properties:
18
+
19
+ | Property | Type | Description |
20
+ | --------------- | ------- | --------------------------------------------------------------------------- |
21
+ | `name` | string | Display name for the member |
22
+ | `icon` | string | Emoji identifier for UI display |
23
+ | `gofor` | list | Responsibilities and primary duties |
24
+ | `provider` | string | LLM provider key from `llm.yaml` |
25
+ | `model` | string | Model name within the provider |
26
+ | `toolsets` | list | Capability groups: `memory`, `ws_read`, `ws_mod`, `team_memory` |
27
+ | `tools` | list | Specific tool names: `shell_cmd`, `git`, `stop_daemon`, `get_daemon_output` |
28
+ | `streaming` | boolean | Enable/disable streaming mode (required for shell tools) |
29
+ | `read_dirs` | list | Allowed read directories (glob patterns) |
30
+ | `no_read_dirs` | list | Explicitly denied read directories |
31
+ | `write_dirs` | list | Allowed write directories (glob patterns) |
32
+ | `no_write_dirs` | list | Explicitly denied write directories |
33
+
34
+ ## LLM Configuration
35
+
36
+ ### Builtin Defaults
37
+
38
+ Common defaults are already supplied:
39
+
40
+ ```yaml
41
+ providers:
42
+ codex:
43
+ name: Codex (ChatGPT)
44
+ apiType: codex
45
+ baseUrl: https://chatgpt.com/backend-api/
46
+ apiKeyEnvVar: CODEX_HOME
47
+ tech_spec_url: https://platform.openai.com/docs/api-reference/responses
48
+ api_mgmt_url: https://chatgpt.com/
49
+ models:
50
+ gpt-5.2-codex:
51
+ name: GPT-5.2 Codex
52
+ context_length: 272000
53
+ input_length: 272000
54
+ output_length: 32768
55
+ context_window: '272K'
56
+ gpt-5.2:
57
+ name: GPT-5.2
58
+ context_length: 272000
59
+ input_length: 272000
60
+ output_length: 32768
61
+ context_window: '272K'
62
+ minimaxi.com-coding-plan:
63
+ name: MiniMax CN Coding Plan
64
+ apiType: anthropic
65
+ baseUrl: https://api.minimaxi.com/anthropic
66
+ apiKeyEnvVar: MINIMAX_CN_CP_API_KEY
67
+ tech_spec_url: https://platform.minimaxi.com/document/guides
68
+ api_mgmt_url: https://platform.minimaxi.com/
69
+ models:
70
+ MiniMax-M2.1:
71
+ name: MiniMax M2.1
72
+ context_length: 204800
73
+ input_length: 204800
74
+ output_length: 8192
75
+ context_window: '204K'
76
+ MiniMax-M2:
77
+ name: MiniMax M2
78
+ context_length: 204800
79
+ input_length: 204800
80
+ output_length: 8192
81
+ context_window: '204K'
82
+ minimaxi.com:
83
+ name: MiniMax CN
84
+ apiType: anthropic
85
+ baseUrl: https://api.minimaxi.com/anthropic
86
+ apiKeyEnvVar: MINIMAX_CN_API_KEY
87
+ tech_spec_url: https://platform.minimaxi.com/document/guides
88
+ api_mgmt_url: https://platform.minimaxi.com/
89
+ models:
90
+ MiniMax-M2.1:
91
+ name: MiniMax M2.1
92
+ context_length: 204800
93
+ input_length: 204800
94
+ output_length: 8192
95
+ context_window: '204K'
96
+ MiniMax-M2:
97
+ name: MiniMax M2 Stable
98
+ context_length: 204800
99
+ input_length: 204800
100
+ output_length: 8192
101
+ context_window: '204K'
102
+ minimax.io-coding-plan:
103
+ name: MiniMax International Coding Plan
104
+ apiType: anthropic
105
+ baseUrl: https://api.minimax.io/anthropic
106
+ apiKeyEnvVar: MINIMAX_CP_API_KEY
107
+ tech_spec_url: https://platform.minimax.io/docs/api-reference
108
+ api_mgmt_url: https://platform.minimax.io/
109
+ models:
110
+ MiniMax-M2.1:
111
+ name: MiniMax M2.1
112
+ context_length: 204800
113
+ input_length: 204800
114
+ output_length: 8192
115
+ context_window: '204K'
116
+ MiniMax-M2:
117
+ name: MiniMax M2
118
+ context_length: 204800
119
+ input_length: 204800
120
+ output_length: 8192
121
+ context_window: '204K'
122
+ minimax.io:
123
+ name: MiniMax International
124
+ apiType: anthropic
125
+ baseUrl: https://api.minimax.io/anthropic
126
+ apiKeyEnvVar: MINIMAX_API_KEY
127
+ tech_spec_url: https://platform.minimax.io/docs/api-reference
128
+ api_mgmt_url: https://platform.minimax.io/
129
+ models:
130
+ MiniMax-M2.1:
131
+ name: MiniMax M2.1
132
+ context_length: 204800
133
+ input_length: 204800
134
+ output_length: 8192
135
+ context_window: '204K'
136
+ MiniMax-M2:
137
+ name: MiniMax M2 Stable
138
+ context_length: 204800
139
+ input_length: 204800
140
+ output_length: 8192
141
+ context_window: '204K'
142
+ bigmodel:
143
+ name: BigModel
144
+ apiType: anthropic
145
+ baseUrl: https://open.bigmodel.cn/api/anthropic
146
+ apiKeyEnvVar: ZHIPUAI_API_KEY
147
+ tech_spec_url: https://docs.bigmodel.cn/
148
+ api_mgmt_url: https://open.bigmodel.cn/usercenter/apikeys
149
+ models:
150
+ glm-4.7:
151
+ name: GLM-4.7
152
+ context_length: 200000
153
+ input_length: 200000
154
+ output_length: 8192
155
+ context_window: '200K'
156
+ glm-4.6:
157
+ name: GLM-4.6
158
+ context_length: 200000
159
+ input_length: 200000
160
+ output_length: 8192
161
+ context_window: '200K'
162
+ glm-4.5:
163
+ name: GLM-4.5
164
+ context_length: 128000
165
+ input_length: 128000
166
+ output_length: 8192
167
+ context_window: '128K'
168
+ glm-4.5-air:
169
+ name: GLM-4.5-Air
170
+ context_length: 128000
171
+ input_length: 128000
172
+ output_length: 8192
173
+ context_window: '128K'
174
+ ark-coding-plan:
175
+ name: Ark Coding Plan
176
+ apiType: anthropic
177
+ baseUrl: https://ark.cn-beijing.volces.com/api/coding
178
+ apiKeyEnvVar: ARK_API_KEY
179
+ tech_spec_url: https://api.volcengine.com/api-docs/view?serviceCode=ark&version=2024-01-01
180
+ api_mgmt_url: https://console.volcengine.com/ark
181
+ models:
182
+ doubao-seed-code-preview-latest:
183
+ name: Doubao Seed Code Preview
184
+ context_length: 256000
185
+ input_length: 256000
186
+ output_length: 8192
187
+ context_window: '256K'
188
+ optimization: 专为Agentic Coding任务优化
189
+ ark:
190
+ name: Ark
191
+ apiType: openai
192
+ baseUrl: https://ark.cn-beijing.volces.com/api/v3
193
+ apiKeyEnvVar: ARK_API_KEY
194
+ tech_spec_url: https://api.volcengine.com/api-docs/view?serviceCode=ark&version=2024-01-01
195
+ api_mgmt_url: https://console.volcengine.com/ark
196
+ models:
197
+ deepseek-v3-2-251201:
198
+ name: DeepSeek-V3.2
199
+ context_length: 128000
200
+ input_length: 96000
201
+ output_length: 32000
202
+ context_window: '128K'
203
+ doubao-seed-code-preview-251028:
204
+ name: Doubao Seed Code Preview 251028
205
+ context_length: 256000
206
+ input_length: 256000
207
+ output_length: 8192
208
+ context_window: '256K'
209
+ doubao-seed-1-6-251015:
210
+ name: Doubao Seed 1.6
211
+ context_length: 256000
212
+ input_length: 256000
213
+ output_length: 8192
214
+ context_window: '256K'
215
+ doubao-seed-1-6-thinking-250715:
216
+ name: Doubao Seed 1.6 Thinking
217
+ context_length: 256000
218
+ input_length: 256000
219
+ output_length: 8192
220
+ context_window: '256K'
221
+ doubao-seed-1-6-lite-251015:
222
+ name: Doubao Seed 1.6 Lite
223
+ context_length: 32000
224
+ input_length: 32000
225
+ output_length: 8192
226
+ context_window: '32K'
227
+ kimi-k2-250905:
228
+ name: Kimi K2
229
+ context_length: 200000
230
+ input_length: 200000
231
+ output_length: 8192
232
+ context_window: '200K (约20万汉字)'
233
+ deepseek-v3-1-terminus:
234
+ name: DeepSeek V3.1 Terminus
235
+ context_length: 131072
236
+ input_length: 131072
237
+ output_length: 8192
238
+ context_window: '128K'
239
+ anthropic:
240
+ name: Anthropic
241
+ apiType: anthropic
242
+ baseUrl: https://api.anthropic.com
243
+ apiKeyEnvVar: ANTHROPIC_API_KEY
244
+ tech_spec_url: https://docs.anthropic.com/en/docs
245
+ api_mgmt_url: https://console.anthropic.com/
246
+ models:
247
+ claude-opus-4.5:
248
+ name: Claude Opus 4.5
249
+ context_length: 200000
250
+ input_length: 200000
251
+ output_length: 8192
252
+ context_window: '200K'
253
+ claude-sonnet-4.5:
254
+ name: Claude Sonnet 4.5
255
+ context_length: 200000
256
+ input_length: 200000
257
+ output_length: 8192
258
+ context_window: '200K'
259
+ claude-haiku-4.5:
260
+ name: Claude Haiku 4.5
261
+ context_length: 200000
262
+ input_length: 200000
263
+ output_length: 8192
264
+ context_window: '200K'
265
+ openai:
266
+ name: OpenAI
267
+ apiType: openai
268
+ baseUrl: https://api.openai.com/v1
269
+ apiKeyEnvVar: OPENAI_API_KEY
270
+ tech_spec_url: https://platform.openai.com/docs
271
+ api_mgmt_url: https://platform.openai.com/api-keys
272
+ models:
273
+ gpt-5.2:
274
+ name: GPT-5.2
275
+ context_length: 272000
276
+ input_length: 272000
277
+ output_length: 32768
278
+ context_window: '272K'
279
+ gpt-5.2-codex:
280
+ name: GPT-5.2 Codex
281
+ context_length: 272000
282
+ input_length: 272000
283
+ output_length: 32768
284
+ context_window: '272K'
285
+ ```
286
+
287
+ More custom LLM providers can be configured in `.minds/llm.yaml` with the same format as above.