Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions docs/design/2026-09-08-reasoning-model-presets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Kimi, Qwen and DeepSeek reasoning model presets

[English](2026-09-08-reasoning-model-presets.md) | [简体中文](2026-09-08-reasoning-model-presets.zh-CN.md)

## Problem and boundaries

PR #10999 introduced declarative reasoning capabilities but configured tiers only for native DeepSeek V4 Pro. Other models still rely on the legacy table or generic tiers, and native Kimi installs an enable_thinking field outside its protocol. This change expands provider presets and regression coverage through the existing installer, registry, ACP/WebShell, TUI and request pipeline without adding model-name checks.

Qwen 3.8 Flash exposed a legacy Max-only DashScope check that appended enable_thinking even after tiers were declared. The existing tiered-protocol predicate now prioritizes the resolved capability, and UI static-override reporting uses the same predicate. Unconfigured models retain the name fallback. Alibaba Kimi K3 accepts text/images; native Moonshot K3 retains video input.

CLI mock acceptance also found that provider defaults overwrite the global off preference during initial authentication. refreshAuth previously restored only tiers. It now restores reasoning=false in both live and rebuildable configuration so headless startup's two consecutive authentications preserve Off; mandatory-thinking models remain exempt. Authentication and hot-reload rebuilds preserve the session preference following the existing tier policy; model switching still applies the target model's defaults through its existing flow.

## Configuration matrix

| Route / model | Tiers or toggle | Default tier | Disable field |
| ---------------------------------------------------------------- | ---------------------------- | ---------------- | --------------------- |
| Moonshot K3 | low / high / max | max | Cannot disable |
| Moonshot K2.7 Code / Highspeed | Mandatory thinking, no tiers | Provider default | Cannot disable |
| Moonshot K2.6 | Toggle | Provider default | thinking.type |
| Native DeepSeek V4 Pro / Flash | low / high / max | high | thinking.type |
| Alibaba Standard Qwen 3.8 Max / Max-0902 / Flash | low / medium / xhigh | xhigh | reasoning_effort=none |
| Existing Alibaba Qwen 3.5 / 3.6 / 3.7 and Qwen3 Max-0123 hybrids | Toggle | Retain preset On | enable_thinking |
| Alibaba DeepSeek V4 Pro / Flash | high / max | high | enable_thinking |
| Alibaba DeepSeek V4 Pro-0813 / Flash-0731 | low / high / max | high | enable_thinking |
| Alibaba Standard Kimi K3 | low / high / max | max | Cannot disable |
| Alibaba Standard / existing Token Plan Kimi K2.7 Code | Mandatory thinking, no tiers | Provider default | Cannot disable |
| Alibaba Standard / existing plan Kimi K2.6 / K2.5 | Toggle | Retain preset On | enable_thinking |

The existing Token Plan DeepSeek V3.2 entry also gains an enable_thinking toggle capability.

Token Plan adds the listed Qwen 3.8 Flash and DeepSeek V4 Pro-0813 entries, retaining the existing mandatory-thinking restrictions on 3.8 Max / Preview and reflecting them in canDisable. Preview remains as an existing compatibility alias. Coding Plan adds capabilities only to existing hybrids, without adding models. Native DeepSeek stable IDs already point to the newer snapshots; Alibaba snapshot IDs are not assumed to be native API IDs.

## Native tiers and compatibility inputs

Qwen 3.8's native choices are low / medium / xhigh. The official Chat parameter reference also maps high and max to xhigh, so high in the legacy input ladder does not introduce another native tier. Explicit capabilities expose native choices only; unsupported persisted values are omitted and use the provider default (xhigh for Qwen 3.8). Routes without capabilities retain their existing clamp and warning for compatibility; explicit extra_body / samplingParams remain provider overrides. This is intentional configuration precedence, not a claim that the provider rejects high or max. No-argument /effort reports the model/provider default for unsupported saved tiers without modifying settings.

## Implementation and acceptance

Update the moonshot, deepseek, alibaba-standard, alibaba-token-plan and alibaba-coding-plan presets. Native Kimi removes enableThinking because its API defaults thinking on. Mandatory models retain thinkingMandatory and declare canDisable=false for existing generation-config consumers. toggleOnly declares no fabricated tiers. Alibaba Standard DeepSeek V4 Pro removes the redundant enableThinking; high/max send reasoning_effort alone, while Off still sends enable_thinking=false.

Preset installation tests inspect real configuration output. Request tests build configurations from real presets and assert the final payload. ACP tests verify exact choices and defaults. Coverage includes Off, non-thinking side queries, invalid tiers and unknown models. Run build, typecheck, bundle, focused tests and lint, and drive CLI acceptance against a mock API with isolated settings. Live paid provider requests are not part of local validation.

Presets affect new installations or provider reconfiguration. Existing settings are not automatically migrated or modified. Regional availability depends on the provider and account; existing endpoint scope is not expanded. GLM, MiniMax, Step, OpenRouter, ModelScope, Idealab and independent boundaries tracked in #11328 are outside this change.

## Official evidence (checked 2026-09-08)

- [Kimi K3](https://platform.kimi.ai/docs/guide/kimi-k3-quickstart): three tiers, default max, always thinking.
- [Kimi K2.7 Code](https://platform.kimi.ai/docs/guide/kimi-k2-7-code-quickstart): thinking defaults on and cannot be disabled.
- [Kimi K2.6](https://platform.kimi.ai/docs/guide/kimi-k2-6-quickstart): thinking.type toggle.
- [DeepSeek Thinking Mode](https://api-docs.deepseek.com/guides/thinking_mode/) and [model entry point](https://api-docs.deepseek.com/): native stable-ID versions, three tiers and disable shape.
- [Alibaba Chat parameters](https://help.aliyun.com/zh/model-studio/qwen-api-via-openai-chat-completions): family-specific tiers/defaults, enable_thinking and Qwen 3.8 parameter exclusivity.
- [Alibaba DeepSeek](https://help.aliyun.com/zh/model-studio/deepseek-api): stable-versus-snapshot tier differences.
- [Alibaba Kimi](https://help.aliyun.com/zh/model-studio/kimi-api): models and routes; max-only kimi/kimi-k3 is not added.
- [Token Plan model list](https://help.aliyun.com/zh/model-studio/token-plan-personal-overview): added Flash, Pro snapshot and Preview alias.
84 changes: 84 additions & 0 deletions docs/design/2026-09-08-reasoning-model-presets.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Kimi、Qwen 与 DeepSeek 推理模型配置补全

[English](2026-09-08-reasoning-model-presets.md) | [简体中文](2026-09-08-reasoning-model-presets.zh-CN.md)

## 问题与边界

PR #10999 已提供声明式 reasoning capability,但只有原生 DeepSeek V4 Pro
配置了档位。其他模型仍依赖旧表或通用档位,原生 Kimi 还会安装不属于其
协议的 `enable_thinking`。本次扩展 provider 预设及其回归测试,复用
安装、模型注册、ACP/WebShell、TUI 和请求流水线,不增加模型名判断。

Qwen 3.8 Flash 暴露了 DashScope 的旧 Max-only 判断:声明档位之后仍会追加
enable_thinking。让现有 tiered 协议判断优先读取已解析 capability,同时
让 UI 的高优先级参数提示使用相同判定。未配置模型保留原来的名称回退。
阿里云 Kimi K3 仅开放文本/图片;原生 Moonshot K3 保留视频输入能力。

CLI mock 验收另发现全局关闭偏好在初次认证时被 provider 默认值覆盖;
refreshAuth 原先只恢复档位。现在同时恢复 live 与可重建配置中的
reasoning=false,使 headless 的连续两次认证也保留关闭状态;强制思考
模型仍豁免。认证或热重载引发的重建按已有档位策略保留会话偏好;
模型切换仍通过已有流程应用新模型默认值。

## 配置矩阵

| 路由 / 模型 | 档位或开关 | 默认档位 | 关闭字段 |
| ---------------------------------------------------------------- | -------------------- | ------------- | --------------------- |
| Moonshot K3 | low / high / max | max | 不允许关闭 |
| Moonshot K2.7 Code / Highspeed | 强制思考,无可选档位 | provider 默认 | 不允许关闭 |
| Moonshot K2.6 | 开关 | provider 默认 | thinking.type |
| 原生 DeepSeek V4 Pro / Flash | low / high / max | high | thinking.type |
| Alibaba Standard Qwen 3.8 Max / Max-0902 / Flash | low / medium / xhigh | xhigh | reasoning_effort=none |
| 已有 Alibaba Qwen 3.5 / 3.6 / 3.7 与 Qwen3 Max-0123 混合思考条目 | 开关 | 保留预设开启 | enable_thinking |
| Alibaba DeepSeek V4 Pro / Flash | high / max | high | enable_thinking |
| Alibaba DeepSeek V4 Pro-0813 / Flash-0731 | low / high / max | high | enable_thinking |
| Alibaba Standard Kimi K3 | low / high / max | max | 不允许关闭 |
| Alibaba Standard / 已有 Token Plan Kimi K2.7 Code | 强制思考,无可选档位 | provider 默认 | 不允许关闭 |
| Alibaba Standard / 已有套餐 Kimi K2.6 / K2.5 | 开关 | 保留预设开启 | enable_thinking |

已有 Token Plan DeepSeek V3.2 也补上 enable_thinking 开关能力。

Token Plan 补充已列出的 Qwen 3.8 Flash 和 DeepSeek V4 Pro-0813,保留
3.8 Max / Preview 现有强制思考限制并同步 canDisable。Preview 作为已有
兼容别名保留。Coding Plan 只补已有混合思考条目的能力,不增加模型。
原生 DeepSeek 的稳定 ID 已指向新快照;不把阿里云的快照 ID 猜测为原生 API ID。

## 原生档位与兼容输入

Qwen 3.8 的原生选项为 low / medium / xhigh。官方 Chat 参数文档同时规定
high、max 映射到 xhigh,因此旧兼容表包含 high 并不代表新增了一个原生档位。
显式 capability 只展示原生选项;不在声明中的持久化值被省略,采用 provider
默认值(Qwen 3.8 为 xhigh)。未声明 capability 的路由继续使用原有 clamp
和警告,以保留兼容行为;显式 extra_body / samplingParams 仍作为 provider
参数透传。这是有意的配置优先规则,不代表 provider 会拒绝 high 或 max。
无参数 /effort 对不支持的旧档位报告使用模型/provider 默认值,查询不修改设置。

## 实现与验收

修改 moonshot、deepseek、alibaba-standard、alibaba-token-plan 和
alibaba-coding-plan 预设。原生 Kimi 删除 enableThinking;其 API 默认开启
思考。强制思考模型同时保留 thinkingMandatory 和声明 canDisable=false,
照顾已有 generation config 消费者。toggleOnly 不声明虚构档位。
Alibaba Standard DeepSeek V4 Pro 移除冗余 enableThinking,high/max 只发送
reasoning_effort;关闭仍发送 enable_thinking=false。

预设安装测试覆盖真实配置产物;请求测试从真实预设生成配置并断言最终
payload;ACP 测试验证精确选项和默认值。测试包含关闭、副请求关闭、非法
档位和未知模型。执行 build、typecheck、bundle、聚焦测试与 lint,并使用
隔离配置的 mock API 完成 CLI 验收;真实供应商付费调用不作为本地验证。

这些预设影响新安装或重新配置 provider。已有 settings 不会自动迁移,
不修改用户当前配置。地域可用性取决于账号和供应商,不扩大既有 endpoint
范围。GLM、MiniMax、Step、OpenRouter、ModelScope、Idealab 及 #11328 中
与本次条目无关的边界不在范围内。

## 官方依据(2026-09-08 核对)

- [Kimi K3](https://platform.kimi.ai/docs/guide/kimi-k3-quickstart):三档、默认 max、始终思考。
- [Kimi K2.7 Code](https://platform.kimi.ai/docs/guide/kimi-k2-7-code-quickstart):thinking 默认开启且不允许关闭。
- [Kimi K2.6](https://platform.kimi.ai/docs/guide/kimi-k2-6-quickstart):thinking.type 开关。
- [DeepSeek Thinking Mode](https://api-docs.deepseek.com/guides/thinking_mode/) 与 [模型入口](https://api-docs.deepseek.com/):原生稳定 ID 的版本、三档和关闭形状。
- [Alibaba Chat 参数](https://help.aliyun.com/zh/model-studio/qwen-api-via-openai-chat-completions):各系列档位、默认值、enable_thinking 与 Qwen 3.8 互斥字段。
- [Alibaba DeepSeek](https://help.aliyun.com/zh/model-studio/deepseek-api):稳定版与快照的档位差异。
- [Alibaba Kimi](https://help.aliyun.com/zh/model-studio/kimi-api):模型及路由;不加入仅支持 max 的 kimi/kimi-k3。
- [Token Plan 模型列表](https://help.aliyun.com/zh/model-studio/token-plan-personal-overview):新增 Flash、Pro 快照和 Preview 别名。
82 changes: 82 additions & 0 deletions packages/cli/src/acp-integration/model-configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
*/

import type { Config, ContentGeneratorConfig } from '@qwen-code/qwen-code-core';
import {
buildInstallPlan,
findProviderById,
resolveBaseUrl,
} from '@qwen-code/qwen-code-core';
import type { LoadedSettings } from '../config/settings.js';
import { describe, expect, it, vi } from 'vitest';
import {
Expand Down Expand Up @@ -58,6 +63,83 @@ describe('default reasoning configuration', () => {
});

describe('model configuration manifest', () => {
it.each([
['moonshot', 'kimi-k3', ['low', 'high', 'max'], 'max'],
['moonshot', 'kimi-k2.7-code', ['default'], 'default'],
['moonshot', 'kimi-k2.7-code-highspeed', ['default'], 'default'],
['moonshot', 'kimi-k2.6', ['none', 'default'], 'default'],
['deepseek', 'deepseek-v4-pro', ['none', 'low', 'high', 'max'], 'high'],
['deepseek', 'deepseek-v4-flash', ['none', 'low', 'high', 'max'], 'high'],
[
'alibabaStandard',
'qwen3.8-max',
['none', 'low', 'medium', 'xhigh'],
'xhigh',
],
[
'alibabaStandard',
'qwen3.8-max-0902',
['none', 'low', 'medium', 'xhigh'],
'xhigh',
],
[
'alibabaStandard',
'qwen3.8-flash',
['none', 'low', 'medium', 'xhigh'],
'xhigh',
],
['alibabaStandard', 'deepseek-v4-pro', ['none', 'high', 'max'], 'high'],
[
'alibabaStandard',
'deepseek-v4-pro-0813',
['none', 'low', 'high', 'max'],
'high',
],
['alibabaStandard', 'kimi-k3', ['low', 'high', 'max'], 'max'],
['token-plan', 'qwen3.8-max', ['low', 'medium', 'xhigh'], 'xhigh'],
['token-plan', 'qwen3.8-max-preview', ['low', 'medium', 'xhigh'], 'xhigh'],
[
'token-plan',
'qwen3.8-flash',
['none', 'low', 'medium', 'xhigh'],
'xhigh',
],
[
'token-plan',
'deepseek-v4-flash-0731',
['none', 'low', 'high', 'max'],
'high',
],
['coding-plan', 'qwen3.5-plus', ['none', 'default'], 'default'],
['coding-plan', 'kimi-k2.5', ['none', 'default'], 'default'],
] as const)(
'projects installed %s / %s native choices',
(providerId, model, values, currentValue) => {
const preset = findProviderById(providerId)!;
const installed = buildInstallPlan(preset, {
baseUrl: resolveBaseUrl(preset),
apiKey: 'test-key',
modelIds: [model],
}).modelProviders![0].models[0];
const reasoning = installed.capabilities?.reasoning;
expect(reasoning).toBeDefined();
const option = buildModelReasoningConfigOption(model, {}, reasoning);
expect(
option?.options.map((item) =>
'value' in item ? item.value : undefined,
),
).toEqual(values);
expect(option?.currentValue).toBe(currentValue);
const restored = buildModelReasoningConfigOption(
model,
{ effort: 'high' },
reasoning,
);
expect(restored?.currentValue).toBe(
values.some((value) => value === 'high') ? 'high' : currentValue,
);
},
);
it.each([
['gpt-5.1', ['none', 'low', 'medium', 'high'], 'none'],
['gpt-5.4', ['none', 'low', 'medium', 'high', 'xhigh'], 'none'],
Expand Down
28 changes: 27 additions & 1 deletion packages/cli/src/ui/commands/effort-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { describe, it, expect, beforeEach, vi } from 'vitest';
import type { Config } from '@qwen-code/qwen-code-core';
import { tokenPlanProvider, type Config } from '@qwen-code/qwen-code-core';
import { type CommandContext } from './types.js';
import { effortCommand } from './effort-command.js';
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
Expand Down Expand Up @@ -103,6 +103,32 @@ describe('effortCommand', () => {
expect(setReasoningEffort).not.toHaveBeenCalled();
});

it.each(['high', 'max', 'low'] as const)(
'reports the effective state for saved %s without changing settings',
async (effort) => {
const spec = tokenPlanProvider.models!.find(
(m) => m.id === 'qwen3.8-max',
)!;
Object.assign(context.services.config!, {
getModel: () => spec.id,
getAuthType: () => 'openai',
getResolvedModelConfig: () => spec,
});
getReasoningEffort.mockReturnValue(effort);
const res = await effortCommand.action!(
{ ...context, executionMode: 'non_interactive' },
'',
);
expect((res as { content: string }).content).toContain(
effort === 'low'
? 'Current reasoning effort:'
: 'using the model/provider default',
);
expect(setValue).not.toHaveBeenCalled();
expect(setReasoningEffort).not.toHaveBeenCalled();
},
);

it('sets and persists a valid tier', async () => {
const res = await effortCommand.action!(context, 'high');
expect(setReasoningEffort).toHaveBeenCalledWith('high');
Expand Down
19 changes: 10 additions & 9 deletions packages/cli/src/ui/commands/effort-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,16 @@ export const effortCommand: SlashCommand = {
return {
type: 'message',
messageType: 'info',
content: current
? t(
'Current reasoning effort: {{current}}\nAvailable: {{tiers}}\nUse "/effort <tier>" to change it.',
{ current, tiers: availableTierList },
)
: t(
'Reasoning effort: not set (using the model/provider default).\nAvailable: {{tiers}}\nUse "/effort <tier>" to set it.',
{ tiers: availableTierList },
),
content:
current && availableTiers.includes(current)
? t(
'Current reasoning effort: {{current}}\nAvailable: {{tiers}}\nUse "/effort <tier>" to change it.',
{ current, tiers: availableTierList },
)
: t(
'Reasoning effort: not set (using the model/provider default).\nAvailable: {{tiers}}\nUse "/effort <tier>" to set it.',
Comment thread
callmeYe marked this conversation as resolved.
{ tiers: availableTierList },
),
};
}

Expand Down
Loading
Loading