fix(code): scope selection copy to the clicked screen - #5140
Merged
Mason Daugherty (mdrxy) merged 2 commits intoJul 29, 2026
Merged
fix(code): scope selection copy to the clicked screen#5140Mason Daugherty (mdrxy) merged 2 commits into
Mason Daugherty (mdrxy) merged 2 commits into
Conversation
Auto-copy on mouse-up scanned `App.query("*")`, which Textual roots at the
app's default (compose) screen. A selection left on the transcript therefore
kept being copied by clicks inside a modal, racing that modal's own copy
action (e.g. the Debug Console thread id) for the clipboard.
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Mason Daugherty (mdrxy)
marked this pull request as ready for review
July 29, 2026 14:43
Follow-up to the screen-scoping fix, from PR review. `copy_selection_to_clipboard` took `screen: Screen | None = None` and fell back to `app.screen`. That fallback was late-bound: it resolved the active screen at callback time, which is the exact semantics the scoping fix removed, so any future caller that omitted the argument would silently reintroduce the bug. Make `screen` required and drop the branch. Both empty-`screen_stack` guards go with it. Neither was reachable: `App.on_event` already dereferences `self.screen` unguarded to forward the `MouseUp`, and the only code that empties the stack runs after the message loop has stopped. Mutants deleting either guard killed no test. Close the coverage gap that mattered. The suite asserted only that a selection below a modal is *not* copied, never that the modal's own selection *is* — so an over-correction skipping modal screens entirely passed all 25 tests while breaking the feature the fix exists to protect (selecting the Debug Console thread id). Add a test covering both directions; that mutant now fails. Replace the default-screen test with one that passes a non-active screen while both screens hold selections, so it actually exercises the arg rather than coinciding with the old behavior. Docstrings stated conclusions rather than mechanisms: "the screen the release landed on" implied hit-testing when `self.screen` is simply top-of-stack, and the rationale leaned on private `App._get_dom_base`. Restate both in terms of Textual routing mouse events only to the top of the stack, and name the reproducible symptom (a spurious "copied" toast).
Mason Daugherty (mdrxy)
deleted the
mdrxy/code/scope-selection-copy-to-active-screen
branch
July 29, 2026 17:53
Marcelo5444
pushed a commit
to Marcelo5444/deepagents
that referenced
this pull request
Jul 30, 2026
) Clicking a copyable value in a modal (for example the thread id in the Debug Console) no longer fights with text still selected in the conversation behind it — only the value you clicked lands on the clipboard. --- Text selected with the mouse is auto-copied on mouse release, and that scan walked `App.query("*")`. Textual roots `App.query` at the app's *default* (compose) screen rather than the active one, so a selection left behind in the transcript stayed in scope even while a modal was on top. Any click inside the modal then produced two clipboard writes — the modal's own copy plus the stale transcript selection — and whichever landed last won. Selections are per-screen state, so the scan is now scoped to a single screen: `copy_selection_to_clipboard` takes an optional keyword-only `screen` (defaulting to the app's active screen), and the mouse-up handler pins it to the screen the release actually landed on. Background selections are left untouched and visible, matching the current behavior; they simply aren't copied by clicks that happened somewhere else. As a side effect, selections made *inside* a modal are now copyable, which the app-rooted scan never reached. The new regression tests drive a real selection through Textual's event path (triple-click via `Pilot`) with a modal pushed on top, and fail against the previous implementation. Made by [Open SWE](https://openswe.vercel.app/agents/bde43330-a625-d287-611f-af90f64dac82) --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Mason Daugherty (mdrxy)
pushed a commit
that referenced
this pull request
Jul 30, 2026
> [!CAUTION] > Merging this PR will automatically publish to **PyPI** and create a **GitHub release**. For the full release process, see [`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md). --- _Release notes preview: keep this section in sync with the package `CHANGELOG.md`. Publish reads the merged CHANGELOG via `release.yml`, not this PR description — keep them aligned anyway so the PR stays an accurate historical record for reviewers and anyone returning later._ --- ## [0.1.50](deepagents-code==0.1.49...deepagents-code==0.1.50) (2026-07-30) ### Highlights - Added project hooks workspace trust and expanded Hooks v2 support with client and server lifecycle events plus runtime feedback ([#5105](#5105), [#5104](#5104), [#4997](#4997), [#5045](#5045)). - Added an option to mute the “YOLO is active” toast ([#5103](#5103)). - Made the splash screen `thread` ID clickable to copy it ([#5173](#5173)). - Show `ask_user` answers directly on the answered tool row ([#5100](#5100)). - Show a toast when submitting an empty required `ask_user` answer ([#5095](#5095)). - Added thread message counts to the Debug Console ([#5117](#5117)). ### Fixes and improvements - Gated Hooks v2 behind `DEEPAGENTS_CODE_EXPERIMENTAL` and improved hook resume stability across identity and Command tool results ([#5146](#5146), [#5176](#5176)). - Kept server hook state out of task results ([#5164](#5164)). - Stopped duplicate Auto transcript events during interrupt replay ([#5157](#5157)). - Kept `/update` and `/install --package` prompts responsive ([#5127](#5127)). - Refreshed the `/threads` cache after each turn ([#5174](#5174)). - Anchored toasts above the chat input and added a toast when media is dropped into a free-text question ([#5101](#5101), [#5099](#5099)). - Improved thread status message styling and links ([#5118](#5118)). - Made resume hints echo the launched command name ([#5119](#5119)). - Scoped selection copy to the clicked screen ([#5140](#5140)). - Ignored mouse hits on detached widgets ([#5114](#5114)). _End release notes preview._ --- > [!NOTE] > A **New Contributors** section is appended to the GitHub release notes automatically at publish time (see [Release Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline), step 2). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: langchain-oss-automated-triage[bot] <248757908+langchain-oss-automated-triage[bot]@users.noreply.github.com> Co-authored-by: Johannes du Plessis <johannes@langchain.dev>
Mason Daugherty (mdrxy)
added a commit
that referenced
this pull request
Jul 30, 2026
Clicking a copyable value in a modal (for example the thread id in the
Debug Console) no longer fights with text still selected in the
conversation behind it — only the value you clicked lands on the
clipboard.
---
Text selected with the mouse is auto-copied on mouse release, and that
scan walked `App.query("*")`. Textual roots `App.query` at the app's
*default* (compose) screen rather than the active one, so a selection
left behind in the transcript stayed in scope even while a modal was on
top. Any click inside the modal then produced two clipboard writes — the
modal's own copy plus the stale transcript selection — and whichever
landed last won.
Selections are per-screen state, so the scan is now scoped to a single
screen: `copy_selection_to_clipboard` takes an optional keyword-only
`screen` (defaulting to the app's active screen), and the mouse-up
handler pins it to the screen the release actually landed on. Background
selections are left untouched and visible, matching the current
behavior; they simply aren't copied by clicks that happened somewhere
else. As a side effect, selections made *inside* a modal are now
copyable, which the app-rooted scan never reached.
The new regression tests drive a real selection through Textual's event
path (triple-click via `Pilot`) with a modal pushed on top, and fail
against the previous implementation.
Made by [Open
SWE](https://openswe.vercel.app/agents/bde43330-a625-d287-611f-af90f64dac82)
---------
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Mason Daugherty (mdrxy)
pushed a commit
that referenced
this pull request
Jul 30, 2026
> [!CAUTION] > Merging this PR will automatically publish to **PyPI** and create a **GitHub release**. For the full release process, see [`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md). --- _Release notes preview: keep this section in sync with the package `CHANGELOG.md`. Publish reads the merged CHANGELOG via `release.yml`, not this PR description — keep them aligned anyway so the PR stays an accurate historical record for reviewers and anyone returning later._ --- ## [0.1.50](deepagents-code==0.1.49...deepagents-code==0.1.50) (2026-07-30) ### Highlights - Added project hooks workspace trust and expanded Hooks v2 support with client and server lifecycle events plus runtime feedback ([#5105](#5105), [#5104](#5104), [#4997](#4997), [#5045](#5045)). - Added an option to mute the “YOLO is active” toast ([#5103](#5103)). - Made the splash screen `thread` ID clickable to copy it ([#5173](#5173)). - Show `ask_user` answers directly on the answered tool row ([#5100](#5100)). - Show a toast when submitting an empty required `ask_user` answer ([#5095](#5095)). - Added thread message counts to the Debug Console ([#5117](#5117)). ### Fixes and improvements - Gated Hooks v2 behind `DEEPAGENTS_CODE_EXPERIMENTAL` and improved hook resume stability across identity and Command tool results ([#5146](#5146), [#5176](#5176)). - Kept server hook state out of task results ([#5164](#5164)). - Stopped duplicate Auto transcript events during interrupt replay ([#5157](#5157)). - Kept `/update` and `/install --package` prompts responsive ([#5127](#5127)). - Refreshed the `/threads` cache after each turn ([#5174](#5174)). - Anchored toasts above the chat input and added a toast when media is dropped into a free-text question ([#5101](#5101), [#5099](#5099)). - Improved thread status message styling and links ([#5118](#5118)). - Made resume hints echo the launched command name ([#5119](#5119)). - Scoped selection copy to the clicked screen ([#5140](#5140)). - Ignored mouse hits on detached widgets ([#5114](#5114)). _End release notes preview._ --- > [!NOTE] > A **New Contributors** section is appended to the GitHub release notes automatically at publish time (see [Release Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline), step 2). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: langchain-oss-automated-triage[bot] <248757908+langchain-oss-automated-triage[bot]@users.noreply.github.com> Co-authored-by: Johannes du Plessis <johannes@langchain.dev>
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.
Clicking a copyable value in a modal (for example the thread id in the Debug Console) no longer fights with text still selected in the conversation behind it — only the value you clicked lands on the clipboard.
Text selected with the mouse is auto-copied on mouse release, and that scan walked
App.query("*"). Textual rootsApp.queryat the app's default (compose) screen rather than the active one, so a selection left behind in the transcript stayed in scope even while a modal was on top. Any click inside the modal then produced two clipboard writes — the modal's own copy plus the stale transcript selection — and whichever landed last won.Selections are per-screen state, so the scan is now scoped to a single screen:
copy_selection_to_clipboardtakes an optional keyword-onlyscreen(defaulting to the app's active screen), and the mouse-up handler pins it to the screen the release actually landed on. Background selections are left untouched and visible, matching the current behavior; they simply aren't copied by clicks that happened somewhere else. As a side effect, selections made inside a modal are now copyable, which the app-rooted scan never reached.The new regression tests drive a real selection through Textual's event path (triple-click via
Pilot) with a modal pushed on top, and fail against the previous implementation.Made by Open SWE