Chaining models¶
Any file field takes an earlier run's id, and uses that run's answer:
{"image": "exec_..."}
{"image": {"execution": "exec_...", "item": 2}}
{"mask": {"execution": "exec_..."}}
{"prompt": {"execution": "exec_..."}}
The field decides what is taken: a file field takes the answer's file, a text
field its text, and a field like mask the whole answer. Nothing leaves our
side between steps, so a 3D model or a long video is not downloaded and uploaded
again.
When an answer cannot fill a field, the refusal names the model that converts
it. Masks are not a picture, for example; image-cutout makes one from them.
Example: find an object, cut it out, ask about it¶
Three models - segmentation, an image operation, and a vision-language model - each taking the one before it by id.
# 1. Find the object
curl $API/v1/executions -H "$AUTH" -H "Content-Type: application/json" \
-d '{"model": "sam3-segment",
"input": {"image": "med_PHOTO", "objects": [{"id": "ball", "text": "blue ball"}]}}'
# -> "id": "exec_SEG"
# 2. Cut it out of the photo, cropped to the object
curl $API/v1/executions -H "$AUTH" -H "Content-Type: application/json" \
-d '{"model": "image-cutout",
"input": {"image": "med_PHOTO", "mask": "exec_SEG", "object": "ball", "crop": true}}'
# -> "id": "exec_CUT"
# 3. Ask a vision model about the cut-out
curl $API/v1/executions -H "$AUTH" -H "Content-Type: application/json" \
-d '{"model": "gemini-3.8-flash",
"input": {"image": "exec_CUT", "prompt": "What is this, and is it damaged?"}}'
seg = f.run(model="sam3-segment", input={
"image": "photo.jpg", "objects": [{"id": "ball", "text": "blue ball"}]})
cut = f.run(model="image-cutout", input={
"image": "photo.jpg", "mask": seg.id, "object": "ball", "crop": True})
ask = f.run(model="gemini-3.8-flash", input={
"image": cut.id, "prompt": "What is this, and is it damaged?"})
print(ask.text)
const photo = await upload("photo.jpg");
const seg = await run("sam3-segment", { image: photo, objects: [{ id: "ball", text: "blue ball" }] });
const cut = await run("image-cutout", { image: photo, mask: seg.id, object: "ball", crop: true });
const ask = await run("gemini-3.8-flash", { image: cut.id, prompt: "What is this, and is it damaged?" });
console.log(ask.output.text);
upload and run are the two functions from the Quickstart.
This exact chain costs about a cent.
The glue models¶
Small, fast, a tenth of a cent or less - the steps between the models that do the work:
| Model | What it does |
|---|---|
image-cutout |
One object out of a picture, by its mask |
image-crop |
Each detected or segmented object as its own picture, or any boxes you give |
image-overlay |
Masks and boxes drawn on a picture, coloured and labelled |
image-resize |
Smaller, or another format |
video-frames |
Pictures from a video, every N seconds or at chosen times |
video-clip |
A stretch of a video |
video-downsample |
A video made smaller |
video-scenes |
One keyframe per scene, with when each starts and ends |
Steps that wait for each other¶
The runs above are called one after another. To submit a whole graph at once - each step starting as soon as the steps it uses have finished, the server carrying it on if your process goes away - use a workflow. Most pipelines do not need one.