PipeImgGen
The PipeImgGen operator is used to generate images from a text prompt using a specified image generation model.
How it works
PipeImgGen takes a required prompt string template (plus an optional negative_prompt) and a set of parameters, then calls an underlying image generation service (like GPT Image or Flux) to create one or more images. It does not consume a dedicated "prompt concept" — the prompt is a template you write directly on the pipe.
The variables you declare in inputs are injected into that template at run time:
- Text inputs (concept
Text, or anything refining it) are interpolated into the prompt string — reference them with$var(or@var/{{ var }}). - Image inputs (concept
Image, single or a list) are referenced in the prompt the same way. Each referenced image is pulled from working memory, replaced in the text by an[Image N]placeholder token, and passed alongside the rendered text to the generator. This is the same vision pattern used for image inputs toPipeLLM, and it is what enables image-to-image, reference-image, and image-editing generation (e.g. Flux / GPT Image with reference images), bounded by the model'smax_prompt_images.
The pipe can be configured to generate a single image or a list of images. Its only concept constraints are that declared image inputs must be Image-compatible and the output must be Image-compatible.
Every input the pipe declares must be read by the prompt or the negative_prompt, and every variable they read must be declared in inputs. Validation refuses an input neither template reads as extraneous_input_variable, naming the input: an image declared in inputs but never referenced in the prompt is never passed to the generator, so reference it in the prompt, or remove it from inputs. An undeclared variable is refused as missing_input_variable.
Configuration
PipeImgGen is configured in your pipeline's .mthds file.
The prompt Field is Required
IMPORTANT: PipeImgGen requires an explicit prompt field. When using dynamic inputs, the prompt field must reference the input variable using the $ prefix.
Wrong - Missing required prompt field:
[pipe.render_slide]
type = "PipeImgGen"
inputs = { img_prompt = "Text" }
output = "Image"
model = "$gen-image"
# ERROR: Missing required field 'prompt'
Correct - prompt field references the input:
[pipe.render_slide]
type = "PipeImgGen"
inputs = { img_prompt = "Text" }
output = "Image"
prompt = "$img_prompt"
model = "$gen-image"
Image Generation Models and Backend System
PipeImgGen uses the unified inference backend system to manage image generation models. This means you can:
- Use different image generation providers (OpenAI GPT Image, FAL models like Flux, etc.)
- Configure image generation models through the same backend system as LLMs and OCR models
- Use image generation presets for consistent configurations across your pipelines
- Route image generation requests to different backends based on your routing profile
Common image generation model handles:
default-general: General-purpose image generation model (alias for gpt-image-2)default-premium: Premium image generation model (alias for gpt-image-2)default-small: Small, fast image generation model (alias for gpt-image-1-mini)best-gpt: Best OpenAI image generation model (alias for gpt-image-2)
Image generation presets are defined in your model deck configuration and can include parameters like quality, guidance_scale, and safety_tolerance.
A prompt or an input image a model's safety filter blocks fails the pipe with the code model.content_refused, naming the model and the reason the provider gave, so revising the prompt or its images is the fix. On a Gemini model such as nano-banana-2, that reason is the finish reason of the answer (IMAGE_SAFETY, IMAGE_PROHIBITED_CONTENT and their kin) or the block reason of the prompt, since Gemini answers a refusal with no image rather than with an error. A Gemini answer stopped because the image may reproduce an existing source (RECITATION, IMAGE_RECITATION) or because the prompt's language is not supported (LANGUAGE) reads the same code, and its message says which reason Gemini gave rather than blaming a safety filter. A Gemini answer whose output token limit stopped it before it held an image (MAX_TOKENS) fails the pipe with the code model.output_truncated instead, and its next step is a simpler prompt or another image model, since the pipe sets no output limit for an image.
MTHDS Parameters
| Parameter | Type | Description | Required |
|---|---|---|---|
type |
string | The type of the pipe: PipeImgGen |
Yes |
description |
string | A description of the image generation operation. | Yes |
inputs |
dictionary | The input concept(s) for the image generation operation, as a dictionary mapping input names to concept codes. Required when the prompt references variables. | No |
output |
string | The output concept produced by the image generation operation. Use bracket notation for multiple images: "Image[3]" generates exactly 3 images. |
Yes |
model |
string | The choice of image generation model name, setting, or preset to use (e.g., "gpt-image-1"). Defaults to the model specified in the global config. |
No |
prompt |
string | The image generation prompt. Can be a static string or reference input variables using $ prefix (e.g., "$description" or "A sketch of: $subject"). |
Yes |
negative_prompt |
string | Optional negative prompt when supported by the selected model or provider. | No |
aspect_ratio |
string | The desired aspect ratio of the image. Valid values: "square", "landscape_4_3", "landscape_3_2", "landscape_16_9", "landscape_21_9", "landscape_4_1", "landscape_8_1", "portrait_3_4", "portrait_2_3", "portrait_9_16", "portrait_9_21", "portrait_1_4", "portrait_1_8". The banner ratios (landscape_4_1, landscape_8_1, portrait_1_4, portrait_1_8) are only supported by Gemini 3.1 image models. |
No |
size |
string | Portable size intent: either a size tier ("1k", "2k", "4k") or an exact pixel size like "2048x1152". A tier composes with aspect_ratio; an exact size implies its own ratio, so setting both an exact size and aspect_ratio is a validation error. When unset, the model's provider default applies. See Image size and portability. |
No |
seed |
integer or "auto" | A seed for the random number generator to ensure reproducibility. "auto" uses a random seed. |
No |
background |
string | Optional background setting when supported by the selected provider. | No |
output_format |
string | Optional output image format when supported by the selected provider. | No |
is_raw |
boolean | Request a raw generation mode when supported by the selected provider. | No |
Image size and portability
The size parameter carries a size intent that stays portable when you switch the pipe's model between providers. It accepts two forms:
- A size tier (
"1k","2k","4k"): "produce this pixel class at my chosenaspect_ratio". A tier promises a pixel class, not identical dimensions across providers —size = "2k"at 16:9 yields 2752×1536 onnano-banana-2(Google's published grid) and 3072×1728 ongpt-image-2(computed from OpenAI's constraints). Both are 2K-class images; that is the abstraction. The"0.5k"tier token is reserved and currently rejected by every model. - An exact pixel size (
"2048x1152"): "produce exactly these pixels". Deterministic everywhere it runs. Because an exact size implies its own ratio, combining it withaspect_ratiois a blueprint validation error. On tier-grid models (Gemini), an exact size runs only if it exactly matches a cell of the model's published grid — a near-miss is a validation error suggesting the nearest valid cells, never a silent snap.
When size is unset, no size intent is sent: Gemini-routed jobs omit the image_size parameter entirely, and OpenAI models fall back to their fixed 1K-class preset for the chosen aspect ratio. Either way you stay at the provider's default resolution and cost — Pipelex never silently upgrades.
Per-model support:
| Model | Size tiers | Exact size |
|---|---|---|
nano-banana (Gemini 2.5 Flash Image) |
1k |
matching grid cells only |
nano-banana-pro (Gemini 3 Pro Image) |
1k, 2k, 4k |
matching grid cells only |
nano-banana-2 (Gemini 3.1 Flash Image) |
1k, 2k, 4k (all ratios incl. banners) |
matching grid cells only |
nano-banana-2-lite (Gemini 3.1 Flash Lite) |
1k |
matching grid cells only |
gpt-image-2 |
1k, 2k |
arbitrary within OpenAI's constraints (multiples of 16, ≤ 3:1 ratio, 0.65–8.29 MP) |
gpt-image-1 / -1-mini / -1.5 (legacy) |
1k |
the fixed OpenAI sizes only |
| Flux / Flux 1.1 Ultra / SDXL / Qwen | 1k (no-op) |
not supported |
An unsatisfiable request is a hard validation error, never a warn-and-ignore: it fails at blueprint-load time when the pipe's model resolves to a concrete model with rules, or at runtime before any API call when the choice is a preset or alias resolved later. Worked examples of switching model on an otherwise unchanged pipe:
nano-banana-2+aspect_ratio = "landscape_16_9"+size = "2k"→ switch togpt-image-2: runs, 2K-class dimensions. Switch toflux-pro/v1.1: validation error (Flux cannot produce the 2K class).gpt-image-2+size = "2048x2048"→ switch tonano-banana-2: runs (exact grid hit: square at 2K). Withsize = "2000x2000"instead: validation error suggesting2048x2048.- SDXL +
size = "1k"→ runs on every model (worst case as a no-op). nano-banana-2+size = "4k"→ switch togpt-image-2: validation error (4K exceeds its pixel cap) — an honest refusal, not a silent downgrade.
Cost
Size tiers change the bill: providers charge proportionally more for larger outputs (Google's output tokens scale with the tier, OpenAI's prices scale with the size), so 2k and 4k generations cost several times a 1k generation. Leaving size unset keeps the model at its provider-default size and cost.
Example: Generating a single image from a static prompt
This pipe generates one image of a futuristic car without requiring any input.
[pipe.generate_car_image]
type = "PipeImgGen"
description = "Generate a futuristic car image"
output = "Image"
prompt = "A sleek, futuristic sports car driving on a neon-lit highway at night."
model = "$gen-image"
aspect_ratio = "landscape_16_9"
Example: Generating an image from a dynamic prompt
This pipe takes a text prompt as input and generates an image.
[pipe.generate_from_description]
type = "PipeImgGen"
description = "Generate an image from a description"
inputs = { description = "Text" }
output = "Image"
prompt = "$description"
model = "$gen-image"
Example: Dynamic prompt with prefix text
You can combine static text with dynamic variables in the prompt:
[pipe.generate_sketch]
type = "PipeImgGen"
description = "Generate a black and white sketch from a description"
inputs = { subject = "Text" }
output = "Image"
prompt = "Create a black and white pencil sketch of: $subject"
model = "$gen-image"
Example: Generating multiple images
This pipe takes a text prompt as input and generates three variations of the image using bracket notation.
[pipe.generate_logo_variations]
type = "PipeImgGen"
description = "Generate three logo variations from a prompt"
inputs = { img_prompt = "Text" }
output = "Image[3]"
prompt = "$img_prompt"
model = "$gen-image"
aspect_ratio = "square"
Example: Image-to-image with a reference image
Declare an Image input and reference it in the prompt. At run time the referenced image is pulled from working memory, replaced in the text by an [Image N] placeholder, and passed to the generator alongside the rendered text — enabling image-to-image, reference-image, and editing generation.
[pipe.restyle_photo]
type = "PipeImgGen"
description = "Restyle a reference photo as an oil painting"
inputs = { ref = "Image" }
output = "Image"
prompt = "Repaint this photo as an oil painting in the style of Van Gogh: $ref"
model = "$gen-image"
You can also reference several images by declaring a list input. Each referenced image becomes its own [Image N] token, up to the model's max_prompt_images:
[pipe.blend_references]
type = "PipeImgGen"
description = "Blend multiple reference images into one scene"
inputs = { refs = "Image[]" }
output = "Image"
prompt = "Combine the styles of these reference images into a single coherent scene: $refs"
model = "$gen-image"
Image references also work through a dotted path to a nested image field (e.g. $page.page_view when the pipe declares page = "Page"), and through any of the $var, @var, or {{ var }} syntaxes. The image is detected from the concept the path reaches, so only the root is declared: an input name is a plain name, and a key such as "page.page_view" = "Image" is refused as invalid_input_name.
Inputs and outputs
The output of PipeImgGen has to be a concept compatible with the native Image concept — a concept is compatible if it refines Image. Its inputs are ordinary variables injected into the prompt template: Text-compatible variables are interpolated as text, and Image-compatible variables are injected as reference images (as shown above). There is no dedicated prompt concept anywhere in this flow.
To use the multiple-images example above, you would reference an ordinary Text stuff (e.g., "A minimalist logo for a coffee shop, featuring a stylized mountain and a coffee bean") from the prompt template. After running, the output will be a list containing three generated ImageContent objects.
Related Documentation
- Image Generation Feature - Overview of image generation capabilities
- Cloud Storage - Store generated images in cloud storage