Skip to content

Bring read-tool image processing closer to Pi parity #482

Description

@alejandro-ao

Summary

Follow up on #479 by bringing Tau's read-tool image handling closer to Pi's production behavior.

Tau now detects JPEG, PNG, GIF, and WebP files by content and returns provider-neutral ImageContent blocks. The next step is to make that pipeline more resilient and extensible: validate image signatures more carefully, normalize additional formats, resize images to provider-safe limits instead of immediately rejecting large files, and isolate filesystem/image-processing operations behind testable boundaries.

This issue should document the product-development process and provide a concrete starting point for a focused PR. Preserve Tau's package boundaries:

tau_coding  -> local read tool and image processing
tau_agent   -> provider-neutral TextContent/ImageContent contracts
tau_ai      -> model capability filtering and provider serialization

Desired behavior

Image detection and normalization

  • Continue detecting formats from file magic rather than filename extensions.
  • Validate supported signatures sufficiently to avoid treating malformed files as valid attachments, following Pi's checks for PNG structure, animated PNG exclusion, JPEG edge cases, and BMP structure where practical.
  • Add BMP input support and convert BMP to a provider-safe inline format such as PNG before creating ImageContent.
  • Keep JPEG, static PNG, GIF, and WebP behavior compatible with Send read-tool images to vision models #479.
  • Return a clear text-only omission/error note when decoding or conversion fails.

Resizing and provider-safe output

  • Replace the current unconditional “over 5 MB” omission with bounded image processing that attempts to resize or recompress an oversized image first.
  • Define and document deterministic limits for dimensions, encoded payload size, processing time, and memory use.
  • Preserve aspect ratio and avoid upscaling.
  • Report useful processing notes to the model, for example when an image was resized or converted.
  • If no safe output can be produced, omit the image with an explicit explanation rather than sending an invalid or excessively large request.

Testable read operations

  • Consider introducing a small ReadOperations-style boundary, similar to Pi, for reading bytes, checking access, and detecting image types.
  • Keep local filesystem behavior as the default.
  • Ensure this abstraction does not move local filesystem concerns into tau_agent or couple the reusable harness to the CLI/TUI.
  • Use fake operations and fixtures for deterministic tests; remote filesystem support itself does not need to be implemented in the first PR.

Capability handling and provider serialization

  • Keep canonical ImageContent in tool results and sessions; do not duplicate base64 data in details.
  • Evaluate whether unsupported-image downgrade logic can be centralized before provider-specific serialization, as Pi does, while retaining the explicit (tool image omitted: model does not support images) behavior.
  • Preserve existing provider mappings for Anthropic, OpenAI Responses/Codex, OpenAI Chat Completions, Gemini, Mistral, GitHub Copilot, and other currently supported compatible transports.
  • Keep capability decisions based on the effective model catalog, with transport-specific exceptions documented and tested.

Delivery process

A PR originating from this issue should proceed in small, reviewable stages:

  1. Document proposed limits, dependencies, and ownership across tau_coding, tau_agent, and tau_ai.
  2. Add failing unit tests and representative fixtures for malformed files, BMP conversion, resizing, and omission paths.
  3. Implement the smallest provider-neutral processing layer.
  4. Run payload regression tests for all existing provider families.
  5. Update dev-notes/ and website/content/reference/tools.md with behavior, limits, and failure modes.
  6. Run the full Python, lint, formatting, type, package, and documentation builds.
  7. Follow up with credentialed live-provider validation using the matrix tracked in TODO.md.

Notes / questions

  • Pi currently resizes images automatically, converts BMP to PNG, validates image structures more defensively, and supports pluggable read operations. Its provider-neutral ImageContent and provider serialization strategy already closely match Tau's implementation from Send read-tool images to vision models #479.
  • Which image library should Tau use? Prefer a small, well-maintained dependency with predictable cross-platform wheels. Document security, decompression-bomb, memory, and installation implications before selecting it.
  • Should the current 5 MB value remain the final encoded attachment ceiling, or should limits be provider/model metadata? A first PR may use one conservative documented limit if the design leaves room for provider-specific limits later.
  • Animated PNG remains intentionally unsupported unless provider compatibility is established. Existing GIF behavior should not accidentally be narrowed.
  • Inline display of the returned image in Tau's interactive TUI is likely not practical in this phase. Tau uses Textual, which does not currently provide built-in terminal-image protocol support comparable to Pi's custom TUI handling. Keep the existing textual read result as the required behavior. A separate investigation may evaluate a custom Textual widget or third-party integration, but this PR should not depend on terminal image rendering.
  • More provider adapters should be handled as separate provider work. This issue should guarantee robust behavior for Tau's existing adapters and leave reusable tests/contracts for future adapters.
  • Avoid storing transformed and original image payloads together in JSONL sessions. Session size and resume behavior need explicit tests.

Acceptance criteria

  • JPEG, static PNG, GIF, WebP, and valid BMP files are recognized from file content, not extension.
  • BMP input is converted to a provider-supported ImageContent MIME type and covered by tests.
  • Malformed signatures and animated PNG files do not produce image attachments.
  • Oversized or over-dimension images are resized/recompressed within documented safety limits when possible.
  • Aspect ratio is preserved, images are not upscaled, and processing resource limits are enforced.
  • Conversion/resizing failures return a clear text-only result without crashing the agent loop.
  • Tool results contain one canonical image payload and do not duplicate base64 data in details.
  • Vision-capable models receive processed images through every currently supported provider family's correct wire format.
  • Text-only models receive the explicit omission marker and no image bytes are sent to the provider.
  • Image-containing session JSONL round-trips correctly without storing both original and transformed payloads.
  • The processing/read boundary has deterministic unit tests using fake operations or local fixtures.
  • Existing image payload regression tests continue to pass.
  • User-facing tool documentation and a beginner-friendly dev-notes/ design/implementation note are updated.
  • TUI image rendering is explicitly documented as out of scope pending a viable Textual integration; textual status/output remains usable.
  • uv run pytest, uv run ruff check ., uv run ruff format --check ., uv run mypy, uv build, and the Hugo documentation build pass.
  • Credentialed live-provider validation remains tracked as a follow-up rather than requiring secrets in CI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions