> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ko/llms.txt # 라이브킷 그만큼`@mastra/livekit`패키지는 Mastra Agent를 LiveKit Agent 프레임워크에 연결합니다. LiveKit은 오디오 파이프라인(음성 활동 감지, 음성-텍스트, 회전 감지, 텍스트-음성, 참여)을 실행하고 패키지는 응답 생성을 Mastra Agent의`stream()`부르다. 설정과 개념은 [실시간 음성](https://mastra.zisheng.pro/ko/guides/voice/realtime-voice)을 참조하세요. 패키지에는 세 가지 진입점이 있습니다. - `@mastra/livekit`: 서버 측 API인 [`liveKitConnectionRoute()`](#livekitconnectionroute), [`dispatchVoiceSession()`](#dispatchvoicesession), [`pipeAgentReplyToWriter()`](#pipeagentreplytowriter), [`serializeSessionMetadata()`](#livekitsessionmetadata), [`createEndCallTool()`](#createendcalltool)을 제공합니다. Mastra 서버 코드에서 가져오세요. 이 진입점은 LiveKit Agent 런타임을 로드하지 않습니다. - `@mastra/livekit/worker`: 작업자 런타임인 [`createLiveKitWorker()`](#createlivekitworker), [`runLiveKitWorker()`](#runlivekitworker), [`chatContextToMessages()`](#chatcontexttomessages)와 세션 헬퍼 [`speakGreeting()`](#speakgreeting), [`waitForAgentDoneSpeaking()`](#waitforagentdonespeaking), [`runEndCall()`](#runendcall)을 제공합니다. 작업자 진입점 파일에서만 가져오세요. - `@mastra/livekit/plugin`: LLM 구성 요소 플러그인인 [`MastraLLM`](#mastrallm)과 [`createRemoteAgentReplyGenerator()`](#createremoteagentreplygenerator)를 제공합니다. 자체 `voice.AgentSession`을 구성하는 작업자에서 가져오세요. `createRemoteAgentReplyGenerator()`는 `createLiveKitWorker()`의 `generate` 옵션에 연결되므로 `@mastra/livekit/worker`에서도 내보냅니다. `MastraLLM`은 플러그인 전용입니다. ## `createLiveKitWorker()` Mastra Agent와의 음성 세션에 응답하는 LiveKit Agent 정의를 구축합니다. 이를 작업자 항목 파일의 기본 내보내기로 사용하십시오. ```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 키 또는 ID를 사용하거나, 디스패치 메타데이터와 작업 컨텍스트를 받아 세션마다 호출되는 리졸버를 사용할 수 있습니다. 기본값은 디스패치 메타데이터의 agentId입니다. **workflow** (`string | Workflow | (args) => string | Promise`): Agent 대신 Mastra Workflow로 각 턴의 응답을 생성합니다. Workflow 인스턴스, 고정 Workflow 키 또는 ID, 세션별 Workflow ID를 반환하는 리졸버를 사용할 수 있습니다. Workflow는 턴마다 완료될 때까지 한 번 실행됩니다(일시 중단 또는 재개 없음). agent와 함께 사용할 수 없으며 workflowInput이 필요합니다. **workflowInput** (`(args: VoiceTurnContext & { metadata }) => unknown | Promise`): 턴을 Workflow inputData에 매핑합니다. workflow가 설정된 경우 필수입니다. 턴마다 전체 대화 기록을 전달하는 상태 비저장 매핑을 사용하면 Workflow에서 대화 상태를 유지하지 않아도 됩니다. **replyStep** (`string`): 이 Workflow 단계 ID의 텍스트만 스트리밍합니다. 기본적으로 writer에 쓰는 모든 단계를 사용합니다. **resultText** (`(result: unknown) => string | undefined`): Workflow가 writer를 통해 텍스트를 스트리밍하지 않을 때 사용하는 대체 동작입니다. 최종 실행 결과에서 음성 응답을 추출합니다. **generate** (`VoiceReplyGenerator`): 가장 낮은 수준의 탈출구입니다. 사용자 정의 Workflow, 원격 브리지 등 원하는 응답 생성기를 직접 제공할 수 있습니다. **stt** (`STT | string`): 음성을 텍스트로 변환합니다. LiveKit 플러그인 인스턴스 또는 'deepgram/nova-3' 같은 추론 Model 문자열을 사용할 수 있습니다. 통화별로 선택하려면 configuration.stt 리졸버를 설정하세요. 이 리졸버가 우선하며, 이 옵션은 대체 값으로 사용됩니다. **tts** (`TTS | string`): 텍스트를 음성으로 변환합니다. LiveKit 플러그인 인스턴스 또는 'cartesia/sonic-3' 같은 추론 Model 문자열을 사용할 수 있습니다. 통화별로 선택하려면 configuration.tts 리졸버를 설정하세요. 이 리졸버가 우선하며, 이 옵션은 대체 값으로 사용됩니다. **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`): 턴 처리 조정 옵션입니다. 엔드포인트 지연, 중단 민감도, 선제 생성을 설정할 수 있습니다. 여기에서 설정하지 않으면 작업자는 preemptiveGeneration을 비활성화합니다. 선제 생성이 시도될 때마다 Mastra Agent가 다시 실행되고 중복 사용자 메시지가 저장되기 때문입니다. **sessionOptions** (`Partial`): 이 헬퍼가 구성한 옵션 위에 병합할 추가 LiveKit AgentSession 옵션입니다. **memory** (`false | ((args) => { thread, resource } | false)`): Memory 매핑입니다. 확인된 Agent에 Memory가 구성되어 있으면 기본값은 { thread: metadata.threadId ?? room name, resource: metadata.resourceId ?? thread }입니다. 비활성화하려면 false를 전달하고, 사용자 지정하려면 함수를 전달하세요. **toolFeedback** (`(toolCall) => string | undefined`): Mastra Agent가 응답 도중 Tool 호출을 시작할 때 호출됩니다. Tool이 실행되는 동안 말할 짧은 문구를 반환하세요. **onTurnComplete** (`(ctx: VoiceTurnCompleteContext) => void | Promise`): 응답이 텍스트 음성 변환으로 스트리밍을 마친 후 턴마다 한 번 호출됩니다. 오디오 경로 외부에서 실행되며 완료를 기다리지 않습니다. 컨텍스트에는 생성된 응답(text, toolCalls, interrupted, usage)과 확인된 Memory 매핑이 포함됩니다. **configuration** (`LiveKitWorkerConfiguration`): 그룹화된 대화 및 규정 준수 구성입니다. 시작 인사말과 AI 고지, 동의 요구 사항, Agent 주도 통화 종료, 통화별 STT/TTS 선택을 설정합니다. **configuration.greeting** (`GreetingConfiguration`): 시작 인사말과 AI 고지를 설정합니다. text(고정 문자열 또는 테넌트별 인사말을 위한 통화별 리졸버), allowInterruptions, awaitPlayout, persist와 repeatEvery 및 repeatText를 통한 주기적 재고지를 구성할 수 있습니다. **configuration.consentPolicy** (`ConsentConfiguration`): 명명된 요구 사항(summaryStorage로 시작)으로 지정하는 통화 동의 정책입니다. 선언 전용이며 작업자 자체는 아무것도 차단하지 않습니다. 런타임에 createConsentTool로 동의를 기록하고 자체 코드에서 적용하세요. 선언된 정책은 교차 확인할 수 있도록 onCallEnd에 제공됩니다. **configuration.endCall** (`EndCallConfiguration`): Agent 주도 통화 종료입니다. 작업자는 각 턴에서 통화 종료 Tool을 감시하고(createEndCallTool과 함께 사용), Agent의 마무리 말이 모두 재생될 때까지 기다린 후 연결을 끊으며, 종료 과정에서 onCallEnd를 실행합니다. **configuration.stt** (`(context: VoiceCallContext) => STT | string | undefined`): 통화별 음성 텍스트 변환입니다. 연결 후 통화마다 한 번 { metadata, requestContext, roomName, ctx }와 함께 호출되는 리졸버로, 최상위 stt 옵션이 허용하는 모든 값을 반환할 수 있습니다. 최상위 stt로 대체하려면 undefined를 반환하세요. 리졸버는 통화 설정 중 실행되므로 플러그인 인스턴스를 통화 간에 캐시하세요. **configuration.tts** (`(context: VoiceCallContext) => TTS | string | undefined`): 통화별 텍스트 음성 변환입니다. 연결 후 통화마다 한 번 { metadata, requestContext, roomName, ctx }와 함께 호출되는 리졸버로, 최상위 tts 옵션이 허용하는 모든 값을 반환하여 테넌트별로 하나의 음성 또는 언어를 지정할 수 있습니다. 최상위 tts로 대체하려면 undefined를 반환하세요. 플러그인 인스턴스를 통화 간에 캐시하세요. **greeting** (`string`): 세션이 시작될 때 말하는 정적 인사말입니다. 더 이상 권장되지 않습니다. 대신 configuration.greeting.text를 사용하세요. **persistGreeting** (`boolean`): 말한 인사말을 어시스턴트 메시지로 Memory 스레드에 저장하여 저장된 스레드가 통화 내용을 충실히 기록하도록 합니다. 인사말이 설정되고 Memory가 활성화된 경우에만 적용됩니다. 더 이상 권장되지 않습니다. 대신 configuration.greeting.persist를 사용하세요. (Default: `true`) **observability** (`boolean`): Mastra 인스턴스에 Observability가 구성되어 있으면 각 통화를 Trace합니다. 세션마다 voice call span을 엽니다. 각 턴의 Agent 실행은 그 아래에 중첩되고, LiveKit의 STT, TTS, 발화 종료, VAD, LLM 지연 시간 메트릭은 자식 span이 되며, Model별 사용량 집계와 함께 span이 닫힙니다. 비활성화하려면 false를 전달하세요. (Default: `true`) **inputOptions** (`Partial`): session.start()에 전달되는 LiveKit 룸 입력 옵션입니다. **outputOptions** (`Partial`): session.start()에 전달되는 LiveKit 룸 출력 옵션입니다. **onSessionStart** (`(args: { session, ctx, agent, metadata }) => void | Promise`): 세션이 시작된 후 호출됩니다. 여기에서 이벤트 리스너를 연결하거나 응답을 트리거하세요. ## `runLiveKitWorker()` 작업자 진입점 파일의 LiveKit 작업자 CLI(`dev`, `start`, `connect` 하위 명령)를 시작합니다. 작업자 정의를 기본 내보내기하는 파일에서 호출하고, 직접 실행될 때만 실행되도록 보호하세요. 작업자는 세션마다 동일한 파일을 다시 가져오는 자식 프로세스를 생성합니다. `@livekit/agents`의 `cli.runApp` 대신 이 헬퍼를 사용하면 작업자 런타임과 브리지가 하나의 LiveKit SDK 사본을 공유합니다. ### 옵션 **entry** (`string | URL`): 기본 내보내기가 Agent 정의인 작업자 진입점 모듈입니다. import.meta.url을 전달하세요. **agentName** (`string`): 명시적 디스패치에 사용할 LiveKit Agent 이름입니다. (Default: `'mastra-voice'`) **serverOptions** (`Partial`): 이 헬퍼가 구성한 옵션 위에 병합할 추가 LiveKit ServerOptions입니다. ## `pipeAgentReplyToWriter()` Mastra Agent의 응답을 Workflow 응답 경로의 `writer`로 스트리밍합니다. Agent의 텍스트 델타를 전달하므로 전체 응답이 준비되기 전에 텍스트 음성 변환이 시작되며, Tool 호출 청크도 전달하므로 `toolFeedback`이 실행되고 `onTurnComplete`에서 Tool 목록을 확인할 수 있습니다. `stream.textStream`만 파이프하면 Tool 호출이 아무런 알림 없이 누락됩니다. 끼어들기가 생성을 신속하게 중단하도록 단계의 `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 비동기 이터러블을 노출하는 모든 객체를 사용할 수 있습니다. **writer** (`WritableStream`): Workflow 단계의 writer입니다. ## `chatContextToMessages()` LiveKit 채팅 컨텍스트를 `agent.stream()`이 허용하는 일반 메시지로 변환하며, 지침과 함수 호출은 제외합니다. 상태 비저장 Workflow에 전체 대화 기록을 전달하려면 `workflowInput`에서 사용하세요. ```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 플러그인(`llm.LLM`)입니다. 직접 `voice.AgentSession`을 구성하면서 `llm` 슬롯에 Mastra를 사용하려는 경우 사용하세요. [`createLiveKitWorker()`](#createlivekitworker)는 관리형 대안입니다. 선택 방법은 [Mastra를 LLM 구성 요소로 사용하기](https://mastra.zisheng.pro/ko/guides/voice/realtime-voice)를 참조하세요. `remote`를 사용하면 플러그인은 Server-Sent Events(SSE)를 사용하는 HTTP를 통해 Mastra 서버에서 각 턴을 스트리밍합니다. Agent 루프, 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 } }, }) ``` 플러그인은 `provider`를 `mastra`로, `model`을 Agent ID로 보고하므로 LiveKit 메트릭과 대체 어댑터가 다른 LLM과 동일하게 이를 식별합니다. ### 생성자 옵션 `remote`, `agent`, `generate` 중 정확히 하나의 응답 소스를 제공하세요. **remote** (`RemoteMastraAgentOptions`): HTTP를 통해 연결하는 원격 Mastra 서버입니다. createRemoteAgentReplyGenerator()와 동일한 연결 옵션인 baseUrl, agentId, apiPrefix, headers, fetch, timeoutMs, retries, body를 사용합니다. **agent** (`Agent`): 프로세스 내 Mastra Agent입니다. 별도의 배포 없이 세션을 소유합니다. **generate** (`VoiceReplyGenerator`): 사용자 정의 응답 소스입니다. generate 소스는 자체 훅을 사용합니다. 아래의 toolFeedback, onToolCall, onTurnComplete는 remote 및 agent 소스에만 적용됩니다. **memory** (`{ thread: string; resource?: string } | false`): 통화별로 결정되는 대화 영속성 설정입니다(예: SIP 발신자 ID에서 결정). 설정하면 Agent가 마지막으로 응답한 이후의 새 메시지만 각 턴에 전송되고 Mastra Memory가 기록을 제공합니다. 생략하면 각 턴에 전체 LiveKit 채팅 컨텍스트가 전송됩니다. (Default: `false`) **requestContext** (`RequestContext | Record`): 생성에 전달되는 요청 컨텍스트입니다(테넌트, 수신 번호 등). **toolFeedback** (`(toolCall: VoiceToolCall) => string | undefined`): 서버 측 Tool이 실행되는 동안 말할 짧은 문구를 반환합니다. **onToolCall** (`(toolCall: VoiceToolCall) => void`): 스트리밍 도중 각 Tool 호출이 시작될 때 호출됩니다. 자체 Agent 주도 통화 종료 흐름을 구현하려면 runEndCall()과 함께 사용하세요. **onTurnComplete** (`(ctx: VoiceTurnCompleteContext) => void | Promise`): 응답이 스트리밍을 마친 후 턴마다 한 번 호출되며, 오디오 경로 외부에서 실행되고 완료를 기다리지 않습니다. 컨텍스트에는 생성된 응답의 text, toolCalls, interrupted, usage가 포함됩니다. > **경고:** `memory`를 세션의 `preemptiveGeneration` 옵션과 함께 사용하지 마세요. 직접 구성한 세션에서는 LiveKit이 이 옵션을 기본적으로 활성화합니다. LiveKit이 선제 턴을 폐기하기 전에 해당 턴이 완료되면 사용자 메시지와 실제로 말하지 않은 응답이 스레드에 저장됩니다. 세션에서 `turnHandling: { preemptiveGeneration: { enabled: false } }`를 설정하세요. 상태 비저장 모드(`memory` 없음)는 선제 생성과 함께 사용할 수 있습니다. ### Mastra Agent에서 실행되는 Tool Tool은 Mastra Agent에서 서버 측에 정의되고 실행됩니다. 플러그인은 LiveKit Tool 정의를 전달하지 않습니다. 세션에서 비어 있지 않은 `toolCtx`를 전달하면 무시된 Tool 이름을 포함한 경고를 한 번 기록합니다. 모든 Tool은 서버 측에서 완료되어야 합니다. 승인 또는 클라이언트 측 실행이 필요한 Tool은 통화를 멈춘 채 대기하는 대신 설명이 포함된 오류와 함께 턴을 실패시킵니다. Tool 활동은 `toolFeedback`, `onToolCall`, `onTurnComplete`를 통해 작업자에 전달됩니다. ### 지침 LiveKit은 `voice.Agent`의 `instructions`를 모든 요청의 채팅 컨텍스트에 삽입합니다. 서버 측 Mastra Agent 자체의 지침이 우선하므로 플러그인은 이를 제거합니다. Prompt를 변경하려면 Mastra Agent를 변경하세요. ### 중단된 회전 사용자가 답장을 중단하는 경우: 1. 플러그인이 스트림을 취소합니다. 서버는 생성을 중단하고 해당 턴부터 아무것도 지속하지 않습니다. 2. LiveKit은 사용자가 채팅 컨텍스트에서 실제로 들었던 부분을 녹음하고 중단된 것으로 표시됩니다. 3. 다음 차례에 플러그인은 새 사용자 메시지 이전에 주문된 청취 전용 조각을 다시 전송하므로 Memory 스레드가 호출과 일치하도록 다시 채워집니다. 메시지는 LiveKit의 메시지 ID를 전달하고 서버는 ID별로 중복을 제거하므로 재시도 및 재전송은 멱등성을 유지합니다. 중단 후 즉시 전화를 끊은 사용자는 마지막 부분을 녹음하지 않은 상태로 둡니다. 기록에서 캡처해야 하는 경우 세션 이벤트에서 즉시 조정합니다. 공유 메시지 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(), }, ], }) }) ``` ### 사용량 측정항목 서버가 턴의 토큰 사용량을 보고하면 플러그인이 이를 LiveKit에 제공하므로 세션의 `metrics_collected` 이벤트에 다른 LLM 플러그인과 마찬가지로 첫 토큰까지의 시간, 지속 시간, 토큰 수가 포함됩니다. 동일한 사용량 객체(`promptTokens`, `completionTokens`, `promptCachedTokens`, `totalTokens`)가 `onTurnComplete`의 `result.usage`로 전달됩니다. ### 오류 및 시간 초과 전송 과정에서는 LiveKit의 `APIError` 유형(`APIStatusError`, `APIConnectionError`, `APITimeoutError`)을 발생시키므로 세션의 재시도 정책(`connOptions.maxRetry`)과 `FallbackAdapter` 장애 조치는 변경 없이 작동합니다. 첫 번째 토큰 이후에는 턴을 재시도하지 않습니다. 음성 응답은 일부만 들린 상태로 다시 재생하는 것보다 빠르게 실패하는 편이 낫습니다. 연결 및 첫 토큰 감시는 세션의 `connOptions.timeoutMs`(기본값 10초)를 사용하므로 연결을 수락한 뒤 스트리밍하지 않는 서버로 인해 무음 상태가 무기한 지속되지 않습니다. Mastra 서버가 통화 중에 다운되면 각 응답 시도는 재시도 후 입력된 오류와 함께 실패하며, LiveKit은 여러 번 연속 실패한 응답 후에 세션을 닫습니다. 예산이 소진되기 전에 서버를 복원하고 다음 차례에 통화가 복구됩니다. ### 메시지 내용 메시지 추출은 텍스트 전용입니다. 이미지 콘텐츠는 삭제되고 오디오 콘텐츠는 해당 내용을 통해서만 포함됩니다. 음성 파이프라인은 영향을 받지 않지만 채팅 컨텍스트에 직접 삽입하는 항목에는 텍스트가 포함되어야 합니다. ## `createRemoteAgentReplyGenerator()` HTTP/SSE를 통해 **remote** Mastra 서버에서 Agent 루프를 실행하는 응답 생성기를 구성합니다. `MastraLLM`의 `remote` 모드가 내부적으로 이를 사용합니다. 모든 기능이 포함된 작업자를 원격 서버와 함께 실행하려면 `createLiveKitWorker`의 `generate` 옵션을 통해 직접 사용하세요. ```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` 경로에서는 작업자 수준의 `toolFeedback` 및 `onTurnComplete` 옵션이 적용되지 않으며, 작업자의 통화 종료 감지도 실행되지 않습니다. 대신 생성기에 훅을 전달하세요. 턴(참여)을 취소하면 HTTP 요청이 중단되어 서버 측 생성도 중단됩니다. 오류는 LiveKit `APIError` 유형으로 발생합니다. `retries` 옵션은 최초 연결 시도에만 적용됩니다. 첫 번째 청크 이후에는 턴을 재시도하지 않습니다. 보고:`VoiceReplyGenerator`. ### 옵션 **baseUrl** (`string`): 원격 Mastra 서버의 기본 URL입니다(예: https\://my-app.example.com). **agentId** (`string`): 원격 Mastra 인스턴스에 등록된 Agent 키 또는 ID입니다. **apiPrefix** (`string`): Mastra API의 경로 접두사입니다. (Default: `'/api'`) **headers** (`Record | () => Record | Promise>`): 정적 헤더 또는 턴마다 호출되는 리졸버입니다. 예를 들어 새로운 인증 토큰을 발급할 때 사용할 수 있습니다. **fetch** (`typeof fetch`): 테스트 또는 프록시에 주입할 수 있는 fetch 구현입니다. (Default: `globalThis.fetch`) **timeoutMs** (`number`): 연결 및 첫 토큰 제한 시간(밀리초)입니다. MastraLLM을 통해 사용할 때는 대신 세션의 connOptions.timeoutMs가 기본값입니다. (Default: `10000`) **retries** (`number`): 첫 번째 청크를 받기 전에만 수행하는 최초 연결 재시도 횟수입니다. MastraLLM을 통해 사용할 때는 LiveKit 세션이 재시도를 관리하므로 이 값은 0으로 강제됩니다. (Default: `2`) **body** (`Record`): 각 스트림 요청 본문에 병합할 추가 필드입니다. **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 발신자를 포함한 발신자의 통화를 종료합니다. 등록된 콜백과 함께 작업이 종료됩니다. 소유한 세션에서 Agent 주도 통화 종료를 다시 구성하려면 서버 측 Agent의 [통화 종료 Tool](#createendcalltool) 및 [`MastraLLM`](#mastrallm)의 `onToolCall`과 함께 사용하세요. ```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 작업 컨텍스트입니다. **config** (`{ message?: string; reason?: string; maxWaitMs?: number; drainMs?: number }`): 통화 종료 전에 말할 선택적 최종 메시지, 기록할 종료 사유, 마무리 말을 기다리는 시간의 안전 제한, 그리고 룸을 삭제하기 전에 발신자 측 버퍼에 있는 오디오의 재생을 마칠 수 있도록 하는 재생 후 배출 시간(기본값 800ms)입니다. LiveKit의 재생 집계는 작업자 내부에서만 이루어지므로 완료되는 즉시 통화를 종료하면 작별 인사가 잘릴 수 있습니다. **logger** (`{ warn: (message: string, ...args: unknown[]) => void }`): 종료 단계가 실패할 때 경고를 받습니다. 사용 중인 로거 또는 console을 전달하세요. ## `createEndCallTool()` Agent가 통화를 종료하려고 할 때 호출하는 Mastra Tool을 구축합니다. 이 Tool은 의도를 알리고 선택적 장부를 실행할 수 있습니다. 작업자가 실제 전화 끊기를 수행합니다. 이 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: {} }`을 설정하면 작업자가 Tool을 감시하고 통화를 종료합니다. 소유한 세션에서는 [`runEndCall()`](#runendcall)을 사용해 통화 종료를 다시 구성하세요. ### 옵션 **id** (`string`): Agent가 통화를 종료하기 위해 호출하는 Tool ID입니다. 작업자가 감시하는 이름(작업자의 configuration.endCall.tool 또는 자체 onToolCall 검사)과 일치해야 합니다. (Default: `'endCall'`) **description** (`string`): Tool 호출 여부를 결정할 때 Model에 표시되는 설명을 재정의합니다. **onEndCall** (`(request: { reason?: string; resourceId?: string; threadId?: string }) => void | Promise`): Agent가 Tool을 호출할 때 실행되는 기록 관리 훅입니다. 사유를 기록하거나 통화가 해결되었음을 표시할 수 있습니다. 턴 내부에서 실행되므로 신속하게 처리하세요. 이 훅 자체는 통화를 종료하지 않습니다. ## `liveKitConnectionRoute()` 음성 Agent가 룸에 디스패치된 LiveKit 액세스 토큰을 발급하는 [API 경로](https://mastra.zisheng.pro/ko/docs/server/custom-api-routes)를 반환합니다. 프런트엔드가 이를 호출해 세션에 참여합니다. ```typescript import { Mastra } from '@mastra/core/mastra' import { liveKitConnectionRoute } from '@mastra/livekit' export const mastra = new Mastra({ server: { apiRoutes: [liveKitConnectionRoute({ agentName: 'mastra-voice' })], }, }) ``` 경로는 선택적 `agentId`, `threadId`, `resourceId` 필드가 포함된 JSON 본문을 허용하고 `{ serverUrl, roomName, participantName, participantToken }`으로 응답합니다. `threadId`의 기본값은 생성된 룸 이름입니다. ### 옵션 **path** (`string`): 경로입니다. (Default: `'/voice/livekit/connection-details'`) **serverUrl** (`string`): LiveKit 서버 URL입니다. (Default: `process.env.LIVEKIT_URL`) **apiKey** (`string`): LiveKit API 키입니다. (Default: `process.env.LIVEKIT_API_KEY`) **apiSecret** (`string`): LiveKit API 비밀 키입니다. (Default: `process.env.LIVEKIT_API_SECRET`) **agentName** (`string`): 명시적 디스패치에 사용할 LiveKit Agent 이름입니다. 작업자의 agentName과 일치해야 합니다. (Default: `'mastra-voice'`) **ttl** (`string | number`): 토큰 유효 기간입니다. (Default: `'15m'`) **requiresAuth** (`boolean`): 경로에 인증이 필요한지 여부입니다. (Default: `true`) **roomName** (`string | (args) => string`): 룸 이름 또는 요청에서 룸 이름을 생성하는 함수입니다. **participantIdentity** (`string | (args) => string`): 참가자 ID 또는 요청에서 참가자 ID를 생성하는 함수입니다. **metadata** (`(args) => LiveKitSessionMetadata | Promise`): 작업자에 전달할 세션 메타데이터를 구성합니다. 기본적으로 요청 본문의 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`): 작업자의 agentName과 일치해야 합니다. (Default: `'mastra-voice'`) **metadata** (`LiveKitSessionMetadata`): 세션 메타데이터인 agentId, threadId, resourceId, requestContext입니다. **serverUrl** (`string`): LiveKit 서버 URL입니다. (Default: `process.env.LIVEKIT_URL`) **apiKey** (`string`): LiveKit API 키입니다. (Default: `process.env.LIVEKIT_API_KEY`) **apiSecret** (`string`): LiveKit API 비밀 키입니다. (Default: `process.env.LIVEKIT_API_SECRET`) ## `LiveKitSessionMetadata` LiveKit 작업 디스패치를 ​​통해 Mastra 서버에서 작업자로 전달되는 메타데이터입니다. **agentId** (`string`): 등록된 키 또는 Agent ID로 실행할 Mastra Agent입니다. **threadId** (`string`): Memory 스레드 ID입니다. 기본값은 LiveKit 룸 이름입니다. **resourceId** (`string`): Memory 리소스 ID이며, 일반적으로 최종 사용자 ID를 사용합니다. **requestContext** (`Record`): Agent 실행을 위해 RequestContext에 복원되는 일반 객체 항목입니다. 메타데이터는 JSON 문자열로 전달됩니다. `liveKitConnectionRoute()`와 `dispatchVoiceSession()`은 이를 자동으로 직렬화합니다. 자체 코드로 디스패치할 때는 `serializeSessionMetadata(metadata)`를 사용하거나, SIP 디스패치 규칙 같은 LiveKit 측 구성에 JSON을 직접 작성하세요. `requestContext` 항목은 통화의 모든 턴에서 Agent의 런타임 정의 지침, Tool, 입력 프로세서에 전달됩니다. ## 관련된 - [실시간 음성](https://mastra.zisheng.pro/ko/guides/voice/realtime-voice) - [LiveKit Agent 문서](https://docs.livekit.io/agents/)