Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/configurable-swarm-launch-ramp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Make the AgentSwarm launch ramp configurable via the `[swarm]` section in `config.toml` (`initial_launch_limit`, `launch_interval_ms`).
11 changes: 11 additions & 0 deletions docs/en/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,17 @@ 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`.

## `swarm`

`swarm` controls the launch ramp of the `AgentSwarm` tool: when a swarm batch starts, a number of subagents launch immediately and the rest follow one at a time at a fixed interval.

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `initial_launch_limit` | `integer` | `5` | Number of subagents launched immediately when a swarm batch starts |
| `launch_interval_ms` | `integer` | `700` | Delay in milliseconds between subsequent launches once `initial_launch_limit` subagents have started; `0` launches all remaining subagents without delay |

These settings only shape the initial launch ramp; the rate-limit backoff that applies when the provider throttles requests is unchanged.

## `mcp`

| Field | Type | Default | Description |
Expand Down
2 changes: 1 addition & 1 deletion docs/en/reference/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Collaboration tools handle inter-Agent coordination, user interaction, and Skill

**`Agent`** delegates a subtask to a sub-Agent. Required parameters: `prompt` (complete task description) and `description` (a 3–5 word short summary). Optional parameters: `subagent_type` (defaults to `coder`), `resume` (ID of an existing Agent to resume; mutually exclusive with `subagent_type`), `run_in_background` (defaults to false), and `model` (available only when the [subagent model pool](../configuration/config-files.md#subagent-model-pool) experiment is enabled and a pool is configured — a `[secondary_model.models]` table or a lone `default_model`: a pool alias, or `"primary"` for the model the caller itself is running; ignored when resuming). Without it, the subagent binds the pool's `default_model`; without a configured pool, subagents always inherit the caller's model. Agent tasks time out after 2 hours by default; the limit is configurable via `[subagent] timeout_ms` in `config.toml` (`0` = no timeout, or the `KIMI_SUBAGENT_TIMEOUT_MS` env var), and defaults to no timeout in print mode (`kimi -p`). In foreground mode the parent Agent waits for the sub-Agent to complete before continuing; in background mode a task ID is returned immediately and the result is automatically delivered back to the main Agent via a synthetic User message when done. When several foreground `Agent` calls run in the same step, the TUI groups them and shows each subagent's running, waiting, completed, or failed status with elapsed time. See [Agent & Sub-Agents](../customization/agents.md) for details.

**`AgentSwarm`** launches subagents from a shared `prompt_template` and an `items` array, resumes existing subagents through `resume_agent_ids`, or combines both in one call. The template must contain the `{{item}}` placeholder; each item replaces that placeholder and launches one new subagent. Pass `subagent_type` to choose the profile used by every spawned subagent in the swarm, or omit it to use `coder`. Pass `model` (available only when the [subagent model pool](../configuration/config-files.md#subagent-model-pool) experiment is enabled and a pool is configured — a `[secondary_model.models]` table or a lone `default_model`) to run item-spawned subagents on a pool alias or on the caller's own model (`"primary"`). Without it, item-spawned subagents bind the pool's `default_model`; without a configured pool, they inherit the caller's model. Resumed subagents keep their own model. Without `resume_agent_ids`, the tool requires at least 2 items; with `resume_agent_ids`, it can resume one or more existing subagents. The tool supports up to 128 total subagents, waits for all subagents to finish, and returns an aggregated report. In the TUI, foreground swarms show a live `Agent swarm` progress panel above the input box. If a model response calls `AgentSwarm`, that call must be the only tool call in the response; to run multiple swarms, call one `AgentSwarm`, wait for its result, then call the next, or combine the work into one swarm when a single template can cover it. In `manual` permission mode, `AgentSwarm` calls outside active swarm mode request approval unless a permission rule allows them; while swarm mode is active, `AgentSwarm` itself is auto-approved. Permission rules match `AgentSwarm` by tool name only — argument patterns such as `AgentSwarm(swarm)` are not supported. By default the tool ramps up concurrency without an upper limit (5 subagents start immediately, then 1 more every 700 ms); set `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` to a positive integer to cap how many subagents run at the same time during that ramp, or leave it unset for no cap. If it is set to a value that is not a positive integer, the AgentSwarm call fails fast.
**`AgentSwarm`** launches subagents from a shared `prompt_template` and an `items` array, resumes existing subagents through `resume_agent_ids`, or combines both in one call. The template must contain the `{{item}}` placeholder; each item replaces that placeholder and launches one new subagent. Pass `subagent_type` to choose the profile used by every spawned subagent in the swarm, or omit it to use `coder`. Pass `model` (available only when the [subagent model pool](../configuration/config-files.md#subagent-model-pool) experiment is enabled and a pool is configured — a `[secondary_model.models]` table or a lone `default_model`) to run item-spawned subagents on a pool alias or on the caller's own model (`"primary"`). Without it, item-spawned subagents bind the pool's `default_model`; without a configured pool, they inherit the caller's model. Resumed subagents keep their own model. Without `resume_agent_ids`, the tool requires at least 2 items; with `resume_agent_ids`, it can resume one or more existing subagents. The tool supports up to 128 total subagents, waits for all subagents to finish, and returns an aggregated report. In the TUI, foreground swarms show a live `Agent swarm` progress panel above the input box. If a model response calls `AgentSwarm`, that call must be the only tool call in the response; to run multiple swarms, call one `AgentSwarm`, wait for its result, then call the next, or combine the work into one swarm when a single template can cover it. In `manual` permission mode, `AgentSwarm` calls outside active swarm mode request approval unless a permission rule allows them; while swarm mode is active, `AgentSwarm` itself is auto-approved. Permission rules match `AgentSwarm` by tool name only — argument patterns such as `AgentSwarm(swarm)` are not supported. By default the tool ramps up concurrency without an upper limit (5 subagents start immediately, then 1 more every 700 ms — both configurable via [`swarm`](../configuration/config-files.md#swarm) in `config.toml`); set `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` to a positive integer to cap how many subagents run at the same time during that ramp, or leave it unset for no cap. If it is set to a value that is not a positive integer, the AgentSwarm call fails fast.

**`AskUserQuestion`** asks the user a structured multiple-choice question — useful for disambiguation or option selection. The `questions` parameter accepts 1–4 questions; each question requires `question` (ending with `?`), `options` (2–4 choices, each with a `label` and `description`), and optional `header` (max 12 characters) and `multi_select` (defaults to false). An "Other" option is appended automatically. Setting `background` to true starts a background question task and returns a task ID immediately. When the host does not support interactive questioning, a failure message is returned and the Agent should ask the user directly in a text reply instead.

Expand Down
11 changes: 11 additions & 0 deletions docs/zh/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,17 @@ k3-max = "同一模型的 max Thinking 档位。适合最难的子任务。"

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

## `swarm`

`swarm` 控制 `AgentSwarm` 工具的启动节奏:swarm 批次开始时立即启动一定数量的 subagent,其余 subagent 按固定间隔逐个启动。

| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `initial_launch_limit` | `integer` | `5` | swarm 批次开始时立即启动的 subagent 数量 |
| `launch_interval_ms` | `integer` | `700` | 启动数达到 `initial_launch_limit` 后,后续每次启动之间的间隔(毫秒);`0` 表示无延迟地启动全部剩余 subagent |

这些设置只影响初始启动节奏;当供应商限流时应用的速率限制退避行为不受影响。

## `mcp`

| 字段 | 类型 | 默认值 | 说明 |
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/reference/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Plan 模式是一种受约束的工作状态:进入后 `Write` 与 `Edit` 只

**`Agent`** 将子任务委托给 subagent 执行。必填参数:`prompt`(完整任务描述)和 `description`(3–5 个词的简短说明)。可选参数:`subagent_type`(默认 `coder`)、`resume`(恢复已有 Agent 的 ID,与 `subagent_type` 互斥)、`run_in_background`(默认 false)和 `model`(仅在启用 [subagent 模型池](../configuration/config-files.md#subagent-模型池) 实验功能并配置模型池后可用——`[secondary_model.models]` 表或仅一行 `default_model`:池中别名,或 `"primary"` 表示调用方自己运行的模型;resume 时无效)。未传入时 subagent 绑定池的 `default_model`;未配置模型池时,subagent 一律继承调用方模型。Agent 任务默认 2 小时超时,可通过 `config.toml` 的 `[subagent] timeout_ms`(`0` = 无超时,或 `KIMI_SUBAGENT_TIMEOUT_MS` 环境变量)配置,且在 print 模式(`kimi -p`)下默认无超时。前台模式下父 Agent 等待 subagent 完成再继续;后台模式立即返回任务 ID,完成时通过合成 User 消息自动回到 main agent。多个前台 `Agent` 调用在同一步运行时,TUI 会合并展示,并为每个 subagent 显示运行、等待、完成或失败状态以及已耗时长。subagent 体系细节见 [Agent 与 subagent](../customization/agents.md)。

**`AgentSwarm`** 可以从共享的 `prompt_template` 和 `items` 数组启动 subagent,也可以通过 `resume_agent_ids` 恢复已有 subagent,或在一次调用中同时使用两者。模板必须包含 `{{item}}` 占位符;每个 item 会替换该占位符,并启动一个新的 subagent。传入 `subagent_type` 可以指定整个 swarm 中所有新启动的 subagent 使用的 profile;省略时默认使用 `coder`。传入 `model`(仅在启用 [subagent 模型池](../configuration/config-files.md#subagent-模型池) 实验功能并配置模型池后可用——`[secondary_model.models]` 表或仅一行 `default_model`)可以让新启动的 subagent 运行在池中别名指定的模型或调用方自己的模型(`"primary"`)上。未传入时新启动的 subagent 绑定池的 `default_model`;未配置模型池时则继承调用方模型。恢复的 subagent 保持其原有模型。不传 `resume_agent_ids` 时,本工具要求至少 2 个 item;传入 `resume_agent_ids` 时,可以恢复 1 个或多个已有 subagent。本工具最多支持 128 个 subagent,会等待全部 subagent 完成,并返回聚合报告。在 TUI 中,前台 swarm 会在输入框上方显示实时 `Agent swarm` 进度面板。若一次模型响应调用 `AgentSwarm`,该调用必须是该响应中的唯一工具调用;如需运行多个 swarm,应先调用一个 `AgentSwarm` 并等待结果,再调用下一个,若单个模板可以覆盖这些工作,也可以合并为一个 swarm。在 `manual` 权限模式下,未处于 swarm mode 时调用 `AgentSwarm` 会触发审批,除非已有权限规则允许;swarm mode 已开启时,`AgentSwarm` 本身会自动放行。权限规则只能按工具名 `AgentSwarm` 匹配,不支持 `AgentSwarm(swarm)` 这类参数模式。默认情况下,本工具会逐步提升并发且不设上限(立即启动 5 个 subagent,之后每 700 毫秒再启动 1 个);将 `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` 设为正整数可限制该阶段同时运行的 subagent 数量,不设置则表示不限制。若设置为非正整数的值,本次 AgentSwarm 调用会立即失败。
**`AgentSwarm`** 可以从共享的 `prompt_template` 和 `items` 数组启动 subagent,也可以通过 `resume_agent_ids` 恢复已有 subagent,或在一次调用中同时使用两者。模板必须包含 `{{item}}` 占位符;每个 item 会替换该占位符,并启动一个新的 subagent。传入 `subagent_type` 可以指定整个 swarm 中所有新启动的 subagent 使用的 profile;省略时默认使用 `coder`。传入 `model`(仅在启用 [subagent 模型池](../configuration/config-files.md#subagent-模型池) 实验功能并配置模型池后可用——`[secondary_model.models]` 表或仅一行 `default_model`)可以让新启动的 subagent 运行在池中别名指定的模型或调用方自己的模型(`"primary"`)上。未传入时新启动的 subagent 绑定池的 `default_model`;未配置模型池时则继承调用方模型。恢复的 subagent 保持其原有模型。不传 `resume_agent_ids` 时,本工具要求至少 2 个 item;传入 `resume_agent_ids` 时,可以恢复 1 个或多个已有 subagent。本工具最多支持 128 个 subagent,会等待全部 subagent 完成,并返回聚合报告。在 TUI 中,前台 swarm 会在输入框上方显示实时 `Agent swarm` 进度面板。若一次模型响应调用 `AgentSwarm`,该调用必须是该响应中的唯一工具调用;如需运行多个 swarm,应先调用一个 `AgentSwarm` 并等待结果,再调用下一个,若单个模板可以覆盖这些工作,也可以合并为一个 swarm。在 `manual` 权限模式下,未处于 swarm mode 时调用 `AgentSwarm` 会触发审批,除非已有权限规则允许;swarm mode 已开启时,`AgentSwarm` 本身会自动放行。权限规则只能按工具名 `AgentSwarm` 匹配,不支持 `AgentSwarm(swarm)` 这类参数模式。默认情况下,本工具会逐步提升并发且不设上限(立即启动 5 个 subagent,之后每 700 毫秒再启动 1 个——两者均可通过 `config.toml` 中的 [`swarm`](../configuration/config-files.md#swarm) 配置);将 `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` 设为正整数可限制该阶段同时运行的 subagent 数量,不设置则表示不限制。若设置为非正整数的值,本次 AgentSwarm 调用会立即失败。

**`AskUserQuestion`** 以结构化多选题的形式向用户提问,适用于需要消歧或选择方案的场景。`questions` 参数接受 1–4 道题,每道题需提供 `question`(以 `?` 结尾)、`options`(2–4 个选项,每项含 `label` 和 `description`)以及可选的 `header`(最多 12 字符)和 `multi_select`(默认 false)。系统自动附加"其他"选项。`background` 为 true 时启动后台问题任务并立即返回任务 ID。宿主未实现交互式提问能力时返回失败提示,Agent 应改为在文本回复中直接提问。

Expand Down
13 changes: 12 additions & 1 deletion packages/agent-core-v2/docs/config-manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# commented "# field: type" lines describe the remaining schema fields.
# Values resolve as: default -> config.toml -> env overlay -> memory.

# Index (25 sections · 2 overlay(s))
# Index (26 sections · 2 overlay(s))
# background src/agent/task/configSection.ts
# builtinProductSkills src/app/skillCatalog/configSection.ts
# cron src/app/cron/configSection.ts
Expand All @@ -30,6 +30,7 @@
# secondaryModel src/session/subagent/configSection.ts
# services src/app/auth/configSection.ts
# subagent src/session/subagent/configSection.ts
# swarm src/features/swarm/configSection.ts
# task src/agent/task/configSection.ts
# thinking src/app/kosongConfig/configSection.ts
# tokenCounting src/agent/tokenCounting/configSection.ts
Expand Down Expand Up @@ -381,6 +382,16 @@ merge_all_available_skills = true
[subagent]
timeout_ms = 7200000

# ##########################################################################
# swarm
# owner: src/features/swarm/configSection.ts
# scope: core
# ##########################################################################

[swarm]
initial_launch_limit = 5
launch_interval_ms = 700

# ##########################################################################
# task
# owner: src/agent/task/configSection.ts
Expand Down
22 changes: 22 additions & 0 deletions packages/agent-core-v2/src/features/swarm/configSection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { z } from 'zod';

import { registerConfigSection } from '#/app/config/configSectionContributions';

export const SWARM_SECTION = 'swarm';

export const SWARM_INITIAL_LAUNCH_LIMIT_DEFAULT = 5;
export const SWARM_LAUNCH_INTERVAL_MS_DEFAULT = 700;

export const SwarmConfigSchema = z.object({
initialLaunchLimit: z.number().int().min(1).optional(),
launchIntervalMs: z.number().int().min(0).optional(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject launch intervals above Node's timer limit

When launch_interval_ms is 2147483648 or larger, this schema accepts it, but the value is passed directly to setTimeout in AgentRunBatch; on the supported Node.js 24 runtime, an overflowing timeout is reduced to 1 ms. A user requesting a very slow ramp therefore gets an almost immediate ramp instead. Cap the schema at the runtime's maximum timer delay or schedule through the existing setClampedTimeout helper.

Useful? React with 👍 / 👎.

});

export type SwarmConfig = z.infer<typeof SwarmConfigSchema>;

registerConfigSection(SWARM_SECTION, SwarmConfigSchema, {
defaultValue: {
initialLaunchLimit: SWARM_INITIAL_LAUNCH_LIMIT_DEFAULT,
launchIntervalMs: SWARM_LAUNCH_INTERVAL_MS_DEFAULT,
},
});
16 changes: 12 additions & 4 deletions packages/agent-core-v2/src/features/swarm/session/agentRunBatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import * as retry from 'retry';
import { isUserCancellation } from '#/_base/utils/abort';
import { setClampedTimeout } from '#/_base/utils/timer';
import { BugIndicatingError, Error2, ErrorCodes } from '#/errors';
import {
SWARM_INITIAL_LAUNCH_LIMIT_DEFAULT,
SWARM_LAUNCH_INTERVAL_MS_DEFAULT,
} from '../configSection';
import type { SessionSwarmRunResult, SessionSwarmTask } from './sessionSwarm';

export interface AgentRunAttemptOptions {
Expand Down Expand Up @@ -34,8 +38,6 @@ export type AgentRunAttemptHandle = {
}>;
};

const INITIAL_LAUNCH_LIMIT = 5;
const INITIAL_LAUNCH_INTERVAL_MS = 700;
const RATE_LIMIT_RETRY_BASE_MS = 3000;
const RATE_LIMIT_RETRY_FACTOR = 2;
const RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS = 2000;
Expand Down Expand Up @@ -91,6 +93,8 @@ type ActiveAttempt<T> = {

export type AgentRunBatchOptions = {
readonly maxConcurrency?: number;
readonly initialLaunchLimit?: number;
readonly launchIntervalMs?: number;
};

export class AgentRunBatch<T> {
Expand All @@ -102,6 +106,8 @@ export class AgentRunBatch<T> {
private readonly batchSignal: AbortSignal | undefined;
private readonly batchAbortListener: () => void;
private readonly maxConcurrency: number | undefined;
private readonly initialLaunchLimit: number;
private readonly launchIntervalMs: number;
private normalLaunchCount = 0;
private normalLaunchTimer: ReturnType<typeof setTimeout> | undefined;
private rateLimitLaunchTimer: ReturnType<typeof setTimeout> | undefined;
Expand All @@ -124,6 +130,8 @@ export class AgentRunBatch<T> {
options: AgentRunBatchOptions = {},
) {
this.maxConcurrency = options.maxConcurrency;
this.initialLaunchLimit = options.initialLaunchLimit ?? SWARM_INITIAL_LAUNCH_LIMIT_DEFAULT;
this.launchIntervalMs = options.launchIntervalMs ?? SWARM_LAUNCH_INTERVAL_MS_DEFAULT;
this.states = tasks.map((task, index) => ({
index,
task,
Expand Down Expand Up @@ -183,7 +191,7 @@ export class AgentRunBatch<T> {

private scheduleNormalLaunch(): void {
while (
this.normalLaunchCount < INITIAL_LAUNCH_LIMIT &&
this.normalLaunchCount < this.initialLaunchLimit &&
this.pending.length > 0 &&
!this.rateLimitMode &&
!this.isAtConcurrencyLimit()
Expand All @@ -208,7 +216,7 @@ export class AgentRunBatch<T> {
this.startAttempt(this.pending.shift()!);
this.normalLaunchCount += 1;
this.schedule();
}, INITIAL_LAUNCH_INTERVAL_MS);
}, this.launchIntervalMs);
}

private isAtConcurrencyLimit(): boolean {
Expand Down
Loading