dominds 1.23.7 → 1.23.9

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 (116) hide show
  1. package/dist/apps-host/client.d.ts +2 -3
  2. package/dist/apps-host/host.js +5 -7
  3. package/dist/apps-host/ipc-types.d.ts +2 -3
  4. package/dist/docs/dialog-system.md +3 -0
  5. package/dist/docs/dialog-system.zh.md +3 -0
  6. package/dist/docs/diligence-push.md +9 -7
  7. package/dist/llm/gen/codex.js +26 -5
  8. package/dist/llm/gen/openai.js +36 -4
  9. package/dist/llm/kernel-driver/events.js +6 -3
  10. package/dist/llm/kernel-driver/flow.js +17 -103
  11. package/dist/persistence.d.ts +1 -0
  12. package/dist/persistence.js +44 -43
  13. package/dist/priming.js +39 -2
  14. package/dist/runtime/driver-messages.d.ts +1 -0
  15. package/dist/runtime/driver-messages.js +26 -14
  16. package/dist/server/websocket-handler.js +2 -2
  17. package/dist/tools/app-reminders.js +16 -2
  18. package/dist/tools/mcp.js +4 -2
  19. package/dist/tools/os.js +18 -12
  20. package/dist/tools/pending-tellask-reminder.js +6 -15
  21. package/package.json +3 -3
  22. package/webapp/dist/assets/{_basePickBy-528dB5Tu.js → _basePickBy-7LUdAfWz.js} +3 -3
  23. package/webapp/dist/assets/{_basePickBy-528dB5Tu.js.map → _basePickBy-7LUdAfWz.js.map} +1 -1
  24. package/webapp/dist/assets/{_baseUniq-DkdKmFUs.js → _baseUniq-DwjWeodO.js} +2 -2
  25. package/webapp/dist/assets/{_baseUniq-DkdKmFUs.js.map → _baseUniq-DwjWeodO.js.map} +1 -1
  26. package/webapp/dist/assets/{arc-BXvXVeL_.js → arc-CEnfISy0.js} +2 -2
  27. package/webapp/dist/assets/{arc-BXvXVeL_.js.map → arc-CEnfISy0.js.map} +1 -1
  28. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-Ck1IMDXl.js → architectureDiagram-2XIMDMQ5-BpimPdpL.js} +7 -7
  29. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-Ck1IMDXl.js.map → architectureDiagram-2XIMDMQ5-BpimPdpL.js.map} +1 -1
  30. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-DLRhkTKE.js → blockDiagram-WCTKOSBZ-BSRtGkFY.js} +7 -7
  31. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-DLRhkTKE.js.map → blockDiagram-WCTKOSBZ-BSRtGkFY.js.map} +1 -1
  32. package/webapp/dist/assets/{c4Diagram-IC4MRINW-D2Hc1l7q.js → c4Diagram-IC4MRINW-kSgcfdmL.js} +3 -3
  33. package/webapp/dist/assets/{c4Diagram-IC4MRINW-D2Hc1l7q.js.map → c4Diagram-IC4MRINW-kSgcfdmL.js.map} +1 -1
  34. package/webapp/dist/assets/{channel-DuagLVFr.js → channel-Dp-cGMNE.js} +2 -2
  35. package/webapp/dist/assets/{channel-DuagLVFr.js.map → channel-Dp-cGMNE.js.map} +1 -1
  36. package/webapp/dist/assets/{chunk-4BX2VUAB-BVowxdVQ.js → chunk-4BX2VUAB-Cp-fmbaK.js} +2 -2
  37. package/webapp/dist/assets/{chunk-4BX2VUAB-BVowxdVQ.js.map → chunk-4BX2VUAB-Cp-fmbaK.js.map} +1 -1
  38. package/webapp/dist/assets/{chunk-55IACEB6-DOqixome.js → chunk-55IACEB6-BOJKMAPr.js} +2 -2
  39. package/webapp/dist/assets/{chunk-55IACEB6-DOqixome.js.map → chunk-55IACEB6-BOJKMAPr.js.map} +1 -1
  40. package/webapp/dist/assets/{chunk-FMBD7UC4-BQE3IRbI.js → chunk-FMBD7UC4-DfQxVVLu.js} +2 -2
  41. package/webapp/dist/assets/{chunk-FMBD7UC4-BQE3IRbI.js.map → chunk-FMBD7UC4-DfQxVVLu.js.map} +1 -1
  42. package/webapp/dist/assets/{chunk-JSJVCQXG-BWvy_u2h.js → chunk-JSJVCQXG-DTl-4Rvh.js} +2 -2
  43. package/webapp/dist/assets/{chunk-JSJVCQXG-BWvy_u2h.js.map → chunk-JSJVCQXG-DTl-4Rvh.js.map} +1 -1
  44. package/webapp/dist/assets/{chunk-KX2RTZJC-DsSmqNSf.js → chunk-KX2RTZJC-D5--lFcw.js} +2 -2
  45. package/webapp/dist/assets/{chunk-KX2RTZJC-DsSmqNSf.js.map → chunk-KX2RTZJC-D5--lFcw.js.map} +1 -1
  46. package/webapp/dist/assets/{chunk-NQ4KR5QH-B3jQt0DX.js → chunk-NQ4KR5QH-BDa1UceW.js} +4 -4
  47. package/webapp/dist/assets/{chunk-NQ4KR5QH-B3jQt0DX.js.map → chunk-NQ4KR5QH-BDa1UceW.js.map} +1 -1
  48. package/webapp/dist/assets/{chunk-QZHKN3VN-CWST9WcY.js → chunk-QZHKN3VN-B6PiydXk.js} +2 -2
  49. package/webapp/dist/assets/{chunk-QZHKN3VN-CWST9WcY.js.map → chunk-QZHKN3VN-B6PiydXk.js.map} +1 -1
  50. package/webapp/dist/assets/{chunk-WL4C6EOR-DjGCVqJN.js → chunk-WL4C6EOR-BKbEzBrJ.js} +6 -6
  51. package/webapp/dist/assets/{chunk-WL4C6EOR-DjGCVqJN.js.map → chunk-WL4C6EOR-BKbEzBrJ.js.map} +1 -1
  52. package/webapp/dist/assets/{classDiagram-VBA2DB6C-BnjkPcus.js → classDiagram-VBA2DB6C-CbCDPvgK.js} +7 -7
  53. package/webapp/dist/assets/{classDiagram-VBA2DB6C-BnjkPcus.js.map → classDiagram-VBA2DB6C-CbCDPvgK.js.map} +1 -1
  54. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BnjkPcus.js → classDiagram-v2-RAHNMMFH-CbCDPvgK.js} +7 -7
  55. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BnjkPcus.js.map → classDiagram-v2-RAHNMMFH-CbCDPvgK.js.map} +1 -1
  56. package/webapp/dist/assets/{clone-BlToIURl.js → clone-B5WbSwel.js} +2 -2
  57. package/webapp/dist/assets/{clone-BlToIURl.js.map → clone-B5WbSwel.js.map} +1 -1
  58. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-BDVnPWt2.js → cose-bilkent-S5V4N54A-DcYLhdFN.js} +2 -2
  59. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-BDVnPWt2.js.map → cose-bilkent-S5V4N54A-DcYLhdFN.js.map} +1 -1
  60. package/webapp/dist/assets/{dagre-KLK3FWXG-aEZUtpHt.js → dagre-KLK3FWXG-BeG9lIKK.js} +7 -7
  61. package/webapp/dist/assets/{dagre-KLK3FWXG-aEZUtpHt.js.map → dagre-KLK3FWXG-BeG9lIKK.js.map} +1 -1
  62. package/webapp/dist/assets/{diagram-E7M64L7V-CvNVSxxk.js → diagram-E7M64L7V-BIRobVwO.js} +8 -8
  63. package/webapp/dist/assets/{diagram-E7M64L7V-CvNVSxxk.js.map → diagram-E7M64L7V-BIRobVwO.js.map} +1 -1
  64. package/webapp/dist/assets/{diagram-IFDJBPK2-Cvwaoava.js → diagram-IFDJBPK2-CEOYT9-f.js} +7 -7
  65. package/webapp/dist/assets/{diagram-IFDJBPK2-Cvwaoava.js.map → diagram-IFDJBPK2-CEOYT9-f.js.map} +1 -1
  66. package/webapp/dist/assets/{diagram-P4PSJMXO-ffnT7Lr_.js → diagram-P4PSJMXO-BQoM5Ex6.js} +7 -7
  67. package/webapp/dist/assets/{diagram-P4PSJMXO-ffnT7Lr_.js.map → diagram-P4PSJMXO-BQoM5Ex6.js.map} +1 -1
  68. package/webapp/dist/assets/{erDiagram-INFDFZHY-DvGIVeJS.js → erDiagram-INFDFZHY-Cqjswes_.js} +5 -5
  69. package/webapp/dist/assets/{erDiagram-INFDFZHY-DvGIVeJS.js.map → erDiagram-INFDFZHY-Cqjswes_.js.map} +1 -1
  70. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-BkQUpSc9.js → flowDiagram-PKNHOUZH-Cja2_InV.js} +7 -7
  71. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-BkQUpSc9.js.map → flowDiagram-PKNHOUZH-Cja2_InV.js.map} +1 -1
  72. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-BlG96EZZ.js → ganttDiagram-A5KZAMGK-DBUuaEd2.js} +3 -3
  73. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-BlG96EZZ.js.map → ganttDiagram-A5KZAMGK-DBUuaEd2.js.map} +1 -1
  74. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CnyjUBR4.js → gitGraphDiagram-K3NZZRJ6-Dl4JE5EA.js} +8 -8
  75. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-CnyjUBR4.js.map → gitGraphDiagram-K3NZZRJ6-Dl4JE5EA.js.map} +1 -1
  76. package/webapp/dist/assets/{graph-D-OO7MVR.js → graph-BfMWseJJ.js} +3 -3
  77. package/webapp/dist/assets/{graph-D-OO7MVR.js.map → graph-BfMWseJJ.js.map} +1 -1
  78. package/webapp/dist/assets/{index-DvqI98wY.js → index-Dnj_jTsn.js} +734 -129
  79. package/webapp/dist/assets/{index-DvqI98wY.js.map → index-Dnj_jTsn.js.map} +1 -1
  80. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-Bid564Un.js → infoDiagram-LFFYTUFH-D_rvRkCc.js} +6 -6
  81. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-Bid564Un.js.map → infoDiagram-LFFYTUFH-D_rvRkCc.js.map} +1 -1
  82. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-BoU1GXkx.js → ishikawaDiagram-PHBUUO56-CvPTsJgE.js} +2 -2
  83. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-BoU1GXkx.js.map → ishikawaDiagram-PHBUUO56-CvPTsJgE.js.map} +1 -1
  84. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-C-JJRe4y.js → journeyDiagram-4ABVD52K-C1gZ4Bzf.js} +5 -5
  85. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-C-JJRe4y.js.map → journeyDiagram-4ABVD52K-C1gZ4Bzf.js.map} +1 -1
  86. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-BPGHC2fL.js → kanban-definition-K7BYSVSG-DqSjhrSU.js} +3 -3
  87. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-BPGHC2fL.js.map → kanban-definition-K7BYSVSG-DqSjhrSU.js.map} +1 -1
  88. package/webapp/dist/assets/{layout-BFpoiNr0.js → layout-CRVydERy.js} +5 -5
  89. package/webapp/dist/assets/{layout-BFpoiNr0.js.map → layout-CRVydERy.js.map} +1 -1
  90. package/webapp/dist/assets/{linear-BwnDVwt9.js → linear-BKsEk85O.js} +2 -2
  91. package/webapp/dist/assets/{linear-BwnDVwt9.js.map → linear-BKsEk85O.js.map} +1 -1
  92. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-D4aHh1Ye.js → mindmap-definition-YRQLILUH-DfBx0FRA.js} +4 -4
  93. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-D4aHh1Ye.js.map → mindmap-definition-YRQLILUH-DfBx0FRA.js.map} +1 -1
  94. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-DIp7yy6V.js → pieDiagram-SKSYHLDU-DKrkyxnK.js} +8 -8
  95. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-DIp7yy6V.js.map → pieDiagram-SKSYHLDU-DKrkyxnK.js.map} +1 -1
  96. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-uKOhvCPR.js → quadrantDiagram-337W2JSQ-jC0ZA6Ei.js} +3 -3
  97. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-uKOhvCPR.js.map → quadrantDiagram-337W2JSQ-jC0ZA6Ei.js.map} +1 -1
  98. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-Da_5DlcQ.js → requirementDiagram-Z7DCOOCP-We3xysp7.js} +4 -4
  99. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-Da_5DlcQ.js.map → requirementDiagram-Z7DCOOCP-We3xysp7.js.map} +1 -1
  100. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-P3UD1XYS.js → sankeyDiagram-WA2Y5GQK-CVKXirbt.js} +2 -2
  101. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-P3UD1XYS.js.map → sankeyDiagram-WA2Y5GQK-CVKXirbt.js.map} +1 -1
  102. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-jY-eNlAg.js → sequenceDiagram-2WXFIKYE-C_FP9akr.js} +4 -4
  103. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-jY-eNlAg.js.map → sequenceDiagram-2WXFIKYE-C_FP9akr.js.map} +1 -1
  104. package/webapp/dist/assets/{stateDiagram-RAJIS63D-HMXNbLUd.js → stateDiagram-RAJIS63D-I_Z9tp8x.js} +9 -9
  105. package/webapp/dist/assets/{stateDiagram-RAJIS63D-HMXNbLUd.js.map → stateDiagram-RAJIS63D-I_Z9tp8x.js.map} +1 -1
  106. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-C-50Qbn8.js → stateDiagram-v2-FVOUBMTO-CapbGJFk.js} +5 -5
  107. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-C-50Qbn8.js.map → stateDiagram-v2-FVOUBMTO-CapbGJFk.js.map} +1 -1
  108. package/webapp/dist/assets/{timeline-definition-YZTLITO2-CkiLYjSG.js → timeline-definition-YZTLITO2-BshxRk1F.js} +3 -3
  109. package/webapp/dist/assets/{timeline-definition-YZTLITO2-CkiLYjSG.js.map → timeline-definition-YZTLITO2-BshxRk1F.js.map} +1 -1
  110. package/webapp/dist/assets/{treemap-KZPCXAKY-DKYYu8t-.js → treemap-KZPCXAKY-CocYDGAm.js} +5 -5
  111. package/webapp/dist/assets/{treemap-KZPCXAKY-DKYYu8t-.js.map → treemap-KZPCXAKY-CocYDGAm.js.map} +1 -1
  112. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-n9k6D3Up.js → vennDiagram-LZ73GAT5-BqnmMyq0.js} +2 -2
  113. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-n9k6D3Up.js.map → vennDiagram-LZ73GAT5-BqnmMyq0.js.map} +1 -1
  114. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-DJZb5SW1.js → xychartDiagram-JWTSCODW-DFRdd2qS.js} +3 -3
  115. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-DJZb5SW1.js.map → xychartDiagram-JWTSCODW-DFRdd2qS.js.map} +1 -1
  116. package/webapp/dist/index.html +1 -1
@@ -1,6 +1,5 @@
1
- import type { DomindsAppDynamicToolsetsContext, DomindsAppReminderOwnerApplyContext, DomindsAppReminderOwnerRenderContext, DomindsAppReminderOwnerUpdateContext, DomindsAppRunControlContext, DomindsAppRunControlResult } from '@longrun-ai/kernel/app-host-contract';
1
+ import type { DomindsAppDynamicToolsetsContext, DomindsAppReminderOwnerApplyContext, DomindsAppReminderOwnerRenderContext, DomindsAppReminderOwnerUpdateContext, DomindsAppReminderRenderedMessage, DomindsAppRunControlContext, DomindsAppRunControlResult } from '@longrun-ai/kernel/app-host-contract';
2
2
  import type { DomindsAppHostReminderUpdateResult, DomindsAppHostToolResult, DomindsAppInstallJson, DomindsAppReminderApplyRequest, DomindsAppReminderApplyResult } from '@longrun-ai/kernel/app-json';
3
- import type { ChatMessage } from '../llm/client';
4
3
  import type { ToolArguments } from '../tool';
5
4
  import type { AppsHostMessageToKernel } from './ipc-types';
6
5
  export type EnabledAppForHost = Readonly<{
@@ -22,7 +21,7 @@ export type AppsHostClient = Readonly<{
22
21
  applyRunControl: (controlId: string, payload: DomindsAppRunControlContext) => Promise<DomindsAppRunControlResult>;
23
22
  applyReminder: (appId: string, ownerRef: string, request: DomindsAppReminderApplyRequest, ctx: DomindsAppReminderOwnerApplyContext) => Promise<DomindsAppReminderApplyResult>;
24
23
  updateReminder: (appId: string, ownerRef: string, ctx: DomindsAppReminderOwnerUpdateContext) => Promise<DomindsAppHostReminderUpdateResult>;
25
- renderReminder: (appId: string, ownerRef: string, ctx: DomindsAppReminderOwnerRenderContext) => Promise<ChatMessage>;
24
+ renderReminder: (appId: string, ownerRef: string, ctx: DomindsAppReminderOwnerRenderContext) => Promise<DomindsAppReminderRenderedMessage>;
26
25
  shutdown: () => Promise<void>;
27
26
  }>;
28
27
  export type AppsHostReadyMessage = Extract<AppsHostMessageToKernel, {
@@ -6,8 +6,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const url_1 = require("url");
9
- const log_1 = require("../log");
10
9
  const app_id_1 = require("../apps/app-id");
10
+ const log_1 = require("../log");
11
11
  const ipc_types_1 = require("./ipc-types");
12
12
  const log = (0, log_1.createLogger)('apps-host');
13
13
  const dynamicImport = new Function('specifier', 'return import(specifier)');
@@ -186,12 +186,10 @@ function isReminderUpdateResult(value) {
186
186
  const updatedMeta = value['updatedMeta'];
187
187
  return updatedMeta === undefined || isJsonValue(updatedMeta);
188
188
  }
189
- function isChatMessage(value) {
189
+ function isReminderRenderedMessage(value) {
190
190
  if (!isRecord(value))
191
191
  return false;
192
- if (typeof value['type'] !== 'string')
193
- return false;
194
- if (typeof value['role'] !== 'string')
192
+ if (typeof value['content'] !== 'string')
195
193
  return false;
196
194
  return true;
197
195
  }
@@ -697,12 +695,12 @@ process.on('message', (raw) => {
697
695
  }
698
696
  try {
699
697
  const message = await found.fn.renderReminder(msg.ctx);
700
- if (!isChatMessage(message)) {
698
+ if (!isReminderRenderedMessage(message)) {
701
699
  send({
702
700
  type: 'reminder_render_result',
703
701
  callId: msg.callId,
704
702
  ok: false,
705
- errorText: `Invalid reminder render result shape: ${msg.appId}/${msg.ownerRef}`,
703
+ errorText: `Invalid reminder render result shape: ${msg.appId}/${msg.ownerRef}; expected { content: string }`,
706
704
  });
707
705
  return;
708
706
  }
@@ -1,7 +1,6 @@
1
- import type { DomindsAppRunControlResult } from '@longrun-ai/kernel/app-host-contract';
1
+ import type { DomindsAppReminderRenderedMessage, DomindsAppRunControlResult } from '@longrun-ai/kernel/app-host-contract';
2
2
  import type { DomindsAppDialogReminderRequestBatch, DomindsAppHostReminderUpdateResult, DomindsAppInstallJson, DomindsAppReminderApplyRequest, DomindsAppReminderApplyResult, DomindsAppReminderState } from '@longrun-ai/kernel/app-json';
3
3
  import type { LanguageCode } from '@longrun-ai/kernel/types/language';
4
- import type { ChatMessage } from '../llm/client';
5
4
  import type { ToolArguments, ToolCallOutput } from '../tool';
6
5
  export type AppsHostKernelInitMessage = Readonly<{
7
6
  type: 'init';
@@ -171,7 +170,7 @@ export type AppsHostReminderRenderResultMessage = Readonly<{
171
170
  callId: string;
172
171
  } & (Readonly<{
173
172
  ok: true;
174
- message: ChatMessage;
173
+ message: DomindsAppReminderRenderedMessage;
175
174
  }> | Readonly<{
176
175
  ok: false;
177
176
  errorText: string;
@@ -241,6 +241,9 @@ flowchart TD
241
241
 
242
242
  - If a Side Dialog has completed all assigned goals and can deliver the final result, it MUST reply directly with the response body; do not use `tellaskBack` to send final delivery.
243
243
  - Runtime treats that direct reply as the completion delivery to the tellasker and injects the work-language marker automatically (`【Completed】` in English work language, `【最终完成】` in Chinese work language).
244
+ - There is no separate technical state for keeping Side Dialogs active. A Side Dialog continues because normal business state still requires work: a tool result needs reaction, Q4H is pending, a downstream Side Dialog is pending, or an explicit runtime/user prompt is queued. Do not add a side path whose only purpose is to keep a dialog active.
245
+ - Reply-obligation tail handling is one small state machine: after runtime reaches a non-suspended tail, it inspects the newest non-empty assistant generation candidate produced by the current drive, preferring public saying over thinking when both exist on the same generation. If a Side Dialog still owes `replyTellask*` and has produced that candidate content without using the exact reply tool, runtime queues one reply-tool reminder. If the next answer to that reminder is still only thinking/saying, runtime intentionally delivers that content through direct-reply fallback and marks it as fallback.
246
+ - Runtime must not infer this tail state by scanning historical message text. Historical context is for the model and the UI; scheduling state must be carried explicitly by the current drive result, active reply obligation, pending blocker indexes, or queued prompts.
244
247
  - If the work is unfinished, do not default to `tellaskBack`; first use team SOP / role ownership to judge whether a responsible owner is already clear, and if yes for execution work, directly use `tellask` / `tellaskSessionless` for that owner.
245
248
  - Use `tellaskBack({ tellaskContent: "..." })` only when the tellasker must clarify the request, decide a tradeoff, confirm acceptance criteria, provide missing input, or current SOP cannot determine ownership.
246
249
  - **FBR exception**: FBR Side Dialogs forbid all tellask calls (including `tellaskBack` / `tellask` / `tellaskSessionless` / `askHuman`); they must list missing context and return.
@@ -239,6 +239,9 @@ flowchart TD
239
239
  **支线交付规则(规范)**:
240
240
 
241
241
  - 只有当所有目标完成时,支线对话才可直接正常回复诉请者。
242
+ - 支线对话没有独立的活性维持状态。支线继续推进,是因为正常业务状态仍未完成:工具结果需要处理、Q4H 待答、下游支线待回贴,或已有显式 runtime/user prompt 排队。不要新增只为维持活跃而存在的旁路。
243
+ - 回复义务的尾部处理是一条很小的状态机:运行时到达未挂起的尾部后,只检查本次 drive 产出的最新非空 assistant generation 候选;同一 generation 同时存在 saying/thinking 时优先取公开 saying。若支线仍欠 `replyTellask*`,并且已经产出候选内容但没有调用精确 reply 工具,运行时只排队一次 reply-tool reminder;如果模型在 reminder 后仍只产出 thinking/saying,运行时会有意通过 direct-reply fallback 投递该内容,并显式标注 fallback。
244
+ - 运行时不得通过回扫历史消息文本来推断这个尾部状态。历史上下文属于模型和 UI;调度状态必须由当前 drive result、active reply obligation、pending blocker 索引或 queued prompt 等显式状态携带。
242
245
  - 若目标尚未完成,不要默认直接 `tellaskBack`;应先按团队规程 / SOP / 职责卡判断能否明确负责人,若能明确且属于执行性处理,直接 `tellask` / `tellaskSessionless` 对应负责人。
243
246
  - 只有当必须由诉请者补充需求、澄清目标、做业务裁决、确认验收口径、提供缺失输入,或现有规程无法明确判责时,才使用 `tellaskBack({ tellaskContent: "..." })` 回问诉请者再继续。
244
247
  - **FBR 例外**:FBR 支线对话禁止一切 tellask(包括 `tellaskBack` / `tellask` / `tellaskSessionless` / `askHuman`),只能列出缺口与阻塞原因并直接回复。
@@ -77,13 +77,15 @@ idle" path. In that recovery-only case, pending sideDialogs do not veto the sing
77
77
  injection, because the deadlock may happen in a function-result-driven generation round right after
78
78
  the main dialog has already registered an in-flight tellask/sideDialog.
79
79
 
80
- Side Dialogs may also use this recovery path, but only when an active reply obligation still exists.
81
- If no active reply obligation exists, runtime does not inject a push and leaves the retry-stopped
82
- state for a human to handle. The Side Dialog recovery template does not read rtws diligence files;
83
- it uses a built-in bilingual template containing the current time, the current Tellask goal, and the
84
- single runtime-confirmed `replyTellask*` tool (for example
85
- `replyTellaskSessionless({ replyContent })`). The LLM must not guess the reply variant. Q4H remains
86
- a hard blocker.
80
+ Side Dialogs may also use this recovery path, but only for provider/API retry-stopped deadlock
81
+ recovery while an active reply obligation still exists. This is not a general mechanism for keeping
82
+ Side Dialogs active. Normal Side Dialog continuation must come from ordinary business state: tool
83
+ results, Q4H, downstream Side Dialog blockers, or queued runtime/user prompts. If no active reply
84
+ obligation exists, runtime does not inject a push and leaves the retry-stopped state for a human to
85
+ handle. The Side Dialog recovery template does not read rtws diligence files; it uses a built-in
86
+ bilingual template containing the current time, the current Tellask goal, and the single
87
+ runtime-confirmed `replyTellask*` tool (for example `replyTellaskSessionless({ replyContent })`).
88
+ The LLM must not guess the reply variant. Q4H remains a hard blocker.
87
89
 
88
90
  ### Action
89
91
 
@@ -263,8 +263,23 @@ function extractReasoningPayload(item) {
263
263
  reasoning.content = content;
264
264
  if (encrypted)
265
265
  reasoning.encrypted_content = encrypted;
266
+ const hasReasoningData = summary.length > 0 || (content?.length ?? 0) > 0 || encrypted !== undefined;
267
+ if (hasReasoningData) {
268
+ reasoning.metadata = {
269
+ itemType: item.type,
270
+ };
271
+ if (typeof item.id === 'string' && item.id.length > 0) {
272
+ reasoning.metadata.itemId = item.id;
273
+ }
274
+ }
266
275
  return reasoning;
267
276
  }
277
+ function hasReasoningPayloadSignals(payload) {
278
+ return (payload.summary.length > 0 ||
279
+ (payload.content?.length ?? 0) > 0 ||
280
+ (payload.encrypted_content?.length ?? 0) > 0 ||
281
+ payload.metadata !== undefined);
282
+ }
268
283
  function buildReasoningPayloadFromText(text) {
269
284
  if (text.trim().length === 0)
270
285
  return undefined;
@@ -932,7 +947,7 @@ class CodexGen {
932
947
  : sawReasoningDeltaWithoutItemId;
933
948
  if (!sawReasoningDelta) {
934
949
  const text = extractReasoningText(event.item);
935
- if (text.length > 0) {
950
+ if (text.length > 0 || hasReasoningPayloadSignals(payloadFromItem)) {
936
951
  if (activeStream === 'saying') {
937
952
  const detail = 'CODEX stream overlap violation: received reasoning while saying stream still active';
938
953
  log.error(detail, new Error('codex_stream_overlap_violation'));
@@ -951,9 +966,11 @@ class CodexGen {
951
966
  await receiver.thinkingStart();
952
967
  activeStream = 'thinking';
953
968
  }
954
- currentThinkingContent += text;
955
- await receiver.thinkingChunk(text);
956
- await receiver.thinkingFinish(payloadFromItem ?? buildReasoningPayloadFromText(currentThinkingContent));
969
+ if (text.length > 0) {
970
+ currentThinkingContent += text;
971
+ await receiver.thinkingChunk(text);
972
+ }
973
+ await receiver.thinkingFinish(payloadFromItem);
957
974
  thinkingStarted = false;
958
975
  currentThinkingContent = '';
959
976
  if (activeStream === 'thinking')
@@ -961,12 +978,16 @@ class CodexGen {
961
978
  }
962
979
  }
963
980
  else if (thinkingStarted) {
964
- await receiver.thinkingFinish(payloadFromItem ?? buildReasoningPayloadFromText(currentThinkingContent));
981
+ await receiver.thinkingFinish(payloadFromItem);
965
982
  thinkingStarted = false;
966
983
  currentThinkingContent = '';
967
984
  if (activeStream === 'thinking')
968
985
  activeStream = 'idle';
969
986
  }
987
+ else if (hasReasoningPayloadSignals(payloadFromItem)) {
988
+ await receiver.thinkingStart();
989
+ await receiver.thinkingFinish(payloadFromItem);
990
+ }
970
991
  return;
971
992
  }
972
993
  case 'local_shell_call':
@@ -1135,8 +1135,28 @@ function extractReasoningPayload(item) {
1135
1135
  out.content = content;
1136
1136
  if (encrypted)
1137
1137
  out.encrypted_content = encrypted;
1138
+ const hasReasoningData = summary.length > 0 || content.length > 0 || encrypted !== undefined;
1139
+ if (hasReasoningData) {
1140
+ const metadata = { itemType: item.type };
1141
+ if (typeof item.id === 'string' && item.id.length > 0) {
1142
+ metadata.itemId = item.id;
1143
+ }
1144
+ if (item.status === 'in_progress' ||
1145
+ item.status === 'completed' ||
1146
+ item.status === 'incomplete') {
1147
+ metadata.status = item.status;
1148
+ }
1149
+ out.metadata = metadata;
1150
+ }
1138
1151
  return out;
1139
1152
  }
1153
+ function hasReasoningPayloadSignals(payload) {
1154
+ return (payload !== null &&
1155
+ (payload.summary.length > 0 ||
1156
+ (payload.content?.length ?? 0) > 0 ||
1157
+ (payload.encrypted_content?.length ?? 0) > 0 ||
1158
+ payload.metadata !== undefined));
1159
+ }
1140
1160
  function openAiResponseToBatchOutputs(response, genseq) {
1141
1161
  const outputs = [];
1142
1162
  const output = response.output;
@@ -1149,7 +1169,7 @@ function openAiResponseToBatchOutputs(response, genseq) {
1149
1169
  if (item.type === 'reasoning') {
1150
1170
  const reasoning = extractReasoningPayload(item);
1151
1171
  const content = extractReasoningText(item);
1152
- if (content.length > 0 || reasoning !== null) {
1172
+ if (content.length > 0 || hasReasoningPayloadSignals(reasoning)) {
1153
1173
  outputs.push({
1154
1174
  kind: 'message',
1155
1175
  message: {
@@ -1157,7 +1177,7 @@ function openAiResponseToBatchOutputs(response, genseq) {
1157
1177
  role: 'assistant',
1158
1178
  genseq,
1159
1179
  content,
1160
- reasoning: reasoning ?? undefined,
1180
+ ...(reasoning !== null ? { reasoning } : {}),
1161
1181
  },
1162
1182
  });
1163
1183
  }
@@ -1655,6 +1675,7 @@ class OpenAiGen {
1655
1675
  const sawReasoningDelta = itemId !== null
1656
1676
  ? streamedReasoningItemIds.has(itemId)
1657
1677
  : sawReasoningDeltaWithoutItemId;
1678
+ const payload = extractReasoningPayload(item);
1658
1679
  if (sawReasoningDelta) {
1659
1680
  if (itemId !== null) {
1660
1681
  streamedReasoningItemIds.delete(itemId);
@@ -1662,9 +1683,20 @@ class OpenAiGen {
1662
1683
  else {
1663
1684
  sawReasoningDeltaWithoutItemId = false;
1664
1685
  }
1686
+ if (thinkingStarted) {
1687
+ await receiver.thinkingFinish(payload ?? buildReasoningPayloadFromText(currentThinkingContent));
1688
+ thinkingStarted = false;
1689
+ currentThinkingContent = '';
1690
+ if (activeStream === 'thinking')
1691
+ activeStream = 'idle';
1692
+ break;
1693
+ }
1694
+ if (hasReasoningPayloadSignals(payload)) {
1695
+ await receiver.thinkingStart();
1696
+ await receiver.thinkingFinish(payload);
1697
+ }
1665
1698
  break;
1666
1699
  }
1667
- const payload = extractReasoningPayload(item);
1668
1700
  const text = extractReasoningText(item);
1669
1701
  if (thinkingStarted) {
1670
1702
  if (currentThinkingContent.length === 0 && text.length > 0) {
@@ -1678,7 +1710,7 @@ class OpenAiGen {
1678
1710
  activeStream = 'idle';
1679
1711
  break;
1680
1712
  }
1681
- if (text.length > 0 || payload !== null) {
1713
+ if (text.length > 0 || hasReasoningPayloadSignals(payload)) {
1682
1714
  if (activeStream === 'saying') {
1683
1715
  if (sayingStarted) {
1684
1716
  await receiver.sayingFinish();
@@ -3,10 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.emitThinkingEvents = emitThinkingEvents;
4
4
  exports.emitSayingEvents = emitSayingEvents;
5
5
  async function emitThinkingEvents(dlg, content, reasoning) {
6
- if (!content.trim())
7
- return undefined;
6
+ const hasContent = content.trim().length > 0;
7
+ if (!hasContent && reasoning === undefined)
8
+ return;
8
9
  await dlg.thinkingStart();
9
- await dlg.thinkingChunk(content);
10
+ if (hasContent) {
11
+ await dlg.thinkingChunk(content);
12
+ }
10
13
  await dlg.thinkingFinish(reasoning);
11
14
  }
12
15
  async function emitSayingEvents(dlg, content) {
@@ -81,6 +81,7 @@ function isNonIdleDisplayProjection(state) {
81
81
  return state !== undefined && state.kind !== 'idle_waiting_user';
82
82
  }
83
83
  function resolveDirectFallbackResponse(args) {
84
+ let saying;
84
85
  if (args.driveResult.lastAssistantSayingContent !== null &&
85
86
  args.driveResult.lastAssistantSayingContent.trim() !== '') {
86
87
  if (typeof args.driveResult.lastAssistantSayingGenseq !== 'number' ||
@@ -88,16 +89,22 @@ function resolveDirectFallbackResponse(args) {
88
89
  args.driveResult.lastAssistantSayingGenseq <= 0) {
89
90
  throw new Error(`Direct reply fallback invariant violation: missing lastAssistantSayingGenseq for dialog=${args.dialog.id.valueOf()}`);
90
91
  }
91
- return {
92
+ saying = {
92
93
  responseText: args.driveResult.lastAssistantSayingContent,
93
94
  responseGenseq: Math.floor(args.driveResult.lastAssistantSayingGenseq),
94
95
  source: 'saying',
95
96
  };
96
97
  }
97
- // Thinking-only output is intentionally a fallback candidate: some providers/models can finish a
98
- // Side Dialog with useful content in thinking and no public saying. This helper only extracts the
99
- // candidate; callers below must still reject it when a same-round function/tellask call needs
100
- // auto-continuation, when the dialog is suspended, or when another follow-up prompt is queued.
98
+ // Thinking output is intentionally a fallback candidate: some providers/models can finish a
99
+ // Side Dialog with useful content in thinking and no public saying. Pick the newest non-empty
100
+ // assistant generation candidate across the whole drive, preferring public saying over thinking
101
+ // on the same generation. A post-tool thinking segment must not be shadowed by an older pre-tool
102
+ // saying segment from an earlier generation iteration.
103
+ //
104
+ // This helper only extracts the candidate; callers below must still reject it when a same-round
105
+ // function/tellask call needs auto-continuation, when the dialog is suspended, or when another
106
+ // follow-up prompt is queued.
107
+ let thinking;
101
108
  if (args.driveResult.lastAssistantThinkingContent !== null &&
102
109
  args.driveResult.lastAssistantThinkingContent.trim() !== '') {
103
110
  if (typeof args.driveResult.lastAssistantThinkingGenseq !== 'number' ||
@@ -105,13 +112,16 @@ function resolveDirectFallbackResponse(args) {
105
112
  args.driveResult.lastAssistantThinkingGenseq <= 0) {
106
113
  throw new Error(`Direct reply fallback invariant violation: missing lastAssistantThinkingGenseq for dialog=${args.dialog.id.valueOf()}`);
107
114
  }
108
- return {
115
+ thinking = {
109
116
  responseText: args.driveResult.lastAssistantThinkingContent,
110
117
  responseGenseq: Math.floor(args.driveResult.lastAssistantThinkingGenseq),
111
118
  source: 'thinking_only',
112
119
  };
113
120
  }
114
- return undefined;
121
+ if (saying !== undefined && thinking !== undefined) {
122
+ return saying.responseGenseq >= thinking.responseGenseq ? saying : thinking;
123
+ }
124
+ return saying ?? thinking;
115
125
  }
116
126
  async function buildReplyToolReminderPrompt(args) {
117
127
  return (0, reply_prompt_copy_1.buildReplyToolReminderText)({
@@ -209,79 +219,6 @@ async function loadPendingDiagnosticsSnapshot(args) {
209
219
  };
210
220
  }
211
221
  }
212
- async function hasAssistantOutputAfterAssignmentAnchor(args) {
213
- const events = await persistence_1.DialogPersistence.loadCourseEvents(args.dialog.id, args.dialog.currentCourse, args.dialog.status);
214
- let assignmentGenseq;
215
- for (const event of events) {
216
- if (event.type === 'tellask_anchor_record' &&
217
- event.anchorRole === 'assignment' &&
218
- event.callId === args.callId) {
219
- assignmentGenseq = event.genseq;
220
- continue;
221
- }
222
- if (assignmentGenseq !== undefined &&
223
- (event.type === 'agent_thought_record' || event.type === 'agent_words_record') &&
224
- event.genseq >= assignmentGenseq &&
225
- event.content.trim() !== '') {
226
- return true;
227
- }
228
- }
229
- return false;
230
- }
231
- async function resolveStrandedSideDialogReplyReminderFollowUp(args) {
232
- const latest = await persistence_1.DialogPersistence.loadDialogLatest(args.dialog.id, args.dialog.status);
233
- const displayState = latest?.displayState;
234
- const isRecoverableProjection = displayState?.kind === 'idle_waiting_user' ||
235
- (displayState?.kind === 'stopped' && displayState.reason.kind === 'pending_reply_obligation');
236
- if (!latest ||
237
- !isRecoverableProjection ||
238
- latest.pendingCourseStartPrompt !== undefined ||
239
- latest.executionMarker?.kind === 'dead') {
240
- return undefined;
241
- }
242
- const directive = await (0, tellask_special_1.loadActiveTellaskReplyDirective)(args.dialog);
243
- if (!directive) {
244
- return undefined;
245
- }
246
- const ownerDialogId = directive.targetDialogId.trim();
247
- if (ownerDialogId === '') {
248
- throw new Error(`stranded sideDialog reply recovery invariant violation: empty targetDialogId ` +
249
- `(dialogId=${args.dialog.id.valueOf()}, targetCallId=${directive.targetCallId})`);
250
- }
251
- const pending = await persistence_1.DialogPersistence.loadPendingSideDialogs(new dialog_1.DialogID(ownerDialogId, args.dialog.id.rootId), args.dialog.status);
252
- const pendingRecord = pending.find((record) => record.sideDialogId === args.dialog.id.selfId && record.callId === directive.targetCallId);
253
- if (!pendingRecord) {
254
- return undefined;
255
- }
256
- if (!(await hasAssistantOutputAfterAssignmentAnchor({
257
- dialog: args.dialog,
258
- callId: pendingRecord.callId,
259
- }))) {
260
- return undefined;
261
- }
262
- const language = (0, work_language_1.getWorkLanguage)();
263
- const sideDialogReplyTarget = {
264
- ownerDialogId,
265
- callType: pendingRecord.callType,
266
- callId: pendingRecord.callId,
267
- callSiteCourse: pendingRecord.callSiteCourse,
268
- callSiteGenseq: pendingRecord.callSiteGenseq,
269
- };
270
- return {
271
- kind: 'runtime_sideDialog_reply_reminder',
272
- prompt: await buildReplyToolReminderPrompt({
273
- dlg: args.dialog,
274
- directive,
275
- language,
276
- }),
277
- msgId: (0, id_1.generateShortId)(),
278
- grammar: 'markdown',
279
- origin: 'runtime',
280
- userLanguageCode: language,
281
- tellaskReplyDirective: directive,
282
- sideDialogReplyTarget,
283
- };
284
- }
285
222
  async function clearConsumedDeferredRootQueueIfIdle(dialog) {
286
223
  if (dialog.id.selfId !== dialog.id.rootId) {
287
224
  return;
@@ -741,29 +678,6 @@ async function executeDriveRound(args) {
741
678
  // suspended by pending Q4H or sideDialogs. This prevents duplicate generations when
742
679
  // multiple wake-ups race around the same sideDialog completion boundary.
743
680
  if (!humanPrompt) {
744
- if (dialog instanceof dialog_1.SideDialog && !dialog.hasUpNext()) {
745
- const strandedReplyReminder = await resolveStrandedSideDialogReplyReminderFollowUp({
746
- dialog,
747
- });
748
- if (strandedReplyReminder !== undefined) {
749
- await queueReplyReminderFollowUp({ dialog, followUp: strandedReplyReminder });
750
- args.scheduleDrive(dialog, {
751
- waitInQue: true,
752
- driveOptions: {
753
- source: 'kernel_driver_follow_up',
754
- reason: 'follow_up_prompt',
755
- },
756
- });
757
- log_1.log.warn('kernel-driver recovered stranded sideDialog reply obligation by queueing reply reminder', undefined, {
758
- dialogId: dialog.id.valueOf(),
759
- rootId: dialog.id.rootId,
760
- selfId: dialog.id.selfId,
761
- targetCallId: strandedReplyReminder.tellaskReplyDirective.targetCallId,
762
- targetOwnerDialogId: strandedReplyReminder.sideDialogReplyTarget.ownerDialogId,
763
- });
764
- return;
765
- }
766
- }
767
681
  if (dialog instanceof dialog_1.SideDialog && !dialog.hasUpNext()) {
768
682
  try {
769
683
  const inspection = await inspectNoPromptSideDialogDrive({ dialog, driveOptions });
@@ -97,6 +97,7 @@ export declare class DiskFileDialogStore extends DialogStore {
97
97
  private sayingContent;
98
98
  private thinkingContent;
99
99
  private thinkingReasoning;
100
+ private thinkingStarted;
100
101
  sayingStart(dialog: Dialog): Promise<void>;
101
102
  sayingChunk(dialog: Dialog, chunk: string): Promise<void>;
102
103
  sayingFinish(dialog: Dialog): Promise<void>;
@@ -1816,6 +1816,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
1816
1816
  this.sayingContent = '';
1817
1817
  this.thinkingContent = '';
1818
1818
  this.thinkingReasoning = undefined;
1819
+ this.thinkingStarted = false;
1819
1820
  this.dialogId = dialogId;
1820
1821
  }
1821
1822
  // === DialogStore interface methods ===
@@ -2261,6 +2262,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
2261
2262
  // Reset thinking content tracker
2262
2263
  this.thinkingContent = '';
2263
2264
  this.thinkingReasoning = undefined;
2265
+ this.thinkingStarted = true;
2264
2266
  const thinkingStartEvt = {
2265
2267
  type: 'thinking_start_evt',
2266
2268
  course,
@@ -2286,13 +2288,13 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
2286
2288
  if (reasoning)
2287
2289
  this.thinkingReasoning = reasoning;
2288
2290
  const thinkingContent = this.thinkingContent;
2289
- if (thinkingContent || this.thinkingReasoning) {
2291
+ if (this.thinkingStarted || thinkingContent || this.thinkingReasoning) {
2290
2292
  const thinkingMessageEvent = {
2291
2293
  ts: (0, time_1.formatUnifiedTimestamp)(new Date()),
2292
2294
  type: 'agent_thought_record',
2293
2295
  genseq: dialog.activeGenSeq,
2294
2296
  content: thinkingContent,
2295
- reasoning: this.thinkingReasoning,
2297
+ ...(this.thinkingReasoning !== undefined ? { reasoning: this.thinkingReasoning } : {}),
2296
2298
  };
2297
2299
  await this.appendEvent(dialog, course, thinkingMessageEvent);
2298
2300
  }
@@ -2300,8 +2302,10 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
2300
2302
  type: 'thinking_finish_evt',
2301
2303
  course,
2302
2304
  genseq: dialog.activeGenSeq,
2305
+ ...(this.thinkingReasoning !== undefined ? { reasoning: this.thinkingReasoning } : {}),
2303
2306
  };
2304
2307
  (0, evt_registry_1.postDialogEvent)(dialog, thinkingFinishEvt);
2308
+ this.thinkingStarted = false;
2305
2309
  }
2306
2310
  async markdownStart(dialog) {
2307
2311
  const course = dialog.activeGenCourseOrUndefined ?? dialog.currentCourse;
@@ -2805,8 +2809,8 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
2805
2809
  type: 'agent_thought_record',
2806
2810
  genseq,
2807
2811
  content: content || '',
2808
- reasoning,
2809
- provider_data,
2812
+ ...(reasoning !== undefined ? { reasoning } : {}),
2813
+ ...(provider_data !== undefined ? { provider_data } : {}),
2810
2814
  }
2811
2815
  : {
2812
2816
  ts: (0, time_1.formatUnifiedTimestamp)(new Date()),
@@ -3319,43 +3323,26 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
3319
3323
  break;
3320
3324
  }
3321
3325
  case 'agent_thought_record': {
3322
- // Replay thinking content as thinking events
3326
+ // Replay persisted thinking records as substream boundaries, with chunks when content exists.
3323
3327
  const content = event.content || '';
3324
- if (content) {
3325
- // Start thinking phase
3326
- const thinkingStartEvent = {
3327
- type: 'thinking_start_evt',
3328
- course,
3329
- genseq: event.genseq,
3330
- dialog: {
3331
- selfId: dialog.id.selfId,
3332
- rootId: dialog.id.rootId,
3333
- },
3334
- timestamp: event.ts,
3335
- };
3336
- if (ws.readyState === 1) {
3337
- ws.send(JSON.stringify(thinkingStartEvent));
3338
- }
3339
- const thinkingChunks = this.createOptimalChunks(content);
3340
- for (const chunk of thinkingChunks) {
3341
- const thinkingChunkEvent = {
3342
- type: 'thinking_chunk_evt',
3343
- chunk,
3344
- course,
3345
- genseq: event.genseq,
3346
- dialog: {
3347
- selfId: dialog.id.selfId,
3348
- rootId: dialog.id.rootId,
3349
- },
3350
- timestamp: event.ts,
3351
- };
3352
- if (ws.readyState === 1) {
3353
- ws.send(JSON.stringify(thinkingChunkEvent));
3354
- }
3355
- }
3356
- // Finish thinking phase
3357
- const thinkingFinishEvent = {
3358
- type: 'thinking_finish_evt',
3328
+ const thinkingStartEvent = {
3329
+ type: 'thinking_start_evt',
3330
+ course,
3331
+ genseq: event.genseq,
3332
+ dialog: {
3333
+ selfId: dialog.id.selfId,
3334
+ rootId: dialog.id.rootId,
3335
+ },
3336
+ timestamp: event.ts,
3337
+ };
3338
+ if (ws.readyState === 1) {
3339
+ ws.send(JSON.stringify(thinkingStartEvent));
3340
+ }
3341
+ const thinkingChunks = this.createOptimalChunks(content);
3342
+ for (const chunk of thinkingChunks) {
3343
+ const thinkingChunkEvent = {
3344
+ type: 'thinking_chunk_evt',
3345
+ chunk,
3359
3346
  course,
3360
3347
  genseq: event.genseq,
3361
3348
  dialog: {
@@ -3365,9 +3352,23 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
3365
3352
  timestamp: event.ts,
3366
3353
  };
3367
3354
  if (ws.readyState === 1) {
3368
- ws.send(JSON.stringify(thinkingFinishEvent));
3355
+ ws.send(JSON.stringify(thinkingChunkEvent));
3369
3356
  }
3370
3357
  }
3358
+ const thinkingFinishEvent = {
3359
+ type: 'thinking_finish_evt',
3360
+ course,
3361
+ genseq: event.genseq,
3362
+ ...(event.reasoning !== undefined ? { reasoning: event.reasoning } : {}),
3363
+ dialog: {
3364
+ selfId: dialog.id.selfId,
3365
+ rootId: dialog.id.rootId,
3366
+ },
3367
+ timestamp: event.ts,
3368
+ };
3369
+ if (ws.readyState === 1) {
3370
+ ws.send(JSON.stringify(thinkingFinishEvent));
3371
+ }
3371
3372
  break;
3372
3373
  }
3373
3374
  case 'agent_words_record': {
@@ -6933,8 +6934,8 @@ class DialogPersistence {
6933
6934
  role: 'assistant',
6934
6935
  genseq: event.genseq,
6935
6936
  content: event.content,
6936
- reasoning: event.reasoning,
6937
- provider_data: event.provider_data,
6937
+ ...(event.reasoning !== undefined ? { reasoning: event.reasoning } : {}),
6938
+ ...(event.provider_data !== undefined ? { provider_data: event.provider_data } : {}),
6938
6939
  });
6939
6940
  break;
6940
6941
  }