Skip to content

Tasks

A task says what a robot should do and how success shows: five fields of prose (description, scene, steps, success, failure) and an optional procedure, in one editable draft. Publishing writes an immutable, numbered revision. The Robots and Tasks guide walks through it.

Every method takes a task’s id, put under your account, or its full name, accounts/<ACCOUNT_UUID>/tasks/<TASK_ID>. An API key acts as the person who created it.

from qualia import Qualia
client = Qualia()
task = client.tasks.create(
"Restock shelf",
draft={"description": "Move every box from the tray to the shelf"},
)
task = client.tasks.update(task.id, success="The tray is empty")
revision = client.tasks.publish(task.id, etag=task.etag, note="first cut")
client.tasks.list(limit=20) # PaginatedPage of Task, newest first
client.tasks.get(task.id) # the task with its draft
client.tasks.revisions(task.id) # PaginatedPage of TaskRevision
client.tasks.revision(task.id, 1) # one published revision
client.tasks.delete(task.id, force=True) # account owners only

update saves only the fields you pass; draft= replaces the whole draft. A stale etag is refused with 409.

A reference is an episode that shows success, or a named failure or recovery mode. A task holds 1 to 3 success references and any number of modes, each with 1 or 2.

episode = "accounts/<ACCOUNT_UUID>/datasets/<DATASET_ID>/episodes/<EPISODE_ID>"
ref = client.tasks.add_reference(task.id, {"role": "SUCCESS", "episode": episode})
client.tasks.add_reference(
task.id,
{"role": "FAILURE", "mode": "slip", "episode": episode,
"startSeconds": 1.5, "endSeconds": 4.0},
)
page = client.tasks.references(task.id) # PaginatedPage of TaskReference
for r in page.items:
print(r.id, r.role, r.mode, r.episode)
client.tasks.delete_reference(task.id, ref.id) # the episode is untouched

client.task_drafts asks a VLM to draft the task from exactly its references. It never publishes.

client.task_drafts.estimate(task.id) # {"estimated_credits": ..., "min_cost": ...}
draft = client.task_drafts.create(task.id)
draft = client.task_drafts.wait(draft.name)
client.task_drafts.apply(draft) # saves the proposal as the task's draft
client.task_drafts.list(task.id) # PaginatedPage of TaskDraft

A draft is made as a person. A personal API key acts as the person who created it, so estimate, create and cancel work with it as they do signed in. A service key (one owned by a workspace or the organization) acts as no person and is refused (a person or their personal API key must draft a Task). list, get, wait and apply work with any key.

A task links the datasets and episodes recorded against it. A link is not an edit: the label training reads stays as it is.

where = f'linked_task = "{task.name}"'
client.datasets.list(filter=where) # PaginatedPage of qualia.v1.Dataset
client.episodes.list("-", filter=where) # every dataset's linked episodes
client.episodes.link_task(episode, task.id) # link one episode
client.episodes.link_task(episode, "") # remove its own link

An episode with no link of its own reads its dataset’s link (linked_task_inherited is true). Link a whole upload with client.datasets.update(dataset, linked_task=task.name).

A link keeps the revision the Task was at when it was made (linked_task_revision, 0 for a draft), and checks judge that revision. Publishing a new revision moves no link and starts no check. A dataset whose latest_task_revision is higher has drifted; relink it and rerun its checks:

bound = client.datasets.relink_task(dataset, validate_only=True).credit_bound
done = client.datasets.relink_task(dataset, max_cost=bound)
done.revision, done.check_runs # the new revision, the runs started