Aller au contenu principal

Maîtriser les Événements WebSocket

Mis à jour le 29 juillet 2026

Une conversation faite d’événements JSON

Sous la surface, un échange vocal avec le Voice Agent n’est qu’une suite de messages JSON qui circulent dans les deux sens sur la connexion WebSocket. Chaque message porte un champ type qui dit ce qu’il est. Tant que vous ne connaissez pas ce vocabulaire, votre client fonctionne par chance ; dès que vous le maîtrisez, vous savez exactement où intervenir pour couper une réponse, afficher une transcription ou rattraper une erreur.

Les événements se répartissent en deux familles selon leur sens de circulation. Ceux que vous émettez pilotent la session ; ceux que vous recevez vous racontent ce qui se passe côté serveur.

Ce que votre application envoie

Vos messages sortants couvrent quatre besoins : configurer la session, alimenter le buffer audio, manipuler l’historique de conversation et contrôler la génération des réponses.

ÉvénementRôle
session.updateConfigure ou reconfigure la session (voix, instructions, outils, VAD, format audio)
input_audio_buffer.appendEnvoie un chunk d’audio encodé en base64, en continu pendant que l’utilisateur parle
input_audio_buffer.commitValide le contenu actuel du buffer comme message de l’utilisateur — nécessaire uniquement en mode manuel
input_audio_buffer.clearVide le buffer audio sans le traiter
conversation.item.createAjoute un élément à la conversation : message texte, historique préalable ou résultat d’un appel de fonction
conversation.item.deleteSupprime un élément de la conversation par son identifiant
response.createDemande au modèle de générer une réponse — automatique en mode VAD, explicite en mode manuel
response.cancelAnnule une réponse en cours de génération

Deux de ces messages méritent qu’on s’y arrête. conversation.item.create est votre porte d’entrée pour injecter du contexte : c’est par lui que vous replacez l’historique d’un appel précédent au début d’une nouvelle session, contournant ainsi la limite de trente minutes. Quant à input_audio_buffer.clear, il rend service quand l’utilisateur a manifestement parlé pour ne rien dire — un raclement de gorge capté par un micro trop sensible — et que vous préférez repartir d’un buffer propre plutôt que de laisser le modèle interpréter du bruit.

Ce que le serveur vous renvoie

Le flux entrant est plus dense, parce qu’il commente en direct chaque étape du traitement.

ÉvénementSignification
session.createdLa session est ouverte
session.updatedUne mise à jour de configuration a été prise en compte
conversation.createdLa conversation est établie
input_audio_buffer.speech_startedLe VAD détecte que l’utilisateur commence à parler
input_audio_buffer.speech_stoppedLe VAD détecte que l’utilisateur a cessé de parler
input_audio_buffer.committedLe buffer audio a été validé, par le VAD ou manuellement
response.createdUne réponse est en cours de génération
response.output_audio.deltaUn chunk d’audio de réponse, en base64
response.output_audio.doneL’audio de réponse est complet
response.output_audio_transcript.deltaLa transcription texte de l’audio, en streaming
response.doneLa réponse est entièrement terminée
conversation.item.input_audio_transcription.completedLa transcription du message de l’utilisateur est disponible
response.text.deltaDu texte en streaming, pour les réponses non vocales
response.function_call_arguments.deltaLes arguments d’un appel de fonction arrivent en streaming
response.function_call_arguments.doneL’appel de fonction est complet, prêt à être exécuté
errorUne erreur récupérable s’est produite

Le dernier appelle une mise en garde. Recevoir error ne signifie pas que la session est perdue : ces erreurs sont récupérables, et un client qui ferme la connexion au premier error venu casse une conversation qui aurait pu continuer. Journalisez, informez éventuellement l’utilisateur, mais laissez la socket ouverte.

Le squelette d’un client

En pratique, tout se joue dans un aiguillage sur msg.type. Voici la forme minimale d’un client JavaScript :

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  switch (msg.type) {
    case "session.created":
      // Envoyer session.update avec la configuration
      break;

    case "input_audio_buffer.speech_started":
      // L'utilisateur parle : couper l'audio de reponse en cours
      break;

    case "response.output_audio.delta":
      // Decoder le base64 et jouer l'audio
      playAudioChunk(msg.delta);
      break;

    case "response.function_call_arguments.done":
      // Executer la fonction et renvoyer le resultat
      handleFunctionCall(msg);
      break;

    case "error":
      console.error("Erreur Voice Agent:", msg.error);
      break;
  }
};

Quatre branches suffisent à faire tourner un agent : configurer à l’ouverture, réagir à la prise de parole, jouer l’audio entrant, exécuter les fonctions. Le reste des événements sert à enrichir l’interface et peut attendre une seconde itération.

Le cas délicat : l’interruption

Le barge-in, c’est-à-dire l’utilisateur qui reprend la parole alors que l’agent est en train de répondre, est le moment où une implémentation approximative se voit. Le serveur annule de lui-même la réponse en cours et se met à en générer une nouvelle à partir de ce qu’il vient d’entendre. Mais lui a arrêté d’émettre, tandis que votre application, elle, tient encore dans son buffer de sortie plusieurs secondes d’audio déjà reçues.

Si vous ne faites rien, l’utilisateur continue d’entendre la phrase qu’il vient d’interrompre pendant qu’il parle par-dessus : l’effet est celui d’un agent qui n’écoute pas. Dès la réception de speech_started, coupez donc la lecture audio en cours, videz le buffer de sortie pour ne pas jouer de son devenu obsolète, et laissez le serveur traiter la nouvelle entrée. Ces deux gestes tiennent en quelques lignes et font toute la différence entre un agent qu’on peut couper et un agent qui parle dans le vide.

Points clés à retenir

  • Les événements client couvrent la configuration, l’envoi audio, la gestion de conversation et le contrôle des réponses
  • Les événements serveur informent sur la détection de parole, les chunks audio, les transcriptions et les appels de fonctions
  • Le VAD gère automatiquement les interruptions (barge-in)
  • L’événement error est récupérable : ne fermez pas la connexion, gérez l’erreur
  • En mode manuel, vous devez appeler commit puis response.create explicitement