Skip to content

feat(agent-core-v2): add named subagent model slots for autonomous model selection - #2264

Open
Yiksing wants to merge 1 commit into
MoonshotAI:mainfrom
Yiksing:feat/subagent-model-slots
Open

feat(agent-core-v2): add named subagent model slots for autonomous model selection#2264
Yiksing wants to merge 1 commit into
MoonshotAI:mainfrom
Yiksing:feat/subagent-model-slots

Conversation

@Yiksing

@Yiksing Yiksing commented Jul 27, 2026

Copy link
Copy Markdown

Related Issue

Resolve #2250

Problem

See linked issue. In short: with the experimental secondary-model feature, spawned subagents can bind to a single [secondary_model] slot, but one alternate slot is not enough — routine search/formatting wants a cheap fast model, architecture review wants the highest-quality one, and the main agent has no information to choose by task.

What changed

  • [subagent_models.<slot>] config section (agent-core-v2, session/subagent domain): each named slot carries a base model, a description, recommended_for tags, an optional default marker, and optional per-slot model patch fields (same shape as [models.*.overrides]). Slot names are validated (^[a-zA-Z][a-zA-Z0-9_]*$, primary and __-prefixed names rejected).
  • Tool surface: Agent and AgentSwarm expose the slot names dynamically as the model parameter enum (plus primary), and their descriptions list every slot's model, description, and recommended uses, so the calling model can choose per task. Selection priority: explicit tool-call model > profile model_preference > the slot marked default > the first slot. With no named slots the legacy [secondary_model] keeps working as a single secondary slot; with neither, subagents inherit the caller's model. Resumed subagents always keep their recorded model.
  • Runtime-only derived models: patched slots synthesize __sm__<slot> entries through a derived-phase config overlay. They never persist to config.toml (runtime-only provenance marks plus a recipe-echo strip guard), never surface in GET /api/v1/models (mirroring the __secondary__ hiding from feat(kap-server): accept secondary_model in the config API #2228), and never override a user-defined [models.__sm__*] entry — a collision warns once per session, tool metadata degrades gracefully, and spawning on that slot fails closed.
  • Config layering: ConfigService overlays now carry a phase (environment / derived) so derived overlays always run after env bindings and Memory-layer input; overlay failures land in diagnostics without breaking other domains.
  • Gating: everything sits behind the existing KIMI_CODE_EXPERIMENTAL_SECONDARY_MODEL flag; behavior with the flag off is unchanged, and the interactive TUI is unaffected (same surface support as the current secondary-model experiment: kimi web and experimental kimi -p).
  • Tests: ~90 new tests across the config layer (slot schema, TOML read/write, derived overlay persistence stripping, collision handling), the tool layer (enum/description surfacing, binding priority, fail-closed spawn), the warning service, and the kap-server model-catalog filtering.
  • Docs: bilingual user docs updated (docs/en + docs/zh: config-files, agents, tools) alongside the config manifest.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset. (A patch changeset is included, worded to note the experimental flag and effective surfaces — following the precedent of feat: support a configurable secondary model for subagents #2064, which introduced the secondary-model experiment with a patch entry.)
  • Ran gen-docs skill, or this PR needs no doc update. (Bilingual docs updated in this PR.)

…del selection

Add a [subagent_models.<slot>] config section: each named slot carries a base
model, description, recommended_for tags, an optional default marker, and
optional model patch fields. The Agent and AgentSwarm tools expose the slot
names dynamically in their model parameter enum and describe every slot to the
calling model, so the main agent can pick a subagent model by task fit and
cost. Explicit tool-call choice > profile model_preference > default slot >
first slot; the legacy [secondary_model] single slot remains the fallback when
no named slots exist, and resumed subagents keep their recorded model.

Patched slots synthesize runtime-only derived model entries (__sm__<slot>)
through a derived-phase config overlay that also covers Memory-layer recipes.
Derived entries never persist to config.toml (identity provenance marks plus a
recipe-echo strip guard), never surface in /api/v1/models, and never override
a user-defined [models.__sm__*] entry — collisions warn once per session,
degrade tool metadata gracefully, and fail closed at spawn. Gated behind the
existing secondary-model experimental flag.
@changeset-bot

changeset-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 880c0fd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 880c0fd432

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

): AgentFileDefinition['modelPreference'] {
if (value === undefined || value === null) return undefined;
if (value === 'primary' || value === 'secondary') return value;
if (typeof value === 'string' && value.trim().length > 0) return value.trim();

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 model preferences that cannot name a slot

When an agent file uses a value such as model_preference: fast-model or one containing internal whitespace, this parser now accepts it even though [subagent_models] only permits names matching ^[a-zA-Z][a-zA-Z0-9_]*$. If Agent or AgentSwarm later spawns that profile without an explicit model, resolveSubagentBinding always rejects the impossible preference as an unknown slot instead of the invalid agent file being skipped (or rejected when passed explicitly). Validate preferences against the slot-name grammar while retaining the supported primary and legacy secondary values.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: named subagent model slots ([subagent_models]) so the main agent can choose subagent models by task

1 participant