Skip to content

Improve speed and responsiveness for code entered or sent to the Console - #15078

Merged
jmcphers merged 28 commits into
mainfrom
feature/reduce-console-roundtrips
Aug 7, 2026
Merged

Improve speed and responsiveness for code entered or sent to the Console#15078
jmcphers merged 28 commits into
mainfrom
feature/reduce-console-roundtrips

Conversation

@jmcphers

Copy link
Copy Markdown
Collaborator

Fixes #8915

Summary

This PR holistically addresses a number of performance and responsiveness problems around running and sending code to the console, especially in Workbench and Remote SSH scenarios.

It has the following goals:

  • When you make a gesture to run code, it will always be visually acknowledged in some way within 400ms.
  • When Positron is waiting on a step to prepare code for submission, it is displayed visually and can be canceled.
  • There should be no redundant checks for completeness or statement boundaries.

Previously, pressing Enter in the Console triggered up to three separate is_complete_request roundtrips to the kernel (Enter handler, enqueueCode, and the pending-input queue drain), each of which is especially costly on remote configurations, and none of which gave the user any feedback or a way to cancel while it was in flight.

This PR introduces a single submission entry point (submitCode) on the Console instance that chooses the cheapest available completeness strategy:

  • Input boundary provider (Flow 1) - when the language registers an InputBoundaryProvider (R does, via Ark), the input is split locally over LSP with no kernel queue. Complete statements are executed and queued individually as pre-verified fragments (so the queue drain no longer re-checks each one); an incomplete tail yields a continuation prompt; an invalid fragment executes the whole input as-is so the interpreter surfaces
    the error.
  • Unprocessed mode (Flow 2) - when no provider matches (e.g. Python), code is sent with a new Unprocessed execution mode. The supervisor (running in the possibly-remote extension host) performs the is_complete_request itself before execute_request, eliminating the client-to-remote roundtrip. Incomplete code rejects with CodeIncompleteError and the Console shows the continuation prompt.
  • Setting off (Flow 3) - with console.promptWhenIncomplete disabled, code runs immediately with no completeness check at all. This makes execution very snappy for people who don't want prompting.

When the code is sent to the console from the Editor via a statement range provider, we now skip the completeness check entirely (Flow 3), making this common path more responsive.

Submission is now observable state on the Console instance with debounced visuals: at 400ms the input dims slightly and a green barber pole appears; at 1000ms a "Submitting..." overlay with a Cancel button appears bottom-right.

image

The action bar stop button and Ctrl+C both cancel the in-flight submission (which also aborts the supervisor-side check for Flow 2). The Unprocessed mode is an internal wire detail only - accepted executions are reported as Interactive in onDidExecuteCode.

To support this, LanguageRuntimeSession.execute() is now awaitable end to end (Thenable<void> | void) so a completeness rejection can propagate back across the RPC boundary, identified by error.name
(CodeIncompleteError / ExecutionCancelledError).

Release Notes

New Features

Bug Fixes

Validation Steps

@:console @:ark

R (input boundary provider path):

  1. Type several statements on one line and submit: print("a") <CR> Sys.sleep(4) <CR> print("B") both execute with interleaved echo; the second appears as a dimmed queued pending-input item, then runs.
  2. Type an incomplete expression and press Enter: f <- function( -> a continuation prompt appears and nothing executes. Confirm the barber pole does NOT flicker for fast checks (< 400ms).

Python (Unprocessed path):

  1. Type def f(): and press Enter -> a continuation prompt appears.
  2. Complete the function body and submit -> it executes.

Submission feedback / cancel (any language, simulate a slow check):

  1. On a slow or hung completeness check: after ~400ms the input dims with a green barber pole; after ~1s a "Submitting... [Cancel]" overlay appears bottom-right and the stop button appears in the action bar.
  2. Click Cancel, press the stop button, or press Ctrl+C -> the input becomes editable again with its text intact and nothing is executed.

Setting / regression:

  1. Set console.promptWhenIncomplete to false -> incomplete input submits immediately and the interpreter reports the syntax error; no dim/barber pole appears.
  2. Regression: Shift+Enter inserts a newline; history navigation works; Cmd+Enter execution from the editor works; Assistant executions work.

@github-actions

Copy link
Copy Markdown

E2E Tests 🚀
This PR will run tests tagged with: @:critical @:console @:ark @:interpreter @:sessions @:positron-notebooks @:packages-pane @:quarto @:connections

Why these tags?
Tag Source
@:critical Always runs (required)
@:console PR description
@:ark PR description
@:interpreter Changed files
@:sessions Changed files
@:positron-notebooks Changed files
@:packages-pane Changed files
@:quarto Changed files
@:connections Changed files

More on automatic tags from changed files.

Warning

This PR touches a Positron directory that isn't mapped in test-tag-paths-map.json: src/vs/editor/contrib/positronInputBoundaries/. Add an entry (an e2e tag or [] for no coverage) so future changes are tagged automatically.

readme  valid tags

@jmcphers
jmcphers requested a review from seeM August 5, 2026 17:25

@seeM seeM left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am still reading through the code, but did some manual tests and found a possible issue with the responsiveness improvements where code disappears.

R multiple ✅

Screen.Recording.2026-08-06.at.19.35.59.mov

R incomplete ✅

Screen.Recording.2026-08-06.at.19.40.18.mov

Python incomplete ✅

Screen.Recording.2026-08-06.at.19.42.32.mov

Responsiveness

I added a 5 second timeout to the beginning of PositronConsoleInstance.tryProvideInputBoundaries and ran code.

The code disappears after I press Enter, and only reappears when the 5 seconds completes. So there is also no barber pole. ❎

Could be that I am putting the timeout at the wrong place?

Screen.Recording.2026-08-06.at.19.53.09.mov

The "Submitting" popup shows, and clicking "Cancel" does cancel the execution and repopulate the console input box. ✅

Screen.Recording.2026-08-06.at.19.54.30.mov

1 frame flicker

There is a momentary (~1 frame) flicker when I press Enter in both R cases. I am sensitive to flickers like that but it doesn't seem to bother most. It could also be related to the code disappearing above.

Frame before enter:

Image

Frame immediately after enter:

Image

Next frame:

Image

@seeM

seeM commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

It can also dim the wrong text if I type while the code is being submitted.

Screen.Recording.2026-08-06.at.20.14.25.mov

@seeM seeM left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code changes look good as best as I could read given the size of the PR. I think this one may be best tested with exposure in dailies.

Comment thread src/vs/workbench/services/positronConsole/browser/positronConsoleService.ts Outdated
Comment thread src/vs/workbench/contrib/positronConsole/browser/components/consoleInput.tsx Outdated
@jmcphers
jmcphers force-pushed the feature/reduce-console-roundtrips branch from 670ad54 to a4213b5 Compare August 7, 2026 00:07

@seeM seeM left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good! I found one more non-blocking edge case, which again might just be because of where I added the 5 sec timeout (tryProvideInputBoundaries). I tried to execute multiple statements waiting <5s between each attempt. It extends the pending state and the restarts the "Submitting" popup debounce timer (and the interrupt button debounce timer), so I only get a result when all executions finish.

Screen.Recording.2026-08-07.at.19.53.01.mov

@jmcphers

jmcphers commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

I tried to execute multiple statements waiting <5s between each attempt. It extends the pending state and the restarts the "Submitting" popup debounce timer (and the interrupt button debounce timer), so I only get a result when all executions finish.

This is intentional, and it is somewhat necessary because during the 5s, we don't know if the input is complete or not. So imagine you did this:

  1. type os.getenv(
  2. press Enter
  3. finish the statement by typing "PATH")

Until the 5s finishes, we don't know whether the first thing you typed and the second thing you typed go together or not.

It is harmless if we guess that they go together and they don't, but it is harmful if we guess that they don't go together and they do (you will get a syntax error and a continuation prompt). So the approach we take is that if you submit more stuff before we are finished analyzing what you've already submitted, we restart the evaluation with the new code.

@jmcphers
jmcphers merged commit 2da43f3 into main Aug 7, 2026
46 checks passed
@jmcphers
jmcphers deleted the feature/reduce-console-roundtrips branch August 7, 2026 23:26
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Console: Reduce code execution latency by reducing roundtrips

2 participants