# Tarefas assíncronas

> Como o LMSP executa gerações longas como tarefas persistidas, com criação de tarefas, a máquina de estados, cancelamento idempotente, fluxos de eventos e políticas de reinicialização para tarefas inacabadas.

Source: https://madeforagent.com/pt-br/lmsp/1.0/tasks/
Language: pt-BR
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 7.1 Criar uma tarefa {#create}

Um cliente cria uma tarefa enviando por POST a requisição de resposta que deseja executar, envolvida em um envelope de tarefa. Um cabeçalho `Idempotency-Key` é recomendado ([seção 9.2](https://madeforagent.com/pt-br/lmsp/1.0/common-rules.md#idempotency)).

```http
POST /lmsp/v1/tasks
Authorization: Bearer <token>
Idempotency-Key: 01J8M7C4Y3N5P8R2T6V9X1Z4BH
```

```json
{
  "type": "response",
  "input": {
    "model": "qwen3:14b-q4_k_m",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Write a long report."
          }
        ]
      }
    ]
  },
  "on_restart": "fail"
}
```

| Campo | Obrigatório | Significado |
| --- | --- | --- |
| `type` | Sim | `response`, o único tipo de tarefa na 1.0. |
| `input` | Sim | Uma requisição de resposta, exatamente como em `POST /lmsp/v1/responses`. Seu campo `stream` é ignorado. |
| `on_restart` | Não | `fail` (o padrão), `retry` ou `resume`. Veja a [seção 7.5](https://madeforagent.com/pt-br/lmsp/1.0/tasks.md#restart). |

O serviço **DEVE** persistir a tarefa antes de responder. Em seguida, ele retorna:

```http
HTTP/1.1 202 Accepted
```

```json
{
  "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC",
  "object": "task",
  "type": "response",
  "status": "queued",
  "created_at": 1794200100,
  "updated_at": 1794200100,
  "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW",
  "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events",
  "on_restart": "fail",
  "response": null,
  "error": null
}
```

| Campo da tarefa | Significado |
| --- | --- |
| `id` | Identificador da tarefa, como `task_...`. |
| `object` | Sempre `"task"`. |
| `type` | `response`. |
| `status` | O estado atual ([seção 7.2](https://madeforagent.com/pt-br/lmsp/1.0/tasks.md#states)). |
| `created_at`, `updated_at` | Momentos em segundos desde a época Unix. |
| `response_id` | ID da resposta que a tarefa produz. É atribuído quando a tarefa é criada. |
| `events_url` | Caminho do fluxo de eventos. Presente quando a capacidade `event_resume` é `true`. |
| `on_restart` | A política de reinicialização da tarefa. |
| `response` | O objeto de resposta quando `status` é `succeeded`; caso contrário, `null`. |
| `error` | Um objeto de problema ([seção 9.3](https://madeforagent.com/pt-br/lmsp/1.0/common-rules.md#errors)) quando `status` é `failed`; caso contrário, `null`. |

`GET /lmsp/v1/tasks/{task_id}` retorna o objeto da tarefa. Os clientes que não usam fluxos de eventos consultam este endpoint periodicamente. Um ID desconhecido resulta em `404` com `task_not_found`. Uma tarefa concluída tem esta aparência:

```json
{
  "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC",
  "object": "task",
  "type": "response",
  "status": "succeeded",
  "created_at": 1794200100,
  "updated_at": 1794200162,
  "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW",
  "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events",
  "on_restart": "fail",
  "response": {
    "id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW",
    "object": "response",
    "created_at": 1794200100,
    "status": "completed",
    "model": "qwen3:14b-q4_k_m",
    "output": [
      {
        "id": "msg_01J8M8R6A2C5E8G1J4M7P0S3VY",
        "type": "message",
        "role": "assistant",
        "content": [
          {
            "type": "output_text",
            "text": "Local model services make on-device inference a shared, discoverable utility..."
          }
        ]
      }
    ],
    "usage": {
      "input_tokens": 12,
      "output_tokens": 1480,
      "total_tokens": 1492
    },
    "error": null,
    "incomplete_details": null
  },
  "error": null
}
```

## 7.2 Máquina de estados {#states}

```text
queued --> loading --> running --> succeeded
  |           |           |
  |           |           +--> failed
  |           |           +--> cancelling --> cancelled
  |           +--------------> failed
  +--------------------------> cancelled
```

| Estado | Significado | Próximos estados |
| --- | --- | --- |
| `queued` | Aceita e persistida, aguardando para começar. | `loading`, `cancelled`, `failed` |
| `loading` | O modelo está sendo carregado. | `running`, `cancelling`, `failed` |
| `running` | O modelo está gerando. | `succeeded`, `failed`, `cancelling` |
| `cancelling` | O cancelamento foi solicitado, e o backend ainda não parou. | `cancelled` |
| `succeeded` | Final. A resposta está completa. | nenhum |
| `failed` | Final. | nenhum |
| `cancelled` | Final. | nenhum |

Os estados terminais são `succeeded`, `failed` e `cancelled`. Uma tarefa em estado terminal **NÃO DEVE** mudar novamente. Uma tarefa cuja resposta termina como `incomplete`, por exemplo no limite de tokens, é `succeeded`.

Toda transição é atômica, de modo que uma tarefa nunca fica cancelada e concluída ao mesmo tempo. Vale a transição que for confirmada primeiro.

## 7.3 Cancelamento {#cancel}

```http
POST /lmsp/v1/tasks/{task_id}/cancel
```

O serviço retorna `200 OK` e o objeto da tarefa atual. Uma tarefa `queued` passa a `cancelled` imediatamente. Uma tarefa `loading` ou `running` passa a `cancelling` até que o backend tenha parado e, depois, a `cancelled`.

O cancelamento **DEVE** ser idempotente. Cancelar uma tarefa que já está `cancelling` ou `cancelled` retorna a tarefa atual e não produz novo erro.

Cancelar uma tarefa que já está `succeeded` ou `failed` é respondido com `409` e `task_not_cancelable`. Um ID desconhecido resulta em `404` com `task_not_found`.

## 7.4 Fluxos de eventos {#events}

```http
GET /lmsp/v1/tasks/{task_id}/events
Accept: text/event-stream
```

Este endpoint é opcional. Ele está disponível quando a capacidade `event_resume` é `true`.

- Os eventos são os eventos de resposta da [seção 6.3](https://madeforagent.com/pt-br/lmsp/1.0/responses.md#streaming), para a resposta que a tarefa produz. A numeração e a retomada seguem a [seção 6.4](https://madeforagent.com/pt-br/lmsp/1.0/responses.md#reconnection).
- O fluxo começa com `response.created`, que é registrado quando a tarefa é aceita. Ele termina com um único evento final que corresponde ao resultado: `response.completed`, `response.incomplete`, `response.failed` ou `response.cancelled`.
- Um cliente que se conecta tarde recebe primeiro os eventos que perdeu e depois os eventos ao vivo. O serviço fecha o fluxo após o evento final.
- Os eventos são mantidos por um período de retenção ([seção 11.2](https://madeforagent.com/pt-br/lmsp/1.0/persistence.md#rules)). Eventos mais antigos resultam em `410 Gone` com `event_history_expired`.

## 7.5 Semântica de reinicialização {#restart}

`on_restart` define o que acontece com uma tarefa inacabada quando o serviço é reiniciado:

| Valor | Comportamento |
| --- | --- |
| `fail` | O padrão. O serviço marca a tarefa inacabada como `failed`, com o código de erro `server_restarted`. |
| `retry` | O serviço executa a tarefa novamente desde o início. |
| `resume` | O serviço continua a partir de um snapshot. Isso só é permitido quando o backend suporta explicitamente snapshots retomáveis. Caso contrário, a requisição de criação é rejeitada com `400` e `unsupported_capability`. |

Uma tarefa que está `cancelling` quando o serviço reinicia conclui o seu cancelamento e passa a `cancelled`, qualquer que seja a sua política.

`retry` não é recomendado como padrão, porque a tarefa pode já ter executado ferramentas ou produzido efeitos colaterais externos. Um cliente que escolhe `retry` **DEVE** combiná-lo com um `Idempotency-Key` e tornar suas chamadas de ferramentas idempotentes.
