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
2 changes: 1 addition & 1 deletion .agents/skills/agent-core-dev/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 0 additions & 4 deletions docs/en/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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 |
Expand Down
4 changes: 0 additions & 4 deletions docs/zh/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` 不能顶替。

要显式迁移,把模型别名改为池的默认模型即可:
Expand Down Expand Up @@ -382,8 +380,6 @@ max_output_size = 8192

`timeout_ms` 可被环境变量 `KIMI_SUBAGENT_TIMEOUT_MS` 覆盖,优先级高于配置文件。

之前在此配置的模型池(`default_model`、`[subagent.models]`)已移至 `[secondary_model]` 下的[子 Agent 模型池](#子-agent-模型池);旧键不再生效,并会以弃用警告的形式报告。

## `mcp`

| 字段 | 类型 | 默认值 | 说明 |
Expand Down
3 changes: 0 additions & 3 deletions packages/agent-core-v2/docs/config-manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
# ##########################################################################
Expand Down
8 changes: 1 addition & 7 deletions packages/agent-core-v2/src/session/subagent/configSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 →
Expand Down Expand Up @@ -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);
Expand Down
25 changes: 0 additions & 25 deletions packages/agent-core-v2/test/app/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
{},
Expand Down
Loading