Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/07_tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,18 @@ A tool’s __call__ method may return:
- None
- a list or tuple containing any of the above

**Image size limit:** When a tool returns a `PIL.Image.Image`, it is the tool’s responsibility to ensure the image does not exceed **2000×2000 px** (longest side ≤ 2000 px). The Claude API enforces a 2000×2000 px per-image limit when more than 20 images are sent in a single request, which is common in agentic loops. Use `downscale_image()` from `askui.utils.image_utils` to downscale images that may be too large:

```python
from PIL import Image
from askui.utils.image_utils import downscale_image

image: Image.Image = ... # your image
image = downscale_image(image, max_dimension=2000)
```

This preserves the original aspect ratio and only downscales images whose longest side exceeds the limit.

### Complete Example

Here’s a greeting tool that demonstrates all the key concepts:
Expand Down
27 changes: 27 additions & 0 deletions src/askui/utils/image_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,33 @@ def scale_image_to_fit(
return _center_image_in_background(scaled_image, target_size)


def downscale_image(
image: Image.Image,
max_dimension: int = 2000,
) -> Image.Image:
"""Downscale an image so its longest side does not exceed `max_dimension`.

Preserves the original aspect ratio. Images that are already
within the limit are returned unchanged.

Args:
image (Image.Image): The PIL Image to downscale.
max_dimension (int, optional): Maximum allowed size for the longest side. Defaults to `2000`.

Returns:
Image.Image: The downscaled image, or the original if no scaling was needed.
"""
longest_side = max(image.width, image.height)
if longest_side <= max_dimension:
return image
scale_factor = max_dimension / longest_side
new_size = (
int(image.width * scale_factor),
int(image.height * scale_factor),
)
return image.resize(new_size, Image.Resampling.LANCZOS)


def _scale_coordinates(
coordinates: tuple[int, int],
offset: tuple[int, int],
Expand Down
Loading