> ## Documentation Index
> Fetch the complete documentation index at: https://adcp-docs-ja.pier1.co.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# コンテキストとセッション

> AdCP における context_id と task_id の使い分け、MCP および A2A プロトコルリクエストをまたいだ会話状態・セッション継続・拡張フィールドの管理方法。

AdCP はリクエスト間で状態を維持するために識別子とデータフィールドを利用します。これらを理解することは、効果的な統合を行う上で不可欠です。

## 主要な識別子

AdCP では用途の異なる 2 種類の識別子を使用します:

### context\_id と task\_id

| Identifier      | Purpose      | Lifespan     | Scope          |
| --------------- | ------------ | ------------ | -------------- |
| **context\_id** | 会話・セッションの継続  | 約 1 時間       | 複数のタスク呼び出しをまたぐ |
| **task\_id**    | 特定オペレーションの追跡 | 完了まで（数時間〜数日） | 個別オペレーション      |

**context\_id**:

* プロトコル層から付与（A2A は自動、MCP は手動）
* 会話履歴とセッション継続を提供
* 複数タスク呼び出し間の状態維持に使用
* タイムアウト後に失効（一般的に 1 時間）

**task\_id**:

* 非同期になり得る個別リクエストに固有
* 会話をまたいで存続
* オペレーションの進行状況を長期にわたり追跡
* タスク完了まで保持（複雑なメディアバイでは数日かかることも）
* 別の会話やセッションから参照可能

### 使用例

```javascript theme={null}
// First call - establishes context and creates task
const result = await call('create_media_buy', {
  brief: "Launch summer campaign"
});

const contextId = result.context_id;  // 会話継続に使用
const taskId = result.task_id;        // このメディアバイを追跡

// 同じ会話内の後続呼び出し - context_id を使用
const update1 = await call('update_media_buy', {
  context_id: contextId,    // Maintains conversation state
  task_id: taskId,          // References the specific media buy
  updates: {...}
});

// 数日後の別会話 - task_id のみで十分
const delivery = await call('get_media_buy_delivery', {
  task_id: taskId          // No context_id - this is a new conversation
});
```

## プロトコルの違い

* **A2A**: コンテキストはプロトコルが自動で管理
* **MCP**: `context_id` を手動で管理する必要あり

### A2A のコンテキスト（自動）

A2A はセッションをネイティブに扱うため、コンテキスト管理は不要です:

```javascript theme={null}
// A2A はコンテキストを自動管理
const task = await a2a.send({ message: {...} });
// contextId is managed by A2A protocol

// Follow-ups automatically use the same context
const followUp = await a2a.send({
  contextId: task.contextId,  // 任意 - A2A が追跡
  message: {...}
});
```

### MCP のコンテキスト（手動）

MCP では状態を維持するために明示的なコンテキスト管理が必要です:

```javascript theme={null}
// First call - no context
const result1 = await mcp.call('get_products', {
  brief: "Video ads"
});
const contextId = result1.context_id;  // 保存しておく！

// Follow-up - must include context_id
const result2 = await mcp.call('get_products', {
  context_id: contextId,  // 継続に必須
  brief: "Focus on premium inventory"
});
```

### MCP におけるコンテキスト管理パターン

```javascript theme={null}
class MCPSession {
  constructor(mcp) {
    this.mcp = mcp;
    this.contextId = null;
  }

  async call(method, params) {
    const result = await this.mcp.call(method, {
      ...params,
      context_id: this.contextId
    });
    this.contextId = result.context_id;  // 次の呼び出し用に更新
    return result;
  }
}
```

### MCP エージェント側: セッション ID フォールバック

多くの MCP クライアント（ChatGPT、Claude など）は `context_id` を渡しません。エージェントはトランスポートのセッション ID をフォールバックとして使用することで、自動的なセッション永続化を実現できます:

```typescript theme={null}
server.tool('get_products', schema, async (args, extra) => {
  // 明示的な context_id があればそれを使用し、なければ MCP sessionId にフォールバック
  const contextId = args.context_id ?? extra?.sessionId;

  const products = await generateProducts(args.brief, contextId);
  await productStore.save(contextId, products);

  return products;
});
```

これにより、シンプルなクライアントでも自動セッション永続化を利用しながら、再開可能なセッションを必要とする高度なバイヤーには明示的な制御を残せます。実装例は [Snap AdCP Agent](https://github.com/scope3data/snap-adcp) を参照してください。

## コンテキストが保持するもの

`context_id` はプロトコルに関わらず会話状態を保持します:

* 現在議論中のメディアバイや商品
* 検索結果と適用済みフィルター
* 会話履歴とユーザー意図
* セッション内で示されたユーザーの嗜好
* ワークフロー状態と一時的な判断

Note: メディアバイのステータスやクリエイティブアセット、パフォーマンスデータなど長期的なタスク状態は `context_id` ではなく `task_id` で追跡します。

## 拡張フィールド (`ext`)

拡張フィールドはプロトコル互換性を保ちつつ、プラットフォーム固有の機能を実現します。

### スキーマパターン

Extensions appear consistently across requests, responses, and domain objects:

```json theme={null}
{
  "product_id": "ctv_premium",
  "name": "Connected TV Premium Inventory",
  "ext": {
    "gam": {
      "order_id": "1234567890",
      "dashboard_url": "https://..."
    },
    "roku": {
      "content_genres": ["comedy", "drama"]
    }
  }
}
```

`ext` オブジェクトの特徴:

* 常に **任意**（必須にしない）
* 任意の有効な JSON 構造を許容
* 実装側は未知のフィールドでも必ず保持
* AdCP スキーマでバリデートしない（実装側での検証は可）

### 名前空間（重要）

拡張は必ずベンダー/プラットフォームごとの名前空間を用います:

```json theme={null}
// ✅ Correct - Namespaced
{
  "ext": {
    "gam": { "test_mode": true },
    "roku": { "app_ids": ["123"] }
  }
}

// ❌ Incorrect - Not namespaced
{
  "ext": {
    "test_mode": true,  // Missing namespace!
    "app_ids": ["123"]  // Which platform?
  }
}
```

## アプリケーションコンテキスト (`context`)

コンテキストは、レスポンスや Webhook でそのまま返される不透明な相関データを提供します。

### 主な特性

* エージェントはコンテキストを解析せず、動作に利用しません
* 呼び出し元の内部トラッキング用途のみに存在
* レスポンスや Webhook で内容を変えずに返されます

### 規範的なエコー契約

エージェントは以下のルールに従わなければなりません。コンプライアンスランナーはこれらを文字どおり検証し、バイヤーは相関のためにこれらに依存します。

1. **成功時のエコー。** 呼び出し元がリクエストにトップレベルの `context` オブジェクトを含めた場合、エージェントはレスポンスに同じオブジェクトをバイト単位で等価な形で含めなければなりません。これはレスポンスのステータスが `completed`、`submitted`、`working`、`input-required`、その他いかなる終端または中間状態であっても適用されます。
2. **エラー時のエコー。** 失敗レスポンスも `context` をそのままエコーしなければなりません。エラーパスでコンテキストを落とすと、バイヤーが最も必要とするまさにそのときに相関が壊れます。`adcp_error`、`errors[]`、その他いかなるエラーエンベロープを返すエージェントも、呼び出し元の `context` を引き継がなければなりません。
3. **非同期更新時のエコー。** プッシュ通知、Webhook ペイロード、および同じオペレーションに対してエージェントが発行するその後のメッセージは、元の `context` を引き継がなければなりません。エージェントは初回レスポンスと後続のステータス更新の間でコンテキストを落としてはなりません。`context.trace_id` で相関したバイヤーは、そのオペレーションのすべてのメッセージに同じトレースが現れることを期待します。
4. **合成の禁止。** 呼び出し元が `context` オブジェクトを提供しない場合、エージェントはそれを捏造してはなりません。コンテキストなしのリクエストへのレスポンスは `context` フィールドを省略しなければなりません（またはトランスポートの通常のシリアライズに従い null / 不在として発行します）。エージェント側からの合成コンテキストはコンフォーマンス違反です。コンテキストの要点は、それが呼び出し元によって所有されることにあります。
5. **改変の禁止。** エージェントはエコーするコンテキスト内のフィールドを追加・削除・改名・並べ替え・型変更してはなりません。JSON 等価性が適用されます。`{"a":1,"b":2}` と `{"b":2,"a":1}` は異なるシリアライズになり得ますが、キー集合と値が一致していればエコールール上は等価とみなされます。バイトリテラルの等価性に依存する検証器（例: 生の JSON をハッシュする MCP クライアント）は、エージェント側で安定したキー順序でシリアライズすべきです。
6. **アクションの禁止。** エージェントは `context` 内のいかなる値も解析・検証・ログ記録・分岐に利用してはなりません。コンテキストはエージェントにとって不透明です。構造化された識別子のように見える値も、それを解釈してよいという合図ではありません。

### Schema Pattern

```json theme={null}
{
  "tool": "create_media_buy",
  "arguments": {
    "packages": [...],
    "context": {
      "ui_session_id": "sess_abc123",
      "trace_id": "trace_xyz789",
      "internal_campaign_id": "camp_456"
    }
  }
}
```

レスポンスでも同じコンテキストが返されます:

```json theme={null}
{
  "status": "input-required",
  "message": "Media buy requires manual approval before activation.",
  "context_id": "ctx_ghi789",
  "context": {
    "ui_session_id": "sess_abc123",
    "trace_id": "trace_xyz789",
    "internal_campaign_id": "camp_456"
  }
}
```

### コンテキストの主な用途

1. **UI/セッショントラッキング** - 非同期処理間の状態維持
2. **リクエスト相関** - 分散システムでのリクエスト追跡
3. **内部 ID** - 内部データ構造へのマッピング
4. **組織コンテキスト** - マルチテナントの追跡

## 使い分けの指針

| Field        | Purpose      | Agent Reads? | Agent Modifies?       |
| ------------ | ------------ | ------------ | --------------------- |
| `context_id` | セッション継続      | Yes          | Yes (creates/updates) |
| `task_id`    | オペレーション追跡    | Yes          | Yes (creates)         |
| `ext`        | プラットフォーム固有設定 | MAY          | MAY add response data |
| `context`    | 不透明な相関情報     | NEVER        | NEVER                 |

### `ext` を使うとき:

* プラットフォーム側でデータを解釈する必要があります
* データがオペレーション動作に影響し得ます
* プラットフォーム固有の設定を表現します
* 複数オペレーションにわたりデータを残す必要があります

### `context` を使うとき:

* 呼び出し元の内部用途に限定されます
* エージェントの動作に決して影響させない
* 相関/トラッキングのみの目的です
* そのままの内容で返してほしい

## ベストプラクティス

### A2A の場合

* プロトコルにコンテキスト管理を任せる
* 必要に応じて contextId で会話を明示的に紐づける
* セッション管理を信頼します

### MCP の場合

* 呼び出し間で context\_id を必ず保持
* セッションラッパーを実装（上記パターン参照）
* コンテキストの有効期限（1 時間）に対応
* 新しいワークフローでは新規コンテキストを開始
* **Agents**: `context_id` が提供されない場合はトランスポートのセッション ID をフォールバックとして使用（[セッション ID フォールバック](#mcp-エージェント側-セッション-id-フォールバック)参照）

### 拡張フィールドについて

* 必ずベンダーキー配下で名前空間を分ける
* 拡張仕様を十分にドキュメント化します
* 共通パターンは標準化を提案することを検討

### アプリケーションコンテキストについて

* 不透明のままにし、エージェントが解釈する前提で構造化しません
* 大きなペイロードは避ける（コンテキストは全レスポンスで返されます）
* 相関用途のみに使い、運用データには使わない
