Skip to content

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.