MoonshotAI / MoonshotAI/kimi-code
Expose steering over ACP: map _session/steering to the existing Session.steer()
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
Summary
kimi acp currently has no way for an ACP client to inject a message into a running turn, even though Kimi Code already implements steering everywhere else. As a result, ACP hosts can only queue a follow-up and wait for the turn to finish, while the TUI can steer it immediately with Ctrl-S.
This is a request to expose the existing capability through the ACP surface, matching the extension method that claude-agent-acp and codex-acp already ship.
The capability already exists — only the ACP surface is missing
| Core SDK | packages/node-sdk/src/session.ts — async steer(input: string | PromptInput) → rpc.steer({ sessionId, input }) |
| Official smoke test | packages/node-sdk/examples/kimi-harness-steer-smoke.ts — calls await session.steer(STEER) while a prompt stream is still running |
| TUI | docs/en/reference/keyboard.md — Ctrl-S: "Steer: inject the current input directly into the running turn" |
| ACP adapter | packages/acp-adapter/** — no reference to steering anywhere; AcpSession.prompt() maps straight to session.prompt() |
The adapter already holds the same KimiHarness / Session instance that exposes steer(), so this is a thin mapping rather than new functionality.
Prior art: the wire shape is already established by two other adapters
Both adapters below implement the same extension method, so hosts can support all of them with one code path:
@agentclientprotocol/claude-agent-acp(verified in0.62.0)@agentclientprotocol/codex-acp(verified in1.1.7)
Advertisement — top-level _meta in the initialize response:
{ "_meta": { "steering": { "supported": true } } }
Request — _session/steering:
{ "sessionId": "…", "prompt": [ { "type": "text", "text": "…" } ] }
Response:
{ "outcome": "injected" }
injected means the prompt joined the turn that is currently running. Both adapters also define a startedNewTurn outcome for the case where the target turn had already finished.
One caveat worth avoiding from the start
In claude-agent-acp, the startedNewTurn path starts a detached turn: it emits session/update notifications, but no ACP request owns its lifecycle, so its terminal response is discarded and hosts cannot reliably consume or cancel it (see claude-agent-acp#903, and the proposed opt-in host-owned fallback in PR #919: _meta.steering.idleBehavior: "promptRequired" → a promptRequired outcome that leaves the content unconsumed).
Since Kimi would be implementing this fresh, it can skip that problem entirely: when there is no live turn to steer, leave the content unconsumed and let the host submit it as a normal session/prompt. Steering is an operation on an in-flight turn, not an alternative way to start one. Whatever signal you choose for "no live turn" (a distinct outcome value, or an error the host can branch on) is fine from our side — the important part is that the host keeps ownership of the new turn's lifecycle.
Why it matters
We are building a desktop client that drives Claude Code, Codex and Kimi Code through a single ACP transport. Our message-queue feature lets users type while a turn is running; a queued message can either wait for the turn to end or be sent immediately. Capability is detected at runtime from _meta.steering.supported, with no per-vendor branching — so the moment kimi acp advertises it, Kimi users get the same behaviour with no changes on our side. Until then, Kimi is the only one of the three where "send now" has to degrade to "send next".
Question
Would you accept a PR for this? If so, we are happy to prepare it (adapter method + _meta advertisement + tests). We wanted to align on the shape first, per CONTRIBUTING.md.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/acp-adapter/**, compare AcpSession.prompt() with the existing Session.steer() entry point in packages/node-sdk/src/session.ts, and review the steering smoke test in packages/node-sdk/examples/kimi-harness-steer-smoke.ts. Add the ACP advertisement, request mapping, outcomes, and tests; done means an in-flight turn accepts steering while content is left unconsumed when no turn is active.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100