Skip to main content
すべての AdCP レスポンスには status フィールドが含まれ、現在の状態と次に取るべき行動を示します。これはすべての AdCP 処理の基盤です。

ステータス値

AdCP は A2A プロトコルの TaskState enum と同じステータス値を使用します:
StatusMeaningYour Action
submittedTask queued for executionShow “queued” indicator, wait for updates
workingAgent actively processingShow progress, poll frequently for updates
input-requiredNeeds information from youRead message field, prompt user, send follow-up
completedSuccessfully finishedProcess data, show success message
canceledUser/system canceled taskShow cancellation notice, clean up
failedError occurredShow error from message, handle gracefully
rejectedAgent rejected the requestShow rejection reason, don’t retry
auth-requiredAuthentication neededPrompt for auth, retry with credentials
unknownIndeterminate stateLog for debugging, may need manual intervention

レスポンス構造

AdCP レスポンスはタスク固有フィールドがトップレベルにある フラット構造 です:
{
  "status": "completed",           // Always present: what state we're in
  "message": "Found 5 products",   // Always present: human explanation
  "context_id": "ctx-123",         // Session continuity
  "context": {                     // Application-level context echoed back
    "ui": "buyer_dashboard"
  },
  "products": [...]                // Task-specific fields at top level
}

ステータス処理

基本パターン

function handleAdcpResponse(response) {
  switch (response.status) {
    case 'completed':
      // 成功 - データ処理(タスクフィールドはトップレベル)
      showSuccess(response.message);
      return processData(response);

    case 'input-required':
      // 追加情報が必要 - ユーザーに確認
      const userInput = await promptUser(response.message);
      return sendFollowUp(response.context_id, userInput);

    case 'working':
      // 進行中 - 進捗表示して待機
      showProgress(response.message);
      return pollForUpdates(response.context_id);

    case 'failed':
      // エラー - メッセージを表示し丁寧に処理
      showError(response.message);
      return handleError(response.errors);

    case 'auth-required':
      // 認証が必要
      const credentials = await getAuth();
      return retryWithAuth(credentials);

    default:
      // 想定外のステータス
      console.warn('Unknown status:', response.status);
      showMessage(response.message);
  }
}

確認フロー

ステータスが input-required のとき、必要な情報が message で示されます:
{
  "status": "input-required",
  "message": "I need more information about your campaign. What's your budget and target audience?",
  "context_id": "ctx-123",
  "products": [],
  "suggestions": ["budget", "audience", "timing"]
}
クライアント側の処理:
if (response.status === 'input-required') {
  // message から必要項目を抽出
  const missingInfo = extractRequirements(response.message);

  // 必要項目に応じて質問
  const answers = await promptForInfo(missingInfo);

  // 同じ context_id で追送
  return sendMessage(response.context_id, answers);
}

承認フロー

人による承認は input-required の特殊ケースです:
{
  "status": "input-required",
  "message": "Media buy exceeds auto-approval limit ($100K). Please approve to proceed with campaign creation.",
  "context_id": "ctx-123",
  "approval_required": true,
  "amount": 150000,
  "reason": "exceeds_limit"
}
クライアント側の処理:
if (response.status === 'input-required' && response.approval_required) {
  // 承認 UI を表示
  const approved = await showApprovalDialog(response.message, response);

  // 承認結果を送信
  const decision = approved ? "Approved" : "Rejected";
  return sendMessage(response.context_id, decision);
}

長時間オペレーション

非同期オペレーションは working または submitted で開始し、進捗を返します:
{
  "status": "working",
  "message": "Creating media buy. Validating inventory availability...",
  "context_id": "ctx-123",
  "task_id": "task-456",
  "progress": 25,
  "step": "inventory_validation"
}
プロトコル別のポーリング:
  • MCP: context_id を使ってポーリング
  • A2A: SSE ストリームでリアルタイム更新を購読

ステータスの流れ

Tasks progress through predictable states:
submitted → working → completed
    ↓          ↓         ↑
input-required → → → → →

  failed
  • submitted: 実行待ち。Webhook を設定するかポーリング
  • working: 処理中。高頻度でポーリング
  • input-required: ユーザー入力が必要。会話を継続
  • completed: 成功。結果を処理
  • failed: エラー。適切に処理

ポーリングパターン

ステータス別ポーリング間隔

ステータスによってポーリング頻度を変えます:
const POLLING_INTERVALS = {
  working: 5000,      // 5 seconds - should complete within 120s
  submitted: 60000,   // 1 minute - long-running operations
  'input-required': null  // Don't poll - wait for user input
};

async function pollForUpdates(taskId, currentStatus) {
  const interval = POLLING_INTERVALS[currentStatus];
  if (!interval) return;

  await sleep(interval);

  const response = await adcp.call('tasks/get', {
    task_id: taskId,
    include_result: true
  });

  if (['completed', 'failed', 'canceled'].includes(response.status)) {
    return response;
  }

  return pollForUpdates(taskId, response.status);
}

タイムアウト処理

オペレーション種別に応じて妥当なタイムアウトを設定します:
const TIMEOUTS = {
  sync: 30_000,        // 30 seconds for immediate operations
  interactive: 300_000, // 5 minutes for human input
  working: 120_000,    // 2 minutes for working tasks
  submitted: 86_400_000 // 24 hours for submitted tasks
};

function setTimeoutForStatus(status) {
  switch (status) {
    case 'working': return TIMEOUTS.working;
    case 'submitted': return TIMEOUTS.submitted;
    case 'input-required': return TIMEOUTS.interactive;
    default: return TIMEOUTS.sync;
  }
}

タスク再同期

tasks/list で失われた状態を復元します:
// 保留中のオペレーションを取得
const pending = await session.call('tasks/list', {
  filters: {
    statuses: ["submitted", "working", "input-required"]
  }
});

// ローカル状態と突き合わせ
const missingTasks = pending.tasks.filter(task =>
  !localState.hasTask(task.task_id)
);

// 未追跡タスクの監視を再開
for (const task of missingTasks) {
  startPolling(task.task_id);
}

ベストプラクティス

  1. まず status を確認 - 成功前提にしない
  2. すべてのステータスを処理 - 未知の状態も default でカバー
  3. context_id を保持 - 会話継続に必須
  4. task_id で追跡 - 特に長時間オペレーションで重要
  5. タイムアウトを実装 - 無限に待たない
  6. ステータス遷移をログ - デバッグと監査に有用

次のステップ

  • Async Operations: 異なるオペレーション種別の扱いは Async Operations
  • Webhooks: プッシュ通知パターンは Webhooks
  • Error Handling: エラー分類と復旧は Error Handling