Skip to content

fix(vscode): stop mid-turn core errors from corrupting the active turn - #1807

Merged
wbxl2000 merged 2 commits into
mainfrom
fix/vscode-reentrant-turn-guard
Jul 17, 2026
Merged

fix(vscode): stop mid-turn core errors from corrupting the active turn#1807
wbxl2000 merged 2 commits into
mainfrom
fix/vscode-reentrant-turn-guard

Conversation

@wbxl2000

Copy link
Copy Markdown
Collaborator

Related Issue

None — reported from user feedback: during a running turn the extension surfaced Internal error occurred: A response is already being generated for this session. and showed a Retry button while the turn was still alive.

Problem

Two host-side flaws chained into that corruption:

  1. The core emits non-fatal error events mid-turn (e.g. records.write_failed, MCP tool-name collisions, compaction failures). The extension forwarded them to the Webview as plain turn-ending errors: the composer unlocked, Retry appeared, and queued messages auto-flushed after 50ms. The next send then collided with the still-active turn.
  2. When that collision hit the re-entrancy guard in SessionRuntime.runTurnAction, the catch path settled the original, still-running prompt as failed — orphaning the live engine turn and displaying the internal already being generated error.

What changed

  • SessionRuntime.runTurnAction: a busy call now fails only itself, emitting a non-terminal warning, and never touches this.activePrompt. The catch also only settles the prompt this call created (previously, when the event pipeline had already settled it, a duplicate error was emitted).
  • SessionRuntime.onSdkEvent: core errors forwarded while the active turn is started are marked terminal: false on the wire (StreamError.terminal is documented in shared/types.ts).
  • Webview chat.store: error events with terminal: false are shown as a transient toast and never touch isStreaming, the pending input, or the message queue — the composer only unlocks on stream_complete or genuine terminal errors. This mirrors the TUI, where busy state is driven solely by turn lifecycle events.
  • beginHostAction reuses the shared busy message constant; no behavior change.

Tests

  • test/kimi-runtime.test.ts: fake-session emit/prompt knobs added; new cases cover reentrant-prompt rejection, mid-turn error marking (terminal: false, turn survives to completion), and unchanged preflight-failure behavior.
  • test/kimi-harness.integration.test.ts: real-stack reproduction — a concurrent prompt during a running turn returns failed, the original turn still finishes, isBusy stays correct throughout.
  • test/settings-store.test.ts: non-terminal error shows a toast, keeps the composer locked and the queue intact; the following stream_complete still flushes the queue.
  • Full suite: 279 passed; typecheck clean; no new oxlint warnings.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my fix works.
  • Ran gen-changesets skill, or this PR needs no changeset. → Needs none: the VS Code extension (apps/vscode, private package) is versioned manually outside the changesets flow; the fix rides the next extension release.
  • Ran gen-docs skill, or this PR needs no doc update. → No doc change: this restores the intended error-handling behavior instead of introducing new UX.

@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 08c3637

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d9332b096

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +183 to +186
if (this.isBusy) {
throw new Error("A response is already being generated for this session.");
// A re-entrant turn request must never disturb the active turn: surface
// the rejection as a mid-turn warning and fail only this call.
this.emitError(new Error(ALREADY_GENERATING_MESSAGE), "runtime", { terminal: false });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat exclusive-operation rejections as terminal

When isBusy is true solely because exclusiveActionActive is set, there is no active turn whose eventual stream_complete can clear this non-terminal warning. This occurs, for example, when another Webview sends a prompt while ForkKimiSession is materializing a fork through runExclusiveAfterCancelling; that Webview sets isStreaming before sending, ignores this warning for lifecycle purposes, and remains locked indefinitely. Emit terminal: false only when hasActiveWork guarantees a later terminal event, and reject exclusive-only conflicts as terminal.

Useful? React with 👍 / 👎.

@pkg-pr-new

pkg-pr-new Bot commented Jul 17, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@08c3637
npx https://pkg.pr.new/@moonshot-ai/kimi-code@08c3637

commit: 08c3637

@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08c3637b40

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

this.emitError(
new Error(ALREADY_GENERATING_MESSAGE),
"runtime",
{ terminal: this.hasActiveWork ? false : undefined },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Settle only the rejected caller's request

When two Webviews send nearly simultaneously, or a newly attached Webview sends while another view's turn is active, this marks the busy rejection as non-terminal and emitError broadcasts it to every subscriber. The rejected caller therefore remains in isStreaming; when the original turn later broadcasts stream_complete, that caller clears its own pendingInput and silently loses the message that was never submitted. If the active work is a host action that fails, no shared completion is emitted and the caller can remain locked indefinitely. The busy rejection needs to terminally settle only the initiating Webview without disturbing the existing turn.

Useful? React with 👍 / 👎.

@wbxl2000
wbxl2000 merged commit 1a5c0de into main Jul 17, 2026
17 checks passed
@wbxl2000
wbxl2000 deleted the fix/vscode-reentrant-turn-guard branch July 17, 2026 06:40
@wbxl2000 wbxl2000 mentioned this pull request Jul 17, 2026
5 tasks
7723qqq pushed a commit to 7723qqq/kimi-code that referenced this pull request Jul 17, 2026
MoonshotAI#1807)

* fix(vscode): stop mid-turn core errors from corrupting the active turn

* fix(vscode): reject prompts during exclusive operations with a terminal error
ywh114 pushed a commit to ywh114/kimi-code that referenced this pull request Jul 19, 2026
MoonshotAI#1807)

* fix(vscode): stop mid-turn core errors from corrupting the active turn

* fix(vscode): reject prompts during exclusive operations with a terminal error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant