feat(acp): add /undo builtin and kimi/session fork, close, steer extension methods#1686
feat(acp): add /undo builtin and kimi/session fork, close, steer extension methods#1686zhiyuan1i wants to merge 3 commits into
Conversation
🦋 Changeset detectedLatest commit: 9eaf140 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
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 |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 98e739e824
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| count = parsed; | ||
| } | ||
| await this.session.undoHistory(count); |
There was a problem hiding this comment.
Validate undo count before mutating history
When /undo asks for more turns than are undoable (or crosses a compaction boundary), the core ContextMemory.undo() removes messages as it walks history and only then throws REQUEST_INVALID; the TUI and web service avoid this by checking undo availability before calling undoHistory. This ACP path only syntax-checks the number, so /undo 99 on a shorter session can delete the available conversation context while reporting a failure. Please compute the available undo count from getContext() before calling the mutating RPC.
Useful? React with 👍 / 👎.
| const fork = await this.harness.forkSession({ | ||
| id: sessionId, | ||
| title: `Fork of ${sessionId}`, | ||
| }); |
There was a problem hiding this comment.
Preserve ACP filesystem routing for forks
In clients that advertise fs.readTextFile/fs.writeTextFile, session/new, session/load, and session/resume build an AcpKaos so tool file reads and writes go through the ACP client. This fork path calls KimiHarness.forkSession(), whose implementation resumes the fork without any kaos override, so prompts in the fork fall back to the server's local filesystem and miss client buffers/sandboxing. Please make the fork registration use the same ACP kaos path before exposing it as a promptable ACP session.
Useful? React with 👍 / 👎.
|
|
||
| All methods not listed above return `methodNotFound`. | ||
|
|
||
| ## Extension methods (`kimi/*` namespace) |
There was a problem hiding this comment.
Keep the Chinese ACP docs in sync
docs/AGENTS.md requires docs/en/ and docs/zh/ pages to stay mirrored for non-changelog edits. This change adds the new kimi/session/fork, kimi/session/close, and /undo documentation only to docs/en/reference/kimi-acp.md, leaving docs/zh/reference/kimi-acp.md without the new sections, so Chinese readers get stale ACP capabilities.
Useful? React with 👍 / 👎.
…ck /undo availability
- kimi/session/steer: new extension method injecting a pending user
message into the active turn (consumed at the next step boundary);
resolves { steered: false, reason: 'no_active_turn' } instead of
erroring when no turn is running, gated adapter-side via the tracked
currentTurnId because the v1 kernel's steer launches a fresh turn
rather than rejecting when idle.
- kimi/session/fork: thread the AcpKaos/persistenceKaos pair through
the fork path (core forkSessionWithOverrides, SDK forkSessionWithKaos,
ForkSessionInput.kaos) so forked sessions keep routing file I/O to
the client when fs capabilities are advertised.
- /undo: pre-check undoable prompt count against the live context
(mirroring sessionService.canUndoHistory) and refuse up front with
the kernel's message wording, instead of the kernel partially
deleting history before throwing REQUEST_INVALID.
871ffb0 to
9eaf140
Compare
Related Issue
Resolve #1685
Problem
See linked issue. In short: ACP clients (and hosts embedding
kimi acp) cannot undo history, cannot create an ephemeral fork for btw-style side conversations, and cannot steer a pending user message into a running turn — even though the SDK/kernel already support all three (undoHistory,forkSession,steer).What changed
/undo [count]built-in slash command (acp-adapter)available_commands_update; intercepted inAcpSession.promptthrough the existing slash-intent routing.Session.undoHistory(count)— the same RPC the TUI's/undouses. Default count 1; malformed counts get a usage message.context.undohas no active-turn guard, so the adapter checks its owncurrentTurnIdbefore splicing history out from under an in-flight turn.getContext+ acanUndoHistorywalk mirroring the web backend) and refused up front with the kernel's own message wording — the kernel'sContextMemory.undodeletes as it walks and only throwsREQUEST_INVALIDwhen it runs out of undoable prompts, so an over-large count would otherwise partially delete history before failing. A race fallback between pre-check and kernel call surfaces the kernel message verbatim.kimi/session/forkextension method ({ sessionId } -> { sessionId })KimiHarness.forkSessionand registers the fork as a first-class ACP session, so clients drive it with the normalsession/promptstreaming/tool surface — no new prompt path.SESSION_FORK_ACTIVE_TURNrejection.AcpKaos/persistence pair assession/newwhen the client advertisesfs.readTextFile/fs.writeTextFile: the kernel gainsforkSessionWithOverridesand the SDK a matchingForkSessionInput.kaos+forkSessionWithKaospassthrough, so forked sessions keep talking to the client's filesystem instead of silently falling back to the kernel'sLocalKaos.kimi/session/closeextension method ({ sessionId, archive? })archive: trueit also archives the on-disk directory — the cleanup path for btw forks, which would otherwise accumulate forever.kimi/session/steerextension method ({ sessionId, prompt: ContentBlock[] } -> { steered: true } | { steered: false, reason: 'no_active_turn' })Session.steer— the model consumes it at the next step boundary while in-flight tool calls and subagents run on undisturbed. The content pipeline (blocks → prompt parts → image compression) is identical tosession/prompt.{ steered: false, reason: 'no_active_turn' }instead of erroring, so the client can fall back tosession/prompt. The gate reads the adapter-trackedcurrentTurnIdand is best-effort (re-checked after the compression await): the v1 kernel has no idle-rejecting steer variant — with no active turn itsTurn.steerlaunches a fresh one — so a residual RPC-hop race is documented in code. Kernel-started turns (background/cron completion) are a known blind spot; closing it needs a kernel turn-state query (follow-up).invalidParamson malformed blocks), matching thesessionIdchecks of fork/close.node-sdk
rpc.archiveSessionpassthrough +KimiHarness.archiveSession(id)(agent-core already implementsarchiveSession; it just was not wired through the SDK).ForkSessionInput.kaos/persistenceKaos+forkSessionWithKaospassthrough (mirrors the create/resume kaos-override chain).Docs & release
docs/en/reference/kimi-acp.mdanddocs/zh/reference/kimi-acp.mdboth carry the extension-methods table (fork/close/steer) and the built-in slash-commands table.@moonshot-ai/kimi-codeminor (fork/close/undo, and steer+fork-kaos) + patch (undo pre-check);@moonshot-ai/kimi-code-sdkminor.Tests (acp-adapter 313 tests, kimi-sdk 192 tests, all passing; typecheck + oxlint clean)
/undo 3detected as builtin./undo//undo 3callundoHistory(1)/undoHistory(3)without invokingSession.prompt; malformed count yields the usage message;/undoduring an in-flight turn is refused; over-large counts and compaction boundaries are refused by the pre-check with the kernel's exact wording (undoHistorynot called); injection messages are skipped by the walk; a racing kernelCannot undoerror surfaces verbatim instead of the/undo failed:wrapper.kimi/session/forkroundtrip over the wire: forks via the harness and registers a promptable session; with fs capabilities advertised the fork carries anAcpKaos/persistence pair and a pre-mintedforkId; unknown/missingsessionId→invalidParams (-32602). SDK-level integration test drivesharness.forkSession({ kaos, persistenceKaos })against an in-process kernel and assertsfork.id === forkIdwith source content copied.kimi/session/close: drops the session;archive: trueroutes toarchiveSession, default routes tocloseSession.kimi/session/steer: happy path converts blocks and returns{ steered: true }; no active turn →{ steered: false, reason: 'no_active_turn' }; aprompt.not_foundkernel rejection maps to the same; missing/empty/malformedprompt→invalidParams.Known limitation (documented in code + issue): ACP-supplied
mcpServersare not carried into forks —resumeSessionrebuilds MCP from the on-disk config only. Follow-up if needed.Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.