Commit graph

818 commits

Author SHA1 Message Date
github-actions[bot]
53c832dfdf
ci: release packages (#2592)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-05 16:21:32 +08:00
qer
2b3e9a9f79
fix(tui): clarify curated plugin marketplace (#2635) 2026-08-05 16:18:50 +08:00
liruifengv
7a631522fb
chore(changeset): trim the v2 engine entry and drop the custom identity entry (#2634) 2026-08-05 16:08:42 +08:00
liruifengv
3bd098b806
chore(changeset): add changesets for the v2 TUI and web UI updates (#2630) 2026-08-05 15:27:27 +08:00
qer
75fe068a01
fix(cli): stabilize built-in capability installation (#2601)
* fix(cli): show built-in capabilities before the first session exists

The lazy-session refactor left capability calls going through
requireSession(), so on a session-less v2 startup /plugins reported the
capabilities unavailable and hid the built-in rows behind the promo.
Like plugin management, capability readiness and installs are app-global
on the v2 engine: the node-sdk harness gains a capability facade over
the global channel, and the TUI resolves session-or-harness for every
capability call.

* fix(cli): count the dev marketplace server as the default catalog

dev.mjs always points KIMI_CODE_PLUGIN_MARKETPLACE_URL at its own
repo-serving server, which the override gate mistook for a user-configured
marketplace and suppressed the built-in capability rows in every dev run.
The dev server now marks itself, and the gate treats that marked URL as
the default catalog while still honoring real overrides (slash-command
source, user-set env, KIMI_CODE_DEV_MARKETPLACE_URL).

* fix(cli): align built-in capability updates
2026-08-05 14:55:04 +08:00
Haozhe
f881cdd970
feat(cli): default CLI surfaces to the agent-core-v2 engine (#2627)
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
* feat(cli): default to agent-core-v2 engine with KIMI_CODE_LEGACY_FLAG opt-out

- invert the engine gate: isKimiV2Enabled() now returns true unless
  KIMI_CODE_LEGACY_FLAG is truthy; KIMI_CODE_EXPERIMENTAL_FLAG no longer
  selects the engine
- replace the experimental `kimi acp-v2` command with the native v2
  implementation as the default `kimi acp`; the legacy acp-adapter path
  remains under the legacy flag
- drop the acp-v2 experimental flag from the registry
- rename the dev:cli:v2 script to dev:cli:legacy
- update en/zh docs for the new default engine and the legacy flag

* feat(cli): route export and provider through the engine gate

- select the harness via isKimiV2Enabled(): agent-core-v2 by default,
  the legacy harness when KIMI_CODE_LEGACY_FLAG is truthy
- close the harness after each one-shot command so the v2 engine's
  watchers do not keep the process alive
- document both commands in the KIMI_CODE_LEGACY_FLAG env-var entry
2026-08-05 14:42:23 +08:00
7Sageer
e3570280bd
fix(agent-core-v2): bound the project skill-root watch fd footprint (#2612)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(agent-core-v2): bound the project skill-root watch fd footprint

The workspace skill-root source recursively watches the skill-root
candidates with chokidar, which holds one fs.watch fd per file and per
directory on macOS. A skill bundling a large runtime tree can exhaust
the process fd budget and break every subsequent spawn (EBADF).

Mirror the scanner's own pruning (node_modules / dot entries, scan
depth cap) in the watch filter, and add a signal mode to hostFsWatch:
rescan-style consumers get ONE native recursive fs.watch on
darwin/win32, whose fd footprint is constant in the subtree size.

* fix(agent-core-v2): align the skill watch with scanner semantics and harden signal mode

Review follow-up:

- The scanner probes every entry's direct SKILL.md before gating
  recursion, so the watch filter now keeps an excluded entry itself and
  its direct SKILL.md (keepEntryFile) instead of pruning them — skills
  under node_modules / dot directories keep their hot reload.
- The signal-mode native leg now owns its recovery: a native watch
  error fires one root invalidation and re-arms with capped exponential
  backoff; chokidar is used only where recursive fs.watch is
  unavailable, so a transient failure can neither silently end hot
  reload nor downgrade to the per-node watcher.
- Native event path resolution handles absolute filenames and the
  root-basename case, clamping out-of-root events to a root
  invalidation instead of dropping them.
- The event mapping is extracted into NativeSignalMapper with the stat
  call injected, so the native-branch decisions are unit-tested on any
  platform.

* Fix spawn EBADF issue on macOS for large file trees

The skill watcher no longer opens every file it watches, improving performance.

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* fix(agent-core-v2): harden native signal watch recovery

* fix(agent-core-v2): align skill watch with scanner traversal

* fix(agent-core-v2): make skill watch handoff converge

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>
2026-08-05 13:47:26 +08:00
liruifengv
541ddd2d89
chore(web): replace apps/kimi-web with the code-app web bundle (#2599)
* chore(web): remove apps/kimi-web in favor of the code-app web bundle

The web UI source now lives in the code-app repo (apps/web); this repo
only ships the prebuilt bundle at apps/kimi-code/dist-web, synced from
code-app via \.

- delete apps/kimi-web (source, tests, docs)
- root package.json: drop dev:web and the kimi-web typecheck leg
- apps/kimi-code: drop the workspace dep and the build-from-source step;
  replace copy-web-assets.mjs with check-web-assets.mjs so packaging
  fails fast when the committed bundle is missing
- CI: _native-build verifies the committed bundle instead of building
  from source; ci.yml and pkg-pr-new.yml drop the kimi-web legs
- docs: AGENTS.md project map, changeset README, gen-changesets and
  sync-changelog skills now key web UI entries on dist-web

* chore(web): stop ignoring dist-web now that the bundle is committed

The ignore entry predates the code-app sync flow, when dist-web was a
local build artifact. The bundle is now the canonical, committed form of
the web UI, so ignoring it only forces every sync to git add -f.

* docs(skills): drop the web-specific changeset and changelog rules

The web: prefix convention and the web-specific dedup guidance belonged
to the in-repo web app. With the source moved to code-app, web UI
changes follow the same generic rules as any other CLI-bundle change.

* chore(web): add changesets for the web UI changes in the bundle

* chore(web): collapse the bundle changesets into one umbrella entry

* ci: unbreak nix and lint after the kimi-web removal

- flake.nix: drop apps/kimi-web from the source fileset and package
  lists, and verify the committed dist-web in the native build phase
  instead of building the web app from source
- .oxlintrc.json: exclude dist-web (a committed build artifact) now
  that .gitignore no longer hides it from the linter

* ci(nix): update pnpmDeps hash for the post-kimi-web lockfile

* chore(web): resync dist-web from code-app main

Bundle rebuilt from code-app main (upstream parity ports #175, pinned
sidebar #176) with the CLI version 0.32.0 embedded.
2026-08-05 13:38:30 +08:00
zy
2ee6e43124
fix(mcp): re-register the OAuth client when its redirect URI no longer matches (#2620)
The callback listener binds a random port per flow, while DCR
registration records the redirect URI of the flow that created it —
so every interactive authorization after the first was rejected with
"Invalid redirect URI", an error rendered only in the user's browser
while the client waited for a callback that never came. Detect the
mismatch before invoking auth() and drop the stale registration so the
flow re-registers with the current callback URI (v1 + v2).

Resolve #2606

Co-authored-by: zouying <zouying@moonshot.cn>
2026-08-05 10:24:24 +08:00
Kai
8db7d42f23
feat(tui): add /bug as an alias for /feedback (#2614)
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
2026-08-04 23:54:21 +08:00
Kai
98ee35afd2
feat(agent-core-v2): add custom agent identity (#2573)
* refactor(agent-core-v2): simplify context tags and shared copy

Rename the context-injection tags to `<skill-loaded>` and
`<plugin-instructions>`, drop the product prefix from the CronCreate tool
description and the default agent description, and point the MCP OAuth
callback page back to "your terminal" instead of naming one client.

The callback page is shared by the ACP host, the web UI, and embedding
hosts, so naming a single client was inaccurate there. The tags and the
two descriptions read exactly the same without the prefix. Verified no
runtime consumer matches the old tag names; the updated snapshots cover
the tool descriptions that changed.

* feat(agent-core-v2): add a switch for the product-documentation skills

Five builtin skills document this CLI itself — `update-config`,
`custom-theme`, `mcp-config`, `check-kimi-code-docs`, and
`import-from-cc-codex`. Their names and descriptions sit in the system
prompt on every turn, which is dead weight for runs that will never
reconfigure the CLI.

Add a top-level `builtin_product_skills` field (also settable through
`KIMI_CODE_BUILTIN_PRODUCT_SKILLS`) to drop them. On by default, so
nothing changes unless it is set; the trade when off is that the model
loses the guided flows for those tasks.

Filtering happens where the catalog is assembled — a later filter would
leave the skills advertised to the model. The whole section is one
scalar, so it exercises the section-level env binding branch and needs
its own strip: `stripEnvBoundFields` only walks object fields, so an env
override would otherwise be written back into `config.toml`.

* feat(agent-core-v2): add custom agent identity

Add an `[identity]` config section (`name`, optional `slug`, both also
settable through `KIMI_CODE_IDENTITY_NAME` / `KIMI_CODE_IDENTITY_SLUG`)
that sets the identity the agent presents: the name it calls itself in
the system prompt, the `User-Agent` product token sent to third-party
providers, and the client name announced to MCP servers. Leaving it
unset changes nothing.

Until now every one of these was fixed, which left no way to run the
agent as part of another product — an internal deployment, a fork with
its own branding, an embedding host.

The identity resolves inside the engine rather than being seeded by each
host, so it applies to every launch surface — including headless runs,
which today seed no display name at all and fall through to the built-in
default.

Two deliberate asymmetries:

- The display name is a filling value with a fallback chain (config >
  host-declared > the consumer's own default); the slug is a rewriting
  value with two states only, so with no identity configured the
  rewriting paths are equivalent to not existing.
- The rewrite happens in the outbound header assembly, the one layer
  that knows which vendor it is building for. Vendors declaring
  `hostHeaders: 'full'` keep the host's own product token, which that
  header set is built around and which backends key on; the configured
  identity applies to the third-party path.

Resolution is lazy throughout: config loads asynchronously, and a
constructor snapshot would freeze the pre-load value under some startup
orderings.

Two input edges the resolver has to absorb, since both would otherwise
reach the User-Agent builder and either break it or quietly rewrite the
header: blank and whitespace-only values read as unset in the file just
as they already did in the env, so a stray `name = ""` cannot claim an
identity; and a name that folds away to nothing under slug
normalization (a CJK-only name, say) falls back to a neutral token
rather than producing a blank product, which the builder rejects.

* fix(agent-core-v2): keep the file value when a scalar env binding fails to parse

`config.ts` documents that an env value failing its binding's `parse` is
ignored, and `applyEnvBindings` honors that for object fields by
assigning only when the resolved value is defined. `applySectionEnv`
returned the parse result straight through for whole-section scalar
bindings, so a blank or mistyped variable resolved to `undefined` and
cleared the configured file value instead of being ignored.

Nothing hit this before: every existing section either binds object
fields or is env-only. `builtin_product_skills` is the first
whole-section scalar binding, where exporting an empty or misspelled
`KIMI_CODE_BUILTIN_PRODUCT_SKILLS` would silently undo a configured
`false`.

* feat(agent-core-v2): extend the custom identity to discovery and global MCP

Two outbound paths still announced the built-in product name under a
configured identity:

- `DiscoveryService` read the host User-Agent straight from bootstrap
  args when refreshing provider models, so custom registries — which are
  third-party endpoints — saw the original token while chat requests to
  the same class of endpoint saw the configured one.
- `SDKRpcClientV2` builds its own global `McpOAuthService` plus a
  throwaway `McpConnectionManager` for server testing, neither of which
  goes through the workspace-owned manager that carries the resolver.

Both now resolve the identity from the App scope.

* refactor(agent-core-v2): neutralize remaining copy and align comments

The synthetic MCP authentication tool description is injected into the
model context and still named the product; it and the OAuth callback
pages now use client-neutral wording. "Return to your terminal" was no
improvement over naming a client — both assume what the host is, and
that page serves the ACP host, the web UI and embedding hosts alike.

Comments introduced by the identity work move into their module headers,
per the domain convention. Interface field docs stay: the rule names
functions, methods and statements, and field-level docs are established
across the codebase.

The new tests gain scenario headers and dispose the scoped hosts they
create, and the `[identity]` docs state which engine reads the section.

* fix(agent-core-v2): read the product-skill switch after config is ready

`BuiltinSkillSource` is the lowest-priority skill source, so the workspace
catalog loads it first — before `IConfigService` has finished loading — and
keeps the contribution it returns for the life of the handler, with no
reload path and no change event. Reading `builtin_product_skills` eagerly
therefore stranded the startup configuration: an explicit `false` could be
ignored for the whole process. `UserFileSkillSource` already awaits config
readiness for exactly this ordering; this source now does the same.

Also record the identity collaborator in the two module headers that gained
the dependency without documenting it, and scope the
`builtin_product_skills` docs to the engine that reads it, matching the
note the identity section already carries.

* fix(agent-core-v2): apply the product-skill switch to session-less listings

`builtin_product_skills = false` only reached the scoped skill source. The
SDK's `listWorkspaceSkills` and the server's `GET /workspaces/{id}/skills`
both composed the raw `BUILTIN_SKILLS` constant, and the web app feeds its
pre-session onboarding menu from that route — so the five product skills
stayed listed until a session existed, then vanished from the session's
catalog.

Move the decision into `visibleBuiltinSkills(enabled)` next to the constant
and route every consumer through it, reading the switch via the shared
`builtinProductSkillsEnabled`. Keeping "what counts as a product skill" in
one place is the point: three copies of the predicate would drift the next
time a builtin is added. The SDK listing also awaits config readiness,
which it did not do before.

* fix(node-sdk): await config before materializing the global MCP OAuth provider

`McpOAuthService` caches providers by store key and stamps the client name
when it first builds one, and the preceding `globalMcpConfig.get()` reads
`mcp.json` directly rather than through `IConfigService`. So a
`beginGlobalMcpServerAuth` call made right after the harness is created
could resolve the identity before config finished loading, pinning the
built-in label for the rest of the process — including the OAuth dynamic
registration a third-party MCP server records.

`testGlobalMcpServer` already awaited config readiness for its own reasons;
this path now does too.

* refactor(agent-core-v2): drop the unused builtin-skill registrar

`registerBuiltinSkills` stamped the raw constant into a catalog for "edge
composition without a Session" — exactly the shape that now has to respect
`builtin_product_skills`. It has no callers in v2 and is not exported from
the package index, so it was dead code that also stood as an invitation to
bypass the switch. v1 keeps its own copy.

Every remaining path composes builtins through `visibleBuiltinSkills`.

* fix(agent-core-v2): send the configured identity on custom-registry imports

`:import_registry` fetched a user-supplied third-party URL with a
hardcoded `kimi-code-kap-server` User-Agent, so the first request to a
registry announced the product while every scheduled refresh of the same
registry announced the configured identity. The hardcoded value was wrong
on its own terms too: that token names the server, and this path also runs
in the CLI.

Both services now project the identity through `identityUserAgent`, which
carries the two guards (no host header, or no identity) once instead of
per caller. The model catalog keeps an inline copy on purpose — kosong is
a foundational layer and must not import an app domain.

Sweeping the remaining outbound User-Agent sources found no further gaps:
WebFetch deliberately sends a Chrome-like UA, the models.dev catalog fetch
sends none from the CLI, and kap-server's `user-agent` reads are inbound.

* docs: scope the identity env vars and condense the changeset

The environment-variable reference advertised all three new variables
without noting that only the agent-core-v2 engine reads them; the
configuration page already carried that note. Added in both locales.

The changeset had grown into two paragraphs of implementation detail,
which is what would land in the CLI release changelog. `gen-changesets`
asks for one short sentence plus at most a one-line usage hint.

* docs(agent-core-v2): describe the identity as what the agent calls itself

The module headers had drifted into describing the feature by what it
keeps off the wire rather than what it configures. Reworded so they state
the capability: the identity is the name the agent uses for itself, and
the unset case is a no-op rather than something "safe". The product-skill
switch excludes skills rather than hiding them.

Wording only; behavior and structure unchanged.

* test(agent-core-v2): cover the identity on custom-registry imports

The import path switched from a hardcoded `kimi-code-kap-server` token to
the host User-Agent projected through the identity, but nothing asserted
it. Two cases pin both halves: a configured identity reaches the request,
and an unconfigured one leaves the host header intact — the second matters
because a single case would also pass if one hardcoded value had simply
replaced another.

Both fail against the previous implementation.

* fix(node-sdk): guard every global MCP OAuth path behind config readiness

`McpOAuthService` caches providers by store key and stamps the client name
when it first builds one, so any path that can materialize a provider has
to run after config has loaded. `beginGlobalMcpServerAuth` awaited
readiness, but `resetGlobalMcpServerAuth` reaches the same cache through
`invalidate()` -> `getProvider()` without waiting: resetting auth right
after the harness is constructed pinned the built-in client name, and the
await added to the begin path could not help because it then reused that
cached provider.

Rather than add the missing await, the accessor is now async and holds the
guard itself, so the service cannot be obtained before config is ready and
a future entry point cannot forget. The remaining `configReady` in
`testGlobalMcpServer` stays — that one is for its own `[mcp]` section read.

* fix(agent-core-v2): send the configured identity on models.dev requests

The directory fetch behind `listModelsDevProviders` / `getModelsDevProvider`
still hardcoded a `kimi-code-kap-server` User-Agent, so browsing or importing
from models.dev announced the built-in product — and claimed to be the server
even when running in the CLI. Only the custom-registry import had been fixed.

`getModelsDevCatalog` now takes the User-Agent from its caller: the module is
plain module-level state with no container access, and the value depends on
the host and the configured identity, which only the calling service can see.
All four third-party fetches in that service share one helper.

Where the host states no User-Agent, a neutral token stands in rather than
dropping the header — these are directories the service chooses to call, so
there is no host intent to preserve, unlike the provider requests the model
catalog assembles.

Both new tests fail against the previous hardcoded value.

* test(agent-core-v2): assert the product-skill set literally

The expected sets were derived from the same `productSpecific` field the
production filter reads, so a builtin silently losing its marker would just
move between sets and leave every assertion green — while staying visible to
the model once the switch is off. The five names are now literal, with a test
asserting the marked set matches them exactly.

Dropping the marker from one skill now fails four tests instead of none.

Also states the App scope in the identity contract header, per the domain's
comment convention for contract files.

* fix(agent-core-v2): normalize the host-declared display name too

Blank and padded values were normalized on the config side but not on the
host fallback, so an embedding host passing `displayName: "   "` rendered
"You are   ," into the system prompt, and a padded name kept its padding.
Same rule now applies to every source of the name.

Also names `agentIdentity` as the collaborator in the request-headers
adapter header, which described the value it obtains without saying which
domain resolves it.

The three new cases fail against the previous implementation.

* fix(agent-core-v2): keep the configured slug when the host sends no User-Agent

The neutral fallback added for hosts that state no `User-Agent` discarded a
configured identity along with it: `identityUserAgent` returns `undefined`
as soon as there is no host header to rewrite, so `?? DEFAULT_IDENTITY_SLUG`
sent the literal `agent` even when `[identity].slug` was set — precisely the
case that fallback exists to serve. The configured slug now stands on its
own, with the neutral token reserved for having neither.

The four combinations of (host header, configured slug) had three tests; the
missing one is the one that was wrong. It now fails without this change.

`outboundUserAgent` also awaits config readiness before reading the identity,
so a browse issued right after bootstrap cannot send the pre-load value — the
guard lives in the accessor rather than at its four call sites, matching how
the same race is handled elsewhere in this branch.

Both headers here and in `discoveryService` now name `agentIdentity` as the
collaborator resolving that token.

* test(acp-server): follow the renamed skill-activation tag

`acp-server` arrived on main after the tag rename, so its two assertions
still expected `kimi-skill-loaded` and failed once the branches met. Also
updates the web app's CSS comment, which named the old tag from the start
of this branch — a comment, so nothing ever failed on it.

Found by CI: the merge verification only ran agent-core-v2's suite, and
this package is neither a dependency nor a dependent of it.

* fix(agent-core-v2): present the configured slug on registry refreshes too

The previous round taught the import path to fall back to the configured
slug when the host states no `User-Agent`, but left the scheduled refresh
of the same registry on the bare projection — so one registry could see
`acme` on import and the runtime default on refresh.

Extracting `identityUserAgent` had made the two paths share a function
without sharing the policy. The choice itself is now the shared piece:
`identityUserAgentOrDefault` always yields a value, for the directories
this process chooses to call, while `identityUserAgent` stays the form
that rewrites only what the host already sends — what a provider request
needs, where the host's silence is its own choice.

* docs(agent-core-v2): move new member docs into the module headers

The domain's comment convention is absolute — comments live solely in the
top-of-file block — and I had read the "functions, methods, or statements"
clause as leaving interface members out. It does not: only 25 of 734 v2
sources carry an indented block, so the members I documented were the
exception, not the pattern.

Seven members across six files move into their headers. `types.ts` had no
header at all, so it gains one.

* fix(agent-core-v2): connect session MCP overlays after config is ready

The shared manager reaches `connectAll` through `initialize()`, which awaits
the config domain first; `sessionOverlay` called it straight away. A session
carrying ephemeral `mcpServers` created right after bootstrap therefore
resolved the client name before config had loaded and initialized under the
built-in one.

The blast radius is wider than that one connection: a remote server sends
the overlay through `hasTokens()`, which materializes an OAuth provider on
the *shared* service and caches it by store key — so the early name outlives
the connection that raced. The overlay now connects behind `mcpConfig.ready`,
leaving the returned readiness promise unchanged.

* fix(agent-core-v2): reload builtin skills when their switch changes

The workspace catalog keeps each source's contribution for the life of the
handler, so a `builtin_product_skills` toggle never reached an existing
handler's sessions. That was harmless while every surface read the same
constant — but routing the session-less listings through the config made the
two views disagree, since those read the switch on every call.

Follows `ExtraFileSkillSource`: subscribe to the owning section and fire
`onDidChange`, which the catalog already turns into a source reload. The
test asserts an unrelated section does not trigger it.

* fix(agent-core-v2): apply the identity to self-configured web services

`[services.moonshot_search]` and `[services.moonshot_fetch]` name their own
`base_url`, so both services can point at an endpoint the user chose — but
each forwarded the host request headers verbatim, sending the built-in
product token there under a configured identity.

Only the services-config path is rewritten; the managed OAuth path keeps the
host headers as they are, being the endpoint the session authenticated
against. The distinction is the same one the model catalog draws per vendor.

`identityHeaders` carries the rewrite across a whole header set, so this is
the fourth caller sharing the projection rather than repeating its guards.
A pair of tests pins both halves.

My earlier sweep classified these two as official by their names instead of
asking who chooses the URL, which is why they were missed. The contract
header is also condensed here, per the convention below.

* docs(agent-core-v2): condense the identity headers to their contracts

The comment convention is one sentence with two halves — comments live only
in the top-of-file block, *and* that block states the module's role without
narrating implementation. Moving the member docs up last round satisfied the
first and broke the second: the headers ended up spelling out the slug
folding algorithm, the strip mechanics, and the load order.

Kept what a caller or the next editor would get wrong without it (why the
value is read rather than snapshotted, what `undefined` obliges a consumer
to do, why this source waits for config). Dropped what the code already
says. 22/12/12/13 lines, against 53 in `catalogService.ts` — length was
never the problem.

* fix(agent-core-v2): rebuild active prompts when the builtin skills change

Reloading the catalog on a `builtin_product_skills` toggle left existing
agents holding the old listing: `AgentProfileService` refreshes the prompt
only for the plugin source, so a disabled switch kept advertising skills
that were gone, and enabling it left them missing until an unrelated
refresh.

The plugin source is special because it also contributes prompt sections
(#2314), and the file-backed sources are left out for cost — their fs
watches would rebuild every agent's prompt on each edit. The builtin source
has no watch: it changes only when its config switch is toggled, so it
belongs with the plugin source rather than with the file ones.

Subscribing to the catalog rather than the config section is load-bearing.
The catalog fires after the contribution is replaced, whereas a config
subscription would race the reload, and `resolveSkillListing` only awaits
the catalog's *initial* readiness — so the rebuilt prompt could read the
listing it was meant to replace.

The source id is a named constant now, so the subscription does not match
on a bare string.

* refactor(agent-core-v2): freeze the agent identity for the process lifetime

The identity is announced outward (MCP initialize, OAuth registration,
provider request logs) and cannot be re-announced, so mid-process changes
could only ever apply partially. Resolve it once when config first loads
and hold it for the life of the process: IAgentIdentity now hands out a
frozen snapshot via resolved()/current(), carrying finished products
(outbound User-Agent variants, rewritten header set) so call sites stop
composing host headers with the slug themselves. The kosong host-headers
port carries two finished layers and the catalog only picks one; consumers
gain no invalidation obligations because the value can never change after
the freeze. [identity] edits take effect on the next start (documented).

* fix(agent-core-v2): locate the User-Agent header case-insensitively

HTTP header names are case-insensitive, but the snapshot builder looked up
'User-Agent' by exact key: an embedding host spelling it 'user-agent' got no
third-party UA and kept its own product token on the services path even with
an identity configured. The builder now locates every case variant and
rewrites each in place, keeping the host's spelling. Also corrects the two
web-service headers that still described both paths as sending the bootstrap
headers, naming agentIdentity as the collaborator behind the config path,
and documents that a resumed session keeps its recorded system prompt.

* fix(agent-core-v2): attribute header provenance from the finished third-party layer

Inspection reconstructed the non-full host layer from the raw headers with an
exact-case 'User-Agent' lookup, so a host spelling the header 'user-agent'
got a resolved User-Agent with no provenance entry even though the runtime
sends the rewritten value. buildModel now captures the port's finished
third-party layer in the trace and attribution reads it, keeping inspect()
on the same resolution pass as get(). Also condenses the identity contract
header to its external role, and documents that an existing MCP OAuth
authorization keeps the client registration it was granted under (reset the
server's auth to register under the new identity).

* fix(agent-core-v2): keep web tool backends from racing the identity freeze

An env-configured [services] endpoint is visible before config finishes
loading, and FetchURLTool / WebSearchTool materialized their backends at
construction — so a fast bootstrap could hit the identity snapshot's
pre-freeze guard during agent creation, and the composed backend pinned
config and login state for the agent's lifetime against the service's
documented per-call resolution. Both tools now resolve their backend per
invocation, the WebSearch activation gate checks presence alone through the
new hasWebSearchProvider() (no provider composition, no identity read), and
bind() awaits the identity freeze before materializing the model, whose
resolution reads the identity through the host-headers port.
2026-08-04 22:35:15 +08:00
zy
c32e661faa
fix(mcp): pass structuredContent and _meta through to model-visible tool output (#2596)
MCP tool results were narrowed to {content, isError}, dropping the
spec-defined structuredContent field and _meta metadata. Servers that
return structured contracts in these fields (validated against
outputSchema, or namespaced metadata such as browser-handoff payloads)
were invisible to the agent. Surface them as a serialized
<mcp-structured-result> block appended to the tool output, still subject
to the existing text budget.

Co-authored-by: zouying <zouying@moonshot.cn>
2026-08-04 18:01:42 +08:00
qer
0abcd00f7f
feat(cli): add built-in Computer Use and WebBridge capabilities (#2407)
* feat(agent-core-v2): add built-in capabilities (kimi-cu, kimi-webbridge) with REST routes

Add a capability domain holding a closed registry of built-in product
capabilities. Each entry owns layered readiness detection and idempotent
install orchestration: binary runtimes from fixed official CDN URLs
(KimiCU.app + launchd service + TCC permission state; the WebBridge
daemon with start-if-down semantics for Kimi Work coexistence) plus
agent wiring through the plugin service. The WebBridge wiring un-shadows
stale user-source skill copies (user priority beats plugin priority).

kap-server exposes the domain as GET /api/v1/capabilities,
GET /api/v1/capabilities/{id}, and POST /api/v1/capabilities/{id}:install
with client-polled progress and new wire codes 40418 / 40922 / 40923.

The plugin marketplace gains an official kimi-webbridge entry
(browser-control skills) packaged by the existing CDN build.

* fix(agent-core-v2): rename the webbridge wiring plugin to kimi-webbridge-skill

An official kimi-webbridge guide plugin (install/remove setup skills,
v3.0.4) already exists at the marketplace path the capability installer
pointed at — a different artifact owned by another release line. Give
the browser-control usage-skill plugin its own id/path instead of
colliding with (or overwriting) the guide plugin. The capability entry's
detect/install now tracks kimi-webbridge-skill; a machine with only the
guide plugin correctly reports the skill layer as missing.

* feat(agent-core-v2): shelf installs auto-complete capability binary layers

Two changes to make the plugin marketplace a first-class install path:

- Marketplace gains kimi-cu (sourced from the CU team's CDN zip — no
  repackaging) and the kimi-webbridge usage-skill plugin now claims the
  kimi-webbridge id at v4.0.0, deliberately superseding the WebBridge
  guide plugin (v3.0.4, install/remove guide skills): guide users get a
  version upgrade onto the real usage skill.
- The capability service subscribes to IPluginService.onDidReload: when
  a capability's wiring step flips to ok through ANY install path
  (shelf, TUI, CLI), it auto-completes the missing binary layers
  (KimiCU.app + service, or the WebBridge daemon). Triggers only on the
  false→true edge so completed installs with still-missing manual steps
  (TCC permissions) never retrigger heavy downloads on later reloads.

* fix(plugins): keep kimi-webbridge plugin version aligned with the upstream skill

The plugin version tracks the bundled official usage skill (1.11.3) so
version drift against the WebBridge release line stays visible, instead
of minting an independent 4.0.0.

* fix(agent-core-v2): never report the webbridge installer-script version as the product version

The on-disk ~/.kimi-webbridge/bin/kimi-webbridge.version file tracks the
installer's own lineage (3.1.x, bumps on every install/upgrade run),
not the product version (v1.11.3 — daemon, extension, and skills all
share it). A downed daemon would have shown the misleading installer
number; report no version instead (live /status remains the source of
truth).

* chore(plugins): list kimi-cu on the marketplace without a pinned version

Marketplace versions are optional by schema: rows display the version
detected from the installed plugin's manifest, and update prompts only
fire on a valid semver latest > local comparison. A hand-maintained
number would drift just like the guide plugin's did. The locally built
kimi-webbridge entry keeps its manifest-stamped version (1.11.3).

* fix(agent-core-v2): fire onDidReload on plugin mutations, not just explicit reload

installPlugin / setPluginEnabled / removePlugin changed the catalog
silently — consumers listening to onDidReload (session skill-catalog
convergence, the capability shelf-install hook) only converged on an
explicit reloadPlugins(). Fire the same summary-shaped event on every
mutation (added:[id] / [] / removed:[id]) so every install path
converges. This also unbreaks the shelf-install hook on real hosts:
its unit tests passed against a fake emitter that fired on installs,
which the real service never did.

* feat(kap-server): add plugin management and marketplace REST routes

Expose the App-scope plugin service over the wire so non-CLI hosts
(desktop, web) can manage plugins end to end:

- GET  /api/v1/plugins/marketplace — catalog (pluginMarketplaceUrl
  server option / KIMI_CODE_PLUGIN_MARKETPLACE_URL env / production
  default) merged on demand with live install state; updateAvailable
  only on strict semver catalog > installed (no semver dependency)
- GET  /api/v1/plugins, POST /api/v1/plugins {source}
- POST /api/v1/plugins/{id}:{enable,disable,remove}
- New wire code 40419 plugin.not_found

Mutations flow through IPluginService, so they serialize with other
install paths and fire onDidReload (session skill catalogs and the
capability shelf-install hook converge).

* feat(agent-core-v2): surface a machine-key note from capability installs

CapabilityEntry.install now resolves an optional note exposed through
CapabilityInstallProgress.note (wire-visible). The webbridge entry
returns 'user-skill-migrated' when it replaces a pre-existing
user-source skill (from the official installer) with the plugin-managed
copy — clients can localize the migration instead of the skill silently
disappearing from the user's directory.

* feat(tui): let the real WebBridge marketplace entry win over the pinned promo

The hardcoded Web Bridge row was built when WebBridge had no plugin
package — it pinned above the Official tab and shadowed any catalog
entry with the same id (open-in-browser only). Now that the marketplace
carries the real kimi-webbridge plugin, flip the precedence: the catalog
entry renders and installs normally, and the pinned promo becomes a
loading/error/legacy-catalog fallback only. Footer counts keep their old
semantics (catalog-only; the promo row is never counted).

* fix(tui): dim the installed state so it stops reading as the install action

Both badges shared a near-identical green-ish treatment in the same
column, making a quiet fact look like a clickable action. States now
recede (installed → textDim) while actions stay loud (install →
primary, update → warning).

* feat(agent-core-v2): converge plugin state across processes sharing a home

Multiple hosts share one KIMI_CODE_HOME (CLI, desktop, other agents), but
each PluginService kept a private in-memory snapshot: a plugin installed
or removed in one process stayed invisible to every other live process
until its next restart — new sessions there kept offering stale plugin
skills/MCP, and the capability shelf hook never saw peer installs.

Watch <home>/plugins for installed.json changes and reloadPlugins
(debounced, echo-suppressed around our own mutations) so all consumers
converge in well under a second: session skill catalogs, plugin MCP
mounts, and the capability shelf-install hook alike.

* fix(agent-core-v2): un-shadow webbridge user skills in BOTH user dirs

kimi-code resolves user-scope skills from two roots (~/.kimi-code/skills
and ~/.agents/skills), both at priority 20 — a stale copy in either
shadows the plugin-managed wiring (priority 5), and also keeps the
capability working after the plugin is removed, which reads as
'uninstall did nothing'. Migrate copies in both dirs during install;
other runtimes' dirs (~/.claude, ~/.codex) remain untouched.

* feat(tui): show live runtime-setup progress for capability installs

Installing a capability plugin (kimi-cu, kimi-webbridge) from the
/plugins shelf kicked off a silent background binary install — the row
flipped to installed while megabytes of runtime downloaded invisibly.
Route capability entries through the capability surface instead: the
panel's inline installing line now mirrors live progress (step +
percent) until the install settles, and the transcript reports
ready / failure-with-retry / still-running accordingly. Capability
removal prints an explicit note that runtime binaries are deliberately
left untouched (the capability keeps working), since that read as
'uninstall did nothing'.

Plumbs the capability service through klient's global facade
('capabilityService' decorator resolves in-process) and the node-sdk
v2 client; Session exposes it with a structural feature-detect so v1
engines fail clearly.

* docs(plugins): keep the kimi-cu marketplace blurb accurate for every client

Only the capability-aware clients auto-install the KimiCU.app runtime;
older builds still get wiring-only (the wrapper's error message then
points at the official setup script). Don't overpromise in the catalog
text every version reads.

* feat(agent-core-v2): install capability wiring from client-bundled plugin copies

The kimi-cu / kimi-webbridge wiring plugins ship inside the client release
instead of the marketplace catalog, binding their visibility to the client
version. Capability installs now resolve the bundled copy (env override,
then npm-layout and source-checkout probes from the module) and install it
as a local path, replacing the two CDN zip URLs. A missing bundle fails the
wiring step with a clear reinstall-or-upgrade message.

* build(cli): bundle the capability wiring plugins into client releases

Vendor the official kimi-cu plugin (v0.5.4, from the CU team's plugin zip)
next to kimi-webbridge under plugins/official, copy both into
apps/kimi-code/bundled-plugins at build time, and ship them in the npm
package (files) and the native SEA blob (a new bundled-plugins asset set
extracted into the native cache at startup, published to the engine via
KIMI_CODE_BUNDLED_PLUGINS_DIR). Desktop points the same variable at its
extraResources copy. The .gitignore build-output entries are anchored so
sources under src/native and test/native stop being silently ignored.

* revert(plugins): remove the kimi-cu and kimi-webbridge marketplace entries

Both capabilities now distribute with the client (bundled wiring), so the
catalog drops back to kimi-datasource / superpowers / vercel-plugin. Older
clients never see the entries; current clients install from the Built-in
section. This also reverts the marketplace blurb commit 0635e99c5.

* feat(tui): add a Built-in capabilities section to the plugins panel

The Official tab now opens with a Built-in section fed by the engine's
capability registry (kimi-cu / kimi-webbridge): per-row install state
(install / finish setup / ready), Enter runs the full capability install
with live progress, and unsupported rows hide (kimi-cu off macOS). The
WebBridge promo fallback only remains for v1 engines — on v2 the real
built-in entry wins. Rows double as the reinstall path: a client upgrade
ships newer wiring, and installing again upserts from the new bundle.

* docs(plugins): document the Built-in section and refresh the capability changeset

* build(nix): stage bundled capability plugins into the SEA build

The native SEA blob now embeds the bundled-plugins asset set, so the nix
derivation needs the plugins tree in its src fileset and the staging step
alongside copy-web-assets before build:native:sea.

* revert: drop the client-bundled wiring distribution

Built-in visibility is simpler to get by injecting the two capability
entries into the marketplace catalog at load time; the wiring plugins
themselves keep installing from their fixed official CDN zips. Removes
the vendored kimi-cu plugin, the bundled-plugins npm/SEA packaging and
flake staging, the engine bundle resolver, and the plugins panel's
Built-in section. Keeps the /agents/ and /native/ gitignore anchors so
sources under src/native and test/native are not silently ignored.

* feat(cli): inject the built-in capability entries into the marketplace catalog

The kimi-cu / kimi-webbridge entries are appended by the client at catalog
load time instead of being served by the remote marketplace.json, binding
their visibility to the client version (older clients never see them). No
version is pinned — reinstalling upserts the wiring — and ids the catalog
already carries always win. In a source checkout the webbridge entry
installs the repo's own plugin copy; packaged builds use the official CDN
zip. This reverts the docs paragraph about the Built-in section, which the
simpler approach makes unnecessary.

* test(tui): select the catalog's own first row in marketplace install tests

The client-injected capability entries suppress the WebBridge promo and
append after the catalog rows, so Kimi Datasource now leads the Official
tab — the extra down-key landed on kimi-cu instead.

* feat(cli): surface the built-in capabilities as client-injected marketplace entries

The kimi-cu / kimi-webbridge entries are injected into the marketplace
catalog by the client (v2 engine, default catalog only) instead of being
served remotely, binding their visibility to the client version; injected
rows mask same-id catalog rows, so what these ids mean stays decided by
the client release — a future official listing only reaches older clients,
whose fix is to upgrade.

The /plugins panel shows capability readiness on the rows (setup
incomplete / installing…), platform-gates kimi-cu to macOS, and Enter
finishes the runtime setup with live progress; v1 keeps the plain plugin
install path and the WebBridge promo fallback.

Capability and plugin calls move from the ad-hoc REST routes onto the
typed klient contract (capabilityService next to pluginService), so the
public REST surface returns to its pre-feature shape. Detection is
presence-only — version pins removed: the current version is always read
live (Info.plist, daemon status, install records), installs are
detect-first and idempotent so an interrupted setup can be retried, and
reinstalling pulls the latest managed artifacts (the passive upgrade
path).

* ci: retrigger checks

* fix(cli): recognize Computer Use CDN plugins as official

* fix(cli): keep built-in entries on catalog outage and isolate detector failures

Two review follow-ups: the client-injected entries no longer disappear when
the marketplace catalog is unreachable (they are not served by it), and a
single capability's failing detect probe degrades to a failed step on that
entry instead of rejecting the whole listCapabilities call.

* refactor(cli): simplify built-in capability integration

* refactor(cli): source built-in catalog rows from the engine and tighten detect probes

The injected marketplace entries are now derived from the engine's
capability registry (listCapabilities) instead of hardcoded client-side
copies — the util only owns the mask/append mechanics, and capability ids
are no longer pinned in the CLI (the remove note resolves them through the
registry too). kimi-cu's detect-path probes (service-status, xpc-ping) get
a 3s timeout — they answer in milliseconds when healthy but run on every
status listing, so a wedged binary must degrade quickly instead of
stalling the panel. Document the Official tab's built-in capability rows
in the plugins guide.

* fix(cli): answer capability id membership without running detectors

listCapabilities() runs every entry's detect probes (seconds on a wedged
binary), so using it to decide whether to print the post-remove hint made
every plugin removal pay a full detection round. The id set is part of the
client/engine contract (mirrored in the klient schema), not product data
that drifts — restore the closed-set check. The injected catalog rows keep
flowing from the registry.

* fix(agent-core-v2): make capability setup recover from disabled, partial, and wedged states

Three review follow-ups on the install path: setup now re-enables the
wiring plugin when a previous disable survived installPlugin's upsert
(detection requires enabled, so it would otherwise strand the capability
at partial); the webbridge daemon-binary step verifies the executable bit
on POSIX, so an install interrupted between rename and chmod re-downloads
instead of failing start with EACCES; and kimi-cu's detect degrades
wedged CLI probes (service-status, xpc-ping) to failed steps instead of
throwing, keeping the detect-first install able to repair the remaining
layers — with the probe timeout injectable for tests.

* fix(agent-core-v2): abort capability downloads whose byte stream stalls

downloadToFile had no inactivity deadline: a CDN connection that stops
producing bytes hung the background install forever, wedging the
capability in a permanent installing state (retries rejected as
in-progress) until the process restarted. An idle watchdog now fails the
download after 30s without a chunk; slow but flowing downloads are
unaffected.

* fix(tui): stop offering capability setup on unsupported platforms

An installed wiring plugin whose capability is unsupported on this
OS/arch (kimi-cu off macOS, webbridge on an unknown arch) was treated
like a partial setup: the Installed tab showed setup incomplete and
Enter routed to installCapability, which the service always rejects.
Setup actions are now gated to actionable states (not_installed /
partial); unsupported renders as a dim fact and Enter opens details.

* fix(agent-core-v2): cover the two remaining install wedge modes

Review follow-ups: the KimiCU app step now requires an executable binary,
so a ditto interrupted mid-copy reads as missing and the next setup
re-copies instead of failing EACCES forever; and downloadToFile's idle
budget now also covers the response-header phase via an AbortSignal on
the fetch itself, so a connection that never completes headers fails the
install (clearing the running state) instead of hanging it.

* fix(tui): render capability rows independently of the catalog fetch

While the marketplace catalog was loading or unreachable, the Official
tab showed only the pinned WebBridge promo — built-in runtime setup was
blocked by an unrelated remote fetch, and Enter opened the browser
instead of installing. Locally-known capability rows (from the engine
registry) now render and install in every catalog state; the promo
remains only as the v1 fallback.

* fix(agent-core-v2): keep KimiCU cleanup timeouts best-effort

stopOldProcesses is documented as || true, but runCommand propagates
timeouts: a wedged old binary made kimi-cu uninstall exceed the command
timeout and the reinstall died before ditto could replace the app.
Cleanup commands now swallow failures (the timeout already attempts a
kill) so the replacement always proceeds; the command timeout is
injectable for tests alongside the probe timeout.

* fix(cli): inject built-in entries only for the default marketplace catalog

Injection is part of the default catalog experience: any explicit
replacement (slash-command source or KIMI_CODE_PLUGIN_MARKETPLACE_URL)
now opts out wholesale — its same-id rows are never masked by the
built-ins, and an unreachable custom catalog surfaces its own failure
instead of being silently replaced by a built-in-only tab.

* refactor: align capability row rendering on the source marker and drop conditional spreads

Marketplace-row capability enrichment (status, badges, issue details,
platform filtering) now keys on the capability:<id> source marker — the
same condition Enter uses to route installs — so a custom catalog row
that merely reuses a built-in id renders and installs as a plain plugin.
Also replaces the conditional-spread optional fields with direct
undefined-valued assignments per the repo coding rules.

* refactor(agent-core-v2): move capability comments to the file headers

The domain's comment convention allows only the top-of-file block:
responsibility and scope context for the recent hardening (detect-first
idempotent install, executability gates, probe-failure degradation,
best-effort cleanup, download watchdog, per-entry detection isolation)
now lives in the module headers, and inline narration beside statements
and members is removed.

* fix(tui): follow an in-progress capability install instead of restarting it

Opening /plugins while a capability setup is already running showed the
installing… row, but Enter called installCapability again and the
service's duplicate-start rejection (40922) surfaced as a fake failure.
The panel now checks the live status first and, when an install is
already running, skips the start call and just polls for the existing
progress.

* fix: align two more replacement paths with their contracts

The EXDEV daemon-binary fallback now stages on the target filesystem and
atomically renames over the destination instead of opening a
possibly-running binary for write (ETXTBSY on Linux). And the panel's
fallback capability rows (catalog loading/error) now follow the same
default-catalog condition as the loader injection, so an explicitly
overridden marketplace fully replaces the Official tab.

* fix(tui): make the built-in row marker unforgeable

The capability:<id> source string was the trust signal for routing rows
into capability installs, but any catalog can write that string — a
custom marketplace could smuggle a row past the third-party trust path
into an official runtime install. Injected rows now carry an internal
builtIn flag that the field-by-field catalog parser never produces;
rendering and install routing key on the flag, and the source string is
purely diagnostic.

* fix(agent-core-v2): include MCP server enablement in capability readiness

A user who disabled the kimi-cu stdio MCP server (/plugins mcp disable)
got a ready capability with no Computer Use tools in new sessions: the
plugin step only checked the plugin toggle, and installPlugin's upsert
preserves per-server state. Readiness now requires every declared MCP
server enabled (reporting e.g. mcp 0/1 enabled), and setup re-enables
disabled servers alongside the plugin toggle.

* fix(agent-core-v2): shell-quote ditto paths in the elevated KimiCU copy

The elevated fallback escaped paths only for the AppleScript string
delimiters, not for the /bin/sh command line inside do shell script: a
TMPDIR with spaces broke the install, and shell metacharacters in the
temp path could inject commands into an administrator-privileged script.
Paths are now POSIX single-quoted first, then the assembled command is
AppleScript-escaped.

* fix(agent-core-v2): never break a working KimiCU on a failed update

The reinstall stopped and uninstalled the old service before the
downloaded archive was unpacked: a corrupt or captive-portal zip then
tore down a previously ready setup. The archive is now staged and
unpacked first, and the app step additionally requires the bundle's
Info.plist, so a partially copied bundle reads as missing and gets
re-copied instead of failing registration against a corrupt bundle.

* fix(agent-core-v2): limit the fetch deadline to the header phase

The 30s AbortSignal stayed attached for the whole request, so a
slow-but-healthy download of a large archive was aborted at 30s total
even while chunks kept arriving — exactly what the per-chunk idle
watchdog was meant to allow. The header phase now uses an
AbortController cleared once headers arrive; the body remains governed
by the inactivity watchdog alone.

* test(tui): provide the harness plugin facade in the capability command fakes

The lazy-session refactor routes session-less plugin calls through
host.harness; the fake host now mirrors that shape.
2026-08-04 17:59:16 +08:00
7Sageer
278b6af19d
fix(agent-core-v2): make MCP initial connect non-blocking during startup (#2586)
* fix(agent-core-v2): make MCP initial connect non-blocking during startup

* Delete .changeset/mcp-nonblocking-startup.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* fix(agent-core-v2): wait for MCP readiness before first turn

* fix(klient): wait for MCP startup before listing

* fix(klient): keep MCP server listing non-blocking

* test(acp-server): allow pending MCP snapshot

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>
2026-08-04 16:47:55 +08:00
7Sageer
54c04bf03d
feat: /fork no longer switches to the forked session (#2565)
* feat: /fork no longer switches to the forked session

Forking used to switch to the new session, which closed the source
session and force-stopped its background tasks (and canceled any
in-flight turn). /fork now creates the copy and stays in the current
session; the fork can be opened explicitly via /sessions.

* fix(tui): release fork runtime when staying current
2026-08-04 15:24:12 +08:00
github-actions[bot]
4ac7240fff
ci: release packages (#2469)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-04 15:11:04 +08:00
qer
6cb615cd37
chore(changeset): downgrade token-counting strategy entry to patch (#2590) 2026-08-04 15:06:54 +08:00
Haozhe
c39687318c
fix(kap-server): accept question ids containing colons on resolve (#2585)
Some checks are pending
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(kap-server): accept question ids containing colons on resolve

Some OpenAI-compatible providers emit tool_call ids like
`AskUserQuestion:0`, which the question service adopts as the question
id. The action-suffix parse then rejected the bare resolve POST as an
unsupported action (40001), so clients could never submit answers.

When the suffix parse fails, fall back to matching the full tail
against the pending question list before emitting 40001. Also add
maxRetries to the test home cleanup to absorb the async query-store
shard flush (ENOTEMPTY on macOS), matching fs.test.ts.

* fix(kap-server): preserve 40902 on duplicate resolve of colon-id questions

A retried bare resolve of a colon-bearing question id re-entered the
invalid-suffix fallback after the question settled, found no pending
match, and returned 40001 — bypassing the recently-resolved idempotency
window. Accept the tail in the fallback when it is recently resolved so
the shared duplicate-resolve path emits 40902 as documented.
2026-08-04 12:58:51 +08:00
Haozhe
21185447fe
feat(agent-core-v2): add tokenCounting service with strategy config and measured anchors (#2563)
* feat(agent-core-v2): add tokenCounting service with strategy config and measured anchors

- add IAgentTokenCountingService as the single owner of token counts:
  context size, full-request size, and estimate primitives, replacing
  the scattered contextSize/tokenEstimate/fullCompaction paths
- add [token_counting] config section with strategy = measured+estimated
  (default) / measured / estimated, plus the KIMI_TOKEN_COUNTING_STRATEGY
  env override; measured zeroes all estimates, estimated ignores anchors
- keep a live measured-anchor ledger in TokenCountingModel: each LLM
  exchange writes a real anchor, undo truncates the ledger so the
  surviving prefix restores its REAL measured size instead of a
  re-estimate, and compaction rebases to a single anchor that blends the
  compaction exchange's measured summary output tokens
- skip writing an anchor when the stream reports no usage event instead
  of anchoring emptyUsage() zeros, which zeroed the context size and
  silenced compaction for providers without usage reporting
- return the strategy-resolved size (not measured) from rpc getContext
  so the tokenCount contract stays correct under the estimated strategy
- migrate all consumers (contextMemory, fullCompaction, llmRequester,
  rpc, mirrorAgentRun, sessionLegacy, kap-server legacyStatus, node-sdk,
  kimi-inspect) to the new service; edge bridges no longer read the wire
  model directly
- document [token_counting] and KIMI_TOKEN_COUNTING_STRATEGY in the
  bilingual config reference

* fix(kap-server): omit maxContextTokens instead of pushing 0 when unknown

- readLegacyStatus falls back to the default model's context limit when no
  model is bound, and omits maxContextTokens entirely when the limit is
  unknown (0 is the engine's UNKNOWN_CAPABILITY marker, not a real limit)
- profileService no longer emits maxContextTokens in agent.status.updated
  when the bound model alias does not resolve

* fix(agent-core-v2): resolve token_counting strategy only at the reporting edge

- keep measured anchors and heuristic estimates both recorded and feeding
  internal logic (compaction triggers, budgets, overflow backoff) regardless
  of the configured strategy
- add IAgentTokenCountingService.statusSize() as the single strategy-resolved
  outward reading and route the WS/REST/RPC status surfaces through it
- fix the context-size display falling back to provider-reported usage under
  the estimated strategy
- fix compaction overflow backoff retrying identical messages until failure
  under the measured strategy (the strategy-gated estimator read as 0)
2026-08-04 09:44:21 +08:00
7Sageer
98ef0f0b2f
fix(agent-core): replay v2 profile.bind records so resumed sessions keep their tools (#2567)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(agent-core): replay v2 profile.bind records so resumed sessions keep their tools

Sessions created by the v2 engine (CLI 0.31+, wire protocol 1.5) persist
the profile binding, including the tool allowlist, as a profile.bind
record. The v1 replay path had no branch for it and silently dropped the
record, so a session resumed by a v1 host (e.g. the VS Code extension via
kimi-code-sdk) never called setActiveTools and sent requests with no
tools at all (observed server-side as tools_count=0; the model emits
reasoning only and stops with empty content).

v1 replay now maps profile.bind onto config.update + setActiveTools when
activeToolNames is an array, skips the record otherwise so the
resume-time default-profile fallback still applies, and treats
tools.reset_active_tools as a no-op.

* fix(vis): handle v2 profile records in context projection

* fix(agent-core): avoid synthetic replay for v2 profile binds

* fix(vis): render v2 profile wire records
2026-08-03 20:59:46 +08:00
Haozhe
6ba75a173b
feat(config): add deprecation mechanism and rename loop retry limit (#2572)
* feat(config): add deprecation mechanism and rename loop retry limit

- agent-core-v2 config: declarative section `deprecations` (deprecated TOML
  keys are ignored and report a warning diagnostic; the file is never
  rewritten) and env binding `deprecatedEnv` (old var still resolves as a
  fallback with a warning), surfaced via the new
  `IConfigService.onDidChangeDiagnostics` event
- loop_control: rename `max_retries_per_step` to `max_attempts_per_step` and
  `KIMI_LOOP_MAX_RETRIES_PER_STEP` to `KIMI_LOOP_MAX_ATTEMPTS_PER_STEP`;
  `max_steps_per_run` moves onto the same mechanism (no longer silently
  mapped)
- kap-server: push the global `event.config.warning` WS event to every
  connection whenever the config warning set changes
- TUI: show config diagnostics in warning yellow at startup instead of the
  dim startup notice
- docs: config-files/env-vars (en+zh), regenerated config manifest, and the
  agent-core-dev config guide

* feat(cli): validate config.toml against v2 section registry in doctor

- add v2/validate-config.ts: validate config.toml with the agent-core-v2
  ConfigRegistry, reporting registered-section schema failures as errors
  and unknown top-level keys / deprecated keys and env vars as non-fatal
  warnings
- route `kimi doctor` config validation through the v2 validator when the
  KIMI_CODE_EXPERIMENTAL_FLAG master switch is on (lazy dynamic import,
  keeping the v2 module graph off the default path)
- let doctor checks surface non-fatal warning messages on OK results

* chore: downgrade loop-control changeset to patch
2026-08-03 20:17:01 +08:00
Haozhe
071b6a50d9
refactor(kap-server): own v1 message history and snapshot assembly (#2562)
- move the v1 message protocol and projection out of the engine into
  kap-server and delete the engine-side messageLegacy edge adapter
- add a shared message history loader that folds the main agent's wire
  journal into full history across compactions, backing both the
  messages routes and the snapshot endpoint
- drop the disk-reading SnapshotReader fast path; assemble snapshots
  from engine services for cold and live sessions, removing the
  KIMI_SNAPSHOT_READER, KIMI_SNAPSHOT_TIMEOUT_MS and
  KIMI_SNAPSHOT_CACHE_LIMIT knobs
- collect persisted wire record rebuild helpers in the transcript
  service
2026-08-03 17:55:28 +08:00
Haozhe
75395f6abb
feat(agent-core-v2): add lifecycle hook events and enrich hook payloads (#2558)
* feat(agent-core-v2): add lifecycle hook events and enrich hook payloads

New hook events:
- TurnStarted: fired from the turn.started bus event, covering queued
  turns, stop-hook continuations, and background/system turns that
  UserPromptSubmit misses
- UserPromptQueued: fired when a prompt cannot launch immediately,
  carrying the queue length
- TaskStarted: fired from the existing task.started bus event, so
  background tasks no longer only produce a completion-time Notification
- SessionHeartbeat: per-session 60s liveness beat, armed only when the
  event has hooks registered, letting hook consumers distinguish a
  session hanging on a long permission wait from a crashed one

Payload enrichment:
- client_type (host platform identity) on every event
- session_title on every session/agent-scoped event
- model and profile on SessionStart
- SessionEnd reason is now 'exit' or 'archive' instead of a hardcoded
  'exit'
- SubagentStart/SubagentStop now carry session_id/cwd like every other
  event

* fix(agent-core-v2): re-sync SessionHeartbeat timer on hook-index reloads

The heartbeat timer was armed once after the runner's initial load, so a
SessionHeartbeat hook contributed later by a plugin reload never produced
beats for existing sessions. The runner now exposes onDidReload (fired
after every index build), and the session adapter re-syncs on it: arming
when a heartbeat hook appears, disarming when none remains.

* fix(node-sdk): keep the v1 PluginInfo contract assignable with v2-only hook events

The v2 hook-event union is now a superset of v1's, which broke the
node-sdk type projection in two places:

- the klient contract's hookDefSchema rejected plugin manifests using
  the new events (TurnStarted, UserPromptQueued, TaskStarted,
  SessionHeartbeat) at validation time — accept them
- getPluginInfo returned the v2 PluginInfo where the SDK contract
  promises the v1 shape — project manifest.hooks through the v1-known
  event list (read from the legacy HookDefSchema), mirroring how the
  config mapper drops domains v1 does not know
2026-08-03 17:14:34 +08:00
qer
dfc55a5c97
fix(tui): make the /login already-logged-in notice visible (#2559)
The "Already logged in. Model configuration refreshed." confirmation was
rendered with the default dim text color, so users easily missed it and
assumed /login did nothing. Render it with the theme's success color,
matching the success styling used by the login spinner's "✓ Logged in."
line.

Co-authored-by: Mira Bot <mira-bot@moonshot.cn>
2026-08-03 16:37:55 +08:00
liruifengv
e22479a62e
feat(kap-server): expose effective experimental flags in /meta (#2417)
Some checks failed
CI / build (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test (5) (push) Has been cancelled
CI / test-pi-tui (push) Has been cancelled
CI / test-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
Release / Release (push) Has been cancelled
Nix Build / Check flake.nix workspace sync (push) Has been cancelled
Release / Deploy docs (push) Has been cancelled
Release / Native release artifact (push) Has been cancelled
Release / Publish native release assets (push) Has been cancelled
Nix Build / nix build .#kimi-code (push) Has been cancelled
2026-08-01 10:22:23 +08:00
StaR4y
bfa00807c9
fix(web): correct dark monochrome composer styling (#2083)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Co-authored-by: StaR4y <star4y@origin.pw>
Co-authored-by: qer <wbxl2000@outlook.com>
2026-07-31 22:38:45 +08:00
Mangesh Raut
eaab2b6f28
fix(cli): fall back to built-in models.dev catalog when fetch fails (#2416)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
When the remote models.dev catalog cannot be fetched, fall back to the
built-in catalog so CLI/TUI model selection keeps working offline or
under network failure. Import the shared helper via the #/utils alias.
2026-07-31 19:54:09 +08:00
github-actions[bot]
6b56c11697
ci: release packages (#2403)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-31 19:29:29 +08:00
qer
326e1fb6ce
fix(web): restore chat code block styling after the markstream upgrade (#2459)
* fix(web): restore chat code block styling after the markstream upgrade

markstream-vue 1.0.9 renders shiki code blocks through stream-diffs
(code-editor-container) instead of <pre>, and drives font size, line
height, and font family from monacoOptions applied as inline styles.
With only lineNumbers passed, blocks fell back to 12px/18px in the
inherited proportional UI font, and the pre/copy-button/content CSS
overrides in Markdown.vue no longer matched anything.

Pass fontSize/lineHeight/fontFamily/padding through codeBlockProps
monacoOptions (the only channel that reaches the shiki renderer),
retarget the dead overrides to code-block-shell-content and
code-action-btn, and hide the loading fallback's hardcoded line-number
gutter so the highlight upgrade no longer shifts layout.

* fix(web): keep code block metrics in sync

* fix(web): pin chat code font to 13px and align the loading fallback

Tying the code font size to the Appearance UI font size setting changed the
default rendering from the 13px design token to 14px and broke the 15/14/13
type scale; revert to the fixed token size. Keep the fallback ↔ settled
alignment: the restored monaco padding option feeds the fallback pre's
inline padding (12px, ignored by the shadow-root renderer), and a relative
1.65 line-height with !important beats the inline 1.5x default upstream
stamps on the fallback.

* chore(web): pin markstream-vue and its renderer stack to exact versions

The markstream family ships breaking rendering changes in patch releases
(1.0.8 swapped the code-block engine and renamed its DOM classes), so a
floating caret range hands merge control to upstream. Pin markstream-vue,
stream-diffs, stream-markdown and stream-monaco exactly — upgrades become
deliberate actions with a visual check, same posture as @chenglou/pretext
in the same file.
2026-07-31 19:14:02 +08:00
7Sageer
1f3f5dadaa
feat(agent-core-v2): interruption reminder for user-cancelled turns (#2400)
* feat(agent-core-v2): interruption reminder for user-cancelled turns

When the user interrupts a turn with Esc, append a durable
<system-reminder> (origin: injection/interruption) to the agent context
via a new loop aspect watching turn.ended, so the model learns the
previous turn was deliberately cut off. The marker persists to the
wire, replays on resume, stays hidden from transcripts, skips non-user
aborts and steer, and does not stack on repeated cancels.

Two supporting fixes:

- An aborted LLM stream now persists its accumulated partial
  text/thinking as content.part loop events instead of dropping every
  produced token; gated on the turn signal so retried or
  step-cancelled attempts keep their partial output out of the record.
- The turn.cancel wire op carries an optional reason
  ('user_cancelled' | 'aborted') so cold readers can tell deliberate
  interrupts from programmatic aborts. Goal-lifecycle cancels now pass
  an explicit programmatic reason to keep that field honest.

* feat(transcript): mark user-cancelled turns with an interruption marker

Project the deliberate user interrupt onto the transcript timeline: the
live projector emits an 'interruption' marker when a turn ends with
interruptReason 'user_cancelled', and the cold fold consumes the
persisted turn.cancel reason into the same marker. Programmatic aborts
keep surfacing through their own outlets (errors, goal/task state), and
queued cancels that left no visible residue are skipped.

* fix(agent-core-v2): make user-turn cancellation idempotent and reconcile interruption reminders on restore

* fix(transcript): dedupe user-cancelled interruption markers by turn in the cold fold

* chore(agent-core-v2): regenerate state manifest after merging main

* refactor(agent-core-v2): split interruptionReminder out of the loop domain

The loop domain owns turn execution mechanics; whether an interrupted turn
should produce a model-visible reminder is a model-context policy. Move it
into its own L4 domain with its own wire model that cross-reduces the
loop's turn.cancel fact, and rename the op to interruptionReminder.recorded.

---------

Signed-off-by: Haozhe <yanghaozhe@moonshot.ai>
Co-authored-by: Haozhe <yanghaozhe@moonshot.ai>
2026-07-31 18:17:14 +08:00
Rick
302b2cd680
fix(vscode): all AskUserQuestions should be answered and added to the context (#2326)
Co-authored-by: rickgao <rickgao@tencent.com>
Co-authored-by: qer <wbxl2000@outlook.com>
2026-07-31 17:40:12 +08:00
Bowen Liang
e111c878fd
fix(web): unify permission mode order and risk colors across settings surfaces (#2125)
* web: reorder default permission options in Agent settings

Align the Agent settings default-permission segmented control with the
Composer toolbar order, arranging modes from safest (manual) to most
permissive (auto).

* web: reorder mobile permission cycle from safest to most permissive

The mobile settings sheet still cycled manual → auto → yolo, jumping from
the safest mode straight to the most permissive one on a single tap. Align
the tap-to-cycle order with the Composer menu and Agent settings
(manual → yolo → auto).

* web: align permission risk colors with the Composer's progression

Both the desktop status panel and the mobile settings sheet mapped
yolo → danger and auto → warning, the inverse of the Composer menu
(yolo → warning, auto → danger). Since auto is the most permissive
mode, it should carry the danger color everywhere.

---------

Co-authored-by: qer <wbxl2000@outlook.com>
2026-07-31 13:28:05 +08:00
Haozhe
ed7a4cc095
feat(kap-server): add session-less POST /workspace/fs:search route (#2437)
* feat(kap-server): let fs:search resolve a workspace ref for draft sessions

- fs:search accepts a workspace id or absolute root in the session_id slot
  so the @ file mention works before the session exists
- kimi-web searchFiles falls back to the active workspace id in draft state

* fix(agent-core-v2): report empty thinking level for unbound main agent

- sessionLegacyService.status returns thinking_level '' when the main
  agent has no bound model (mirroring model: undefined), so clients
  fall back to the catalog default instead of folding in the wire
  model's 'off' zero value
- add regression test for a never-bound main agent status
- add web changesets: draft @ file mention, new-session thinking level

* perf(minidb): make text index rebuilds async and non-blocking

- TextIndex.build() yields to the event loop during tokenization and
  batches postings writes (~1 MiB), so large rebuilds no longer
  hard-block the host process
- writes landing mid-build are queued and replayed onto the new base at
  swap time, keeping the rebuilt index exact
- PostingsFile.rebuildSync renamed to async rebuild with a synchronous
  commit section (beforeRename hook + atomic rename)
- onCompacted hook is now awaited (sync or async); open-time compaction
  runs in the background so open() returns without blocking on the
  snapshot rewrite and postings rebuild
- compaction skips the postings rebuild when the index's write buffer is
  clean (needsRebuild)
- createTextIndex registers before building so concurrent writes feed
  the build queue; dropTextIndex throws while a build is in flight

* refactor(agent-core-v2): rename workspaceHandler to sessionLifecycle

- rename IWorkspaceHandlerService to ISessionLifecycleService and move
  src/workspace/workspaceHandler/ to src/workspace/sessionLifecycle/;
  update all consumers (gateway, sessionExport, sessionLegacy,
  sessionLookup, kap-server, klient, node-sdk, kimi-inspect, kimi-code)
- rename IStateService to IAppStateService and add the Workspace-scope
  IWorkspaceStateService, so the state domain spans all four scope tiers
- add cascading StateRegistry.inspect(): each tier injects the parent
  tier's registry and folds App to current scope into one StateInspection
  tree; check-domain-layers gains a Rule 2b exemption for state-on-state
  imports

* feat(kap-server): add session-less POST /workspace/fs:search route

Carry the workspace reference (registered id or absolute root) in the
request body and resolve it to the same Workspace-scope fs service the
session route uses, so clients no longer borrow the session route's
{session_id} slot. kimi-web's @ file mention now calls this route with
the workspace ref instead of a session id; the session-route fallback
stays for wire compatibility.

* refactor(agent-core-v2): register workspace-scope service state into IWorkspaceStateService

- move workspaceDirs / workspaceInstructions / workspaceSkillCatalog / workspaceTrust
  runtime state from bare instance fields into the workspace state container
- extend gen-state-manifest.mts to scan app/workspace scopes, emitting
  AppStateSnapshot / WorkspaceStateSnapshot alongside Session/Agent
- regenerate docs/state-manifest.d.ts and update AGENTS.md + agent-core-dev skill
- update affected tests to register the state services and assert the new state keys
2026-07-31 12:11:26 +08:00
liruifengv
bb2919eb81
fix(tui): reduce frequent full-screen redraws (#2442)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
2026-07-31 11:35:39 +08:00
qer
5c0ec2938a
fix(web): upgrade markstream-vue to 1.0.9-beta.1 and enable Monaco code highlighting (#2415)
* fix(web): upgrade markstream-vue to 1.0.9-beta.1 and enable Monaco code highlighting

* fix(nix): update pnpm deps hash for markstream-vue 1.0.9-beta.1
2026-07-30 20:01:57 +08:00
Haozhe
f1a3475ad5
fix(agent-core-v2): write refresh results in one atomic config transition (#2410)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(agent-core-v2): write refresh results in one atomic config transition

- add IConfigService.replaceSections: applies several domains in a single
  state transition — one disk write, one effective rebuild, change events
  fire only after all domains took effect
- rework ProviderDiscoveryService to absorb the orchestrator's two-phase
  removeProvider/setConfig host contract into one replaceSections write, so
  the kosong registries never pass through a halfway-removed catalog
- stop writing the env-synthesized __kimi_env__ slice to config; the
  bridge's event-driven sync carries it into the registries on its own
- fixes sporadic "model is not configured" errors when starting kimi web,
  caused by the background refresh transiently clearing the model catalog
  while the first session was being created

* fix(agent-core-v2): stage replaceSections writes before mutating raw config

Validate and strip every domain into a staged copy of the raw/memory layer
first, then swap it in only after the whole batch succeeds — previously a
later domain failing validation left earlier domains already applied to
this.raw/this.memory while the call reported failure, exposing a partially
applied user layer to inspect() and future merges.
2026-07-30 18:42:20 +08:00
qer
479403e701
chore(vscode): release 0.6.6 (#2401)
* chore(vscode): release 0.6.6

* chore(vscode): release 0.6.7

* chore(vscode): fold the sign-in wording fix into 0.6.6

* chore(vscode): backfill the 0.6.5 changelog entry
2026-07-30 15:33:19 +08:00
qer
0f3b106c42
fix(vscode): reword the sign-in waiting message to authentication (#2402) 2026-07-30 15:13:57 +08:00
github-actions[bot]
bc28e9d802
ci: release packages (#2342)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-30 14:56:30 +08:00
qer
6d0a046488
fix(vscode): keep sign-in reachable from the no-models screen (#2393)
* fix(vscode): keep sign-in reachable from the no-models screen

* fix(vscode): stop flagging bundled this.require(...) calls as VSIX runtime dependencies
2026-07-30 14:47:37 +08:00
Haozhe
d10b1c1308
fix(agent-core-v2): treat cache entries missing required fields as cold misses (#2395)
* fix(agent-core-v2): treat cache entries missing required fields as cold misses

- normalize `archived` to a boolean when mirroring session metadata to the
  read model, so entries for pre-`archived` sessions no longer lose the key
  during JSON serialization
- add a runtime shape check on read-model cache hits; entries missing
  required fields are rebuilt from disk and overwritten, self-healing
  poisoned entries written before the fix
- log a warning when the TUI session picker fails to fetch sessions instead
  of silently showing "No sessions found."

* chore: add changeset for session index cold-miss fix
2026-07-30 14:28:28 +08:00
liruifengv
40172c7ca9
feat: unify the host identity across OAuth, telemetry, and kap-server (#2382)
* refactor(oauth): make X-Msh-Platform an explicit host identity field

X-Msh-Platform was hardcoded to kimi_code_cli in createKimiDeviceHeaders,
so non-CLI hosts could not state their own platform and the desktop had
to patch the header after the fact. KimiHostIdentity now carries a
required platform (every host declares its own value; the CLI constant
stays the fallback only for direct createKimiDeviceHeaders callers), and
userAgentProduct is renamed to productName so the transport identity
uses one name everywhere.

All in-repo identity constructions pass platform explicitly; the wire
value for CLI and VS Code hosts is unchanged (kimi_code_cli).

* feat(agent-core-v2): carry the host identity in the bootstrap snapshot

Replace the flat clientVersion field with a required clientIdentity
(KimiHostIdentity) so every consumer reads the same host identity
object: OAuthToolkitService now passes it to the OAuth toolkit, which
means the OAuth device-flow endpoints (device authorization, token
polling, refresh) on the kap-server path finally send the full X-Msh-*
device headers instead of none, and the telemetry cloud appender reads
client_version from the same source. A built-in CLI fallback keeps bare
bootstrap() calls in tests working; composition roots must pass their
own identity.

The session export manifest grows an optional desktopVersion field
(payload plumbed through; filled by kap-server in a follow-up).

* feat(agent-core): thread the host identity into the managed auth facades

The v1 managed auth facade constructed its OAuth toolkit without an
identity, so token refreshes from inside the core went out without any
X-Msh-* device headers. createManagedAuthFacade now takes an optional
KimiHostIdentity and every call site supplies one:
CoreProcessService._defaultOAuthTokenResolver forwards the core
process's options.identity (the same source _defaultKimiRequestHeaders
uses), and the DI-held services (oauth / auth summary / model catalog)
read it from a new optional identity field on IEnvironmentService. The
library-level "no identity, no device headers" contract is unchanged.

* feat(kap-server)!: require the host identity and derive request headers from it

ServerStartOptions.hostIdentity is now a required ServerHostIdentity
(KimiHostIdentity + optional prompt display fields), replacing both the
old optional HostIdentityOverrides (renamed to PromptIdentityOverrides,
its productName field now displayName) and the version option (renamed
to serverVersion — it is the engine version reported as server_version,
while the host product version travels in hostIdentity.version).

The server now feeds bootstrap's clientIdentity from hostIdentity and
derives the default outbound headers (User-Agent + X-Msh-*) from it via
createKimiDefaultHeaders, so kap-server-hosted OAuth flows and model /
WebSearch requests carry the real host identity instead of a hardcoded
kimi-code-cli fallback UA. Explicit header seeds still win as an escape
hatch.

Session export manifests record the host product version: kimiCodeVersion
now carries hostIdentity.version (the engine version no longer appears),
and desktop exports (desktop: true) are additionally stamped with a
desktopVersion field. The instance registry keeps its host_version wire
field for compatibility (kimi-inspect reads it); only the in-memory name
changed to serverVersion.

* feat(cli): wire the CLI host identity into the kimi web server

kimi web now passes createKimiCodeHostIdentity(version) as the server's
hostIdentity, so web-UI OAuth flows and the engine's outbound requests
carry the explicit CLI identity (productName + version + platform). The
explicit hostRequestHeadersSeed is dropped — kap-server derives the same
headers from hostIdentity — and buildKimiDefaultHeaders goes away with
its only consumer.

* test(klient): drop clientVersion from the bootstrap contract parity list

* chore: add changesets for the host identity unification

* feat(cli): tag kimi web requests with a (web) User-Agent suffix

kimi web shares the CLI product token and platform, so its outbound
requests were indistinguishable from direct CLI runs upstream. Its host
identity now carries userAgentSuffix 'web', putting web-UI traffic at
kimi-code-cli/<version> (web) while X-Msh-Platform stays kimi_code_cli.

* fix(klient): keep the env() clientVersion wire field after the bootstrap identity switch

The bootstrap snapshot replaced the flat clientVersion scalar with
clientIdentity, which broke klient's env() fan-out (RPCError: method not
found). The wire surface keeps clientVersion — now sourced from
clientIdentity.version — and bootstrapService gains a clientIdentity
read (registered in envContract with an object schema) for consumers
that want the full identity.

* feat(oauth): send the product User-Agent on OAuth requests

The OAuth endpoints used to receive only the X-Msh-* device headers
(undici's default UA otherwise), which left the OAuth host unable to
distinguish runtime surfaces — notably kimi web, whose platform matches
the CLI and whose only distinguishing mark is the (web) UA suffix. The
toolkit now feeds the full identity headers (User-Agent + X-Msh-*) into
every device authorization, token polling, and refresh request; the
request-header type widens from DeviceHeaders to OAuthRequestHeaders.

* feat(vscode): report kimi_code_vscode as the extension's platform

The VS Code extension inherited the CLI's hardcoded X-Msh-Platform value;
with platform now an explicit identity field it declares its own, so the
managed endpoints and OAuth host can tell extension traffic apart from
CLI runs.

* refactor(agent-core-v2)!: require the client identity at the composition root

The bootstrap fallback identity fabricated a kimi-code-cli/unknown host
for any caller that forgot to pass one — the same silent-misreport
pattern this series set out to remove, and it made "required" a lie.
BootstrapInput.clientIdentity is now required, so a missing identity
fails at compile time instead of being papered over. Test and example
callers pass a shared fixture (klient examples and test engines get one
each); the node-sdk v2 client asserts its host identity with the oauth
helper. Also folds DeviceHeaders from an interface into a type alias so
it stays assignable to the widened OAuthRequestHeaders record.

* feat(oauth)!: require and validate the platform in device headers

Drops the quiet CLI fallback in createKimiDeviceHeaders (the same
silent-misreport pattern removed from the bootstrap identity): platform
is now a required option, validated with the same required-ASCII rule as
the version — empty or all-non-ASCII values throw instead of emitting a
blank X-Msh-Platform, and header-unsafe characters are stripped rather
than sent raw.

* fix(node-sdk): seed the host request headers on the v2 client path

The interactive v2 engine path (experimental flag) bootstrapped without
a hostRequestHeaders seed, so managed vendor calls went out with the
SDK's default User-Agent (OpenAI/JS) and no X-Msh-* at all — v1 passes
the full identity headers on the same requests. The v2 client now seeds
the headers from its asserted host identity, and a test pins the seed.

* chore: simplify the CLI changeset wording
2026-07-30 13:45:41 +08:00
Kai
691ec4679e
fix: remove the blocking wait from the TaskOutput tool (#2379)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix: remove the blocking wait from the TaskOutput tool

The block/timeout parameters let a model stall the whole turn waiting
for a background task (up to 3600s), even though completion already
arrives via automatic notification. Remove both parameters from the v1
and v2 engines (kept in model-facing parity), simplify retrieval_status
to success/not_ready, and update the tool, Bash, and Agent prompt
wording plus user docs accordingly. Stale callers passing block are
silently treated as a non-blocking snapshot.

* fix: align background-task prompts with the non-blocking TaskOutput

The compaction reminder promised TaskOutput could fetch a task's result
for tasks that are still running, where it now returns not_ready —
reword it to snapshot semantics and point at the completion
notification. Also list AskUserQuestion(background=true) as a task
source in the TaskOutput description.

* test: exercise stale TaskOutput args through the runtime validator

A stale block/timeout argument never reaches the tool: the executor's
preflight validates args against the closed tool schema and rejects
them immediately, so the old test documented silent-tolerance semantics
the runtime never exhibits. Assert the real behavior through
compileToolArgsValidator/validateToolArgs instead, and drop
statement-adjacent comments to match the package's header-only comment
convention.
2026-07-30 01:26:56 +08:00
7Sageer
fa2c5ce18b
feat: support plugin-contributed custom agents (#2365)
* feat: support plugin-contributed custom agents

* fix: await plugin loading before agent catalog

* fix: refresh plugin agents on v1 reload

* test(agent-core-v2): add enabledSystemPrompts to the plugin service stub
2026-07-29 21:59:48 +08:00
7Sageer
1896d1a13a
Revert "fix(kosong): match Kimi's standalone "Unsupported image." rejection (…" (#2368)
This reverts commit dbb69a2678.
2026-07-29 20:56:41 +08:00
7Sageer
02d77b20d9
feat(agent-core-v2): let plugins contribute system prompt instructions via the manifest systemPrompt field (#2314)
* feat(agent-core-v2): let plugins contribute system prompt instructions via the manifest systemPrompt field

* feat(agent-core-v2): add systemPromptPath to load plugin system prompt from a file

* docs: explain plugin system prompt templates

* fix(agent-core-v2): refresh plugin system prompts after changes

* fix(agent-core-v2): freeze restored profile bindings and converge plugin contributions at session scope

- restore no longer re-renders or re-persists prompts: a resumed agent
  keeps its replayed profile binding (prompt and tool set) as persisted
- a new Session-level convergence point reloads plugin skills into the
  session skill catalog before fanning out to every live agent prompt,
  and every catalog-kind plugin mutation awaits the whole pipeline;
  MCP-only toggles carry a distinct change kind and skip it
- live refreshes after a restart re-resolve the bound profile by name
  and rebind the full slice (prompt, disallowed tools, active tools)
  atomically, warning and keeping the persisted state when the profile
  is gone; renders reuse the first-render timestamp and unchanged
  prompts are not re-persisted, so convergence never churns the wire
- cap plugin system-prompt contributions (32 KB per field/file, 64 KB
  aggregate per prompt build) with manifest diagnostics and warnings
- bump the changeset to minor: this is a new user-facing capability

* fix(agent-core-v2): register the new session domain and dedupe the missing-profile warning

- add sessionPluginContribution to the domain-layer registry so
  lint:domain stays green
- emit system-prompt-refresh-profile-missing once per profile name,
  matching the service's other deduped warnings
- document the convergence timeout escape hatch and the klient
  exclusion of enabledSystemPrompts

* fix(agent-core-v2): dedupe the plugin budget warning and surface section read failures

- emit plugin-sections-oversized once per skipped-plugin signature
- let enabledSystemPrompts failures propagate to the refresh catch
  (keeps the current prompt and warns) instead of silently rendering
  and persisting a prompt without plugin instructions
- cover the convergence timeout cut-off with a fake-timers test
- clarify that the first-render timestamp anchors per process

* fix(agent-core-v2): serialize session convergence and restore onDidReload timing

- run at most one convergence per session and bound each change's wait
  by the timeout, so a fan-out emitter never interleaves deliveries
  after a timed-out convergence
- fire onDidReload as soon as the reload commits again, keeping hook
  reloads independent of prompt convergence
- sign the plugin budget warning with an unambiguous key

* docs(agent-core-v2): align convergence wording with the serialized semantics

- the timeout retry promise only holds once stalled work clears
- note the per-session serial delivery cost model on the plugin change
  contract and the dual-queue invariant on the service

* fix(agent-core-v2): keep empty plugin sections byte-neutral in the prompt template

- place ${plugin_sections} on the same template line as
  ${skills_section} so prompts without either block render exactly as
  before this feature
- note on the change contract that waitUntil work must not call back
  into plugin mutations, and spell out the per-session convergence
  order in the user docs

* fix(agent-core-v2): pin a fork's profile so refresh triggers never rebind it

- applyBindingSnapshot left the fork with no pinned profile, which
  routed in-process forks into the post-restart catalog rebind and
  could reset an inherited tool set; forks now inherit the source
  agent's pinned profile object
- pin the first-render timestamp reuse with a ${now}-embedding test
  and document the anchored ${now} semantics
- tighten the plugin docs budget and resume-refresh wording

* fix(agent-core-v2): join in-flight convergence during agent bootstrap

- an agent created while a plugin convergence is in flight now waits
  for it, and a restored agent refreshes once after it, so a plugin
  mutation never straddles an agent's bootstrap
- warn on a non-string systemPrompt field and strip a UTF-8 BOM from
  systemPromptPath files before trimming
- correct the consumption-surface wording (every CLI surface on the
  experimental flag, not just kimi -p), the per-session queueing note,
  and the single-plugin combined budget clause

* fix(agent-core-v2): bound the bootstrap convergence join by the timeout

A permanently wedged convergence kept convergeTail pending forever,
and the unconditional settled() wait in bindBootstrap would have
blocked every later agent creation in that session; the join now
races the shared convergence timeout and continues (a restored agent
still refreshes once, which never touches the tail), and the timeout
constant moves to the contract for reuse

* fix(agent-core-v2): close the convergence race against in-progress restores

- a convergence fan-out could land while an agent's wire log is still
  replaying, dispatching a replay-visible config record whose effect
  the rest of the replay then overwrites; refreshSystemPrompt now
  skips while the wire restore is in progress
- convergence completion is tracked by a generation counter; bootstrap
  compares it (after a bounded join) and refreshes a restored agent
  exactly once when a round completed after its creation began,
  replacing the wasConverging flag that could miss both windows

* fix(agent-core-v2): bound each convergence so a wedged participant cannot stop the pipeline

- the fan-out now races the convergence timeout, so convergeTail always
  settles: a permanently hung refresh delays its round (blocked entries
  drain oldest-first on later changes) instead of killing the session's
  convergence for good
- warn when agent bootstrap stops waiting on a stalled convergence
- diagnose a blank systemPromptPath and pin the plugin-root escape
  guard with traversal, absolute-path, and symlink tests

* fix(agent-core-v2): bound the skill reload, preserve user-tool overlays, roll the prompt clock daily

- the convergence's skill-reload segment now races the same timeout as
  the fan-out, so no segment of the pipeline can wedge a session for
  good; it continues with the previous catalog and retries next change
- a cold rebind that resets the tool set replays session-added user
  tools onto the new base instead of dropping them for the rest of the
  process
- the rendered timestamp re-anchors when the UTC date rolls over, so
  long-lived processes keep a fresh clock while steady-state renders
  stay byte-stable within a day
- the plugin budget warning dedupes per plugin id, and the docs note
  that systemPromptPath content is frozen until the next reload

* feat(agent-core-v2): converge cold plugin changes on resume through a drift-free gate

- restore replays the persisted binding untouched, then bootstrap
  refreshes only when drift-free inputs changed while the session was
  cold: the catalog profile's tool set/denylist, or the plugin-sections
  baseline persisted alongside the prompt on the existing bind/update
  payloads; directory-listing and date drift wait for live triggers,
  so quiet resumes append no replay-visible records
- the rendered timestamp is day-precision (UTC date at 00:00,
  re-anchored on rollover), keeping steady-state renders byte-stable
  across resumes and sessions on the same day
- consolidate both timeout helpers onto a shared raceOutcome, and drop
  the generation counter the gate supersedes
- align the plugin-sections precedence prose with the AGENTS.md
  disclaimer (no self-granted authority, system instructions win on
  conflict)

* fix(agent-core-v2): bound the restored-prompt gate and land the sections baseline

- the gate's plugin-sections read now races the convergence timeout, so
  agent creation never blocks behind an unrelated plugin mutation
- refreshes serialize per agent through a tail, so overlapping triggers
  cannot write prompts out of order
- when plugin sections change but a plugin-free custom prompt does not,
  the new baseline lands as a sections-only update instead of making
  every later resume re-render in vain
- align the system prompt's Date and Time paragraph with the
  day-precision anchored timestamp

* Update plugin system-prompt instructions in changeset

Live sessions pick up plugin changes, while the default TUI and `kimi -p` paths ignore these fields.

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* refactor(agent-core-v2): keep plugin skill reload user-driven

Plugin mutations still converge live agent prompts, but the session
skill catalog goes back to refreshing only on explicit plugin reload,
as before: the prompt feature does not need skill convergence, and the
pre-existing manual-reload semantics stay uniform across all plugin
contributions. Removes the convergence-driven skill reload, the
reloadSource de-privatization, and their tests; restores the
PluginSkillSource onDidReload forwarding and its catalog tests.

* refactor(agent-core-v2): apply plugin system-prompt changes only on explicit reload

Drop the live convergence machinery (the plugin onDidChange barrier,
the sessionPluginContribution fan-out, the restored-prompt drift gate,
and the day-precision render clock) so plugin system-prompt sections
take effect at the same point as every other plugin contribution:
/plugins reload or a new session. The profile now refreshes when the
session skill catalog re-pulls its plugin source on reload, reading
both the skill list and the prompt sections fresh.

* feat(agent-core): let plugins contribute system prompt instructions via the manifest systemPrompt field

* chore(agent-core-v2): remove inline implementation comment

* docs: clarify plugin prompt refresh semantics

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>
2026-07-29 20:30:07 +08:00
STAR-QUAKE
dbb69a2678
fix(kosong): match Kimi's standalone "Unsupported image." rejection (#2362)
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
isImageFormatError missed the production phrasing "Unsupported image.
Please try another one." — the existing pattern requires a url/format/
type suffix, so the deterministic image rejection never triggered the
media-stripped resend, and the session failed on every later request.

Add a standalone-sentence pattern (punctuation- or end-terminated) to
both the kosong and agent-core-v2 classifiers, keeping the deliberate
boundary that count/size phrasings must not match.

Co-authored-by: fengchenchen <fengchenchen@moonshot.ai>
2026-07-29 18:54:07 +08:00
7Sageer
efac96c8a9
feat(agent-core): custom agent files and secondary model on the v1 engine (#2232)
* feat(agent-core): custom agent files and secondary model on the v1 engine

Migrate the custom agentfile and secondary-model capabilities from
agent-core-v2 to the v1 engine so they work in the TUI and plain
kimi -p sessions:

- discover Markdown agent files from user/project/extra/explicit
  directories with the v2 precedence rules, a merged session profile
  catalog replacing the hardcoded builtin profile lookups, SYSTEM.md
  main prompt override, and ${base_prompt} backed by the effective
  default
- --agent/--agent-file now work in print mode on the default engine;
  CreateSessionOptions gains agentProfile/agentFiles
- [secondary_model] config + KIMI_SECONDARY_MODEL/EFFORT bind newly
  spawned subagents to a cheaper model behind the secondary-model
  experiment flag, with primary/secondary model params on Agent and
  AgentSwarm and upfront session warnings
- full disallowedTools deny semantics (exact names + mcp__ globs)
  evaluated by the tool manager and persisted in the agent wire

* fix(cli): guard optional agentFiles in the prompt runner

runPrompt is also driven programmatically (headless goal flow) with
options that never pass through the CLI parser defaults, so agentFiles
can be undefined; mirror the addDirs optional-chaining pattern. Also
extend the SDK experimental-feature assertion with the secondary-model
flag.

* fix(agent-core): preserve custom agent bindings on v1

* fix(agent-core): narrow secondary model error hints

* fix(agent-core): persist custom agent profile bindings

* Delete .changeset/sdk-agent-profile-options.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* Update v1-custom-agent-files.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* Update v1-secondary-model.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* Update v1-custom-agent-files.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* fix(agent-core): keep SYSTEM.md a prompt-only overlay for delegation

* docs: update agent file and secondary model availability wording

* fix(cli): reject --agent-file combined with session resume

The resume path only forwards the agent file's name for the bound-profile
assertion; the file's content is never re-applied (the session keeps its
creation-time catalog snapshot). Previously the combination was silently
accepted, so an edited file (or a same-named one) appeared to apply but did
not. Reject it at option validation and document the constraint.

* refactor(agent-core): share prompt-section prose and note v2 twins in agentfile headers

The Windows notes, additional-dirs and skills prose blocks existed twice:
inline in the builtin default template (system.md) and as constants in the
agent-file renderer (from-file.ts). Extract them to profile/prompt-sections.ts
as the single source: system.md renders them through injected KIMI_* template
variables and from-file.ts imports the same constants. Rendered prompts are
byte-identical for all four builtin profiles across macOS/Windows and
skills/dirs on/off; a new test pins system.md to the shared constants.

Also mark each profile/agentfile file with the path of its agent-core-v2
counterpart so format/semantics changes land in both engines.

* feat(cli): add /secondary_model command for the subagent model

Mirror /model: a picker with a thinking-effort step that persists [secondary_model] and live-applies to the current session via a new Session.setSecondaryModel RPC (node-sdk wrapper included), so newly spawned subagents bind the new model right away. The /model picker now hides the synthesized __secondary__ derived entry; docs and the update-config builtin skill mention the section.

* feat(tui): show the bound model in subagent run stats

Subagents report their model alias via agent.status.updated after spawn; resolve it to a display name and surface it in tool-call subagent stats and agent-group rows.

* fix(agent-core): validate agent profile before session persistence

* fix(agent-core): refresh subagent tools after model switch

* fix(agent-core): show subagent model preferences

* fix(agent-core): preserve secondary model recipe on live apply

* fix(agent-core): make secondary model apply explicit

* fix(tui): refresh secondary model display state

* chore: merge secondary model changesets into one

* Add /secondary_model command for subagent configuration

Show each subagent's model in the subagent card header and agent-group rows. Requires the secondary-model experiment (KIMI_CODE_EXPERIMENTAL_SECONDARY_MODEL=1); run /secondary_model to pick a model and thinking effort, applied to the current session immediately.

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* fix(agent-core): align explicit agent file precedence

* fix(agent-core): let disallowedTools deny select_tools

* chore(cli): drop engine mention from --agent/--agent-file help text

* feat(cli): support --agent/--agent-file in the interactive TUI

Bind the selected agent profile to the startup session when launching
the TUI with --agent/--agent-file, including the session created after
an OAuth login at startup. Sessions created later in the process (/new)
keep the default profile.

Make both flags creation-only in every mode: combining them with
--session/--continue is now rejected in print mode too, since resume
restores the bound agent from the session automatically.

* fix(agent-core): persist new secondary-model selections under env overrides

stripSecondaryModelConfig restored secondary_model.model/default_effort
from raw whenever KIMI_SECONDARY_MODEL/KIMI_SECONDARY_EFFORT was set, so
a /secondary_model pick made under the env vars was silently discarded
on write. Restore from raw only when the value being written still
equals the env value (an overlay round-trip), mirroring the pointer
check in stripEnvModelConfig; a genuinely different selection now
reaches config.toml.

* fix(cli): report the effective secondary model when env overrides the pick

/secondary_model toasted the picked alias even when
KIMI_SECONDARY_MODEL/KIMI_SECONDARY_EFFORT made the session bind a
different model. Read the effective binding back from the reloaded
config (as /model does from session status) and warn with the
env-overridden values instead.

* feat(tui): show the bound model name in the AgentSwarm panel header

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>
2026-07-29 12:06:26 +08:00
github-actions[bot]
16c7189bd5
ci: release packages (#2244)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-29 11:35:59 +08:00
liruifengv
973e2a008c
chore: prune non-user-facing changesets before release (#2335)
* chore: prune non-user-facing changesets before release

- Drop changesets for changes users cannot perceive: internal bash
  parser groundwork, host-identity server start option, and the
  structured managed-usage refactor
- Drop the duplicate agent-core-v2 repeat-breaker entry and remap the
  v1 fix to @moonshot-ai/kimi-code with user-facing wording
- Remove the untouched @moonshot-ai/kimi-code-sdk entry from the
  quota-exhausted fail-fast changeset
- Downgrade the upload size-cap removal to patch and drop the
  implementation detail from its wording

* chore: simplify verbose changeset entries

* chore: shorten changeset entries to single statements
2026-07-29 11:27:45 +08:00