Run a background Task
Use an on-demand Task when an Agent should complete work asynchronously without a schedule. This guide creates the definition, submits one run, and verifies both its status and transcript.
Outcome
You will obtain a terminal Task run and its final assistant message. The main
path expects succeeded; production code must also handle blocked, failed,
and canceled.
Before you begin
You need an enabled Agent, its agentId, a configured backend SDK client, and
a fixed instruction for the Task. Review Tasks and schedules,
Sessions and Turns, and
Versions and lifecycle.
Create an on-demand Task
Create the Task with agentId, name, and prompt. Omitting schedule
stores null; enabled, submit, userId, metadata, and
agentVersion default to true, false, "", {}, and null. A null
agentVersion resolves the Agent's latest Version when each run is
enqueued. Set a Version number to Pin future runs of this Task.
Submit an idempotent run
Pass a stable, Task-scoped business key to createRun. Repeating the same
key for the same tenant and Task resolves to the same run ID. A different
submission while that Task has a queued or running run is rejected because
only one run can be active.
Wait for completion
Poll getRun with a bounded loop. queued and running are active;
blocked, succeeded, failed, and canceled are terminal.
Read the transcript
Every executing run receives a fresh Session. runMessages returns its
UIMessage transcript; the final response is the last message whose role
is assistant. A run blocked before Session creation has an empty
transcript.
Treat run.error as an untrusted, potentially sensitive arbitrary error
message. Redact it before logging or sharing; do not interpolate it into a
newly thrown error.
Cancel an active run
To exercise cancellation, use this five-line branch with the primary
example's waitForTerminal helper. It submits a fresh run and immediately
requests cancellation while the run can still be active. Missing,
mismatched, already terminal, and repeated cancellations are no-op 204
responses for an owned Task.
const cancelInput = { idempotencyKey: `weekly-report-cancel:${weekStart}` };
const cancellation = await client.tasks.createRun(task.id, cancelInput);
await client.tasks.cancelRun(task.id, cancellation.runId);
const canceled = await waitForTerminal(task.id, cancellation.runId);
console.log(canceled.status);Cancellation can race normal completion; branch on the terminal status
you observe instead of assuming canceled.
Verify the terminal state
const terminal = new Set(["blocked", "succeeded", "failed", "canceled"]);
async function waitForTerminal(taskId: string, runId: string) {
let run = await client.tasks.getRun(taskId, runId);
for (let attempt = 0; attempt < 60 && !terminal.has(run.status); attempt++) {
await new Promise((resolve) => setTimeout(resolve, 1_000));
run = await client.tasks.getRun(taskId, runId);
}
if (!terminal.has(run.status)) throw new Error("Task polling timed out");
return run;
}
const { task } = await client.tasks.create({
agentId,
name: "Build weekly report",
prompt: "Build the weekly report and summarize the result.",
});
const { runId } = await client.tasks.createRun(task.id, {
idempotencyKey: `weekly-report:${weekStart}`,
});
const run = await waitForTerminal(task.id, runId);
const messages = await client.tasks.runMessages(task.id, runId);
const finalResponse = messages.data.findLast(
(message) => message.role === "assistant",
);
if (run.status !== "succeeded" || !finalResponse) {
throw new Error(`Task verification failed with status ${run.status}`);
}
console.log(finalResponse.parts);The check proves that the documented terminal state and at least one assistant transcript message are both observable without propagating the raw run error.
Production notes
- Keep idempotency keys stable across client retries. Task creation and
submit: trueare not idempotent; create the Task first, then usecreateRunwhen submission deduplication matters. - Task execution is at-most-once. Recovery returns a recorded completed outcome without rerunning the Turn; an interrupted claimed Turn is finalized as failed rather than replaying model or Tool effects.
- Updating
agentVersionchanges the Pin for future runs.nullrestores latest-Version resolution; each run records the Version it actually used. - A Task is preflighted before Session creation and checked again at the normal
Turn gate. Quota denial ends as
blocked, notfailed. - Read Limits and reliability and Usage and quotas before setting retry and alert policy.
Related capabilities
- Tasks and schedules
- Sessions and Turns
- Versions and lifecycle
- Usage and quotas
- Limits and reliability
SDK and REST reference
See the TypeScript SDK operations for
create,
createRun,
getRun,
runMessages, and
cancelRun. The matching REST
contracts are Tasks,
create Task run,
get Task run,
list Task run messages,
and cancel Task run.