feat(cua-driver): let get_window_state skip the a11y tree and return capture metadata - #3516
Conversation
1632c08 to
f135c04
Compare
…capture metadata Fold the capture-only / window-preview capability into the existing get_window_state tool instead of adding a separate tool. A standalone capture-only tool would duplicate get_window_state's existing per-window screenshot path and create a tool-selection hazard — an agent that wants a window's pixels might call one when it meant the other. One entry point is clearer and cheaper to maintain. get_window_state already returns a per-window screenshot scoped to window_id, already supports include_screenshot:false (tree-only), and already caps the walk with max_elements/max_depth. This adds the mirror image plus metadata: - include_accessibility_tree (bool, default true). When false, SKIP the AX / AT-SPI / UIA walk entirely (the expensive part) and return just the screenshot + window metadata — the capture-only / picture-in-picture path. Mirrors include_screenshot; default true keeps existing behavior unchanged. - Guard the degenerate case: include_accessibility_tree:false AND include_screenshot:false returns a clear "nothing to return" error rather than an empty payload. - max_dimension (optional) downscales the returned screenshot's long edge, folded with the session/global max_image_dimension ceiling (the tighter wins), reusing the existing resize_png_if_needed path. - Enrich the structured screenshot metadata with the fields the preview path needs that weren't already present: app_name + window_title on every platform, and window_bounds on Linux/Windows (macOS already emitted window_bounds + screenshot_scale + width/height + mime). All additive. pid + window_id stay required; the schema is not loosened. The capture path is unchanged, so the Wayland per-window limitation still stands: get_window_state on Wayland returns the tree with a typed surface_identity_unproven screenshot error rather than faked pixels. get_window_state already carries screen-capture scope (it always screenshots), so no new policy, capability token, or risk surface is introduced. Docs (mcp-tools.mdx) regenerated. The tool roster is unchanged (56), so the compat manifest and its guard need no edit. Refs CUA-1106 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
f135c04 to
95b49c1
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new capture-only path can produce successful responses with an empty content stream (and on Wayland can yield neither tree nor screenshot on surface_identity_unproven), which risks breaking consumers and contradicts the documented behavior.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR extends the existing get_window_state tool to support a capture-only path by allowing callers to skip the expensive accessibility-tree walk, while also enriching the returned window metadata and adding an optional per-call screenshot downscale cap.
Changes:
- Add
include_accessibility_tree(defaulttrue) and a both-false guard to prevent empty tool outputs. - Add
max_dimensionand fold it with the configuredmax_image_dimensionceiling to downscale screenshots. - Enrich structured output with
window_bounds,app_name, andwindow_titleacross platforms, and update MCP tool docs accordingly.
File summaries
| File | Description |
|---|---|
| libs/cua-driver/rust/crates/platform-windows/src/tools/impl_.rs | Adds capture-only controls, max-dimension folding, and window metadata to Windows get_window_state. |
| libs/cua-driver/rust/crates/platform-macos/src/tools/get_window_state.rs | Adds capture-only controls, max-dimension folding, metadata enrichment, and unit tests for schema + folding behavior on macOS. |
| libs/cua-driver/rust/crates/platform-linux/src/tools/impl_.rs | Adds capture-only controls, max-dimension folding, and window metadata to Linux get_window_state (AT-SPI/X11/Wayland). |
| docs/content/docs/reference/cua-driver/mcp-tools.mdx | Documents the new include_accessibility_tree and max_dimension arguments and the capture-only behavior. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…apture-only path Address AI code-review feedback on the include_accessibility_tree capture-only path. - Linux: enumerate the pid's windows once (list_windows_dispatch) and reuse the result for both the Wayland window-ownership check and the additive window metadata, instead of calling the compositor/X11 enumerator twice per get_window_state call. - Linux + Windows: on the capture-only path (include_accessibility_tree:false) the response could be a "success" with no content parts — when the screenshot was written to disk via screenshot_out_file (image not embedded, and no tree markdown), or on Wayland when per-window capture cannot prove surface identity (no tree, no image). Push a text content part when the screenshot goes to disk, and return a structured error (carrying the screenshot_error reason) when nothing at all was produced, matching the macOS path which already guards this. Refs CUA-1106 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Folds the capture-only / live-window-preview capability into the existing
get_window_statetool, instead of adding a standalone tool.A separate capture-only tool would duplicate
get_window_state's existing per-window screenshot path and create a tool-selection hazard — an agent that wants a window's pixels might reach for one when it meant the other. One entry point is clearer and cheaper to maintain.Why this is a small change
get_window_statealready:window_id,include_screenshot:false(tree-only, the cheap re-index path),max_elements/max_depth.So this is the mirror image plus the missing metadata.
Changes
include_accessibility_tree(bool, defaulttrue). Whenfalse, SKIP the AX / AT-SPI / UIA walk entirely (the expensive part — up to 20 s on macOS) and return just the screenshot + window metadata. This is the capture-only / picture-in-picture path. Mirrorsinclude_screenshot; defaulttruekeeps existing behavior unchanged.include_accessibility_tree:falseandinclude_screenshot:falsereturns a clear"nothing to return"error rather than an empty payload (screenshot_out_filestill forces a capture).max_dimension(optional) downscales the returned screenshot's long edge (aspect preserved), folded with the session/globalmax_image_dimensionceiling — the tighter wins — reusing the existingresize_png_if_neededpath.window_bounds,screenshot_scale,screenshot_width/height,screenshot_mime_type; this addsapp_name+window_title.screenshot_width/height+screenshot_mime_type; this addswindow_bounds+app_name+window_title.pid+window_idstay required — the schema is not loosened.Preserved invariants
get_window_statereturns the tree with a typedsurface_identity_unprovenscreenshot error rather than faked pixels — never a fabricated capture.get_window_statealready carries screen-capture scope (it always screenshots), so no new policy rule, capability token, or risk-class entry is introduced.outputSchemacounts are unchanged.Platform note on
screenshot_scalescreenshot_scaleis emitted on macOS, where the capture frame is validated against WindowServer bounds and the backing scale (1x/2x Retina) is proven. Linux (X11) and Windowsget_window_statedo not compute a proven backing scale today, so this change does not fabricate one there (it would be exactly the kind of misleading cross-platform behavior the repo's contract forbids). Those platforms gainwindow_bounds+app_name+window_title. Emitting a proven per-platform scale on Linux/Windows is a separate follow-up.Tests
get_window_stateunit tests: schema advertisesinclude_accessibility_tree+max_dimension, keepspid/window_idrequired, documents the both-false error;max_dimensionfolding (tighter cap wins, unlimited ceiling defers to per-call, absent passes through). The existingscreenshot_only_path_does_not_degradeunit test already covers the tree-skipped degradation rung.Local validation on macOS:
cargo build(full workspace incl. Linux/Windows stub paths) + release build,cargo test(core 587 + macOS 360 lib, get_window_state 28),cargo fmt --check, docs regenerated. Linux/Windows nativeget_window_statecompiles only on their OS and is covered by CI's Rust Linux/Windows lanes.Refs CUA-1106