dominds 1.27.2 → 1.27.4

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 (47) hide show
  1. package/dist/apps/runtime.js +3 -1
  2. package/dist/dialog-fork.js +2 -1
  3. package/dist/dialog-global-registry.d.ts +11 -1
  4. package/dist/dialog-global-registry.js +45 -0
  5. package/dist/dialog.d.ts +14 -5
  6. package/dist/dialog.js +114 -21
  7. package/dist/docs/daemon-cmd-runner.md +5 -0
  8. package/dist/docs/daemon-cmd-runner.zh.md +5 -0
  9. package/dist/llm/kernel-driver/drive.js +228 -49
  10. package/dist/llm/kernel-driver/fbr.d.ts +9 -0
  11. package/dist/llm/kernel-driver/fbr.js +186 -59
  12. package/dist/mcp/supervisor.js +4 -1
  13. package/dist/minds/load.js +1 -0
  14. package/dist/minds/system-prompt-parts.js +30 -30
  15. package/dist/persistence.js +83 -17
  16. package/dist/priming.js +2 -3
  17. package/dist/runtime/driver-messages.d.ts +9 -0
  18. package/dist/runtime/driver-messages.js +103 -33
  19. package/dist/runtime/shared-reminder-update-impact.d.ts +20 -0
  20. package/dist/runtime/shared-reminder-update-impact.js +110 -0
  21. package/dist/shared-reminders.js +2 -2
  22. package/dist/tool-availability.js +1 -0
  23. package/dist/tool.d.ts +7 -4
  24. package/dist/tool.js +10 -4
  25. package/dist/tools/app-reminders.js +4 -3
  26. package/dist/tools/builtins.js +2 -0
  27. package/dist/tools/cmd-runner-protocol.d.ts +6 -0
  28. package/dist/tools/cmd-runner-protocol.js +57 -2
  29. package/dist/tools/cmd-runner.js +83 -2
  30. package/dist/tools/ctrl.d.ts +2 -0
  31. package/dist/tools/ctrl.js +183 -6
  32. package/dist/tools/os.js +115 -14
  33. package/dist/tools/pending-tellask-reminder.js +1 -0
  34. package/dist/tools/process-kill.js +49 -0
  35. package/dist/tools/prompts/control/en/errors.md +1 -1
  36. package/dist/tools/prompts/control/en/index.md +4 -4
  37. package/dist/tools/prompts/control/en/principles.md +22 -21
  38. package/dist/tools/prompts/control/en/scenarios.md +10 -3
  39. package/dist/tools/prompts/control/en/tools.md +28 -5
  40. package/dist/tools/prompts/control/zh/errors.md +1 -1
  41. package/dist/tools/prompts/control/zh/index.md +4 -4
  42. package/dist/tools/prompts/control/zh/principles.md +21 -20
  43. package/dist/tools/prompts/control/zh/scenarios.md +10 -3
  44. package/dist/tools/prompts/control/zh/tools.md +28 -5
  45. package/dist/tools/prompts/os/en/tools.md +2 -0
  46. package/dist/tools/prompts/os/zh/tools.md +2 -0
  47. package/package.json +4 -4
@@ -123,7 +123,9 @@ async function resolveTargetDialog(sourceDlg, target) {
123
123
  }
124
124
  return sideDialog;
125
125
  }
126
- const matches = targetRoot.getAllDialogs().filter((dialog) => dialog.agentId === target.agentId);
126
+ const matches = targetRoot
127
+ .getLoadedDialogTreeSnapshot()
128
+ .filter((dialog) => dialog.agentId === target.agentId);
127
129
  if (matches.length === 1) {
128
130
  return matches[0];
129
131
  }
@@ -483,9 +483,10 @@ async function appendForkBaselineState(plan, baselineSideDialogCreatedRecords) {
483
483
  ownerName: reminder.owner?.name,
484
484
  meta: reminder.meta,
485
485
  echoback: reminder.echoback,
486
- scope: reminder.scope ?? 'dialog',
486
+ scope: reminder.scope,
487
487
  createdAt: reminder.createdAt ?? baselineTs,
488
488
  priority: reminder.priority ?? 'medium',
489
+ renderMode: reminder.renderMode,
489
490
  })),
490
491
  };
491
492
  const q4hRecord = {
@@ -1,4 +1,4 @@
1
- import { type MainDialog } from './dialog';
1
+ import { type Dialog, type MainDialog } from './dialog';
2
2
  export type DriveTriggerEvent = Readonly<{
3
3
  type: 'drive_trigger_evt';
4
4
  action: 'queue_root_drive' | 'clear_root_drive_queue' | 'active_run_cleared';
@@ -47,6 +47,16 @@ declare class GlobalDialogRegistry {
47
47
  noteActiveRunBlockedQueuedDrive(rootId: string): void;
48
48
  hasPendingActiveRunClearedDrive(rootId: string): boolean;
49
49
  isRootDriveQueued(rootId: string): boolean;
50
+ /**
51
+ * One-shot runtime snapshot for shared-reminder impact routing.
52
+ *
53
+ * This intentionally does not enumerate persisted "all running dialogs". It walks only the roots
54
+ * this runtime has already registered, and includes only dialogs with direct in-memory evidence
55
+ * of current work: locked running main dialogs and the loaded active-callee frontier under each
56
+ * root. Dialogs that merely remain in memory/history but have no current-work signal are not
57
+ * considered parallel work.
58
+ */
59
+ getLoadedInFlightDialogsForSharedReminderImpact(): Dialog[];
50
60
  getLastDriveTrigger(rootId: string): DriveTriggerEvent | undefined;
51
61
  consumeQueuedMainDialogs(): MainDialog[];
52
62
  get size(): number;
@@ -218,6 +218,51 @@ class GlobalDialogRegistry {
218
218
  isRootDriveQueued(rootId) {
219
219
  return this.entries.get(rootId)?.driveQueued === true;
220
220
  }
221
+ /**
222
+ * One-shot runtime snapshot for shared-reminder impact routing.
223
+ *
224
+ * This intentionally does not enumerate persisted "all running dialogs". It walks only the roots
225
+ * this runtime has already registered, and includes only dialogs with direct in-memory evidence
226
+ * of current work: locked running main dialogs and the loaded active-callee frontier under each
227
+ * root. Dialogs that merely remain in memory/history but have no current-work signal are not
228
+ * considered parallel work.
229
+ */
230
+ getLoadedInFlightDialogsForSharedReminderImpact() {
231
+ const dialogs = [];
232
+ for (const entry of this.entries.values()) {
233
+ const rootDialog = entry.mainDialog;
234
+ const visitedDialogIds = new Set();
235
+ const stack = [];
236
+ if (rootDialog.status === 'running' && rootDialog.isLocked()) {
237
+ dialogs.push(rootDialog);
238
+ visitedDialogIds.add(rootDialog.id.valueOf());
239
+ }
240
+ for (const calleeId of rootDialog.activeCalleeDialogIds) {
241
+ const loadedCallee = rootDialog.lookupDialog(calleeId.selfId);
242
+ if (loadedCallee && loadedCallee.status === 'running') {
243
+ stack.push(loadedCallee);
244
+ }
245
+ }
246
+ while (stack.length > 0) {
247
+ const current = stack.pop();
248
+ if (!current || visitedDialogIds.has(current.id.valueOf())) {
249
+ continue;
250
+ }
251
+ visitedDialogIds.add(current.id.valueOf());
252
+ if (current.status !== 'running') {
253
+ continue;
254
+ }
255
+ dialogs.push(current);
256
+ for (const calleeId of current.activeCalleeDialogIds) {
257
+ const loadedCallee = rootDialog.lookupDialog(calleeId.selfId);
258
+ if (loadedCallee && loadedCallee.status === 'running') {
259
+ stack.push(loadedCallee);
260
+ }
261
+ }
262
+ }
263
+ }
264
+ return dialogs;
265
+ }
221
266
  getLastDriveTrigger(rootId) {
222
267
  return this.lastDriveTriggerByRootId.get(rootId);
223
268
  }
package/dist/dialog.d.ts CHANGED
@@ -21,7 +21,7 @@ import { ChatMessage, FuncResultMsg, TellaskCarryoverMsg, TellaskResultMsg } fro
21
21
  import type { ToolResultImageIngest, UserImageIngest } from './llm/gen';
22
22
  import { type SharedReminderTarget } from './shared-reminders';
23
23
  import type { JsonValue } from './tool';
24
- import { Reminder, ReminderOptions, ReminderOwner } from './tool';
24
+ import { Reminder, ReminderOptions, ReminderOwner, ReminderUpdateOptions } from './tool';
25
25
  export declare class InvalidReminderIndexError extends Error {
26
26
  readonly index: number;
27
27
  readonly total: number;
@@ -265,9 +265,9 @@ export declare abstract class Dialog {
265
265
  * Post a dialog event using the standard event registry.
266
266
  */
267
267
  postEvent(event: DialogEvent): void;
268
- addReminder(content: string, owner?: ReminderOwner, meta?: JsonValue, position?: number, options?: ReminderOptions): Reminder;
268
+ addReminder(content: string, owner: ReminderOwner | undefined, meta: JsonValue | undefined, position: number | undefined, options: ReminderOptions): Reminder;
269
269
  deleteReminder(index: number): Reminder;
270
- updateReminder(index: number, content: string, meta?: JsonValue, options?: ReminderOptions): Reminder;
270
+ updateReminder(index: number, content: string, meta?: JsonValue, options?: ReminderUpdateOptions): Reminder;
271
271
  clearReminders(): void;
272
272
  listVisibleReminderTargets(): Promise<VisibleReminderTarget[]>;
273
273
  listVisibleReminders(): Promise<Reminder[]>;
@@ -275,6 +275,8 @@ export declare abstract class Dialog {
275
275
  private processReminderCollection;
276
276
  private buildVisibleReminderContents;
277
277
  private emitFullRemindersUpdate;
278
+ private reportReminderRuntimeFailure;
279
+ private dispatchSharedReminderOwnerUpdateImpacts;
278
280
  /**
279
281
  * Emits current visible reminders without reconciling tool-owned state or writing persistence.
280
282
  * This is for read-only dialog display, especially completed/archived dialogs opened from old tabs.
@@ -371,6 +373,13 @@ export declare abstract class Dialog {
371
373
  tellaskReplyDirective: TellaskReplyDirective;
372
374
  skipTaskdoc?: boolean;
373
375
  }): Promise<DialogQueuedPromptState>;
376
+ queueRuntimeGuidePrompt(options: {
377
+ prompt: string;
378
+ msgId: string;
379
+ grammar: 'markdown';
380
+ userLanguageCode?: LanguageCode;
381
+ skipTaskdoc?: boolean;
382
+ }): Promise<DialogQueuedPromptState>;
374
383
  queueRuntimeSideDialogPrompt(options: {
375
384
  prompt: string;
376
385
  msgId: string;
@@ -529,9 +538,9 @@ export declare class MainDialog extends Dialog {
529
538
  */
530
539
  lookupDialog(selfId: string): Dialog | undefined;
531
540
  /**
532
- * Get all registered dialogs in this dialog tree.
541
+ * Snapshot of dialogs loaded in this root's in-memory dialog tree.
533
542
  */
534
- getAllDialogs(): Dialog[];
543
+ getLoadedDialogTreeSnapshot(): Dialog[];
535
544
  /**
536
545
  * Remove a dialog from the local registry.
537
546
  */
package/dist/dialog.js CHANGED
@@ -478,13 +478,16 @@ class Dialog {
478
478
  //
479
479
  // Reminder management methods
480
480
  addReminder(content, owner, meta, position, options) {
481
+ if (options === undefined) {
482
+ throw new Error('Dialog.addReminder requires explicit reminder options');
483
+ }
481
484
  const reminder = (0, tool_1.materializeReminder)({
482
485
  content,
483
486
  owner,
484
487
  meta,
485
- echoback: options?.echoback,
486
- scope: options?.scope ?? 'dialog',
487
- renderMode: options?.renderMode,
488
+ echoback: options.echoback,
489
+ scope: options.scope,
490
+ renderMode: options.renderMode,
488
491
  });
489
492
  const insertIndex = position !== undefined ? position : this.reminders.length;
490
493
  if (insertIndex < 0 || insertIndex > this.reminders.length) {
@@ -572,6 +575,7 @@ class Dialog {
572
575
  }
573
576
  async processReminderCollection(reminders) {
574
577
  let changed = false;
578
+ const updatedReminderIds = [];
575
579
  const indicesToRemove = [];
576
580
  for (let i = 0; i < reminders.length; i++) {
577
581
  const reminder = reminders[i];
@@ -599,26 +603,42 @@ class Dialog {
599
603
  priority: reminder.priority,
600
604
  renderMode: reminder.renderMode,
601
605
  });
602
- const contentChanged = updatedReminder.content !== reminder.content;
603
- const metaChanged = updatedReminder.meta !== reminder.meta;
604
- if (contentChanged || metaChanged) {
606
+ const reminderChanged = (0, tool_1.computeReminderRenderRevision)(updatedReminder) !==
607
+ (0, tool_1.computeReminderRenderRevision)(reminder);
608
+ if (reminderChanged) {
605
609
  reminders[i] = updatedReminder;
606
610
  changed = true;
611
+ updatedReminderIds.push(updatedReminder.id);
607
612
  }
608
613
  break;
609
614
  }
610
615
  case 'keep':
611
616
  break;
617
+ default: {
618
+ const _exhaustive = result.treatment;
619
+ return _exhaustive;
620
+ }
612
621
  }
613
622
  }
614
623
  catch (error) {
615
- log_1.log.error(`Error updating reminder from tool ${reminder.owner}:`, error);
624
+ const detail = `Reminder owner update failed ` +
625
+ `(rootId=${this.id.rootId}, selfId=${this.id.selfId}, course=${this.currentCourse}, ` +
626
+ `reminderId=${reminder.id}, owner=${reminder.owner.name}, taskDocPath=${this.taskDocPath})`;
627
+ await this.reportReminderRuntimeFailure(detail, error, {
628
+ rootId: this.id.rootId,
629
+ selfId: this.id.selfId,
630
+ course: this.currentCourse,
631
+ reminderId: reminder.id,
632
+ ownerName: reminder.owner.name,
633
+ taskDocPath: this.taskDocPath,
634
+ });
635
+ throw error;
616
636
  }
617
637
  }
618
638
  for (let i = indicesToRemove.length - 1; i >= 0; i--) {
619
639
  reminders.splice(indicesToRemove[i], 1);
620
640
  }
621
- return changed;
641
+ return { changed, updatedReminderIds };
622
642
  }
623
643
  buildVisibleReminderContents(taskSharedReminders, runtimeReminders) {
624
644
  const visibleReminders = [
@@ -634,7 +654,7 @@ class Dialog {
634
654
  renderRevision: (0, tool_1.computeReminderRenderRevision)(r),
635
655
  echoback: (0, tool_1.reminderEchoBackEnabled)(r),
636
656
  scope: r.scope,
637
- renderMode: r.renderMode ?? 'markdown',
657
+ renderMode: r.renderMode,
638
658
  }));
639
659
  }
640
660
  emitFullRemindersUpdate(reminders) {
@@ -644,6 +664,32 @@ class Dialog {
644
664
  };
645
665
  (0, evt_registry_1.postDialogEvent)(this, fullRemindersEvt);
646
666
  }
667
+ async reportReminderRuntimeFailure(detail, error, context) {
668
+ try {
669
+ await this.streamError(detail);
670
+ }
671
+ catch (streamError) {
672
+ log_1.log.warn('Failed to emit stream_error_evt for reminder runtime failure', streamError, {
673
+ ...context,
674
+ streamErrorMessage: streamError instanceof Error ? streamError.message : String(streamError),
675
+ });
676
+ }
677
+ log_1.log.error(detail, error, {
678
+ ...context,
679
+ errorMessage: error instanceof Error ? error.message : String(error),
680
+ });
681
+ }
682
+ async dispatchSharedReminderOwnerUpdateImpacts(reminderIds, scope) {
683
+ const { dispatchSharedReminderUpdateImpact } = await import('./runtime/shared-reminder-update-impact.js');
684
+ for (const reminderId of reminderIds) {
685
+ await dispatchSharedReminderUpdateImpact({
686
+ updater: this,
687
+ reminderId,
688
+ scope,
689
+ language: (0, work_language_1.getWorkLanguage)(),
690
+ });
691
+ }
692
+ }
647
693
  /**
648
694
  * Emits current visible reminders without reconciling tool-owned state or writing persistence.
649
695
  * This is for read-only dialog display, especially completed/archived dialogs opened from old tabs.
@@ -675,10 +721,10 @@ class Dialog {
675
721
  const runtimeTarget = { kind: 'agent', agentId: this.agentId };
676
722
  const taskSharedReminders = await (0, shared_reminders_1.loadSharedReminders)(taskSharedTarget);
677
723
  const runtimeReminders = await (0, shared_reminders_1.loadSharedReminders)(runtimeTarget);
678
- const localChanged = await this.processReminderCollection(this.reminders);
679
- const taskSharedChanged = await this.processReminderCollection(taskSharedReminders);
680
- const runtimeChanged = await this.processReminderCollection(runtimeReminders);
681
- if (localChanged || taskSharedChanged || runtimeChanged) {
724
+ const localResult = await this.processReminderCollection(this.reminders);
725
+ const taskSharedResult = await this.processReminderCollection(taskSharedReminders);
726
+ const runtimeResult = await this.processReminderCollection(runtimeReminders);
727
+ if (localResult.changed || taskSharedResult.changed || runtimeResult.changed) {
682
728
  this.touchReminders();
683
729
  }
684
730
  // Centralized persistence - called when emitting event.
@@ -687,26 +733,55 @@ class Dialog {
687
733
  await this.dlgStore.persistReminders(this, this.reminders);
688
734
  }
689
735
  catch (err) {
690
- log_1.log.warn('Failed to persist reminders', err, { dialogId: this.id.valueOf() });
736
+ const detail = `Failed to persist dialog-local reminders ` +
737
+ `(rootId=${this.id.rootId}, selfId=${this.id.selfId}, course=${this.currentCourse})`;
738
+ await this.reportReminderRuntimeFailure(detail, err, {
739
+ rootId: this.id.rootId,
740
+ selfId: this.id.selfId,
741
+ course: this.currentCourse,
742
+ taskDocPath: this.taskDocPath,
743
+ });
744
+ throw err;
691
745
  }
692
746
  try {
693
747
  await (0, shared_reminders_1.replaceSharedReminders)(taskSharedTarget, taskSharedReminders);
694
748
  }
695
749
  catch (err) {
696
- log_1.log.warn('Failed to persist task-scoped reminders', err, {
697
- dialogId: this.id.valueOf(),
750
+ const detail = `Failed to persist task-scoped reminders ` +
751
+ `(rootId=${this.id.rootId}, selfId=${this.id.selfId}, course=${this.currentCourse}, ` +
752
+ `agentId=${this.agentId}, taskDocPath=${this.taskDocPath})`;
753
+ await this.reportReminderRuntimeFailure(detail, err, {
754
+ rootId: this.id.rootId,
755
+ selfId: this.id.selfId,
756
+ course: this.currentCourse,
698
757
  agentId: this.agentId,
699
758
  taskDocPath: this.taskDocPath,
700
759
  });
760
+ throw err;
701
761
  }
762
+ await this.dispatchSharedReminderOwnerUpdateImpacts(taskSharedResult.updatedReminderIds, 'task');
702
763
  try {
703
764
  await (0, shared_reminders_1.replaceSharedReminders)(runtimeTarget, runtimeReminders);
704
765
  }
705
766
  catch (err) {
706
- log_1.log.warn('Failed to persist agent-scoped reminders', err, {
707
- dialogId: this.id.valueOf(),
767
+ const detail = `Failed to persist agent-scoped reminders ` +
768
+ `(rootId=${this.id.rootId}, selfId=${this.id.selfId}, course=${this.currentCourse}, ` +
769
+ `agentId=${this.agentId})`;
770
+ await this.reportReminderRuntimeFailure(detail, err, {
771
+ rootId: this.id.rootId,
772
+ selfId: this.id.selfId,
773
+ course: this.currentCourse,
708
774
  agentId: this.agentId,
775
+ taskDocPath: this.taskDocPath,
709
776
  });
777
+ throw err;
778
+ }
779
+ for (const reminderId of runtimeResult.updatedReminderIds) {
780
+ const reminder = runtimeReminders.find((candidate) => candidate.id === reminderId);
781
+ if (!reminder) {
782
+ throw new Error(`Updated shared reminder ${reminderId} disappeared before update impact dispatch`);
783
+ }
784
+ await this.dispatchSharedReminderOwnerUpdateImpacts([reminderId], reminder.scope === 'runtime' ? 'runtime' : 'agent');
710
785
  }
711
786
  const reminders = this.buildVisibleReminderContents(taskSharedReminders, runtimeReminders);
712
787
  this.emitFullRemindersUpdate(reminders);
@@ -1168,6 +1243,24 @@ class Dialog {
1168
1243
  });
1169
1244
  return created;
1170
1245
  }
1246
+ async queueRuntimeGuidePrompt(options) {
1247
+ const common = this.runtimePromptCommon(options);
1248
+ const created = {
1249
+ ...common,
1250
+ kind: 'new_course_runtime_guide',
1251
+ skipTaskdoc: options.skipTaskdoc,
1252
+ };
1253
+ this.enqueueQueuedPromptState(created);
1254
+ await this.persistPendingRuntimePrompt({
1255
+ content: created.prompt,
1256
+ msgId: created.msgId,
1257
+ grammar: created.grammar ?? 'markdown',
1258
+ userLanguageCode: created.userLanguageCode,
1259
+ origin: 'runtime',
1260
+ skipTaskdoc: created.skipTaskdoc,
1261
+ });
1262
+ return created;
1263
+ }
1171
1264
  async queueRuntimeSideDialogPrompt(options) {
1172
1265
  const common = this.runtimePromptCommon(options);
1173
1266
  const created = {
@@ -1860,7 +1953,7 @@ exports.SideDialog = SideDialog;
1860
1953
  */
1861
1954
  class MainDialog extends Dialog {
1862
1955
  _status = 'running';
1863
- // Tracks all dialogs in this dialog tree for O(1) lookup
1956
+ // Tracks dialogs loaded into this root's in-memory dialog tree for O(1) lookup
1864
1957
  _localRegistry = new Map();
1865
1958
  // Tracks Type-B registered sideDialogs by agentId!sessionSlug
1866
1959
  _sideDialogRegistry = new Map();
@@ -1887,9 +1980,9 @@ class MainDialog extends Dialog {
1887
1980
  return this._localRegistry.get(selfId);
1888
1981
  }
1889
1982
  /**
1890
- * Get all registered dialogs in this dialog tree.
1983
+ * Snapshot of dialogs loaded in this root's in-memory dialog tree.
1891
1984
  */
1892
- getAllDialogs() {
1985
+ getLoadedDialogTreeSnapshot() {
1893
1986
  return Array.from(this._localRegistry.values());
1894
1987
  }
1895
1988
  /**
@@ -115,6 +115,8 @@ Ownership boundaries are simple:
115
115
  - `pid: number`
116
116
  - `stdout?: boolean`
117
117
  - `stderr?: boolean`
118
+ - `wait_for_new_output?: boolean`
119
+ - `timeout_ms?: number`
118
120
 
119
121
  ### Semantics
120
122
 
@@ -123,6 +125,9 @@ Ownership boundaries are simple:
123
125
  - output order is always `stdout` first, then `stderr`
124
126
  - each stream gets its own heading, content block, and scroll notice
125
127
  - unrequested streams are omitted entirely
128
+ - when `wait_for_new_output=true`, the runner waits until at least one requested stream receives output after the request is accepted
129
+ - if `timeout_ms` is provided, the wait is bounded by that many milliseconds, capped at `86400000` (24h), and returns the current snapshot with an explicit timeout notice
130
+ - `timeout_ms` cannot be combined with `wait_for_new_output=false`; that contradictory argument set returns an error
126
131
 
127
132
  ### Why this is better
128
133
 
@@ -114,6 +114,8 @@ runner 自己作为进程组 leader,daemon 默认继承该 pgid。这样 `stop
114
114
  - `pid: number`
115
115
  - `stdout?: boolean`
116
116
  - `stderr?: boolean`
117
+ - `wait_for_new_output?: boolean`
118
+ - `timeout_ms?: number`
117
119
 
118
120
  ### 语义
119
121
 
@@ -122,6 +124,9 @@ runner 自己作为进程组 leader,daemon 默认继承该 pgid。这样 `stop
122
124
  - 返回顺序固定为 `stdout` 在前、`stderr` 在后
123
125
  - 每个流各自带自己的标题、内容、scroll notice
124
126
  - 未请求的流不展示
127
+ - `wait_for_new_output=true` 时,runner 会等到请求的流中至少一个在请求被接受后出现新输出再返回
128
+ - 提供 `timeout_ms` 时,等待最多持续指定毫秒数,上限为 `86400000`(24 小时);超时后返回当前快照,并显式提示等待超时
129
+ - `timeout_ms` 不可与 `wait_for_new_output=false` 同时使用;这种矛盾参数会直接报错
125
130
 
126
131
  ### 取舍理由
127
132