Multimodal / vision

import std.image
img = image.load("chart.png")

ai "what does this chart show?" on img

The on clause attaches image input. The image is a std.image handle, so a resize or crop pipeline flows straight into the call:

small = image.resize(image.load("photo.jpg"), 512, 512)
ai "describe this" on small

Typed and multiple

type Kind = Chart | Photo | Diagram | Screenshot

ai[Kind] "classify this image" on img            # typed vision output
ai "spot the differences" on [before, after]     # several images

on composes with [T], so vision output is coerced and retried like any other typed call.

One program, either provider

The handle serializes into whatever the configured provider expects - OpenAI image_url data URLs, Anthropic base64 image blocks. The same source runs on both; switching is an environment variable.

Offline

A vision call in mock mode echoes the prompt plus each image's real dimensions:

[AI Mock] describe [image 4x2]

The dimensions are read from the actual file, so the mock proves the image was loaded, decoded and passed correctly - the part of the wiring that actually breaks

  • while staying deterministic. Typed vision calls return their schema-valid mock

as usual.

Restrictions

on composes with [T]. Combining it with using (tools), with (a session), voting, or -> stream is not supported yet and is a clear parse error rather than a runtime surprise.

Size and cost

Images are tokens, often a lot of them. Resize before sending: a 4000-pixel photograph rarely answers a question better than a 1000-pixel one, and costs several times more.

ai "read the label" on image.resize(photo, 1024, 1024)