MoonshotAI / MoonshotAI/kimi-code

ACP: session/set_mode "plan" fails with -32603 "Already in plan mode" after session/new reports currentModeId "default"

Open
#3,356 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

Summary

Over ACP, session/set_mode with modeId: "plan" fails with -32603 Internal error ("Already in plan mode") immediately after session/new reports currentModeId: "default". The session state reported to the client and the server's internal state contradict each other, so ACP clients that set an explicit mode after session creation fail to create the session at all.

Environment

  • kimi-code versions: 0.39.0 and 0.39.1 (both reproduce)
  • Platform: Windows 10 (install via official installer / npm i @moonshot-ai/kimi-code)
  • Client: raw ACP over stdio (reproduced below); originally hit through Paseo 0.6.1

Steps to reproduce

  1. Start kimi acp.
  2. initialize with protocolVersion: 1.
  3. session/new (any cwd). Response contains:
"modes": {"currentModeId": "default", "availableModes": [
  {"id": "default"}, {"id": "plan"}, {"id": "auto"}, {"id": "yolo"}]}
  1. session/set_mode with {"sessionId": "<id>", "modeId": "plan"}.

Expected

set_mode plan succeeds (mode switches default → plan), or — if the session really is in plan mode already — session/new should report currentModeId: "plan" so clients skip the redundant set.

Actual

{"jsonrpc": "2.0", "id": 20, "error": {"code": -32603, "message": "Internal error",
  "data": {"details": "Already in plan mode"}}}

Note: set_mode auto works fine on the same session, so this is specific to plan.

Minimal repro (Python, stdlib only, no model call / no quota consumed)

import json, subprocess, threading, queue, time

proc = subprocess.Popen(["kimi", "acp"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
q = queue.Queue()
threading.Thread(target=lambda: [q.put(l.decode().strip()) for l in proc.stdout], daemon=True).start()

def send(o): proc.stdin.write((json.dumps(o) + "\n").encode()); proc.stdin.flush()
def wait(rid, t=20):
    end = time.time() + t
    while time.time() < end:
        try: line = q.get(timeout=max(0.1, end - time.time()))
        except queue.Empty: return None
        if line:
            m = json.loads(line)
            if m.get("id") == rid: return m

send({"jsonrpc": "2.0", "id": 1, "method": "initialize",
      "params": {"protocolVersion": 1, "clientCapabilities": {}}})
wait(1)
send({"jsonrpc": "2.0", "id": 2, "method": "session/new",
      "params": {"cwd": ".", "mcpServers": []}})
r = wait(2)
print("currentModeId:", r["result"]["modes"]["currentModeId"])   # -> "default"
sid = r["result"]["sessionId"]
send({"jsonrpc": "2.0", "id": 3, "method": "session/set_mode",
      "params": {"sessionId": sid, "modeId": "plan"}})
print(wait(3))  # -> error -32603 "Already in plan mode"
proc.kill()

Impact

ACP hosts that apply a configured mode right after session/new (standard flow in Paseo's ACP adapter) abort session creation entirely, so plan mode is unusable through ACP clients even though it works in the interactive CLI.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start the kimi acp entry point and trace the session/new and session/set_mode handlers, comparing the reported currentModeId with the server's stored mode. Reproduce the sequence with the provided Python stdlib script; done means default followed by set_mode to plan succeeds, or both responses consistently report plan.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.