fix(vscode): reuse the existing runtime when session opens race - #2800
Open
matthiasgoergens wants to merge 1 commit into
Open
fix(vscode): reuse the existing runtime when session opens race#2800matthiasgoergens wants to merge 1 commit into
matthiasgoergens wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 6839ebc The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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
force-pushed
the
fix/vscode-duplicate-session-wrap
branch
from
August 11, 2026 11:06
e39972a to
f8855b6
Compare
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
force-pushed
the
fix/vscode-duplicate-session-wrap
branch
from
August 11, 2026 14:08
f8855b6 to
6839ebc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.getcheck before either registers, andwrapSessionunconditionally overwrites the map entry. The orphanedSessionRuntimekeeps itsonEventsubscription (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
wrapSessionreturns the existing runtime when the session already has one, instead of blindly overwriting. The loser's freshly resumedSessionhandle is inert until wrapped — its constructor registers nothing, and listeners/handlers are only installed by theSessionRuntimeconstructor — 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).wrapSessionreportsreusedand both call sites then runreconcileWrappedApproval, 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
openSessioncalls for the same session id end up on the same runtime, with exactly one event subscription and oneContentPartbroadcast per view per delta — fails without the fix; (2) racing opens with differentyoloModevalues 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
gen-changesetsskill, or this PR needs no changeset. (changeset included:kimi-codepatch)gen-docsskill, or this PR needs no doc update.