Skip to content

fix(vscode): reuse the existing runtime when session opens race - #2800

Open
matthiasgoergens wants to merge 1 commit into
MoonshotAI:mainfrom
matthiasgoergens:fix/vscode-duplicate-session-wrap
Open

fix(vscode): reuse the existing runtime when session opens race#2800
matthiasgoergens wants to merge 1 commit into
MoonshotAI:mainfrom
matthiasgoergens:fix/vscode-duplicate-session-wrap

Conversation

@matthiasgoergens

@matthiasgoergens matthiasgoergens commented Aug 11, 2026

Copy link
Copy Markdown

Related Issue

Resolve #2799

Problem

See linked issue. When two views race to open the same session (sidebar + editor tab, or a window reload overlapping a reattach), both get past the sessions.get check before either registers, and wrapSession unconditionally overwrites the map entry. The orphaned SessionRuntime keeps its onEvent subscription (and its approval/question handler registrations, which the SDK rpc layer keys by session id), so both runtimes adapt and broadcast every event — and a view subscribed in both receives every streamed part twice, rendered as strictly interleaved duplicated text ("TheThe roaring roaring …").

What changed

  • wrapSession returns the existing runtime when the session already has one, instead of blindly overwriting. The loser's freshly resumed Session handle is inert until wrapped — its constructor registers nothing, and listeners/handlers are only installed by the SessionRuntime constructor — so it can simply be dropped. It is deliberately not closed: Session.close() closes the shared engine-side session by id, which would kill it for the winning runtime. The error paths guard this too: a failing setup or reconciliation on the losing handle never closes the shared session (review feedback).
  • Because the losing call may already have written its own approval state (metadata + permission) onto the shared engine session before reaching the guard, wrapSession reports reused and both call sites then run reconcileWrappedApproval, which re-asserts the surviving runtime's approval flags on the engine session — engine permission, persisted metadata, and the runtime's flags always end up consistent (review feedback).

Regression tests: (1) two concurrent openSession calls for the same session id end up on the same runtime, with exactly one event subscription and one ContentPart broadcast per view per delta — fails without the fix; (2) racing opens with different yoloMode values leave the engine permission and persisted metadata matching the surviving runtime's flags; (3) a failing reconciliation on the losing handle does not close the shared session — fails without the guard.

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. (changeset included: kimi-code patch)
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6839ebc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

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

@matthiasgoergens
matthiasgoergens force-pushed the fix/vscode-duplicate-session-wrap branch from e39972a to f8855b6 Compare August 11, 2026 11:06
Two concurrent opens of the same session (sidebar + editor tab, or a
reload overlapping a reattach) both passed the sessions.get check,
resumed, and wrapped: wrapSession unconditionally overwrote the map
entry, orphaning the first SessionRuntime with its event subscription
still live. Both runtimes then adapted and broadcast every SDK event,
and a view subscribed in both received each streamed part twice —
visible as interleaved duplicated assistant text in the chat.

wrapSession now returns the existing runtime when the session already
has one. A resumed Session handle is inert until wrapped (its
constructor registers nothing; listeners and approval/question
handlers are only installed by the SessionRuntime constructor), so the
loser's handle can simply be dropped — and must not be closed, since
close() would tear down the shared engine session.

Fixes MoonshotAI#2799
@matthiasgoergens
matthiasgoergens force-pushed the fix/vscode-duplicate-session-wrap branch from f8855b6 to 6839ebc Compare August 11, 2026 14:08
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.

[VSCode] Streamed output duplicated/interleaved when two views race to open the same session

1 participant