Skip to content
Go To Dashboard

Generate Images

Image Generation lets a deployed agent turn a prompt into one or more images. Agent steps call the typed ctx.sapiom.contentGeneration.images capability; Sapiom supplies the authenticated cloud connection when the deployed agent runs.

What the agent needsRecommended operation or input
Generate and wait in the current stepcontentGeneration.images.create(...)
Suspend the workflow while generation finishesimages.launch(...) plus pauseUntilSignal(...)
More than one imageSet count
A durable private assetstorage: { visibility: "private" }
An asset intended for public sharingstorage: { visibility: "public" }
A video rather than an imageSee Generate Video

Use create for an ordinary blocking step. Use launch when the workflow should pause and resume on the completed generation instead of holding the launching step open.

const generation = await ctx.sapiom.contentGeneration.images.create({
prompt:
"Editorial illustration of a solar-powered city block at sunrise, clean geometric forms",
aspectRatio: "16:9",
count: 2,
storage: { visibility: "private" },
});
const images = generation.images ?? [];
if (images.length === 0) {
throw new Error("Image generation returned no images");
}
return {
resolvedModel: generation.resolvedModel,
images: images.map((image) => {
if (image.storageError) {
throw new Error(`Image persistence failed: ${image.storageError}`);
}
return {
fileId: image.fileId ?? null,
temporaryUrl: image.url,
width: image.width ?? null,
height: image.height ?? null,
};
}),
};

The result includes the resolvedModel and an optional images array. Each image has a provider-hosted url and can include dimensions and content type. Treat the provider URL as temporary.

When storage succeeds, retain fileId as the durable reference. A returned downloadUrl is convenient but short-lived; mint a fresh one later with ctx.sapiom.fileStorage.getDownloadUrl(fileId). Persistence is per output, so inspect storageError on every image rather than assuming the whole batch stored successfully.

Control the output without pinning a provider

Section titled “Control the output without pinning a provider”

Omit model unless the agent needs a specific Sapiom routing alias. Prefer the neutral fields—aspectRatio, count, seed, negativePrompt, referenceImage, and outputFormat—over provider-specific passthrough values. A field unsupported by the selected model is rejected rather than silently ignored.

Generation is not guaranteed to be visually identical across models or service updates. Use a deterministic seed only where the selected model supports it, and test downstream code against the returned shape rather than pixel identity.

images.launch returns a handle with a request ID, resolved model, wait(), and the signal metadata required by pauseUntilSignal. The signal is IMAGE_RESULT_SIGNAL and the resumed step receives an ImageResultPayload; import both from @sapiom/tools.

Declare the static pause edge on the launching step. Both signal and resumeStep are required, and the declaration is what allows that step’s run to return a pause directive:

import {
defineStep,
pauseUntilSignal,
terminate,
type AgentExecutionContext,
} from "@sapiom/agent";
import { IMAGE_RESULT_SIGNAL, type ImageResultPayload } from "@sapiom/tools";
const generateHero = defineStep({
name: "generate-hero",
pause: { signal: IMAGE_RESULT_SIGNAL, resumeStep: "use-image" },
async run(input: { prompt: string }, ctx: AgentExecutionContext) {
const handle = await ctx.sapiom.contentGeneration.images.launch({
prompt: input.prompt,
storage: { visibility: "private" },
});
return pauseUntilSignal(handle, { resumeStep: "use-image" });
},
});
const useImage = defineStep({
name: "use-image",
terminal: true,
async run(result: ImageResultPayload, ctx: AgentExecutionContext) {
const output = result.outputs[0];
if (!output?.fileId) {
throw new Error("Resumed without a stored image");
}
return terminate({ fileId: output.fileId });
},
});

The resume target declares no pause of its own — it receives the payload as its input. That payload is an outputs array plus the generation’s resolvedModel, not the live handle or the same images wrapper returned by create(), and it carries one entry per generated image. Import ImageResultPayload instead of hand-writing that shape.

A downloadUrl on a resumed output may already have expired, since the step can resume long after the URL was minted. Re-fetch from fileId rather than treating a missing or stale URL as a missing asset.

handle.wait() is the alternative to pausing: it polls inline and resolves the same result create would, accepting timeoutMs and pollMs (2 minutes and 2 seconds by default). A generation that fails is not currently distinguishable from a slow one on that path — the call surfaces the timeout error either way — so prefer the pause and resume path for long generations, where the completion signal drives the resume instead of a deadline.

Local Run replaces image generation with deterministic data and does not generate or store an image. Override the exact path when the step requires a stored output or a particular failure:

{
"version": 1,
"steps": {
"generate-hero": {
"contentGeneration.images.create": {
"images": [
{
"url": "https://fixtures.example/hero.png",
"contentType": "image/png",
"width": 1280,
"height": 720,
"fileId": "file-hero-local",
"downloadUrl": "https://fixtures.example/hero-download",
"downloadUrlExpiresAt": "2099-01-01T00:00:00.000Z"
}
],
"resolvedModel": "stub-model"
}
}
}
}

contentGeneration.images.launch can use its own override or the shared create result. After the run, assert the terminal output and require both unusedStubs and stubWarnings to be empty. A passing fixture does not prove live model availability, visual quality, storage, latency, or usage.

Image count, model route, dimensions, and persistence can affect runtime usage. Generate only the variants the decision needs, avoid retrying a satisfactory output, and request storage only when the result must survive the provider URL.

Use the signed-in capability catalog for current models, limits, and pricing. Do not copy a model inventory or fixed rate into the agent.