# Generating launch images and short videos from an agent (/blog/generate-launch-assets-with-media-tools)

![Illustration: A small friendly robot with a round camera-eye head paints a bold orange circle on a canvas on an easel.](/blog/generate-launch-assets-with-media-tools/hero.webp)

An agent generates launch assets through four media tools: `media__list_models` to pick a model, `media__get_model` to read its schema and rate, `media__generate` to run it, and `media__get_result` to collect the output. An image's `art_*` id feeds the next generation, so an image to video chain stays inside CoreSpeed.

Every product name, prompt and credit figure in this post is a fictional example, except the rates quoted from the docs. The tool names are real.

**Pick, price, generate, collect**

**List models** (media\_\_list\_models by kind, name or category) → **Read the rate** (media\_\_get\_model: input\_schema and credits\_per\_unit) → **Generate** (media\_\_generate: assets inline or a job\_id) → **Collect** (media\_\_get\_result: the job and fresh signed URLs)

Failures, cancels and expiries never charge. Signed URLs expire after 12 hours; call media\_\_get\_result again.

The rate comes from the catalog before anything runs; billing happens after success.

## How does the agent pick a model? \[#how-does-the-agent-pick-a-model]

The catalog holds more than a thousand hosted image, video and audio models. `media__list_models` searches it by name, by `kind` (image, video or audio) or by exact `category`, and returns credit rates with each entry. With no arguments it returns the featured picks.

Before generating, the agent calls `media__get_model` for the chosen id. The result carries the model's `input_schema` and a structured `price`. The price is a rate, never a total:

```json
{ "state": "priced", "credits_per_unit": 4, "unit": "image" }
```

A price of `state: "unavailable"` means there is no rate right now. Generation is refused with `pricing_unavailable` rather than billed blind; retry shortly. The schema and the rate both come from the catalog, never from the client.

## How does a generation run? \[#how-does-a-generation-run]

For a fictional launch of a product called Driftwood, the agent builds `input` against the image model's schema: a prompt, a size, a count. Unknown top-level keys are rejected. Safety parameters are policy: any `safety*`, `nsfw*` or `moderation*` key is discarded and the safe value enforced on the server.

`wait_seconds` (default 45, max 300) is the time budget for the whole call. Inside it, the server answers one of two ways: the finished assets inline, each with an `art_*` id and a signed URL, or a running `job_id`. A running job keeps going on the server for up to 60 minutes. Any agent in the organization can collect it with `media__get_result`, which also takes `wait_seconds` to long-poll.

| Tool                   | Role in the flow                              |
| ---------------------- | --------------------------------------------- |
| `media__list_models`   | Find a model by kind, name or category        |
| `media__get_model`     | Read its input schema and rate before running |
| `media__generate`      | Run it, inline or as a job                    |
| `media__get_result`    | Collect a job and fresh signed URLs           |
| `media__list_jobs`     | Find a job when the client timed out          |
| `media__cancel`        | Stop a running job, never charged             |
| `media__create_upload` | Mint a one-use upload URL for a private file  |
| `media__understand`    | Ask a question about a finished asset         |

Three rules from the [Media docs](/docs/media) keep this from costing you twice. Do not set a client-side tool timeout at or below `wait_seconds`; that kills the reply carrying your `job_id`. If the client timed out anyway, the newest entry in `media__list_jobs` is your job, so do not resubmit. Signed URLs expire after 12 hours; call `media__get_result` again for a fresh set, and the stored artifact stays put.

## How does the image become a video? \[#how-does-the-image-become-a-video]

File-typed inputs accept three sources: a public `https` URL, a `cs_file_*` upload handle, or an `art_*` artifact id from an earlier generation. The chain is three calls.

First, the agent uploads the Driftwood logo. `media__create_upload` takes the exact `mime_type` and `size_bytes` and returns a `cs_file_*` handle, an upload URL and the headers to send. The agent PUTs the bytes within 10 minutes; the handle stays valid for 48 hours, and files up to 2 GB are accepted.

Second, it generates a hero image with the logo handle as a reference input, and gets back an `art_*` id.

Third, it picks a video model with `media__list_models` and `kind: "video"`, reads its schema and rate with `media__get_model`, and passes the `art_*` id as the image input. Video runs long, so the agent sets `wait_seconds` high or collects the job later. The image never leaves CoreSpeed between steps.

## What does it cost? \[#what-does-it-cost]

Generation is billed once, after success, at the model's rate times the usage the upstream reports. Failures, cancels and expiries never charge. For video, check `media__get_model` first; the rate is per model and the final amount can differ from the rate card when the output size is only known afterward.

For a quick check, the agent asks `media__understand` whether the hero image spells the product name correctly. Understanding bills 0.5 credits per image plus answer tokens; the question itself is free. Every charge lands itemized in the organization [ledger](/docs/billing), and an API key's monthly spend cap applies to media calls the same way as to any other metered call.

## Where do the assets show up? \[#where-do-the-assets-show-up]

Dashboard → Media shows everything the organization generated, whichever agent started the job. From there, the agent can hand the signed URL to a connector, for example `slack__post_message` to the launch channel. That post is a write, so if Smart Approval is on, your [policy](/docs/approvals) decides whether it runs, asks, or is refused.

## FAQ \[#faq]

**Does a failed generation cost credits?** No. Failures, cancels and expiries never charge. Only a successful generation bills, at the model's rate.

**The client timed out before I got a job id. Is the job lost?** No. The newest entry in `media__list_jobs` is your job. Collect it with `media__get_result` and do not resubmit.

**Can a different agent collect a job this one started?** Yes. Any agent in the organization can call `media__get_result` with the job id.

**Can I pass a file from my laptop?** Yes. `media__create_upload` mints a one-use PUT URL. Upload within 10 minutes, then use the `cs_file_*` handle for up to 48 hours.