# Tasks and polling

> Wait with generate(), return early with generateAsync(), how long the SDK polls, and how to hand a browser the pat_ token.

Every SDK call that does work creates a task. `generate()` polls that task for
you. `generateAsync()` returns a `TaskAsync` right after the task is created,
and you decide who waits.

```ts
import Mynth from "@mynthio/sdk";

const mynth = new Mynth();

const pending = await mynth.image.generateAsync({
  model: "black-forest-labs/flux.2-pro",
  prompt: "A lighthouse at dusk, film grain",
});

console.log(pending.id); // tsk_...
const task = await pending.wait();
console.log(task.urls[0]);
```

`image.generate()` is `generateAsync()` followed by `wait()`. The tools follow
the same pattern: `rate()` and `rateAsync()`, `alt()` and `altAsync()`,
`review()` and `reviewAsync()`, `removeBackground()` and
`removeBackgroundAsync()`, `video.generate()` and `video.generateAsync()`.
`upload()` and `video.estimate()` do not create tasks.

## `TaskAsync`

| Member   | Holds                                                                    |
| -------- | ------------------------------------------------------------------------ |
| `id`     | The task id                                                              |
| `access` | `{ publicAccessToken? }`, the browser token when the endpoint issues one |
| `wait()` | Polls until the task settles, then returns the result class              |

`wait()` polls until `completed`, then loads the full task and builds the
result. Calling it twice returns the same promise. A task that settles as
`failed` makes it throw `TaskAsyncTaskFailedError`.
[Errors](https://mynth.io/docs/sdks/typescript/errors.md) lists every throw.

## How long it polls

| Wait               | Interval                                       | Gives up after |
| ------------------ | ---------------------------------------------- | -------------- |
| Images and tools   | every 2.5 s for the first 12 s, then every 5 s | 30 minutes     |
| `video.generate()` | every 10 s                                     | 1 hour         |

Each sleep adds up to 500 ms of jitter. After the budget runs out, `wait()`
throws `TaskAsyncTimeoutError`. The task itself keeps running, and you can
still read it by id. Status reads that fail with a network error, a `404`, or
a `5xx` are retried, up to 20 in a row.

Hold the connection only where that wait is acceptable, such as a script or a
background worker. A request handler should store `pending.id`, respond, and
finish in a [webhook](https://mynth.io/docs/concepts/webhooks.md).

## Poll from the browser

`image.generateAsync()`, `image.removeBackgroundAsync()`, and
`video.generateAsync()` expose the task's `pat_` token as
`pending.access.publicAccessToken`. Rate, alt text, and review do not issue
one.

```ts
// server
const pending = await mynth.image.generateAsync({
  model: "black-forest-labs/flux.2-pro",
  prompt: "A lighthouse at dusk, film grain",
});

return Response.json({ taskId: pending.id, token: pending.access.publicAccessToken });
```

The browser calls `GET /tasks/{id}/status` and `GET /tasks/{id}/result` with
`Authorization: Bearer pat_...`. [Poll for results](https://mynth.io/docs/guides/poll-for-results.md#from-a-browser)
has the browser loop.

- The token works only on those two routes and expires one hour after it is
  issued. A long video render can outlive it.
- `publicAccessToken` can be missing if Mynth failed to sign one. Fall back
  to polling from the server.
- `wait()` is for the server. Its last call is `GET /tasks/{id}`, which a
  `pat_` cannot make.

## Partial results

`urls`, `getImages()`, and `getVideos()` skip failed items. Compare
`getImages().length` with `count` when a short list is a problem. A video
request renders one video, so a failed render shows up as an empty `urls` on a
completed task. [Tasks](https://mynth.io/docs/concepts/tasks.md#completed-does-not-mean-every-item-worked)
explains why a completed task can hold failed items.

## Next steps

- [Errors](https://mynth.io/docs/sdks/typescript/errors.md): what `wait()` throws, and how to read the code.
- [Webhooks](https://mynth.io/docs/concepts/webhooks.md): take the result without a polling loop.
- [Poll for results](https://mynth.io/docs/guides/poll-for-results.md): the REST loop.
