Vai alla navigazione

Eventi client

Comprendi e gestisci gli eventi in tempo reale ricevuti dal client nelle applicazioni conversazionali.

Gli eventi client sono eventi a livello di sistema inviati dal server al client che facilitano la comunicazione in tempo reale. Questi eventi forniscono audio, trascrizioni, risposte dell’agente e altre informazioni critiche all’applicazione client.

Per informazioni sugli eventi che puoi inviare dal client al server, consulta la documentazione sugli eventi dal client al server.

Panoramica

Gli eventi client sono essenziali per mantenere le conversazioni in tempo reale. Forniscono ogni elemento, dai metadati di inizializzazione all’audio elaborato e alle risposte dell’agente.

Questi eventi fanno parte del protocollo di comunicazione WebSocket e vengono gestiti automaticamente dai nostri SDK. Comprenderli è fondamentale per implementazioni avanzate e debug.

Tipi di eventi client

  • Inviato automaticamente all’avvio di una conversazione
  • Inizializza le impostazioni e i parametri della conversazione
// 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
}
}
  • Inviato soltanto ai chiamanti in attesa nella coda delle chiamate mentre l’agente ha raggiunto il limite di concorrenza
  • waiting viene inviato una volta, dopo conversation_initiation_metadata e prima di qualsiasi audio di attesa
  • admitted o timed_out viene inviato una volta al termine dell’attesa. Dopo timed_out, il WebSocket viene chiuso con il codice 4300
  • Viene sempre inviato ai chiamanti in coda. Non deve essere abilitato nella configurazione client_events dell’agente

Mentre un chiamante è in coda, l’audio di attesa arriva come normali eventi audio. Usa questo evento per mostrare uno stato di attesa invece di trattare l’audio di attesa come voce dell’agente.

// 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();
}
});
  • Evento di controllo dello stato che richiede una risposta immediata
  • Gestito automaticamente dall’SDK
  • Utilizzato per mantenere la connessione 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');
});
  • Contiene audio codificato in base64 per la riproduzione
  • Include un ID evento numerico per il monitoraggio e l’ordinamento
  • Gestisce lo streaming dell’output vocale
  • Include dati di allineamento con informazioni temporali a livello di carattere

Nelle connessioni WebRTC, l’evento audio non viene inviato perché l’audio viene gestito direttamente da 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]);
});
});
  • Contiene risultati definitivi della conversione da voce a testo
  • Rappresenta enunciati completi dell’utente
  • Utilizzato per la cronologia della conversazione
// 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);
});
  • Contiene il messaggio completo dell’agente
  • Viene inviato quando il messaggio è terminato, quindi nelle conversazioni vocali di solito arriva dopo che l’audio del messaggio ha già iniziato lo streaming.
  • Utilizzato per la visualizzazione e la cronologia

Per visualizzare il testo dell’agente mentre viene generato, usa l’evento agent_chat_response_part descritto di seguito anziché attendere questo evento.

// 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);
});
  • Contiene la risposta troncata dopo un’interruzione
  • Aggiorna il messaggio visualizzato
  • Mantiene l’accuratezza della conversazione
// 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);
});
  • Contiene metadati arbitrari da una risposta LLM personalizzata
  • Inviato solo quando usi un LLM personalizzato
  • Deve essere abilitato esplicitamente nella configurazione client_events dell’agente

Questo evento è specifico delle integrazioni LLM personalizzate. Permette al tuo server LLM personalizzato di trasmettere metadati aggiuntivi insieme alla risposta, che possono essere utilizzati dall’applicazione client.

// 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);
});
  • Rappresenta una chiamata di funzione che l’agente vuole far eseguire al client
  • Contiene il nome dello strumento, l’ID della chiamata dello strumento e i parametri
  • Richiede l’esecuzione lato client della funzione e l’invio del risultato al server

Se usi l’SDK, sono disponibili callback per gestire l’invio del risultato al server.

// 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
});
}
});
  • Indica quando l’agente ha eseguito una funzione di uno strumento
  • Contiene i metadati dello strumento e lo stato di esecuzione
  • Offre visibilità sull’uso degli strumenti dell’agente durante le conversazioni
// 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}`);
}
});
  • Rispecchia agent_tool_response e trasmette inoltre il payload completo del risultato dello strumento come stringa in full_tool_result.
  • Espone l’output dello strumento nel client per la visualizzazione o l’elaborazione a valle.
  • Deve essere abilitato esplicitamente nella configurazione client_events dell’agente.

Questo evento espone al client il risultato completo dello strumento e potrebbe contenere dati sensibili. Abilitalo solo quando il client è affidabile per gestire il payload. I risultati superiori a 64 KB vengono automaticamente troncati.

// 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>
);
}
  • Evento relativo al punteggio di rilevamento dell’attività vocale
  • Indica la probabilità che l’utente stia parlando
  • I valori vanno da 0 a 1, dove valori più alti indicano una maggiore confidenza nella presenza di parlato
// Example VAD score event
{
"type": "vad_score",
"vad_score_event": {
"vad_score": 0.95
}
}
  • Indica quando l’agente ha eseguito una funzione di uno strumento MCP
  • Contiene il nome dello strumento, l’ID della chiamata dello strumento e i parametri
  • Viene chiamato con uno di quattro stati: loading, awaiting_approval, success e 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
}
}
  • Trasmette in streaming il testo della risposta dell’agente mentre viene generato, come messaggi start, delta e stop
  • Viene sempre inviato nella modalità solo testo; nelle conversazioni vocali deve essere abilitato esplicitamente nella configurazione client_events dell’agente
  • Non viene inviato mentre l’agente o una procedura attiva usa un guardrail bloccante, che deve valutare l’intera risposta prima che una sua parte venga rilasciata
  • response_id identifica il messaggio in streaming e corrisponde al response_id di agent_response che lo conferma in seguito
// 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 trasmette in streaming il ragionamento fornito dal modello durante le conversazioni solo testo. Abilita l’evento in client_events e attiva il riepilogo del ragionamento per l’agente. Il server invia messaggi start, delta e stop. Non invia questo evento durante le conversazioni vocali né mentre l’agente o una procedura attiva usa guardrail bloccanti.

Questo evento e il callback SDK corrispondente sono sperimentali. Il loro comportamento e la loro struttura potrebbero cambiare in qualsiasi versione.

Payload dell'evento
{
"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
}
}

Gli eventi di inizio e fine usano un valore text vuoto.

Gestire gli eventi di ragionamento
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();
}
},
});
  • Si attiva quando l’agente ha completato la sua risposta, incluse eventuali chiamate di strumenti in sospeso. Dopo questo evento, l’agente produrrà ulteriori output solo se l’utente fornisce un nuovo input o se un timeout del turno attiva un nuovo turno.
  • Deve essere abilitato esplicitamente nella configurazione client_events dell’agente
// 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`);
});
  • Si attiva quando una violazione di un guardrail termina la conversazione. Non viene inviato quando un guardrail attiva un nuovo tentativo che riesce.
  • L’evento stesso è il segnale: non contiene payload oltre al campo type.
  • Deve essere abilitato esplicitamente nella configurazione client_events dell’agente.
// 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.');
},
});

Flusso degli eventi

Ecco una tipica sequenza di eventi durante una conversazione:

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

Quando un agente ha raggiunto il limite di concorrenza e l’accodamento delle chiamate è abilitato, il server invia eventi queue_status tra conversation_initiation_metadata e il primo evento audio. L’audio di attesa viene inviato come eventi audio finché il chiamante non viene ammesso.

Best practice

  1. Gestione degli errori

    • Implementa una corretta gestione degli errori per ogni tipo di evento
    • Registra gli eventi importanti per il debug
    • Gestisci correttamente le interruzioni della connessione
  2. Gestione dell’audio

    • Memorizza nel buffer i chunk audio in modo appropriato
    • Implementa una corretta pulizia in caso di interruzione
    • Gestisci le risorse audio
  3. Gestione della connessione

    • Rispondi tempestivamente agli eventi PING
    • Implementa la logica di riconnessione
    • Monitora lo stato della connessione

Risoluzione dei problemi

  • Assicurati che la connessione WebSocket sia configurata correttamente
  • Controlla le risposte PING/PONG
  • Verifica le credenziali API
  • Controlla la gestione dei chunk audio
  • Verifica la compatibilità del formato audio
  • Monitora l’utilizzo della memoria
  • Registra tutti gli eventi per il debug
  • Implementa gli error boundary
  • Controlla la registrazione degli event handler

Per esempi di implementazione dettagliati, consulta la documentazione SDK.