Feat/rust agent engine migration - #2774
Conversation
- http.rs: widen the shared turn-context grace period from 100ms to 2s — a lagging WS projector could miss turn.started after the async-submit cleanup, silently dropping the whole turn projection and leaving its messages stuck in pending (v1 #2/MoonshotAI#5) - kimi-web agent projector: only emit the client-accumulated usage snapshot at turn end when the turn actually reported step usage, so the authoritative event.session.usage_updated numbers are no longer clobbered with zeros (v1 #3) - regression tests for the usage gating
Cut the first slice of @moonshot-ai/kimi-code-sdk consumption in the CLI host: resolveKimiHome/resolveConfigPath/loadRuntimeConfigSafe (trimmed TOML read + camelCase transform), ErrorCodes/KimiError/isKimiError/ resolveErrorTitle (structural cross-boundary check, i18n titles), and the git-bash error code. Behavior is equivalent; tests mock the new local module paths.
Port fetchCatalog/CatalogFetchError/DEFAULT_CATALOG_URL, the full import-resolution chain (wire guessing, endpoint adaptation, per-model provider overrides), and applyCatalogProvider from kosong/node-sdk into a local catalog-local module. Behavior is verbatim; only the config type is trimmed to the host-written surface.
🦋 Changeset detectedLatest commit: f433f3d The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 562e6f5cba
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| resolve(repoRoot, 'packages/kimi-build/target/release/kimi-build' + ext), | ||
| resolve(repoRoot, 'packages/kimi-build/target/debug/kimi-build' + ext), | ||
| resolve(appRoot, 'packages/kimi-build/target/release/kimi-build' + ext), | ||
| resolve(appRoot, 'packages/kimi-build/target/debug/kimi-build' + ext), |
There was a problem hiding this comment.
With postject removed from the app dependencies in this commit, build:native:* now falls back to kimi-build, but these candidates never include the Cargo workspace output path (target/{release,debug}/kimi-build) and the workflow does not build a per-package packages/kimi-build/target tree. As a result a normal native build reaches No SEA injector available even after cargo build -p kimi-build; either restore a packaged postject dependency or look for/build the helper where Cargo actually writes it.
Useful? React with 👍 / 👎.
| } | ||
| let router = match assets { | ||
| Some(dir) => kimi_server_transport::http::router_with_assets(state, dir), | ||
| None => kimi_server_transport::http::router(state), |
There was a problem hiding this comment.
Serve the packaged SPA for
kimi web
For installs where the new wrapper finds a Rust binary, kimi web reaches this default None branch because neither bin/kimi.mjs nor the command supplies --assets; the server then registers only the API router, so the browser opened at the root URL gets no web UI. Default this path to the package's dist-web assets (or require and pass an assets directory) before falling back to the API-only router.
Useful? React with 👍 / 👎.
| ) | ||
| .with_auth(auth); | ||
| let listener = tokio::net::TcpListener::bind((host, port)).await?; | ||
| let url = format!("http://{host}:{port}"); |
There was a problem hiding this comment.
Include the bearer token in opened web URLs
When auth is enabled by default, web_auth_config reads or generates a server.token and the HTTP middleware rejects API calls without Authorization: Bearer ...; however this URL is printed and opened without the #token= fragment that the TS web flow uses to authenticate the SPA. Even with assets supplied, a fresh kimi web opens an unauthenticated page unless the user already has the token stored, so build the openable URL from the resolved token.
Useful? React with 👍 / 👎.
| #[derive(Subcommand)] | ||
| enum Commands { | ||
| /// Run one prompt non-interactively. | ||
| #[command(name = "print", alias = "-p")] |
There was a problem hiding this comment.
Preserve the legacy
kimi -p flag
Once bin/kimi.mjs prefers the Rust binary, the common headless invocation kimi -p "prompt" no longer goes through Commander; clap documents flag-style subcommand dispatch via short_flag_alias/short_flag, while plain alias is a normal subcommand alias. This alias = "-p" therefore leaves the documented top-level -p path parsed as an option/unknown argument instead of the Print subcommand.
Useful? React with 👍 / 👎.
| import { fileURLToPath } from 'node:url'; | ||
|
|
||
| const HERE = dirname(fileURLToPath(import.meta.url)); | ||
| const candidates = ['kimi-win32-x64.exe', 'kimi.exe', 'kimi-linux-x64', 'kimi-darwin-arm64', 'kimi']; |
There was a problem hiding this comment.
Probe the platform name that
pack.mjs writes
pack.mjs writes the binary as kimi-${process.platform}-${process.arch}${exe}, but this wrapper only probes win32-x64, linux-x64, and darwin-arm64 (plus generic fallbacks). Packages built on linux-arm64, darwin-x64, or win32-arm64 therefore contain a correctly named binary that this entrypoint never finds, causing immediate Rust binary not found on those supported targets.
Useful? React with 👍 / 👎.
| @@ -0,0 +1,16 @@ | |||
| { | |||
| "name": "@moonshot-ai/kimi-code-rust", | |||
There was a problem hiding this comment.
Add the Rust wrapper package to flake workspaces
Adding packages/kimi-code-rust-bin under the packages/* workspace glob makes it a pnpm workspace, but flake.nix still lacks both its path and package name. Nix builds will drop this package from the source fileset and pnpmConfigHook will not know about @moonshot-ai/kimi-code-rust, so add it to both hardcoded flake lists with the new workspace.
Useful? React with 👍 / 👎.
Eliminate @moonshot-ai/kimi-code-sdk imports across the CLI host (23 files -> 1 transitional seam): local modules now provide the harness config surface, auth token read, device-flow login (ported from kimi-code-oauth), config-RPC, MCP/plugin/system-prompt/profile loading, catalog config write, engine-bridge types, and the pure type surface (Event/GoalSnapshot/TokenUsage/...). ACP now drives native engine sessions directly. One seam remains: prompt-harness-local still imports the SDK factory for the fallback harness (G-6 cutover point). Also correct a stale 100ms comment in the v1 transport tests.
…ete) The last @moonshot-ai/kimi-code-sdk import in apps/kimi-code is gone: prompt-harness-local now drives native engine sessions directly (config via local runtime-config, sessions via NativeServerClient + createNativeTuiSession, auth via auth-local, telemetry via the local client), and the opt-in e2e tests import the engine runtime logger directly. The devDependency is removed; node-sdk now has no consumer in the CLI host and can retire with G-6.
…t (missing #[test])
…obing - 03-inject.mjs probes the Cargo workspace target dir for kimi-build and drops the broken appRoot/packages candidates - kimi.mjs / kimi.js inject --assets for the web subcommand when a dist-web ships next to the wrapper - kimi.js probes kimi-<platform>-<arch> before the legacy name list - kimi web appends #token=<server.token> to the opened URL - lock the kimi -p alias behavior with a CLI regression test
…tocol/kaos (G-6) - move the six frozen TS packages to retired/ (zero external refs after G-1/G-2/G-3 consumption switches) - drop dead aliases/paths in apps/vscode and apps/vis/server configs, remove the stale kaos devDependency from migration-legacy - sync flake.nix workspace lists (add kimi-code-rust-bin, drop the six retired packages) and regenerate the pnpm lockfile - update AGENTS.md and CODEX_MIGRATION_PLAN.md to the new state
…ng (G-6) - export-local talks to kimi-server-serve via NativeServerClient (session/list + session/export RPC) instead of the rust-loop bridge - proxy and logging-core localize into apps/kimi-code (undici/socks dependencies move along); runtime errors/i18n were already unreferenced - kimi-agent package is now Rust-only plus the generated wire.gen.ts (exports reduced to ./rpc/wire); rust-loop/runtime/contract and their tests are deleted - kosong moves to retired/; flake.nix, lockfile, AGENTS.md and the migration plan are synced
…kage (G-3) - telemetry source (10 files, zero external deps) moves into apps/kimi-code/src/utils/telemetry; all 6 host imports and 5 vi.mock call sites switch to #/utils/telemetry (new imports mapping) - packages/telemetry moves to retired/; flake.nix, lockfile, AGENTS.md and the migration plan are synced
…package (G-5) - transcript source (3.7k lines, zod-only dep) moves to kimi-inspect/src/transcript-data; all 10 imports switch to relative paths - kimi-inspect gains zod + i18n-shared dependencies (the latter fixes a pre-existing missing-dependency build/typecheck failure) - packages/transcript moves to retired/; flake.nix, lockfile, AGENTS.md and the migration plan are synced
…hint - kimi migrate now prints the one-time legacy-data migration path instead of an unknown-subcommand error (the Rust binary does not bundle the migration screen); covered by a CLI regression assertion - remove the unreferenced slash-command-types and pi-tui-theme host files - record the migration evaluation decision: migration-legacy/pi-tui stay with the TS entry until G-7 (one-time host data feature, not ported to Rust)
…MoonshotAI#5) - eventReducer messageUpdated now stores the protocol status on the message instead of dropping it, so streamed assistant messages leave their initial/pending state when the Rust server projects the completed close-out - AppMessage gains an optional status field; REST snapshot messages map as completed history (toAppMessage status param), WS-created messages stay unset until message.updated arrives - regression test covers the status hand-off; G-2 #2/#3 verified already fixed (take_turn 2s grace, usage_updated consumption)
…shotAI#5) - new mappers-to-app-event tests lock message.updated status and session.usage_updated normalization onto the AppEvent shapes the Rust server projects - toAppMessage status parameter covered: snapshot loads carry 'completed', WS-created messages stay unset until message.updated - record the G-3 entry-switch assessment: the TS command surface is equivalent (plugin_run_node is superseded by the engine plugin model); the remaining blocker is the stage-F distribution packaging
…eardown - clear the 8 pre-existing typecheck errors (kaos-local resolve arg, web.test option args, vis v1-compat codePoint undefined guards) - drop retired-package entries from the five locale/scan scripts and regenerate locale JSON (new keys were missing from the built files) - NativeServerClient.close now waits for the child to exit so callers can clean the home dir (Windows unlink was EBUSY); call sites await it - kimi export releases its engine client after the one-shot export - rewrite the logging-export e2e for engine export semantics (wire.json + manifest; host-log bundling was retired with the SDK) — now passes under KIMI_E2E=1
…package - new _rust-bin-build.yml: 6-platform matrix builds kimi-cli + kimi-server-serve (release profile, macOS codesigned) and packs them into packages/kimi-code-rust-bin/bin via pack.mjs - release.yml downloads the per-platform artifacts before the changesets publish and merges them into the package, so @moonshot-ai/kimi-code-rust ships with a working binary instead of an empty bin/ - smoke step verifies the packed binary responds (kimi --version) - pack.mjs verified locally against a debug build
- the two vscode integration suites imported kosong's fake-provider-harness (retired with the package) and failed at module load; the zero-dependency mock server now lives in apps/vscode/test/fixtures and both imports point at it - full verification matrix green: cargo all crates + vitest 2044 passed
…tatus - apps/kimi-code had an unreferenced @moonshot-ai/kimi-agent devDep (no imports anywhere; wire.gen is only mentioned in comments) — removed - migration plan refreshed: G-1 SDK/vscode items marked done, G-5 items retired with kosong, frozen list trimmed to the remaining packages, known-gap list drops the fixed/flaky entries (vscode typecheck is green, release packaging is wired into CI)
…ta source) - the native Task tool now runs tracked subagents through run_child_agent_persistent_with_model (agent_id = task_id), the same session-store persistence swarm children use — the resume surface gets a host-visible subagent data source it previously lacked - untracked bare agents keep the non-persistent path - migration plan updated: vscode legacy backfill verified closed, gap list trimmed
…ort) - new LlmCompactionDelegate summarizes through any LLM implementation (shared summarize_with_llm core); NativeLlmCompactionDelegate reuses it - ensure_compaction_delegate falls back to HostLlmProxy over HostCallbacks::llm_chat when no native provider exists — host-proxy sessions can now compact instead of failing with compaction.unable - unit tests cover the generic delegate (multi-thread runtime for the block_in_place bridge); the stdio integration test now asserts the host-proxy path reaches the strategy phase (no missing-delegate error) - migration plan: compaction dual-channel gap closed
…arity) - top-level #[arg(long = "prompt", short = 'p')] routes into the print flow; the -p first-token alias still resolves to the print subcommand, so the documented kimi --prompt "..." form now works and -p<value> attached values parse as the short option - regression test covers all three shapes (long form, alias, attached); docs kimi-command.md claim is now honored
…e codec - the two Rust codecs' only remaining drift was the resize filter (native Triangle/jimp-parity vs engine Lanczos3); EXIF orientation and alpha handling were already equivalent with test coverage - native fit_within_edge now uses Lanczos3, matching the engine media pipeline (kimi-agent media/image.rs) so both paths produce identical output; the jimp-parity filter is retired with the TS host - migration plan §8 records the merge evaluation: shared-core extraction is not worth the image dependency in kimi-shared
Related Issue
Resolve #(issue_number)
Problem
What changed
Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.