Skip to content

fix(code): ignore mouse hits on detached widgets - #5114

Merged
Mason Daugherty (mdrxy) merged 1 commit into
mainfrom
mdrxy/code/textual-detached-hit-guard
Jul 28, 2026
Merged

fix(code): ignore mouse hits on detached widgets#5114
Mason Daugherty (mdrxy) merged 1 commit into
mainfrom
mdrxy/code/textual-detached-hit-guard

Conversation

@mdrxy

Copy link
Copy Markdown
Member

Related Textualize/textual#6643

Clicking or starting a text selection in the transcript while the agent was streaming a response could take the whole app down with AttributeError: 'NoneType' object has no attribute 'region'. Mouse presses on markdown that is being replaced mid-stream are now ignored instead of crashing.


Textual's compositor keeps reporting a widget as visible for a few event-loop iterations after it leaves the DOM. Markdown.update — which MarkdownStream runs on every flush of a streaming assistant message — detaches and remounts its blocks constantly, so that stale window is open more or less continuously while output streams. When a mouse press lands in it, Screen._forward_event starts a text selection from the hit widget's parent, which is None for a detached widget, and dereferences container.region.

Reproduced against the pinned Textual with upstream's minimal example (no deepagents code involved), so this is fixed here only as a stopgap: it joins the other version-scoped shims in the Textual patch module as a fourth independent, separately guarded patch, with Textualize/textual#6643 as its removal criterion.

The guard wraps the public Screen.get_widget_and_offset_at — the single funnel for all three hit lookups in _forward_event (selection start, drag update, and drag-in-progress) — and returns no hit when the widget is detached. Textual then takes its existing "nothing selectable here" branch, so a press on a just-pruned paragraph starts no selection rather than killing the process. This mirrors Textual's own is_attached guarding of live selections.

Worth a careful look: the patch is on a public Textual method rather than a private one, so it changes hit-testing for every mouse event, not just selection. Live widgets are unaffected, and there is a test pinning that.

Made by Open SWE

References

Clicking in the transcript while an assistant message streamed could kill
the app with `AttributeError: 'NoneType' object has no attribute 'region'`.
Textual's compositor keeps reporting a widget as visible for a few event
loop iterations after `Markdown.update` prunes it, and `_forward_event`
starts a selection from that widget's now-`None` parent. Filter detached
hits out of `Screen.get_widget_and_offset_at` so Textual takes its existing
"nothing selectable here" branch instead.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
@github-actions github-actions Bot added dcode Related to `deepagents-code` fix A bug fix (PATCH) internal User is a member of the `langchain-ai` GitHub organization size: S 50-199 LOC labels Jul 28, 2026
@johannes117
Johannes du Plessis (johannes117) marked this pull request as ready for review July 28, 2026 16:08

@open-swe open-swe Bot 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.

✅ Open SWE Review: No issues found

Open SWE reviewed this PR and found no potential bugs to report.

Open in WebView Open SWE trace

@mdrxy
Mason Daugherty (mdrxy) merged commit d4d2b60 into main Jul 28, 2026
62 checks passed
@mdrxy
Mason Daugherty (mdrxy) deleted the mdrxy/code/textual-detached-hit-guard branch July 28, 2026 16:29
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 2026
Related Textualize/textual#6643

Clicking or starting a text selection in the transcript while the agent
was streaming a response could take the whole app down with
`AttributeError: 'NoneType' object has no attribute 'region'`. Mouse
presses on markdown that is being replaced mid-stream are now ignored
instead of crashing.

---

Textual's compositor keeps reporting a widget as visible for a few
event-loop iterations after it leaves the DOM. `Markdown.update` — which
`MarkdownStream` runs on every flush of a streaming assistant message —
detaches and remounts its blocks constantly, so that stale window is
open more or less continuously while output streams. When a mouse press
lands in it, `Screen._forward_event` starts a text selection from the
hit widget's parent, which is `None` for a detached widget, and
dereferences `container.region`.

Reproduced against the pinned Textual with upstream's minimal example
(no `deepagents` code involved), so this is fixed here only as a
stopgap: it joins the other version-scoped shims in the Textual patch
module as a fourth independent, separately guarded patch, with
Textualize/textual#6643 as its removal criterion.

The guard wraps the public `Screen.get_widget_and_offset_at` — the
single funnel for all three hit lookups in `_forward_event` (selection
start, drag update, and drag-in-progress) — and returns no hit when the
widget is detached. Textual then takes its existing "nothing selectable
here" branch, so a press on a just-pruned paragraph starts no selection
rather than killing the process. This mirrors Textual's own
`is_attached` guarding of live selections.

Worth a careful look: the patch is on a public Textual method rather
than a private one, so it changes hit-testing for every mouse event, not
just selection. Live widgets are unaffected, and there is a test pinning
that.

Made by [Open
SWE](https://openswe.vercel.app/agents/a1475bad-bf2c-b5aa-716f-6d5e0cdbc40b)

## References
- Plan:
https://openswe.vercel.app/agents/a1475bad-bf2c-b5aa-716f-6d5e0cdbc40b/plan

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) 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dcode Related to `deepagents-code` fix A bug fix (PATCH) internal User is a member of the `langchain-ai` GitHub organization size: S 50-199 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant