MoonshotAI / MoonshotAI/kimi-code

ACP adapter does not surface failed turns (non-auth failures resolve as end_turn, error only in session log)

Open
#1,865 1 comment 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

What issue are you seeing?

The ACP adapter does not surface a failed turn to the client. When a turn fails for a non-auth reason (e.g. a non-retryable upstream HTTP 400, a rate limit, an expired token after retries are exhausted), packages/acp-adapter/src/session.ts handles turn.ended with reason: 'failed' by calling log.warn(...) and then resolving session/prompt with stopReason: 'end_turn' (only auth-coded failures are routed to a JSON-RPC error via authRequiredFromPayload). The actual error is written to the session log (~/.kimi-code/sessions/.../logs/kimi-code.log) but is not exposed on the ACP wire — not on the JSON-RPC error channel, not as refusal, and not in PromptResponse.

Consequence for ACP orchestration clients (Multica, OpenCode, Claude Code running kimi as a backend): a genuinely failed turn is indistinguishable from a clean, empty completion. The client reports the task as successfully completed with no output, and the actionable error stays buried in the local log.

Concrete case that motivated this report: a session accumulated an empty assistant message, so every subsequent prompt got 400 the message at position N with role 'assistant' must not be empty. kimi acp exited 0 with no output; the orchestrator recorded status=completed, output_bytes=0 on each attempt — a silent no-op the user experienced as "Kimi returns nothing".

Related: #1855 (usage not reported over ACP). Both are ACP-adapter observability gaps; this one is about failure visibility.

What steps can reproduce the bug?
  1. Drive kimi over ACP (kimi acp) from any ACP client.
  2. Force a non-auth, non-retryable turn failure — e.g. resume a session whose history contains an empty assistant message (server returns 400 ... must not be empty), or otherwise trigger a 4xx that exhausts retries.
  3. Observe: session/prompt resolves with stopReason: end_turn, no error is delivered to the client, and the failure appears only in logs/kimi-code.log (WARN llm request failed ... statusCode=400).
What is the expected behavior?

A non-auth turn failure should be observable by the ACP client without reading kimi's local log — e.g. surface the error on the JSON-RPC error channel, or attach the failure payload to PromptResponse (the spec provides _meta for out-of-band data), or otherwise signal that the turn did not complete cleanly. As-is, clients cannot tell a failed turn from an empty successful one.

Additional information
  • Version: Kimi Code 0.26.0
  • Source pointer: packages/acp-adapter/src/session.ts, the turn.ended handler — reason === 'failed' non-auth branch resolves { stopReason: turnEndReasonToStopReason(...) } = end_turn, per the documented rationale in events-map.ts (ACP StopReason has no failed variant, so the failure is only logged).
  • Downstream: MoonshotAI/kimi-code#1855 (usage). Multica has landed a defensive daemon-side workaround (promote completed+empty+no-usage → failed), but the robust fix belongs here.

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 in packages/acp-adapter/src/session.ts at the turn.ended handler, then read the documented rationale in events-map.ts for StopReason mapping. Reproduce the failure with kimi acp using an empty assistant message or an exhausted non-auth retry, and verify that the ACP client can distinguish the failed turn from a clean empty completion without reading kimi-code.log.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.