Feat/rust agent engine migration - #2774
Conversation
…gine-home test isolation - listSessions merges the engine's persisted records with the host mirror so a harness sees sessions another harness created in the same home; summaries carry engine-persisted metadata. addAdditionalDir mirrors the caller's path verbatim (the forward-slash normalization rewrote it). - replayFromContext maps messages with the same mapContextMessage the context surface uses (tool calls/results preserved, field-identical records); resume summaries surface modelAlias/thinkingEffort. - createSession passes the real workDir to the engine. - test isolation: KIMI_AGENT_HOME points at a scratch store (materialized by a per-worker setup file) for node-sdk/vscode/kap-server suites, so fixed session ids no longer leak stale records across runs. - vscode: compaction tests assert the no-summarizer failure semantics, replay display assertions drop the retired host-rendered blocks, legacy backfill/subagent-replay tests are skipped as known gaps, and the replay status payload tolerates the leaner engine resume state.
The plan accumulated ~950 lines of session-by-session log. Rewrite it as a state-of-the-migration document: current status (2026-08-10), scope targets, crate inventory, G-0..G-7 progress, actionable TODO list, decision log (engine semantics, test strategy, known gaps) and a commit index. Historical session logs are condensed into decisions and kept only where they still constrain future work.
…ction + regression tests
…andbox, config roundtrip - session/create records the explicit work_dir (not homedir) and keeps the persisted workspace on resume re-creates - session/cancel no longer blocks on the manager lock held by long-running init/turns (Stop stays responsive) - native tool execution keys off workspace_root/work_dir instead of homedir; supports_tool_lifecycle enables engine-side gated write/bash/network tools - KimiConfig round-trips the host-facing thinking/yolo sections through config/get and config/set - adds regression tests for work_dir precedence, resume preservation, and the thinking section
Replace the @moonshot-ai/kimi-code-sdk dependency with the local sdk-local surface: camelCase status/context projections, user-agent identity on the native LLM, session mirror for additionalDirs, native tool execution wiring (workspace_root sandbox), and the corrected add_additional_dir method. The extension now talks to the Rust engine over stdio with no node-sdk import.
All 13 @moonshot-ai/kimi-code-oauth imports in apps/kimi-code now resolve to local modules ported from the package (device-id/UA identity glue and the custom-registry provider import), so the oauth package has no CLI consumer left and can retire with G-6. Behavior is unchanged: identity headers/device id semantics and registry api.json parsing/merging are ported verbatim; tests keep their mocks via the new module paths. Also drop the dead oauth alias from the vscode tsdown config and exempt test files from no-useless-undefined (it mis-fixes required mock arguments).
- 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: 71f9a84 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
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.