mcpField
A
ag2-multimodal-input

ag2-multimodal-input

github.com/ag2aiAgent workflows1265 installsUpdated 13w ago
Repository

About ag2-multimodal-input

A guide to sending images, audio, video, and documents to AG2 agents. It describes shared input factories, file uploads, and provider-specific format support.

Key features

  1. 01Image, audio, video, and document inputs
  2. 02URL, local file, bytes, or file ID sources
  3. 03Provider-specific input support
  4. 04File upload and lifecycle through FilesAPI
  5. 05Gemini video metadata and YouTube URLs

Use cases

  1. 01Ask an agent to describe images
  2. 02Transcribe or analyze audio inputs
  3. 03Summarize videos or extract document content

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/ag2ai/ag2-skills --skill ag2-multimodal-input

After installing, type/ag2-multimodal-inputin Claude Code to confirm it loaded.

Details

From the project README

Multimodal inputs

When to use

The user wants the agent to process non-text input: an image to describe, audio to transcribe, video to summarise, or a PDF / document to extract from. The same factory pattern works across providers; per-provider support varies.

60-second recipe

from ag2 import Agent
from ag2.config import GeminiConfig
from ag2.events import ImageInput

agent = Agent(
    "vision",
    "You describe images.",
    config=GeminiConfig(model="gemini-3-flash-preview"),
)

image = ImageInput("https://example.com/photo.jpg")
reply = await agent.ask("Describe this image in detail.", image)
print(reply.body)

Multiple inputs in one ask are fine:

reply = await agent.ask(
    "Compare these two images.",
    ImageInput("https://example.com/before.jpg"),
    ImageInput("https://example.com/after.jpg"),
)

Input factories

FactoryFormats
ImageInput(...)JPEG, PNG, GIF, WebP
AudioInput(...)WAV, MP3, OGG, FLAC, AAC
VideoInput(...)MP4, WebM, MOV, MKV, MPEG
DocumentInput(...)PDF, TXT, HTML, Markdown, CSV, JSON, Office formats

Each accepts the same four data sources:

from ag2.events import ImageInput

ImageInput("https://example.com/photo.jpg")     # URL
ImageInput(path="photo.jpg")                    # local file
ImageInput(data=raw_bytes, media_type="image/png")  # bytes
ImageInput(file_id="file-abc123")               # provider-uploaded

Provider matrix

Input typeOpenAIOpenAI ResponsesGeminiAnthropic
Text✓✓✓✓
Image (URL)✓✓✓✓
Image (binary)✓✓✓✓
Audio (URL)––✓–
Audio (binary)✓–✓–
Video (URL)––✓–
Video (binary)––✓–
Document (URL)–✓✓✓
Document (binary)✓✓✓✓
File ID✓✓✓✓

Unsupported combinations raise UnsupportedInputError with a clear message.

Gemini has the broadest multimodal support. If you don't know which provider to pick for a multimodal task, start there.

Provider-specific niceties

Gemini — YouTube URLs work directly
from ag2.events import VideoInput

video = VideoInput("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
reply = await agent.ask("Summarize this video.", video)
Gemini — large files (> 20MB) via Google Files API
from google import genai
from ag2.events import VideoInput
import time

client = genai.Client()
uploaded = client.files.upload(file="large_video.mp4")
while uploaded.state.name == "PROCESSING":
    time.sleep(2)
    uploaded = client.files.get(name=uploaded.name)

video = VideoInput(uploaded.uri)
Gemini — vendor_metadata
KeyPurpose
media_resolutionMEDIA_RESOLUTION_LOW/MEDIUM/HIGH/ULTRA_HIGH — token vs cost
video_metadataClipping (start_offset, end_offset) and fps
display_nameDisplay name for the file
ImageInput(data=raw, media_type="image/jpeg", vendor_metadata={"media_resolution": "MEDIA_RESOLUTION_LOW"})

VideoInput(path="lecture.mp4", vendor_metadata={
    "video_metadata": {"start_offset": "60s", "end_offset": "120s", "fps": 0.5},
})
OpenAI — image detail
ImageInput(data=raw, media_type="image/png", vendor_metadata={"detail": "low"})  # "low" | "high" | "auto"
Anthropic — File ID + prompt caching
import anthropic
from ag2.events import ImageInput, DocumentInput

client = anthropic.Anthropic()
uploaded = client.beta.files.upload(file=("photo.jpg", open("photo.jpg", "rb"), "image/jpeg"))

# filename determines block type (image vs document)
image = ImageInput(file_id=uploaded.id, filename="photo.jpg")

# Cache an attachment so subsequent turns skip re-uploading
doc = DocumentInput(path="report.pdf", vendor_metadata={"cache_control": {"type": "ephemeral"}})

FilesAPI — upload lifecycle, provider-agnostic

For any provider that has a file API (OpenAIConfig, OpenAIResponsesConfig, AnthropicConfig, GeminiConfig):

from ag2 import FilesAPI
from ag2.config import OpenAIResponsesConfig

files = FilesAPI(OpenAIResponsesConfig(model="gpt-5-mini"))

uploaded = await files.upload(path="report.pdf", purpose="assistants")
print(uploaded.file_id)

# Or from bytes (filename required)
uploaded = await files.upload(data=b"...", filename="hello.txt", purpose="assistants")

# List, read, delete
all_files = await files.list()
data = await files.read(uploaded.file_id)        # NotImplementedError on Gemini
await files.delete(uploaded.file_id)

Pass the file_id to DocumentInput, ImageInput, etc.:

from ag2.events import DocumentInput

doc = DocumentInput(file_id=uploaded.file_id)
reply = await agent.ask("Summarize this report.", doc)

Going deeper

  • website/docs/user-guide/multimodal/inputs.mdx — full provider matrix and vendor_metadata reference.
  • website/docs/user-guide/advanced/files.mdx — FilesAPI reference (upload / list / read / delete).
  • For tools that return images / binary back to the LLM, see ag2-add-custom-tool (ImageInput, BinaryInput, ToolResult).

Common pitfalls

  • Picking a provider that doesn't support your input type — silently you'll get UnsupportedInputError. Check the matrix; Gemini is broadest.
  • FilesAPI.read() on Gemini — raises NotImplementedError. Gemini doesn't expose download.
  • Calling files.upload(data=...) without filename= — raises ValueError. Filename is required for in-memory uploads.
  • Supplying more than one source to a factory — not an error. The factory resolves in priority order url > file_id > path > data, so extra sources are silently ignored. Pass exactly one to get what you intend. Supplying zero sources raises ValueError.
  • Anthropic ImageInput(file_id=...) without filename= — Anthropic decides block type (image vs document) by filename extension. Pass it.
  • Gemini vendor_metadata keys are nested — video_metadata itself takes a dict. Check the doc table for shape.
  • Forgetting to wait for Gemini file processing — large uploads have a PROCESSING state. Poll client.files.get(name=...) until ready before referencing the URI.

Comments

Markdown supported