kimi-code/.changeset
Kai ace7901066
feat(agent-core): compress oversized images before sending to the model (#1243)
* feat(agent-core): compress oversized images before sending to the model

Downsample images to a 2000px longest-edge and per-image byte budget at the
single prompt-ingestion chokepoint (the prompt/steer RPC) and on tool results
(ReadMediaFile, MCP), so every client transport — CLI, web, desktop, ACP, SDK —
is covered uniformly inside the core. PNG screenshots stay lossless and only
degrade to JPEG when the byte budget cannot otherwise be met. Best-effort: the
original image is sent unchanged if compression fails.

* fix(agent-core): serialize prompt/steer RPCs to avoid a turn-claim race

The prompt/steer RPC handlers await image compression before turn.launch()
synchronously claims the active turn, so two overlapping calls could both
compress first — letting the faster-to-compress one win the turn and strand the
other on agent_busy. Run these two RPCs through a per-agent serialization chain
so they claim in submit order; cancel and the other RPCs stay immediate.

* fix: update flake.nix pnpmDeps hash for the jimp dependency

Adding jimp to the workspace changed pnpm-lock.yaml, so the pnpmDeps
fixed-output hash was stale and the nix build failed. Update it to the value
the CI nix build reported.

* fix(agent-core): guard image compression against decompression bombs

A tiny-byte, huge-dimension image (e.g. a solid 30000x30000 PNG) would be fully
decoded into a multi-gigabyte bitmap by Jimp before any resize — an OOM vector
the byte budget never catches. Skip compression when the sniffed pixel count
exceeds MAX_DECODE_PIXELS (~100 MP), before the decode; oversized images pass
through uncompressed as they did before compression existed.

* fix(agent-core): cap decode byte size before compressing images

Compression runs before downstream size caps (e.g. the 10MB MCP per-part
limit), so a huge or invalid base64 image from an MCP tool was Buffer.from-
decoded — and handed to Jimp — just to be dropped afterward. Add a
MAX_DECODE_BYTES ceiling (64MB, overridable) checked before the base64 decode
and before Jimp, the byte-side complement to the pixel-count guard; oversized
payloads pass through uncompressed.

* refactor(agent-core): compress images at ingestion, not on the turn RPC

Move image compression off the prompt/steer RPC path and back to each ingestion
site (CLI paste, server upload resolution, ACP conversion; ReadMediaFile and MCP
already compressed at their producers). Compressing on the RPC control path put
an async step before the synchronous turn-claim, which spawned a series of
races: prompt/steer interleaving, and — with a cancel arriving mid-compression —
an ineffective abort that let a cancelled prompt launch anyway.

Treating compression as a pure input-stage transform (done while the content
part is built, before it ever enters the agent loop) removes those races
structurally: rpc.prompt/steer are plain synchronous handlers again, and the
serialization/cancel-window machinery is gone. Records stay compressed, resume
stays consistent, and coverage degrades gracefully (a new client that skips
compression just sends a larger image, as before this feature).

* fix: compress inline base64 prompts and honor ACP cancels mid-compression

Two contained ingestion-site follow-ups:

- server: resolvePromptMediaFiles now also compresses images submitted as an
  inline `{ kind: 'base64' }` source, not just uploaded files, so the REST
  inline-base64 path gets the same downsampling.
- acp-adapter: AcpSession tracks a pending-abort flag while prompt() awaits
  image compression (before any turn exists). A session/cancel in that window
  flips it, so the prompt returns `cancelled` instead of launching a turn the
  client already stopped.

* fix(acp-adapter): cover all concurrent pre-turn prompts on cancel

The pending-abort marker was a single session field, so with two
`session/prompt` requests compressing large inline images at once the later
one overwrote it and a `session/cancel` could mark only one — the other
launched after the client had cancelled. Track a token per in-flight prompt in
a set and flip them all on cancel so every pre-turn prompt is covered.

* chore(node-sdk): declare jimp as a devDependency

The SDK re-exports the image compressor, whose lazy `import('jimp')` (inside
the bundled agent-core code) is inlined into the published dist. jimp was
resolved only transitively via agent-core, so declare it as an explicit build
input here — matching the CLI — to make the bundling reliable rather than
phantom. It stays a devDependency: jimp is bundled, not a runtime dependency.
2026-07-01 19:36:48 +08:00
..
config.json feat(server): add fast disk-based snapshot reader (#975) 2026-06-22 19:47:31 +08:00
google-genai-base-url.md fix(provider): honor base_url for google-genai and vertexai providers (#1269) 2026-07-01 19:33:35 +08:00
hide-off-always-on-effort.md fix(tui): hide redundant Off option for always-on effort models (#1264) 2026-07-01 18:33:56 +08:00
image-compression.md feat(agent-core): compress oversized images before sending to the model (#1243) 2026-07-01 19:36:48 +08:00
README.md chore(daemon): remove unused daemon package and stale references (#852) 2026-06-17 21:11:36 +08:00
tune-transcript-window-defaults.md fix(tui): reduce default transcript window to keep long sessions responsive (#1265) 2026-07-01 18:41:27 +08:00
web-search-query-only.md fix(changeset): drop private kimi-code-docs from web-search changeset to unblock release (#1270) 2026-07-01 19:28:20 +08:00

Changesets

This repository uses changesets to manage npm package versions and releases.

Package Publishing Strategy

This repository uses an independent, manually-selected publishing strategy. When generating a changeset, only select the publishable packages that this change actually affects. The repository's .changeset/config.json already filters out internal workspace packages via ignore, so only the publishable packages listed below should appear in the pnpm changeset prompt.

Current publishable packages:

Package Directory Description
@moonshot-ai/kimi-code apps/kimi-code CLI / TUI application — provides the kimi command after install
@moonshot-ai/kimi-code-sdk packages/node-sdk Public TypeScript SDK

All other workspace packages are private internal packages, are not published to npm, and are excluded via ignore in .changeset/config.json:

  • @moonshot-ai/acp-adapter
  • @moonshot-ai/agent-core
  • @moonshot-ai/kaos
  • @moonshot-ai/kimi-code-oauth
  • @moonshot-ai/kimi-telemetry
  • @moonshot-ai/kimi-web
  • @moonshot-ai/kosong
  • @moonshot-ai/migration-legacy
  • @moonshot-ai/protocol
  • @moonshot-ai/server
  • @moonshot-ai/server-e2e
  • @moonshot-ai/vis
  • @moonshot-ai/vis-server
  • @moonshot-ai/vis-web
  • kimi-migration-legacy

Version impact from internal dependencies must be judged manually. The published artifacts for CLI and SDK bundle internal workspace packages into the artifact itself; runtime dependencies of published packages must not include any @moonshot-ai/* internal workspace packages.

The repository's .changeset/config.json sets updateInternalDependencies: "patch". Because internal packages are not published, you still need to manually select all affected publishable packages in the changeset — do not rely solely on automatic dependency bumps to express user-visible changes.

Example scenarios:

Change Changeset selection
Only modifies TUI behavior in @moonshot-ai/kimi-code Add patch / minor / major to @moonshot-ai/kimi-code
Only modifies internal packages, no user-visible change in SDK / CLI Usually no changeset needed
Internal package fix changes the CLI user experience Add a changeset to @moonshot-ai/kimi-code describing the user-visible fix
Internal package adds a new capability exposed by the SDK Add a changeset to @moonshot-ai/kimi-code-sdk
SDK behavior change affects CLI user experience Add changesets to both @moonshot-ai/kimi-code-sdk and @moonshot-ai/kimi-code
Provider abstraction change affects SDK / CLI Add changesets to the affected @moonshot-ai/kimi-code-sdk and/or @moonshot-ai/kimi-code
Test-only, internal refactor, docs, or private debug tooling changes Usually no changeset needed
Bundled official plugin change under plugins/ (e.g. kimi-datasource) No changeset — the plugin is versioned via its own kimi.plugin.json / plugins/marketplace.json and shipped through the marketplace CDN, not the npm package

Prerequisite: NPM Trusted Publishing (OIDC)

This repository uses npm's Trusted Publishing (OIDC-based) for publishing — no NPM_TOKEN is required.

Configuration steps

  1. Open each publishable package's page on the npm website, e.g. https://www.npmjs.com/package/@moonshot-ai/kimi-code.
  2. Go to Settings -> Publishing access.
  3. Find Automate publishing with GitHub Actions or Add trusted publisher.
  4. Click Add a new trusted publisher.

Fill in the following:

Field Value
GitHub Organization MoonshotAI
GitHub Repository kimi-code
GitHub Workflow release.yml
Environment leave empty

Each publishable package needs its Trusted Publisher configured once. The current GitHub Actions workflow lives at .github/workflows/release.yml and already has id-token: write configured.

Development Workflow

1. Implement the feature or fix

Complete code, tests, and documentation changes as usual. A changeset is required when the change affects user-visible behavior, public API, dependency ranges, or release artifacts of a publishable package.

2. Generate a changeset

From the repository root:

pnpm changeset

Follow the prompts to choose:

  • Which publishable packages this change affects;
  • The version bump level:
    • patch: bug fixes, small changes, follow-up dependency updates;
    • minor: backward-compatible new features;
    • major: breaking changes;
  • A user-facing description of the change.

The command creates a .changeset/*.md file that must be committed alongside the code.

3. Commit the changeset

git add .changeset/
git commit -m "chore: add changeset for package release"
git push

Commit messages must follow Conventional Commit style. Do not include any author/agent identity in the commit message.

4. CI generates the release PR

Once the changeset file is merged into main, .github/workflows/release.yml uses changesets/action@v1 to create or update a release PR.

The release PR runs:

  • pnpm changeset version: bumps publishable package versions and updates changelogs;
  • Deletes the consumed .changeset/*.md files;
  • Uses the title [CI]: Release packages.

5. Merge the release PR

Once the release PR is merged into main, the same workflow runs:

  • pnpm install --frozen-lockfile
  • pnpm build
  • pnpm changeset publish

The packages are then published via npm Trusted Publishing, and a GitHub Release is created.

Only publish manually when CI is unavailable. Before publishing manually, make sure you are logged into npm locally and using the Node.js and pnpm versions required by the repository.

pnpm run version
pnpm run publish

The underlying changesets commands are:

pnpm changeset version
pnpm changeset publish

The root-level pnpm run publish first runs typecheck, lint, sherif, test, build, and package lint, then runs changeset publish.

Notes

  • Every PR that affects publishable-package behavior or public API should include a corresponding changeset.
  • Changes under plugins/ (the bundled official plugins such as kimi-datasource) do not need a changeset: each plugin carries its own version in kimi.plugin.json and plugins/marketplace.json and is distributed via the marketplace CDN, separately from the @moonshot-ai/kimi-code npm package.
  • Changeset files must be committed to the repository — release PRs are only triggered after they're merged.
  • Release PRs require human review and merge; they will not publish automatically.
  • Do not add release changesets for private internal packages; only select @moonshot-ai/kimi-code and @moonshot-ai/kimi-code-sdk.
  • If a change in an underlying internal package alters user-visible behavior or public API of a publishable package, add a changeset to the affected publishable package. For example, when a bug fixed in @moonshot-ai/agent-core resolves an issue CLI users encounter, add a changeset to @moonshot-ai/kimi-code describing the user-visible fix.
  • @moonshot-ai/kimi-code is the official CLI package name; after a global install it provides the kimi command.
  • Make sure each publishable package on npm has a Trusted Publisher configured.

References