dominds 1.27.3 → 1.27.5

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 (38) hide show
  1. package/dist/dialog-fork.js +2 -1
  2. package/dist/dialog.d.ts +3 -3
  3. package/dist/dialog.js +7 -4
  4. package/dist/docs/dialog-system.md +4 -4
  5. package/dist/docs/dialog-system.zh.md +4 -4
  6. package/dist/docs/diligence-push.md +6 -3
  7. package/dist/docs/diligence-push.zh.md +1 -1
  8. package/dist/llm/api-quirks.d.ts +1 -0
  9. package/dist/llm/api-quirks.js +3 -1
  10. package/dist/llm/defaults.yaml +8 -4
  11. package/dist/llm/gen/openai-compatible.js +14 -1
  12. package/dist/llm/kernel-driver/drive.js +67 -40
  13. package/dist/llm/kernel-driver/tellask-special.js +2 -2
  14. package/dist/mcp/supervisor.js +4 -1
  15. package/dist/minds/system-prompt-parts.js +30 -30
  16. package/dist/minds/system-prompt.js +6 -4
  17. package/dist/persistence.js +65 -16
  18. package/dist/priming.js +2 -3
  19. package/dist/runtime/driver-messages.js +42 -28
  20. package/dist/runtime/reply-prompt-copy.js +6 -5
  21. package/dist/server/websocket-handler.js +3 -3
  22. package/dist/shared-reminders.js +2 -2
  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/ctrl.js +4 -1
  27. package/dist/tools/pending-tellask-reminder.js +1 -0
  28. package/dist/tools/prompts/control/en/index.md +3 -3
  29. package/dist/tools/prompts/control/en/principles.md +4 -4
  30. package/dist/tools/prompts/control/en/scenarios.md +10 -3
  31. package/dist/tools/prompts/control/en/tools.md +4 -4
  32. package/dist/tools/prompts/control/zh/index.md +3 -3
  33. package/dist/tools/prompts/control/zh/principles.md +4 -4
  34. package/dist/tools/prompts/control/zh/scenarios.md +10 -3
  35. package/dist/tools/prompts/control/zh/tools.md +4 -4
  36. package/dist/tools/team_mgmt-manual.js +2 -2
  37. package/package.json +4 -4
  38. package/webapp/package.json +0 -1
@@ -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 = {
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[]>;
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) {
@@ -651,7 +654,7 @@ class Dialog {
651
654
  renderRevision: (0, tool_1.computeReminderRenderRevision)(r),
652
655
  echoback: (0, tool_1.reminderEchoBackEnabled)(r),
653
656
  scope: r.scope,
654
- renderMode: r.renderMode ?? 'markdown',
657
+ renderMode: r.renderMode,
655
658
  }));
656
659
  }
657
660
  emitFullRemindersUpdate(reminders) {
@@ -159,21 +159,21 @@ This ensures crash recovery and enables the backend to resume from any persisted
159
159
 
160
160
  When a dialog still carries an inter-dialog reply obligation, but the user temporarily interjects and asks it to handle a local question first, the system must distinguish between the **UI projection** and the **true driving source state**.
161
161
 
162
- Plainly: the system should answer the user's interjection first. Once the user receives a visible answer, the backend records that answer as A2H (Answer to Human) in Human Attention so the user can find and acknowledge it even if the dialog immediately continues automatically. In addition to recovering A2H from visible `saying`, the LLM may also produce structured `answering` output (or call the equivalent `answerHuman` tool entry) to create A2H directly.
162
+ Plainly: the system should answer the user's interjection first. Once the user receives a visible answer, the backend records that answer as A2H (Answer to Human) in Human Attention so the user can find and acknowledge it even if the dialog immediately continues automatically. In addition to recovering A2H from visible `saying`, the LLM may also produce structured `answering` output (or call the equivalent `answerHuman` tool entry) to create A2H directly. A2H may also carry a human-facing status explanation when the expected action is to stop and wait, such as while pending active callees are still running.
163
163
 
164
164
  **Normative semantics**:
165
165
 
166
166
  1. Every user interjection message is driven as a complete normal round.
167
167
  2. If that round needs tools, the system MUST finish the full tool round and any post-tool follow-up before treating the interjection as answered.
168
168
  3. A visible assistant `saying` settles the pending user-interjection reply only when no same-round function/tellask call remains after that `saying`.
169
- 4. The model may also produce structured `answering` output (or call `answerHuman({ answerContent })`) to express "this is an answer for the human." That output is always appended to the dialog's `a2h.yaml`, but it is not the same thing as a Side Dialog's formal reply to its requester.
169
+ 4. The model may also produce structured `answering` output (or call `answerHuman({ answerContent })`) to express "this is an answer or status for the human." That output is always appended to the dialog's `a2h.yaml`, but it is not the same thing as a Side Dialog's formal reply to its requester.
170
170
  5. If an inter-dialog reply obligation still exists after the interjection is answered, it remains ordinary durable reply-obligation state. Subsequent continuation is driven by the normal business paths: queued prompts, reply reminders, diligence push, or explicit resume when the dialog is genuinely blocked.
171
- 6. A2H disappears when the user acknowledges it. This is intentionally "read then burn"; `answerRef` only links back to the course/genseq that produced the answer. When A2H comes from visible `saying`, the canonical text remains in the transcript; when it comes from structured `answering`, the A2H item itself carries that one-way output text.
171
+ 6. A2H disappears when the user acknowledges it. This is intentionally "read then burn"; `answerRef` only links back to the course/genseq that produced the A2H item. When A2H comes from visible `saying`, the canonical text remains in the transcript; when it comes from structured `answering`, the A2H item itself carries that one-way output text.
172
172
  7. The Human Attention panel shows Q4H and A2H together. Q4H waits for a human answer; A2H waits only for human acknowledgement.
173
173
 
174
174
  **Strict boundary**: a formal `askHuman` answer is not part of this "user interjection" category. As soon as a prompt carries a real `q4hAnswerCallId`, it belongs to the askHuman reply channel and semantically continues an already-materialized question/answer chain; it must never be downgraded into temporary local side-chat.
175
175
 
176
- **Modeling boundary**: Dominds does not structurally model "current human question context", does not maintain coordinates for "which human question this A2H answers", and does not store `userInterjection` coordinates in A2H. `a2h` / `answering` is only one-way structured modeling at the LLM output layer: the model produced text meant for the human, and the runtime put it into the human-acknowledgement queue. Questions, interjections, task obligations, and continuation duties remain represented by existing business facts such as prompts, Q4H, reply obligations, and queued prompts.
176
+ **Modeling boundary**: Dominds does not structurally model "current human question context", does not maintain coordinates for "which human question or status boundary this A2H addresses", and does not store `userInterjection` coordinates in A2H. `a2h` / `answering` is only one-way structured modeling at the LLM output layer: the model produced text meant for the human, and the runtime put it into the human-acknowledgement queue. Questions, interjections, wait boundaries, task obligations, and continuation duties remain represented by existing business facts such as prompts, Q4H, reply obligations, active callees, and queued prompts.
177
177
 
178
178
  **Key point**: pending user-interjection reply and inter-dialog reply obligation are independent business facts. Reminder/footer copy can use those two facts directly: if the interjection is still pending, prioritize answering the user; if it is settled and the reply obligation remains active, continue toward the required inter-dialog closure.
179
179
 
@@ -158,21 +158,21 @@ askerDialog 可以在执行期间接收来自当前需向它回复的支线对
158
158
 
159
159
  当某个对话仍带有跨对话回复义务,但用户临时插话要求它先处理本地问题时,系统必须区分**UI 投影**与**真实驱动源状态**。
160
160
 
161
- 直白地说:先把用户这次插话接住并答完。用户看到可见答复后,后端把这条答复记录成 A2H(Answer to Human)放进“待人处理”,这样即使对话马上自动续推,用户也能找到并确认已阅。除了从可见 `saying` 恢复 A2H 之外,LLM 还可以产生结构化 `answering` 输出(或调用等价的 `answerHuman` 工具入口)直接形成 A2H
161
+ 直白地说:先把用户这次插话接住并答完。用户看到可见答复后,后端把这条答复记录成 A2H(Answer to Human)放进“待人处理”,这样即使对话马上自动续推,用户也能找到并确认已阅。除了从可见 `saying` 恢复 A2H 之外,LLM 还可以产生结构化 `answering` 输出(或调用等价的 `answerHuman` 工具入口)直接形成 A2H。当预期动作是停下来等待时,A2H 也可以承载给人类看的状态说明,例如仍有 pending active callees 在运行。
162
162
 
163
163
  **规范语义**:
164
164
 
165
165
  1. 每条用户插话消息都按正常驱动轮完整执行。
166
166
  2. 若该轮需要工具,则必须先完整跑完该工具轮及其 post-tool follow-up,之后才可认为插话已答完。
167
167
  3. 只有当模型产生可见 `saying`,且该 `saying` 后同轮没有普通 function/tellask call 继续挂起时,才用这条 `saying` 结算“待回复用户插话”。
168
- 4. 模型也可以产生结构化 `answering` 输出(或调用 `answerHuman({ answerContent })`)来表达“这是给人类看的答复”。该输出无条件追加到该对话的 `a2h.yaml`,但它不等价于支线对话对诉请者的正式回贴。
168
+ 4. 模型也可以产生结构化 `answering` 输出(或调用 `answerHuman({ answerContent })`)来表达“这是给人类看的答复或状态说明”。该输出无条件追加到该对话的 `a2h.yaml`,但它不等价于支线对话对诉请者的正式回贴。
169
169
  5. 如果插话答完后仍有跨对话回复义务,它保持为普通的 durable reply-obligation 状态;后续由正常业务路径推进:queued prompt、回贴提醒、鞭策续推,或在对话确实阻塞时由显式 resume 触发。
170
- 6. 用户 Ack 以后 A2H 立即消失,语义是“阅后即焚”;`answerRef` 只回链到产生答复的 course/genseq,用于定位来源生成轮。若 A2H 来自可见 `saying`,正文真源仍在 transcript 中;若来自结构化 `answering`,A2H 条目本身承载该单向输出正文。
170
+ 6. 用户 Ack 以后 A2H 立即消失,语义是“阅后即焚”;`answerRef` 只回链到产生该 A2H 条目的 course/genseq,用于定位来源生成轮。若 A2H 来自可见 `saying`,正文真源仍在 transcript 中;若来自结构化 `answering`,A2H 条目本身承载该单向输出正文。
171
171
  7. “待人处理”面板同时显示 Q4H 与 A2H:Q4H 等人回答,A2H 只等人确认已阅。
172
172
 
173
173
  **严格边界**:`askHuman` 的正式回答不属于这里的“用户插话”。只要一条 prompt 带着真实的 `q4hAnswerCallId`,它就属于 askHuman 回复通道,语义上是在继续已 materialize 的提问/应答链路,绝不能被压入“本地临时插话聊天”。
174
174
 
175
- **建模边界**:Dominds 不对“当前人类问题上下文”做结构化业务建模,不维护“这个 A2H 回答的是哪一个人类问题”的坐标,也不把 `userInterjection` 坐标写进 A2H。`a2h` / `answering` 只是 LLM 输出层面的单向结构化建模:模型产生一段给人类看的答复,运行时把它放入待人确认队列。问题/插话/任务义务本身仍由既有 prompt、Q4H、reply obligation、queued prompt 等业务事实表达。
175
+ **建模边界**:Dominds 不对“当前人类问题上下文”做结构化业务建模,不维护“这个 A2H 对应哪一个人类问题或等待边界”的坐标,也不把 `userInterjection` 坐标写进 A2H。`a2h` / `answering` 只是 LLM 输出层面的单向结构化建模:模型产生一段给人类看的文本,运行时把它放入待人确认队列。问题/插话/等待边界/任务义务本身仍由既有 prompt、Q4H、reply obligation、active callees、queued prompt 等业务事实表达。
176
176
 
177
177
  **关键点**:“是否还有用户插话待可见回复”和“是否还有跨对话回复义务”是两个独立业务事实。提醒项 footer 可以直接用这两个事实定制:插话尚未答复时优先答人;插话已答复且回复义务仍 active 时,继续按跨对话回贴要求收口。
178
178
 
@@ -21,9 +21,12 @@ This document specifies two related runtime controls:
21
21
  - **Required tool-use control**: for ordinary main and side dialog rounds, the Diligence Push
22
22
  checkbox controls whether the provider request must end through a Dominds tool call. When checked,
23
23
  the model is expected to call a tool such as `askHuman`, `tellask*`, `replyTellask*`, or another
24
- runtime-provided function instead of stopping with a plain-text question/final answer. FBR middle
25
- rounds are the intentional exception: they may run with no callable tools; FBR closure requires one
26
- of the conclusion tools.
24
+ runtime-provided function instead of stopping with a plain-text question/final answer. If no
25
+ substantive tool should be called, `answerHuman` is the expected completion path for that required
26
+ tool round. This is intentional for wait boundaries such as pending active callees: the model
27
+ should explain the wait state through `answerHuman` and then stop for the reply to arrive, rather
28
+ than continue spinning through ordinary tool calls. FBR middle rounds are the intentional
29
+ exception: they may run with no callable tools; FBR closure requires one of the conclusion tools.
27
30
 
28
31
  ## Goals
29
32
 
@@ -12,7 +12,7 @@ Dominds 主线对话旨在长期运行。主线对话"停止"(变为空闲)
12
12
  本文档指定两个相关但不同的运行时控制:
13
13
 
14
14
  - **自动续推注入**:仅针对**主线对话**,当驱动程序即将停止、且没有 Q4H 或 pending active callee dispatch 时,运行时会自动发送一个简短的鞭策语(渲染为正常的用户气泡)并继续生成。pending tellask 是后台被诉请者事实,不是阻塞态;但在没有其它具体驱动来源时,它表示主线已经到达可 idle 的后台等待边界,不应靠鞭策语保持主线空转。
15
- - **强制工具调用控制**:对于普通的主线/支线对话轮次,`鞭策` 勾选项控制本轮 provider 请求是否必须通过 Dominds 工具结束。勾选时,模型应通过 `askHuman`、`tellask*`、`replyTellask*` 或其他运行时函数完成这一轮,而不是用普通文本直接收尾。FBR 中间轮是刻意例外:它们可以处于无可调用工具状态;FBR 收口阶段则必须调用两个结论工具之一。
15
+ - **强制工具调用控制**:对于普通的主线/支线对话轮次,`鞭策` 勾选项控制本轮 provider 请求是否必须通过 Dominds 工具结束。勾选时,模型应通过 `askHuman`、`tellask*`、`replyTellask*` 或其他运行时函数完成这一轮,而不是用普通文本直接收尾。若确实没有其它实质工具应调用,`answerHuman` 就是该强制工具轮次的预期收口路径。等待 pending active callees 这类边界属于预期场景:模型应通过 `answerHuman` 说明当前等待状态,然后停止等待回贴到达,而不是继续调用普通工具空转。FBR 中间轮是刻意例外:它们可以处于无可调用工具状态;FBR 收口阶段则必须调用两个结论工具之一。
16
16
 
17
17
  ## 目标
18
18
 
@@ -5,6 +5,7 @@ import type { LlmRetryStrategy } from './gen';
5
5
  export type LlmFailureKind = 'retriable' | 'rejected' | 'fatal';
6
6
  export declare const KIMI_CODE_API_QUIRK = "kimi-code";
7
7
  export declare const MINIMAX_REASONING_DETAILS_API_QUIRK = "minimax-reasoning-details";
8
+ export declare const MINIMAX_THINKING_TYPE_API_QUIRK = "minimax-thinking-type";
8
9
  export declare const SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = "same-context-empty-response";
9
10
  export declare const VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK = "volcengine-invalid-parameter-aggressive-retry";
10
11
  export type LlmFailureSummary = {
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.XCODE_BEST_STREAM_INTERNAL_ERROR_CODE = exports.VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK = exports.SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = exports.MINIMAX_REASONING_DETAILS_API_QUIRK = exports.KIMI_CODE_API_QUIRK = void 0;
3
+ exports.XCODE_BEST_STREAM_INTERNAL_ERROR_CODE = exports.VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK = exports.SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = exports.MINIMAX_THINKING_TYPE_API_QUIRK = exports.MINIMAX_REASONING_DETAILS_API_QUIRK = exports.KIMI_CODE_API_QUIRK = void 0;
4
4
  exports.normalizeProviderApiQuirks = normalizeProviderApiQuirks;
5
5
  exports.createLlmFailureQuirkHandlerSession = createLlmFailureQuirkHandlerSession;
6
6
  const persistence_errors_1 = require("../persistence-errors");
7
7
  exports.KIMI_CODE_API_QUIRK = 'kimi-code';
8
8
  exports.MINIMAX_REASONING_DETAILS_API_QUIRK = 'minimax-reasoning-details';
9
+ // MiniMax's `/v1` API rejects `thinking.type: 'enabled'`; rewrites the request `thinking` form to use `adaptive` instead.
10
+ exports.MINIMAX_THINKING_TYPE_API_QUIRK = 'minimax-thinking-type';
9
11
  exports.SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = 'same-context-empty-response';
10
12
  exports.VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK = 'volcengine-invalid-parameter-aggressive-retry';
11
13
  const DOMINDS_LLM_EMPTY_RESPONSE_ERROR_CODE = 'DOMINDS_LLM_EMPTY_RESPONSE';
@@ -177,6 +177,7 @@ providers:
177
177
  apiType: openai-compatible
178
178
  apiQuirks:
179
179
  - minimax-reasoning-details
180
+ - minimax-thinking-type
180
181
  baseUrl: https://api.minimaxi.com/v1
181
182
  apiKeyEnvVar: MINIMAX_CN_TP_API_KEY
182
183
  tech_spec_url: https://platform.minimaxi.com/docs/api-reference/text-openai-api
@@ -186,7 +187,7 @@ providers:
186
187
  thinking:
187
188
  prominent: true
188
189
  type: boolean|object
189
- description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=enabled, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
190
+ description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=adaptive, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
190
191
  reasoning_split:
191
192
  prominent: true
192
193
  type: boolean
@@ -245,6 +246,7 @@ providers:
245
246
  apiType: openai-compatible
246
247
  apiQuirks:
247
248
  - minimax-reasoning-details
249
+ - minimax-thinking-type
248
250
  baseUrl: https://api.minimaxi.com/v1
249
251
  apiKeyEnvVar: MINIMAX_CN_API_KEY
250
252
  tech_spec_url: https://platform.minimaxi.com/docs/api-reference/text-openai-api
@@ -254,7 +256,7 @@ providers:
254
256
  thinking:
255
257
  prominent: true
256
258
  type: boolean|object
257
- description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=enabled, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
259
+ description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=adaptive, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
258
260
  reasoning_split:
259
261
  prominent: true
260
262
  type: boolean
@@ -313,6 +315,7 @@ providers:
313
315
  apiType: openai-compatible
314
316
  apiQuirks:
315
317
  - minimax-reasoning-details
318
+ - minimax-thinking-type
316
319
  baseUrl: https://api.minimax.io/v1
317
320
  apiKeyEnvVar: MINIMAX_TP_API_KEY
318
321
  tech_spec_url: https://platform.minimax.io/docs/api-reference/text-openai-api
@@ -322,7 +325,7 @@ providers:
322
325
  thinking:
323
326
  prominent: true
324
327
  type: boolean|object
325
- description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=enabled, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
328
+ description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=adaptive, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
326
329
  reasoning_split:
327
330
  prominent: true
328
331
  type: boolean
@@ -381,6 +384,7 @@ providers:
381
384
  apiType: openai-compatible
382
385
  apiQuirks:
383
386
  - minimax-reasoning-details
387
+ - minimax-thinking-type
384
388
  baseUrl: https://api.minimax.io/v1
385
389
  apiKeyEnvVar: MINIMAX_API_KEY
386
390
  tech_spec_url: https://platform.minimax.io/docs/api-reference/text-openai-api
@@ -390,7 +394,7 @@ providers:
390
394
  thinking:
391
395
  prominent: true
392
396
  type: boolean|object
393
- description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=enabled, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
397
+ description: OpenAI-compatible MiniMax thinking control. Set true to send thinking.type=adaptive, false to send thinking.type=disabled, or provide the provider-specific thinking object documented by MiniMax. Leave unset to use the provider/model default.
394
398
  reasoning_split:
395
399
  prominent: true
396
400
  type: boolean
@@ -641,6 +641,11 @@ function isMiniMaxReasoningDetailsProvider(providerConfig) {
641
641
  return false;
642
642
  return (0, api_quirks_1.normalizeProviderApiQuirks)(providerConfig).has(api_quirks_1.MINIMAX_REASONING_DETAILS_API_QUIRK);
643
643
  }
644
+ function isMiniMaxThinkingTypeProvider(providerConfig) {
645
+ if (providerConfig === undefined)
646
+ return false;
647
+ return (0, api_quirks_1.normalizeProviderApiQuirks)(providerConfig).has(api_quirks_1.MINIMAX_THINKING_TYPE_API_QUIRK);
648
+ }
644
649
  function isKimiCodeReasoningEffort(value) {
645
650
  return typeof value === 'string' && KIMI_CODE_REASONING_EFFORTS.has(value);
646
651
  }
@@ -841,7 +846,15 @@ function buildOpenAiCompatibleExtraParams(args) {
841
846
  if (thinking === undefined && reasoningEffort === undefined && reasoningSplit === undefined) {
842
847
  return {};
843
848
  }
844
- const thinkingPayload = typeof thinking === 'boolean' ? { type: thinking ? 'enabled' : 'disabled' } : thinking;
849
+ // `thinking` is narrowed to `boolean | Record<string, unknown> | undefined` because the
850
+ // `string` branch threw above. MiniMax rejects `type: 'enabled'`; rewrite both the
851
+ // boolean true form and the explicit object form to `adaptive`.
852
+ const isMiniMaxThinkingType = isMiniMaxThinkingTypeProvider(args.providerConfig);
853
+ const thinkingPayload = typeof thinking === 'boolean'
854
+ ? { type: thinking ? (isMiniMaxThinkingType ? 'adaptive' : 'enabled') : 'disabled' }
855
+ : thinking !== undefined && isMiniMaxThinkingType && thinking.type === 'enabled'
856
+ ? { ...thinking, type: 'adaptive' }
857
+ : thinking;
845
858
  return {
846
859
  ...(thinkingPayload !== undefined ? { thinking: thinkingPayload } : {}),
847
860
  ...(reasoningEffort !== undefined ? { reasoning_effort: reasoningEffort } : {}),
@@ -359,38 +359,41 @@ async function maybeResolveAnsweredUserInterjection(args) {
359
359
  return undefined;
360
360
  }
361
361
  const course = args.dlg.activeGenCourseOrUndefined ?? args.dlg.currentCourse;
362
- const answerIdSource = [
363
- args.dlg.id.rootId,
364
- args.dlg.id.selfId,
365
- `c${String(course)}`,
366
- `g${String(args.assistantSayingGenseq)}`,
367
- pending.msgId,
368
- ].join('|');
369
- const answer = {
370
- id: `a2h-${Buffer.from(answerIdSource).toString('base64url')}`,
371
- content: args.assistantSayingContent,
372
- answeredAt: (0, time_1.formatUnifiedTimestamp)(new Date()),
373
- answerRef: {
374
- course,
375
- genseq: args.assistantSayingGenseq,
376
- },
377
- };
378
- const existingAnswers = await persistence_1.DialogPersistence.loadAnswersToHumanState(args.dlg.id, args.dlg.status);
379
- if (!existingAnswers.some((item) => item.id === answer.id)) {
380
- await persistence_1.DialogPersistence.appendAnswerToHumanState(args.dlg.id, answer, args.dlg.status);
381
- const metadata = await persistence_1.DialogPersistence.loadDialogMetadata(args.dlg.id, args.dlg.status);
382
- const taskDocPath = metadata?.taskDocPath ?? args.dlg.taskDocPath ?? '';
383
- const event = {
384
- type: 'new_a2h_answered',
385
- answer: {
386
- ...answer,
387
- selfId: args.dlg.id.selfId,
388
- rootId: args.dlg.id.rootId,
389
- agentId: metadata?.agentId ?? args.dlg.agentId,
390
- taskDocPath,
362
+ const answer = args.recordAnswerToHuman
363
+ ? {
364
+ id: `a2h-${Buffer.from([
365
+ args.dlg.id.rootId,
366
+ args.dlg.id.selfId,
367
+ `c${String(course)}`,
368
+ `g${String(args.assistantSayingGenseq)}`,
369
+ pending.msgId,
370
+ ].join('|')).toString('base64url')}`,
371
+ content: args.assistantSayingContent,
372
+ answeredAt: (0, time_1.formatUnifiedTimestamp)(new Date()),
373
+ answerRef: {
374
+ course,
375
+ genseq: args.assistantSayingGenseq,
391
376
  },
392
- };
393
- (0, evt_registry_1.postDialogEvent)(args.dlg, event);
377
+ }
378
+ : undefined;
379
+ if (answer !== undefined) {
380
+ const existingAnswers = await persistence_1.DialogPersistence.loadAnswersToHumanState(args.dlg.id, args.dlg.status);
381
+ if (!existingAnswers.some((item) => item.id === answer.id)) {
382
+ await persistence_1.DialogPersistence.appendAnswerToHumanState(args.dlg.id, answer, args.dlg.status);
383
+ const metadata = await persistence_1.DialogPersistence.loadDialogMetadata(args.dlg.id, args.dlg.status);
384
+ const taskDocPath = metadata?.taskDocPath ?? args.dlg.taskDocPath ?? '';
385
+ const event = {
386
+ type: 'new_a2h_answered',
387
+ answer: {
388
+ ...answer,
389
+ selfId: args.dlg.id.selfId,
390
+ rootId: args.dlg.id.rootId,
391
+ agentId: metadata?.agentId ?? args.dlg.agentId,
392
+ taskDocPath,
393
+ },
394
+ };
395
+ (0, evt_registry_1.postDialogEvent)(args.dlg, event);
396
+ }
394
397
  }
395
398
  await persistence_1.DialogPersistence.mutateDialogLatest(args.dlg.id, (previous) => {
396
399
  const previousPending = previous.pendingUserInterjectionReply;
@@ -437,7 +440,7 @@ function resolveToolUseRequirement(dlg, policy) {
437
440
  // For ordinary Dominds dialog rounds, the Diligence Push checkbox controls the provider-level
438
441
  // obligation directly. The numeric Diligence Push budget only limits automatic runtime prompts;
439
442
  // it must not downgrade the round into ordinary chat where the model can stop by asking/answering
440
- // in plain text instead of calling askHuman/tellask/reply tools.
443
+ // in plain text instead of calling askHuman/answerHuman/tellask/reply tools.
441
444
  return dlg.disableDiligencePush ? 'auto' : 'required';
442
445
  }
443
446
  function resolveModelInfo(providerCfg, model) {
@@ -746,7 +749,7 @@ const TELLASK_SPECIAL_VIRTUAL_TOOLS = [
746
749
  type: 'func',
747
750
  name: 'answerHuman',
748
751
  followupMode: 'deferred',
749
- description: 'Record the current human-facing answer for human attention.',
752
+ description: 'Record the current human-facing answer or status for human attention. Use this to finish the current required-tool round when no other substantive tool should be called, especially to explain that this dialog is waiting for pending active callees or tellask replies.',
750
753
  parameters: {
751
754
  type: 'object',
752
755
  properties: {
@@ -778,7 +781,7 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
778
781
  '',
779
782
  '不要再尝试获取各种大段的输出,都不会显示给你。现在先做两件事:',
780
783
  '1. 把需要回传给主线对话的结论、证据定位和风险整理清楚。',
781
- '2. 对于下一程恢复工作需要的信息,写入提醒项。',
784
+ '2. 用当前对话范围(scope=dialog)提醒项写明本路对话任务目标,并把下一程恢复当前支线工作需要的信息带过桥。',
782
785
  '',
783
786
  '然后调用 clear_mind({}) 开启新一程,并尽快完成当前支线回复。',
784
787
  '',
@@ -790,7 +793,7 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
790
793
  '',
791
794
  '不要再尝试获取各种大段的输出,都不会显示给你。现在先做两件事:',
792
795
  '1. 把下一程对话需要知道的此程细节信息写入差遣牒合适章节。',
793
- '2. 对于不适合差遣牒章节覆盖、但下一程恢复工作需要的信息写入提醒项。',
796
+ '2. 对于不适合差遣牒章节覆盖、但下一程恢复当前对话需要的信息,用当前对话范围(scope=dialog)提醒项写明本路对话任务目标并带过桥。',
794
797
  '',
795
798
  '然后调用 clear_mind({}) 开启新一程。',
796
799
  '',
@@ -803,7 +806,7 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
803
806
  '',
804
807
  'Do not try again to fetch any kind of large output; it still will not be shown. Do two things now:',
805
808
  '1. Organize the conclusions, evidence pointers, and risks that need to go back to the Mainline dialog.',
806
- '2. Write any details needed to resume the next course into reminders.',
809
+ '2. Use current-dialog scoped (scope=dialog) reminders to state this dialog task goal and carry over the details needed to resume this Sideline dialog in the next course.',
807
810
  '',
808
811
  'Then call clear_mind({}) to start a new course, and finish the current Sideline dialog reply as soon as possible.',
809
812
  '',
@@ -815,7 +818,7 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
815
818
  '',
816
819
  'Do not try again to fetch any kind of large output; it still will not be shown. Do two things now:',
817
820
  '1. Write the details from this course that the next course needs into the appropriate Taskdoc sections.',
818
- '2. Write information that does not fit a Taskdoc section, but is needed to resume the next course, into reminders.',
821
+ '2. For information that does not fit a Taskdoc section but is needed to resume this dialog in the next course, use current-dialog scoped (scope=dialog) reminders to state this dialog task goal and carry it over.',
819
822
  '',
820
823
  'Then call clear_mind({}) to start a new course.',
821
824
  '',
@@ -3825,6 +3828,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
3825
3828
  const currentRoundAnsweringGenseq = dlg.activeGenSeqOrUndefined;
3826
3829
  const hasCurrentRoundAnsweringOutput = currentRoundAnsweringGenseq !== undefined &&
3827
3830
  lastAssistantAnsweringGenseq === currentRoundAnsweringGenseq;
3831
+ let pendingVisibleUserInterjectionAnswer;
3828
3832
  if (userInterjectionMsgIdForVisibleAnswer !== undefined &&
3829
3833
  !hasCurrentRoundAnsweringOutput) {
3830
3834
  const streamedCurrentRoundSayingContent = batchOutputs.length === 0 &&
@@ -3835,14 +3839,25 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
3835
3839
  lastAssistantSayingGenseq !== previousAssistantSayingGenseq
3836
3840
  ? lastAssistantSayingGenseq
3837
3841
  : null;
3838
- await maybeResolveAnsweredUserInterjection({
3839
- dlg,
3842
+ pendingVisibleUserInterjectionAnswer = {
3840
3843
  userPromptMsgId: userInterjectionMsgIdForVisibleAnswer,
3841
3844
  assistantSayingContent: currentRoundAssistantSayingContent ?? streamedCurrentRoundSayingContent,
3842
3845
  assistantSayingGenseq: currentRoundAssistantSayingGenseq ?? streamedCurrentRoundSayingGenseq,
3843
3846
  functionCallGenseqs: currentRoundFunctionCallGenseqs,
3844
- });
3847
+ };
3845
3848
  }
3849
+ const settleVisibleUserInterjectionAnswer = async (recordAnswerToHuman) => {
3850
+ const pendingAnswer = pendingVisibleUserInterjectionAnswer;
3851
+ if (pendingAnswer === undefined) {
3852
+ return;
3853
+ }
3854
+ pendingVisibleUserInterjectionAnswer = undefined;
3855
+ await maybeResolveAnsweredUserInterjection({
3856
+ dlg,
3857
+ ...pendingAnswer,
3858
+ recordAnswerToHuman,
3859
+ });
3860
+ };
3846
3861
  if (routed.tellaskToolOutputs.length > 0) {
3847
3862
  newMsgs.push(...routed.tellaskToolOutputs);
3848
3863
  }
@@ -3905,6 +3920,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
3905
3920
  }
3906
3921
  await persistDialogFbrState(dlg, undefined);
3907
3922
  dlg.setFbrConclusionToolsEnabled(false);
3923
+ await settleVisibleUserInterjectionAnswer(false);
3908
3924
  break;
3909
3925
  }
3910
3926
  if (inspection.kind === 'rejected') {
@@ -3924,6 +3940,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
3924
3940
  await persistDialogFbrState(dlg, nextFbrState);
3925
3941
  dlg.setFbrConclusionToolsEnabled((0, fbr_1.isFbrFinalizationState)(nextFbrState));
3926
3942
  pendingPrompt = buildKernelDriverFbrPrompt(dlg, nextFbrState);
3943
+ await settleVisibleUserInterjectionAnswer(true);
3927
3944
  continue;
3928
3945
  }
3929
3946
  fbrConclusion = {
@@ -3943,6 +3960,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
3943
3960
  }
3944
3961
  await persistDialogFbrState(dlg, undefined);
3945
3962
  dlg.setFbrConclusionToolsEnabled(false);
3963
+ await settleVisibleUserInterjectionAnswer(false);
3946
3964
  break;
3947
3965
  }
3948
3966
  if (routed.shouldStopAfterReplyTool) {
@@ -3962,12 +3980,14 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
3962
3980
  call.name === 'replyTellaskBack')
3963
3981
  .map((call) => call.name),
3964
3982
  });
3983
+ await settleVisibleUserInterjectionAnswer(false);
3965
3984
  break;
3966
3985
  }
3967
3986
  const queuedNewCoursePrompt = await consumeQueuedNewCourseRuntimePromptForSameDrive(dlg);
3968
3987
  if (queuedNewCoursePrompt !== undefined) {
3969
3988
  pendingPrompt = queuedNewCoursePrompt;
3970
3989
  skipTaskdocForThisDrive = false;
3990
+ await settleVisibleUserInterjectionAnswer(true);
3971
3991
  continue;
3972
3992
  }
3973
3993
  // Start an immediate post-tool generation only when this round produced tool outputs that
@@ -4009,6 +4029,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
4009
4029
  remindersVer: dlg.remindersVer,
4010
4030
  pubRemindersVer,
4011
4031
  });
4032
+ await settleVisibleUserInterjectionAnswer(true);
4012
4033
  break;
4013
4034
  }
4014
4035
  if (dlg.remindersVer > pubRemindersVer) {
@@ -4032,6 +4053,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
4032
4053
  pubRemindersVer,
4033
4054
  });
4034
4055
  await preserveDiligenceBudgetAcrossQ4H(dlg);
4056
+ await settleVisibleUserInterjectionAnswer(false);
4035
4057
  break;
4036
4058
  }
4037
4059
  if (!shouldStartImmediatePostToolGeneration) {
@@ -4053,6 +4075,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
4053
4075
  rootId: dlg.id.rootId,
4054
4076
  selfId: dlg.id.selfId,
4055
4077
  });
4078
+ await settleVisibleUserInterjectionAnswer(false);
4056
4079
  break;
4057
4080
  }
4058
4081
  const healthFirst = await maybeContinueWithHealthPromptBeforeDiligence({
@@ -4065,6 +4088,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
4065
4088
  if (healthFirst.resetTaskdoc) {
4066
4089
  skipTaskdocForThisDrive = false;
4067
4090
  }
4091
+ await settleVisibleUserInterjectionAnswer(true);
4068
4092
  continue;
4069
4093
  }
4070
4094
  const next = await maybeContinueWithDiligencePrompt({
@@ -4074,6 +4098,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
4074
4098
  });
4075
4099
  if (next.kind === 'continue') {
4076
4100
  pendingPrompt = next.prompt;
4101
+ await settleVisibleUserInterjectionAnswer(true);
4077
4102
  continue;
4078
4103
  }
4079
4104
  lastToolRoundStopDiagnostics = buildToolRoundStopDiagnostics({
@@ -4088,6 +4113,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
4088
4113
  remindersVer: dlg.remindersVer,
4089
4114
  pubRemindersVer,
4090
4115
  });
4116
+ await settleVisibleUserInterjectionAnswer(false);
4091
4117
  break;
4092
4118
  }
4093
4119
  await repairMissingImmediateFollowupTrigger({
@@ -4102,6 +4128,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
4102
4128
  resolvingImmediateToolResultUserPromptMsgId = resolvingImmediateToolResultForUserPrompt
4103
4129
  ? currentUserPromptMsgId
4104
4130
  : undefined;
4131
+ await settleVisibleUserInterjectionAnswer(true);
4105
4132
  continue;
4106
4133
  }
4107
4134
  catch (err) {
@@ -2101,8 +2101,8 @@ async function executeReplyTellaskCall(args) {
2101
2101
  function formatAnswerHumanResultContent(args) {
2102
2102
  const language = (0, work_language_1.getWorkLanguage)();
2103
2103
  return language === 'zh'
2104
- ? `已记录给人类的答复。\n\n${args.answerContent}`
2105
- : `Recorded the answer for the human.\n\n${args.answerContent}`;
2104
+ ? `已记录给人类的答复或状态说明。\n\n${args.answerContent}`
2105
+ : `Recorded the answer or status for the human.\n\n${args.answerContent}`;
2106
2106
  }
2107
2107
  async function recordAnswerToHuman(args) {
2108
2108
  const answer = {
@@ -109,7 +109,10 @@ function ensureLeaseReminder(dlg, serverId) {
109
109
  '',
110
110
  `This MCP server is treated as non-stateless; the current dialog holds an underlying process/connection with explicit lifecycle management.`,
111
111
  ].join('\n');
112
- dlg.addReminder(content, owner, makeLeaseReminderMeta(serverId));
112
+ dlg.addReminder(content, owner, makeLeaseReminderMeta(serverId), undefined, {
113
+ scope: 'dialog',
114
+ renderMode: 'markdown',
115
+ });
113
116
  }
114
117
  class McpServerDispatch {
115
118
  serverId;