> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-HK/llms.txt # LiveKit `@mastra/livekit` 套件將 Mastra Agent 連接至 LiveKit Agents 框架。LiveKit 負責執行音訊管線(語音活動偵測、語音轉文字、話輪偵測、文字轉語音及插話),而此套件會將回覆產生流程橋接至 Mastra Agent 的 `stream()` 呼叫。 有關設定及概念,請參閱[即時語音](https://mastra.zisheng.pro/zh-HK/guides/voice/realtime-voice)。 此套件有三個進入點: - `@mastra/livekit`:伺服器端 API,包括 [`liveKitConnectionRoute()`](#livekitconnectionroute)、[`dispatchVoiceSession()`](#dispatchvoicesession)、[`pipeAgentReplyToWriter()`](#pipeagentreplytowriter)、[`serializeSessionMetadata()`](#livekitsessionmetadata) 及 [`createEndCallTool()`](#createendcalltool)。請在 Mastra 伺服器程式碼中匯入這些項目。此進入點絕不會載入 LiveKit Agents 執行階段。 - `@mastra/livekit/worker`:worker 執行階段,包括 [`createLiveKitWorker()`](#createlivekitworker)、[`runLiveKitWorker()`](#runlivekitworker)、[`chatContextToMessages()`](#chatcontexttomessages),以及工作階段輔助函式 [`speakGreeting()`](#speakgreeting)、[`waitForAgentDoneSpeaking()`](#waitforagentdonespeaking) 和 [`runEndCall()`](#runendcall)。只應在 worker 進入點檔案中匯入。 - `@mastra/livekit/plugin`:LLM 元件 plugin,包括 [`MastraLLM`](#mastrallm) 和 [`createRemoteAgentReplyGenerator()`](#createremoteagentreplygenerator)。請在自行建立 `voice.AgentSession` 的 worker 中匯入。`createRemoteAgentReplyGenerator()` 亦會從 `@mastra/livekit/worker` 匯出,因為它可接入 `createLiveKitWorker()` 的 `generate` 選項。`MastraLLM` 只由 plugin 提供。 ## `createLiveKitWorker()` 建立一個以 Mastra Agent 回應語音工作階段的 LiveKit Agent 定義。請將它用作 worker 進入點檔案的預設匯出。 ```typescript 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** (`Mastra`): 由其 Agent 處理語音工作階段的 Mastra 執行個體。 **agent** (`string | (args) => string | Agent | Promise`): 指定由哪個 Mastra Agent 回應每個工作階段:固定的 Agent key 或 id,或在每個工作階段以分派 metadata 和 job context 呼叫的 resolver。預設為分派 metadata 中的 agentId。 **workflow** (`string | Workflow | (args) => string | Promise`): 使用 Mastra Workflow 而非 Agent 產生每個話輪的回覆:Workflow 執行個體、固定的 Workflow key 或 id,或為每個工作階段傳回 Workflow id 的 resolver。Workflow 會在每個話輪執行一次直至完成(不可暫停或恢復)。不可與 agent 同時使用;必須提供 workflowInput。 **workflowInput** (`(args: VoiceTurnContext & { metadata }) => unknown | Promise`): 將話輪映射至 Workflow 的 inputData。設定 workflow 時必須提供。每個話輪都傳入完整逐字稿的無狀態映射,可避免在 Workflow 中攜帶對話狀態。 **replyStep** (`string`): 只串流來自此 Workflow step id 的文字。預設包括所有會寫入其 writer 的 step。 **resultText** (`(result: unknown) => string | undefined`): 當 Workflow 沒有透過 writer 串流文字時的後備方案:從最終執行結果衍生要讀出的回覆。 **generate** (`VoiceReplyGenerator`): 最低層級的替代方案:直接提供任何回覆產生器(自訂 Workflow、遠端橋接器等)。 **stt** (`STT | string`): 語音轉文字:LiveKit plugin 執行個體或 'deepgram/nova-3' 等推理模型字串。如要為每次通話作出選擇,請設定 configuration.stt resolver;它會優先使用,並以此選項作後備。 **tts** (`TTS | string`): 文字轉語音:LiveKit plugin 執行個體或 'cartesia/sonic-3' 等推理模型字串。如要為每次通話作出選擇,請設定 configuration.tts resolver;它會優先使用,並以此選項作後備。 **vad** (`VAD | 'silero' | false`): 語音活動偵測。'silero' 會在預熱期間從 @livekit/agents-plugin-silero 載入 Silero VAD。傳入執行個體以使用自訂實作,或傳入 false 停用。 (Default: `'silero'`) **turnDetection** (`'multilingual' | 'english' | TurnDetectionMode`): 話輪結束偵測。'multilingual' 和 'english' 會從 @livekit/agents-plugin-livekit 載入 LiveKit 的語意話輪偵測器。'vad'、'stt' 或 'manual' 等其他值會原樣傳入。 **turnHandling** (`Partial`): 話輪處理調整:端點延遲、中斷敏感度及預先產生。除非在此設定,否則 worker 會停用 preemptiveGeneration;每次預先產生嘗試都會重新執行 Mastra Agent,並保存重複的使用者訊息。 **sessionOptions** (`Partial`): 額外的 LiveKit AgentSession 選項,會合併並覆蓋此輔助函式建立的設定。 **memory** (`false | ((args) => { thread, resource } | false)`): Memory 映射。當解析出的 Agent 已設定 Memory 時,預設為 { thread: metadata.threadId ?? 房間名稱, resource: metadata.resourceId ?? thread }。傳入 false 可停用,或傳入函式自訂。 **toolFeedback** (`(toolCall) => string | undefined`): 當 Mastra Agent 在回覆途中開始 Tool 呼叫時觸發。傳回一段簡短語句,在 Tool 執行期間讀出。 **onTurnComplete** (`(ctx: VoiceTurnCompleteContext) => void | Promise`): 每個話輪在回覆完成串流至文字轉語音後呼叫一次。它會在音訊路徑以外執行,且不會被 await。context 包含產生的回覆(text、toolCalls、interrupted、usage)及已解析的 Memory 映射。 **configuration** (`LiveKitWorkerConfiguration`): 組合式對話與合規設定:開場問候及 AI 身分披露、同意要求、由 Agent 發起掛線,以及每次通話的 STT/TTS 選擇。 **configuration.greeting** (`GreetingConfiguration`): 開場問候及 AI 身分披露:text(固定字串,或按每次通話為各 tenant 提供問候語的 resolver)、allowInterruptions、awaitPlayout、persist,以及透過 repeatEvery 和 repeatText 定期再次披露。 **configuration.consentPolicy** (`ConsentConfiguration`): 通話的同意政策,以具名要求表示(由 summaryStorage 開始)。它只作聲明用途,worker 本身不會阻止任何操作。請在執行階段使用 createConsentTool 擷取授權,並在自己的程式碼中強制執行;已聲明的政策會在 onCallEnd 中提供,以便交叉核對。 **configuration.endCall** (`EndCallConfiguration`): 由 Agent 發起掛線:worker 會在每個話輪監察結束通話 Tool(配合 createEndCallTool 使用),等待 Agent 的結語播放完畢後中斷連線,並在退出期間執行 onCallEnd。 **configuration.stt** (`(context: VoiceCallContext) => STT | string | undefined`): 每次通話的語音轉文字:每次通話在連線後以 { metadata, requestContext, roomName, ctx } 呼叫一次的 resolver,可傳回頂層 stt 選項接受的任何值。傳回 undefined 會改用頂層 stt。請跨通話快取 plugin 執行個體;resolver 會在通話設定期間執行。 **configuration.tts** (`(context: VoiceCallContext) => TTS | string | undefined`): 每次通話的文字轉語音:每次通話在連線後以 { metadata, requestContext, roomName, ctx } 呼叫一次的 resolver,可傳回頂層 tts 選項接受的任何值,讓每個 tenant 使用一種聲線或語言。傳回 undefined 會改用頂層 tts。請跨通話快取 plugin 執行個體。 **greeting** (`string`): 工作階段開始時讀出的靜態問候語。已棄用:建議使用 configuration.greeting.text。 **persistGreeting** (`boolean`): 將讀出的問候語以 assistant 訊息形式儲存至 Memory thread,使已儲存的 thread 成為忠實的通話逐字稿。只在已設定問候語並啟用 Memory 時適用。已棄用:建議使用 configuration.greeting.persist。 (Default: `true`) **observability** (`boolean`): 當 Mastra 執行個體已設定 observability 時追蹤每次通話。每個工作階段會開啟一個 voice call span:每個話輪的 Agent 執行都會巢狀置於其下,LiveKit 的 STT、TTS、語句結束、VAD 及 LLM 延遲指標會成為子 span,而該 span 會連同按模型彙總的用量資料一併關閉。傳入 false 可停用。 (Default: `true`) **inputOptions** (`Partial`): 傳至 session.start() 的 LiveKit 房間輸入選項。 **outputOptions** (`Partial`): 傳至 session.start() 的 LiveKit 房間輸出選項。 **onSessionStart** (`(args: { session, ctx, agent, metadata }) => void | Promise`): 在工作階段開始後呼叫。可在此附加事件監聽器或觸發回覆。 ## `runLiveKitWorker()` 為 worker 進入點檔案啟動 LiveKit worker CLI(`dev`、`start` 及 `connect` 子命令)。請從預設匯出 worker 定義的檔案呼叫,並加入防護條件,確保只在直接執行時啟動(worker 會為每個工作階段建立子程序,並重新匯入同一檔案)。使用此輔助函式,而非 `@livekit/agents` 的 `cli.runApp`,可確保 worker 執行階段和橋接器共用同一份 LiveKit SDK。 ### 選項 **entry** (`string | URL`): 預設匯出 Agent 定義的 worker 進入點模組。請傳入 import.meta.url。 **agentName** (`string`): 用於明確分派的 LiveKit Agent 名稱。 (Default: `'mastra-voice'`) **serverOptions** (`Partial`): 額外的 LiveKit ServerOptions,會合併並覆蓋此輔助函式建立的設定。 ## `pipeAgentReplyToWriter()` 在 Workflow 回覆路徑上,將 Mastra Agent 的回覆串流至 Workflow step 的 `writer`。它會轉發 Agent 的文字增量,讓文字轉語音可在完整回覆準備好之前開始;亦會轉發 Tool 呼叫區塊,讓 `toolFeedback` 觸發,並讓 `onTurnComplete` 取得 Tool 清單。只傳送 `stream.textStream` 會在沒有提示下遺失 Tool 呼叫。請將 step 的 `abortSignal` 傳至 `agent.stream()`,讓插話能立即停止產生內容。 ```typescript 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`,累積的回覆文字。 ### 參數 **agentStream** (`AgentReplyStreamLike`): 由 agent.stream() 傳回的串流,即任何公開 fullStream 非同步 iterable 的物件。 **writer** (`WritableStream`): Workflow step 的 writer。 ## `chatContextToMessages()` 將 LiveKit chat context 轉換為 `agent.stream()` 接受的純訊息,並排除 instructions 及函式呼叫。在 `workflowInput` 中使用它,可將完整逐字稿傳入無狀態 Workflow。 ```typescript 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 }`。 ## `MastraLLM` 由 Mastra Agent 支援的標準 LiveKit LLM plugin(`llm.LLM`)。當你自行建立 `voice.AgentSession`,並希望在 `llm` 位置使用 Mastra 時使用。[`createLiveKitWorker()`](#createlivekitworker) 是受管理的替代方案。選擇方法請參閱[使用 Mastra 作為 LLM 元件](https://mastra.zisheng.pro/zh-HK/guides/voice/realtime-voice)。 使用 `remote` 時,plugin 會透過 HTTP 使用伺服器傳送事件(SSE),從你的 Mastra 伺服器串流每個話輪。Agent loop、Tool 及 Memory 均在伺服器端執行;中斷 Agent 亦會中止伺服器端的內容產生。 ```typescript 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 } }, }) ``` plugin 會將 `provider` 回報為 `mastra`,並將 `model` 回報為 Agent id,因此 LiveKit 指標及後備 adapter 可像識別任何其他 LLM 一樣識別它。 ### 建構函式選項 只可提供一個回覆來源:`remote`、`agent` 或 `generate`。 **remote** (`RemoteMastraAgentOptions`): 透過 HTTP 連接的遠端 Mastra 伺服器。接受與 createRemoteAgentReplyGenerator() 相同的連線選項:baseUrl、agentId、apiPrefix、headers、fetch、timeoutMs、retries、body。 **agent** (`Agent`): 程序內的 Mastra Agent。無需第二個部署即可擁有工作階段。 **generate** (`VoiceReplyGenerator`): 自訂回覆來源。generate 來源會管理自己的 hook;下方的 toolFeedback、onToolCall 及 onTurnComplete 只適用於 remote 和 agent 來源。 **memory** (`{ thread: string; resource?: string } | false`): 對話持久保存,按每次通話解析(例如根據 SIP 來電者身分)。設定後,每個話輪只會傳送 Agent 上次說話後新增的訊息,並由 Mastra Memory 提供歷史記錄。省略時,每個話輪都會傳送完整的 LiveKit chat context。 (Default: `false`) **requestContext** (`RequestContext | Record`): 轉發至內容產生程序的 request context(tenant、撥打號碼等)。 **toolFeedback** (`(toolCall: VoiceToolCall) => string | undefined`): 傳回一段簡短語句,在伺服器端 Tool 執行期間讀出。 **onToolCall** (`(toolCall: VoiceToolCall) => void`): 在串流途中,每個 Tool 呼叫開始時觸發。配合 runEndCall() 使用,以實作自己的由 Agent 發起掛線流程。 **onTurnComplete** (`(ctx: VoiceTurnCompleteContext) => void | Promise`): 每個話輪在回覆完成串流後呼叫一次,於音訊路徑以外執行且不會被 await。context 包含產生的回覆:text、toolCalls、interrupted 及 usage。 > **注意:** 請勿將 `memory` 與工作階段的 `preemptiveGeneration` 選項一併使用;LiveKit 會在你自行建立的工作階段中預設啟用此選項。如果推測話輪在 LiveKit 捨棄前已完成,便會將一則使用者訊息和一段從未讀出的回覆保存至 thread。請在工作階段設定 `turnHandling: { preemptiveGeneration: { enabled: false } }`。無狀態模式(不使用 `memory`)可配合預先產生使用。 ### 在 Mastra Agent 上執行的 Tool Tool 會在伺服器端的 Mastra Agent 上定義及執行。plugin 絕不會轉發 LiveKit Tool 定義:如果工作階段傳入非空白的 `toolCtx`,它會記錄一次性警告,列出被忽略的 Tool。每個 Tool 都必須在伺服器端完成:需要批准或在用戶端執行的 Tool 會令該話輪以具描述性的錯誤失敗,而不會令通話停滯。 Tool 活動會透過 `toolFeedback`、`onToolCall` 及 `onTurnComplete` 傳送至 worker。 ### 指示 LiveKit 會將你的 `voice.Agent` 的 `instructions` 注入每個請求的 chat context。plugin 會捨棄這些內容,因為應以伺服器端 Mastra Agent 自身的 instructions 為準。如要更改 prompt,請更改 Mastra Agent。 ### 被中斷的話輪 當使用者中斷回覆時: 1. plugin 會取消串流。伺服器會中止產生內容,且不會保存該話輪的任何內容。 2. LiveKit 會在其 chat context 記錄使用者實際聽到的部分,並標記為 interrupted。 3. 在下一個話輪,plugin 會重新傳送只有已聽取內容的片段,並將它置於新的使用者訊息之前,讓 Memory thread 回填至與通話相符。訊息會攜帶 LiveKit message id,而伺服器會按 id 移除重複項目,因此重試及重新傳送均保持冪等。 如果使用者在中斷後立即掛線,最後的片段便不會被記錄。當逐字稿必須擷取該片段時,請立即透過工作階段事件進行協調;共用的 message id 表示下一個話輪重新傳送時會執行 upsert,而不會建立重複項目: ```typescript 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(), }, ], }) }) ``` ### 用量指標 當伺服器回報某個話輪的 token 用量時,plugin 會將資料提供給 LiveKit,因此工作階段的 `metrics_collected` 事件會像任何 LLM plugin 一樣,包含首個 token 所需時間、持續時間及 token 數量。同一個 usage 物件(`promptTokens`、`completionTokens`、`promptCachedTokens`、`totalTokens`)會以 `result.usage` 傳至 `onTurnComplete`。 ### 錯誤及逾時 傳輸層會擲出 LiveKit 的 `APIError` 類型(`APIStatusError`、`APIConnectionError`、`APITimeoutError`),因此工作階段的重試政策(`connOptions.maxRetry`)及 `FallbackAdapter` 容錯轉移會維持原有運作。話輪在產生首個 token 後絕不會重試:語音回覆宜快速失敗,避免重播使用者只聽到一半的內容。 連線及首個 token watchdog 會使用工作階段的 `connOptions.timeoutMs`(預設為 10 秒),因此即使伺服器接受連線後一直不串流,也不會造成無限期靜音。 如果 Mastra 伺服器在通話期間停止運作,每次回覆嘗試都會在完成重試後以具類型錯誤失敗,而 LiveKit 會在連續數次回覆失敗後關閉工作階段。在容許次數用盡前恢復伺服器,通話便會在下一個話輪復原。 ### 訊息內容 訊息只會擷取文字:圖片內容會被捨棄,音訊內容則只會透過其逐字稿納入。語音管線不受影響,但你自行注入 chat context 的項目必須包含文字。 ## `createRemoteAgentReplyGenerator()` 建立透過 HTTP/SSE 在**遠端** Mastra 伺服器上執行 Agent loop 的回覆產生器。`MastraLLM` 的 `remote` 模式會在內部使用它。可透過 `createLiveKitWorker` 的 `generate` 選項直接使用,以遠端伺服器執行功能齊備的 worker: ```typescript 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 傳給產生器。 取消話輪(插話)會終止 HTTP 請求,從而中止伺服器上的內容產生。錯誤會以 LiveKit `APIError` 類型擲出。`retries` 選項只適用於初始連線嘗試。話輪在產生首個區塊後絕不會重試。 傳回:`VoiceReplyGenerator`。 ### 選項 **baseUrl** (`string`): 遠端 Mastra 伺服器的基礎 URL,例如 https\://my-app.example.com。 **agentId** (`string`): Agent 在遠端 Mastra 執行個體上註冊的 key 或 id。 **apiPrefix** (`string`): Mastra API 的路徑前綴。 (Default: `'/api'`) **headers** (`Record | () => Record | Promise>`): 靜態 header,或在每個話輪呼叫的 resolver,例如用於簽發新的授權 token。 **fetch** (`typeof fetch`): 可注入的 fetch 實作,用於測試或 proxy。 (Default: `globalThis.fetch`) **timeoutMs** (`number`): 連線及首個 token 的逾時時間(毫秒)。透過 MastraLLM 使用時,改以工作階段的 connOptions.timeoutMs 為預設值。 (Default: `10000`) **retries** (`number`): 初始連線的重試次數,只適用於首個區塊之前。透過 MastraLLM 使用時,重試由 LiveKit 工作階段管理,此值會強制設為 0。 (Default: `2`) **body** (`Record`): 合併至每個串流請求 body 的額外欄位。 **toolFeedback** (`(toolCall: VoiceToolCall) => string | undefined`): 傳回一段簡短語句,在伺服器端 Tool 執行期間讀出。 **onToolCall** (`(toolCall: VoiceToolCall) => void`): 在串流途中,每個 Tool 呼叫開始時觸發。 **onTurnComplete** (`(ctx: VoiceTurnCompleteContext) => void | Promise`): 每個話輪在回覆完成串流後呼叫一次,並於音訊路徑以外執行。 ## `speakGreeting()` 在你擁有的工作階段讀出開場問候語,並遵從中斷及播放選項。傳回 LiveKit `SpeechHandle`;如沒有問候文字,則傳回 `undefined`。`createLiveKitWorker()` 會在內部將它用於 `greeting` 設定。 ```typescript 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** (`voice.AgentSession`): 要在其中讀出內容的工作階段。 **greeting** (`{ text?: string; allowInterruptions?: boolean; awaitPlayout?: boolean }`): 問候文字及播放選項。當 awaitPlayout 為 true 時,傳回的 promise 會在問候語播放完畢(或被中斷)後解析。 ## `waitForAgentDoneSpeaking()` 當 Agent 不再產生或播放回覆,即其狀態已離開 `thinking` 和 `speaking` 時解析。若 Agent 已閒置,便會立即解析;為安全起見,亦必定會在 `maxWaitMs`(預設 30 秒)內解析。在終止工作階段前使用,可讓結語播放完畢而不會被截斷。 ```typescript import { waitForAgentDoneSpeaking } from '@mastra/livekit/worker' await waitForAgentDoneSpeaking(session) ``` ## `runEndCall()` 在 Agent 要求掛線後結束通話。它會等待 Agent 的結語,並在不受中斷的情況下讀出可選的最後 `message`。然後,它會刪除房間並為來電者掛線,包括 SIP 來電者。job 會連同其已註冊 callback 一併關閉。 將它配合 [`MastraLLM`](#mastrallm) 的 `onToolCall` 及伺服器端 Agent 上的[結束通話 Tool](#createendcalltool) 使用,以便在你擁有的工作階段中重建由 Agent 發起掛線的功能: ```typescript 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** (`voice.AgentSession`): 其 Agent 正在完成結語的工作階段。 **ctx** (`JobContext`): 用於刪除房間及關閉的 LiveKit job context。 **config** (`{ message?: string; reason?: string; maxWaitMs?: number; drainMs?: number }`): 掛線前讀出的可選最後訊息、要記錄的關閉原因、等待結語的安全上限,以及播放後的 drain(預設 800ms),讓來電者端已緩衝的音訊可在房間刪除前播放完畢。LiveKit 的播放計算只限於 worker 本機,因此在計算一清除時立即掛線會截斷道別語。 **logger** (`{ warn: (message: string, ...args: unknown[]) => void }`): 在終止步驟失敗時接收警告。請傳入你的 logger 或 console。 ## `createEndCallTool()` 建立 Agent 想結束通話時呼叫的 Mastra Tool。Tool 會表示意圖,亦可執行可選的記錄工作。實際掛線由 worker 執行。此 Tool 位於可安全用於伺服器的根進入點。請將它加入伺服器程式碼中定義的 Agent。 ```typescript 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()`](#runendcall) 重建掛線功能。 ### 選項 **id** (`string`): Agent 為結束通話而呼叫的 Tool id。必須與 worker 所監察的名稱(worker 的 configuration.endCall.tool,或你自己的 onToolCall 檢查)相符。 (Default: `'endCall'`) **description** (`string`): 覆蓋模型決定是否呼叫 Tool 時看到的描述。 **onEndCall** (`(request: { reason?: string; resourceId?: string; threadId?: string }) => void | Promise`): Agent 呼叫 Tool 時觸發的記錄 hook,可記錄原因或將通話標記為已解決。它會在話輪內執行,請確保快速完成。它不會掛斷通話。 ## `liveKitConnectionRoute()` 傳回一個 [API route](https://mastra.zisheng.pro/zh-HK/docs/server/custom-api-routes),用來簽發 LiveKit access token,並將語音 Agent 分派至房間。前端會呼叫它以加入工作階段。 ```typescript 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 body,並以 `{ serverUrl, roomName, participantName, participantToken }` 回應。`threadId` 預設為產生的房間名稱。 ### 選項 **path** (`string`): Route 路徑。 (Default: `'/voice/livekit/connection-details'`) **serverUrl** (`string`): LiveKit 伺服器 URL。 (Default: `process.env.LIVEKIT_URL`) **apiKey** (`string`): LiveKit API key。 (Default: `process.env.LIVEKIT_API_KEY`) **apiSecret** (`string`): LiveKit API secret。 (Default: `process.env.LIVEKIT_API_SECRET`) **agentName** (`string`): 用於明確分派的 LiveKit Agent 名稱。必須與 worker 的 agentName 相符。 (Default: `'mastra-voice'`) **ttl** (`string | number`): Token 有效期。 (Default: `'15m'`) **requiresAuth** (`boolean`): Route 是否需要驗證身分。 (Default: `true`) **roomName** (`string | (args) => string`): 房間名稱,或從請求衍生房間名稱的函式。 **participantIdentity** (`string | (args) => string`): 參與者身分,或從請求衍生參與者身分的函式。 **metadata** (`(args) => LiveKitSessionMetadata | Promise`): 建立傳送至 worker 的工作階段 metadata。預設會原樣傳遞請求 body 中的 agentId、threadId 及 resourceId。 ## `dispatchVoiceSession()` 以程式方式將 Mastra 語音 Agent 分派至 LiveKit 房間,適用於外撥通話等由伺服器發起的工作階段。 ```typescript import { dispatchVoiceSession } from '@mastra/livekit' await dispatchVoiceSession({ roomName: 'support-call-42', agentName: 'mastra-voice', metadata: { agentId: 'support', threadId: 'thread-42' }, }) ``` ### 選項 **roomName** (`string`): 要將 Agent 分派至其中的房間。按需要建立。 **agentName** (`string`): 必須與 worker 的 agentName 相符。 (Default: `'mastra-voice'`) **metadata** (`LiveKitSessionMetadata`): 工作階段 metadata:agentId、threadId、resourceId、requestContext。 **serverUrl** (`string`): LiveKit 伺服器 URL。 (Default: `process.env.LIVEKIT_URL`) **apiKey** (`string`): LiveKit API key。 (Default: `process.env.LIVEKIT_API_KEY`) **apiSecret** (`string`): LiveKit API secret。 (Default: `process.env.LIVEKIT_API_SECRET`) ## `LiveKitSessionMetadata` 透過 LiveKit job 分派,從 Mastra 伺服器傳至 worker 的 metadata。 **agentId** (`string`): 要執行的 Mastra Agent,以已註冊的 key 或 Agent id 指定。 **threadId** (`string`): Memory thread id。預設為 LiveKit 房間名稱。 **resourceId** (`string`): Memory resource id,通常為終端使用者 id。 **requestContext** (`Record`): 還原至 RequestContext 以執行 Agent 的純物件項目。 metadata 會以 JSON 字串傳送。`liveKitConnectionRoute()` 和 `dispatchVoiceSession()` 會代你將它序列化;透過自己的程式碼分派時,請使用 `serializeSessionMetadata(metadata)`,或直接在 LiveKit 端設定(例如 SIP 分派規則)中寫入 JSON。`requestContext` 中的項目會在每個通電話輪傳至 Agent 在執行階段定義的 instructions、Tool 及輸入處理器。 ## 相關內容 - [即時語音](https://mastra.zisheng.pro/zh-HK/guides/voice/realtime-voice) - [LiveKit Agents 文件](https://docs.livekit.io/agents/)