dominds 1.27.2 → 1.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/apps/runtime.js +3 -1
  2. package/dist/dialog-global-registry.d.ts +11 -1
  3. package/dist/dialog-global-registry.js +45 -0
  4. package/dist/dialog.d.ts +11 -2
  5. package/dist/dialog.js +107 -17
  6. package/dist/docs/daemon-cmd-runner.md +5 -0
  7. package/dist/docs/daemon-cmd-runner.zh.md +5 -0
  8. package/dist/llm/kernel-driver/drive.js +163 -11
  9. package/dist/llm/kernel-driver/fbr.d.ts +9 -0
  10. package/dist/llm/kernel-driver/fbr.js +186 -59
  11. package/dist/minds/load.js +1 -0
  12. package/dist/persistence.js +18 -1
  13. package/dist/runtime/driver-messages.d.ts +9 -0
  14. package/dist/runtime/driver-messages.js +61 -5
  15. package/dist/runtime/shared-reminder-update-impact.d.ts +20 -0
  16. package/dist/runtime/shared-reminder-update-impact.js +110 -0
  17. package/dist/tool-availability.js +1 -0
  18. package/dist/tools/builtins.js +2 -0
  19. package/dist/tools/cmd-runner-protocol.d.ts +6 -0
  20. package/dist/tools/cmd-runner-protocol.js +57 -2
  21. package/dist/tools/cmd-runner.js +83 -2
  22. package/dist/tools/ctrl.d.ts +2 -0
  23. package/dist/tools/ctrl.js +179 -5
  24. package/dist/tools/os.js +115 -14
  25. package/dist/tools/process-kill.js +49 -0
  26. package/dist/tools/prompts/control/en/errors.md +1 -1
  27. package/dist/tools/prompts/control/en/index.md +1 -1
  28. package/dist/tools/prompts/control/en/principles.md +18 -17
  29. package/dist/tools/prompts/control/en/tools.md +24 -1
  30. package/dist/tools/prompts/control/zh/errors.md +1 -1
  31. package/dist/tools/prompts/control/zh/index.md +1 -1
  32. package/dist/tools/prompts/control/zh/principles.md +17 -16
  33. package/dist/tools/prompts/control/zh/tools.md +24 -1
  34. package/dist/tools/prompts/os/en/tools.md +2 -0
  35. package/dist/tools/prompts/os/zh/tools.md +2 -0
  36. package/package.json +4 -4
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MAX_CMD_RUNNER_OUTPUT_WAIT_TIMEOUT_MS = void 0;
6
7
  exports.parseCmdRunnerInitMessage = parseCmdRunnerInitMessage;
7
8
  exports.parseCmdRunnerInitialIpcMessage = parseCmdRunnerInitialIpcMessage;
8
9
  exports.parseCmdRunnerRequestLine = parseCmdRunnerRequestLine;
@@ -10,6 +11,7 @@ exports.parseCmdRunnerResponseLine = parseCmdRunnerResponseLine;
10
11
  exports.getCmdRunnerEndpointForDaemonPid = getCmdRunnerEndpointForDaemonPid;
11
12
  const node_os_1 = __importDefault(require("node:os"));
12
13
  const node_path_1 = __importDefault(require("node:path"));
14
+ exports.MAX_CMD_RUNNER_OUTPUT_WAIT_TIMEOUT_MS = 24 * 60 * 60 * 1_000;
13
15
  function isRecord(value) {
14
16
  return typeof value === 'object' && value !== null && !Array.isArray(value);
15
17
  }
@@ -33,13 +35,39 @@ function parseStreamSnapshot(raw, label) {
33
35
  }
34
36
  const content = asString(raw['content']);
35
37
  const linesScrolledOut = asNumber(raw['linesScrolledOut']);
38
+ const version = asNumber(raw['version']);
36
39
  if (content === null) {
37
40
  throw new Error(`Invalid cmd_runner ${label}.content: expected string`);
38
41
  }
39
42
  if (linesScrolledOut === null) {
40
43
  throw new Error(`Invalid cmd_runner ${label}.linesScrolledOut: expected number`);
41
44
  }
42
- return { content, linesScrolledOut };
45
+ if (version === null) {
46
+ throw new Error(`Invalid cmd_runner ${label}.version: expected number`);
47
+ }
48
+ return { content, linesScrolledOut, version };
49
+ }
50
+ function parseOptionalTimeoutMs(raw, label) {
51
+ if (raw === undefined) {
52
+ return undefined;
53
+ }
54
+ const value = asNumber(raw);
55
+ if (value === null ||
56
+ !Number.isInteger(value) ||
57
+ value < 0 ||
58
+ value > exports.MAX_CMD_RUNNER_OUTPUT_WAIT_TIMEOUT_MS) {
59
+ throw new Error(`Invalid cmd_runner ${label}: expected non-negative integer <= ${String(exports.MAX_CMD_RUNNER_OUTPUT_WAIT_TIMEOUT_MS)}`);
60
+ }
61
+ return value;
62
+ }
63
+ function parseOutputWaitStatus(raw) {
64
+ if (raw === undefined) {
65
+ return undefined;
66
+ }
67
+ if (raw === 'output' || raw === 'timeout' || raw === 'exited') {
68
+ return raw;
69
+ }
70
+ throw new Error(`Invalid cmd_runner output waitStatus: ${String(raw)}`);
43
71
  }
44
72
  function parseStatusPayload(raw) {
45
73
  const daemonPid = asNumber(raw['daemonPid']);
@@ -239,10 +267,28 @@ function parseCmdRunnerRequestLine(line) {
239
267
  if (type === 'get_output') {
240
268
  const stdout = asBoolean(raw['stdout']);
241
269
  const stderr = asBoolean(raw['stderr']);
270
+ const waitForNewOutputRaw = raw['waitForNewOutput'];
271
+ const waitForNewOutput = waitForNewOutputRaw === undefined ? false : asBoolean(waitForNewOutputRaw);
272
+ const timeoutMs = parseOptionalTimeoutMs(raw['timeoutMs'], 'get_output.timeoutMs');
242
273
  if (stdout === null || stderr === null) {
243
274
  throw new Error('Invalid cmd_runner get_output request: stdout/stderr must be boolean');
244
275
  }
245
- return { type, stdout, stderr };
276
+ if (waitForNewOutput === null) {
277
+ throw new Error('Invalid cmd_runner get_output request: waitForNewOutput must be boolean');
278
+ }
279
+ if (!stdout && !stderr) {
280
+ throw new Error('Invalid cmd_runner get_output request: at least one stream is required');
281
+ }
282
+ if (!waitForNewOutput && timeoutMs !== undefined) {
283
+ throw new Error('Invalid cmd_runner get_output request: timeoutMs requires waitForNewOutput=true');
284
+ }
285
+ return {
286
+ type,
287
+ stdout,
288
+ stderr,
289
+ waitForNewOutput,
290
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
291
+ };
246
292
  }
247
293
  throw new Error(`Invalid cmd_runner request type: ${String(type)}`);
248
294
  }
@@ -269,6 +315,15 @@ function parseCmdRunnerResponseLine(line) {
269
315
  if (type !== 'pong' && type !== 'status' && type !== 'output' && type !== 'stop_result') {
270
316
  throw new Error(`Invalid cmd_runner response type: ${String(type)}`);
271
317
  }
318
+ if (type === 'output') {
319
+ const waitStatus = parseOutputWaitStatus(raw['waitStatus']);
320
+ return {
321
+ type,
322
+ ok: true,
323
+ ...(waitStatus === undefined ? {} : { waitStatus }),
324
+ ...parseStatusPayload(raw),
325
+ };
326
+ }
272
327
  return {
273
328
  type,
274
329
  ok: true,
@@ -17,10 +17,15 @@ class ScrollingBuffer {
17
17
  maxLines;
18
18
  lines = [];
19
19
  linesScrolledOut = 0;
20
+ version = 0;
20
21
  constructor(maxLines) {
21
22
  this.maxLines = maxLines;
22
23
  }
23
24
  addText(text) {
25
+ if (text.length === 0) {
26
+ return;
27
+ }
28
+ this.version += 1;
24
29
  const newLines = text.split('\n');
25
30
  if (newLines[newLines.length - 1] === '') {
26
31
  newLines.pop();
@@ -37,8 +42,12 @@ class ScrollingBuffer {
37
42
  return {
38
43
  content: this.lines.join('\n'),
39
44
  linesScrolledOut: this.linesScrolledOut,
45
+ version: this.version,
40
46
  };
41
47
  }
48
+ getVersion() {
49
+ return this.version;
50
+ }
42
51
  }
43
52
  async function flushIpc(msg) {
44
53
  const send = process.send;
@@ -177,6 +186,64 @@ async function main() {
177
186
  let closeRequested = false;
178
187
  let timeoutHandle;
179
188
  let initialResultSent = false;
189
+ const outputWaiters = [];
190
+ const requestedOutputChanged = (waiter) => (waiter.stdout && state.stdout.getVersion() !== waiter.initialStdoutVersion) ||
191
+ (waiter.stderr && state.stderr.getVersion() !== waiter.initialStderrVersion);
192
+ const removeOutputWaiter = (waiter) => {
193
+ const index = outputWaiters.indexOf(waiter);
194
+ if (index !== -1) {
195
+ outputWaiters.splice(index, 1);
196
+ }
197
+ };
198
+ const settleOutputWaiter = (waiter, status) => {
199
+ removeOutputWaiter(waiter);
200
+ if (waiter.timeoutHandle !== undefined) {
201
+ clearTimeout(waiter.timeoutHandle);
202
+ }
203
+ waiter.resolve(status);
204
+ };
205
+ const notifyOutputWaiters = () => {
206
+ for (const waiter of [...outputWaiters]) {
207
+ if (requestedOutputChanged(waiter)) {
208
+ settleOutputWaiter(waiter, 'output');
209
+ continue;
210
+ }
211
+ if (!state.isRunning) {
212
+ settleOutputWaiter(waiter, 'exited');
213
+ }
214
+ }
215
+ };
216
+ const waitForRequestedNewOutput = async (request, socket) => {
217
+ if (!state.isRunning) {
218
+ return 'exited';
219
+ }
220
+ return await new Promise((resolve) => {
221
+ let waiter;
222
+ const onSocketClosed = () => {
223
+ if (waiter !== undefined) {
224
+ settleOutputWaiter(waiter, 'client_closed');
225
+ }
226
+ };
227
+ waiter = {
228
+ stdout: request.stdout,
229
+ stderr: request.stderr,
230
+ initialStdoutVersion: state.stdout.getVersion(),
231
+ initialStderrVersion: state.stderr.getVersion(),
232
+ resolve: (status) => {
233
+ socket.off('close', onSocketClosed);
234
+ resolve(status);
235
+ },
236
+ };
237
+ if (request.timeoutMs !== undefined) {
238
+ waiter.timeoutHandle = setTimeout(() => {
239
+ settleOutputWaiter(waiter, 'timeout');
240
+ }, request.timeoutMs);
241
+ }
242
+ socket.once('close', onSocketClosed);
243
+ outputWaiters.push(waiter);
244
+ notifyOutputWaiters();
245
+ });
246
+ };
180
247
  const tryFlushInitialResult = async (msg) => {
181
248
  if (initialResultSent) {
182
249
  return false;
@@ -262,6 +329,7 @@ async function main() {
262
329
  state.isRunning = false;
263
330
  state.exitCode = code;
264
331
  state.exitSignal = signal;
332
+ notifyOutputWaiters();
265
333
  void (async () => {
266
334
  if (state.daemonCommandLine === null && !initialResultSent) {
267
335
  await tryFlushInitialResult({
@@ -292,9 +360,11 @@ async function main() {
292
360
  });
293
361
  stdout.on('data', (data) => {
294
362
  state.stdout.addText(data.toString());
363
+ notifyOutputWaiters();
295
364
  });
296
365
  stderr.on('data', (data) => {
297
366
  state.stderr.addText(data.toString());
367
+ notifyOutputWaiters();
298
368
  });
299
369
  await ensureSocketParentDir(endpoint);
300
370
  if (closeRequested) {
@@ -331,13 +401,24 @@ async function main() {
331
401
  return;
332
402
  }
333
403
  if (request.type === 'get_output') {
404
+ const waitStatus = request.waitForNewOutput
405
+ ? await waitForRequestedNewOutput(request, socket)
406
+ : undefined;
407
+ if (waitStatus === 'client_closed') {
408
+ return;
409
+ }
334
410
  const payload = buildStatusPayload(state);
335
411
  writeSocketResponse(socket, {
336
412
  type: 'output',
337
413
  ok: true,
414
+ ...(waitStatus === undefined ? {} : { waitStatus }),
338
415
  ...payload,
339
- stdout: request.stdout ? payload.stdout : { content: '', linesScrolledOut: 0 },
340
- stderr: request.stderr ? payload.stderr : { content: '', linesScrolledOut: 0 },
416
+ stdout: request.stdout
417
+ ? payload.stdout
418
+ : { content: '', linesScrolledOut: 0, version: 0 },
419
+ stderr: request.stderr
420
+ ? payload.stderr
421
+ : { content: '', linesScrolledOut: 0, version: 0 },
341
422
  });
342
423
  return;
343
424
  }
@@ -12,6 +12,7 @@
12
12
  * - add_reminder: Add a reminder
13
13
  * - delete_reminder: Delete a reminder by id
14
14
  * - update_reminder: Update reminder content
15
+ * - migrate_reminder: Move a visible shared reminder back into the current dialog
15
16
  * - clear_mind: Start a new course, optionally add a reminder
16
17
  * - do_mind: Main Dialog only; create a new `.tsk/` Taskdoc section without starting a new course
17
18
  * - change_mind: Main Dialog only; update a `.tsk/` Taskdoc section without starting a new course
@@ -32,6 +33,7 @@ import { type FuncTool } from '../tool';
32
33
  export declare const deleteReminderTool: FuncTool;
33
34
  export declare const addReminderTool: FuncTool;
34
35
  export declare const updateReminderTool: FuncTool;
36
+ export declare const migrateReminderTool: FuncTool;
35
37
  export declare const clearMindTool: FuncTool;
36
38
  export declare const changeMindTool: FuncTool;
37
39
  export declare const doMindTool: FuncTool;
@@ -13,6 +13,7 @@
13
13
  * - add_reminder: Add a reminder
14
14
  * - delete_reminder: Delete a reminder by id
15
15
  * - update_reminder: Update reminder content
16
+ * - migrate_reminder: Move a visible shared reminder back into the current dialog
16
17
  * - clear_mind: Start a new course, optionally add a reminder
17
18
  * - do_mind: Main Dialog only; create a new `.tsk/` Taskdoc section without starting a new course
18
19
  * - change_mind: Main Dialog only; update a `.tsk/` Taskdoc section without starting a new course
@@ -63,12 +64,13 @@ var __importStar = (this && this.__importStar) || (function () {
63
64
  };
64
65
  })();
65
66
  Object.defineProperty(exports, "__esModule", { value: true });
66
- exports.recallTaskdocTool = exports.mindMoreTool = exports.neverMindTool = exports.doMindTool = exports.changeMindTool = exports.clearMindTool = exports.updateReminderTool = exports.addReminderTool = exports.deleteReminderTool = void 0;
67
+ exports.recallTaskdocTool = exports.mindMoreTool = exports.neverMindTool = exports.doMindTool = exports.changeMindTool = exports.clearMindTool = exports.migrateReminderTool = exports.updateReminderTool = exports.addReminderTool = exports.deleteReminderTool = void 0;
67
68
  const fs = __importStar(require("fs"));
68
69
  const path = __importStar(require("path"));
69
70
  const dialog_1 = require("../dialog");
70
71
  const rtws_1 = require("../rtws");
71
72
  const driver_messages_1 = require("../runtime/driver-messages");
73
+ const shared_reminder_update_impact_1 = require("../runtime/shared-reminder-update-impact");
72
74
  const tool_result_messages_1 = require("../runtime/tool-result-messages");
73
75
  const work_language_1 = require("../runtime/work-language");
74
76
  const shared_reminders_1 = require("../shared-reminders");
@@ -276,6 +278,87 @@ function replaceReminderContent(reminder, content, meta, renderMode) {
276
278
  renderMode: renderMode ?? reminder.renderMode,
277
279
  });
278
280
  }
281
+ function resolveSharedReminderUpdateImpactScope(target) {
282
+ if (target.source !== 'runtime') {
283
+ return undefined;
284
+ }
285
+ if (target.target.kind === 'task') {
286
+ return 'task';
287
+ }
288
+ return target.reminder.scope === 'runtime' ? 'runtime' : 'agent';
289
+ }
290
+ function appendSharedReminderUpdateImpactToToolResult(output, language, reminderId, dispatch) {
291
+ if (dispatch === undefined) {
292
+ return output;
293
+ }
294
+ const notice = (0, driver_messages_1.formatSharedReminderUpdateImpactNotice)(language, {
295
+ reminderId,
296
+ scope: dispatch.scope,
297
+ audience: 'updater',
298
+ });
299
+ const dispatchLine = language === 'zh'
300
+ ? `已向 ${dispatch.dispatchedDialogCount}/${dispatch.peerDialogCount} 个受影响的并行对话派发提醒。`
301
+ : `Dispatched notices to ${dispatch.dispatchedDialogCount}/${dispatch.peerDialogCount} affected parallel dialog(s).`;
302
+ return {
303
+ ...output,
304
+ content: `${output.content}\n\n${notice}\n${dispatchLine}`,
305
+ };
306
+ }
307
+ function appendSharedReminderMigrationImpactToToolResult(output, language, dispatch) {
308
+ if (dispatch === undefined) {
309
+ return output;
310
+ }
311
+ const dispatchLine = language === 'zh'
312
+ ? `已向 ${dispatch.dispatchedDialogCount}/${dispatch.peerDialogCount} 个受影响的并行对话派发撤下提醒。`
313
+ : `Dispatched withdrawal notices to ${dispatch.dispatchedDialogCount}/${dispatch.peerDialogCount} affected parallel dialog(s).`;
314
+ return {
315
+ ...output,
316
+ content: `${output.content}\n${dispatchLine}`,
317
+ };
318
+ }
319
+ async function formatUpdateReminderSuccessResult(args) {
320
+ const scope = resolveSharedReminderUpdateImpactScope(args.target);
321
+ const dispatch = scope === undefined
322
+ ? undefined
323
+ : await (0, shared_reminder_update_impact_1.dispatchSharedReminderUpdateImpact)({
324
+ updater: args.dlg,
325
+ reminderId: args.target.reminder.id,
326
+ scope,
327
+ language: args.language,
328
+ });
329
+ return appendSharedReminderUpdateImpactToToolResult((0, tool_result_messages_1.formatToolActionResult)(args.language, 'updated'), args.language, args.target.reminder.id, dispatch);
330
+ }
331
+ async function migrateSharedReminderTargetToDialog(args) {
332
+ const reminderId = args.target.reminder.id;
333
+ const existingDialogIndex = findReminderIndexById('dialog', args.dlg.reminders, reminderId);
334
+ if (existingDialogIndex !== null) {
335
+ throw new Error(`Duplicate visible reminder_id before migration: ${reminderId}`);
336
+ }
337
+ let migratedReminder;
338
+ await (0, shared_reminders_1.mutateSharedReminders)(args.target.target, (sharedReminders) => {
339
+ const index = findReminderIndexById('shared', sharedReminders, reminderId);
340
+ if (index === null)
341
+ return;
342
+ migratedReminder = sharedReminders[index];
343
+ sharedReminders.splice(index, 1);
344
+ });
345
+ if (migratedReminder === undefined) {
346
+ return false;
347
+ }
348
+ args.dlg.reminders.push((0, tool_1.materializeReminder)({
349
+ id: migratedReminder.id,
350
+ content: migratedReminder.content,
351
+ owner: migratedReminder.owner,
352
+ meta: migratedReminder.meta,
353
+ echoback: migratedReminder.echoback,
354
+ scope: 'dialog',
355
+ createdAt: migratedReminder.createdAt,
356
+ priority: migratedReminder.priority,
357
+ renderMode: migratedReminder.renderMode,
358
+ }));
359
+ args.dlg.touchReminders();
360
+ return true;
361
+ }
279
362
  async function deleteResolvedReminderTarget(dlg, target) {
280
363
  switch (target.source) {
281
364
  case 'dialog': {
@@ -325,6 +408,9 @@ function getCtrlMessages(language) {
325
408
  invalidFormatAdd: '参数格式不对。用法:add_reminder({ content: string, scope?: "dialog" | "task" | "agent" })(省略 scope 表示 task)',
326
409
  reminderContentEmpty: '提醒内容不能为空',
327
410
  invalidFormatUpdate: '参数格式不对。用法:update_reminder({ reminder_id: string, content: string })',
411
+ invalidFormatMigrate: '参数格式不对。用法:migrate_reminder({ reminder_id: string, scope: "dialog" })',
412
+ reminderAlreadyDialogScope: (reminderId) => `reminder_id=${reminderId} 已经是当前对话范围提醒项,不需要迁移。`,
413
+ reminderMigrateManagedBlocked: (managerTool) => `错误:该提醒项由工具 ${managerTool} 管理,不能用 migrate_reminder 迁移;请使用 ${managerTool} 更新。`,
328
414
  invalidFormatDoMind: '参数格式不对。用法:do_mind({ selector: string, category?: string, content: string })',
329
415
  invalidFormatChangeMind: '参数格式不对。用法:change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
330
416
  tooManyArgsChangeMind: '参数格式不对。用法:change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
@@ -372,6 +458,9 @@ function getCtrlMessages(language) {
372
458
  invalidFormatAdd: 'Error: Invalid args. Use: add_reminder({ content: string, scope?: "dialog" | "task" | "agent" }) (omitting scope means task).',
373
459
  reminderContentEmpty: 'Error: Reminder content cannot be empty',
374
460
  invalidFormatUpdate: 'Error: Invalid args. Use: update_reminder({ reminder_id: string, content: string })',
461
+ invalidFormatMigrate: 'Error: Invalid args. Use: migrate_reminder({ reminder_id: string, scope: "dialog" })',
462
+ reminderAlreadyDialogScope: (reminderId) => `reminder_id=${reminderId} is already dialog-scope in the current dialog; no migration is needed.`,
463
+ reminderMigrateManagedBlocked: (managerTool) => `Error: This reminder is managed by tool ${managerTool}. Do not migrate it via migrate_reminder; use ${managerTool} instead.`,
375
464
  invalidFormatDoMind: 'Error: Invalid args. Use: do_mind({ selector: string, category?: string, content: string })',
376
465
  invalidFormatChangeMind: 'Error: Invalid args. Use: change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
377
466
  tooManyArgsChangeMind: 'Error: Invalid args. Use: change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
@@ -456,7 +545,7 @@ exports.addReminderTool = {
456
545
  description: 'Add a manually maintained reminder for current work. Scope defaults to task so the reminder survives continuing the same Taskdoc in another dialog; dialog is only for truly dialog-local notes; agent is visible to this agent across dialogs and should be reserved for urgent short-lived global cues. Do not manually record runtime-maintained environment state such as background process status or in-flight background asks.',
457
546
  descriptionI18n: {
458
547
  en: 'Add a manually maintained reminder for current work. Scope defaults to task so the reminder survives continuing the same Taskdoc in another dialog; dialog is only for truly dialog-local notes; agent is visible to this agent across dialogs and should be reserved for urgent short-lived global cues. Do not manually record runtime-maintained environment state such as background process status or in-flight background asks.',
459
- zh: '添加手工维护的手头工作提醒。scope 默认 task,以便同一差遣牒任务换新对话继续时仍可见;dialog 只用于真正对话局部的事项;agent 会在本智能体所有对话中可见,仅用于紧急、短期、全局刺眼提醒。不要手工记录后台进程状态、后台进行中诉请等 runtime 会自动维护的环境状态。',
548
+ zh: '添加手工维护的手头工作提醒。scope 默认 task,以便同一差遣牒任务换新对话继续时仍可见;dialog 只用于真正对话局部的事项;agent 会在本智能体后续对话中继续可见,仅用于紧急、短期、全局刺眼提醒。不要手工记录后台进程状态、后台进行中诉请等 runtime 会自动维护的环境状态。',
460
549
  },
461
550
  parameters: {
462
551
  type: 'object',
@@ -592,12 +681,20 @@ exports.updateReminderTool = {
592
681
  const updated = await updateResolvedReminderTarget(dlg, resolved.target, reminderContent, stripResult.nextMeta, reminderRenderMode);
593
682
  if (!updated)
594
683
  return (0, tool_1.toolFailure)(t.reminderTargetChanged);
595
- return (0, tool_result_messages_1.formatToolActionResult)(language, 'updated');
684
+ return await formatUpdateReminderSuccessResult({
685
+ dlg,
686
+ target: resolved.target,
687
+ language,
688
+ });
596
689
  }
597
690
  const updated = await updateResolvedReminderTarget(dlg, resolved.target, reminderContent, undefined, reminderRenderMode);
598
691
  if (!updated)
599
692
  return (0, tool_1.toolFailure)(t.reminderTargetChanged);
600
- return (0, tool_result_messages_1.formatToolActionResult)(language, 'updated');
693
+ return await formatUpdateReminderSuccessResult({
694
+ dlg,
695
+ target: resolved.target,
696
+ language,
697
+ });
601
698
  }
602
699
  const reminderMeta = buildContinuationPackageReminderMeta({
603
700
  existingMeta: reminder?.meta,
@@ -607,7 +704,84 @@ exports.updateReminderTool = {
607
704
  const updated = await updateResolvedReminderTarget(dlg, resolved.target, reminderContent, reminderMeta, reminderRenderMode);
608
705
  if (!updated)
609
706
  return (0, tool_1.toolFailure)(t.reminderTargetChanged);
610
- return (0, tool_result_messages_1.formatToolActionResult)(language, 'updated');
707
+ return await formatUpdateReminderSuccessResult({
708
+ dlg,
709
+ target: resolved.target,
710
+ language,
711
+ });
712
+ },
713
+ };
714
+ exports.migrateReminderTool = {
715
+ type: 'func',
716
+ name: 'migrate_reminder',
717
+ description: 'Move a visible shared reminder back into the current dialog scope. Use this after a task/agent shared reminder update turns out to belong only to the updater dialog, so Dominds withdraws it from affected parallel dialogs.',
718
+ descriptionI18n: {
719
+ en: 'Move a visible shared reminder back into the current dialog scope. Use this after a task/agent shared reminder update turns out to belong only to the updater dialog, so Dominds withdraws it from affected parallel dialogs.',
720
+ zh: '把当前可见的共享提醒项迁回当前对话范围。用于 task/agent 共享提醒更新后发现内容只属于更新者对话时,将它从受影响并行对话中撤下。',
721
+ },
722
+ parameters: {
723
+ type: 'object',
724
+ additionalProperties: false,
725
+ required: ['reminder_id', 'scope'],
726
+ properties: {
727
+ reminder_id: { type: 'string', description: 'Stable reminder id.' },
728
+ scope: {
729
+ type: 'string',
730
+ enum: ['dialog'],
731
+ description: 'Target scope. Currently only dialog is supported.',
732
+ },
733
+ },
734
+ },
735
+ argsValidation: 'dominds',
736
+ async call(dlg, _caller, args) {
737
+ const language = (0, work_language_1.getWorkLanguage)();
738
+ const t = getCtrlMessages(language);
739
+ if (args['scope'] !== 'dialog') {
740
+ return (0, tool_1.toolFailure)(t.invalidFormatMigrate);
741
+ }
742
+ const resolved = await resolveReminderTarget(dlg, args['reminder_id']);
743
+ if (!resolved.ok) {
744
+ const reminderId = resolved.reminderId.trim();
745
+ if (reminderId === '')
746
+ return (0, tool_1.toolFailure)(t.invalidFormatMigrate);
747
+ return (0, tool_1.toolFailure)(t.reminderDoesNotExist(reminderId));
748
+ }
749
+ const targetReminder = resolved.target.reminder;
750
+ if (resolved.target.source === 'dialog') {
751
+ return (0, tool_1.toolSuccess)(t.reminderAlreadyDialogScope(targetReminder.id));
752
+ }
753
+ const deleteAltInstruction = getDeleteAltInstruction(targetReminder.meta);
754
+ if (deleteAltInstruction !== undefined) {
755
+ return (0, tool_1.toolFailure)(formatManualDeleteBlockedError(language, deleteAltInstruction));
756
+ }
757
+ const managerTool = getManagerTool(targetReminder.meta);
758
+ if (managerTool !== undefined) {
759
+ return (0, tool_1.toolFailure)(t.reminderMigrateManagedBlocked(managerTool));
760
+ }
761
+ if (targetReminder.owner?.updateReminder !== undefined) {
762
+ return (0, tool_1.toolFailure)(language === 'zh'
763
+ ? '错误:该提醒项由 reminder owner 自动维护,不能用 migrate_reminder 迁移。'
764
+ : 'Error: This reminder is automatically maintained by a reminder owner and cannot be migrated via migrate_reminder.');
765
+ }
766
+ const scope = resolveSharedReminderUpdateImpactScope(resolved.target);
767
+ const migrated = await migrateSharedReminderTargetToDialog({
768
+ dlg,
769
+ target: resolved.target,
770
+ });
771
+ if (!migrated)
772
+ return (0, tool_1.toolFailure)(t.reminderTargetChanged);
773
+ const baseOutput = (0, tool_1.toolSuccess)(language === 'zh'
774
+ ? `已迁移:reminder_id=${targetReminder.id} 已从共享范围撤下,并保留为当前对话范围提醒项。`
775
+ : `Migrated: reminder_id=${targetReminder.id} has been withdrawn from shared scope and kept as a current-dialog reminder.`);
776
+ const dispatch = scope === undefined
777
+ ? undefined
778
+ : await (0, shared_reminder_update_impact_1.dispatchSharedReminderMigrationImpact)({
779
+ updater: dlg,
780
+ reminderId: targetReminder.id,
781
+ scope,
782
+ language,
783
+ });
784
+ return appendSharedReminderMigrationImpactToToolResult(baseOutput, language, dispatch);
611
785
  },
612
786
  };
613
787
  exports.clearMindTool = {