Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion .changeset/catalog-followup-correctness.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"@moonshot-ai/kimi-code-sdk": patch
"@moonshot-ai/agent-core": patch
"@moonshot-ai/agent-core-v2": patch
"@moonshot-ai/kap-server": patch
"@moonshot-ai/kimi-code": patch
---

Fix a set of small correctness issues on top of the catalog metadata work: configured efforts (config or the KIMI_MODEL_THINKING_EFFORT env override) are now normalized instead of being sent upstream as invalid values; a model's declared input limit can no longer exceed its effective context window, and the clamp now copies the record instead of mutating the user's config in place; context-usage percentages share one denominator (the effective input cap) across status endpoints, clamped to 1 where the wire schema bounds it while event streams keep the documented raw overflow signal; a provider-observed smaller context window now actually wins over the catalog's declared input cap during overflow recovery; per-model endpoints declared with an unrecognized override SDK are preserved via the OpenAI-compatible fallback, while known proprietary SDKs stay refused; and the model inspector attributes input-limit fields to their actual config, override, or clamp provenance.
Fix a set of small correctness issues on top of the catalog metadata work: the always-thinking inference now applies only on the OpenAI wires, so Claude and other Anthropic-protocol models are no longer wrongly locked into always-on thinking (their off switch is natively encodable); configured efforts (config or the KIMI_MODEL_THINKING_EFFORT env override) are now normalized instead of being sent upstream as invalid values; a model's declared input limit can no longer exceed its effective context window, and the clamp now copies the record instead of mutating the user's config in place; context-usage percentages share one denominator (the effective input cap) across status endpoints, clamped to 1 where the wire schema bounds it while event streams keep the documented raw overflow signal; a provider-observed smaller context window now actually wins over the catalog's declared input cap during overflow recovery; per-model endpoints declared with an unrecognized override SDK are preserved via the OpenAI-compatible fallback, while known proprietary SDKs stay refused, and alias-level base URLs are honored on every wire; and the model inspector attributes input-limit fields to their actual config, override, or clamp provenance.
5 changes: 4 additions & 1 deletion docs/en/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,13 @@ Each entry in the `models` table defines a model alias (the name used in `defaul
| `provider` | `string` | Yes | Name of the provider to use; must be defined in `providers` |
| `model` | `string` | Yes | Model identifier sent to the server when calling the API |
| `max_context_size` | `integer` | Yes | Maximum context length in tokens; must be at least 1 |
| `max_input_size` | `integer` | No | Declared per-request input limit when it sits below the total window (e.g. gpt-5: 400k window, 272k input). Compaction, context-overflow checks, and usage ratios prefer it; completion budgeting keeps the total window. Resolution clamps it to `max_context_size` |
| `max_output_size` | `integer` | No | Per-request output token cap (maps to `max_tokens`). Currently only the `anthropic` provider honors it. When set for a Claude model, this explicit value overrides the built-in server-side maximum |
| `capabilities` | `array<string>` | No | Capability tags to add explicitly: `thinking`, `always_thinking`, `image_in`, `video_in`, `audio_in`, `tool_use`. Unioned with the capabilities auto-detected by the provider — entries can only be added, never removed |
| `support_efforts` | `array<string>` | No | Thinking effort levels the model accepts. For `kimi`, selecting another value at runtime fails; when model resolution carries an unsupported configured or previous value, the session falls back to the target model's `default_effort` and reports that effective value to the UI. A Thinking-capable Kimi model without this field uses boolean `on` / `off`. Other providers pass concrete values unchanged when their protocol has a native effort field; protocols that expose only levels or token budgets perform the required format conversion. Managed and open-platform refreshes may rewrite this field; to pin it manually, set `[models."<alias>".overrides] support_efforts` instead |
| `default_effort` | `string` | No | Default thinking effort for the model. Managed and open-platform refreshes may rewrite this field; to pin it manually, set `[models."<alias>".overrides] default_effort` instead |
| `off_effort` | `string` | No | Effort value sent on the wire to disable thinking (e.g. `none` for xai grok). Only meaningful for models that declare such an encoding (catalog imports set it): turning thinking Off then sends this value instead of omitting the effort field — the only way to actually stop reasoning on models that reason by default |
| `base_url` | `string` | No | Per-model endpoint override (written by catalog imports for gateway models served away from the provider default). Resolution prefers it over the provider's `base_url`; only takes effect together with `protocol` |
| `display_name` | `string` | No | Name shown in the UI; falls back to `model` when unset |
| `reasoning_key` | `string` | No | `openai` provider only. Override the field name used for reasoning content when the gateway returns it under a non-standard name; by default `reasoning_content`, `reasoning_details`, and `reasoning` are auto-detected |
| `adaptive_thinking` | `boolean` | No | `anthropic` provider only. Force adaptive thinking on or off, overriding the version inference based on the model name. Omit to infer automatically (Claude ≥ 4.6 uses adaptive) |
Expand Down Expand Up @@ -181,7 +184,7 @@ max_context_size = 131072
display_name = "Kimi for Coding (custom)"
```

`[models."<alias>".overrides]` accepts ordinary model fields such as `max_context_size`, `max_output_size`, `capabilities`, `display_name`, `reasoning_key`, `adaptive_thinking`, `support_efforts`, and `default_effort`. It does not accept identity / routing fields: `provider`, `model`, `protocol`, `beta_api`, and `base_url`.
`[models."<alias>".overrides]` accepts ordinary model fields such as `max_context_size`, `max_input_size`, `max_output_size`, `capabilities`, `display_name`, `reasoning_key`, `adaptive_thinking`, `support_efforts`, `default_effort`, and `off_effort`. It does not accept identity / routing fields: `provider`, `model`, `protocol`, `beta_api`, and `base_url`.

You can also switch models temporarily without touching the config file — by setting `KIMI_MODEL_*` environment variables, the CLI synthesizes a temporary provider in memory that does not persist after restart. See [Define a model from environment variables](./env-vars.md#define-a-model-from-environment-variables-kimi_model).

Expand Down
2 changes: 1 addition & 1 deletion docs/en/configuration/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The manager displays providers as a list of entries grouped by source. Navigatio

Two paths when adding:

- **Known third-party provider**: fetches the model catalog from [models.dev](https://models.dev/), select a provider → enter an API key → select a default model
- **Known third-party provider**: fetches the model catalog from [models.dev](https://models.dev/), select a provider → enter an API key → select a default model. Vendors whose protocol the catalog does not declare (e.g. xai, openrouter, and other vendor-specific SDKs) are imported as OpenAI-compatible with a "guessed" note; when the catalog provides no usable endpoint, a base URL prompt appears first; proprietary protocols (Amazon Bedrock, Cohere) and unrecognized explicit protocols are refused. Deprecated and alpha-status models are excluded from the import list
- **Custom registry (api.json)**: paste a custom registry URL and Bearer token; the CLI automatically creates the `providers` / `models` entries. On later startup, providers from the same registry URL are refreshed together, so upstream provider additions, removals, and model metadata changes are synced.

::: warning
Expand Down
5 changes: 4 additions & 1 deletion docs/zh/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,13 @@ KIMI_BASE_URL = "https://api.moonshot.ai/v1"
| `provider` | `string` | 是 | 使用的供应商名称,必须在 `providers` 中定义 |
| `model` | `string` | 是 | 调用 API 时实际传给服务端的模型 ID |
| `max_context_size` | `integer` | 是 | 最大上下文长度(token 数),必须 ≥ 1 |
| `max_input_size` | `integer` | 否 | 模型声明的单次请求输入上限(当低于总窗口时,如 gpt-5 的 400k 窗口 / 272k 输入)。压缩、上下文溢出检查和用量比率优先使用它;补全预算仍使用总窗口。解析时会被钳制到不超过 `max_context_size` |
| `max_output_size` | `integer` | 否 | 单次请求的输出 token 上限(对应 `max_tokens`)。目前仅 `anthropic` 供应商读取。为 Claude 模型设置后,这个显式值会覆盖内置的服务端最大值 |
| `capabilities` | `array<string>` | 否 | 显式追加的能力标签:`thinking`、`always_thinking`、`image_in`、`video_in`、`audio_in`、`tool_use`。与供应商自动识别的能力取并集,只能追加不能移除 |
| `support_efforts` | `array<string>` | 否 | 模型接受的 Thinking 档位。对 `kimi` 而言,在运行时选择列表外的值会报错;模型解析时若配置值或之前的值不受目标模型支持,会回落到目标模型的 `default_effort`,并将该有效值同步给 UI。支持 Thinking 但没有此字段的 Kimi 模型使用布尔 `on` / `off`。其他 provider 在协议提供原生 effort 字段时会原样传递具体值;协议仅提供等级或 token budget 时,只做必要的格式转换。managed 和 open-platform 刷新可能会改写该字段;如需手动固定,请改用 `[models."<alias>".overrides] support_efforts` |
| `default_effort` | `string` | 否 | 模型的默认 Thinking 档位。managed 和 open-platform 刷新可能会改写该字段;如需手动固定,请改用 `[models."<alias>".overrides] default_effort` |
| `off_effort` | `string` | 否 | 关闭 Thinking 时在线上传输的 effort 编码(如 xai grok 的 `none`)。仅对声明了该编码的模型(catalog 会导入)有意义:设置后选择 Off 会发送这个值而不是省略 effort 字段——对默认就会推理的模型,这是真正关闭推理的唯一方式 |
| `base_url` | `string` | 否 | 模型级端点覆盖(catalog 导入网关模型时写入,这些模型与供应商默认端点不同)。解析时优先于供应商的 `base_url`;仅在与 `protocol` 配合时生效 |
| `display_name` | `string` | 否 | UI 中显示的名称,未设时回退到 `model` |
| `reasoning_key` | `string` | 否 | 仅 `openai` 供应商。当网关用非标准字段名返回推理内容时才需要设置;默认自动识别 `reasoning_content` / `reasoning_details` / `reasoning` |
| `adaptive_thinking` | `boolean` | 否 | 仅 `anthropic` 供应商。强制开启或关闭 adaptive thinking,覆盖按模型名推断的逻辑。省略时自动推断(Claude ≥ 4.6 使用 adaptive) |
Expand Down Expand Up @@ -181,7 +184,7 @@ max_context_size = 131072
display_name = "Kimi for Coding (custom)"
```

`[models."<alias>".overrides]` 接受普通模型字段,例如 `max_context_size`、`max_output_size`、`capabilities`、`display_name`、`reasoning_key`、`adaptive_thinking`、`support_efforts` 和 `default_effort`。不接受身份 / 路由字段:`provider`、`model`、`protocol`、`beta_api` 和 `base_url`。
`[models."<alias>".overrides]` 接受普通模型字段,例如 `max_context_size`、`max_input_size`、`max_output_size`、`capabilities`、`display_name`、`reasoning_key`、`adaptive_thinking`、`support_efforts`、`default_effort` 和 `off_effort`。不接受身份 / 路由字段:`provider`、`model`、`protocol`、`beta_api` 和 `base_url`。

无需修改配置文件也可以临时切换模型——通过 `KIMI_MODEL_*` 环境变量在内存里合成一个临时供应商,详见[用环境变量定义模型](./env-vars.md#用环境变量定义模型-kimi-model)。

Expand Down
2 changes: 1 addition & 1 deletion docs/zh/configuration/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Kimi Code CLI 支持同时接入多家 LLM 平台——用 Kimi Code 托管服

添加时有两条路径:

- **Known third-party provider**:从 [models.dev](https://models.dev/) 拉取模型目录,选供应商 → 输入 API 密钥 → 选默认模型
- **Known third-party provider**:从 [models.dev](https://models.dev/) 拉取模型目录,选供应商 → 输入 API 密钥 → 选默认模型。目录未声明协议类型的供应商(如 xai、openrouter 这类厂商专用 SDK)会按 OpenAI 兼容协议导入并显示 "guessed" 提示;目录没有可用端点时会先弹出 base URL 输入框;Amazon Bedrock / Cohere 等专有协议和无法识别的显式协议会被拒绝导入。已下线(deprecated)和 alpha 状态的模型不会出现在导入列表中
- **Custom registry (api.json)**:粘贴自定义 registry 地址和 Bearer token,CLI 自动创建 `providers` / `models` 条目。后续启动时,同一个 registry 地址下的供应商会一起刷新,因此上游新增、删除供应商以及模型元数据变化都会同步。

::: warning
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/reference/kimi-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ kimi provider catalog list anthropic

#### `kimi provider catalog add <providerId>`

按 id 从 catalog 直接导入一个已知供应商,协议类型、base URL、模型信息均由 catalog 提供,只需提供 API key。catalog 未声明协议的供应商(如 xai、openrouter 这类专有 SDK)按 OpenAI 兼容协议导入,并在输出中标注 "guessed";catalog 未提供可用端点时需用 `--base-url` 显式指定。专有协议(如 Amazon Bedrock)无法导入。
按 id 从 catalog 直接导入一个已知供应商,协议类型、base URL、模型信息均由 catalog 提供,只需提供 API key。catalog 未声明协议的供应商(如 xai、openrouter 这类厂商专用 SDK)按 OpenAI 兼容协议导入,并在输出中标注 "guessed";catalog 未提供可用端点时需用 `--base-url` 显式指定。专有协议(如 Amazon Bedrock)无法导入。

| 参数 / 选项 | 说明 |
| --- | --- |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,23 +451,17 @@ export class AgentLLMRequesterService implements IAgentLLMRequesterService {
private warnAboutAnthropicThinkingEffort(request: ResolvedLLMRequest): void {
if (request.model.protocol !== 'anthropic') return;
const effort = request.thinkingEffort;
if (effort === 'on') return;
if (effort === 'on' || effort === 'off') return;

let code: string;
let message: string;
let knownEfforts: string | undefined;
if (effort === 'off') {
if (!request.model.alwaysThinking) return;
code = 'anthropic-thinking-cannot-disable';
message = `Model "${request.model.name}" declares always-on thinking. The configured effort "off" will be sent unchanged to the Anthropic-compatible backend.`;
} else {
const supportEfforts = request.model.supportEfforts?.filter((value) => value.length > 0);
if (supportEfforts === undefined || supportEfforts.length === 0) return;
if (supportEfforts.includes(effort)) return;
code = 'anthropic-thinking-effort-not-listed';
knownEfforts = supportEfforts.join(',');
message = `Thinking effort "${effort}" is not listed for model "${request.model.name}" (known: ${supportEfforts.join(', ')}). The configured value will be sent unchanged to the Anthropic-compatible backend.`;
}
const supportEfforts = request.model.supportEfforts?.filter((value) => value.length > 0);
if (supportEfforts === undefined || supportEfforts.length === 0) return;
if (supportEfforts.includes(effort)) return;
code = 'anthropic-thinking-effort-not-listed';
knownEfforts = supportEfforts.join(',');
message = `Thinking effort "${effort}" is not listed for model "${request.model.name}" (known: ${supportEfforts.join(', ')}). The configured value will be sent unchanged to the Anthropic-compatible backend.`;

const key = [code, request.modelAlias, request.model.name, effort, knownEfforts].join('\u0000');
if (this.emittedThinkingEffortWarnings.has(key)) return;
Expand Down
18 changes: 6 additions & 12 deletions packages/agent-core-v2/src/agent/profile/profileService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,22 +546,16 @@ export class AgentProfileService extends Disposable implements IAgentProfileServ
const model = this.tryResolveRawModel();
if (model?.protocol !== 'anthropic') return;
const effort = this.getEffectiveThinkingLevel();
if (effort === 'on') return;
if (effort === 'on' || effort === 'off') return;

let code: string;
let message: string;
let knownEfforts = '';
if (effort === 'off') {
if (!model.alwaysThinking) return;
code = 'anthropic-thinking-cannot-disable';
message = `Model "${model.name}" declares always-on thinking. The configured effort "off" will be sent unchanged to the Anthropic-compatible backend.`;
} else {
const efforts = model.supportEfforts?.filter((value) => value.length > 0);
if (efforts === undefined || efforts.length === 0 || efforts.includes(effort)) return;
knownEfforts = efforts.join(',');
code = 'anthropic-thinking-effort-not-listed';
message = `Thinking effort "${effort}" is not listed for model "${model.name}" (known: ${efforts.join(', ')}). The configured value will be sent unchanged to the Anthropic-compatible backend.`;
}
const efforts = model.supportEfforts?.filter((value) => value.length > 0);
if (efforts === undefined || efforts.length === 0 || efforts.includes(effort)) return;
knownEfforts = efforts.join(',');
code = 'anthropic-thinking-effort-not-listed';
message = `Thinking effort "${effort}" is not listed for model "${model.name}" (known: ${efforts.join(', ')}). The configured value will be sent unchanged to the Anthropic-compatible backend.`;

const key = [code, model.id, model.name, effort, knownEfforts].join('\u0000');
if (this.emittedThinkingEffortWarnings.has(key)) return;
Expand Down
22 changes: 9 additions & 13 deletions packages/agent-core-v2/src/kosong/model/thinking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,19 @@ export function usesTraitDrivenThinking(
}

/**
* ⚠ PHASE 6 PARITY PATCH — v1 `provider.type === 'kimi'` gate restored.
*
* Whether client-side thinking-effort validation must be STRICT for the
* (protocol, providerType) pair: the resolved traits take thinking over and
* the last `withThinking` declarer marks `strictThinkingValidation`.
*
* This is the gate for client-side effort strictness (validation, the
* always-on clamp, and the `'on'` projection). The strict flag is declared
* by `kimiOpenAITrait` — Kimi's native API rejects unlisted efforts — and
* deliberately NOT by `kimiAnthropicTrait`: over the Anthropic
* transport the backend may accept efforts the local catalog metadata does
* not list, so the profile must stay lenient there (warn-and-send, with the
* `anthropic-thinking-*` warnings) instead of rejecting or rewriting the
* effort. Gating on plain `usesTraitDrivenThinking` (true for the
* anthropic pair registration too) made `setThinking` throw for Kimi-managed
* Anthropic models and left the warning path unreachable — a v1 behavioral
* regression.
* Strict now gates only listed-effort validation and the `'on'` projection.
Comment thread
RealKai42 marked this conversation as resolved.
Outdated
* The always-on clamp is UNCONDITIONAL — a model that declares
* `always_thinking` never resolves to `'off'` on any wire (a claimed off
* state would be a lie, since upstream keeps reasoning at its default when
* no off encoding exists). Unlisted concrete efforts stay lenient on
* compatible transports (warn-and-send, `anthropic-thinking-effort-not-listed`)
* because the backend may accept values the local catalog does not list. The
* strict flag is declared by `kimiOpenAITrait` — Kimi's native API rejects
* unlisted efforts — and deliberately NOT by `kimiAnthropicTrait`.
*/
export function requiresStrictThinkingValidation(
registry: IProtocolAdapterRegistry,
Expand Down
Loading
Loading