Aller au contenu principal

Voix Inworld Realtime

La classe InworldRealtimeVoice permet une interaction vocale bidirectionnelle simultanée en temps réel à l'aide de l'API Realtime d'Inworld AI via WebSockets. Elle prend en charge la conversation vocale, l'appel d'outils et des paramètres de session propres à Inworld, comme la détection sémantique de l'activité vocale, le routage des Tools MCP et la vitesse de lecture.

Le protocole de communication d'Inworld suit la spécification OpenAI Realtime GA. Les noms d'événements côté client et serveur correspondent donc à ceux de @mastra/voice-openai-realtime. Les différences propres au Provider concernent le point de terminaison (qui utilise dans l'URL une clé de session générée par le client), l'en-tête Authorization: Basic <key>, le champ de constructeur typé session pour les paramètres propres à Inworld et un objet typé providerData pour les extensions Inworld (STT, TTS, Memory, signaux d'écoute et réactivité), envoyé sous session.providerData.

Pour la synthèse vocale et la reconnaissance vocale par lots, consultez @mastra/voice-inworld.

Exemple d'utilisation
Lien direct vers Exemple d'utilisation

src/mastra/index.ts
import { InworldRealtimeVoice } from '@mastra/voice-inworld'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

// Initialize with INWORLD_API_KEY from the environment
const voice = new InworldRealtimeVoice()

// Or initialize with explicit configuration
const voiceWithConfig = new InworldRealtimeVoice({
apiKey: 'your-inworld-api-key',
model: 'inworld/models/gemma-4-26b-a4b-it',
speaker: 'Sarah',
instructions: 'You are a helpful voice assistant.',
session: {
audio: {
output: { speed: 1.1 },
input: { turn_detection: { type: 'semantic_vad', eagerness: 'high' } },
},
},
})

// Establish connection
await voice.connect()

// Listen for audio output (PCM16 @ 24 kHz by default)
voice.on('speaker', stream => {
playAudio(stream)
})

voice.on('writing', ({ text, role }) => {
console.log(`${role}: ${text}`)
})

// Convert text to speech
await voice.speak('Hello, how can I help you today?', {
speaker: 'Hades',
})

// Stream microphone audio to the model
const microphoneStream = getMicrophoneStream()
await voice.send(microphoneStream)

// Clean up
voice.close()

Les clés d'API Inworld sont déjà encodées en Basic. Copiez-les telles quelles dans INWORLD_API_KEY. Le package ne les réencode pas.

Paramètres du constructeur
Lien direct vers Paramètres du constructeur

apiKey?:

string
Clé d'API Inworld. Utilise par défaut la variable d'environnement INWORLD_API_KEY. Les clés sont encodées en Basic et transmises telles quelles dans l'en-tête Authorization.

url?:

string
= 'wss://api.inworld.ai/api/v1/realtime/session'
Point de terminaison WebSocket Realtime. Une clé de session générée par le client et un paramètre de protocole sont ajoutés automatiquement.

model?:

string
= 'inworld/models/gemma-4-26b-a4b-it'
ID du modèle LLM Router. Il est envoyé dans le premier session.update, et non dans l'URL. Tout modèle pris en charge par le routeur d'Inworld est accepté.

speaker?:

string
= 'Sarah'
ID de Voice par défaut pour la synthèse vocale. Toute Voice du catalogue d'Inworld est acceptée.

sessionId?:

string
= 'voice-{Date.now()}'
Clé de session générée par le client et exposée comme paramètre key de l'URL. Si elle est omise, une clé fondée sur l'horodatage est générée automatiquement.

instructions?:

string
Prompt système envoyé avec le premier session.update.

session?:

Partial<InworldSessionConfig>
Options de session typées de premier niveau (audio, tool_choice, output_modalities, temperature, ...). Elles sont fusionnées en profondeur dans chaque session.update afin que les champs imbriqués tels que audio.output.voice et audio.output.speed se combinent au lieu de s'écraser. Consultez le champ session ci-dessous.

debug?:

boolean
= false
Consigne les événements bruts du serveur.

providerData?:

InworldProviderData
Configuration typée des extensions Inworld (stt, tts, memory, backchannel, responsiveness, ainsi que user_id et metadata). Elle est envoyée sous session.providerData à chaque session.update. Elle se combine avec toute valeur session.providerData définie via le champ session ; en cas de conflit de clés, l'option du constructeur l'emporte.

connectTimeoutMs?:

number
= 15000
Durée maximale pendant laquelle connect() attend à la fois la négociation WebSocket et l'aller-retour initial de session.updated. Une erreur ou une fermeture du WebSocket avant son ouverture — ou l'expiration de ce délai — entraîne le rejet de la promesse plutôt qu'une erreur de socket non interceptée.

session (paramètres typés)
Lien direct vers session-typed-knobs

Utilisez le champ typé session pour les options Realtime Inworld documentées. Les champs se combinent avec les valeurs par défaut appliquées lors de la connexion (par exemple, audio.output.voice défini à partir de speaker) :

output_modalities?:

Array<"text" | "audio">
Modalités que le modèle doit produire.

audio.output.voice?:

string
ID du catalogue de Voice. En cas d'omission, le speaker du constructeur est utilisé.

audio.output.speed?:

number
Multiplicateur de vitesse de lecture de l'audio synthétisé (de 0,25 à 1,5).

audio.output.model?:

string
Modèle TTS Inworld (par exemple, "inworld-tts-2").

audio.output.format?:

InworldAudioFormat
Encodage de l'audio de sortie. Une chaîne de codec (par exemple, "audio/pcm", "audio/pcmu", "audio/pcma", "audio/float32") ou un objet { type, rate? }. rate (Hz) s'applique à audio/pcm et audio/float32 (valeur par défaut : 24000) ; audio/pcmu et audio/pcma sont fixés à 8 kHz.

audio.input.format?:

InworldAudioFormat
Encodage de l'audio d'entrée envoyé au serveur. Même forme que audio.output.format : une chaîne de codec ou un objet { type, rate? }.

audio.input.noise_reduction?:

{ type: "near_field" | "far_field" }
Mode de réduction du bruit appliqué à l'entrée avant la transcription et la VAD.

audio.input.transcription?:

{ model?: string; language?: string; prompt?: string }
Transcription côté serveur de l'audio entrant de l'utilisateur. La valeur par défaut est { model: "inworld/inworld-stt-1" }. prompt oriente la transcription à l'aide d'indications de vocabulaire, d'orthographe ou de style. Fournissez votre propre objet pour remplacer cette valeur ; définissez-la sur null pour désactiver la transcription côté utilisateur.

audio.input.turn_detection?:

InworldTurnDetection | null
Détection d'activité vocale et de tour de parole. La valeur par défaut est { type: "semantic_vad", eagerness: "medium", create_response: true, interrupt_response: true }. Fournissez votre propre objet pour la remplacer ; définissez-la sur null pour désactiver entièrement la détection des tours. Le champ eagerness détermine la rapidité avec laquelle la VAD sémantique termine le tour d'un utilisateur : low attend des pauses plus nettes (résiste davantage aux interruptions), tandis que high termine les tours plus tôt (plus réactif, mais plus susceptible de couper la parole). La valeur par défaut medium équilibre les deux. idle_timeout_ms (server_vad uniquement) définit la période d'inactivité avant que le serveur ne valide un tour.

tool_choice?:

string | { type: "function"; name: string } | { type: "mcp"; server_label: string }
Stratégie de sélection des Tools. Utilisez la variante mcp pour acheminer les appels de Tools via un serveur MCP Inworld configuré.

temperature?:

number
Température d'échantillonnage du modèle.

max_output_tokens?:

number | "inf"
Nombre maximal de tokens générés par réponse.

truncation?:

"auto" | "disabled" | { type: "retention_ratio"; retention_ratio: number }
Stratégie de troncature de la conversation.

tracing?:

"auto" | { workflow_name?: string; group_id?: string; metadata?: Record<string, unknown> }
Configuration du traçage distribué. Utilisez "auto" pour les valeurs par défaut du serveur, ou nommez explicitement le Workflow ou le groupe.

include?:

Array<"item.input_audio_transcription.logprobs">
Champs supplémentaires que le serveur doit inclure dans les événements émis lorsque vous les activez.

prompt?:

string | null
Référence à un modèle de prompt côté serveur. Transmettez null pour l'effacer.

providerData (extensions Inworld)
Lien direct vers providerdata-inworld-extensions

providerData est un objet typé destiné aux extensions Realtime propres à Inworld. Il est envoyé sous session.providerData à chaque session.update et se combine avec toute valeur session.providerData définie via le champ session : en cas de conflit de clés, le providerData du constructeur l'emporte.

Il comporte cinq branches et deux champs au niveau de la session :

  • stt : réglage du STT, notamment prompt, voice_profile, language_hints et les seuils de VAD ou de fin de tour.
  • tts : segmentation et diffusion TTS, notamment segmenter_strategy, steering_handling, delivery_mode, conversational et user_turn_mode.
  • memory : Memory glissante automatique, notamment enabled, turn_interval et max_facts. Inworld renvoie son état par l'événement memory.
  • backchannel : brefs signaux d'écoute (« hum-hum ») pendant que l'utilisateur parle. L'audio arrive par l'événement backchannel.
  • responsiveness : audio de remplissage précoce pendant la génération de la réponse principale. Cet audio réutilise les événements ordinaires speaker et speaking ; il n'existe donc pas d'événements distincts.
  • user_id et metadata : identifiants au niveau de la session transmis à Inworld.
const voice = new InworldRealtimeVoice({
providerData: {
stt: { voice_profile: true, language_hints: ['en-US'] },
tts: { delivery_mode: 'CREATIVE', segmenter_strategy: 'balanced' },
memory: { enabled: true, turn_interval: 4 },
backchannel: { enabled: true, max_per_turn: 1 },
user_id: 'user-123',
},
})

Méthodes
Lien direct vers Méthodes

connect()
Lien direct vers connect

Ouvre la connexion WebSocket, envoie le premier session.update et se résout lorsque le serveur répond par session.updated. Cette méthode doit être appelée avant speak(), listen() ou send().

Une error ou une close sur le WebSocket avant son ouverture (ou une négociation qui dépasse connectTimeoutMs (15 s par défaut)) entraîne le rejet de la promesse plutôt qu'une erreur de socket non interceptée. En cas de rejet, le socket partiellement ouvert est fermé.

await voice.connect()

Renvoie : Promise<void>

speak()
Lien direct vers speak

Envoie un message texte au modèle et déclenche une réponse audio. La promesse renvoyée ne se résout qu'une fois le cycle de vie complet de la réponse terminé (response.done pour la réponse déclenchée par cet appel) et est rejetée si la réponse est interrompue par la voix de l'utilisateur ou si une erreur de transport se produit.

Les appels séquentiels à speak() constituent le mode d'utilisation pris en charge. Les appels simultanés partagent le même ensemble de listeners et l'ordre d'association des réponses n'est pas défini.

input:

string | NodeJS.ReadableStream
Texte ou flux de texte à convertir en parole.

options?:

Options
Configuration propre à chaque appel.
Options

speaker?:

string
ID de Voice à utiliser pour cette requête précise.

Renvoie : Promise<void>

listen()
Lien direct vers listen

Envoie un unique tampon audio comme tour utilisateur et demande au modèle de répondre uniquement par du texte.

audioData:

NodeJS.ReadableStream
Flux audio à transcrire.

Renvoie : Promise<void>

send()
Lien direct vers send

Diffuse les données audio en temps réel vers le serveur. Utile pour une entrée continue depuis le microphone.

audioData:

NodeJS.ReadableStream | Int16Array
Données audio à diffuser. Int16Array est envoyé sous forme de fragment base64 unique ; un flux lisible est transmis fragment par fragment.

eventId?:

string
ID d'événement facultatif transmis au serveur avec chaque fragment audio.

Renvoie : Promise<void>

updateConfig()
Lien direct vers updateconfig

Envoie un session.update au serveur. Le champ typé session est fusionné en profondeur dans la charge utile et tout providerData du constructeur est imbriqué sous session.providerData.

sessionConfig:

InworldSessionConfig | Record<string, unknown>
Configuration partielle de session à appliquer.

Renvoie : void

addInstructions()
Lien direct vers addinstructions

Définit les instructions système utilisées lors du prochain appel à connect() ou updateConfig().

instructions?:

string
Prompt système du modèle.

Renvoie : void

addTools()
Lien direct vers addtools

Enregistre les Tools que le modèle peut appeler pendant la session. Lorsque InworldRealtimeVoice est associé à un Agent, les Tools configurés pour cet Agent sont automatiquement disponibles.

tools?:

ToolsInput
Configuration des Tools à fournir.

Renvoie : void

answer()
Lien direct vers answer

Envoie un événement response.create afin de déclencher une réponse du modèle, éventuellement avec des options propres à cette réponse.

options?:

Record<string, unknown>
Options de réponse transmises au serveur.

Renvoie : Promise<void>

Gestion des tours de parole
Lien direct vers Gestion des tours de parole

commitInput()
Lien direct vers commitinput

Valide manuellement l'audio d'entrée mis en mémoire tampon comme tour utilisateur. Utilisez cette méthode pour le mode appuyer-pour-parler ou la gestion manuelle des tours lorsque turn_detection est défini sur null.

voice.commitInput()

Renvoie : void

clearInput()
Lien direct vers clearinput

Supprime l'audio d'entrée mis en mémoire tampon sans le valider comme tour utilisateur.

voice.clearInput()

Renvoie : void

clearOutput()
Lien direct vers clearoutput

Vide entièrement le tampon audio de sortie du serveur, ce qui arrête la lecture. Cela arrête également tout signal d'écoute audio en cours. Le chemin d'interruption par défaut (response.cancel sur interrupted) préserve les signaux d'écoute. Privilégiez-le. N'utilisez clearOutput() que lorsque vous souhaitez tout vider.

voice.clearOutput()

Renvoie : void

close() et disconnect()
Lien direct vers close-and-disconnect

Les deux méthodes ferment le WebSocket et marquent l'instance comme déconnectée.

Renvoie : void

getSpeakers()
Lien direct vers getspeakers

Renvoie la sélection de Voices incluse dans le package. Le catalogue d'Inworld est plus vaste que cette liste ; tout ID de Voice peut être transmis à speaker lors de l'exécution.

Renvoie : Promise<Array<{ voiceId: string }>>

on() et off()
Lien direct vers on-and-off

Enregistrent et suppriment des listeners d'événements. Consultez la section Événements ci-dessous.

Événements
Lien direct vers Événements

La classe InworldRealtimeVoice émet les événements suivants :

speaker:

event
Émis une fois par réponse avec un flux PassThrough contenant de l’audio PCM. Utilisez cet événement pour transmettre l’audio à un lecteur.

speaking:

event
Émis pour chaque delta audio. Le callback reçoit { audio: Buffer, response_id: string }.

speaking.done:

event
Émis lorsque la sortie audio d'une réponse est terminée. Le callback reçoit { response_id: string }.

writing:

event
Émis à mesure que le texte transcrit devient disponible. Le callback reçoit { text: string, response_id: string, role: "assistant" | "user", voiceProfile? }. Les deltas de transcription audio et de texte d'une même réponse sont dédupliqués, de sorte qu'une réponse n'émet qu'un seul flux. Pour les événements utilisateur, voiceProfile est présent lorsque providerData.stt.voice_profile est activé.

speech-started:

event
Front VAD brut input_audio_buffer.speech_started provenant du serveur.

speech-stopped:

event
Front VAD brut input_audio_buffer.speech_stopped provenant du serveur.

interrupted:

event
Signal synthétique côté client : émis une fois par response_id en cours lorsque l'utilisateur commence à parler. Utilisez-le pour arrêter la lecture de la réponse principale lors d'une interruption. Le callback reçoit { response_id: string }. Il ne contient que les ID des réponses principales, jamais ceux des signaux d'écoute. L'arrêt du flux speaker correspondant laisse donc les flux backchannel se poursuivre (les signaux d'écoute sont conçus pour chevaucher la parole de l'utilisateur et ne sont jamais annulés lors d'une interruption).

turn-suggestion:

event
Indication intelligente de fin de tour pour un énoncé utilisateur mis en mémoire tampon. Le callback reçoit { item_id, utterance_index, probability, trailing_silence_ms?, audio_duration_ms?, inference_ms? }.

turn-suggestion-revoked:

event
Une suggestion de tour précédemment émise a été retirée. Le callback reçoit { item_id, utterance_index }.

input-committed:

event
L'audio d'entrée mis en mémoire tampon a été validé comme tour utilisateur (via commitInput() ou la VAD automatique). Le callback reçoit { item_id, previous_item_id? }, où previous_item_id peut être null.

input-cleared:

event
L'audio d'entrée mis en mémoire tampon a été supprimé (via clearInput()). Le callback reçoit {}.

input-timeout:

event
Un délai d'inactivité de la VAD du serveur a validé un tour utilisateur. Le callback reçoit { audio_start_ms, audio_end_ms, item_id }.

output-audio-started:

event
Le serveur a commencé à émettre l'audio de sortie. Le callback reçoit {}.

output-audio-stopped:

event
Le serveur a cessé d'émettre l'audio de sortie de la réponse actuelle. Le callback reçoit {}.

output-audio-cleared:

event
Le tampon audio de sortie du serveur a été vidé, ce qui a arrêté la lecture (via clearOutput()). Le callback reçoit {}.

memory:

event
Émis avec le résumé glissant et l'état des faits d'Inworld, dédupliqués par version. Nécessite providerData.memory.enabled. Le callback reçoit InworldMemoryState.

backchannel:

event
Émis avec un flux PassThrough d'audio PCM de signaux d'écoute (brefs acquiescements pendant que l'utilisateur parle). L'.id de chaque flux est un backchannel_id qui n'apparaît jamais dans interrupted ; lisez donc ces flux sur une piste distincte que les interruptions n'arrêtent pas. Nécessite providerData.backchannel.enabled.

backchannel.done:

event
Émis lorsqu'un signal d'écoute se termine. Le callback reçoit { backchannel_id: string, phrase? }.

backchannel.skipped:

event
Émis lorsque le mécanisme de décision ignore un signal d'écoute avant la production de tout audio. Le callback reçoit { reason: string }.

response.created:

event
Émis lorsqu’une nouvelle réponse commence. Le callback reçoit l’événement serveur complet.

response.done:

event
Émis lorsqu’une réponse se termine. Le callback reçoit l’événement serveur complet.

conversation.item.added:

event
Émis lorsqu’un nouvel élément est ajouté à la conversation.

conversation.item.done:

event
Émis lorsqu’un élément de conversation se termine.

function_call.arguments:

event
Émis avec les arguments complets de l'appel de Tool. Le callback reçoit { call_id, name, arguments }.

tool-call-start:

event
Émis avant l'exécution d'un Tool enregistré.

tool-call-result:

event
Émis après le renvoi d'un résultat par un Tool enregistré.

error:

event
Émis en cas d’erreur de transport ou du serveur.

Voix
Lien direct vers Voix

Le package comprend une sélection d'ID de Voice renvoyés par getSpeakers() :

  • Dennis
  • Hades
  • Wendy
  • Edward
  • Olivia
  • Sarah
  • Timothy
  • Priya
  • Ronald
  • Deborah

Tout ID de Voice du catalogue de Voices d'Inworld peut être transmis à speaker lors de l'exécution.

Remarques
Lien direct vers Remarques

  • Les clés d'API peuvent être fournies via les options du constructeur ou la variable d'environnement INWORLD_API_KEY. Elles sont déjà encodées en Basic. Ne les réencodez pas.
  • L'URL WebSocket ajoute ?key=<sessionId>&protocol=realtime. Le modèle est configuré via le premier session.update, et non dans l'URL.
  • À chaque appel, speak(input, { speaker }) limite le remplacement de la Voice à une seule réponse (via le champ simple response.voice) et ne modifie pas la session.
  • Par défaut, la sortie audio est au format PCM16 à 24 kHz. Les formats téléphoniques audio/pcmu et audio/pcma à 8 kHz, ainsi que audio/float32, sont également pris en charge via session.audio.output.format.
  • Utilisez connect() avant tout appel à send, speak ou listen. Les événements envoyés avant l'ouverture du WebSocket sont mis en file d'attente puis transmis lorsque le serveur confirme session.updated.
  • L'instance de Voice doit être fermée avec close() ou disconnect() pour libérer le WebSocket.
  • audio.input.turn_detection utilise par défaut la VAD sémantique lorsque session ne fournit aucune valeur. Remplacez-la par votre propre objet ou transmettez null pour désactiver entièrement la détection des tours.
  • audio.input.transcription utilise par défaut { model: 'inworld/inworld-stt-1' }, de sorte que les événements writing côté utilisateur sont émis sans configuration supplémentaire. Remplacez cette valeur par votre propre objet ou transmettez null pour désactiver la transcription côté utilisateur.
  • on() et off() sont typés selon InworldVoiceEventMap. Les noms d'événements connus produisent une charge utile de callback typée. Les noms inconnus utilisent par défaut unknown.