Skip to content

Comments

feat(llm): vision (image input) support across all providers#569

Merged
bug-ops merged 4 commits intomainfrom
feat/490-vision-support
Feb 19, 2026
Merged

feat(llm): vision (image input) support across all providers#569
bug-ops merged 4 commits intomainfrom
feat/490-vision-support

Conversation

@bug-ops
Copy link
Owner

@bug-ops bug-ops commented Feb 19, 2026

Summary

Add vision (image input) support across the Zeph stack for local and cloud LLM providers.

  • Add MessagePart::Image variant with base64 serde and LlmProvider::supports_vision() trait method
  • Claude: structured content with AnthropicContentBlock::Image (base64 source)
  • OpenAI: array content format with image_url data-URI encoding
  • Ollama: with_images() on user messages, optional vision_model config for dedicated model routing
  • Agent layer: image extraction from ChannelMessage attachments, 20 MB limit, path traversal protection
  • Channels: /image <path> command in CLI/TUI, Telegram msg.photo() download with pre-download size guard
  • Config: vision_model field in LlmConfig, --init wizard update
  • 28 new unit tests covering all provider vision paths, security, and edge cases

Closes #490,Closes #491,Closes #492,Closes #493,Closes #494,Closes #495,Closes #496

Test plan

  • cargo +nightly fmt --check passes
  • cargo clippy --workspace -- -D warnings passes (zero warnings)
  • cargo nextest run --workspace --lib --bins passes (1811 tests, 0 failures)
  • Manual: attach image via /image <path> in CLI, verify vision-capable provider processes it
  • Manual: send photo in Telegram, verify image is forwarded to provider
  • Manual: verify non-vision provider logs warning and skips image

@github-actions github-actions bot added llm LLM provider related channels User interface channels rust core dependencies enhancement New feature or request size/XL labels Feb 19, 2026
@bug-ops bug-ops force-pushed the feat/490-vision-support branch from 1e1edf7 to a717f38 Compare February 19, 2026 00:08
@github-actions github-actions bot added the documentation Improvements or additions to documentation label Feb 19, 2026
Introduce MessagePart::Image variant with base64 serde, LlmProvider::supports_vision()
trait method, and per-provider implementations:

- Claude: structured content path with base64 ImageSource blocks
- OpenAI: array content format with data-URI image_url entries
- Ollama: with_images() call on user messages, optional separate vision_model

Agent layer extracts AttachmentKind::Image from ChannelMessage into MessagePart::Image
(capped at 20 MB), constructs Message::from_parts when provider supports vision.

Channels:
- CLI: /image <path> command reads local file into image attachment
- Telegram: downloads largest PhotoSize and attaches as Image

Config: vision_model field on LlmConfig; --init wizard prompts for it (Ollama only).
Bootstrap wires vision_model into OllamaProvider.

Closes #490
PERF: replace iter().clone() with consuming partition in resolve_message so
image data is moved rather than cloned (up to 20 MB saved per message).

SEC: reject path traversal (Component::ParentDir) in /image command before
calling std::fs::read.

SEC: add pre-download size guard in Telegram photo handler; skip download
if photo.file.size exceeds 20 MB and pass capacity hint to Vec::with_capacity.

BUG: remove redundant to_llm_content() wrapping in convert_messages_vision;
collect text parts directly to avoid false-empty check on image messages.

TEST: add unit tests for OpenAI has_image_parts, convert_messages_vision
(data-URI format, text-only, image-only cases).

TEST: add unit tests for Claude AnthropicContentBlock::Image serialization,
split_messages_structured with image parts, has_image_parts detection.

TEST: add unit tests for Ollama with_vision_model builder, convert_message
with Image parts (base64 encoding), model selection switch.

TEST: add unit tests for handle_image_command path traversal rejection,
missing file error path, and successful file load with mime detection.
@bug-ops bug-ops force-pushed the feat/490-vision-support branch from 46665eb to f9fb4fd Compare February 19, 2026 00:32
@bug-ops bug-ops enabled auto-merge (squash) February 19, 2026 00:36
@bug-ops bug-ops disabled auto-merge February 19, 2026 00:40
@bug-ops bug-ops enabled auto-merge (squash) February 19, 2026 00:44
@bug-ops bug-ops merged commit 1010786 into main Feb 19, 2026
25 checks passed
@bug-ops bug-ops deleted the feat/490-vision-support branch February 19, 2026 00:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment