Fonctionnalités Speech-to-Speech dans Mastra
IntroductionLien direct vers Introduction
La fonctionnalité Speech-to-Speech (STS) de Mastra fournit une interface standardisée pour des interactions en temps réel auprès de plusieurs fournisseurs. STS permet une communication audio bidirectionnelle continue en écoutant les événements des modèles Realtime. Contrairement à des opérations TTS et STT séparées, STS maintient une connexion ouverte qui traite la parole continuellement dans les deux directions.
ConfigurationLien direct vers Configuration
apiKey: votre clé API OpenAI. Par défaut, la variable d’environnementOPENAI_API_KEYest utilisée.model: l’identifiant du modèle à utiliser pour les interactions vocales en temps réel, par exemplegpt-5.1-realtime.speaker: l’identifiant vocal par défaut pour la synthèse vocale. Vous pouvez indiquer la voix à utiliser pour la sortie vocale.
const voice = new OpenAIRealtimeVoice({
apiKey: 'your-openai-api-key',
model: 'gpt-5.1-realtime',
speaker: 'alloy', // Default voice
})
// If using default settings the configuration can be simplified to:
const voice = new OpenAIRealtimeVoice()
Utiliser STSLien direct vers Utiliser STS
import { Agent } from '@mastra/core/agent'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'
const agent = new Agent({
id: 'agent',
name: 'OpenAI Realtime Agent',
instructions: `You are a helpful assistant with real-time voice capabilities.`,
model: 'openai/gpt-5.6-sol',
voice: new OpenAIRealtimeVoice(),
})
// Connect to the voice service
await agent.voice.connect()
// Listen for agent audio responses
agent.voice.on('speaker', ({ audio }) => {
playAudio(audio)
})
// Initiate the conversation
await agent.voice.speak('How can I help you today?')
// Send continuous audio from the microphone
const micStream = getMicrophoneStream()
await agent.voice.send(micStream)
Pour une présentation plus générale des fournisseurs vocaux associés aux Agents, consultez Voice dans Mastra.
Utiliser des Tools dans des sessions en temps réelLien direct vers Utiliser des Tools dans des sessions en temps réel
Les fournisseurs vocaux en temps réel peuvent utiliser les Tools configurés sur l’Agent. Ajoutez les Tools à la définition de Agent, puis connectez-vous et envoyez l’audio via le fournisseur vocal :
import { Agent } from '@mastra/core/agent'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'
import { calculate, search } from '../tools'
export const agent = new Agent({
id: 'speech-to-speech-agent',
name: 'Speech-to-Speech Agent',
instructions: 'You are a helpful assistant with speech-to-speech capabilities.',
model: 'openai/gpt-5.6-sol',
tools: {
search,
calculate,
},
voice: new OpenAIRealtimeVoice(),
})
Écouter les événements en temps réelLien direct vers Écouter les événements en temps réel
Les fournisseurs vocaux en temps réel émettent des événements que vous pouvez utiliser pour mettre à jour votre interface, lire l’audio de l’assistant, consigner les transcriptions et gérer les erreurs :
agent.voice.on('speaking', ({ audio }) => {
playAudio(audio)
})
agent.voice.on('writing', ({ text, role }) => {
console.log(`${role}: ${text}`)
})
agent.voice.on('error', error => {
console.error('Voice error:', error)
})
Les noms et les charges utiles des événements varient selon le fournisseur. Consultez la section du fournisseur ci-dessous ou sa référence pour obtenir la liste complète des événements.
Instances vocales par sessionLien direct vers Instances vocales par session
Une instance voice statique est partagée entre toutes les requêtes. Cela fonctionne pour une synthèse vocale ponctuelle, mais les fournisseurs en temps réel et Speech-to-Speech stockent l’état de la session, tel que la connexion WebSocket, les Tools, les instructions et le contexte de requête. Si un Agent gère plusieurs sessions actives simultanément, une instance partagée peut permettre à une session d’écraser l’état d’une autre.
Fournissez voice sous forme de résolveur lorsque chaque session active a besoin de sa propre instance vocale. Mastra exécute le résolveur à chaque appel de getVoice() et retourne une nouvelle instance pour ce contexte de requête :
import { Agent } from '@mastra/core/agent'
import { RequestContext } from '@mastra/core/request-context'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'
export const agent = new Agent({
id: 'support-line',
name: 'Support Line',
instructions: ({ requestContext }) => `Help user ${requestContext.get('user')}.`,
model: 'openai/gpt-5.6-sol',
voice: ({ requestContext }) =>
new OpenAIRealtimeVoice({
apiKey: requestContext.get('apiKey'),
}),
})
const requestContext = new RequestContext()
requestContext.set('user', 'user-123')
requestContext.set('apiKey', process.env.OPENAI_API_KEY)
const voice = await agent.getVoice({ requestContext })
await voice.connect()
Lorsque vous utilisez un résolveur :
- Chaque appel à
getVoice()retourne une nouvelle instance ; les sessions concurrentes ne partagent donc pas d’état. - Mastra n’ajoute pas de Tools ni d’instructions à une instance de résolveur. Configurez-les dans le résolveur ou sur le fournisseur.
- Vous êtes responsable du cycle de vie de l’instance retournée ; appelez donc
disconnect()ouclose()lorsque la session se termine.
L’accesseur agent.voice n’a pas de contexte de requête ; il lève donc une erreur lorsque voice est un résolveur. Utilisez plutôt agent.getVoice({ requestContext }).
Google Gemini Live (Realtime)Lien direct vers Google Gemini Live (Realtime)
import { Agent } from '@mastra/core/agent'
import { GeminiLiveVoice } from '@mastra/voice-google-gemini-live'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'
const agent = new Agent({
id: 'agent',
name: 'Gemini Live Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new GeminiLiveVoice({
apiKey: process.env.GOOGLE_API_KEY,
model: 'gemini-2.0-flash-exp',
speaker: 'Puck',
debug: true,
// Vertex AI option:
// vertexAI: true,
// project: 'your-gcp-project',
// location: 'us-central1',
// serviceAccountKeyFile: '/path/to/service-account.json',
}),
})
await agent.voice.connect()
agent.voice.on('speaker', ({ audio }) => {
playAudio(audio)
})
agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})
await agent.voice.speak('How can I help you today?')
const micStream = getMicrophoneStream()
await agent.voice.send(micStream)
Remarque :
- Live API requiert
GOOGLE_API_KEY. Vertex AI requiert le projet, l’emplacement et les identifiants du compte de service. - Événements :
speaker(flux audio),writing(texte),turnComplete,usageeterror.
AWS Nova Sonic (Realtime)Lien direct vers AWS Nova Sonic (Realtime)
import { Agent } from '@mastra/core/agent'
import { NovaSonicVoice } from '@mastra/voice-aws-nova-sonic'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'
const agent = new Agent({
id: 'agent',
name: 'Nova Sonic Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new NovaSonicVoice({
region: 'us-east-1',
speaker: 'matthew',
// Static credentials are optional. The default AWS credential provider
// chain is used when none are passed.
}),
})
await agent.voice.connect()
// Assistant audio is emitted as 16-bit PCM on the `speaking` event
agent.voice.on('speaking', ({ audioData }) => {
if (audioData) playAudio(audioData)
})
agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})
await agent.voice.speak('How can I help you today?')
const micStream = getMicrophoneStream()
await agent.voice.send(micStream)
Remarque :
- Régions disponibles :
us-east-1,us-west-2etap-northeast-1. - L’authentification passe par la chaîne standard de fournisseurs d’identifiants AWS. Transmettez
credentialspour la remplacer. - Événements :
speaking(audio Int16Array),writing(texte avecgenerationStage),toolCall,interrupt,turnComplete,usage,sessioneterror.
Inworld RealtimeLien direct vers Inworld Realtime
import { Agent } from '@mastra/core/agent'
import { InworldRealtimeVoice } from '@mastra/voice-inworld'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'
const agent = new Agent({
id: 'agent',
name: 'Inworld Realtime Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new InworldRealtimeVoice({
apiKey: process.env.INWORLD_API_KEY,
model: 'inworld/models/gemma-4-26b-a4b-it',
speaker: 'Sarah',
// Typed Inworld realtime knobs (semantic VAD, playback speed, etc.)
// session: {
// audio: {
// output: { speed: 1.1 },
// input: { turn_detection: { type: 'semantic_vad', eagerness: 'high' } },
// },
// },
}),
})
await agent.voice.connect()
agent.voice.on('speaker', stream => {
playAudio(stream)
})
agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})
await agent.voice.speak('How can I help you today?')
const micStream = getMicrophoneStream()
await agent.voice.send(micStream)
Remarque :
- Requiert
INWORLD_API_KEY. Les clés API Inworld sont préencodées en Basic : collez-les telles quelles. - L’URL WebSocket ajoute une valeur
?key=...&protocol=realtimegénérée par le client. Le modèle est configuré par lesession.updateinitial, et non dans l’URL. - Le protocole filaire d’Inworld est la spécification OpenAI Realtime GA ; les noms des événements correspondent donc à ceux de
@mastra/voice-openai-realtime. - Les réglages Inworld en temps réel typés, notamment le routage de Tools MCP, le niveau d’empressement VAD sémantique, la vitesse de lecture, le modèle de transcription et les modalités de sortie, sont exposés par le champ constructeur
session. Une échappatoireproviderDatanon typée est également fusionnée en profondeur pour assurer la compatibilité future avec les nouvelles fonctionnalités Inworld. - Événements :
speaker(flux audio PCM),speaking(Buffer audio par delta),writing(texte),conversation.item.added,conversation.item.done,function_call.arguments,tool-call-start,tool-call-resulteterror.