screenshot — capture the desktop, ground the selectors
screenshot is how the model sees. The accessibility tree
(snapshot) is the structured truth; the screenshot is what
the user actually perceives — layout, colors, a canvas nobody labeled. With
annotation on, the capture bridges seeing and addressing: boxes are drawn on
the image and a legend hands back selectors the other tools accept.
Computer::screenshot(&self, input: &ComputerScreenshot) -> Result<ScreenshotOutput, String>
screenshot(metadata, ComputerScreenshot) -> Result<ScreenshotOutput, String>
The model: pick the region → capture → (optionally) annotate
Region first — mutually exclusive choices:
| Wire shape | Captures |
|---|---|
{} |
The full desktop. |
{"region": [x, y, w, h]} |
One display region, display pixels, origin top-left. |
{"app": "Reports"} |
Only the pixels under the app’s window. |
{"surface": "taskbar"} |
Only a shell surface’s region — surface. |
Annotation is the second axis, and it is gated: pass
"annotate": true (requires an app scope) and the capture draws a labeled
box on every matching element — selector then chooses WHICH elements get
boxes (default "*"), not which pixels are shot. The legend maps each
drawn tag back to a selector:
B7 button[name='Export'] button 'Export'
That selector is copy-ready for act / control —
visual grounding without ever doing pixel math.
The coordinate mapping (when you DO need pixels)
The delivered image may be downscaled (max_width, default 1568) to
stay inside a tool-result budget, so image pixels are not desktop pixels.
ScreenshotOutput reports the mapping:
desktop = desktop_origin + image_coord × desktop_scale
Suppose the model spots a button at image pixel (410, 252) on an 800×600
delivery with desktop_origin = (0, 0) and desktop_scale = (1.0, 1.0) —
the desktop point is (410, 252). On a Retina-class scale of (2.0, 2.0) it
would be (820, 504). Prefer the element form — coordinates are the last
resort for node-less canvas targets (see control).
Edges
- Build mode allows only the annotated form. Plain captures (full
display /
region) hand the model pixel coordinates, so they are denied in Build mode;annotate: trueis selector-grounded and allowed. See permissions. nthis ignored when annotating — the legend covers every match; narrowselectorinstead.- Comma alternations are rejected up front (
"button, link")::nth(k)would bind to the last clause only, so the legend would label a box with a selector that resolves elsewhere. - Coordinates in tool calls always refer to the delivered image — never the original screen size.
See also
snapshot for the tree form of the same app ·
cargo run --example computer-screenshot