# 非同期タスク

> LMSP が長時間の生成を永続化されたタスクとして実行する方法。タスクの作成、状態遷移、冪等なキャンセル、イベントストリーム、未完了タスクの再起動ポリシーを定めます。

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

## 7.1 タスクの作成 {#create}

クライアントは、実行したいレスポンスリクエストをタスクエンベロープで包んで POST することでタスクを作成する。`Idempotency-Key` ヘッダーを付けることを推奨する（[9.2 節](https://madeforagent.com/ja/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"
}
```

| フィールド | 必須 | 意味 |
| --- | --- | --- |
| `type` | はい | `response`。1.0 で唯一のタスクタイプ。 |
| `input` | はい | `POST /lmsp/v1/responses` とまったく同じレスポンスリクエスト。その `stream` フィールドは無視される。 |
| `on_restart` | いいえ | `fail`（既定）、`retry`、`resume`。[7.5 節](https://madeforagent.com/ja/lmsp/1.0/tasks.md#restart)を参照。 |

サービスは、応答する前にタスクを永続化し**なければならない**。その後、次を返す。

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

| タスクのフィールド | 意味 |
| --- | --- |
| `id` | タスク識別子。例: `task_...`。 |
| `object` | 常に `"task"`。 |
| `type` | `response`。 |
| `status` | 現在の状態（[7.2 節](https://madeforagent.com/ja/lmsp/1.0/tasks.md#states)）。 |
| `created_at`, `updated_at` | Unix エポックからの秒数で表した時刻。 |
| `response_id` | タスクが生成するレスポンスの ID。タスクの作成時に割り当てられる。 |
| `events_url` | イベントストリームのパス。`event_resume` 機能が `true` のときに存在する。 |
| `on_restart` | タスクの再起動ポリシー。 |
| `response` | `status` が `succeeded` になるとレスポンスオブジェクト、それ以外は `null`。 |
| `error` | `status` が `failed` のときは problem オブジェクト（[9.3 節](https://madeforagent.com/ja/lmsp/1.0/common-rules.md#errors)）、それ以外は `null`。 |

`GET /lmsp/v1/tasks/{task_id}` はタスクオブジェクトを返す。イベントストリームを使わないクライアントは、このエンドポイントをポーリングする。未知の ID では `404` と `task_not_found` を返す。完了したタスクは次のようになる。

```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 状態遷移 {#states}

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

| 状態 | 意味 | 次の状態 |
| --- | --- | --- |
| `queued` | 受理され永続化済みで、開始を待っている。 | `loading`、`cancelled`、`failed` |
| `loading` | モデルをロード中。 | `running`、`cancelling`、`failed` |
| `running` | モデルが生成中。 | `succeeded`、`failed`、`cancelling` |
| `cancelling` | キャンセルが要求されたが、バックエンドはまだ停止していない。 | `cancelled` |
| `succeeded` | 終端。レスポンスは完了している。 | なし |
| `failed` | 終端。 | なし |
| `cancelled` | 終端。 | なし |

終端状態は `succeeded`、`failed`、`cancelled` である。終端状態のタスクは、再び変化し**てはならない**。レスポンスが `incomplete` で終わるタスク（たとえばトークン上限による）は `succeeded` である。

すべての遷移はアトミックであるため、タスクがキャンセルと完了の両方になることはない。先にコミットされた遷移が有効になる。

## 7.3 キャンセル {#cancel}

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

サービスは `200 OK` と現在のタスクオブジェクトを返す。`queued` のタスクは直ちに `cancelled` になる。`loading` または `running` のタスクは、バックエンドが停止するまで `cancelling` となり、その後 `cancelled` になる。

キャンセルは冪等で**なければならない**。すでに `cancelling` または `cancelled` のタスクをキャンセルしても、現在のタスクが返され、新しいエラーは生じない。

すでに `succeeded` または `failed` のタスクをキャンセルすると、`409` と `task_not_cancelable` で応答する。未知の ID では `404` と `task_not_found` を返す。

## 7.4 イベントストリーム {#events}

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

このエンドポイントは任意である。`event_resume` 機能が `true` のときに利用できる。

- イベントは、タスクが生成するレスポンスについての、[6.3 節](https://madeforagent.com/ja/lmsp/1.0/responses.md#streaming)のレスポンスイベントである。番号付けと再開は[6.4 節](https://madeforagent.com/ja/lmsp/1.0/responses.md#reconnection)に従う。
- ストリームは、タスクの受理時に記録される `response.created` で始まる。結果に対応する最終イベントを 1 つ送って終わる。`response.completed`、`response.incomplete`、`response.failed`、`response.cancelled` のいずれかである。
- 遅れて接続したクライアントは、まず取り逃したイベントを受け取り、その後でライブのイベントを受け取る。サービスは最終イベントの後にストリームを閉じる。
- イベントは保持期間の間、保存される（[11.2 節](https://madeforagent.com/ja/lmsp/1.0/persistence.md#rules)）。それより古いイベントを要求すると、`410 Gone` と `event_history_expired` が返る。

## 7.5 再起動時の動作 {#restart}

`on_restart` は、サービスの再起動時に未完了のタスクをどう扱うかを示す。

| 値 | 動作 |
| --- | --- |
| `fail` | 既定。サービスは未完了のタスクを `failed` とし、エラーコードは `server_restarted` とする。 |
| `retry` | サービスはタスクを最初からもう一度実行する。 |
| `resume` | サービスはスナップショットから続行する。これが許されるのは、バックエンドが再開可能なスナップショットに明示的に対応している場合だけである。そうでない場合、作成リクエストは `400` と `unsupported_capability` で拒否される。 |

サービスの再起動時に `cancelling` だったタスクは、ポリシーにかかわらず、キャンセルを完了して `cancelled` になる。

`retry` を既定にすることは推奨しない。タスクがすでにツールを実行していたり、外部への副作用を生じていたりする可能性があるためである。`retry` を選ぶクライアントは、`Idempotency-Key` と組み合わせ、かつツール呼び出しを冪等にし**なければならない**。
