Événements client

Comprendre et gérer les événements en temps réel reçus par le client dans les applications conversationnelles.

Les événements client sont des événements système envoyés du serveur au client afin de faciliter la communication en temps réel. Ces événements transmettent l’audio, la transcription, les réponses de l’agent et d’autres informations essentielles à l’application cliente.

Pour en savoir plus sur les événements que vous pouvez envoyer du client au serveur, consultez la documentation sur les événements du client vers le serveur.

Vue d’ensemble

Les événements client sont essentiels pour préserver le caractère temps réel des conversations. Ils fournissent toutes les informations, des métadonnées d’initialisation à l’audio traité et aux réponses de l’agent.

Ces événements font partie du protocole de communication WebSocket et sont automatiquement gérés par nos SDK. Les comprendre est essentiel pour les implémentations avancées et le débogage.

Types d’événements client

  • Envoyé automatiquement au démarrage d’une conversation
  • Initialise les paramètres et réglages de la conversation
// 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
}
}
  • Envoyé uniquement aux appelants placés dans la file d’attente des appels lorsque l’agent a atteint sa limite de requêtes simultanées
  • waiting est envoyé une fois, après conversation_initiation_metadata et avant tout audio d’attente
  • admitted ou timed_out est envoyé une fois à la fin de l’attente. timed_out est suivi d’une fermeture WebSocket avec le code 4300
  • Toujours envoyé aux appelants en attente. Il n’est pas nécessaire de l’activer dans la configuration client_events de l’agent

Lorsqu’un appelant est en attente, l’audio d’attente arrive sous forme d’événements audio classiques. Utilisez cet événement pour afficher un état d’attente plutôt que de traiter l’audio d’attente comme la parole de l’agent.

// 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();
}
});
  • Événement de vérification de l’état nécessitant une réponse immédiate
  • Géré automatiquement par le SDK
  • Utilisé pour maintenir la connexion 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');
});
  • Contient l’audio encodé en base64 pour la lecture
  • Inclut un ID d’événement numérique pour le suivi et le séquençage
  • Gère le streaming de la sortie vocale
  • Inclut des données d’alignement avec des informations de synchronisation au niveau des caractères

Sur les connexions WebRTC, l’événement audio n’est pas envoyé, car l’audio est géré directement par LiveKit.

// 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]);
});
});
  • Contient les résultats finalisés de la conversion parole-texte
  • Représente les énoncés complets de l’utilisateur
  • Utilisé pour l’historique de la conversation
// 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);
});
  • Contient le message complet de l’agent
  • Envoyé une fois le message terminé. Dans les conversations vocales, il arrive donc généralement après le début du streaming audio du message.
  • Utilisé pour l’affichage et l’historique

Pour afficher le texte de l’agent au fur et à mesure de sa génération, utilisez plutôt l’événement agent_chat_response_part décrit ci-dessous, sans attendre cet événement.

// 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);
});
  • Contient la réponse tronquée après une interruption
  • Met à jour le message affiché
  • Préserve l’exactitude de la conversation
// 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);
});
  • Contient des métadonnées arbitraires provenant d’une réponse LLM personnalisée
  • Envoyé uniquement lors de l’utilisation d’un LLM personnalisé
  • Doit être explicitement activé dans la configuration client_events de l’agent

Cet événement est propre aux intégrations LLM personnalisées. Il permet à votre serveur LLM personnalisé de transmettre des métadonnées supplémentaires avec la réponse, que l’application cliente peut exploiter.

// 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);
});
  • Représente un appel de fonction que l’agent souhaite faire exécuter par le client
  • Contient le nom de l’outil, l’ID de l’appel d’outil et les paramètres
  • Nécessite l’exécution côté client de la fonction et l’envoi du résultat au serveur

Si vous utilisez le SDK, des rappels sont fournis pour gérer l’envoi du résultat au serveur.

// 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
});
}
});
  • Indique que l’agent a exécuté une fonction d’outil
  • Contient les métadonnées de l’outil et le statut d’exécution
  • Offre une visibilité sur l’utilisation des outils par l’agent pendant les conversations
// 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}`);
}
});
  • Reflète agent_tool_response et transmet également le résultat complet de l’outil sous forme de chaîne dans full_tool_result.
  • Expose la sortie de l’outil dans le client pour l’affichage ou le traitement en aval.
  • Doit être explicitement activé dans la configuration client_events de l’agent.

Cet événement expose le résultat complet de l’outil au client et peut contenir des données sensibles. Activez-le uniquement lorsque le client est digne de confiance pour gérer cette charge utile. Les résultats dépassant 64 Ko sont automatiquement tronqués.

// 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>
);
}
  • Événement de score de détection d’activité vocale
  • Indique la probabilité que l’utilisateur parle
  • Les valeurs vont de 0 à 1, les valeurs élevées indiquant une plus grande certitude de parole
// Example VAD score event
{
"type": "vad_score",
"vad_score_event": {
"vad_score": 0.95
}
}
  • Indique que l’agent a exécuté une fonction d’outil MCP
  • Contient le nom de l’outil, l’ID de l’appel d’outil et les paramètres
  • Appelé avec l’un des quatre états suivants : loading, awaiting_approval, success et failure.
{
"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
}
}
  • Transmet en streaming le texte de réponse de l’agent à mesure de sa génération, sous forme de messages start, delta et stop
  • Toujours envoyé en mode texte uniquement ; dans les conversations vocales, il doit être explicitement activé dans la configuration client_events de l’agent
  • Non envoyé lorsque l’agent ou une procédure active utilise un garde-fou bloquant, qui doit évaluer l’intégralité de la réponse avant qu’une partie ne soit diffusée
  • response_id identifie le message diffusé et correspond au response_id de l’élément agent_response qui le valide ultérieurement
// 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 transmet en streaming le raisonnement fourni par le modèle lors de conversations en texte uniquement. Activez l’événement dans client_events et activez le résumé du raisonnement pour l’agent. Le serveur envoie des messages start, delta et stop. Il n’envoie pas cet événement lors des conversations vocales ni lorsque l’agent ou une procédure active utilise des garde-fous bloquants.

Cet événement et le rappel SDK correspondant sont expérimentaux. Leur comportement et leur structure peuvent changer dans toute version.

Charge utile de l’événement
{
"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
}
}

Les événements de début et de fin utilisent une valeur text vide.

Gérer les événements de raisonnement
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();
}
},
});
  • Se déclenche lorsque l’agent a terminé sa réponse, y compris les éventuels appels d’outils en attente. Après cet événement, l’agent ne produira de nouvelle sortie que si l’utilisateur fournit une nouvelle entrée ou qu’un délai d’expiration de tour déclenche un nouveau tour.
  • Doit être explicitement activé dans la configuration client_events de l’agent
// 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`);
});
  • Se déclenche lorsqu’une violation d’un garde-fou met fin à la conversation. N’est pas envoyé lorsqu’un garde-fou déclenche une nouvelle tentative qui réussit.
  • L’événement lui-même constitue le signal, il ne contient aucune charge utile au-delà du champ type.
  • Doit être explicitement activé dans la configuration client_events de l’agent.
// 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.');
},
});

Flux d’événements

Voici une séquence d’événements typique au cours d’une conversation :

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

Lorsqu’un agent atteint sa limite de requêtes simultanées et que la mise en file d’attente des appels est activée, le serveur envoie des événements queue_status entre conversation_initiation_metadata et le premier événement audio. L’audio d’attente est transmis sous forme d’événements audio jusqu’à l’admission de l’appelant.

Bonnes pratiques

  1. Gestion des erreurs

    • Mettez en place une gestion des erreurs adaptée à chaque type d’événement
    • Consignez les événements importants à des fins de débogage
    • Gérez les interruptions de connexion avec élégance
  2. Gestion de l’audio

    • Mettez les segments audio en mémoire tampon de manière appropriée
    • Mettez en place un nettoyage approprié en cas d’interruption
    • Gérez les ressources audio
  3. Gestion des connexions

    • Répondez rapidement aux événements PING
    • Mettez en place une logique de reconnexion
    • Surveillez l’état de la connexion

Résolution des problèmes

  • Assurez-vous que la connexion WebSocket est correctement établie
  • Vérifiez les réponses PING/PONG
  • Vérifiez les identifiants API
  • Vérifiez le traitement des segments audio
  • Vérifiez la compatibilité des formats audio
  • Surveillez l’utilisation de la mémoire
  • Consignez tous les événements à des fins de débogage
  • Mettez en place des limites d’erreur
  • Vérifiez l’enregistrement des gestionnaires d’événements

Pour des exemples d’implémentation détaillés, consultez notre documentation des SDK.