Support session init hooks (mostly motivated by R)#12312
Merged
Conversation
|
E2E Tests 🚀 |
9cbc7df to
536a796
Compare
4a244e3 to
9c2f8a7
Compare
9c2f8a7 to
d2d35f4
Compare
This reverts commit 4a244e3.
The opening of the UI comm signals to the runtime that the frontend is ready. Include `console_width` and `start_type` in the `comm_open` data. Allows the runtime to set the console width (existing behaviour) and to fire session init hooks with the appropriate data (new behaviour).
This reverts commit 4a244e3.
d2d35f4 to
6655e7b
Compare
positron.session_init, positron.session_reconnect)
positron.session_init, positron.session_reconnect)
jmcphers
previously approved these changes
Apr 1, 2026
Collaborator
jmcphers
left a comment
There was a problem hiding this comment.
This looks and works great for me. I'm seeing all 3 start types (new, restart, reconnect) fire correctly, and verified that console width is still getting tracked correctly at attach and resize.
jennybc
added a commit
to posit-dev/ark
that referenced
this pull request
Apr 1, 2026
#1088) Addresses posit-dev/positron#9763 Closes #697 Companion PR in Positron: posit-dev/positron#12312 (see there for full context, background, and QA instructions) ## Summary Adds R session init hooks that fire after the frontend is fully connected, so that rstudioapi functions (including those that make RPCs back to the frontend, like `getActiveProject()`) work from hook code. ### Hook design (two hooks) - **`positron.session_init(start_type)`** -- fires on new sessions and restarts - `start_type = "new"` for new sessions - `start_type = "restart"` for restarted sessions - **`positron.session_reconnect()`** -- fires on reconnects only (e.g. window reload) These are analogous to RStudio's [`rstudio.sessionInit`](https://rstudio.github.io/rstudioapi/articles/r-session.html). Users register hooks in `.Rprofile` via `setHook()`. ### The originator problem and fix rstudioapi functions like `getActiveProject()` make synchronous RPCs back to the frontend. These RPCs require a Jupyter message originator so replies can be properly parented. Previously, only `ExecuteRequest` handlers set an originator -- `comm_msg` handlers did not. Since the `frontend_ready` signal arrives as a `comm_msg` on the UI comm, hooks fired from that context couldn't make frontend RPCs. This PR threads the originator from the `comm_msg` Jupyter message through to the R thread: - **amalthea**: `handle_comm_msg` trait method gains an `originator` parameter; `shell.rs` creates `Originator` from the `comm_msg` request header - **ark**: `KernelRequest::CommMsg` carries the originator; `Console` temporarily sets `comm_msg_originator` during `comm_handle_msg`; `call_frontend_method()` falls back to `comm_msg_originator` when there is no `active_request` ### Other changes - **`comm_open` data**: `handle_comm_open` trait method gains a `data` parameter. The UI comm deserializes this into a typed `UiCommOpenData` struct and reads `console_width` from it to set immediately (replacing the old `setConsoleWidth` RPC from `positron-r`). - **`frontend_ready` handler**: Dispatches to `.ps.run_session_init_hooks(start_type)` or `.ps.run_session_reconnect_hooks()` based on `start_type`. - **`hooks.R`**: Two new internal functions with tryCatch error isolation per hook. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Lionel Henry <lionel.hry@proton.me>
Signed-off-by: Jennifer (Jenny) Bryan <jenny.f.bryan@gmail.com>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Addresses #9763
Addresses posit-dev/ark#697
Requires this companion PR in ark: posit-dev/ark#1088
Summary
Adds infrastructure for R session init hooks that fire after the frontend is fully connected to the runtime. This enables a user or admin to store code in
.Rprofilethat drives the UI or requires two-way communication with the frontend.Two main changes:
comm_opendata carries{ console_width, start_type }when the UI comm opens. The runtime usesconsole_widthimmediately (no separate RPC needed).start_typeis informational/logging. (This is not load-bearing for session init hooks. Rather, it's a little goodie I kept from my second approach to this problem. We had hoped to fire session init hooks during UI comm opening, but it just doesn't work. It's too early. But this does feel like the right way to inform the backend of the initial console width.)frontend_readyRPC is sent aftercomm_opensucceeds. The runtime uses this signal to fire session hooks. This is a separate step fromcomm_openbecause the hooks may need to make RPCs back to the frontend, which requires the comm to be fully registered first. (This is basically a return to my first approach to the problem. Even more work was required in ark and is described in that PR.)Start type mapping
RuntimeStartModeis an internal Positron enum.start_typeis the external value sent to the runtime via thefrontend_readyRPC, which the runtime uses to decide which hooks to fire.RuntimeStartMode(Positron internal)start_type(runtime-facing)Starting"new"Switching"new"Restarting"restart"Reconnecting"reconnect"Changes
ui-backend-openrpc.json: Addedfrontend_readyRPC withstart_typeparam. Ran codegen (npx tsx generate-comms.ts ui), which updatedpositronUiComm.ts,ui_comm.py, andui_comm.rs(in ark).languageRuntimeUiClient.ts: AddedfrontendReady()wrapper onUiClientInstance(the generated method lives onPositronUiCommbut callers go throughUiClientInstance).activeRuntimeSession.ts: TracksstartModeonActiveRuntimeSession. NewgetStartType()maps it to runtime-facing values.startUiClientImpl()passes{ console_width, start_type }incomm_opendata (previously{}). SendsfrontendReady(startType)after comm setup completes.runtimeSession.ts: ThreadsstartModethroughattachToSession()and updates it when a restart is detected.positron-r/session.ts: RemovedsetConsoleWidth()(now handled viacomm_opendata on the ark side).Background
This enables runtime-side session init hooks, inspired by RStudio's
rstudio.sessionInit. See the ark companion PR for the runtime-side implementation. Relevant docs re: RStudio:What sorts of things do people do in
rstudio.sessionInit? Special thanks to @jthomasmock for helping gather this list. It's worth noting that session init hooks are much more relevant in a Workbench/enterprise context than desktop/individual user.rstudioapi::navigateToFile(). This has been my main manual test case. However, since it's "fire and forget", it can't be the only test case.rstudioapi::getActiveProject(). This turns out to be a very important use case to test.renv::restore(), after an OS upgrade. Note that the hook itself does not detect the OS upgrade. But if the upgrade has been detected, the hook gets registered. This example is from Posit Cloud.Release Notes
New Features
positron.session_initandpositron.session_reconnectare new hooks that are executed in the R session, once R startup is complete and Positron is fully operational and able to handle requests that pertain to the UI, such as rstudioapi calls. This duo is intended to be analogous to RStudio'srstudio.sessionInit. Apositron.session_inithook function should accept astart_typeparameter, with possible values"new"or"restart". Apositron.session_reconnecthook takes no input.Bug Fixes
QA Notes
Temporarily make this your
.Rprofile(requires ark built from companion PR) and make sure the current folder has aDESCRIPTIONfile.Click to expand
In each case,
DESCRIPTIONshould be opened in the editor viarstudioapi::navigateToFile(). Here's what you should see in the Console, up to whatever your console width and active project are.New session (
start_type = "new"):Restart R (
start_type = "restart"):Reload window (
start_type = "reconnect"):Notice that only the hook is being run, not the top-level
.Rprofilestatements.TODOs:
.Rprofilemessages so red?message()output during R startup appears red in Positron console ark#1101readline()ormenu()in a session init hook?menu()andreadline()don't work in positron session init hooks ark#1130