Skip to content

feat: add stream cancellation support for R and Python#241

Merged
cpsievert merged 17 commits into
mainfrom
feat/stream-cancellation
May 27, 2026
Merged

feat: add stream cancellation support for R and Python#241
cpsievert merged 17 commits into
mainfrom
feat/stream-cancellation

Conversation

@cpsievert
Copy link
Copy Markdown
Contributor

Summary

Adds the ability to cancel in-progress LLM response streams in both R and Python. When a user sends a message, a stop button now appears during streaming — clicking it (or pressing Escape) cooperatively cancels the response.

  • Both packages wire up cancellation inside their Shiny module servers, so app authors get it automatically with no extra code
  • Includes Playwright tests verifying the stop button appears, cancellation works, and subsequent messages still function after a cancel

Dependency bumps

Package Old New Why
chatlas (Python) >= 0.13.2 >= 0.18.0 StreamController class
shinychat (Python) >= 0.3.1 >= 0.4.0 enable_cancel param in chat_ui()
shinychat (R) >= 0.3.0 >= 0.4.0 enable_cancel param in chat_ui()
ellmer (R) >= 0.3.0 >= 0.4.1 stream_controller()

Note: shinychat 0.4.0 hasn't been released yet in either language. Python is temporarily installed from GitHub via [tool.uv.sources]; R requires a dev install (pak::pak("posit-dev/shinychat/pkg-r")).

Test plan

  • Playwright: stop button appears during streaming
  • Playwright: clicking stop cancels the response and shows "Response cancelled"
  • Playwright: can send another message after cancelling
  • Manual: verify R cancellation works with dev shinychat/ellmer

Users can now cancel in-progress LLM responses via a stop button that
appears during streaming. This leverages shinychat's enable_cancel UI
and cooperative cancellation via ellmer::stream_controller() (R) and
chatlas.StreamController (Python).

Dependency bumps:
- chatlas >= 0.18.0 (StreamController)
- shinychat >= 0.4.0 (enable_cancel)
- ellmer >= 0.4.1 (stream_controller)
@cpsievert cpsievert marked this pull request as draft May 26, 2026 20:37
cpsievert and others added 4 commits May 26, 2026 15:38
- Add Remotes field to DESCRIPTION for dev shinychat from GitHub
- Add chat_cancel to mock input objects in unit tests
The dev shinychat on GitHub reports 0.3.0.9000, which doesn't satisfy
>= 0.4.0. Use >= 0.3.0.9000 until shinychat 0.4.0 is released.
Comment thread pkg-py/src/querychat/_shiny_module.py Outdated
Use input[f"{CHAT_ID}_cancel"] instead of hardcoded input.chat_cancel,
and make the test mock input subscriptable to support bracket access.

This comment was marked as resolved.

Python: use kwargs.setdefault() so callers can override.
R: accept enable_cancel as a named argument with default TRUE.
@cpsievert cpsievert requested a review from gadenbuie May 26, 2026 21:06
@cpsievert cpsievert marked this pull request as ready for review May 26, 2026 21:06
cpsievert added 9 commits May 26, 2026 16:07
The cancel_app was nearly identical to 01-hello-app, and cancellation
is always enabled, so a separate app isn't needed.
These tests were deeply coupled to internal wiring (closure vars,
patched Shiny primitives, fake sessions). The Playwright E2E tests
cover the same user-visible behavior through the real stack.
The viz tests depend on LLM reliably producing tool calls, which is
inherently non-deterministic. This flakiness also occurs on main
(see runs from May 14). Bump reruns from 2 to 4 and timeout from
30 to 45 minutes.
The viz example app had no static greeting, so the LLM generated one
via stream_async on startup. Tests didn't wait for this greeting stream
to finish before sending user input, causing two concurrent streams on
the same Chat object — corrupting conversation history and producing
flaky failures (especially under parallel workers and with shinychat
0.4.0's new cancel button).

- Add greeting-viz.md with a static greeting for the titanic viz app
- Update 10-viz-app.py and viz_bookmark_app.py to use the static greeting
- Wait for greeting text to render before sending test input
- Remove bookmark test's dependency on greeting triggering a bookmark
  (static messages may not trigger bookmark_on="response" due to
  ignore_init timing)
The increased reruns (2→4) and timeout (30→45 min) were a workaround
for flaky viz tests caused by the LLM-generated greeting race condition,
which is now fixed by the static greeting approach.

This comment was marked as resolved.

@cpsievert cpsievert merged commit 9e8ef7e into main May 27, 2026
18 checks passed
@cpsievert cpsievert deleted the feat/stream-cancellation branch May 27, 2026 03:13
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.

2 participants