e166159f26
Add an optional `region: [x1, y1, x2, y2]` parameter to vision_analyze (pixel coordinates in the ORIGINAL image space). The crop is applied with Pillow BEFORE the downscale/embed-cap pipeline, so the cropped region gets the full resolution budget — a zoom for reading small text or UI details after a full shot. - New `_crop_image_region` helper: clamps out-of-bounds coordinates to the image, rejects zero-area/inverted/malformed regions with an error naming the actual image dimensions so the model can retry sensibly. - Wired into both the native fast path (`_vision_analyze_native`) and the legacy aux-LLM path (`vision_analyze_tool`). - Schema gains one static optional param (byte-stable thereafter); the description documents the intended flow: full shot first, then zoom. - No region supplied = behavior unchanged (regression-guarded). Tests: tests/tools/test_vision_region.py (11 tests — crop applied, clamping, zero-area rejection with dims, malformed input, pre-downscale full-budget zoom, schema shape, handler pass-through, no-region unchanged). Widened one narrow fake_native stub in test_vision_tools.py to be kwargs-tolerant. Ported from: QwenLM/qwen-code zoom-image.ts (Apache-2.0)