LiveKit
@mastra/livekit パッケージは、Mastra Agent を LiveKit Agents フレームワークに接続します。LiveKit が音声パイプライン(Voice Activity Detection、Speech-to-Text、ターン検出、Text-to-Speech、割り込み)を実行し、このパッケージが応答生成を Mastra Agent の stream() 呼び出しに橋渡しします。
セットアップと概念については、リアルタイム Voiceを参照してください。
パッケージには3つのエントリーポイントがあります。
@mastra/livekit:サーバー側 API のliveKitConnectionRoute()、dispatchVoiceSession()、pipeAgentReplyToWriter()、serializeSessionMetadata()、createEndCallTool()。Mastra サーバーコードからインポートします。このエントリーが LiveKit Agents ランタイムを読み込むことはありません。@mastra/livekit/worker:Worker ランタイムのcreateLiveKitWorker()、runLiveKitWorker()、chatContextToMessages()、セッションヘルパーのspeakGreeting()、waitForAgentDoneSpeaking()、runEndCall()。Worker エントリーファイルからだけインポートします。@mastra/livekit/plugin:LLM コンポーネントプラグインのMastraLLMとcreateRemoteAgentReplyGenerator()。独自のvoice.AgentSessionを構築する Worker でインポートします。createRemoteAgentReplyGenerator()はcreateLiveKitWorker()のgenerateオプションに接続するため、@mastra/livekit/workerからもエクスポートされます。MastraLLMはプラグイン専用です。
createLiveKitWorker()createlivekitworkerへの直接リンク
Mastra Agent で Voice セッションに応答する LiveKit Agent 定義を構築します。Worker エントリーファイルのデフォルトエクスポートとして使用します。
import { fileURLToPath } from 'node:url'
import { createLiveKitWorker, runLiveKitWorker } from '@mastra/livekit/worker'
import { mastra } from './index'
export default createLiveKitWorker({
mastra,
agent: 'support',
stt: 'deepgram/nova-3',
tts: 'cartesia/sonic-3',
turnDetection: 'multilingual',
})
if (process.argv[1] === fileURLToPath(import.meta.url)) {
runLiveKitWorker({ entry: import.meta.url, agentName: 'mastra-voice' })
}
オプションオプションへの直接リンク
mastra:
agent?:
workflow?:
workflowInput?:
replyStep?:
resultText?:
generate?:
stt?:
tts?:
vad?:
turnDetection?:
turnHandling?:
sessionOptions?:
memory?:
toolFeedback?:
onTurnComplete?:
configuration?:
greeting?:
consentPolicy?:
endCall?:
stt?:
tts?:
greeting?:
persistGreeting?:
observability?:
voice call Span を開き、各ターンの Agent 実行をその下にネストします。LiveKit の STT、TTS、発話終了、VAD、LLM レイテンシーのメトリクスが子 Span となり、モデルごとの使用量集計とともに Span を閉じます。無効にするには false を渡します。inputOptions?:
outputOptions?:
onSessionStart?:
runLiveKitWorker()runlivekitworkerへの直接リンク
Worker エントリーファイル用の LiveKit Worker CLI(dev、start、connect サブコマンド)を起動します。Worker 定義をデフォルトエクスポートするファイルから呼び出し、直接実行した場合だけ動作するようにガードします。@livekit/agents の cli.runApp の代わりにこのヘルパーを使用すると、Worker ランタイムとブリッジが LiveKit SDK の同じコピーを共有することが保証されます。
オプションオプションへの直接リンク
entry:
agentName?:
serverOptions?:
pipeAgentReplyToWriter()pipeagentreplytowriterへの直接リンク
Workflow の応答パスで、Mastra Agent の応答を Workflow Step の writer にストリーミングします。Agent のテキスト差分を転送するため、完全な応答の準備前に Text-to-Speech が開始されます。また Tool 呼び出しチャンクも転送するため、toolFeedback が発生し、onTurnComplete で Tool 一覧を確認できます。stream.textStream だけをパイプすると Tool 呼び出しが通知なしで失われます。Step の abortSignal を agent.stream() に渡し、割り込み時に生成をすぐ停止できるようにしてください。
import { pipeAgentReplyToWriter } from '@mastra/livekit'
const generateResponse = createStep({
id: 'generateResponse',
// input and output schemas omitted
execute: async ({ inputData, mastra, writer, abortSignal }) => {
const stream = await mastra.getAgent('support').stream(inputData.turn, { abortSignal })
const reply = await pipeAgentReplyToWriter(stream, writer)
return { reply }
},
})
戻り値:Promise<string>。蓄積された応答テキスト。
パラメーターパラメーターへの直接リンク
agentStream:
writer:
chatContextToMessages()chatcontexttomessagesへの直接リンク
LiveKit Chat コンテキストを、指示と関数呼び出しを除いた agent.stream() が受け付けるプレーンメッセージに変換します。完全な文字起こしをステートレスな Workflow に渡すため、workflowInput で使用します。
import { createLiveKitWorker, chatContextToMessages } from '@mastra/livekit/worker'
export default createLiveKitWorker({
mastra,
workflow: 'phoneConversation',
workflowInput: ({ chatCtx }) => ({ history: chatContextToMessages(chatCtx) }),
})
戻り値:VoiceTurnMessage[]。各要素は { role: 'system' | 'user' | 'assistant'; content: string; id?: string } です。
MastraLLMmastrallmへの直接リンク
Mastra Agent を基盤とする標準 LiveKit LLM プラグイン(llm.LLM)です。独自に voice.AgentSession を構築し、llm スロットで Mastra を使用する場合に利用します。マネージドな代替手段は createLiveKitWorker() です。選択方法については、Mastra を LLM コンポーネントとして使用するを参照してください。
remote を指定すると、プラグインは Server-Sent Events(SSE)を使用し、Mastra サーバーから HTTP 経由で各ターンをストリーミングします。Agent ループ、Tool、Memory はサーバー側で実行され、Agent を中断するとサーバー側の生成も中止されます。
import { voice } from '@livekit/agents'
import { MastraLLM } from '@mastra/livekit/plugin'
const session = new voice.AgentSession({
llm: new MastraLLM({
remote: { baseUrl: process.env.MASTRA_URL!, agentId: 'support' },
memory: { thread: callId, resource: userId },
}),
stt: 'deepgram/nova-3',
tts: 'cartesia/sonic-3',
// Required with `memory`: LiveKit enables preemptive generation by default.
turnHandling: { preemptiveGeneration: { enabled: false } },
})
プラグインは provider を mastra、model を Agent ID として報告するため、LiveKit のメトリクスとフォールバックアダプターはほかの LLM と同様に識別します。
コンストラクターオプションコンストラクターオプションへの直接リンク
remote、agent、generate のいずれか1つだけを応答ソースとして指定します。
remote?:
agent?:
generate?:
memory?:
requestContext?:
toolFeedback?:
onToolCall?:
onTurnComplete?:
memory をセッションの preemptiveGeneration オプションと組み合わせないでください。独自に構築したセッションでは LiveKit がこのオプションをデフォルトで有効にします。LiveKit が破棄する前に先行ターンが完了すると、ユーザーメッセージと発話されなかった応答が Thread に永続化されます。セッションで turnHandling: { preemptiveGeneration: { enabled: false } } を設定してください。ステートレスモード(memory なし)は先行生成と併用できます。
Mastra Agent で実行する ToolMastra Agent で実行する Toolへの直接リンク
Tool は Mastra Agent のサーバー側で定義および実行されます。プラグインが LiveKit Tool 定義を転送することはありません。セッションが空でない toolCtx を渡すと、無視した Tool の名前を含む警告を1回記録します。すべての Tool はサーバー側で完了する必要があります。承認またはクライアント側の実行が必要な Tool は、通話を停止させる代わりに説明的なエラーでターンを失敗させます。
Tool のアクティビティは toolFeedback、onToolCall、onTurnComplete を通じて Worker に届きます。
指示指示への直接リンク
LiveKit は voice.Agent の instructions を各リクエストの Chat コンテキストに挿入します。サーバー側 Mastra Agent の指示が正となるため、プラグインはこれを破棄します。プロンプトを変更するには Mastra Agent を変更してください。
中断されたターン中断されたターンへの直接リンク
ユーザーが応答を中断した場合:
- プラグインがストリームをキャンセルします。サーバーは生成を中止し、そのターンの内容を永続化しません。
- LiveKit はユーザーが実際に聞いた部分を、中断済みのフラグを付けて Chat コンテキストに記録します。
- 次のターンで、プラグインは聞こえた部分だけを新しいユーザーメッセージの前に再送信し、Memory Thread を通話に合わせて補完します。メッセージには LiveKit のメッセージ ID があり、サーバーは ID で重複排除するため、再試行と再送信は冪等です。
中断直後にユーザーが通話を終了すると、最後の断片は記録されません。文字起こしに含める必要がある場合は、セッションイベントからすぐに反映してください。共有メッセージ ID により、次のターンでの再送信は重複ではなく Upsert になります。
import { voice } from '@livekit/agents'
import { MastraClient } from '@mastra/client-js'
const client = new MastraClient({ baseUrl: process.env.MASTRA_URL! })
session.on(voice.AgentSessionEventTypes.ConversationItemAdded, ({ item }) => {
if (item.type !== 'message' || item.role !== 'assistant' || !item.interrupted) return
void client.saveMessageToMemory({
agentId: 'support',
messages: [
{
id: item.id,
threadId: callId,
resourceId: userId,
role: 'assistant',
content: item.textContent ?? '',
type: 'text',
createdAt: new Date(),
},
],
})
})
使用量メトリクス使用量メトリクスへの直接リンク
サーバーがターンのトークン使用量を報告すると、プラグインは LiveKit に渡します。そのため、セッションの metrics_collected イベントにはほかの LLM プラグインと同様に、最初のトークンまでの時間、所要時間、トークン数が含まれます。同じ使用量オブジェクト(promptTokens、completionTokens、promptCachedTokens、totalTokens)が onTurnComplete に result.usage として届きます。
エラーとタイムアウトエラーとタイムアウトへの直接リンク
トランスポートは LiveKit の APIError 型(APIStatusError、APIConnectionError、APITimeoutError)をスローするため、セッションの再試行ポリシー(connOptions.maxRetry)と FallbackAdapter のフェイルオーバーはそのまま動作します。最初のトークン後にターンが再試行されることはありません。Voice 応答では、途中まで聞こえた内容を再生し直すよりも速やかに失敗する方が適切です。
接続と最初のトークンの Watchdog はセッションの connOptions.timeoutMs(デフォルト10秒)を使用するため、接続を受け入れてもストリーミングしないサーバーによって無音状態が無期限に続くことはありません。
通話途中で Mastra サーバーが停止すると、各応答の試行は再試行後に型付きエラーで失敗し、応答が数回連続で失敗すると LiveKit がセッションを閉じます。その上限に達する前にサーバーを復旧すれば、次のターンで通話が復旧します。
メッセージ内容メッセージ内容への直接リンク
メッセージ抽出の対象はテキストだけです。画像コンテンツは破棄され、音声コンテンツは文字起こしだけが含まれます。Voice パイプラインには影響しませんが、Chat コンテキストに独自に挿入する項目にはテキストが必要です。
createRemoteAgentReplyGenerator()createremoteagentreplygeneratorへの直接リンク
HTTP/SSE 経由でリモート Mastra サーバー上の Agent ループを実行する応答 Generator を構築します。MastraLLM の remote モードが内部で使用します。createLiveKitWorker の generate オプションから直接使用し、機能一式を備えた Worker をリモートサーバーに対して実行できます。
import { createLiveKitWorker, createRemoteAgentReplyGenerator } from '@mastra/livekit/worker'
import { mastra } from './index'
export default createLiveKitWorker({
mastra, // local instance for logger and worker config; replies come from the remote server
generate: createRemoteAgentReplyGenerator({
baseUrl: process.env.MASTRA_URL!,
agentId: 'support',
}),
memory: ({ metadata, roomName }) => ({ thread: metadata.threadId ?? roomName }),
stt: 'deepgram/nova-3',
tts: 'cartesia/sonic-3',
})
generate パスでは Worker レベルの toolFeedback と onTurnComplete オプションは適用されず、Worker の通話終了検出も発生しません。代わりに Hook を Generator へ渡してください。
ターンのキャンセル(割り込み)は HTTP リクエストを破棄し、サーバー上の生成を中止します。エラーは LiveKit の APIError 型としてスローされます。retries オプションは最初の接続試行だけに適用されます。最初のチャンク後にターンが再試行されることはありません。
戻り値:VoiceReplyGenerator。
オプションオプションへの直接リンク
baseUrl:
agentId:
apiPrefix?:
headers?:
fetch?:
timeoutMs?:
retries?:
body?:
toolFeedback?:
onToolCall?:
onTurnComplete?:
speakGreeting()speakgreetingへの直接リンク
所有するセッションで、中断と再生オプションに従って冒頭の挨拶を発話します。LiveKit の SpeechHandle を返し、挨拶テキストがない場合は undefined を返します。createLiveKitWorker() は greeting 設定で内部的に使用します。
import { speakGreeting } from '@mastra/livekit/worker'
await speakGreeting(session, {
text: "You've reached support. You're speaking with an AI assistant.",
allowInterruptions: false,
awaitPlayout: true,
})
パラメーターパラメーターへの直接リンク
session:
greeting:
waitForAgentDoneSpeaking()waitforagentdonespeakingへの直接リンク
Agent が応答の生成も再生も行わなくなり、状態が thinking と speaking から移行すると解決します。Agent がすでにアイドル状態の場合は直ちに解決し、安全上の上限として常に maxWaitMs(デフォルト30秒)以内に解決します。終了メッセージが途中で切れずに再生されるよう、セッションを破棄する前に使用します。
import { waitForAgentDoneSpeaking } from '@mastra/livekit/worker'
await waitForAgentDoneSpeaking(session)
runEndCall()runendcallへの直接リンク
Agent が通話終了を求めた後に通話を終了します。Agent の終了メッセージを待ち、省略可能な最後の message を中断なしで発話します。その後 Room を削除し、SIP 発信者を含む通話相手を切断します。Job は登録済みコールバックとともにシャットダウンします。
MastraLLM の onToolCall およびサーバー側 Agent の通話終了 Toolと組み合わせ、所有するセッションで Agent 主導の通話終了を再構築します。
import { MastraLLM } from '@mastra/livekit/plugin'
import { DEFAULT_END_CALL_TOOL, runEndCall } from '@mastra/livekit/worker'
let ending = false
const llm = new MastraLLM({
remote: { baseUrl: process.env.MASTRA_URL!, agentId: 'support' },
onToolCall: ({ toolName }) => {
if (toolName !== DEFAULT_END_CALL_TOOL || ending) return
ending = true
void runEndCall(session, ctx, {}, console)
},
})
エクスポートされる定数 DEFAULT_END_CALL_TOOL('endCall')、DEFAULT_END_CALL_REASON、DEFAULT_END_CALL_MAX_WAIT_MS(30000)にはデフォルト値が格納されています。
パラメーターパラメーターへの直接リンク
session:
ctx:
config:
logger:
createEndCallTool()createendcalltoolへの直接リンク
Agent が通話を終了するときに呼び出す Mastra Tool を構築します。Tool は意図を通知し、省略可能な記録処理を実行できます。実際の通話終了は Worker が行います。Tool はサーバーセーフなルートエントリーに存在します。サーバーコードで定義された Agent に追加してください。
import { Agent } from '@mastra/core/agent'
import { createEndCallTool } from '@mastra/livekit'
const supportAgent = new Agent({
id: 'support',
name: 'Support',
instructions:
'Help the caller. When everything is wrapped up, say goodbye and call endCall as your final action.',
model: 'openai/gpt-5-mini',
tools: { endCall: createEndCallTool() },
})
createLiveKitWorker() では configuration: { endCall: {} } を設定すると、Worker が Tool を監視して通話を終了します。所有するセッションでは、runEndCall() を使用して通話終了を再構築します。
オプションオプションへの直接リンク
id?:
description?:
onEndCall?:
liveKitConnectionRoute()livekitconnectionrouteへの直接リンク
Voice Agent を Room に Dispatch した LiveKit アクセストークンを発行する API Route を返します。フロントエンドがセッションへの参加時に呼び出します。
import { Mastra } from '@mastra/core/mastra'
import { liveKitConnectionRoute } from '@mastra/livekit'
export const mastra = new Mastra({
server: {
apiRoutes: [liveKitConnectionRoute({ agentName: 'mastra-voice' })],
},
})
Route は省略可能な agentId、threadId、resourceId フィールドを含む JSON 本文を受け取り、{ serverUrl, roomName, participantName, participantToken } で応答します。threadId のデフォルトは生成された Room 名です。
オプションオプションへの直接リンク
path?:
serverUrl?:
apiKey?:
apiSecret?:
agentName?:
ttl?:
requiresAuth?:
roomName?:
participantIdentity?:
metadata?:
dispatchVoiceSession()dispatchvoicesessionへの直接リンク
Mastra Voice Agent をプログラムで LiveKit Room に Dispatch します。発信通話など、サーバーが開始するセッションに使用します。
import { dispatchVoiceSession } from '@mastra/livekit'
await dispatchVoiceSession({
roomName: 'support-call-42',
agentName: 'mastra-voice',
metadata: { agentId: 'support', threadId: 'thread-42' },
})
オプションオプションへの直接リンク
roomName:
agentName?:
metadata?:
serverUrl?:
apiKey?:
apiSecret?:
LiveKitSessionMetadatalivekitsessionmetadataへの直接リンク
LiveKit Job Dispatch を通じて Mastra サーバーから Worker に渡されるメタデータです。
agentId?:
threadId?:
resourceId?:
requestContext?:
メタデータは JSON 文字列として転送されます。liveKitConnectionRoute() と dispatchVoiceSession() がシリアライズします。独自コードから Dispatch する場合は serializeSessionMetadata(metadata) を使用するか、SIP Dispatch ルールなどの LiveKit 側設定に JSON を直接記述します。requestContext の項目は、通話の各ターンで Agent の実行時定義の指示、Tool、Input Processor に届きます。