# Tâches asynchrones

> Comment LMSP exécute les longues générations sous forme de tâches persistées, avec création de tâche, machine à états, annulation idempotente, flux d’événements et politiques de redémarrage des tâches inachevées.

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

## 7.1 Créer une tâche {#create}

Un client crée une tâche en envoyant en POST la requête de réponse qu’il veut exécuter, enveloppée dans une enveloppe de tâche. Un en-tête `Idempotency-Key` est recommandé ([section 9.2](https://madeforagent.com/fr/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"
}
```

| Champ | Obligatoire | Signification |
| --- | --- | --- |
| `type` | Oui | `response`, le seul type de tâche de la version 1.0. |
| `input` | Oui | Une requête de réponse, exactement comme pour `POST /lmsp/v1/responses`. Son champ `stream` est ignoré. |
| `on_restart` | Non | `fail` (la valeur par défaut), `retry` ou `resume`. Voir la [section 7.5](https://madeforagent.com/fr/lmsp/1.0/tasks.md#restart). |

Le service **DOIT** persister la tâche avant de répondre. Il renvoie ensuite :

```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
}
```

| Champ de la tâche | Signification |
| --- | --- |
| `id` | Identifiant de la tâche, tel que `task_...`. |
| `object` | Toujours `"task"`. |
| `type` | `response`. |
| `status` | L’état courant ([section 7.2](https://madeforagent.com/fr/lmsp/1.0/tasks.md#states)). |
| `created_at`, `updated_at` | Dates en secondes depuis l’epoch Unix. |
| `response_id` | Identifiant de la réponse que produit la tâche. Il est attribué à la création de la tâche. |
| `events_url` | Chemin du flux d’événements. Présent lorsque la capacité `event_resume` vaut `true`. |
| `on_restart` | La politique de redémarrage de la tâche. |
| `response` | L’objet réponse une fois que `status` vaut `succeeded`, sinon `null`. |
| `error` | Un objet problème ([section 9.3](https://madeforagent.com/fr/lmsp/1.0/common-rules.md#errors)) lorsque `status` vaut `failed`, sinon `null`. |

`GET /lmsp/v1/tasks/{task_id}` renvoie l’objet tâche. Les clients qui n’utilisent pas les flux d’événements interrogent régulièrement ce point de terminaison. Un identifiant inconnu donne `404` avec `task_not_found`. Une tâche terminée ressemble à ceci :

```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 Machine à états {#states}

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

| État | Signification | États suivants |
| --- | --- | --- |
| `queued` | Acceptée et persistée, en attente de démarrage. | `loading`, `cancelled`, `failed` |
| `loading` | Le modèle est en cours de chargement. | `running`, `cancelling`, `failed` |
| `running` | Le modèle génère. | `succeeded`, `failed`, `cancelling` |
| `cancelling` | L’annulation a été demandée et le backend ne s’est pas encore arrêté. | `cancelled` |
| `succeeded` | Final. La réponse est complète. | aucun |
| `failed` | Final. | aucun |
| `cancelled` | Final. | aucun |

Les états terminaux sont `succeeded`, `failed` et `cancelled`. Une tâche dans un état terminal **NE DOIT PAS** changer de nouveau. Une tâche dont la réponse se termine à l’état `incomplete`, par exemple à la limite de tokens, est `succeeded`.

Chaque transition est atomique, si bien qu’une tâche n’est jamais à la fois annulée et terminée. La première transition validée l’emporte.

## 7.3 Annulation {#cancel}

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

Le service renvoie `200 OK` et l’objet tâche courant. Une tâche `queued` passe immédiatement à `cancelled`. Une tâche `loading` ou `running` passe à `cancelling` jusqu’à l’arrêt du backend, puis à `cancelled`.

L’annulation **DOIT** être idempotente. Annuler une tâche déjà `cancelling` ou `cancelled` renvoie la tâche courante et ne produit aucune nouvelle erreur.

Annuler une tâche qui a déjà `succeeded` ou `failed` reçoit la réponse `409` avec `task_not_cancelable`. Un identifiant inconnu donne `404` avec `task_not_found`.

## 7.4 Flux d’événements {#events}

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

Ce point de terminaison est facultatif. Il est disponible lorsque la capacité `event_resume` vaut `true`.

- Les événements sont les événements de réponse de la [section 6.3](https://madeforagent.com/fr/lmsp/1.0/responses.md#streaming), pour la réponse que produit la tâche. La numérotation et la reprise suivent la [section 6.4](https://madeforagent.com/fr/lmsp/1.0/responses.md#reconnection).
- Le flux commence par `response.created`, qui est enregistré à l’acceptation de la tâche. Il se termine par un seul événement final qui correspond à l’issue : `response.completed`, `response.incomplete`, `response.failed` ou `response.cancelled`.
- Un client qui se connecte tardivement reçoit d’abord les événements qu’il a manqués, puis les événements en direct. Le service ferme le flux après l’événement final.
- Les événements sont conservés pendant une durée de conservation ([section 11.2](https://madeforagent.com/fr/lmsp/1.0/persistence.md#rules)). Les événements plus anciens donnent `410 Gone` avec `event_history_expired`.

## 7.5 Sémantique du redémarrage {#restart}

`on_restart` indique ce qui arrive à une tâche inachevée lorsque le service redémarre :

| Valeur | Comportement |
| --- | --- |
| `fail` | La valeur par défaut. Le service marque la tâche inachevée `failed`, avec le code d’erreur `server_restarted`. |
| `retry` | Le service exécute de nouveau la tâche depuis le début. |
| `resume` | Le service reprend à partir d’un instantané. Cela n’est permis que lorsque le backend prend explicitement en charge les instantanés reprenables. Sinon, la requête de création est rejetée avec `400` et `unsupported_capability`. |

Une tâche à l’état `cancelling` lors du redémarrage du service achève son annulation et passe à `cancelled`, quelle que soit sa politique.

`retry` n’est pas recommandé comme valeur par défaut, car la tâche a peut-être déjà exécuté des outils ou produit des effets de bord externes. Un client qui choisit `retry` **DOIT** le combiner avec un `Idempotency-Key` et rendre idempotents ses appels d’outils.
