dominds 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/agent-priming.js +162 -24
  2. package/dist/docs/dialog-system.md +18 -16
  3. package/dist/docs/dialog-system.zh.md +20 -19
  4. package/dist/llm/driver-v2/core.js +101 -1
  5. package/dist/llm/driver-v2/orchestrator.js +7 -0
  6. package/dist/llm/driver-v2/round.js +114 -4
  7. package/dist/llm/driver-v2/tellask-bridge.js +29 -2
  8. package/dist/llm/driver.js +54 -2
  9. package/dist/persistence.js +20 -0
  10. package/dist/server/websocket-handler.js +99 -7
  11. package/dist/shared/diligence.js +8 -2
  12. package/dist/static/assets/{_baseUniq-BxKNVs_E.js → _baseUniq-C04fddeD.js} +2 -2
  13. package/dist/static/assets/{_baseUniq-BxKNVs_E.js.map → _baseUniq-C04fddeD.js.map} +1 -1
  14. package/dist/static/assets/{arc-SobL0GO-.js → arc-qmZerooe.js} +2 -2
  15. package/dist/static/assets/{arc-SobL0GO-.js.map → arc-qmZerooe.js.map} +1 -1
  16. package/dist/static/assets/{architectureDiagram-VXUJARFQ-MMDS1QOC.js → architectureDiagram-VXUJARFQ-DPAwJ19g.js} +6 -6
  17. package/dist/static/assets/{architectureDiagram-VXUJARFQ-MMDS1QOC.js.map → architectureDiagram-VXUJARFQ-DPAwJ19g.js.map} +1 -1
  18. package/dist/static/assets/{blockDiagram-VD42YOAC-BOsSirNK.js → blockDiagram-VD42YOAC-M0jbEJ-1.js} +7 -7
  19. package/dist/static/assets/{blockDiagram-VD42YOAC-BOsSirNK.js.map → blockDiagram-VD42YOAC-M0jbEJ-1.js.map} +1 -1
  20. package/dist/static/assets/{c4Diagram-YG6GDRKO-D4jQkzwx.js → c4Diagram-YG6GDRKO-DlF8gwFw.js} +3 -3
  21. package/dist/static/assets/{c4Diagram-YG6GDRKO-D4jQkzwx.js.map → c4Diagram-YG6GDRKO-DlF8gwFw.js.map} +1 -1
  22. package/dist/static/assets/{channel-CNJ5IKbI.js → channel-B2Ph7be3.js} +2 -2
  23. package/dist/static/assets/{channel-CNJ5IKbI.js.map → channel-B2Ph7be3.js.map} +1 -1
  24. package/dist/static/assets/{chunk-4BX2VUAB-Dzp3xxyo.js → chunk-4BX2VUAB-BZ2L6PK1.js} +2 -2
  25. package/dist/static/assets/{chunk-4BX2VUAB-Dzp3xxyo.js.map → chunk-4BX2VUAB-BZ2L6PK1.js.map} +1 -1
  26. package/dist/static/assets/{chunk-55IACEB6-CbmixuSI.js → chunk-55IACEB6-COXFmnJW.js} +2 -2
  27. package/dist/static/assets/{chunk-55IACEB6-CbmixuSI.js.map → chunk-55IACEB6-COXFmnJW.js.map} +1 -1
  28. package/dist/static/assets/{chunk-B4BG7PRW-CdpmYjdb.js → chunk-B4BG7PRW-B1HiWlBq.js} +5 -5
  29. package/dist/static/assets/{chunk-B4BG7PRW-CdpmYjdb.js.map → chunk-B4BG7PRW-B1HiWlBq.js.map} +1 -1
  30. package/dist/static/assets/{chunk-DI55MBZ5-wBUIgR3h.js → chunk-DI55MBZ5-BO3wQRnL.js} +4 -4
  31. package/dist/static/assets/{chunk-DI55MBZ5-wBUIgR3h.js.map → chunk-DI55MBZ5-BO3wQRnL.js.map} +1 -1
  32. package/dist/static/assets/{chunk-FMBD7UC4-l62jcBz-.js → chunk-FMBD7UC4-BdavRHSy.js} +2 -2
  33. package/dist/static/assets/{chunk-FMBD7UC4-l62jcBz-.js.map → chunk-FMBD7UC4-BdavRHSy.js.map} +1 -1
  34. package/dist/static/assets/{chunk-QN33PNHL-BXfKZUpE.js → chunk-QN33PNHL-DchoUNF7.js} +2 -2
  35. package/dist/static/assets/{chunk-QN33PNHL-BXfKZUpE.js.map → chunk-QN33PNHL-DchoUNF7.js.map} +1 -1
  36. package/dist/static/assets/{chunk-QZHKN3VN-BYB4VxWj.js → chunk-QZHKN3VN-Dr3uVTtK.js} +2 -2
  37. package/dist/static/assets/{chunk-QZHKN3VN-BYB4VxWj.js.map → chunk-QZHKN3VN-Dr3uVTtK.js.map} +1 -1
  38. package/dist/static/assets/{chunk-TZMSLE5B-CvlWEnXl.js → chunk-TZMSLE5B-BhOcHZNs.js} +2 -2
  39. package/dist/static/assets/{chunk-TZMSLE5B-CvlWEnXl.js.map → chunk-TZMSLE5B-BhOcHZNs.js.map} +1 -1
  40. package/dist/static/assets/{classDiagram-2ON5EDUG-x2kw_AQY.js → classDiagram-2ON5EDUG-Dep-MR6W.js} +6 -6
  41. package/dist/static/assets/{classDiagram-2ON5EDUG-x2kw_AQY.js.map → classDiagram-2ON5EDUG-Dep-MR6W.js.map} +1 -1
  42. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-x2kw_AQY.js → classDiagram-v2-WZHVMYZB-Dep-MR6W.js} +6 -6
  43. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-x2kw_AQY.js.map → classDiagram-v2-WZHVMYZB-Dep-MR6W.js.map} +1 -1
  44. package/dist/static/assets/{clone-CfBpi3MU.js → clone-DzoL-dSX.js} +2 -2
  45. package/dist/static/assets/{clone-CfBpi3MU.js.map → clone-DzoL-dSX.js.map} +1 -1
  46. package/dist/static/assets/{cose-bilkent-S5V4N54A-DQSzPb7y.js → cose-bilkent-S5V4N54A-Bqu_DqDB.js} +2 -2
  47. package/dist/static/assets/{cose-bilkent-S5V4N54A-DQSzPb7y.js.map → cose-bilkent-S5V4N54A-Bqu_DqDB.js.map} +1 -1
  48. package/dist/static/assets/{dagre-6UL2VRFP-BuBo_U3J.js → dagre-6UL2VRFP-49InNTzs.js} +7 -7
  49. package/dist/static/assets/{dagre-6UL2VRFP-BuBo_U3J.js.map → dagre-6UL2VRFP-49InNTzs.js.map} +1 -1
  50. package/dist/static/assets/{diagram-PSM6KHXK-J2z13Z5A.js → diagram-PSM6KHXK-C1IsQq8m.js} +7 -7
  51. package/dist/static/assets/{diagram-PSM6KHXK-J2z13Z5A.js.map → diagram-PSM6KHXK-C1IsQq8m.js.map} +1 -1
  52. package/dist/static/assets/{diagram-QEK2KX5R-x8XUGykE.js → diagram-QEK2KX5R-DyJeSg_Y.js} +6 -6
  53. package/dist/static/assets/{diagram-QEK2KX5R-x8XUGykE.js.map → diagram-QEK2KX5R-DyJeSg_Y.js.map} +1 -1
  54. package/dist/static/assets/{diagram-S2PKOQOG-BE6Nr1BM.js → diagram-S2PKOQOG-aeLjjldp.js} +6 -6
  55. package/dist/static/assets/{diagram-S2PKOQOG-BE6Nr1BM.js.map → diagram-S2PKOQOG-aeLjjldp.js.map} +1 -1
  56. package/dist/static/assets/{erDiagram-Q2GNP2WA-D3qVnFAh.js → erDiagram-Q2GNP2WA-BUcv4AUq.js} +5 -5
  57. package/dist/static/assets/{erDiagram-Q2GNP2WA-D3qVnFAh.js.map → erDiagram-Q2GNP2WA-BUcv4AUq.js.map} +1 -1
  58. package/dist/static/assets/{flowDiagram-NV44I4VS-Cjp9Rt9t.js → flowDiagram-NV44I4VS-DfmTKlf_.js} +6 -6
  59. package/dist/static/assets/{flowDiagram-NV44I4VS-Cjp9Rt9t.js.map → flowDiagram-NV44I4VS-DfmTKlf_.js.map} +1 -1
  60. package/dist/static/assets/{ganttDiagram-JELNMOA3-D_hc66FC.js → ganttDiagram-JELNMOA3-BpJE8Lhp.js} +3 -3
  61. package/dist/static/assets/{ganttDiagram-JELNMOA3-D_hc66FC.js.map → ganttDiagram-JELNMOA3-BpJE8Lhp.js.map} +1 -1
  62. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-1I_zaTtz.js → gitGraphDiagram-NY62KEGX-DmznjSYb.js} +7 -7
  63. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-1I_zaTtz.js.map → gitGraphDiagram-NY62KEGX-DmznjSYb.js.map} +1 -1
  64. package/dist/static/assets/{graph-K6mmQESm.js → graph-CcKyIZaL.js} +3 -3
  65. package/dist/static/assets/{graph-K6mmQESm.js.map → graph-CcKyIZaL.js.map} +1 -1
  66. package/dist/static/assets/{index-RV1MEt3b.js → index-CQr8MdPI.js} +77 -44
  67. package/dist/static/assets/index-CQr8MdPI.js.map +1 -0
  68. package/dist/static/assets/{infoDiagram-WHAUD3N6-CqazW4ov.js → infoDiagram-WHAUD3N6-DwRPjndM.js} +5 -5
  69. package/dist/static/assets/{infoDiagram-WHAUD3N6-CqazW4ov.js.map → infoDiagram-WHAUD3N6-DwRPjndM.js.map} +1 -1
  70. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CCwUViz2.js → journeyDiagram-XKPGCS4Q-BRAFSgVa.js} +5 -5
  71. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CCwUViz2.js.map → journeyDiagram-XKPGCS4Q-BRAFSgVa.js.map} +1 -1
  72. package/dist/static/assets/{kanban-definition-3W4ZIXB7-BKj9P06Z.js → kanban-definition-3W4ZIXB7-DlJ7-fgN.js} +3 -3
  73. package/dist/static/assets/{kanban-definition-3W4ZIXB7-BKj9P06Z.js.map → kanban-definition-3W4ZIXB7-DlJ7-fgN.js.map} +1 -1
  74. package/dist/static/assets/{layout-BcrPlYah.js → layout-CcW5-Iee.js} +5 -5
  75. package/dist/static/assets/{layout-BcrPlYah.js.map → layout-CcW5-Iee.js.map} +1 -1
  76. package/dist/static/assets/{linear-DYXbzldi.js → linear-sKdPIuOH.js} +2 -2
  77. package/dist/static/assets/{linear-DYXbzldi.js.map → linear-sKdPIuOH.js.map} +1 -1
  78. package/dist/static/assets/{min-CAfJrdkg.js → min-CQ0AYqmk.js} +3 -3
  79. package/dist/static/assets/{min-CAfJrdkg.js.map → min-CQ0AYqmk.js.map} +1 -1
  80. package/dist/static/assets/{mindmap-definition-VGOIOE7T-CXWJYrd0.js → mindmap-definition-VGOIOE7T-CTRwSlu8.js} +4 -4
  81. package/dist/static/assets/{mindmap-definition-VGOIOE7T-CXWJYrd0.js.map → mindmap-definition-VGOIOE7T-CTRwSlu8.js.map} +1 -1
  82. package/dist/static/assets/{pieDiagram-ADFJNKIX-DjKlsPYr.js → pieDiagram-ADFJNKIX-DmD5KRKE.js} +7 -7
  83. package/dist/static/assets/{pieDiagram-ADFJNKIX-DjKlsPYr.js.map → pieDiagram-ADFJNKIX-DmD5KRKE.js.map} +1 -1
  84. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-fcJtlyUO.js → quadrantDiagram-AYHSOK5B-C5sqZOBF.js} +3 -3
  85. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-fcJtlyUO.js.map → quadrantDiagram-AYHSOK5B-C5sqZOBF.js.map} +1 -1
  86. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-DmB9Ezaa.js → requirementDiagram-UZGBJVZJ-DBAUwM-7.js} +4 -4
  87. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-DmB9Ezaa.js.map → requirementDiagram-UZGBJVZJ-DBAUwM-7.js.map} +1 -1
  88. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-CdGDwaMo.js → sankeyDiagram-TZEHDZUN-CkaxkOo7.js} +2 -2
  89. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-CdGDwaMo.js.map → sankeyDiagram-TZEHDZUN-CkaxkOo7.js.map} +1 -1
  90. package/dist/static/assets/{sequenceDiagram-WL72ISMW-C-jiKkhi.js → sequenceDiagram-WL72ISMW-CJ6wMDXh.js} +4 -4
  91. package/dist/static/assets/{sequenceDiagram-WL72ISMW-C-jiKkhi.js.map → sequenceDiagram-WL72ISMW-CJ6wMDXh.js.map} +1 -1
  92. package/dist/static/assets/{stateDiagram-FKZM4ZOC-M9808W5W.js → stateDiagram-FKZM4ZOC-C66ZP2NW.js} +9 -9
  93. package/dist/static/assets/{stateDiagram-FKZM4ZOC-M9808W5W.js.map → stateDiagram-FKZM4ZOC-C66ZP2NW.js.map} +1 -1
  94. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-JE0YQyVh.js → stateDiagram-v2-4FDKWEC3-DdoOy271.js} +5 -5
  95. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-JE0YQyVh.js.map → stateDiagram-v2-4FDKWEC3-DdoOy271.js.map} +1 -1
  96. package/dist/static/assets/{timeline-definition-IT6M3QCI-a2Rh8B62.js → timeline-definition-IT6M3QCI-2A2Mqedz.js} +3 -3
  97. package/dist/static/assets/{timeline-definition-IT6M3QCI-a2Rh8B62.js.map → timeline-definition-IT6M3QCI-2A2Mqedz.js.map} +1 -1
  98. package/dist/static/assets/{treemap-KMMF4GRG-D3tvybuo.js → treemap-KMMF4GRG-CTbGSr5o.js} +4 -4
  99. package/dist/static/assets/{treemap-KMMF4GRG-D3tvybuo.js.map → treemap-KMMF4GRG-CTbGSr5o.js.map} +1 -1
  100. package/dist/static/assets/{xychartDiagram-PRI3JC2R-kmwKLP3Y.js → xychartDiagram-PRI3JC2R-C_S3XXZI.js} +3 -3
  101. package/dist/static/assets/{xychartDiagram-PRI3JC2R-kmwKLP3Y.js.map → xychartDiagram-PRI3JC2R-C_S3XXZI.js.map} +1 -1
  102. package/dist/static/index.html +1 -1
  103. package/package.json +1 -1
  104. package/dist/static/assets/index-RV1MEt3b.js.map +0 -1
@@ -71,6 +71,93 @@ async function emitUserMarkdown(dlg, content) {
71
71
  function resolveModelInfo(providerCfg, model) {
72
72
  return providerCfg.models[model];
73
73
  }
74
+ function resolveModelContextLimitTokens(modelInfo) {
75
+ if (modelInfo &&
76
+ typeof modelInfo.context_length === 'number' &&
77
+ Number.isFinite(modelInfo.context_length)) {
78
+ const n = Math.floor(modelInfo.context_length);
79
+ return n > 0 ? n : null;
80
+ }
81
+ if (modelInfo &&
82
+ typeof modelInfo.input_length === 'number' &&
83
+ Number.isFinite(modelInfo.input_length)) {
84
+ const n = Math.floor(modelInfo.input_length);
85
+ return n > 0 ? n : null;
86
+ }
87
+ return null;
88
+ }
89
+ function resolveEffectiveOptimalMaxTokens(args) {
90
+ const configuredOptimal = args.modelInfo &&
91
+ typeof args.modelInfo.optimal_max_tokens === 'number' &&
92
+ Number.isFinite(args.modelInfo.optimal_max_tokens)
93
+ ? Math.floor(args.modelInfo.optimal_max_tokens)
94
+ : undefined;
95
+ const optimalMaxTokensConfigured = configuredOptimal !== undefined && configuredOptimal > 0 ? configuredOptimal : undefined;
96
+ const configuredCritical = args.modelInfo &&
97
+ typeof args.modelInfo.critical_max_tokens === 'number' &&
98
+ Number.isFinite(args.modelInfo.critical_max_tokens)
99
+ ? Math.floor(args.modelInfo.critical_max_tokens)
100
+ : undefined;
101
+ const criticalMaxTokensConfigured = configuredCritical !== undefined && configuredCritical > 0 ? configuredCritical : undefined;
102
+ const defaultOptimal = 100000;
103
+ const effectiveOptimalMaxTokens = optimalMaxTokensConfigured !== undefined ? optimalMaxTokensConfigured : defaultOptimal;
104
+ const defaultCritical = Math.max(1, Math.floor(args.modelContextLimitTokens * 0.9));
105
+ const effectiveCriticalMaxTokens = criticalMaxTokensConfigured !== undefined ? criticalMaxTokensConfigured : defaultCritical;
106
+ return {
107
+ effectiveOptimalMaxTokens,
108
+ optimalMaxTokensConfigured,
109
+ effectiveCriticalMaxTokens,
110
+ criticalMaxTokensConfigured,
111
+ };
112
+ }
113
+ function computeContextHealthSnapshot(args) {
114
+ const modelInfo = args.providerCfg.models[args.model];
115
+ const modelContextWindowText = modelInfo && typeof modelInfo.context_window === 'string'
116
+ ? modelInfo.context_window
117
+ : undefined;
118
+ const modelContextLimitTokens = resolveModelContextLimitTokens(modelInfo);
119
+ if (modelContextLimitTokens === null) {
120
+ return { kind: 'unavailable', reason: 'model_limit_unavailable', modelContextWindowText };
121
+ }
122
+ const { effectiveOptimalMaxTokens, optimalMaxTokensConfigured, effectiveCriticalMaxTokens, criticalMaxTokensConfigured, } = resolveEffectiveOptimalMaxTokens({
123
+ modelInfo,
124
+ modelContextLimitTokens,
125
+ });
126
+ if (args.usage.kind !== 'available') {
127
+ return {
128
+ kind: 'unavailable',
129
+ reason: 'usage_unavailable',
130
+ modelContextWindowText,
131
+ modelContextLimitTokens,
132
+ effectiveOptimalMaxTokens,
133
+ optimalMaxTokensConfigured,
134
+ effectiveCriticalMaxTokens,
135
+ criticalMaxTokensConfigured,
136
+ };
137
+ }
138
+ const hardUtil = args.usage.promptTokens / modelContextLimitTokens;
139
+ const optimalUtil = args.usage.promptTokens / effectiveOptimalMaxTokens;
140
+ const level = args.usage.promptTokens > effectiveCriticalMaxTokens
141
+ ? 'critical'
142
+ : args.usage.promptTokens > effectiveOptimalMaxTokens
143
+ ? 'caution'
144
+ : 'healthy';
145
+ return {
146
+ kind: 'available',
147
+ promptTokens: args.usage.promptTokens,
148
+ completionTokens: args.usage.completionTokens,
149
+ totalTokens: args.usage.totalTokens,
150
+ modelContextWindowText,
151
+ modelContextLimitTokens,
152
+ effectiveOptimalMaxTokens,
153
+ optimalMaxTokensConfigured,
154
+ effectiveCriticalMaxTokens,
155
+ criticalMaxTokensConfigured,
156
+ hardUtil,
157
+ optimalUtil,
158
+ level,
159
+ };
160
+ }
74
161
  async function buildProviderContext(args) {
75
162
  const provider = args.agent.provider ?? args.team.memberDefaults.provider;
76
163
  const model = args.agent.model ?? args.team.memberDefaults.model;
@@ -372,6 +459,7 @@ async function driveDialogStreamCoreV2(dlg, humanPrompt, driveOptions, callbacks
372
459
  const funcTools = projected.tools;
373
460
  let suspendForHuman = false;
374
461
  let llmGenModelForGen = model;
462
+ let contextHealthForGen;
375
463
  await dlg.notifyGeneratingStart();
376
464
  try {
377
465
  const currentPrompt = pendingPrompt;
@@ -553,6 +641,12 @@ async function driveDialogStreamCoreV2(dlg, humanPrompt, driveOptions, callbacks
553
641
  nonStreamResult.llmGenModel.trim() !== '') {
554
642
  llmGenModelForGen = nonStreamResult.llmGenModel.trim();
555
643
  }
644
+ contextHealthForGen = computeContextHealthSnapshot({
645
+ providerCfg,
646
+ model,
647
+ usage: nonStreamResult.usage,
648
+ });
649
+ dlg.setLastContextHealth(contextHealthForGen);
556
650
  const nonStreamMsgs = nonStreamResult.messages;
557
651
  const assistantMsgs = nonStreamMsgs.filter((m) => m.type === 'saying_msg' || m.type === 'thinking_msg');
558
652
  const collectedAssistantCalls = [];
@@ -802,6 +896,12 @@ async function driveDialogStreamCoreV2(dlg, humanPrompt, driveOptions, callbacks
802
896
  streamResult.llmGenModel.trim() !== '') {
803
897
  llmGenModelForGen = streamResult.llmGenModel.trim();
804
898
  }
899
+ contextHealthForGen = computeContextHealthSnapshot({
900
+ providerCfg,
901
+ model,
902
+ usage: streamResult.usage,
903
+ });
904
+ dlg.setLastContextHealth(contextHealthForGen);
805
905
  const collectedCalls = parser.getCollectedCalls();
806
906
  const policyViolation = (0, policy_1.resolveDriverV2PolicyViolationKind)({
807
907
  policy,
@@ -887,7 +987,7 @@ async function driveDialogStreamCoreV2(dlg, humanPrompt, driveOptions, callbacks
887
987
  }
888
988
  }
889
989
  finally {
890
- await dlg.notifyGeneratingFinish(undefined, llmGenModelForGen);
990
+ await dlg.notifyGeneratingFinish(contextHealthForGen, llmGenModelForGen);
891
991
  }
892
992
  }
893
993
  finalRunState = await (0, dialog_run_state_1.computeIdleRunState)(dlg);
@@ -49,6 +49,13 @@ function runBackendDriver() {
49
49
  const dialogsToDrive = dialog_global_registry_1.globalDialogRegistry.getDialogsNeedingDrive();
50
50
  for (const rootDialog of dialogsToDrive) {
51
51
  try {
52
+ const latest = await persistence_1.DialogPersistence.loadDialogLatest(rootDialog.id, 'running');
53
+ const runStateKind = latest?.runState?.kind;
54
+ if (runStateKind === 'interrupted' || runStateKind === 'proceeding_stop_requested') {
55
+ dialog_global_registry_1.globalDialogRegistry.markNotNeedingDrive(rootDialog.id.rootId);
56
+ await persistence_1.DialogPersistence.setNeedsDrive(rootDialog.id, false, rootDialog.status);
57
+ continue;
58
+ }
52
59
  if (!(await rootDialog.canDrive())) {
53
60
  continue;
54
61
  }
@@ -6,11 +6,65 @@ const dialog_run_state_1 = require("../../dialog-run-state");
6
6
  const log_1 = require("../../log");
7
7
  const load_1 = require("../../minds/load");
8
8
  const persistence_1 = require("../../persistence");
9
+ const driver_messages_1 = require("../../shared/i18n/driver-messages");
9
10
  const runtime_language_1 = require("../../shared/runtime-language");
11
+ const id_1 = require("../../shared/utils/id");
10
12
  const context_health_1 = require("./context-health");
11
13
  const core_1 = require("./core");
12
14
  const policy_1 = require("./policy");
13
15
  const supdialog_response_1 = require("./supdialog-response");
16
+ const defaultCriticalCountdownGenerations = 5;
17
+ const contextHealthRoundStateByDialogKey = new Map();
18
+ function getContextHealthRoundState(dialog) {
19
+ const key = dialog.id.key();
20
+ const existing = contextHealthRoundStateByDialogKey.get(key);
21
+ if (existing) {
22
+ return existing;
23
+ }
24
+ const created = {};
25
+ contextHealthRoundStateByDialogKey.set(key, created);
26
+ return created;
27
+ }
28
+ function resetContextHealthRoundState(dialog) {
29
+ contextHealthRoundStateByDialogKey.delete(dialog.id.key());
30
+ }
31
+ function resolveCriticalCountdownRemaining(dialog, snapshot) {
32
+ if (!snapshot || snapshot.kind !== 'available') {
33
+ resetContextHealthRoundState(dialog);
34
+ return defaultCriticalCountdownGenerations;
35
+ }
36
+ if (snapshot.level !== 'critical') {
37
+ if (snapshot.level === 'healthy') {
38
+ resetContextHealthRoundState(dialog);
39
+ return defaultCriticalCountdownGenerations;
40
+ }
41
+ const state = getContextHealthRoundState(dialog);
42
+ state.lastSeenLevel = snapshot.level;
43
+ state.criticalCountdownRemaining = undefined;
44
+ return defaultCriticalCountdownGenerations;
45
+ }
46
+ const state = getContextHealthRoundState(dialog);
47
+ if (state.lastSeenLevel !== 'critical' ||
48
+ typeof state.criticalCountdownRemaining !== 'number' ||
49
+ !Number.isFinite(state.criticalCountdownRemaining)) {
50
+ state.lastSeenLevel = 'critical';
51
+ state.criticalCountdownRemaining = defaultCriticalCountdownGenerations;
52
+ }
53
+ const remaining = Math.floor(state.criticalCountdownRemaining);
54
+ return remaining > 0 ? remaining : 0;
55
+ }
56
+ function consumeCriticalCountdown(dialog) {
57
+ const state = getContextHealthRoundState(dialog);
58
+ const currentRaw = typeof state.criticalCountdownRemaining === 'number' &&
59
+ Number.isFinite(state.criticalCountdownRemaining)
60
+ ? Math.floor(state.criticalCountdownRemaining)
61
+ : defaultCriticalCountdownGenerations;
62
+ const current = currentRaw > 0 ? currentRaw : 0;
63
+ const next = Math.max(0, current - 1);
64
+ state.lastSeenLevel = 'critical';
65
+ state.criticalCountdownRemaining = next;
66
+ return next;
67
+ }
14
68
  function resolveEffectivePrompt(dialog, humanPrompt) {
15
69
  if (humanPrompt) {
16
70
  return humanPrompt;
@@ -39,6 +93,7 @@ async function executeDriveRound(args) {
39
93
  let followUp;
40
94
  let driveResult;
41
95
  let subdialogReplyTarget;
96
+ const allowResumeFromInterrupted = driveOptions?.allowResumeFromInterrupted === true || humanPrompt?.origin === 'user';
42
97
  try {
43
98
  // Prime active-run registration right after acquiring dialog lock so user stop can
44
99
  // reliably interrupt queued auto-revive drives during preflight.
@@ -53,6 +108,23 @@ async function executeDriveRound(args) {
53
108
  latest.runState.kind === 'dead') {
54
109
  return;
55
110
  }
111
+ if (latest && latest.runState && latest.runState.kind === 'proceeding_stop_requested') {
112
+ log_1.log.info('driver-v2 skip drive while stop request is still being processed', undefined, {
113
+ dialogId: dialog.id.valueOf(),
114
+ reason: latest.runState.reason,
115
+ });
116
+ return;
117
+ }
118
+ if (latest &&
119
+ latest.runState &&
120
+ latest.runState.kind === 'interrupted' &&
121
+ !allowResumeFromInterrupted) {
122
+ log_1.log.info('driver-v2 skip drive for interrupted dialog without explicit resume/user prompt', undefined, {
123
+ dialogId: dialog.id.valueOf(),
124
+ reason: latest.runState.reason,
125
+ });
126
+ return;
127
+ }
56
128
  }
57
129
  catch (err) {
58
130
  log_1.log.warn('driver-v2 failed to check runState before drive; proceeding best-effort', err, {
@@ -71,18 +143,56 @@ async function executeDriveRound(args) {
71
143
  if (!validation.ok) {
72
144
  throw new Error(`driver-v2 policy invariant violation: ${validation.detail}`);
73
145
  }
146
+ const snapshot = dialog.getLastContextHealth();
147
+ const hasQueuedUpNext = dialog.hasUpNext();
148
+ const criticalCountdownRemaining = resolveCriticalCountdownRemaining(dialog, snapshot);
74
149
  const healthDecision = (0, context_health_1.decideDriverV2ContextHealth)({
75
- snapshot: dialog.getLastContextHealth(),
76
- hadUserPromptThisGen: args.driveArgs[1] !== undefined,
77
- criticalCountdownRemaining: 1,
150
+ snapshot,
151
+ hadUserPromptThisGen: humanPrompt !== undefined,
152
+ criticalCountdownRemaining,
78
153
  });
79
154
  if (healthDecision.kind === 'suspend') {
80
155
  return;
81
156
  }
157
+ let healthPrompt;
158
+ if (healthDecision.kind === 'continue') {
159
+ if (healthDecision.reason === 'critical_force_new_course') {
160
+ const language = (0, runtime_language_1.getWorkLanguage)();
161
+ const newCoursePrompt = language === 'zh'
162
+ ? '系统因上下文已告急(critical)而自动开启新一程对话,请继续推进任务。'
163
+ : 'System auto-started a new dialog course because context health is critical. Please continue the task.';
164
+ await dialog.startNewCourse(newCoursePrompt);
165
+ dialog.setLastContextHealth({ kind: 'unavailable', reason: 'usage_unavailable' });
166
+ resetContextHealthRoundState(dialog);
167
+ }
168
+ else if (!hasQueuedUpNext) {
169
+ const language = (0, runtime_language_1.getWorkLanguage)();
170
+ const guideText = healthDecision.reason === 'caution_soft_remediation'
171
+ ? (0, driver_messages_1.formatUserFacingContextHealthV3RemediationGuide)(language, {
172
+ kind: 'caution',
173
+ mode: 'soft',
174
+ })
175
+ : (0, driver_messages_1.formatUserFacingContextHealthV3RemediationGuide)(language, {
176
+ kind: 'critical',
177
+ mode: 'countdown',
178
+ promptsRemainingAfterThis: consumeCriticalCountdown(dialog),
179
+ promptsTotal: defaultCriticalCountdownGenerations,
180
+ });
181
+ healthPrompt = {
182
+ content: guideText,
183
+ msgId: (0, id_1.generateShortId)(),
184
+ grammar: 'markdown',
185
+ userLanguageCode: language,
186
+ };
187
+ }
188
+ }
82
189
  args.runtime.driveCount += 1;
83
190
  args.runtime.totalGenIterations += 1;
84
191
  args.runtime.usedLegacyDriveCore = false;
85
- const effectivePrompt = resolveEffectivePrompt(dialog, humanPrompt);
192
+ const promptForCore = healthDecision.kind === 'continue' && healthDecision.reason === 'critical_force_new_course'
193
+ ? undefined
194
+ : (healthPrompt ?? humanPrompt);
195
+ const effectivePrompt = resolveEffectivePrompt(dialog, promptForCore);
86
196
  subdialogReplyTarget = effectivePrompt?.subdialogReplyTarget;
87
197
  if (effectivePrompt && effectivePrompt.userLanguageCode) {
88
198
  dialog.setLastUserLanguageCode(effectivePrompt.userLanguageCode);
@@ -193,6 +193,33 @@ async function updateSubdialogAssignment(subdialog, assignment) {
193
193
  subdialog.assignmentFromSup = assignment;
194
194
  await persistence_1.DialogPersistence.updateSubdialogAssignment(subdialog.id, assignment);
195
195
  }
196
+ async function lookupLiveRegisteredSubdialog(rootDialog, agentId, tellaskSession) {
197
+ const existing = rootDialog.lookupSubdialog(agentId, tellaskSession);
198
+ if (!existing) {
199
+ return undefined;
200
+ }
201
+ const existingSession = existing.tellaskSession;
202
+ if (!existingSession) {
203
+ throw new Error(`Type B registry invariant violation: lookupSubdialog returned entry without tellaskSession (root=${rootDialog.id.valueOf()} sub=${existing.id.valueOf()})`);
204
+ }
205
+ const latest = await persistence_1.DialogPersistence.loadDialogLatest(existing.id, rootDialog.status);
206
+ const runState = latest?.runState;
207
+ if (!runState || runState.kind !== 'dead') {
208
+ return existing;
209
+ }
210
+ const removed = rootDialog.unregisterSubdialog(existing.agentId, existingSession);
211
+ if (!removed) {
212
+ throw new Error(`Failed to unregister dead registered subdialog: root=${rootDialog.id.valueOf()} sub=${existing.id.valueOf()} session=${existingSession}`);
213
+ }
214
+ await rootDialog.saveSubdialogRegistry();
215
+ log_1.log.info('Pruned dead registered subdialog from Type B registry', undefined, {
216
+ rootId: rootDialog.id.rootId,
217
+ subdialogId: existing.id.selfId,
218
+ agentId: existing.agentId,
219
+ tellaskSession: existingSession,
220
+ });
221
+ return undefined;
222
+ }
196
223
  function extractLastAssistantResponse(messages, defaultMessage) {
197
224
  let responseText = '';
198
225
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -662,7 +689,7 @@ async function executeTellaskCall(dlg, agent, firstMention, tellaskHead, body, c
662
689
  callId,
663
690
  collectiveTargets: options?.collectiveTargets ?? [parseResult.agentId],
664
691
  };
665
- const existing = rootDialog.lookupSubdialog(parseResult.agentId, derivedSession);
692
+ const existing = await lookupLiveRegisteredSubdialog(rootDialog, parseResult.agentId, derivedSession);
666
693
  if (existing) {
667
694
  try {
668
695
  await updateSubdialogAssignment(existing, assignment);
@@ -902,7 +929,7 @@ async function executeTellaskCall(dlg, agent, firstMention, tellaskHead, body, c
902
929
  };
903
930
  const pendingOwner = callerDialog;
904
931
  const result = await (0, subdialog_txn_1.withSubdialogTxnLock)(rootDialog.id, async () => {
905
- const existing = rootDialog.lookupSubdialog(parseResult.agentId, parseResult.tellaskSession);
932
+ const existing = await lookupLiveRegisteredSubdialog(rootDialog, parseResult.agentId, parseResult.tellaskSession);
906
933
  if (existing) {
907
934
  try {
908
935
  await updateSubdialogAssignment(existing, assignment);
@@ -915,6 +915,7 @@ async function driveDialogStream(dlg, humanPrompt, waitInQue = false, driveOptio
915
915
  if (!waitInQue && dlg.isLocked()) {
916
916
  throw new Error(`Dialog busy driven, see how it proceeded and try again.`);
917
917
  }
918
+ const allowResumeFromInterrupted = driveOptions?.allowResumeFromInterrupted === true || humanPrompt?.origin === 'user';
918
919
  const release = await dlg.acquire();
919
920
  let followUp;
920
921
  let driveResult;
@@ -930,6 +931,23 @@ async function driveDialogStream(dlg, humanPrompt, waitInQue = false, driveOptio
930
931
  latest.runState.kind === 'dead') {
931
932
  return;
932
933
  }
934
+ if (latest && latest.runState && latest.runState.kind === 'proceeding_stop_requested') {
935
+ log_1.log.info('Skip drive while stop request is still being processed', undefined, {
936
+ dialogId: dlg.id.valueOf(),
937
+ reason: latest.runState.reason,
938
+ });
939
+ return;
940
+ }
941
+ if (latest &&
942
+ latest.runState &&
943
+ latest.runState.kind === 'interrupted' &&
944
+ !allowResumeFromInterrupted) {
945
+ log_1.log.info('Skip drive for interrupted dialog without explicit resume/user prompt', undefined, {
946
+ dialogId: dlg.id.valueOf(),
947
+ reason: latest.runState.reason,
948
+ });
949
+ return;
950
+ }
933
951
  }
934
952
  catch (err) {
935
953
  log_1.log.warn('Failed to check runState before drive; proceeding best-effort', err, {
@@ -991,6 +1009,13 @@ async function runBackendDriver() {
991
1009
  const dialogsToDrive = dialog_global_registry_1.globalDialogRegistry.getDialogsNeedingDrive();
992
1010
  for (const rootDialog of dialogsToDrive) {
993
1011
  try {
1012
+ const latest = await persistence_1.DialogPersistence.loadDialogLatest(rootDialog.id, 'running');
1013
+ const runStateKind = latest?.runState?.kind;
1014
+ if (runStateKind === 'interrupted' || runStateKind === 'proceeding_stop_requested') {
1015
+ dialog_global_registry_1.globalDialogRegistry.markNotNeedingDrive(rootDialog.id.rootId);
1016
+ await persistence_1.DialogPersistence.setNeedsDrive(rootDialog.id, false, rootDialog.status);
1017
+ continue;
1018
+ }
994
1019
  if (!(await rootDialog.canDrive())) {
995
1020
  continue;
996
1021
  }
@@ -2757,6 +2782,33 @@ async function updateSubdialogAssignment(subdialog, assignment) {
2757
2782
  subdialog.assignmentFromSup = assignment;
2758
2783
  await persistence_1.DialogPersistence.updateSubdialogAssignment(subdialog.id, assignment);
2759
2784
  }
2785
+ async function lookupLiveRegisteredSubdialog(rootDialog, agentId, tellaskSession) {
2786
+ const existing = rootDialog.lookupSubdialog(agentId, tellaskSession);
2787
+ if (!existing) {
2788
+ return undefined;
2789
+ }
2790
+ const existingSession = existing.tellaskSession;
2791
+ if (!existingSession) {
2792
+ throw new Error(`Type B registry invariant violation: lookupSubdialog returned entry without tellaskSession (root=${rootDialog.id.valueOf()} sub=${existing.id.valueOf()})`);
2793
+ }
2794
+ const latest = await persistence_1.DialogPersistence.loadDialogLatest(existing.id, rootDialog.status);
2795
+ const runState = latest?.runState;
2796
+ if (!runState || runState.kind !== 'dead') {
2797
+ return existing;
2798
+ }
2799
+ const removed = rootDialog.unregisterSubdialog(existing.agentId, existingSession);
2800
+ if (!removed) {
2801
+ throw new Error(`Failed to unregister dead registered subdialog: root=${rootDialog.id.valueOf()} sub=${existing.id.valueOf()} session=${existingSession}`);
2802
+ }
2803
+ await rootDialog.saveSubdialogRegistry();
2804
+ log_1.log.info('Pruned dead registered subdialog from Type B registry', undefined, {
2805
+ rootId: rootDialog.id.rootId,
2806
+ subdialogId: existing.id.selfId,
2807
+ agentId: existing.agentId,
2808
+ tellaskSession: existingSession,
2809
+ });
2810
+ return undefined;
2811
+ }
2760
2812
  let agentPrimingModulePromise = null;
2761
2813
  async function scheduleInheritedAgentPrimingForSubdialog(callerDialog, subdialog) {
2762
2814
  const rootDialog = callerDialog instanceof dialog_1.RootDialog
@@ -3550,7 +3602,7 @@ async function executeTellaskCall(dlg, agent, firstMention, tellaskHead, body, c
3550
3602
  callId,
3551
3603
  collectiveTargets: options?.collectiveTargets ?? [parseResult.agentId],
3552
3604
  };
3553
- const existing = rootDialog.lookupSubdialog(parseResult.agentId, derivedSession);
3605
+ const existing = await lookupLiveRegisteredSubdialog(rootDialog, parseResult.agentId, derivedSession);
3554
3606
  if (existing) {
3555
3607
  try {
3556
3608
  await updateSubdialogAssignment(existing, assignment);
@@ -3822,7 +3874,7 @@ async function executeTellaskCall(dlg, agent, firstMention, tellaskHead, body, c
3822
3874
  };
3823
3875
  const pendingOwner = callerDialog;
3824
3876
  const result = await withSuspensionStateLock(rootDialog.id, async () => {
3825
- const existing = rootDialog.lookupSubdialog(parseResult.agentId, parseResult.tellaskSession);
3877
+ const existing = await lookupLiveRegisteredSubdialog(rootDialog, parseResult.agentId, parseResult.tellaskSession);
3826
3878
  if (existing) {
3827
3879
  try {
3828
3880
  await updateSubdialogAssignment(existing, assignment);
@@ -941,9 +941,26 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
941
941
  }
942
942
  async loadSubdialogRegistry(rootDialog, status) {
943
943
  const entries = await DialogPersistence.loadSubdialogRegistry(rootDialog.id, status);
944
+ const shouldPruneDead = status === 'running';
945
+ let prunedDeadRegistryEntries = false;
944
946
  for (const entry of entries) {
945
947
  if (!entry.tellaskSession)
946
948
  continue;
949
+ if (shouldPruneDead) {
950
+ const latest = await DialogPersistence.loadDialogLatest(entry.subdialogId, status);
951
+ const runState = latest?.runState;
952
+ if (runState && runState.kind === 'dead') {
953
+ prunedDeadRegistryEntries = true;
954
+ rootDialog.unregisterSubdialog(entry.agentId, entry.tellaskSession);
955
+ log_1.log.info('Skip dead subdialog while loading Type B registry', undefined, {
956
+ rootId: rootDialog.id.rootId,
957
+ subdialogId: entry.subdialogId.selfId,
958
+ agentId: entry.agentId,
959
+ tellaskSession: entry.tellaskSession,
960
+ });
961
+ continue;
962
+ }
963
+ }
947
964
  const existing = rootDialog.lookupDialog(entry.subdialogId.selfId);
948
965
  if (existing) {
949
966
  if (existing instanceof dialog_1.SubDialog && existing.tellaskSession) {
@@ -965,6 +982,9 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
965
982
  });
966
983
  rootDialog.registerSubdialog(subdialog);
967
984
  }
985
+ if (prunedDeadRegistryEntries) {
986
+ await rootDialog.saveSubdialogRegistry();
987
+ }
968
988
  }
969
989
  /**
970
990
  * Clear Questions for Human state in storage