---
title: Event のストリーミング
description: Session のログを SSE で追尾し、接続が切れたら止まったところから再開する。
sidebar:
  order: 1
---

永続的な event ログの要点は、それを見ているかどうかが任意だということです。Run は誰かがつながっているかどうかに関わらず進み続け、再接続すればログが見逃したことをすべて教えてくれます。

## ログを読む

2 つのエンドポイントが同じ event を読みます。ページングするほうはすでに起きた session に追いつくためのもので、ストリームはいま起きているものを見るためのものです。

```http
GET /v1/sessions/{session_id}/events
GET /v1/sessions/{session_id}/events/stream
```

```bash
curl -N "https://api.us.cloud.subako.ai/v1/sessions/$SESSION_ID/events/stream" \
  -H "Authorization: Bearer $SUBAKO_SESSION_TOKEN"
```

どちらのエンドポイントも **session token** を取ります — [作成した session](/ja/quickstart) が返した `id` と `session_token` で、ここでは `SESSION_ID` と `SUBAKO_SESSION_TOKEN` に入っています。API key でも動きますが、ブラウザに渡すべきなのは session ひとつを読めるトークンのほうです。

## ストリームはどこから始まるか

カーソルなしで接続すると、ログの **現在の先頭** から追尾します。これから起きることは見えますが、すでに起きたことは見えません。これはこれから自分で動かす session には望ましい挙動ですが、すでに進行中の session には向きません — そこでは run の冒頭の event を取り逃し、run がすでに終わっていれば何も受け取れません。

`after_seq` は開始点を指定し、そのシーケンス番号より厳密に大きい event を送ります。`after_seq=0` はログ全体を再生してからライブに続くので、ひとつの接続で追いつきと追尾を同時に行えます。

```bash
curl -N "https://api.us.cloud.subako.ai/v1/sessions/$SESSION_ID/events/stream?after_seq=0" \
  -H "Authorization: Bearer $SUBAKO_SESSION_TOKEN"
```

SSE のフレームはそれぞれ 3 つのフィールドを持ちます。

| フィールド | 内容 |
| --- | --- |
| `id` | その event のシーケンス番号 — 再接続の再開点 |
| `event` | Event の種類。例: `message_assistant` |
| `data` | ページングするエンドポイントがその event について返すのと同じ本体 |

## 切断からの再開

実際に処理し終えた最後のシーケンス番号を `Last-Event-ID` に設定して再接続します。ストリームはその直後から再生し、そのままライブに続きます。

```bash
curl -N "https://api.us.cloud.subako.ai/v1/sessions/$SESSION_ID/events/stream" \
  -H "Authorization: Bearer $SUBAKO_SESSION_TOKEN" \
  -H "Last-Event-ID: 42"
```

ブラウザでは、`EventSource` が最後に見た `id` を使って再接続時にそのヘッダーを送ってくれます。これを正しく保つルールが 2 つあります。

1. **event を処理し終えてからカーソルを進める**

    このヘッダーは、届いたものではなく処理し終えたものについての約束です。
    カーソルはハンドラーの最後で動かしてください。

2. **event は再生されうるものとして扱う**

    カーソルが遅れていれば、再接続によってすでに見た event
    が渡されることがあります。UI
    の状態は、無条件に追加するのではなくシーケンス番号を手がかりにしてください。

## Run の終わりを知る

Run は次の 3 つの event のちょうどひとつで終わります。

```txt
run_completed   the turn finished with nothing left to do
run_failed      it stopped on an error; `error` carries the text
run_cancelled   a cancel request was honored
```

Run が終わってもストリームは閉じません — session はまだそこにあり、さらに入力を追記すれば次の run が始まります。特定の run を待っているなら、接続が閉じるのを待つのではなく、終端 event に載る `run_id` を見てください。

```http
POST /v1/sessions/{session_id}/cancel
```

キャンセルは、いまの run に停止を求めるものです。強制終了ではなく要求なので、すでにログにコミットされたものはそこに残り、要求が届いたところで run は `run_cancelled` で終わります。

:::note
ログが完全な真実である以上、正しさのためにストリームを開き続ける必要はありません。ページングするエンドポイントを数秒おきにポーリングする worker も、ストリーミングするクライアントとまったく同じものを、少し遅れて見ることになります。
:::
