fix(computer_use): adapt cua-driver backend to 0.6.x capture API - #51295
fix(computer_use): adapt cua-driver backend to 0.6.x capture API#51295vision-drakon wants to merge 1 commit into
Conversation
The cua_backend was written for cua-driver 0.5.0 but 0.6.x changed the
capture surface, producing 0x0 captures and zeroed element bounds:
- The standalone `screenshot` tool was removed; vision mode that called
it returned an empty result (width/height 0, no PNG).
- Capture unified into `get_window_state` with a `capture_mode`
(som|vision|ax) parameter.
- The screenshot now arrives as an MCP image content-part (and/or
structuredContent.screenshot_png_b64), not from the removed tool.
- Elements come in structuredContent.elements with real `frame`
{x,y,w,h} bounds; the markdown tree parser only ever yields (0,0,0,0).
Fix:
- Route all three modes through get_window_state passing capture_mode.
- Read the screenshot from images[0], fall back to
structuredContent.screenshot_png_b64.
- Add _parse_elements_from_structured() to surface real bounds; prefer
it over the markdown parser, keeping the markdown path as a 0.5.x
fallback.
- Read screenshot_width/height from structuredContent; sniff PNG/JPEG
bytes only when absent.
- Extract window title from the first structured AXWindow element.
- Bump PINNED_CUA_DRIVER_VERSION default to 0.6.5 to match.
Verified live on macOS (cua-driver 0.6.5): som returns screenshot +
elements with real bounds, vision returns a full screenshot (was 0x0),
ax returns the AX tree. Adds TestStructuredElementParsing; full
computer_use suite (127 tests) passes.
|
Thanks for digging into this @vision-drakon — the symptom you describe (0×0 vision captures,
The only legitimate delta your PR adds is passing Could you Going to leave this open for a moment to give you a chance to confirm. Thanks again for taking the time to file a thorough report. |
|
Thanks for this @vision-drakon — the analysis was correct against the code you branched from, but What's already on
One note for the record: this PR also re-introduces Your reasoning was sound; it just got overtaken by parallel work. Appreciate the detailed write-up and the live-verified before/after table. |
Symptom
On macOS with cua-driver 0.6.x installed, the
computer_usetoolset returns broken captures:mode="vision"→width:0 height:0, no screenshot at all.mode="som"→ screenshot present but every element hasbounds (0,0,0,0)and empty labels, breaking coordinate clicks and spatial reasoning.This happens regardless of Screen Recording / Accessibility permissions being correctly granted to
com.trycua.driver(verifiedscreen_recording_capturable: true).Root cause
tools/computer_use/cua_backend.pyis pinned to and written for cua-driver 0.5.0 (PINNED_CUA_DRIVER_VERSION = "0.5.0"), but 0.6.x changed the capture surface:screenshottool was removed.capture(mode="vision")still calls it (self._session.call_tool("screenshot", ...)), so it returns nothing → 0×0.get_window_statewith a newcapture_mode(som|vision|ax) parameter.structuredContent.screenshot_png_b64), not from the removed tool.structuredContent.elements, each with a realframe: {x,y,w,h}. The existing_parse_elements_from_treeonly parses the markdown tree, which carries no coordinates — hence the hard-codedbounds=(0,0,0,0).Fix
get_window_state, passingcapture_mode=<mode>.images[0], falling back tostructuredContent.screenshot_png_b64._parse_elements_from_structured()that readsframe→ real(x,y,w,h)bounds; prefer it over the markdown parser, keeping the markdown path as a 0.5.x fallback.screenshot_width/heightfromstructuredContentwhen present; only sniff PNG/JPEG bytes as a fallback.AXWindowelement (markdown scan fallback).PINNED_CUA_DRIVER_VERSIONdefault to0.6.5to match the current installer.The markdown-tree parsing path is retained as a fallback so older 0.5.x daemons keep working.
Verification
Verified live on macOS with cua-driver 0.6.5 via the real MCP stdio path (not mocks):
somvisionaxDirect-backend probe (
CuaDriverBackend().capture(mode=...)) confirmssom/visionnow return realwidth×height+ populated bounds;568/818Calendar elements carry non-zero frames where before all were zero.Adds
TestStructuredElementParsing(real-bounds parsing, missing-frame default, index-less skip). Fullcomputer_usesuite passes: