From 1fc96025d66167d87230e678852d658c3683fda2 Mon Sep 17 00:00:00 2001 From: wintrover Date: Sat, 13 Jun 2026 14:33:28 +0900 Subject: [PATCH] feat: allow configuring a separate model for subagents Add [subagents] config section to config.toml that allows overriding the model used by subagents independently from the parent agent. Priority order: 1. KIMI_SUBAGENT_MODEL env var (highest) 2. [subagents].model in config.toml 3. Parent agent model (default fallback) Closes #568 --- packages/agent-core/src/config/schema.ts | 8 +++++++ .../agent-core/src/session/subagent-host.ts | 22 ++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/agent-core/src/config/schema.ts b/packages/agent-core/src/config/schema.ts index 094239b73..e00d11328 100644 --- a/packages/agent-core/src/config/schema.ts +++ b/packages/agent-core/src/config/schema.ts @@ -104,6 +104,12 @@ export const BackgroundConfigSchema = z.object({ export type BackgroundConfig = z.infer; +export const SubagentConfigSchema = z.object({ + model: z.string().optional(), +}); + +export type SubagentConfig = z.infer; + export const ExperimentalConfigSchema = z.record(z.string(), z.boolean()); export type ExperimentalConfig = z.infer; @@ -204,6 +210,7 @@ export const KimiConfigSchema = z.object({ loopControl: LoopControlSchema.optional(), background: BackgroundConfigSchema.optional(), experimental: ExperimentalConfigSchema.optional(), + subagents: SubagentConfigSchema.optional(), telemetry: z.boolean().optional(), raw: z.record(z.string(), z.unknown()).optional(), }); @@ -243,6 +250,7 @@ export const KimiConfigPatchSchema = z loopControl: LoopControlPatchSchema.optional(), background: BackgroundConfigPatchSchema.optional(), experimental: ExperimentalConfigPatchSchema.optional(), + subagents: SubagentConfigSchema.optional(), telemetry: z.boolean().optional(), }) .strict(); diff --git a/packages/agent-core/src/session/subagent-host.ts b/packages/agent-core/src/session/subagent-host.ts index b47e1cd68..f6ee96c60 100644 --- a/packages/agent-core/src/session/subagent-host.ts +++ b/packages/agent-core/src/session/subagent-host.ts @@ -143,7 +143,7 @@ export class SessionSubagentHost { const completion = this.runWithActiveChild(agentId, options, async (runOptions) => { this.emitSubagentSpawned(parent, agentId, profileName, runOptions); try { - child.config.update({ modelAlias: parent.config.modelAlias }); + child.config.update({ modelAlias: this.resolveSubagentModel(parent) }); return await this.runPromptTurn(parent, agentId, child, profileName, runOptions); } catch (error) { this.emitSubagentFailed(parent, agentId, runOptions, error); @@ -159,7 +159,7 @@ export class SessionSubagentHost { const completion = this.runWithActiveChild(agentId, options, async (runOptions) => { try { runOptions.signal.throwIfAborted(); - child.config.update({ modelAlias: parent.config.modelAlias }); + child.config.update({ modelAlias: this.resolveSubagentModel(parent) }); this.emitSubagentStarted(parent, agentId); const turnId = child.turn.retry('agent-host'); if (turnId === null) { @@ -220,7 +220,7 @@ export class SessionSubagentHost { ); child.config.update({ - modelAlias: parent.config.modelAlias, + modelAlias: this.resolveSubagentModel(parent), thinkingLevel: parent.config.thinkingLevel, systemPrompt: parent.config.systemPrompt, }); @@ -350,15 +350,27 @@ export class SessionSubagentHost { return { result, usage }; } + private resolveSubagentModel(parent: Agent): string { + // Env var override has highest priority + const envModel = process.env.KIMI_SUBAGENT_MODEL; + if (envModel) return envModel; + + // Config override from [subagents] section + const subagentModel = this.session.options.config?.subagents?.model; + if (subagentModel) return subagentModel; + + // Default: inherit parent model + return parent.config.modelAlias; + } + private async configureChild( parent: Agent, child: Agent, profile: ResolvedAgentProfile, ): Promise { - // A subagent always inherits the parent agent's model. child.config.update({ cwd: parent.config.cwd, - modelAlias: parent.config.modelAlias, + modelAlias: this.resolveSubagentModel(parent), thinkingLevel: parent.config.thinkingLevel, });