chore: drop deprecations for unreleased [subagent] pool keys (#2877)

The [subagent] default_model / models deprecations added in #2700 guard a
migration path that has no users: the pool keys only existed in #2700's own
intermediate commits and never shipped in any release, so no config written
against a released version can contain them. Remove the two deprecation
entries (the mechanism stays — the released loop_control renames still use
it), the migration notes in the en/zh config docs, the agent-core-dev skill
note, and the obsolete test; regenerate the config manifest.

No changeset: #2700 is still unreleased, so no published version ever
emitted these warnings — the removal is invisible to users.
This commit is contained in:
7Sageer 2026-08-13 12:57:22 +08:00 committed by GitHub
parent c9bfe8b2c8
commit 6e31722df1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 2 additions and 44 deletions

View file

@ -101,7 +101,7 @@ pass `ConfigTarget.Memory` for a per-run override that is never written to disk.
- `src/kosong/model/thinking.ts` (owner domain, not `config`) — the `resolveThinkingEffort` helper and the authoritative `ThinkingConfig` type (the `thinking` section itself registers from `src/app/kosongConfig/configSection.ts`).
- `src/app/config/configPure.ts``isPlainObject`, `deepMerge`, `omitUndefined`, `describeUnknownError`.
A domain that owns a section keeps the schema in its own `configSection.ts` (e.g. `src/app/flag/flag.ts` for `experimental`, `src/agent/loop/configSection.ts` for `loopControl`). Exception: kosong-owned sections (`providers`, `models`, `thinking`) — kosong is a pure, persistence-free abstraction layer that defines only the types (`src/kosong/{provider,model}`); the section constants, the zod schemas (re-derived from those types and compile-time pinned via `AssertExact<Equal<z.infer<typeof Schema>, Type>>`, see `_base/utils/typeEquality.ts`), the registrations, env bindings, and TOML transforms all live in the persistence wrapper `src/app/kosongConfig/configSection.ts`. (`modelCatalog` has no kosong-side type at all — its section is fully self-contained in `app/kosongConfig`, types derived from the schema.) A cross-section env overlay (e.g. the `KIMI_MODEL_*` synthesis in `src/app/kosongConfig/envOverlay.ts`) lives in the wrapper too and is registered via module-level `registerConfigOverlay`. The session subagent domain owns two sections in `src/session/subagent/configSection.ts`: `[subagent]` (`timeout_ms` on disk) and `[secondary_model]` (`default_model` plus the `[secondary_model.models]` pool, with a lone legacy v1 `model` key honored as a fallback default below `default_model`), with the legacy `[subagent]` pool keys declared as deprecations; neither carries a cross-section overlay. Cross-field pool validation (default present / in-pool / every key resolvable) runs at session creation in `subagentModelsValidationService.ts`, not in the schema. The two-way sync between config sections and kosong's in-memory registries is owned by `IKosongConfigService` (`src/app/kosongConfig/kosongConfigService.ts`).
A domain that owns a section keeps the schema in its own `configSection.ts` (e.g. `src/app/flag/flag.ts` for `experimental`, `src/agent/loop/configSection.ts` for `loopControl`). Exception: kosong-owned sections (`providers`, `models`, `thinking`) — kosong is a pure, persistence-free abstraction layer that defines only the types (`src/kosong/{provider,model}`); the section constants, the zod schemas (re-derived from those types and compile-time pinned via `AssertExact<Equal<z.infer<typeof Schema>, Type>>`, see `_base/utils/typeEquality.ts`), the registrations, env bindings, and TOML transforms all live in the persistence wrapper `src/app/kosongConfig/configSection.ts`. (`modelCatalog` has no kosong-side type at all — its section is fully self-contained in `app/kosongConfig`, types derived from the schema.) A cross-section env overlay (e.g. the `KIMI_MODEL_*` synthesis in `src/app/kosongConfig/envOverlay.ts`) lives in the wrapper too and is registered via module-level `registerConfigOverlay`. The session subagent domain owns two sections in `src/session/subagent/configSection.ts`: `[subagent]` (`timeout_ms` on disk) and `[secondary_model]` (`default_model` plus the `[secondary_model.models]` pool, with a lone legacy v1 `model` key honored as a fallback default below `default_model`); neither carries a cross-section overlay. Cross-field pool validation (default present / in-pool / every key resolvable) runs at session creation in `subagentModelsValidationService.ts`, not in the schema. The two-way sync between config sections and kosong's in-memory registries is owned by `IKosongConfigService` (`src/app/kosongConfig/kosongConfigService.ts`).
## Scope

View file

@ -264,8 +264,6 @@ Note that `default_effort` stays a model-level default: once a global `[thinking
Configuration errors fail loudly instead of falling back silently: session creation, resume, and fork all fail at startup when `default_model` is missing, is not a pool key, or a pool key does not resolve to a configured `[models]` entry — and likewise when `force` is set without `default_model` or combined with a `[secondary_model.models]` table. The alias `primary` is reserved — it always binds the caller's own model — and is rejected as a pool key. A spawn whose `model` is neither a pool alias nor `"primary"` fails with an error listing the available choices.
The pool keys used to live under `[subagent]`; a leftover `[subagent] default_model` or `[subagent.models]` table no longer applies and is reported as a deprecation warning — move them into `[secondary_model]` as shown above.
When only the recipe `model` key is set — no `default_model`, no `[secondary_model.models]` table — the v2 engine reads it compatibly as the pool default: an implicit single-entry pool ranked below `default_model`, so a recipe setup keeps working unchanged. The compatibility only takes the model alias, though: the recipe patch fields (`default_effort`, `max_output_size`, …) do not carry over — write those settings onto the `[models]` entry the alias points to, for example via [`[models."<alias>".overrides]`](#model-overrides). Once a `[secondary_model.models]` table is configured, `default_model` stays required and `model` does not substitute for it.
To migrate explicitly, point the pool default at the same alias:
@ -383,8 +381,6 @@ In print mode (`kimi -p "<prompt>"`), Kimi Code stays alive after the main agent
`timeout_ms` can be overridden by the `KIMI_SUBAGENT_TIMEOUT_MS` environment variable, which takes higher priority than `config.toml`.
The model pool that used to be configured here (`default_model`, `[subagent.models]`) moved to the [subagent model pool](#subagent-model-pool) under `[secondary_model]`; the old keys no longer apply and are reported as deprecation warnings.
## `mcp`
| Field | Type | Default | Description |

View file

@ -263,8 +263,6 @@ kimi-for-coding-highspeed-deep = "同一模型的高 Thinking 档位。适合较
配置错误一律直接报错,不做静默回退:`default_model` 缺失、不是池中 key或池中 key 无法解析到已配置的 `[models]` 条目时会话的创建、恢复resume与 fork 都会在启动时直接失败;`force` 未搭配 `default_model` 或与 `[secondary_model.models]` 表同用时亦然。别名 `primary` 是保留字——它始终绑定调用方自己的模型——不能作为池中 key。工具调用传入的 `model` 既不是池中别名也不是 `"primary"` 时,本次派生报错并列出可选值。
模型池键之前位于 `[subagent]` 下;遗留的 `[subagent] default_model``[subagent.models]` 表不再生效,并会以弃用警告的形式报告——按上文示例移入 `[secondary_model]` 即可。
只写了配方键 `model`(没有 `default_model`,也没有 `[secondary_model.models]`v2 引擎会兼容读取它,把该别名当作池的默认模型——等价于只含它一个条目的隐式模型池,优先级低于 `default_model`,所以从配方迁移过来不改配置也能工作。注意兼容只取模型别名:补丁字段(`default_effort``max_output_size` 等)不会随之生效——请把这些设置写到别名指向的 `[models]` 条目上,例如通过 [`[models."<alias>".overrides]`](#模型覆盖项)。一旦配置了 `[secondary_model.models]` 表,`default_model` 依旧必填,`model` 不能顶替。
要显式迁移,把模型别名改为池的默认模型即可:
@ -382,8 +380,6 @@ max_output_size = 8192
`timeout_ms` 可被环境变量 `KIMI_SUBAGENT_TIMEOUT_MS` 覆盖,优先级高于配置文件。
之前在此配置的模型池(`default_model``[subagent.models]`)已移至 `[secondary_model]` 下的[子 Agent 模型池](#子-agent-模型池);旧键不再生效,并会以弃用警告的形式报告。
## `mcp`
| 字段 | 类型 | 默认值 | 说明 |

View file

@ -374,9 +374,6 @@ merge_all_available_skills = true
# owner: src/session/subagent/configSection.ts
# scope: core
# hooks: stripEnv
# deprecations (old key is ignored + warns; rename manually):
# default_model -> secondary_model.default_model
# models -> secondary_model.models
# env:
# timeout_ms <- KIMI_SUBAGENT_TIMEOUT_MS (custom parse)
# ##########################################################################

View file

@ -9,9 +9,7 @@
* var is set, `stripEnvBoundFields` restores the env-free raw value before
* persistence, so the override never leaks into `config.toml`. Per-run
* timeouts resolve through `resolveSubagentTimeoutMs`, and the timeout
* message renders with `formatSubagentTimeoutDescription`. The pool keys
* `default_model` / `models` are declared as deprecations on this section:
* they moved to `[secondary_model]` and their values here no longer apply.
* message renders with `formatSubagentTimeoutDescription`.
*
* - `[secondary_model]` the subagent model pool: `default_model` names the
* fallback model and the `[secondary_model.models]` table maps alias
@ -165,10 +163,6 @@ registerConfigSection(SUBAGENT_SECTION, SubagentConfigSchema, {
defaultValue: { timeoutMs: DEFAULT_SUBAGENT_TIMEOUT_MS },
env: subagentEnvBindings,
stripEnv: stripSubagentEnv,
deprecations: [
{ key: 'default_model', replacement: 'secondary_model.default_model' },
{ key: 'models', replacement: 'secondary_model.models' },
],
});
registerConfigSection(SECONDARY_MODEL_SECTION, SecondaryModelConfigSchema);

View file

@ -1208,31 +1208,6 @@ describe('config deprecations', () => {
disposables.dispose();
});
it('warns and ignores the legacy [subagent] pool keys, which moved to [secondary_model]', async () => {
const { config, disposables } = await createConfig(
{},
'[subagent]\ndefault_model = "provider/fast"\n\n[subagent.models]\n"provider/fast" = "fast and cheap"\n',
);
// The old values no longer apply — the pool only resolves from
// [secondary_model] now.
expect(resolveSubagentModelPool(config)).toBeUndefined();
expect(config.diagnostics()).toContainEqual({
domain: SUBAGENT_SECTION,
severity: 'warning',
message:
"[subagent] 'default_model' is deprecated and no longer used; rename it to 'secondary_model.default_model'. Run /update-config to fix it.",
});
expect(config.diagnostics()).toContainEqual({
domain: SUBAGENT_SECTION,
severity: 'warning',
message:
"[subagent] 'models' is deprecated and no longer used; rename it to 'secondary_model.models'. Run /update-config to fix it.",
});
disposables.dispose();
});
it('lets the replacement key win when both are present, still warning', async () => {
const { config, disposables } = await createConfig(
{},