dominds 1.26.1 → 1.26.3

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 (138) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +2 -0
  3. package/dist/cli/webui.js +14 -4
  4. package/dist/docs/cli-usage.md +1 -1
  5. package/dist/docs/cli-usage.zh.md +1 -1
  6. package/dist/llm/gen/mock.js +11 -3
  7. package/dist/llm/kernel-driver/context-health.d.ts +1 -0
  8. package/dist/llm/kernel-driver/context-health.js +7 -0
  9. package/dist/llm/kernel-driver/drive.js +23 -30
  10. package/dist/llm/kernel-driver/idle-reminder-wake.js +6 -2
  11. package/dist/llm/kernel-driver/reminder-context.d.ts +25 -0
  12. package/dist/llm/kernel-driver/reminder-context.js +81 -0
  13. package/dist/llm/kernel-driver/reply-guidance.js +10 -4
  14. package/dist/llm/kernel-driver/tellask-special.js +50 -35
  15. package/dist/mcp/supervisor.js +2 -2
  16. package/dist/minds/system-prompt-parts.js +30 -30
  17. package/dist/minds/system-prompt.js +55 -40
  18. package/dist/persistence.js +15 -1
  19. package/dist/runtime/driver-messages.d.ts +32 -7
  20. package/dist/runtime/driver-messages.js +279 -118
  21. package/dist/runtime/inter-dialog-format.js +24 -12
  22. package/dist/runtime/reply-prompt-copy.d.ts +8 -8
  23. package/dist/runtime/reply-prompt-copy.js +69 -38
  24. package/dist/server/certificates.js +65 -25
  25. package/dist/server/network-hosts.js +42 -29
  26. package/dist/server.js +4 -4
  27. package/dist/tools/mcp.js +12 -12
  28. package/dist/tools/prompts/control/en/index.md +2 -2
  29. package/dist/tools/prompts/control/en/principles.md +12 -12
  30. package/dist/tools/prompts/control/en/scenarios.md +5 -5
  31. package/dist/tools/prompts/control/en/tools.md +10 -10
  32. package/dist/tools/prompts/control/zh/index.md +3 -3
  33. package/dist/tools/prompts/control/zh/principles.md +12 -12
  34. package/dist/tools/prompts/control/zh/scenarios.md +7 -7
  35. package/dist/tools/prompts/control/zh/tools.md +11 -11
  36. package/dist/tools/prompts/mcp_admin/en/principles.md +4 -4
  37. package/dist/tools/prompts/mcp_admin/en/scenarios.md +1 -1
  38. package/dist/tools/prompts/mcp_admin/en/tools.md +3 -3
  39. package/dist/tools/prompts/mcp_admin/zh/principles.md +4 -4
  40. package/dist/tools/prompts/mcp_admin/zh/scenarios.md +1 -1
  41. package/dist/tools/prompts/mcp_admin/zh/tools.md +3 -3
  42. package/dist/tools/team_mgmt-mcp-manual.js +12 -12
  43. package/package.json +3 -2
  44. package/webapp/dist/assets/{_basePickBy-DUivPKf7.js → _basePickBy-DTJFxmut.js} +3 -3
  45. package/webapp/dist/assets/{_basePickBy-DUivPKf7.js.map → _basePickBy-DTJFxmut.js.map} +1 -1
  46. package/webapp/dist/assets/{_baseUniq-hcs024vD.js → _baseUniq-CVu4lo4P.js} +2 -2
  47. package/webapp/dist/assets/{_baseUniq-hcs024vD.js.map → _baseUniq-CVu4lo4P.js.map} +1 -1
  48. package/webapp/dist/assets/{arc-Dr6-FXp5.js → arc-4mEKx1Qr.js} +2 -2
  49. package/webapp/dist/assets/{arc-Dr6-FXp5.js.map → arc-4mEKx1Qr.js.map} +1 -1
  50. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-DXqcDq4R.js → architectureDiagram-2XIMDMQ5-CmUkdSiN.js} +7 -7
  51. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-DXqcDq4R.js.map → architectureDiagram-2XIMDMQ5-CmUkdSiN.js.map} +1 -1
  52. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-IIP6LGXS.js → blockDiagram-WCTKOSBZ-CijmZ89y.js} +7 -7
  53. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-IIP6LGXS.js.map → blockDiagram-WCTKOSBZ-CijmZ89y.js.map} +1 -1
  54. package/webapp/dist/assets/{c4Diagram-IC4MRINW-D_d3F9XD.js → c4Diagram-IC4MRINW-D0GcQMKs.js} +3 -3
  55. package/webapp/dist/assets/{c4Diagram-IC4MRINW-D_d3F9XD.js.map → c4Diagram-IC4MRINW-D0GcQMKs.js.map} +1 -1
  56. package/webapp/dist/assets/{channel-CWWjsXtU.js → channel-6pgfGez4.js} +2 -2
  57. package/webapp/dist/assets/{channel-CWWjsXtU.js.map → channel-6pgfGez4.js.map} +1 -1
  58. package/webapp/dist/assets/{chunk-4BX2VUAB-BF4yph2W.js → chunk-4BX2VUAB-BQDAaqXK.js} +2 -2
  59. package/webapp/dist/assets/{chunk-4BX2VUAB-BF4yph2W.js.map → chunk-4BX2VUAB-BQDAaqXK.js.map} +1 -1
  60. package/webapp/dist/assets/{chunk-55IACEB6-Hn3CmDYz.js → chunk-55IACEB6-DGYbZ_6j.js} +2 -2
  61. package/webapp/dist/assets/{chunk-55IACEB6-Hn3CmDYz.js.map → chunk-55IACEB6-DGYbZ_6j.js.map} +1 -1
  62. package/webapp/dist/assets/{chunk-FMBD7UC4-C05pl9Ov.js → chunk-FMBD7UC4-EVNnQ_SU.js} +2 -2
  63. package/webapp/dist/assets/{chunk-FMBD7UC4-C05pl9Ov.js.map → chunk-FMBD7UC4-EVNnQ_SU.js.map} +1 -1
  64. package/webapp/dist/assets/{chunk-JSJVCQXG-BVlq_BAS.js → chunk-JSJVCQXG-BSQe2NHw.js} +2 -2
  65. package/webapp/dist/assets/{chunk-JSJVCQXG-BVlq_BAS.js.map → chunk-JSJVCQXG-BSQe2NHw.js.map} +1 -1
  66. package/webapp/dist/assets/{chunk-KX2RTZJC-BQoaRWif.js → chunk-KX2RTZJC-I1LMYfrr.js} +2 -2
  67. package/webapp/dist/assets/{chunk-KX2RTZJC-BQoaRWif.js.map → chunk-KX2RTZJC-I1LMYfrr.js.map} +1 -1
  68. package/webapp/dist/assets/{chunk-NQ4KR5QH-0okCAXtW.js → chunk-NQ4KR5QH-C9HmN9dA.js} +4 -4
  69. package/webapp/dist/assets/{chunk-NQ4KR5QH-0okCAXtW.js.map → chunk-NQ4KR5QH-C9HmN9dA.js.map} +1 -1
  70. package/webapp/dist/assets/{chunk-QZHKN3VN-DEiprgz-.js → chunk-QZHKN3VN-73ijGXNd.js} +2 -2
  71. package/webapp/dist/assets/{chunk-QZHKN3VN-DEiprgz-.js.map → chunk-QZHKN3VN-73ijGXNd.js.map} +1 -1
  72. package/webapp/dist/assets/{chunk-WL4C6EOR-B-Xkb3lo.js → chunk-WL4C6EOR-DeVu-9ac.js} +6 -6
  73. package/webapp/dist/assets/{chunk-WL4C6EOR-B-Xkb3lo.js.map → chunk-WL4C6EOR-DeVu-9ac.js.map} +1 -1
  74. package/webapp/dist/assets/{classDiagram-VBA2DB6C-DCCQrdwF.js → classDiagram-VBA2DB6C-2HURCFLk.js} +7 -7
  75. package/webapp/dist/assets/{classDiagram-VBA2DB6C-DCCQrdwF.js.map → classDiagram-VBA2DB6C-2HURCFLk.js.map} +1 -1
  76. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-DCCQrdwF.js → classDiagram-v2-RAHNMMFH-2HURCFLk.js} +7 -7
  77. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-DCCQrdwF.js.map → classDiagram-v2-RAHNMMFH-2HURCFLk.js.map} +1 -1
  78. package/webapp/dist/assets/{clone-Drtik9pk.js → clone-BNPlfGMh.js} +2 -2
  79. package/webapp/dist/assets/{clone-Drtik9pk.js.map → clone-BNPlfGMh.js.map} +1 -1
  80. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-BBWvHErL.js → cose-bilkent-S5V4N54A-BeoZCFA5.js} +2 -2
  81. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-BBWvHErL.js.map → cose-bilkent-S5V4N54A-BeoZCFA5.js.map} +1 -1
  82. package/webapp/dist/assets/{dagre-KLK3FWXG-2qk0ikdt.js → dagre-KLK3FWXG-DYxCt50h.js} +7 -7
  83. package/webapp/dist/assets/{dagre-KLK3FWXG-2qk0ikdt.js.map → dagre-KLK3FWXG-DYxCt50h.js.map} +1 -1
  84. package/webapp/dist/assets/{diagram-E7M64L7V-C1DbHDbf.js → diagram-E7M64L7V-BWxcTI3B.js} +8 -8
  85. package/webapp/dist/assets/{diagram-E7M64L7V-C1DbHDbf.js.map → diagram-E7M64L7V-BWxcTI3B.js.map} +1 -1
  86. package/webapp/dist/assets/{diagram-IFDJBPK2-DToz8zk9.js → diagram-IFDJBPK2-BAIPE4Rn.js} +7 -7
  87. package/webapp/dist/assets/{diagram-IFDJBPK2-DToz8zk9.js.map → diagram-IFDJBPK2-BAIPE4Rn.js.map} +1 -1
  88. package/webapp/dist/assets/{diagram-P4PSJMXO-B9V-tQMe.js → diagram-P4PSJMXO-CvcxPsVp.js} +7 -7
  89. package/webapp/dist/assets/{diagram-P4PSJMXO-B9V-tQMe.js.map → diagram-P4PSJMXO-CvcxPsVp.js.map} +1 -1
  90. package/webapp/dist/assets/{erDiagram-INFDFZHY-CV68FwGf.js → erDiagram-INFDFZHY-BDO90e-f.js} +5 -5
  91. package/webapp/dist/assets/{erDiagram-INFDFZHY-CV68FwGf.js.map → erDiagram-INFDFZHY-BDO90e-f.js.map} +1 -1
  92. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-CW06almb.js → flowDiagram-PKNHOUZH-hd4TorKR.js} +7 -7
  93. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-CW06almb.js.map → flowDiagram-PKNHOUZH-hd4TorKR.js.map} +1 -1
  94. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-C96NncCU.js → ganttDiagram-A5KZAMGK-mID1sFSl.js} +3 -3
  95. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-C96NncCU.js.map → ganttDiagram-A5KZAMGK-mID1sFSl.js.map} +1 -1
  96. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CAuIexWi.js → gitGraphDiagram-K3NZZRJ6-DaA7yodM.js} +8 -8
  97. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CAuIexWi.js.map → gitGraphDiagram-K3NZZRJ6-DaA7yodM.js.map} +1 -1
  98. package/webapp/dist/assets/{graph-CvhwAY6w.js → graph-B86JxOkQ.js} +3 -3
  99. package/webapp/dist/assets/{graph-CvhwAY6w.js.map → graph-B86JxOkQ.js.map} +1 -1
  100. package/webapp/dist/assets/{index-BOO_zFrI.js → index-DYO4ZL8y.js} +369 -389
  101. package/webapp/dist/assets/{index-BOO_zFrI.js.map → index-DYO4ZL8y.js.map} +1 -1
  102. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-C16Sckpz.js → infoDiagram-LFFYTUFH-DxF36W9g.js} +6 -6
  103. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-C16Sckpz.js.map → infoDiagram-LFFYTUFH-DxF36W9g.js.map} +1 -1
  104. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-oNG6I0p3.js → ishikawaDiagram-PHBUUO56-wvAzRzSO.js} +2 -2
  105. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-oNG6I0p3.js.map → ishikawaDiagram-PHBUUO56-wvAzRzSO.js.map} +1 -1
  106. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-437hhFHC.js → journeyDiagram-4ABVD52K-CIBXsttK.js} +5 -5
  107. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-437hhFHC.js.map → journeyDiagram-4ABVD52K-CIBXsttK.js.map} +1 -1
  108. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-DsCV_Tpx.js → kanban-definition-K7BYSVSG-DQTPyM5m.js} +3 -3
  109. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-DsCV_Tpx.js.map → kanban-definition-K7BYSVSG-DQTPyM5m.js.map} +1 -1
  110. package/webapp/dist/assets/{layout-BttZf7fQ.js → layout-BG7IzQAG.js} +5 -5
  111. package/webapp/dist/assets/{layout-BttZf7fQ.js.map → layout-BG7IzQAG.js.map} +1 -1
  112. package/webapp/dist/assets/{linear-B75vD4Ho.js → linear-5XR-mXYw.js} +2 -2
  113. package/webapp/dist/assets/{linear-B75vD4Ho.js.map → linear-5XR-mXYw.js.map} +1 -1
  114. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DA1-XaNi.js → mindmap-definition-YRQLILUH-BwTQE6uN.js} +4 -4
  115. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-DA1-XaNi.js.map → mindmap-definition-YRQLILUH-BwTQE6uN.js.map} +1 -1
  116. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Bx6hUJ4Q.js → pieDiagram-SKSYHLDU-ZYB35zd5.js} +8 -8
  117. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Bx6hUJ4Q.js.map → pieDiagram-SKSYHLDU-ZYB35zd5.js.map} +1 -1
  118. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-zyduIle0.js → quadrantDiagram-337W2JSQ-BM041Q-W.js} +3 -3
  119. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-zyduIle0.js.map → quadrantDiagram-337W2JSQ-BM041Q-W.js.map} +1 -1
  120. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-BgfjyEJM.js → requirementDiagram-Z7DCOOCP-r_xMoroM.js} +4 -4
  121. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-BgfjyEJM.js.map → requirementDiagram-Z7DCOOCP-r_xMoroM.js.map} +1 -1
  122. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-lmOWaczS.js → sankeyDiagram-WA2Y5GQK-Ju2-t24N.js} +2 -2
  123. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-lmOWaczS.js.map → sankeyDiagram-WA2Y5GQK-Ju2-t24N.js.map} +1 -1
  124. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-DqJz-iYI.js → sequenceDiagram-2WXFIKYE-D83Bocd1.js} +4 -4
  125. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-DqJz-iYI.js.map → sequenceDiagram-2WXFIKYE-D83Bocd1.js.map} +1 -1
  126. package/webapp/dist/assets/{stateDiagram-RAJIS63D-CngWYuX-.js → stateDiagram-RAJIS63D-mTmpZzpU.js} +9 -9
  127. package/webapp/dist/assets/{stateDiagram-RAJIS63D-CngWYuX-.js.map → stateDiagram-RAJIS63D-mTmpZzpU.js.map} +1 -1
  128. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-BxyHvrvU.js → stateDiagram-v2-FVOUBMTO-BCn7mFeH.js} +5 -5
  129. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-BxyHvrvU.js.map → stateDiagram-v2-FVOUBMTO-BCn7mFeH.js.map} +1 -1
  130. package/webapp/dist/assets/{timeline-definition-YZTLITO2-C7t6WVS3.js → timeline-definition-YZTLITO2-C1QBcYz8.js} +3 -3
  131. package/webapp/dist/assets/{timeline-definition-YZTLITO2-C7t6WVS3.js.map → timeline-definition-YZTLITO2-C1QBcYz8.js.map} +1 -1
  132. package/webapp/dist/assets/{treemap-KZPCXAKY-BDZ3n5TC.js → treemap-KZPCXAKY-BEyfK-Fo.js} +5 -5
  133. package/webapp/dist/assets/{treemap-KZPCXAKY-BDZ3n5TC.js.map → treemap-KZPCXAKY-BEyfK-Fo.js.map} +1 -1
  134. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-CEw7GPed.js → vennDiagram-LZ73GAT5-C6SZhLMq.js} +2 -2
  135. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-CEw7GPed.js.map → vennDiagram-LZ73GAT5-C6SZhLMq.js.map} +1 -1
  136. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-DmS8BiaA.js → xychartDiagram-JWTSCODW-BUlvexnm.js} +3 -3
  137. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-DmS8BiaA.js.map → xychartDiagram-JWTSCODW-BUlvexnm.js.map} +1 -1
  138. package/webapp/dist/index.html +1 -1
package/README.md CHANGED
@@ -257,6 +257,8 @@ Platform note:
257
257
 
258
258
  Dominds always keeps an HTTP listener. When a valid certificate matching the current `--host` exists under `~/.dominds/certs/`, Dominds also starts HTTPS. Certificates match DNS/IP hostnames, not ports, so one certificate covers all Dominds WebUI ports on that host.
259
259
 
260
+ Dominds generates certificates through npm dependencies, so no separate `openssl` command is required.
261
+
260
262
  ```bash
261
263
  # Create a 10-year self-signed certificate for detected non-loopback LAN hosts
262
264
  dominds cert create
package/README.zh.md CHANGED
@@ -196,6 +196,8 @@ dominds
196
196
 
197
197
  Dominds 默认始终提供 HTTP 监听;当 `~/.dominds/certs/` 下存在匹配当前 `--host` 的有效证书时,会额外启用 HTTPS。证书按 DNS/IP 主机名匹配,不绑定端口,因此同一张证书可覆盖该主机上的所有 Dominds WebUI 端口。
198
198
 
199
+ 证书由 Dominds 通过 npm 依赖生成,无需额外安装 `openssl` 等系统命令。
200
+
199
201
  ```bash
200
202
  # 自动为检测到的一个或多个非 loopback LAN 主机创建 10 年有效的自签名证书
201
203
  dominds cert create
package/dist/cli/webui.js CHANGED
@@ -164,17 +164,19 @@ async function main(args = process.argv.slice(2)) {
164
164
  host: started.urlHost,
165
165
  port: started.port,
166
166
  })}`);
167
+ let httpsEndpoint;
167
168
  if (started.httpsPort !== undefined && started.httpsUrlHost !== undefined) {
169
+ httpsEndpoint = { host: started.httpsUrlHost, port: started.httpsPort };
168
170
  const httpsBaseUrl = (0, auth_1.formatServerOrigin)({
169
171
  scheme: 'https',
170
- host: started.httpsUrlHost,
171
- port: started.httpsPort,
172
+ host: httpsEndpoint.host,
173
+ port: httpsEndpoint.port,
172
174
  });
173
175
  log.info(`HTTPS WebUI ready: ${httpsBaseUrl}`);
174
176
  log.debug(`HTTPS WebSocket endpoint: ${formatWebSocketEndpoint({
175
177
  scheme: 'wss',
176
- host: started.httpsUrlHost,
177
- port: started.httpsPort,
178
+ host: httpsEndpoint.host,
179
+ port: httpsEndpoint.port,
178
180
  })}`);
179
181
  }
180
182
  if (auth.kind === 'enabled') {
@@ -185,6 +187,14 @@ async function main(args = process.argv.slice(2)) {
185
187
  authKey: auth.key,
186
188
  });
187
189
  log.info(`auto auth url (sensitive): ${autoAuthUrl}`);
190
+ if (httpsEndpoint !== undefined) {
191
+ log.info(`HTTPS auto auth url (sensitive): ${(0, auth_1.formatAutoAuthUrl)({
192
+ scheme: 'https',
193
+ host: httpsEndpoint.host,
194
+ port: httpsEndpoint.port,
195
+ authKey: auth.key,
196
+ })}`);
197
+ }
188
198
  if (shouldOpen) {
189
199
  log.debug(`Opening browser: ${autoAuthUrl}`);
190
200
  openInBrowser(autoAuthUrl);
@@ -153,7 +153,7 @@ dominds cert create [--host <host>] [--days <days>] [--force]
153
153
  dominds cert status [--host <host>] [--port <port>] [--origin]
154
154
  ```
155
155
 
156
- Create or inspect local HTTPS certificates for the Dominds WebUI. Certificates live in `~/.dominds/certs/` and match DNS/IP hostnames, not ports; one certificate covers every WebUI port on that host.
156
+ Create or inspect local HTTPS certificates for the Dominds WebUI. Dominds generates certificates through npm dependencies, so no separate `openssl` command is required. Certificates live in `~/.dominds/certs/` and match DNS/IP hostnames, not ports; one certificate covers every WebUI port on that host.
157
157
 
158
158
  **Options:**
159
159
 
@@ -160,7 +160,7 @@ dominds cert create [--host <host>] [--days <days>] [--force]
160
160
  dominds cert status [--host <host>] [--port <port>] [--origin]
161
161
  ```
162
162
 
163
- 创建或检查 Dominds WebUI 的本机 HTTPS 证书。证书保存在 `~/.dominds/certs/`,按 DNS/IP 主机名匹配,不绑定端口;同一张证书可覆盖该主机上的所有 WebUI 端口。
163
+ 创建或检查 Dominds WebUI 的本机 HTTPS 证书。证书由 Dominds 通过 npm 依赖生成,无需额外安装 `openssl` 等系统命令。证书保存在 `~/.dominds/certs/`,按 DNS/IP 主机名匹配,不绑定端口;同一张证书可覆盖该主机上的所有 WebUI 端口。
164
164
 
165
165
  **选项:**
166
166
 
@@ -326,9 +326,17 @@ class MockGen {
326
326
  if (trimmed !== '') {
327
327
  variants.add(trimmed.toLowerCase());
328
328
  }
329
- const tellaskStatusIndexZh = trimmed.lastIndexOf('\n[Dominds 诉请状态]\n');
330
- const tellaskStatusIndexEn = trimmed.lastIndexOf('\n[Dominds tellask status]\n');
331
- const tellaskStatusIndex = Math.max(tellaskStatusIndexZh, tellaskStatusIndexEn);
329
+ const tellaskStatusPrefixes = [
330
+ '\n[Dominds 诉请状态]\n',
331
+ '\n[Dominds tellask status]\n',
332
+ '\n[Dominds 等待人类回复]\n',
333
+ '\n[Dominds waiting for human answer]\n',
334
+ '\n[Dominds 等待队友回贴]\n',
335
+ '\n[Dominds waiting for teammate reply]\n',
336
+ '\n[Dominds 队友回贴状态]\n',
337
+ '\n[Dominds teammate reply status]\n',
338
+ ];
339
+ const tellaskStatusIndex = Math.max(...tellaskStatusPrefixes.map((prefix) => trimmed.lastIndexOf(prefix)));
332
340
  if (tellaskStatusIndex >= 0) {
333
341
  const strippedTellaskStatus = trimmed.slice(0, tellaskStatusIndex).trim();
334
342
  if (strippedTellaskStatus !== '') {
@@ -7,6 +7,7 @@ export type KernelDriverContextHealthDecision = Readonly<{
7
7
  }>;
8
8
  export declare const KERNEL_DRIVER_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = 5;
9
9
  export declare const KERNEL_DRIVER_DEFAULT_CAUTION_REMEDIATION_CADENCE_GENERATIONS = 10;
10
+ export declare function getContextHealthRemediationLevel(snapshot: ContextHealthSnapshot | undefined): 'caution' | 'critical' | undefined;
10
11
  export declare function resetContextHealthRoundState(dialogKey: string): void;
11
12
  export declare function resolveCriticalCountdownRemaining(dialogKey: string, snapshot: ContextHealthSnapshot | undefined): number;
12
13
  export declare function consumeCriticalCountdown(dialogKey: string): number;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KERNEL_DRIVER_DEFAULT_CAUTION_REMEDIATION_CADENCE_GENERATIONS = exports.KERNEL_DRIVER_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = void 0;
4
+ exports.getContextHealthRemediationLevel = getContextHealthRemediationLevel;
4
5
  exports.resetContextHealthRoundState = resetContextHealthRoundState;
5
6
  exports.resolveCriticalCountdownRemaining = resolveCriticalCountdownRemaining;
6
7
  exports.consumeCriticalCountdown = consumeCriticalCountdown;
@@ -9,6 +10,12 @@ exports.decideKernelDriverContextHealth = decideKernelDriverContextHealth;
9
10
  exports.KERNEL_DRIVER_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = 5;
10
11
  exports.KERNEL_DRIVER_DEFAULT_CAUTION_REMEDIATION_CADENCE_GENERATIONS = 10;
11
12
  const stateByDialogKey = new Map();
13
+ function getContextHealthRemediationLevel(snapshot) {
14
+ if (snapshot?.kind !== 'available') {
15
+ return undefined;
16
+ }
17
+ return snapshot.level === 'caution' || snapshot.level === 'critical' ? snapshot.level : undefined;
18
+ }
12
19
  function getOrCreateState(dialogKey) {
13
20
  const existing = stateByDialogKey.get(dialogKey);
14
21
  if (existing)
@@ -34,6 +34,7 @@ const context_health_1 = require("./context-health");
34
34
  const events_1 = require("./events");
35
35
  const fbr_1 = require("./fbr");
36
36
  const guardrails_1 = require("./guardrails");
37
+ const reminder_context_1 = require("./reminder-context");
37
38
  const reply_guidance_1 = require("./reply-guidance");
38
39
  const runtime_1 = require("./runtime");
39
40
  const tellask_special_1 = require("./tellask-special");
@@ -254,31 +255,29 @@ function isUserOriginPrompt(prompt) {
254
255
  return false;
255
256
  return prompt.origin === 'user' && normalizeQ4HAnswerCallId(prompt.q4hAnswerCallId) === undefined;
256
257
  }
257
- function resolveReminderContextFollowingDialogState(prompt, currentTurnDialogMsgsForContext) {
258
- if (prompt === undefined || currentTurnDialogMsgsForContext.length === 0)
259
- return 'none';
260
- return prompt.origin === 'user' ? 'user_message' : 'runtime_notice';
261
- }
262
- function resolveReminderContextHealthState(snapshot) {
263
- const remediationLevel = getContextHealthRemediationLevel(snapshot);
264
- return remediationLevel === undefined ? 'normal' : remediationLevel;
265
- }
266
258
  async function resolveReminderContextFooterState(args) {
267
259
  const latest = await persistence_1.DialogPersistence.loadDialogLatest(args.dlg.id, args.dlg.status);
268
260
  const deferredReplyReassertion = latest?.deferredReplyReassertion;
269
261
  const activeReplyObligation = await persistence_1.DialogPersistence.loadActiveTellaskReplyObligation(args.dlg.id, args.dlg.status);
270
262
  const pendingUserInterjectionReply = latest?.pendingUserInterjectionReply !== undefined;
271
- const interDialogReplyObligation = deferredReplyReassertion?.reason === 'user_interjection_with_parked_original_task'
272
- ? 'parked_by_user_interjection'
273
- : activeReplyObligation !== undefined
274
- ? 'active'
275
- : 'none';
276
- return {
277
- followingDialogState: resolveReminderContextFollowingDialogState(args.prompt, args.currentTurnDialogMsgsForContext),
263
+ const hasDeferredReplyReassertion = deferredReplyReassertion?.reason === 'user_interjection_with_parked_original_task';
264
+ const hasActiveReplyObligation = activeReplyObligation !== undefined;
265
+ // Business scenario: a user can reopen a completed Side Dialog to ask a follow-up. A recorded
266
+ // final response with no active/parked reply task means the old handoff has already been
267
+ // reported back; if a real user message is now present, the footer should say "talk with the
268
+ // user now" instead of making the model infer that from old transcript/reminder context.
269
+ const hasCompletedHandoffWithoutPendingReply = latest?.sideDialogFinalResponse !== undefined &&
270
+ !hasDeferredReplyReassertion &&
271
+ !hasActiveReplyObligation;
272
+ return (0, reminder_context_1.resolveReminderContextFooterStateFromSignals)({
273
+ prompt: args.prompt,
274
+ currentTurnDialogMsgsForContext: args.currentTurnDialogMsgsForContext,
275
+ contextHealth: args.dlg.getLastContextHealth(),
278
276
  pendingUserInterjectionReply,
279
- interDialogReplyObligation,
280
- contextHealthState: resolveReminderContextHealthState(args.dlg.getLastContextHealth()),
281
- };
277
+ hasCompletedHandoffWithoutPendingReply,
278
+ hasDeferredReplyReassertion,
279
+ hasActiveReplyObligation,
280
+ });
282
281
  }
283
282
  function splitDialogMsgsForReminderInsertion(args) {
284
283
  const msgId = args.currentPrompt?.msgId;
@@ -722,12 +721,6 @@ const TELLASK_SPECIAL_VIRTUAL_TOOLS = [
722
721
  const CONTEXT_HEALTH_TOOL_RESULT_VISIBLE_BYTE_LIMIT = 2000;
723
722
  const CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_ZH = '这次函数返回内容太大,清理头脑之前不会显示给你。';
724
723
  const CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_EN = 'This function returned too much content. It will not be shown to you before you clear your mind.';
725
- function getContextHealthRemediationLevel(snapshot) {
726
- if (snapshot?.kind !== 'available') {
727
- return undefined;
728
- }
729
- return snapshot.level === 'caution' || snapshot.level === 'critical' ? snapshot.level : undefined;
730
- }
731
724
  function pickContextHealthForLargeToolResultVisibility(args) {
732
725
  if (args.current?.kind === 'available') {
733
726
  return args.current;
@@ -809,7 +802,7 @@ function countToolResultVisibleBytes(output) {
809
802
  return bytes;
810
803
  }
811
804
  function applyContextHealthToolResultVisibilityLimit(args) {
812
- if (getContextHealthRemediationLevel(args.contextHealth) === undefined) {
805
+ if ((0, context_health_1.getContextHealthRemediationLevel)(args.contextHealth) === undefined) {
813
806
  return { output: args.output, largeReturnUnavailable: false };
814
807
  }
815
808
  const visibleBytes = countToolResultVisibleBytes(args.output);
@@ -1336,7 +1329,7 @@ function formatInvalidFuncCallRuntimeGuide(language, call) {
1336
1329
  const indexLine = call.toolCallIndex === undefined ? undefined : `- toolCallIndex: ${String(call.toolCallIndex)}`;
1337
1330
  if (language === 'en') {
1338
1331
  return [
1339
- '[Runtime notice] The previous model output contained an invalid tool-call payload that could not be represented as a normal provider tool call in the next generation context.',
1332
+ '[Runtime notice] Your previous response tried to call a tool, but the tool call was malformed and could not be run.',
1340
1333
  '',
1341
1334
  `- provider: ${call.provider}`,
1342
1335
  `- callId: ${call.callId}`,
@@ -1348,13 +1341,13 @@ function formatInvalidFuncCallRuntimeGuide(language, call) {
1348
1341
  '```',
1349
1342
  ...(indexLine === undefined ? [] : [indexLine]),
1350
1343
  '',
1351
- 'Treat that payload as failed. Do not assume the tool ran. Continue from the current task, and if a tool call is still needed, emit a new valid tool call with a non-empty function name and valid arguments.',
1344
+ 'Treat that tool call as failed. Do not assume the tool ran. Continue the current task; if you still need a tool, call it again with a real tool name and valid arguments.',
1352
1345
  ]
1353
1346
  .filter((line) => line.length > 0)
1354
1347
  .join('\n');
1355
1348
  }
1356
1349
  return [
1357
- '[运行时提示] 上一轮模型输出包含一个无效工具调用载荷,无法按正常 provider tool call 形态进入下一轮生成上下文。',
1350
+ '[Dominds 提示] 你上一轮尝试调用工具,但工具调用格式无效,Dominds 没有执行它。',
1358
1351
  '',
1359
1352
  `- provider: ${call.provider}`,
1360
1353
  `- callId: ${call.callId}`,
@@ -1366,7 +1359,7 @@ function formatInvalidFuncCallRuntimeGuide(language, call) {
1366
1359
  '```',
1367
1360
  ...(indexLine === undefined ? [] : [indexLine]),
1368
1361
  '',
1369
- '请把该载荷视为调用失败,不要假设工具已经执行。继续当前任务;如果仍需要调用工具,请重新发起一个函数名非空、参数有效的新工具调用。',
1362
+ '请把这次工具调用视为失败,不要假设工具已经执行。继续当前任务;如果仍需要工具,请重新发起一次工具名明确、参数有效的调用。',
1370
1363
  ]
1371
1364
  .filter((line) => line.length > 0)
1372
1365
  .join('\n');
@@ -89,15 +89,19 @@ function buildAggregatedWakePromptContent(events) {
89
89
  return `${String(index + 1)}. ${eventText}`;
90
90
  })
91
91
  .join('\n\n');
92
+ // Business scenario: several reminder/environment wakes arrived while the dialog was idle.
93
+ // The model needs the events as state updates, but they are not a new human request and should
94
+ // not trigger a standalone acknowledgement. Say the product meaning plainly instead of exposing
95
+ // internal "runtime event" wording.
92
96
  return language === 'zh'
93
97
  ? `${prefix}
94
- 以下是对话空闲期间发生的 runtime 环境事件。这些事件不是新的用户指令。
98
+ 以下是对话空闲期间 Dominds 收到的环境事件。这些事件不是新的用户指令。
95
99
 
96
100
  ${body}
97
101
 
98
102
  请结合当前任务上下文继续推进;若这些事件不影响当前工作,不要发送占位式确认。`
99
103
  : `${prefix}
100
- The following runtime environment events happened while the dialog was idle. These events are not new user instructions.
104
+ The following environment events reached Dominds while the dialog was idle. These events are not new user instructions.
101
105
 
102
106
  ${body}
103
107
 
@@ -0,0 +1,25 @@
1
+ import type { ContextHealthSnapshot } from '@longrun-ai/kernel/types/context-health';
2
+ import type { ReminderContextBusiness, ReminderContextFollowingMessage, ReminderContextFooterState, ReminderContextHealth } from '../../runtime/driver-messages';
3
+ import type { ChatMessage } from '../client';
4
+ import type { KernelDriverPrompt } from './types';
5
+ export declare function resolveReminderContextFollowingMessage(args: {
6
+ prompt: KernelDriverPrompt | undefined;
7
+ currentTurnDialogMsgsForContext: readonly ChatMessage[];
8
+ }): ReminderContextFollowingMessage;
9
+ export declare function resolveReminderContextHealth(snapshot: ContextHealthSnapshot | undefined): ReminderContextHealth;
10
+ export declare function resolveReminderContextBusinessState(args: {
11
+ followingMessage: ReminderContextFollowingMessage;
12
+ pendingUserInterjectionReply: boolean;
13
+ hasCompletedHandoffWithoutPendingReply: boolean;
14
+ hasDeferredReplyReassertion: boolean;
15
+ hasActiveReplyObligation: boolean;
16
+ }): ReminderContextBusiness;
17
+ export declare function resolveReminderContextFooterStateFromSignals(args: {
18
+ prompt: KernelDriverPrompt | undefined;
19
+ currentTurnDialogMsgsForContext: readonly ChatMessage[];
20
+ contextHealth: ContextHealthSnapshot | undefined;
21
+ pendingUserInterjectionReply: boolean;
22
+ hasCompletedHandoffWithoutPendingReply: boolean;
23
+ hasDeferredReplyReassertion: boolean;
24
+ hasActiveReplyObligation: boolean;
25
+ }): ReminderContextFooterState;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveReminderContextFollowingMessage = resolveReminderContextFollowingMessage;
4
+ exports.resolveReminderContextHealth = resolveReminderContextHealth;
5
+ exports.resolveReminderContextBusinessState = resolveReminderContextBusinessState;
6
+ exports.resolveReminderContextFooterStateFromSignals = resolveReminderContextFooterStateFromSignals;
7
+ const context_health_1 = require("./context-health");
8
+ function resolveReminderContextFollowingMessage(args) {
9
+ if (args.prompt === undefined || args.currentTurnDialogMsgsForContext.length === 0) {
10
+ return { kind: 'none' };
11
+ }
12
+ if (args.prompt.origin !== 'user') {
13
+ return { kind: 'runtime_notice' };
14
+ }
15
+ return typeof args.prompt.q4hAnswerCallId === 'string' &&
16
+ args.prompt.q4hAnswerCallId.trim() !== ''
17
+ ? { kind: 'human_answer' }
18
+ : { kind: 'user_message' };
19
+ }
20
+ function resolveReminderContextHealth(snapshot) {
21
+ const remediationLevel = (0, context_health_1.getContextHealthRemediationLevel)(snapshot);
22
+ return remediationLevel === undefined ? { kind: 'normal' } : { kind: remediationLevel };
23
+ }
24
+ function resolveReminderContextBusinessState(args) {
25
+ if (args.followingMessage.kind === 'human_answer') {
26
+ // askHuman answers resume a waiting task. They are not fresh user follow-ups and should not
27
+ // inherit interjection or completed-handoff wording from adjacent durable state.
28
+ return { kind: 'none' };
29
+ }
30
+ if (args.followingMessage.kind === 'user_message' &&
31
+ args.hasCompletedHandoffWithoutPendingReply) {
32
+ // Business scenario: the requester-side work has already received its final report, and now a
33
+ // user is speaking again inside that completed Side Dialog. Dominds can know this from durable
34
+ // handoff state; the model should hear the simple product meaning directly instead of guessing
35
+ // from older task context or reminder-maintenance references.
36
+ return { kind: 'user_followup_after_completed_handoff' };
37
+ }
38
+ if (args.pendingUserInterjectionReply) {
39
+ // User-visible reply gaps take priority over handoff continuation state. The completed
40
+ // handoff case is most specific: Dominds already knows the old delegated task is done. The
41
+ // footer should say there is no old handoff to advance and the model should handle the current
42
+ // user message normally. Do not narrow this to "only answer" or "do not organize reminders":
43
+ // a user may explicitly ask for reminder cleanup/correction as the current conversation topic.
44
+ //
45
+ // This branch may run on a later tool-followup turn where no user message immediately
46
+ // follows the reminder block anymore. That is still the same pending user follow-up; do not
47
+ // demote it to generic auto-continuation wording just because the prompt itself is absent
48
+ // on this retry/continuation round.
49
+ if (args.hasCompletedHandoffWithoutPendingReply) {
50
+ return { kind: 'user_followup_after_completed_handoff' };
51
+ }
52
+ if (args.hasDeferredReplyReassertion) {
53
+ return { kind: 'pending_user_interjection_with_parked_reply' };
54
+ }
55
+ if (args.hasActiveReplyObligation) {
56
+ return { kind: 'pending_user_interjection_with_active_reply' };
57
+ }
58
+ return { kind: 'pending_user_interjection' };
59
+ }
60
+ if (args.hasActiveReplyObligation) {
61
+ return { kind: 'active_reply_obligation' };
62
+ }
63
+ return { kind: 'none' };
64
+ }
65
+ function resolveReminderContextFooterStateFromSignals(args) {
66
+ const followingMessage = resolveReminderContextFollowingMessage({
67
+ prompt: args.prompt,
68
+ currentTurnDialogMsgsForContext: args.currentTurnDialogMsgsForContext,
69
+ });
70
+ return {
71
+ followingMessage,
72
+ contextHealth: resolveReminderContextHealth(args.contextHealth),
73
+ business: resolveReminderContextBusinessState({
74
+ followingMessage,
75
+ pendingUserInterjectionReply: args.pendingUserInterjectionReply,
76
+ hasCompletedHandoffWithoutPendingReply: args.hasCompletedHandoffWithoutPendingReply,
77
+ hasDeferredReplyReassertion: args.hasDeferredReplyReassertion,
78
+ hasActiveReplyObligation: args.hasActiveReplyObligation,
79
+ }),
80
+ };
81
+ }
@@ -38,6 +38,12 @@ function buildPromptContentWithExactReplyToolName(args) {
38
38
  ];
39
39
  const directive = args.activeReplyDirective;
40
40
  if (!directive) {
41
+ // Business scenario: a user can come back to a Side Dialog after its final reply has already
42
+ // been delivered to the requester. At that point the business obligation is complete and the
43
+ // visible user is simply asking a follow-up in this dialog. Old assignment text and reply tool
44
+ // names remain in transcript history, so the model may otherwise "finish" the old request
45
+ // again. Dominds has already checked durable reply state here; the prompt says the current
46
+ // business expectation directly: answer/continue this conversation normally.
41
47
  if (isFbrSideDialog) {
42
48
  return args.prompt.content;
43
49
  }
@@ -50,13 +56,13 @@ function buildPromptContentWithExactReplyToolName(args) {
50
56
  const note = args.language === 'zh'
51
57
  ? [
52
58
  noActivePrefix,
53
- '当前没有待完成的跨对话回复义务。',
54
- '这轮不要调用任何 `reply*`;直接按当前本地对话继续即可。',
59
+ 'Dominds 已经判断好:当前没有别的对话在等你发送最终回贴。',
60
+ '本轮按当前对话正常交流即可;如果用户提出了问题,就直接回答这个问题。',
55
61
  ].join('\n')
56
62
  : [
57
63
  noActivePrefix,
58
- 'There is no active inter-dialog reply obligation right now.',
59
- 'Do not call any `reply*` tool in this turn; just continue the current local conversation.',
64
+ 'Dominds has already decided that no other dialog is waiting for your final reply right now.',
65
+ 'Handle this as a normal turn in the current conversation; if the user asked a question, answer that question directly.',
60
66
  ].join('\n');
61
67
  return `${note}\n\n${args.prompt.content}`;
62
68
  }
@@ -40,7 +40,7 @@ const TELLASK_SPECIAL_FUNCTION_NAMES = [
40
40
  'freshBootsReasoning',
41
41
  ];
42
42
  const MULTIPLE_ASKHUMAN_CALLS_ERROR = '不允许一轮多次调用 askHuman,必须单次调用问所有问题。 Do not call askHuman multiple times in one round; ask all questions in a single askHuman call.';
43
- const MULTIPLE_REPLY_TELLASK_CALLS_ERROR = '不允许一轮多次调用 replyTellask*,必须只用当前诉请要求的唯一 reply special 完成交付。 Do not call multiple replyTellask* functions in one round; deliver with exactly one reply special required by the current tellask.';
43
+ const MULTIPLE_REPLY_TELLASK_CALLS_ERROR = '不允许一轮多次调用回复工具;只能用当前诉请要求的那个回复工具发送最终结果。 Do not call multiple reply tools in one round; send the final result with the one reply tool required by the current tellask.';
44
44
  function isTellaskCallFunctionName(name) {
45
45
  return TELLASK_SPECIAL_FUNCTION_NAMES.includes(name);
46
46
  }
@@ -63,6 +63,11 @@ function formatReplyFuncResult(args) {
63
63
  ? `已通过 \`${args.replyCallName}\` 送达回复。`
64
64
  : `Reply delivered via \`${args.replyCallName}\`.`;
65
65
  }
66
+ // Business scenario: the model called a reply tool when Dominds durable state says either "wrong
67
+ // reply path" or "nothing is waiting for this reply anymore". These are programmatic facts from the
68
+ // active reply record, not something the model should infer from transcript history. Keep the
69
+ // tool result actionable: name the exact tool to use, or tell the model to stop trying to send a
70
+ // reply and continue the current local conversation.
66
71
  function formatReplyFuncErrorResult(args) {
67
72
  const language = (0, work_language_1.getWorkLanguage)();
68
73
  if (language === 'zh') {
@@ -74,11 +79,11 @@ function formatReplyFuncErrorResult(args) {
74
79
  return (`错误:当前精确应调用 \`${args.expectedCallName}\`,而不是 \`${args.attemptedCallName}\`。\n\n` +
75
80
  `请改用 \`${args.expectedCallName}({ replyContent })\`。`);
76
81
  case 'no_active':
77
- return (`错误:当前没有待完成的跨对话回复义务。\n\n` +
78
- `不要调用 \`${args.attemptedCallName}\`;请直接继续当前本地对话。`);
82
+ return (`错误:当前没有别的对话在等你发送最终回贴。\n\n` +
83
+ `你刚才调用的 \`${args.attemptedCallName}\` 这次不会送达给别的对话。请按当前对话正常交流;如果用户提出了问题,就直接回答这个问题。`);
79
84
  case 'no_pending':
80
- return (`错误:当前已没有待本对话送达的跨对话回复义务(可能已回复或已失效)。\n\n` +
81
- `不要再次调用 \`${args.attemptedCallName}\`;请直接继续当前本地对话。`);
85
+ return (`错误:这条回贴任务已经不再等待本对话送达(可能已回复或已失效)。\n\n` +
86
+ `你刚才调用的 \`${args.attemptedCallName}\` 这次不会送达给别的对话。请按当前对话正常交流;如果用户提出了问题,就直接回答这个问题。`);
82
87
  }
83
88
  }
84
89
  switch (args.reason) {
@@ -89,11 +94,11 @@ function formatReplyFuncErrorResult(args) {
89
94
  return (`Error: the exact reply tool for the current state is \`${args.expectedCallName}\`, not \`${args.attemptedCallName}\`.\n\n` +
90
95
  `Call \`${args.expectedCallName}({ replyContent })\` instead.`);
91
96
  case 'no_active':
92
- return ('Error: there is no active inter-dialog reply obligation right now.\n\n' +
93
- `Do not call \`${args.attemptedCallName}\`; continue the current local conversation instead.`);
97
+ return ('Error: no other dialog is waiting for your final reply right now.\n\n' +
98
+ `Your \`${args.attemptedCallName}\` call will not deliver anything to another dialog this time. Handle this as a normal turn in the current conversation; if the user asked a question, answer that question directly.`);
94
99
  case 'no_pending':
95
- return ('Error: there is no longer a pending inter-dialog reply obligation for this dialog (it may already be resolved or no longer valid).\n\n' +
96
- `Do not call \`${args.attemptedCallName}\` again; continue the current local conversation instead.`);
100
+ return ('Error: this reply task is no longer waiting for delivery from this dialog; it may already be resolved or no longer valid.\n\n' +
101
+ `Your \`${args.attemptedCallName}\` call will not deliver anything to another dialog this time. Handle this as a normal turn in the current conversation; if the user asked a question, answer that question directly.`);
97
102
  }
98
103
  }
99
104
  function buildAssignmentReplyDirective(args) {
@@ -554,49 +559,54 @@ function formatPendingTellaskFuncResultContent(name, startedAtMs, callId) {
554
559
  const elapsedSec = Math.floor(elapsedMs / 1000);
555
560
  return language === 'zh' ? `${elapsedSec} 秒` : `${elapsedSec}s`;
556
561
  })();
562
+ // Business scenario: a tool call has been accepted and dispatched, but no answer has arrived
563
+ // yet. This tool result is a waiting status, not the teammate/human answer body. If the copy
564
+ // exposes only call IDs and "tellask status", models often treat it as a result and continue
565
+ // with invented content. Say plainly who we are waiting for and that Dominds will add the real
566
+ // answer later.
557
567
  if (name === 'askHuman') {
558
568
  return language === 'zh'
559
569
  ? [
560
- '[Dominds 诉请状态]',
570
+ '[Dominds 等待人类回复]',
561
571
  '',
562
- '`askHuman` 诉请已发出,当前仍在等待人类回复。',
572
+ '你已经向人类提问,当前仍在等待回答。',
563
573
  '',
564
574
  ...(callId ? [`- callId: ${callId}`] : []),
565
575
  `- 已等待: ${elapsed}`,
566
576
  '',
567
- '这不是回贴内容。若后续收到回复,运行时会在后续上下文中用同一 callId 补入对应回复事实。',
577
+ '这不是回答正文。若人类稍后回复,Dominds 会把对应结果补入后续上下文。',
568
578
  ].join('\n')
569
579
  : [
570
- '[Dominds tellask status]',
580
+ '[Dominds waiting for human answer]',
571
581
  '',
572
- '`askHuman` has been issued and is still waiting for human reply.',
582
+ 'You already asked the human and are still waiting for their answer.',
573
583
  '',
574
584
  ...(callId ? [`- callId: ${callId}`] : []),
575
585
  `- Elapsed: ${elapsed}`,
576
586
  '',
577
- 'This is not reply content. If a reply arrives later, runtime will append the corresponding reply fact in later context with the same callId.',
587
+ 'This is not the answer body. If the human replies later, Dominds will add the result to later context.',
578
588
  ].join('\n');
579
589
  }
580
590
  return language === 'zh'
581
591
  ? [
582
- '[Dominds 诉请状态]',
592
+ '[Dominds 等待队友回贴]',
583
593
  '',
584
- `\`${name}\` 诉请已发出,当前仍在等待回贴。`,
594
+ `你已经发出 \`${name}\`,当前仍在等待队友回贴。`,
585
595
  '',
586
596
  ...(callId ? [`- callId: ${callId}`] : []),
587
597
  `- 已等待: ${elapsed}`,
588
598
  '',
589
- '这不是回贴内容。若后续收到回贴,运行时会在后续上下文中用同一 callId 补入对应回贴事实。',
599
+ '这不是回贴正文。若稍后收到回贴,Dominds 会把对应结果补入后续上下文。',
590
600
  ].join('\n')
591
601
  : [
592
- '[Dominds tellask status]',
602
+ '[Dominds waiting for teammate reply]',
593
603
  '',
594
- `\`${name}\` has been issued and is still waiting for a reply.`,
604
+ `You already sent \`${name}\` and are still waiting for the teammate's reply.`,
595
605
  '',
596
606
  ...(callId ? [`- callId: ${callId}`] : []),
597
607
  `- Elapsed: ${elapsed}`,
598
608
  '',
599
- 'This is not reply content. If a reply arrives later, runtime will append the corresponding reply fact in later context with the same callId.',
609
+ 'This is not the reply body. If a reply arrives later, Dominds will add the result to later context.',
600
610
  ].join('\n');
601
611
  }
602
612
  function formatResolvedTellaskFuncResultContent(args) {
@@ -605,55 +615,60 @@ function formatResolvedTellaskFuncResultContent(args) {
605
615
  if (callId === '') {
606
616
  throw new Error(`tellask status formatter invariant violation: empty callId for ${args.name}`);
607
617
  }
618
+ // Business scenario: a previously dispatched teammate request is being summarized back into
619
+ // context as status. For `pending`, there is still no reply body. For `completed`/`failed`, the
620
+ // actual reply/failure fact is injected separately. The model-facing text must keep those
621
+ // separate so the model neither hallucinates a pending result nor treats this status line as the
622
+ // teammate's answer.
608
623
  if (language === 'zh') {
609
624
  if (args.status === 'pending') {
610
625
  return [
611
- '[Dominds 诉请状态]',
626
+ '[Dominds 等待队友回贴]',
612
627
  '',
613
- `\`${args.name}\` 诉请仍在等待回贴,当前没有回贴正文。`,
628
+ `\`${args.name}\` 仍在等待队友回贴,当前没有回贴正文。`,
614
629
  '',
615
630
  `- callId: ${callId}`,
616
631
  '',
617
- '不要把本工具结果当作回贴正文;若后续收到回贴,运行时会用同一 callId 补入对应回贴事实。',
632
+ '不要把这条状态当作回贴正文;若稍后收到回贴,Dominds 会补入对应结果。',
618
633
  ].join('\n');
619
634
  }
620
635
  const statusLabel = args.status === 'completed' ? '已收到回贴' : '已失败收口';
621
636
  return [
622
- '[Dominds 诉请状态]',
637
+ '[Dominds 队友回贴状态]',
623
638
  '',
624
- `\`${args.name}\` 诉请${statusLabel},对应回贴事实已作为独立上下文事实补入。`,
639
+ `\`${args.name}\` ${statusLabel},对应结果已作为独立上下文补入。`,
625
640
  '',
626
641
  `- callId: ${callId}`,
627
642
  '',
628
- '请以同一 callId 的独立回贴事实为准;不要把本工具结果当作回贴正文。',
643
+ '请以那条独立结果为准;不要把这条状态当作回贴正文。',
629
644
  ].join('\n');
630
645
  }
631
646
  if (args.status === 'pending') {
632
647
  return [
633
- '[Dominds tellask status]',
648
+ '[Dominds waiting for teammate reply]',
634
649
  '',
635
- `\`${args.name}\` is still waiting for a reply; there is no reply body yet.`,
650
+ `\`${args.name}\` is still waiting for the teammate's reply; there is no reply body yet.`,
636
651
  '',
637
652
  `- callId: ${callId}`,
638
653
  '',
639
- 'Do not treat this tool result as reply content. If a reply arrives later, runtime will append the corresponding reply fact with the same callId.',
654
+ 'Do not treat this status as the reply body. If a reply arrives later, Dominds will add the result.',
640
655
  ].join('\n');
641
656
  }
642
657
  const statusLabel = args.status === 'completed' ? 'has received a reply' : 'has failed/closed';
643
658
  return [
644
- '[Dominds tellask status]',
659
+ '[Dominds teammate reply status]',
645
660
  '',
646
- `\`${args.name}\` ${statusLabel}; the corresponding reply fact is present separately in context.`,
661
+ `\`${args.name}\` ${statusLabel}; the corresponding result is present separately in context.`,
647
662
  '',
648
663
  `- callId: ${callId}`,
649
664
  '',
650
- 'Use the separate reply fact with the same callId as authoritative; do not treat this tool result as reply content.',
665
+ 'Use that separate result as authoritative; do not treat this status as the reply body.',
651
666
  ].join('\n');
652
667
  }
653
668
  function formatResolvedAskHumanResultContent() {
654
669
  return (0, work_language_1.getWorkLanguage)() === 'zh'
655
- ? 'Q4H 已结束等待状态,请参考 askHuman 结果气泡。'
656
- : 'Q4H wait is resolved; refer to the askHuman result bubble.';
670
+ ? '人类已经回答;请参考 askHuman 结果气泡。'
671
+ : 'The human has answered; refer to the askHuman result bubble.';
657
672
  }
658
673
  function buildPendingTellaskFuncResult(args) {
659
674
  return {
@@ -927,14 +927,14 @@ function upsertMcpToolCallProblem(args) {
927
927
  const hintLines = workLanguage === 'zh'
928
928
  ? [
929
929
  '建议排查:',
930
- `- 如果需要全局重建该 MCP server,直接调用 mcp_restart({"serverId":"${args.serverId}"});它成功后会清理旧 runtime 的全部 lease`,
930
+ `- 如果需要全局重建该 MCP server,直接调用 mcp_restart({"serverId":"${args.serverId}"});它成功后会清理旧连接/进程的全部 lease`,
931
931
  `- 如果只想丢弃当前对话的连接,再调用 mcp_release({"serverId":"${args.serverId}"})`,
932
932
  `- 重新打开/关闭浏览器窗口,避免 Playwright persistent context 残留`,
933
933
  `- 查看 ${MCP_YAML_PATH} 是否已加载且配置正确(Problems 面板 / 后端日志)`,
934
934
  ]
935
935
  : [
936
936
  'Suggested checks:',
937
- `- To rebuild this MCP server globally, call mcp_restart({"serverId":"${args.serverId}"}) directly; a successful restart clears all leases on the old runtime`,
937
+ `- To rebuild this MCP server globally, call mcp_restart({"serverId":"${args.serverId}"}) directly; a successful restart clears all leases on the old connection/process`,
938
938
  `- To discard only this dialog's connection, call mcp_release({"serverId":"${args.serverId}"})`,
939
939
  `- Close/reopen browser windows to avoid leftover Playwright persistent contexts`,
940
940
  `- Verify ${MCP_YAML_PATH} is loaded and valid (Problems panel / backend logs)`,