MoonshotAI / MoonshotAI/kimi-code

web: steered message reappears as ghost user bubble after turn ends (0.43.0 regression)

Open
#3,806 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

Symptom

In the web UI (kimi web), when a message is sent with steer while a turn is running, the steered message renders in place during the turn — but after the turn ends, a second, inert copy of the same user message appears at the bottom of the conversation. It never triggers an agent reply; it is purely a rendering artifact. It disappears once a newer turn starts.

Root cause

Since #3747 (refactor(agent-core-v2): fold the prompt queue into the agent loop service), AgentLoopService dispatches TurnSteer before PromptSteered (packages/agent-core-v2/src/agent/loop/loopService.ts, promptSteered case).

The transcript projector in kap-server (packages/kap-server/src/services/transcript/coreEventMap.ts) pairs a steered user frame with its prompt ids through a FIFO (unpairedSteerPromptIds) that is filled by prompt.steered and drained by turn.steer. With the reversed order the queue is always empty when the frame is emitted, so the frame goes out with promptIds: undefined. Session event journals confirm the regression: turn.steer is consistently journaled one seq before prompt.steered.

The web UI keeps a completed + steered prompt record (finishedAt === steeredAt) and, finding no timeline frame carrying that promptId, synthesizes a fallback optimistic user bubble (msg_opt_steer_<promptId>) appended after the timeline — the ghost.

Verified against a live 0.43.0 server: GET /api/v1/sessions/{id}/transcript shows the steered user frame(s) without promptIds, while the prompts ledger carries the steered prompt with finishedAt === steeredAt.

Secondary bug found while investigating

onPromptSteered in coreEventMap.ts overwrites the active prompt's content with the steered content (content: projectPromptContentParts(event.content)), corrupting the running prompt's ledger entry.

Proposed fix

  • Dispatch PromptSteered before TurnSteer in loopService, restoring the order the transcript projector and its tests were written against.
  • Keep the active prompt's own content in onPromptSteered.

I have the fix ready with regression tests and will open a PR.

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 with the promptSteered case in packages/agent-core-v2/src/agent/loop/loopService.ts and the projector in packages/kap-server/src/services/transcript/coreEventMap.ts. Trace the event ordering and onPromptSteered handling, then run the regression tests mentioned in the issue. Done means the steered frame retains its prompt id, no ghost bubble appears, and the active prompt content remains intact.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.