クライアントイベント

会話型アプリケーションでクライアントが受信するリアルタイムイベントを理解し、処理します。

クライアントイベントは、リアルタイム通信を円滑にするためにサーバーからクライアントへ送信されるシステムレベルのイベントです。これらのイベントは、オーディオ、文字起こし、エージェントの応答など、重要な情報をクライアントアプリケーションに提供します。

クライアントからサーバーへ送信できるイベントについては、クライアントからサーバーへの イベントのドキュメントを参照してください。

概要

クライアントイベントは、会話のリアルタイム性を維持するために不可欠です。初期化メタデータから処理済みのオーディオ、エージェントの応答まで、必要な情報を提供します。

これらのイベントはWebSocket通信プロトコルの一部であり、SDKによって自動的に処理されます。 高度な実装やデバッグには、これらを理解することが重要です。

クライアントイベントの種類

  • 会話開始時に自動送信されます
  • 会話の設定とパラメータを初期化します
// Example initialization metadata
{
"type": "conversation_initiation_metadata",
"conversation_initiation_metadata_event": {
"conversation_id": "conv_123",
"agent_output_audio_format": "pcm_44100", // TTS output format
"user_input_audio_format": "pcm_16000" // ASR input format
}
}
  • エージェントが同時実行数の上限に達している間、通話キューで保留中の発信者にのみ送信されます
  • waitingは、conversation_initiation_metadataの後、保留音声の前に1回送信されます
  • 待機が終了すると、admittedまたはtimed_outが1回送信されます。timed_outの後には、コード4300でWebSocketがクローズされます
  • キュー内の発信者には常に送信されます。エージェントのclient_events設定で有効にする必要はありません

発信者がキューに入っている間、保留音声は通常のaudioイベントとして届きます。保留音声をエージェントの発話として扱うのではなく、このイベントを使用して 待機状態を表示してください。

// Example queue status event structure
{
"type": "queue_status",
"queue_status_event": {
"status": "waiting" // "waiting" | "admitted" | "timed_out"
}
}
// Example queue status handler
websocket.on('queue_status', (event) => {
const { status } = event.queue_status_event;
if (status === 'waiting') {
showWaitingState();
} else if (status === 'admitted') {
hideWaitingState();
} else if (status === 'timed_out') {
showAllAgentsBusyMessage();
}
});
  • 即時の応答が必要なヘルスチェックイベント
  • SDKによって自動的に処理されます
  • WebSocket接続の維持に使用されます
// Example ping event structure
{
"ping_event": {
"event_id": 123456,
"ping_ms": 50 // Optional, estimated latency in milliseconds
},
"type": "ping"
}
// Example ping handler
websocket.on('ping', () => {
websocket.send('pong');
});
  • 再生用のbase64エンコード済みオーディオを含みます
  • 追跡と順序管理のための数値イベントIDを含みます
  • 音声出力ストリーミングを処理します
  • 文字単位のタイミング情報を含むアラインメントデータを含みます

WebRTC接続では、オーディオはLiveKitで直接処理されるため、audioイベントは送信されません。

// Example audio event structure
{
"audio_event": {
"audio_base_64": "base64_encoded_audio_string",
"event_id": 12345,
"alignment": { // Character-level timing data
"chars": ["H", "e", "l", "l", "o"],
"char_durations_ms": [50, 30, 40, 40, 60],
"char_start_times_ms": [0, 50, 80, 120, 160]
}
},
"type": "audio"
}
// Example audio event handler
websocket.on('audio', (event) => {
const { audio_event } = event;
const { audio_base_64, event_id, alignment } = audio_event;
audioPlayer.play(audio_base_64);
// Use alignment data for synchronized text display
const { chars, char_start_times_ms } = alignment;
chars.forEach((char, i) => {
setTimeout(() => highlightCharacter(char, i), char_start_times_ms[i]);
});
});
  • 確定したスピーチtoテキストの結果を含みます
  • 完全なユーザー発話を表します
  • 会話履歴に使用されます
// Example transcript event structure
{
"type": "user_transcript",
"user_transcription_event": {
"user_transcript": "Hello, how can you help me today?"
}
}
// Example transcript handler
websocket.on('user_transcript', (event) => {
const { user_transcription_event } = event;
const { user_transcript } = user_transcription_event;
updateConversationHistory(user_transcript);
});
  • 完全なエージェントメッセージを含みます
  • メッセージの完了後に1回送信されるため、音声会話では通常、メッセージのオーディオがストリーミングを開始した後に届きます。
  • 表示と履歴に使用されます

エージェントのテキストを生成中に表示するには、このイベントを待つのではなく、以下で説明する agent_chat_response_partイベントを使用してください。

// Example response event structure
{
"type": "agent_response",
"agent_response_event": {
"agent_response": "Hello, how can I assist you today?"
}
}
// Example response handler
websocket.on('agent_response', (event) => {
const { agent_response_event } = event;
const { agent_response } = agent_response_event;
displayAgentMessage(agent_response);
});
  • 割り込み後に切り詰められた応答を含みます
  • 表示中のメッセージを更新します
  • 会話の正確性を維持します
// Example response correction event structure
{
"type": "agent_response_correction",
"agent_response_correction_event": {
"original_agent_response": "Let me tell you about the complete history...",
"corrected_agent_response": "Let me tell you about..." // Truncated after interruption
}
}
// Example response correction handler
websocket.on('agent_response_correction', (event) => {
const { agent_response_correction_event } = event;
const { corrected_agent_response } = agent_response_correction_event;
displayAgentMessage(corrected_agent_response);
});
  • カスタムLLM応答からの任意のメタデータを含みます
  • カスタムLLMを使用している場合にのみ送信されます
  • エージェントのclient_events設定で明示的に有効にする必要があります

このイベントはカスタムLLMインテグレーション固有です。カスタムLLMサーバーから応答とともに 追加メタデータを渡し、クライアントアプリケーションで利用できます。

// Example agent response metadata event structure
{
"type": "agent_response_metadata",
"agent_response_metadata_event": {
"metadata": {
// Any key-value pairs returned by your custom LLM
"key": "value"
},
"event_id": 12345
}
}
// Example metadata handler
websocket.on('agent_response_metadata', (event) => {
const { agent_response_metadata_event } = event;
const { metadata, event_id } = agent_response_metadata_event;
// Use metadata for UI updates, logging, or analytics
console.log(`Response ${event_id} metadata:`, metadata);
updateResponseDetails(metadata);
});
  • エージェントがクライアントに実行してほしい関数呼び出しを表します
  • ツール名、ツール呼び出しID、パラメータを含みます
  • クライアント側で関数を実行し、その結果をサーバーに返す必要があります

SDKを使用している場合は、結果をサーバーに返す処理用のコールバックが提供されます。

// Example tool call event structure
{
"type": "client_tool_call",
"client_tool_call": {
"tool_name": "search_database",
"tool_call_id": "call_123456",
"parameters": {
"query": "user information",
"filters": {
"date": "2024-01-01"
}
}
}
}
// Example tool call handler
websocket.on('client_tool_call', async (event) => {
const { client_tool_call } = event;
const { tool_name, tool_call_id, parameters } = client_tool_call;
try {
const result = await executeClientTool(tool_name, parameters);
// Send success response back to continue conversation
websocket.send({
type: "client_tool_result",
tool_call_id: tool_call_id,
result: result,
is_error: false
});
} catch (error) {
// Send error response if tool execution fails
websocket.send({
type: "client_tool_result",
tool_call_id: tool_call_id,
result: error.message,
is_error: true
});
}
});
  • エージェントがツール関数を実行したときに示されます
  • ツールのメタデータと実行ステータスを含みます
  • 会話中のエージェントによるツール使用状況を可視化します
// Example agent tool response event structure
{
"type": "agent_tool_response",
"agent_tool_response": {
"tool_name": "skip_turn",
"tool_call_id": "skip_turn_c82ca55355c840bab193effb9a7e8101",
"tool_type": "system",
"is_error": false
}
}
// Example agent tool response handler
websocket.on('agent_tool_response', (event) => {
const { agent_tool_response } = event;
const { tool_name, tool_call_id, tool_type, is_error } = agent_tool_response;
if (is_error) {
console.error(`Agent tool ${tool_name} failed:`, tool_call_id);
} else {
console.log(`Agent executed ${tool_type} tool: ${tool_name}`);
}
});
  • agent_tool_responseを反映し、さらにツール結果の完全なペイロードを文字列としてfull_tool_resultでストリーミングします。
  • 表示や後続処理のために、クライアントでツール出力を利用できるようにします。
  • エージェントのclient_events設定で明示的に有効にする必要があります。

このイベントは完全なツール結果をクライアントに公開するため、機密データが含まれる可能性があります。クライアントがペイロードを安全に処理できる場合にのみ有効にしてください。64 KBを超える結果は自動的に切り詰められます。

// Example agent tool response full payload event structure
{
"type": "agent_tool_response_full_payload",
"agent_tool_response_full_payload": {
"tool_name": "lookup_order",
"tool_call_id": "lookup_order_c82ca55355c840bab193effb9a7e8101",
"tool_type": "webhook",
"is_error": false,
"full_tool_result": "{\"order_id\": \"ORD-789\", \"status\": \"shipped\"}",
"truncated": false
}
}
// Example agent tool response full payload handler (using @elevenlabs/react)
import { ConversationProvider } from '@elevenlabs/react';
function App() {
return (
<ConversationProvider
onAgentToolResponse={(response) => {
if (!('full_tool_result' in response)) return;
const { tool_name, tool_call_id, is_error, full_tool_result, truncated } = response;
if (is_error) {
console.error(`Agent tool ${tool_name} failed:`, tool_call_id);
} else {
console.log(`Tool ${tool_name} returned:`, full_tool_result);
}
if (truncated) {
console.warn(`Tool ${tool_name} result was truncated (exceeded 64 KB).`);
}
}}
>
<Agent />
</ConversationProvider>
);
}
  • 音声アクティビティ検出スコアイベント
  • ユーザーが発話している確率を示します
  • 値の範囲は0から1で、値が高いほど発話である確信度が高いことを示します
// Example VAD score event
{
"type": "vad_score",
"vad_score_event": {
"vad_score": 0.95
}
}
  • エージェントがMCPツール関数を実行したときに示されます
  • ツール名、ツール呼び出しID、パラメータを含みます
  • loading、awaiting_approval、success、failureの4つの状態のいずれかで呼び出されます。
{
"type": "mcp_tool_call",
"mcp_tool_call": {
"service_id": "xJ8kP2nQ7sL9mW4vR6tY",
"tool_call_id": "call_123456",
"tool_name": "search_database",
"tool_description": "Search the database for user information",
"parameters": {
"query": "user information",
},
"timestamp": "2024-09-30T14:23:45.123456+00:00",
"state": "loading",
"approval_timeout_secs": 10
}
}
  • エージェントの応答テキストを、生成に合わせてstart、delta、stopメッセージとしてストリーミングします
  • テキストのみモードでは常に送信されます。音声会話では、エージェントのclient_events設定で明示的に有効にする必要があります
  • エージェントまたはアクティブなプロシージャが、応答全体を評価してから公開する必要があるブロッキングガードレールを使用している間は送信されません
  • response_idはストリーミング中のメッセージを識別し、後で確定するagent_responseのresponse_idと一致します
// Example start event
{
"type": "agent_chat_response_part",
"text_response_part": {
"type": "start",
"text": "",
"event_id": 12345,
"response_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
}
// Example delta event with text chunk
{
"type": "agent_chat_response_part",
"text_response_part": {
"type": "delta",
"text": "Hello, how can I",
"event_id": 12345,
"response_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
}
// Example stop event
{
"type": "agent_chat_response_part",
"text_response_part": {
"type": "stop",
"text": "",
"event_id": 12345,
"response_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
}
// Example handler
websocket.on('agent_chat_response_part', (event) => {
const { text_response_part } = event;
const { type: partType, text, response_id } = text_response_part;
if (partType === 'start') {
initializeResponseBuffer(response_id);
} else if (partType === 'delta') {
appendToResponseBuffer(response_id, text);
} else if (partType === 'stop') {
finalizeResponse(response_id);
}
});

agent_reasoning_response_partは、テキストのみの会話中にモデルが提供する推論をストリーミングします。 client_eventsでこのイベントを有効にし、エージェントの推論 要約をオンにしてください。サーバーは start、delta、stopメッセージを送信します。音声会話中、または エージェントもしくはアクティブなプロシージャがブロッキングガードレールを使用している間は、このイベントを送信しません。

このイベントと対応するSDKコールバックは実験的機能です。動作と形式は リリースごとに変更される可能性があります。

Event payload
{
"type": "agent_reasoning_response_part",
"reasoning_response_part": {
"type": "delta",
"text": "The user asked to cancel, so I should verify the account before continuing.",
"event_id": 123456
}
}

開始イベントと停止イベントでは、text値は空です。

Handle reasoning events
import { Conversation } from '@elevenlabs/client';
const conversation = await Conversation.startSession({
agentId: 'agent_7101k5zvyjhmfg983brhmhkd98n6',
textOnly: true,
onAgentReasoningResponsePart: ({ type, text, event_id }) => {
if (type === 'start') {
initializeReasoningBuffer(event_id);
} else if (type === 'delta') {
appendToReasoningBuffer(text);
} else if (type === 'stop') {
finalizeReasoning();
}
},
});
  • 保留中のツール呼び出しを含め、エージェントが応答を完了したときに発生します。このイベントの後、ユーザーが新しい入力を提供するか、ターンタイムアウトによって新しいターンが開始されない限り、エージェントは追加の出力を生成しません。
  • エージェントのclient_events設定で明示的に有効にする必要があります
// Example agent response complete event structure
{
"type": "agent_response_complete",
"agent_response_complete_event": {
"event_id": 12345
}
}
// Example handler
websocket.on('agent_response_complete', (event) => {
const { agent_response_complete_event } = event;
const { event_id } = agent_response_complete_event;
console.log(`Agent response ${event_id} complete`);
});
  • ガードレール違反によって会話が終了すると発生します。ガードレールが再試行をトリガーし、その再試行が成功した場合は送信されません。
  • イベント自体がシグナルであり、typeフィールド以外のペイロードは含まれません。
  • エージェントのclient_events設定で明示的に有効にする必要があります。
// Example guardrail triggered event structure
{
"type": "guardrail_triggered"
}
// Example guardrail triggered handler (using @elevenlabs/client)
import { Conversation } from '@elevenlabs/client';
const conversation = await Conversation.startSession({
agentId: 'agent_7101k5zvyjhmfg983brhmhkd98n6',
onGuardrailTriggered: () => {
console.warn('Guardrail triggered — conversation will end.');
},
});

イベントフロー

会話中の一般的なイベントの流れは次のとおりです:

conversation_initiation_metadata ping pong audio user_transcript audio agent_response client_tool_call client_tool_result audio agent_response agent_response_correction Connection established Playing audio User responds Client tool runs Playing audio Interruption detected Client Server

エージェントが同時実行数の上限に達し、通話キューイングが有効になっている場合、サーバーはconversation_initiation_metadataと最初のaudioイベントの間にqueue_statusイベントを送信します。発信者が受け入れられるまで、保留音はaudioイベントとして配信されます。

ベストプラクティス

  1. エラー処理

    • 各イベントタイプに適切なエラー処理を実装する
    • デバッグのために重要なイベントをログに記録する
    • 接続の中断を適切に処理する
  2. オーディオ管理

    • オーディオチャンクを適切にバッファリングする
    • 中断時に適切なクリーンアップを実装する
    • オーディオリソースを適切に管理する
  3. 接続管理

    • PINGイベントにすみやかに応答する
    • 再接続ロジックを実装する
    • 接続状態を監視する

トラブルシューティング

  • WebSocket接続が適切に設定されていることを確認する
  • PING/PONGの応答を確認する
  • API認証情報を確認する
  • オーディオチャンクの処理を確認する
  • オーディオ形式の互換性を確認する
  • メモリ使用量を監視する
  • デバッグのためにすべてのイベントをログに記録する
  • エラーバウンダリーを実装する
  • イベントハンドラーの登録を確認する

詳しい実装例については、SDK ドキュメントを確認してください。