> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Incremental Streaming

> Cloud Agent Session の増分ストリーミングイベントを有効化して検証します。

増分ストリーミングを使うと、クライアントは最終的な完全な `agent.message` イベントの前にアシスタント出力のチャンクを受信できます。Session の作成時に有効化します。

```json theme={null}
{
  "incremental_streaming_enabled": true
}
```

この設定は Session に保存されます。ストリームリクエストのクエリパラメータやヘッダーでは制御しません。

## エンドポイント

パスは変わりません。

| API                                                                  | 増分の動作                     |
| -------------------------------------------------------------------- | ------------------------- |
| `GET /api/v1/cloud/sessions/{session_id}/events/stream`              | ライブ Session SSE ストリーム     |
| `GET /api/v1/cloud/sessions/{session_id}/threads/{thread_id}/stream` | thread に限定したライブ SSE ストリーム |
| `GET /api/v1/cloud/sessions/{session_id}/events`                     | 過去の Session イベントのリプレイ     |
| `GET /api/v1/cloud/sessions/{session_id}/threads/{thread_id}/events` | thread に限定した過去イベントのリプレイ   |

`incremental_streaming_enabled` が `false` または省略されている場合、これらの API は元の動作を維持し、増分イベントを非表示にします。

## イベントモデル

公開イベントは qodercli/Anthropic の raw stream イベントと整合します。CAW は `message_start` や `content_block_start` などの raw stream イベントタイプを発行します。CAS は `type` に `agent.` プレフィックスを付け、`id`、`session_id`、`session_thread_id`、`turn_id`、`message_id`、`parent_tool_use_id`、`processed_at` などの CAS メタデータを追加して、それらを公開します。

トップレベルの増分イベントタイプ:

```text theme={null}
agent.message_start
agent.content_block_start
agent.content_block_delta
agent.content_block_stop
agent.message_delta
agent.message_stop
```

チャンクの種類は `agent.content_block_delta.delta.type` 内にネストされます。これらはトップレベルのイベントタイプではありません。

現在の実装では、`agent.content_block_start.content_block.type` は次のいずれかになります。

| `content_block.type` | 意味                                            |
| -------------------- | --------------------------------------------- |
| `thinking`           | 初期状態で空の `thinking` を持つ thinking ブロック          |
| `text`               | 初期状態で空の `text` を持つ text ブロック                  |
| `tool_use`           | `id`、`name`、初期状態で空の `input` を持つ tool-use ブロック |

| `delta.type`        | 意味                                                                                                |
| ------------------- | ------------------------------------------------------------------------------------------------- |
| `text_delta`        | テキスト出力のチャンク                                                                                       |
| `thinking_delta`    | モデル/プロバイダーが出力する場合の thinking チャンク                                                                  |
| `signature_delta`   | 利用可能な場合の thinking ブロックの署名チャンク                                                                     |
| `input_json_delta`  | ツール入力 JSON のチャンク。製品レベルの `tool_input_delta` 概念はこのワイヤー形を `partial_json` とともに使用します                   |
| `tool_output_delta` | 将来のツール出力ストリーミング向けに予約されています。現在の実装ではこの delta を発行しません。ツール結果は引き続き完全な `agent.tool_result` イベントとして返されます |

一般的なイベントの形:

```json theme={null}
{
  "type": "agent.message_start",
  "message_id": "asst_...",
  "message": {
    "id": "asst_...",
    "type": "message",
    "role": "assistant",
    "model": "qwen3-coder-plus",
    "content": [],
    "stop_reason": null,
    "stop_sequence": null,
    "usage": {
      "input_tokens": 0,
      "output_tokens": 0
    }
  }
}
```

```json theme={null}
{
  "type": "agent.content_block_delta",
  "message_id": "asst_...",
  "index": 0,
  "delta": {
    "type": "text_delta",
    "text": "Hello"
  }
}
```

```json theme={null}
{
  "type": "agent.message_delta",
  "message_id": "asst_...",
  "delta": {
    "stop_reason": "end_turn",
    "stop_sequence": null,
    "container": null
  },
  "usage": {
    "input_tokens": 123,
    "output_tokens": 45
  }
}
```

完全な `agent.message` は増分シーケンスの後に引き続き返され、正規の最終結果のままです。同じ text ブロックでは、`text_delta.text` を順に連結すると、最終的な `agent.message.content[index].text` と一致するはずです。プロバイダーがストリームチャンクから最後のサフィックスを省略する場合、CAW は `agent.content_block_stop` の前に、残りのサフィックスを最終的な `text_delta` として発行します。

## クイック検証

前提条件:

* `QODER_PAT` に有効な PAT
* `AGENT_ID` に既存の Agent ID
* `ENVIRONMENT_ID` に既存の Environment ID
* ローカルに `jq` がインストールされていること

API のベースを設定します。デフォルトでは本番のベースを使用するか、プレリリースのデプロイを検証する場合は Global Test のベースに置き換えてください。

```bash theme={null}
export BASE_URL="https://api.qoder.com/api/v1/cloud"
# export BASE_URL="https://test-api.qoder.ai/api/v1/cloud"

export QODER_PAT="pat_..."
export AGENT_ID="agent_..."
export AGENT_VERSION="1"
export ENVIRONMENT_ID="env_..."
```

増分ストリーミングを有効にして Session を作成します。

```bash theme={null}
SESSION_JSON=$(
  jq -n \
    --arg agent_id "$AGENT_ID" \
    --argjson agent_version "$AGENT_VERSION" \
    --arg environment_id "$ENVIRONMENT_ID" \
    '{
      agent: {id: $agent_id, type: "agent", version: $agent_version},
      environment_id: $environment_id,
      title: "incremental streaming verification",
      incremental_streaming_enabled: true
    }' |
  curl -s -X POST "$BASE_URL/sessions" \
    -H "Authorization: Bearer $QODER_PAT" \
    -H "Content-Type: application/json" \
    --data-binary @-
)

export SESSION_ID=$(echo "$SESSION_JSON" | jq -r '.id')
echo "$SESSION_JSON" | jq '{id, incremental_streaming_enabled, status}'
```

想定されるレスポンス:

```json theme={null}
{
  "id": "sess_...",
  "incremental_streaming_enabled": true,
  "status": "idle"
}
```

1 つのターミナルで Session の SSE ストリームを開きます。

```bash theme={null}
curl -sN "$BASE_URL/sessions/$SESSION_ID/events/stream" \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Accept: text/event-stream" |
while IFS= read -r line; do
  case "$line" in
    event:*) echo "$line" ;;
    data:*) echo "${line#data: }" | jq -cr '{type, message_id, index, block_type: .content_block.type, delta_type: .delta.type, text: .delta.text, thinking: .delta.thinking, partial_json: .delta.partial_json}' ;;
  esac
done
```

別のターミナルからユーザーメッセージを送信します。

```bash theme={null}
curl -s -X POST "$BASE_URL/sessions/$SESSION_ID/events" \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "type": "user.message",
        "content": [
          {"type": "text", "text": "Reply with exactly one short sentence."}
        ]
      }
    ]
  }' | jq
```

ストリームには、最終的な完全イベントの前に増分シーケンスが表示されるはずです。

```text theme={null}
event: agent.message_start
event: agent.content_block_start
event: agent.content_block_delta
{"type":"agent.content_block_delta","delta_type":"text_delta","text":"..."}
event: agent.content_block_stop
event: agent.message_delta
event: agent.message_stop
event: agent.message
event: session.status_idle
```

過去イベントのリプレイを検証します。

```bash theme={null}
curl -s "$BASE_URL/sessions/$SESSION_ID/events?limit=200" \
  -H "Authorization: Bearer $QODER_PAT" |
jq -r '.data[].type' |
grep -E 'agent\.message_start|agent\.content_block_delta|agent\.message_stop'
```

thread に限定したリプレイとストリームを検証します。

```bash theme={null}
export THREAD_ID=$(
  curl -s "$BASE_URL/sessions/$SESSION_ID/threads?limit=20" \
    -H "Authorization: Bearer $QODER_PAT" |
  jq -r '.data[0].id'
)

curl -s "$BASE_URL/sessions/$SESSION_ID/threads/$THREAD_ID/events?limit=200" \
  -H "Authorization: Bearer $QODER_PAT" |
jq -r '.data[].type' |
grep -E 'agent\.message_start|agent\.content_block_delta|agent\.message_stop'
```

thread に限定したライブストリームを観察するには、thread stream エンドポイントに対して同じパーサーループを使用します。

```bash theme={null}
curl -sN "$BASE_URL/sessions/$SESSION_ID/threads/$THREAD_ID/stream" \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Accept: text/event-stream" |
while IFS= read -r line; do
  case "$line" in
    event:*) echo "$line" ;;
    data:*) echo "${line#data: }" | jq -cr '{type, message_id, index, block_type: .content_block.type, delta_type: .delta.type, text: .delta.text, thinking: .delta.thinking, partial_json: .delta.partial_json}' ;;
  esac
done
```

## 無効化した場合の対照確認

`incremental_streaming_enabled` を付けずに、または `false` に設定して、別の Session を作成します。レスポンスには次が含まれるはずです。

```json theme={null}
{
  "incremental_streaming_enabled": false
}
```

同じ `user.message` を送信した後、ストリームと履歴には `agent.message` や `session.status_idle` などの完全イベントが含まれますが、上記の増分イベントタイプは含まれません。

## パーサーのチェックリスト

* SSE の `event:` と JSON の `data.type` を公開イベントタイプとして扱う。
* `delta.type` が `text_delta` のイベントについて、`agent.content_block_delta.delta.text` を連結してテキストを再構築する。
* `delta.type` が `thinking_delta` のイベントについて、`agent.content_block_delta.delta.thinking` を連結して thinking を再構築する。完全な互換用 `agent.thinking` イベントが後で届くこともある。
* ツール入力の増分については、`delta.type == "input_json_delta"` を確認して `delta.partial_json` を連結する。トップレベルの `tool_input_delta` イベントは期待しないこと。
* `tool_output_delta` はまだ発行されない。ツール実行結果は完全な `agent.tool_result` イベントとして返される。
* 複数の content block を区別するために `index` を追跡する。
* agent 生成イベントでは `processed_at` を任意として扱う。
* 同じ接続で複数ターンをサポートするクライアントの場合、`session.status_idle` の後もリッスンを続ける。
* ネットワーク切断後は `Last-Event-ID` を付けて再接続する。
