1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[37214],{37214:function(e,t,n){let o,a;n.d(t,{Conversation:function(){return en}});class i{queue=[];disconnectionDetails=null;onDisconnectCallback=null;onMessageCallback=null;onModeChangeCallback=null;onDebug;constructor(e={}){this.onDebug=e.onDebug}debug(e){this.onDebug&&this.onDebug(e)}onMessage(e){this.onMessageCallback=e;let t=this.queue;this.queue=[],t.length>0&&queueMicrotask(()=>{t.forEach(e)})}onDisconnect(e){this.onDisconnectCallback=e;let t=this.disconnectionDetails;t&&queueMicrotask(()=>{e(t)})}onModeChange(e){this.onModeChangeCallback=e}updateMode(e){this.onModeChangeCallback?.(e)}disconnect(e){this.disconnectionDetails||(this.disconnectionDetails=e,this.onDisconnectCallback?.(e))}handleMessage(e){this.onMessageCallback?this.onMessageCallback(e):this.queue.push(e)}}function s(e){let[t,n]=e.split("_");if(!["pcm","ulaw"].includes(t))throw Error(`Invalid format: ${e}`);let o=Number.parseInt(n);if(Number.isNaN(o))throw Error(`Invalid sample rate: ${n}`);return{format:t,sampleRate:o}}function r(e){return null!=e&&"object"==typeof e&&!Array.isArray(e)}async function l(e){try{let t=await e.json();if(!r(t))return e.statusText||"Unknown error";let n=t.detail,o=r(n)?n.message:n;if("string"==typeof o)return o}catch(e){console.warn("Failed to parse API error response as JSON:",e)}return e.statusText||"Unknown error"}class c extends Error{closeCode;closeReason;constructor(e,t){super(e),this.name="SessionConnectionError",this.closeCode=t?.closeCode,this.closeReason=t?.closeReason}}let u=Object.freeze({name:"js_sdk",version:"1.17.0"});function d(e){return!!e.type}var h,p,m,g,f,v,y=n(66963);let _="conversation_initiation_client_data";function w(e){let t={type:_};return e.overrides&&(t.conversation_config_override={agent:{prompt:e.overrides.agent?.prompt,first_message:e.overrides.agent?.firstMessage,language:e.overrides.agent?.language},tts:{voice_id:e.overrides.tts?.voiceId,speed:e.overrides.tts?.speed,stability:e.overrides.tts?.stability,similarity_boost:e.overrides.tts?.similarityBoost},...e.overrides.asr?.keywords!==void 0?{asr:{keywords:e.overrides.asr.keywords}}:{},conversation:{text_only:e.overrides.conversation?.textOnly}}),e.customLlmExtraBody&&(t.custom_llm_extra_body=e.customLlmExtraBody),e.dynamicVariables&&(t.dynamic_variables=e.dynamicVariables),e.userId&&(t.user_id=e.userId),t.source_info={source:u.name,version:u.version},e.toolMockConfig&&(t.tool_mock_config={mocking_strategy:e.toolMockConfig.mockingStrategy,mocked_tool_names:e.toolMockConfig.mockedToolNames,fallback_strategy:e.toolMockConfig.fallbackStrategy}),t}function C(e){return btoa(String.fromCharCode(...new Uint8Array(e)))}let b={getVolume:()=>0,getByteFrequencyData:()=>{}};function A(e,t,n){let o=e.length,a=n/2/o,i=Math.floor(100/a),s=Math.min(Math.ceil(8e3/a),o),r=s-i,l=t.length;for(let n=0;n<l;n++){let o=n/l*r,a=i+Math.floor(o),c=Math.min(a+1,s-1),u=o-Math.floor(o);t[n]=Math.round(e[a]*(1-u)+e[c]*u)}}class S extends i{conversationId;inputFormat;outputFormat;room;isConnected=!1;audioEventId=1;outputDeviceId=null;audioAdapter;inputAnalyser=void 0;inputVolumeProvider=b;outputAnalyser=void 0;outputVolumeProvider=b;_isMuted=!1;input={close:async()=>{if(this.isConnected)try{this.room.localParticipant.audioTrackPublications.forEach(e=>{e.track&&e.track.stop()})}catch(e){console.warn("Error stopping local tracks:",e)}},setDevice:async e=>{if(e?.sampleRate!==void 0||e?.format!==void 0||e?.preferHeadphonesForIosDevices!==void 0)throw Error("WebRTC input device does not support sampleRate, format, or preferHeadphonesForIosDevices options");let t=e?.inputDeviceId;t&&await this.setAudioInputDevice(t)},setMuted:async e=>{if(!this.isConnected||!this.room.localParticipant){console.warn("Cannot set microphone muted: room not connected or no local participant");return}this._isMuted=e;let t=this.room.localParticipant.getTrackPublication(y.fQ.Source.Microphone);if(t?.track)try{e?await t.track.mute():await t.track.unmute()}catch(t){await this.room.localParticipant.setMicrophoneEnabled(!e)}else await this.room.localParticipant.setMicrophoneEnabled(!e);if(!e){let e=this.room.localParticipant.getTrackPublication(y.fQ.Source.Microphone)?.track;e&&this.setupInputAnalyser(e.mediaStreamTrack)}},isMuted:()=>this._isMuted,getAnalyser:()=>this.inputAnalyser,getVolume:()=>this._isMuted?0:this.inputVolumeProvider.getVolume(),getByteFrequencyData:e=>{if(this._isMuted){e.fill(0);return}this.inputVolumeProvider.getByteFrequencyData(e)}};output={close:async()=>{},setDevice:async e=>{if(e?.sampleRate!==void 0||e?.format!==void 0)throw Error("WebRTC output device does not support sampleRate or format options");let t=e?.outputDeviceId;t&&await this.setAudioOutputDevice(t)},setVolume:e=>{this.setAudioVolume(e)},interrupt:e=>{},getAnalyser:()=>this.outputAnalyser,getVolume:()=>this.outputVolumeProvider.getVolume(),getByteFrequencyData:e=>{this.outputVolumeProvider.getByteFrequencyData(e)}};constructor(e,t,n,a,i={}){super(i),this.room=e,this.conversationId=t,this.inputFormat=n,this.outputFormat=a,this.audioAdapter=o?.()??null,this.setupRoomEventListeners()}static async create(e){let t;if("conversationToken"in e&&e.conversationToken)t=e.conversationToken;else if("agentId"in e&&e.agentId)try{let{name:n,version:o}=u,a=(e.origin??"https://api.elevenlabs.io").replace(/^wss:\/\//,"https://"),i=`${a}/v1/convai/conversation/token?agent_id=${e.agentId}&source=${n}&version=${o}`;e.environment&&(i+=`&environment=${encodeURIComponent(e.environment)}`);let s=await fetch(i);if(!s.ok){let e=await l(s);throw Error(`ElevenLabs API returned ${s.status} ${e}`)}let c=await s.json();if(!r(c)||"string"!=typeof c.token||!(t=c.token))throw Error("No conversation token received from API")}catch(n){let t=n instanceof Error?n.message:String(n);throw n instanceof Error&&n.message.includes("401")&&(t="Your agent has authentication enabled, but no signed URL or conversation token was provided."),Error(`Failed to fetch conversation token for agent ${e.agentId}: ${t}`)}else throw Error("Either conversationToken or agentId is required for WebRTC connection");let n=new y.du({singlePeerConnection:!1});try{let o=`room_${Date.now()}
1`,a=s("pcm_48000"),i=s("pcm_48000"),r=new S(n,o,a,i,e),l=e.livekitUrl||"wss://livekit.rtc.elevenlabs.io",c=e.textOnly?Promise.resolve():new Promise((e,t)=>{n.once(y.TQ.SignalConnected,()=>{n.localParticipant.setMicrophoneEnabled(!0).then(()=>e()).catch(t)})});await n.connect(l,t),await new Promise(e=>{if(r.isConnected)e();else{let t=()=>{n.off(y.TQ.Connected,t),e()};n.on(y.TQ.Connected,t)}}),await c;let u=n.localParticipant.getTrackPublication(y.fQ.Source.Microphone)?.track;u&&r.setupInputAnalyser(u.mediaStreamTrack),n.name&&(r.conversationId=n.name.match(/(conv_[a-zA-Z0-9]+)/)?.[0]||n.name);let d=w(e);return r.debug({type:_,message:d}),await r.sendMessage(d),r}catch(e){throw await n.disconnect(),e}}setupRoomEventListeners(){this.room.on(y.TQ.Connected,()=>{this.isConnected=!0}),this.room.on(y.TQ.Disconnected,e=>{this.isConnected=!1,this.disconnect({reason:"agent",context:{type:"close",reason:e?.toString()}})}),this.room.on(y.TQ.ConnectionStateChanged,e=>{e===y.em.Disconnected&&(this.isConnected=!1,this.disconnect({reason:"error",message:`LiveKit connection state changed to ${e}`,context:{type:"connection_state_changed"}}))}),this.room.on(y.TQ.DataReceived,(e,t)=>{try{let t=JSON.parse(new TextDecoder().decode(e));if("audio"===t.type){d(t)&&this.handleMessage(t);return}d(t)?this.handleMessage(t):console.warn("Invalid socket event received:",t)}catch(t){console.warn("Failed to parse incoming data message:",t),console.warn("Raw payload:",new TextDecoder().decode(e))}}),this.room.on(y.TQ.TrackSubscribed,async(e,t,n)=>{e.kind===y.fQ.Kind.Audio&&n.identity.includes("agent")&&this.audioAdapter&&(await this.audioAdapter.attachRemoteTrack(e,this.outputDeviceId),await this.setupAudioCapture(e),this.onDebug?.({type:"audio_element_ready"}))}),this.room.on(y.TQ.ActiveSpeakersChanged,async e=>{e.length>0?this.updateMode(e[0].identity.startsWith("agent")?"speaking":"listening"):this.updateMode("listening")}),this.room.on(y.TQ.ParticipantDisconnected,e=>{e.identity?.startsWith("agent")&&this.disconnect({reason:"agent",context:{type:"close",reason:"agent disconnected"}})})}close(){if(this.isConnected){try{this.room.localParticipant.audioTrackPublications.forEach(e=>{e.track&&e.track.stop()})}catch(e){console.warn("Error stopping local tracks:",e)}this.audioAdapter?.cleanup(),this.inputAnalyser=void 0,this.outputAnalyser=void 0,this.inputVolumeProvider=b,this.outputVolumeProvider=b,this.room.disconnect()}}async sendMessage(e){if(!this.isConnected||!this.room.localParticipant){console.warn("Cannot send message: room not connected or no local participant");return}if(!("user_audio_chunk"in e))try{let t=new TextEncoder().encode(JSON.stringify(e));await this.room.localParticipant.publishData(t,{reliable:!0})}catch(t){this.debug({type:"send_message_error",message:{message:e,error:t}}),console.error("Failed to send message via WebRTC:",t)}}getRoom(){return this.room}setupInputAnalyser(e){if(this.audioAdapter)try{let t=this.audioAdapter.setupInputAnalysis(e);this.inputVolumeProvider=t.volumeProvider,this.inputAnalyser=t.analyser}catch(e){console.warn("[ConversationalAI] Failed to set up input volume analyser:",e)}}setInputVolumeProvider(e){this.inputVolumeProvider=e}setOutputVolumeProvider(e){this.outputVolumeProvider=e}async setupAudioCapture(e){if(this.audioAdapter)try{let t=await this.audioAdapter.setupOutputAnalysis(e,this.outputFormat,(e,t)=>{if(t>.01){let t=C(e),n=this.audioEventId++;this.handleMessage({type:"audio",audio_event:{audio_base_64:t,event_id:n}})}});this.outputVolumeProvider=t.volumeProvider,this.outputAnalyser=t.analyser}catch(e){console.warn("Failed to set up audio capture:",e)}}setAudioVolume(e){this.audioAdapter?.setVolume(e)}async setAudioOutputDevice(e){if(!this.audioAdapter)throw Error("Cannot set output device: no audio adapter available on this platform");await this.audioAdapter.setOutputDevice(e),this.outputDeviceId=e}async setAudioInputDevice(e){if(!this.isConnected||!this.room.localParticipant)throw Error("Cannot change input device: room not connected or no local participant");try{let t=this.room.localParticipant.getTrackPublication(y.fQ.Source.Microphone);t?.track&&(await t.track.stop(),await this.room.localParticipant.unpublishTrack(t.track));let n=await (0,y.s1)({deviceId:{exact:e},echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,channelCount:{ideal:1}});await this.room.localParticipant.publishTrack(n,{name:"microphone",source:y.fQ.Source.Microphone}),this.setupInputAnalyser(n.mediaStreamTrack)}catch(e){console.error("Failed to change input device:",e);try{await this.room.localParticipant.setMicrophoneEnabled(!0)}catch(e){console.error("Failed to recover microphone after device switch error:",e)}throw e}}}let k=new Map;function E(e,t){return async(n,o)=>{let a=k.get(e);if(a)return n.addModule(a);if(o)try{await n.addModule(o),k.set(e,o);return}catch(t){throw Error(`Failed to load the ${e} worklet module from path: ${o}. Error: ${t}`)}let i=new Blob([t],{type:"application/javascript"}),s=URL.createObjectURL(i);try{await n.addModule(s),k.set(e,s);return}catch{URL.revokeObjectURL(s)}try{let o=btoa(t),a=`data:application/javascript;base64,${o}`;await n.addModule(a),k.set(e,a)}catch(t){throw Error(`Failed to load the ${e} worklet module. Make sure the browser supports AudioWorklets. If you are using a strict CSP, you may
1need to self-host the worklet files.`)}}}let M=E("audioConcatProcessor",`/* 2 * ulaw decoding logic taken from the wavefile library 3 * https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js 4 * USED BY @elevenlabs/client 5 */ 6 7const decodeTable = [0, 132, 396, 924, 1980, 4092, 8316, 16764]; 8 9function decodeSample(muLawSample) { 10 let sign; 11 let exponent; 12 let mantissa; 13 let sample; 14 muLawSample = ~muLawSample; 15 sign = muLawSample & 0x80; 16 exponent = (muLawSample >> 4) & 0x07; 17 mantissa = muLawSample & 0x0f; 18 sample = decodeTable[exponent] + (mantissa << (exponent + 3)); 19 if (sign !== 0) sample = -sample; 20 21 return sample; 22} 23 24class AudioConcatProcessor extends AudioWorkletProcessor { 25 constructor() { 26 super(); 27 this.buffers = []; // Initialize an empty buffer 28 this.cursor = 0; 29 this.currentBuffer = null; 30 this.wasInterrupted = false; 31 this.finished = false; 32 33 this.port.onmessage = ({ data }) => { 34 switch (data.type) { 35 case "setFormat": 36 this.format = data.format; 37 if (globalThis.LibSampleRate && sampleRate !== data.sampleRate) { 38 globalThis.LibSampleRate.create( 39 1, 40 data.sampleRate, 41 sampleRate 42 ).then(resampler => { 43 this.resampler = resampler; 44 }); 45 } 46 break; 47 case "buffer": 48 this.wasInterrupted = false; 49 this.buffers.push( 50 this.format === "ulaw" 51 ? new Uint8Array(data.buffer) 52 : new Int16Array(data.buffer) 53 ); 54 break; 55 case "interrupt": 56 this.wasInterrupted = true; 57 break; 58 case "clearInterrupted": 59 if (this.wasInterrupted) { 60 this.wasInterrupted = false; 61 this.buffers = []; 62 this.currentBuffer = null; 63 } 64 } 65 }; 66 } 67 process(_, outputs) { 68 let finished = false; 69 const output = outputs[0][0]; 70 for (let i = 0; i < output.length; i++) { 71 if (!this.currentBuffer) { 72 if (this.buffers.length === 0) { 73 finished = true; 74 break; 75 } 76 this.currentBuffer = this.buffers.shift(); 77 if (this.resampler) { 78 this.currentBuffer = this.resampler.full(this.currentBuffer); 79 } 80 this.cursor = 0; 81 } 82 83 let value = this.currentBuffer[this.cursor]; 84 if (this.format === "ulaw") { 85 value = decodeSample(value); 86 } 87 output[i] = value / 32768; 88 this.cursor++; 89 90 if (this.cursor >= this.currentBuffer.length) { 91 this.currentBuffer = null; 92 } 93 } 94 95 if (this.finished !== finished) { 96 this.finished = finished; 97 this.port.postMessage({ type: "process", finished }); 98 } 99 100 return true; // Continue processing 101 } 102} 103 104registerProcessor("audioConcatProcessor", AudioConcatProcessor); 105`);async function T(e,t){await e.audioWorklet.addModule(t||"https://cdn.jsdelivr.net/npm/@alexanderolsen/[email protected]/dist/libsamplerate.worklet.js")}function I(e,t){let n,o;let a=e.frequencyBinCount;return{getVolume:()=>(n??=new Uint8Array(a),o??=new Uint8Array(a),e.getByteFrequencyData(n),A(n,o,t),function(e){if(0===e.length)return 0;let t=0;for(let n=0;n<e.length;n++)t+=e[n]/255;return(t/=e.length)<0?0:t>1?1:t}(o)),getByteFrequencyData(o){n??=new Uint8Array(a),e.getByteFrequencyData(n),A(n,o,t)}}}function D(){return["iPad Simulator","iPhone Simulator","iPod Simulator","iPad","iPhone","iPod"].includes(navigator.platform)||navigator.userAgent.includes("Mac")&&"ontouchend"in document}class P{context;analyser;gain;worklet;audioElement;static async create({sampleRate:e,format:t,outputDeviceId:n,workletPaths:o,libsampleratePath:a,audioContext:i}){let s=i??null,r=null;try{let i=navigator.mediaDevices.getSupportedConstraints().sampleRate;s||(s=new AudioContext(i?{sampleRate:e}:{}));let l=s.createAnalyser(),c=s.createGain();(r=new Audio).src="",r.load(),r.autoplay=!0,r.style.display="none",document.body.appendChild(r);let u=s.createMediaStreamDestination();r.srcObject=u.stream,c.connect(l),l.connect(u),i&&s.sampleRate===e||(s.sampleRate!==e&&console.warn(`[ConversationalAI] Sample rate ${e} not available, resampling to ${s.sampleRate}`),await T(s,a)),await M(s.audioWorklet,o?.audioConcatProcessor);let d=new AudioWorkletNode(s,"audioConcatProcessor");return d.port.postMessage({type:"setFormat",format:t,sampleRate:e}),d.connect(c),await s.resume(),!function({sampleRate:e,format:t,worklet:n,audioElement:o}){if(!D())return;let a=Math.floor(100*e/1e3),i="ulaw"===t?new Uint8Array(a).fill(255):new Int16Array(a);n.port.postMessage({type:"buffer",buffer:i.buffer}),o.play().catch(()=>{})}({sampleRate:e,format:t,worklet:d,audioElement:r}),n&&r.setSinkId&&await r.setSinkId(n),new P(s,l,c,d,r)}catch(e){throw r?.parentNode&&r.parentNode.removeChild(r),r?.pause(),s&&"closed"!==s.state&&await s.close(),e}}volume=1;interrupted=!1;interruptTimeout=null;volumeProvider;constructor(e,t,n,o,a){this.context=e,this.analyser=t,this.gain=n,this.worklet=o,this.audioElement=a,this.worklet.port.start(),this.volumeProvider=I(t,e.sampleRate)}getAnalyser(){return this.analyser}getVolume(){return this.volumeProvider.getVolume()}getByteFrequencyData(e){this.volumeProvider.getByteFrequencyData(e)}addListener(e){this.worklet.port.addEventListener("message",e)}removeListener(e){this.worklet.port.removeEventListener("message",e)}setVolume(e){this.volume=e,this.gain.gain.value=e}playAudio(e){this.gain.gain.cancelScheduledValues(this.context.currentTime),this.gain.gain.value=this.volume,this.interruptTimeout&&(clearTimeout(this.interruptTimeout),this.interruptTimeout=null),this.worklet.port.postMessage({type:"clearInterrupted"}),this.worklet.port.postMessage({type:"buffer",buffer:e})}interrupt(e=2e3){this.interrupted=!0,this.interruptTimeout&&(clearTimeout(this.interruptTimeout),this.interruptTimeout=null),this.worklet.port.postMessage({type:"interrupt"}),this.gain.gain.exponentialRampToValueAtTime(1e-4,this.context.currentTime+e/1e3),this.interruptTimeout=setTimeout(()=>{this.interrupted=!1,this.gain.gain.value=this.volume,this.worklet.port.postMessage({type:"clearInterrupted"}),this.interruptTimeout=null},e)}async setDevice(e){if(!("setSinkId"in HTMLAudioElement.prototype))throw Error("setSinkId is not supported in this browser");let t=e?.outputDeviceId;await this.audioElement.setSinkId(t||"")}async close(){this.interruptTimeout&&(clearTimeout(this.interruptTimeout),this.interruptTimeout=null),this.audioElement.parentNode&&this.audioElement.parentNode.removeChild(this.audioElement),this.audioElement.pause(),await this.context.close()}}let R=E("rawAudioProcessor",`/* 106 * ulaw encoding logic taken from the wavefile library 107 * https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js 108 * USED BY @elevenlabs/client 109 */ 110 111const BIAS = 0x84; 112const CLIP = 32635; 113const encodeTable = [ 114 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 115 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 116 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 117 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 118 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 119 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 120 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 121 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 122 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 123 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 124 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 125 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 126 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 127 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 128 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 129 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 130]; 131 132function encodeSample(sample) { 133 let sign; 134 let exponent; 135 let mantissa; 136 let muLawSample; 137 sign = (sample >> 8) & 0x80; 138 if (sign !== 0) sample = -sample; 139 sample = sample + BIAS; 140 if (sample > CLIP) sample = CLIP; 141 exponent = encodeTable[(sample>>7) & 0xFF]; 142 mantissa = (sample >> (exponent+3)) & 0x0F; 143 muLawSample = ~(sign | (exponent << 4) | mantissa); 144 145 return muLawSample; 146} 147 148class RawAudioProcessor extends AudioWorkletProcessor { 149 constructor() { 150 super(); 151 152 this.port.onmessage = ({ data }) => { 153 switch (data.type) { 154 case "setFormat": 155 this.isMuted = false;
156 this.buffer = []; // Initialize an empty buffer 157 const chunkDurationMs = data.chunkDurationMs ?? 25; 158 this.bufferSize = Math.max( 159 1, 160 Math.round((data.sampleRate * chunkDurationMs) / 1000) 161 ); 162 this.format = data.format; 163 164 if (globalThis.LibSampleRate && sampleRate !== data.sampleRate) { 165 globalThis.LibSampleRate.create(1, sampleRate, data.sampleRate).then(resampler => { 166 this.resampler = resampler; 167 }); 168 } 169 break; 170 case "setMuted": 171 this.isMuted = data.isMuted; 172 break; 173 } 174 }; 175 } 176 process(inputs) { 177 if (!this.buffer) { 178 return true; 179 } 180 181 const input = inputs[0]; // Get the first input node 182 if (input.length > 0) { 183 let channelData = input[0]; // Get the first channel's data 184 185 // Resample the audio if necessary 186 if (this.resampler) { 187 channelData = this.resampler.full(channelData); 188 } 189 190 // Add channel data to the buffer 191 this.buffer.push(...channelData); 192 // Get max volume 193 let sum = 0.0; 194 for (let i = 0; i < channelData.length; i++) { 195 sum += channelData[i] * channelData[i]; 196 } 197 const maxVolume = Math.sqrt(sum / channelData.length); 198 // Check if buffer size has reached or exceeded the threshold 199 if (this.buffer.length >= this.bufferSize) { 200 const float32Array = this.isMuted 201 ? new Float32Array(this.buffer.length) 202 : new Float32Array(this.buffer); 203 204 let encodedArray = this.format === "ulaw" 205 ? new Uint8Array(float32Array.length) 206 : new Int16Array(float32Array.length); 207 208 // Iterate through the Float32Array and convert each sample to PCM16 209 for (let i = 0; i < float32Array.length; i++) { 210 // Clamp the value to the range [-1, 1] 211 let sample = Math.max(-1, Math.min(1, float32Array[i])); 212 213 // Scale the sample to the range [-32768, 32767] 214 let value = sample < 0 ? sample * 32768 : sample * 32767; 215 if (this.format === "ulaw") { 216 value = encodeSample(Math.round(value)); 217 } 218 219 encodedArray[i] = value; 220 } 221 222 // Send the buffered data to the main script 223 this.port.postMessage([encodedArray, maxVolume]); 224 225 // Clear the buffer after sending 226 this.buffer = []; 227 } 228 } 229 return true; // Continue processing 230 } 231} 232registerProcessor("rawAudioProcessor", RawAudioProcessor); 233`),x={echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,channelCount:{ideal:1}};class F{context;analyser;worklet;inputStream;mediaStreamSource;permissions;onError;static async create({sampleRate:e,format:t,preferHeadphonesForIosDevices:n,inputDeviceId:o,workletPaths:a,libsampleratePath:i,onError:s,inputChunkDurationMs:r=25}){let l=null,c=null;try{let u={sampleRate:{ideal:e},...x};if(D()&&n){let e=(await window.navigator.mediaDevices.enumerateDevices()).find(e=>"audioinput"===e.kind&&["airpod","headphone","earphone"].find(t=>e.label.toLowerCase().includes(t)));e&&(u.deviceId={ideal:e.deviceId})}o&&(u.deviceId=F.getDeviceIdConstraint(o));let d=navigator.mediaDevices.getSupportedConstraints().sampleRate,h=(l=new window.AudioContext(d?{sampleRate:e}:{})).createAnalyser();d||await T(l,i),await R(l.audioWorklet,a?.rawAudioProcessor);let p={voiceIsolation:!0,...u};c=await navigator.mediaDevices.getUserMedia({audio:p});let m=l.createMediaStreamSource(c),g=new AudioWorkletNode(l,"rawAudioProcessor");g.port.postMessage({type:"setFormat",format:t,sampleRate:e,chunkDurationMs:r}),m.connect(h),h.connect(g),await l.resume();let f=await navigator.permissions.query({name:"microphone"});return new F(l,h,g,c,m,f,s)}catch(e){throw c?.getTracks().forEach(e=>{e.stop()}),l?.close(),e}}static getDeviceIdConstraint(e){if(e)return D()?{ideal:e}:{exact:e}}muted=!1;volumeProvider;constructor(e,t,n,o,a,i,s=console.error){this.context=e,this.analyser=t,this.worklet=n,this.inputStream=o,this.mediaStreamSource=a,this.permissions=i,this.onError=s,this.permissions.addEventListener("change",this.handlePermissionsChange),this.worklet.port.start(),this.volumeProvider=I(t,e.sampleRate)}getAnalyser(){return this.analyser}getVolume(){return this.muted?0:this.volumeProvider.getVolume()}getByteFrequencyData(e){if(this.muted){e.fill(0);return}this.volumeProvider.getByteFrequencyData(e)}isMuted(){return this.muted}addListener(e){this.worklet.port.addEventListener("message",e)}removeListener(e){this.worklet.port.removeEventListener("message",e)}forgetInputStreamAndSource(){for(let e of this.inputStream.getTracks())e.stop();this.mediaStreamSource.disconnect()}async close(){this.forgetInputStreamAndSource(),this.permissions.removeEventListener("change",this.handlePermissionsChange),await this.context.close()}async setMuted(e){this.muted=e,this.worklet.port.postMessage({type:"setMuted",isMuted:e})}settingInput=!1;async setDevice(e){try{if(this.settingInput)throw Error("Input device is already being set");this.settingInput=!0;let t=e?.inputDeviceId,n={...x};t&&(n.deviceId=F.getDeviceIdConstraint(t));let o={voiceIsolation:!0,...n},a=await navigator.mediaDevices.getUserMedia({audio:o});this.forgetInputStreamAndSource(),this.inputStream=a,this.mediaStreamSource=this.context.createMediaStreamSource(a),this.mediaStreamSource.connect(this.analyser)}catch(e){throw this.onError("Failed to switch input device:",e),e}finally{this.settingInput=!1}}handlePermissionsChange=()=>{if("denied"===this.permissions.state)this.onError("Microphone permission denied");else if(!this.settingInput){let[e]=this.inputStream.getAudioTracks(),{deviceId:t}=e?.getSettings()??{};this.setDevice({inputDeviceId:t}).catch(e=>{this.onError("Failed to reset input device after permission change:",e)})}}}class L extends i{socket;conversationId;inputFormat;outputFormat;outputListeners=new Set;pendingAudioEvents=[];constructor(e,t,n,o){super(),this.socket=e,this.conversationId=t,this.inputFormat=n,this.outputFormat=o,this.socket.addEventListener("error",e=>{setTimeout(()=>this.disconnect({reason:"error",message:"The connection was closed due to a socket error.",context:{type:e.type}}),0)}),this.socket.addEventListener("close",e=>{let t=e.code,n=e.reason||void 0,o={type:e.type,code:t,reason:n};this.disconnect(1e3===t?{reason:"agent",context:o,closeCode:t,closeReason:n}:{reason:"error",message:n||"The connection was closed by the server.",context:o,closeCode:t,closeReason:n})}),this.socket.addEventListener("message",e=>{try{let t=JSON.parse(e.data);if(!d(t)){this.debug({type:"invalid_event",message:"Received invali
233d socket event",data:e.data});return}this.handleMessage(t)}catch(t){this.debug({type:"parsing_error",message:"Failed to parse socket message",error:t instanceof Error?t.message:String(t),data:e.data})}})}static async create(e){let t=null;try{let n;let o=e.origin??"wss://api.elevenlabs.io",{name:a,version:i}=u;if(e.signedUrl){let t=e.signedUrl.includes("?")?"&":"?";n=`${e.signedUrl}${t}source=${a}&version=${i}`}else n=`${o}/v1/convai/conversation?agent_id=${e.agentId}&source=${a}&version=${i}`;e.environment&&(n+=`&environment=${encodeURIComponent(e.environment)}`);let r=["convai"];e.authorization&&r.push(`bearer.${e.authorization}`),t=new WebSocket(n,r);let{conversation_id:l,agent_output_audio_format:h,user_input_audio_format:p}=await new Promise((n,o)=>{t.addEventListener("open",()=>{let n=w(e);t?.send(JSON.stringify(n))},{once:!0}),t.addEventListener("error",e=>{setTimeout(()=>o(new c("The connection was closed due to a socket error.")),0)}),t.addEventListener("close",e=>{let t=e.reason||(1e3===e.code?"Connection closed normally before session could be established.":"Connection closed unexpectedly before session could be established.");o(new c(t,{closeCode:e.code,closeReason:e.reason||void 0}))}),t.addEventListener("message",e=>{let t=JSON.parse(e.data);d(t)&&("conversation_initiation_metadata"===t.type?n(t.conversation_initiation_metadata_event):console.warn("First received message is not conversation metadata."))},{once:!0})}),m=s(p??"pcm_16000"),g=s(h);return new L(t,l,m,g)}catch(e){throw t?.close(),e}}close(){this.pendingAudioEvents=[],this.socket.close(1e3,"User ended conversation")}sendMessage(e){this.socket.send(JSON.stringify(e))}addListener(e){let t=this.outputListeners.size>0;if(this.outputListeners.add(e),t||0===this.pendingAudioEvents.length)return;let n=this.pendingAudioEvents;for(let t of(this.pendingAudioEvents=[],n))e(t)}removeListener(e){this.outputListeners.delete(e)}handleMessage(e){if(super.handleMessage(e),"audio"===e.type&&e.audio_event.audio_base_64){let t={audio_base_64:e.audio_event.audio_base_64};if(0===this.outputListeners.size){this.pendingAudioEvents.push(t);return}this.outputListeners.forEach(e=>e(t))}}}async function U(e){let t=function(e){let t="signedUrl"in e&&e.signedUrl;if(t&&"webrtc"===e.connectionType)throw Error("signedUrl only supports websocket connections. Remove connectionType or set it to 'websocket'.");return e.connectionType?e.connectionType:"conversationToken"in e&&e.conversationToken?"webrtc":t?"websocket":e.textOnly?"websocket":"webrtc"}(e);switch(t){case"websocket":return L.create(e);case"webrtc":return S.create(e);default:throw Error(`Unknown connection type: ${t}`)}}let O={default:0,android:3e3};function V(e,t="default"){let n=e??O;return"android"===t?n.android??n.default:"ios"===t?n.ios??n.default:n.default}async function N(e){e>0&&await new Promise(t=>setTimeout(t,e))}let q=["touchstart","touchend","click"],$=null,B=null,W=!1;function Q(){B&&(clearTimeout(B),B=null)}function j(){$&&($.close().catch(()=>{}),$=null,Q())}async function z(){if("wakeLock"in navigator)try{return await navigator.wakeLock.request("screen")}catch(e){}return null}async function G(e,t,n){let[o,a]=await Promise.all([F.create({...t.inputFormat,preferHeadphonesForIosDevices:e.preferHeadphonesForIosDevices,inputDeviceId:e.inputDeviceId,inputChunkDurationMs:e.inputChunkDurationMs,workletPaths:e.workletPaths,libsampleratePath:e.libsampleratePath}),P.create({...t.outputFormat,outputDeviceId:e.outputDeviceId,workletPaths:e.workletPaths,audioContext:n??void 0})]),i=function(e,t){let n=e=>{let n=e.data[0];t.sendMessage({user_audio_chunk:C(n.buffer)})};return e.addListener(n),()=>{e.removeListener(n)}}(o,t),s=function(e,t){let n=e=>{t.playAudio(function(e){let t=atob(e),n=t.length,o=new Uint8Array(n);for(let e=0;e<n;e++)o[e]=t.charCodeAt(e);return o.buffer}(e.audio_base_64))};return e.addListener(n),()=>{e.removeListener(n)}}(t,a);return{input:o,output:a,playbackEventTarget:a,detach:async()=>{i(),s()}}}a=async function(e){let t=e.useWakeLock??!0,n=null,o=null,a=null;try{let i;t&&(n=await z()),o=await navigator.mediaDevices.getUserMedia({audio:!0});let s=/android/i.test(navigator.userAgent)?"android":D()?"ios":"default";await N(V(e.connectionDelay,s));let r=await U(e);try{r instanceof L?(a=function(){let e=$;return $=null,Q(),e}(),i={connection:r,...await G(e,r,a)},a=null):(j(),i=function(e){if(!(e instanceof S))throw Error(`setupWebRTCSession requires a WebRTCConnection. Received: ${e?.constructor?.name??typeof e}`);return{connection:e,input:e.input,output:e.output,playbackEventTarget:null,detach:async()=>{}}}(r))}catch(e){throw await a?.close().catch(()=>{}),a=null,r.close(),e}if(o){for(let e of o.getTracks())e.stop();o=null}let l=null;n&&(l=()=>{"visible"===document.visibilityState&&n?.released&&z().then(e=>{n=e})},document.addEventListener("visibilitychange",l));let c=i.detach;return{...i,detach:async()=>{await c(),l&&document.removeEventListener("visibilitychange",l);try{await n?.release(),n=null}catch(e){}}}}catch(e){if(o)for(let e of o.getTracks())e.stop();try{await n?.release(),n=null}catch(e){}throw j(),e}};class H{audioElements=[];inputAudioContext=null;audioCaptureContext=null;async attachRemoteTrack(e,t){let n=e.attach();if(n.autoplay=!0,n.controls=!1,t&&n.setSinkId)try{await n.setSinkId(t)}catch(e){console.warn("Failed to set output device for new audio element:",e)}n.style.display="none",document.body.appendChild(n),this.audioElements.push(n)}setupInputAnalysis(e){this.inputAudioContext&&(this.inputAudioContext.close().catch(()=>{}),this.inputAudioContext=null);let t=new AudioContext,n=t.createAnalyser();return t.createMediaStreamSource(new MediaStream([e])).connect(n),this.inputAudioContext=t,{volumeProvider:I(n,t.sampleRate),analyser:n}}async setupOutputAnalysis(e,t,n){this.audioCaptureContext&&(this.audioCaptureContext.close().catch(()=>{}),this.audioCaptureContext=null);let o=new AudioContext;this.audioCaptureContext=o;let a=o.createAnalyser();a.fftSize=2048,a.smoothingTimeConstant=.8;let i=new MediaStream([e.mediaStreamTrack]),s=o.createMediaStreamSource(i),r=I(a,o.sampleRate);await R(o.audioWorklet);let l=new AudioWorkletNode(o,"rawAudioProcessor");return l.port.postMessage({type:"setFormat",format:t.format,sampleRate:t.sampleRate}),l.port.onmessage=e=>{let[t,o]=e.data;n(t.buffer,o)},s.connect(a),a.connect(l),{volumeProvider:r,analyser:a}}setVolume(e){for(let t of this.audioElements)t.volume=e}async setOutputDevice(e){if(!("setSinkId"in HTMLAudioElement.prototype))throw Error("setSinkId is not supported in this browser");await Promise.all(this.audioElements.map(async t=>{try{await t.setSinkId(e)}catch(e){throw console.error("Failed to set sink ID for audio element:",e),e}}))}cleanup(){for(let e of(this.inputAudioContext&&(this.inputAudioContext.close().catch(e=>{console.warn("Error closing input audio context:",e)}),this.inputAudioContext=null),this.audioCaptureContext&&(this.audioCaptureContext.close().catch(e=>{console.warn("Error closing audio capture context:",e)}),this.audioCaptureContext=null),this.audioElements))e.remove();this.audioElements=[]}}async function J({conversationId:e,origin:t,file:n,filename:o}){let a=(t??"https://api.elevenlabs.io").replace(/^wss:\/\//,"https://").replace(/^ws:\/\//,"http://"),i=o??("name"in n&&"string"==typeof n.name?n.name:`upload.${(n.type||"image/png").split("/").pop()?.split("+")[0]}`),s=new FormData;s.append("file",n,i);let c=await fetch(`${a}/v1/convai/conversations/${e}/files`,{method:"POST",body:s});if(!c.ok){let e=await l(c);throw Error(`Upload failed: ${c.status} ${e}`)}let u=await c.json();!function(e,t="Expected a JSON object"){if(!r(e))throw Error(t)}(u,"Upload response is not a JSON object");let{file_id:d}=u;if("string"!=typeof d||!d)throw Error("Upload response is missing a valid file_id");return{fileId:d}}E("scribeAudioProcessor",`/* 234 * Scribe Audio Processor for converting microphone audio to PCM16 format 235 * Supports resampling for browsers like Firefox that don't support 236 * AudioContext sample rate constraints. 237 * USED BY @elevenlabs/client 238 */ 239 240class ScribeAudioProcessor extends AudioWorkletProcessor { 241 constructor() { 242 super(); 243 this.buffer = []; 244 this.bufferSize = 4096; // Buffer size for optimal chunk transmission 245 246 // Resampling state 247 this.inputSampleRate = null; 248 this.outputSampleRate = null; 249 this.resampleRatio = 1; 250 this.lastSample = 0; 251 this.resampleAccumulator = 0; 252 253 this.port.onmessage = ({ data }) => { 254 if (data.type === "configure") { 255 this.inputSampleRate = data.inputSampleRate; 256 this.outputSampleRate = data.outputSampleRate; 257 if (this.inputSampleRate && this.outputSampleRate) { 258 this.resampleRatio = this.inputSampleRate / this.outputSampleRate; 259 } 260 } 261 }; 262 } 263 264 // Linear interpolation resampling 265 resample(inputData) { 266 if (this.resampleRatio === 1 || !this.inputSampleRate) { 267 return inputData; 268 } 269 270 const outputSamples = []; 271 272 for (let i = 0; i < inputData.length; i++) { 273 const currentSample = inputData[i]; 274 275 // Generate output samples using linear interpolation 276 while (this.resampleAccumulator < 1) { 277 const interpolated = 278 this.lastSample + 279 (currentSample - this.lastSample) * this.resampleAccumulator; 280 outputSamples.push(interpolated); 281 this.resampleAccumulator += this.resampleRatio; 282 } 283 284 this.resampleAccumulator -= 1; 285 this.lastSample = currentSample; 286 } 287 288 return new Float32Array(outputSamples); 289 } 290 291 process(inputs) { 292 const input = inputs[0]; 293 if (input.length > 0) { 294 let channelData = input[0]; // Get first channel (mono) 295 296 // Resample if needed (for Firefox and other browsers that don't 297 // support AudioContext sample rate constraints) 298 if (this.resampleRatio !== 1) { 299 channelData = this.resample(channelData); 300 } 301 302 // Add incoming audio to buffer 303 for (let i = 0; i < channelData.length; i++) { 304 this.buffer.push(channelData[i]); 305 } 306 307 // When buffer reaches threshold, convert and send 308 if (this.buffer.length >= this.bufferSize) { 309 const float32Array = new Float32Array(this.buffer); 310 const int16Array = new Int16Array(float32Array.length); 311 312 // Convert Float32 [-1, 1] to Int16 [-32768, 32767] 313 for (let i = 0; i < float32Array.length; i++) { 314 // Clamp the value to prevent overflow 315 const sample = Math.max(-1, Math.min(1, float32Array[i])); 316 // Scale to PCM16 range 317 int16Array[i] = sample < 0 ? sample * 32768 : sample * 32767; 318 } 319 320 // Send to main thread as transferable ArrayBuffer 321 this.port.postMessage( 322 { 323 audioData: int16Array.buffer 324 }, 325 [int16Array.buffer] 326 ); 327 328 // Clear buffer 329 this.buffer = []; 330 } 331 } 332 333 return true; // Continue processing 334 } 335} 336 337registerProcessor("scribeAudioProcessor", ScribeAudioProcessor); 338 339`);let Y={reason:"agent",context:{type:"end_call",reason:"Agent ended the call"}};function X(e){let{textOnly:t}=e.overrides?.conversation??{},{textOnly:n}=e;return"boolean"==typeof n?("boolean"==typeof t&&n!==t&&console.warn(`Conflicting textOnly options provided: ${n} via options.textOnly (will be used) and ${t} via options.overrides.conversation.textOnly (will be ignored)`),n):"boolean"==typeof t?t:void 0}class K{options;connection;lastInterruptTimestamp=0;mode="listening";status="connecting";volume=1;currentEventId=1;
339canSendFeedback=!1;static getFullOptions(e){let t=X(e);return{clientTools:{},onConnect:()=>{},onDebug:()=>{},onDisconnect:()=>{},onError:()=>{},onMessage:()=>{},onAudio:()=>{},onModeChange:()=>{},onStatusChange:()=>{},onCanSendFeedbackChange:()=>{},onInterruption:()=>{},onAgentResponseCorrection:()=>{},onAgentTyping:()=>{},onExternalAgentConnected:()=>{},onPing:()=>{},...e,textOnly:t,overrides:{...e.overrides,conversation:{...e.overrides?.conversation,textOnly:t}}}}constructor(e,t){this.options=e,this.connection=t,this.connection.onMessage(this.onMessage),this.connection.onDisconnect(this.endSessionWithDetails),this.connection.onModeChange(e=>this.updateMode(e))}markConnected(){this.updateStatus("connected")}endSession(){return this.endSessionWithDetails({reason:"user"})}endSessionWithDetails=async e=>{("connected"===this.status||"connecting"===this.status)&&(this.updateStatus("disconnecting"),await this.handleEndSession(),this.updateStatus("disconnected"),this.options.onDisconnect&&this.options.onDisconnect(e))};async handleEndSession(){this.connection.close()}updateMode(e){e!==this.mode&&(this.mode=e,this.options.onModeChange&&this.options.onModeChange({mode:e}))}updateStatus(e){e!==this.status&&(this.status=e,this.options.onStatusChange&&this.options.onStatusChange({status:e}),this.updateCanSendFeedback())}updateCanSendFeedback(){let e="connected"===this.status;this.canSendFeedback!==e&&(this.canSendFeedback=e,this.options.onCanSendFeedbackChange&&this.options.onCanSendFeedbackChange({canSendFeedback:e}))}handleInterruption(e){e.interruption_event&&(this.lastInterruptTimestamp=e.interruption_event.event_id,this.options.onInterruption&&this.options.onInterruption({event_id:e.interruption_event.event_id}))}handleAgentResponse(e){this.currentEventId=e.agent_response_event.event_id,this.options.onMessage&&this.options.onMessage({source:"ai",role:"agent",message:e.agent_response_event.agent_response,event_id:e.agent_response_event.event_id})}handleAgentResponseCorrection(e){this.options.onAgentResponseCorrection&&this.options.onAgentResponseCorrection(e.agent_response_correction_event)}handleUserTranscript(e){this.options.onMessage&&this.options.onMessage({source:"user",role:"user",message:e.user_transcription_event.user_transcript,event_id:e.user_transcription_event.event_id})}handleTentativeAgentResponse(e){this.options.onDebug&&this.options.onDebug({type:"tentative_agent_response",response:e.tentative_agent_response_internal_event.tentative_agent_response})}handleVadScore(e){this.options.onVadScore&&this.options.onVadScore({vadScore:e.vad_score_event.vad_score})}handlePing(e){this.options.onPing&&this.options.onPing(e.ping_event)}async handleClientToolCall(e){if(Object.prototype.hasOwnProperty.call(this.options.clientTools,e.client_tool_call.tool_name))try{let t=await this.options.clientTools[e.client_tool_call.tool_name](e.client_tool_call.parameters)??"Client tool execution successful.",n="object"==typeof t?JSON.stringify(t):String(t);this.connection.sendMessage({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:n,is_error:!1})}catch(t){this.onError(`Client tool execution failed with following error: ${t?.message}`,{clientToolName:e.client_tool_call.tool_name}),this.connection.sendMessage({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:`Client tool execution failed: ${t?.message}`,is_error:!0})}else{if(this.options.onUnhandledClientToolCall){this.options.onUnhandledClientToolCall(e.client_tool_call);return}this.onError(`Client tool with name ${e.client_tool_call.tool_name} is not defined on client`,{clientToolName:e.client_tool_call.tool_name}),this.connection.sendMessage({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:`Client tool with name ${e.client_tool_call.tool_name} is not defined on client`,is_error:!0})}}handleAudio(e){}handleMCPToolCall(e){this.options.onMCPToolCall&&this.options.onMCPToolCall(e.mcp_tool_call)}handleMCPConnectionStatus(e){this.options.onMCPConnectionStatus&&this.options.onMCPConnectionStatus(e.mcp_connection_status)}
339handleAgentToolRequest(e){this.options.onAgentToolRequest&&this.options.onAgentToolRequest(e.agent_tool_request)}handleAgentToolResponse(e){"end_call"===e.agent_tool_response.tool_name&&this.endSessionWithDetails(Y).catch(e=>{this.onError("Failed to end session after agent end_call",e)}),this.options.onAgentToolResponse?.(e.agent_tool_response)}handleAgentToolResponseFullPayload(e){"end_call"===e.agent_tool_response_full_payload.tool_name&&this.endSessionWithDetails(Y).catch(e=>{this.onError("Failed to end session after agent end_call",e)}),this.options.onAgentToolResponse?.(e.agent_tool_response_full_payload)}handleConversationMetadata(e){this.options.onConversationMetadata&&this.options.onConversationMetadata(e.conversation_initiation_metadata_event)}handleAsrInitiationMetadata(e){this.options.onAsrInitiationMetadata&&this.options.onAsrInitiationMetadata(e.asr_initiation_metadata_event)}handleAgentChatResponsePart(e){this.options.onAgentChatResponsePart&&this.options.onAgentChatResponsePart(e.text_response_part)}handleAgentReasoningResponsePart(e){this.options.onAgentReasoningResponsePart&&this.options.onAgentReasoningResponsePart(e.reasoning_response_part)}handleGuardrailTriggered(e){this.options.onGuardrailTriggered&&this.options.onGuardrailTriggered()}handleAgentTyping(e){this.options.onAgentTyping&&this.options.onAgentTyping(e.agent_typing_event)}handleExternalAgentConnected(e){this.options.onExternalAgentConnected&&this.options.onExternalAgentConnected()}handleErrorEvent(e){let t=e.error_event,n=t?.error_type,o=t?.message||t?.reason||"Unknown error";if("max_duration_exceeded"===n){this.endSessionWithDetails({reason:"error",message:o,context:{type:"max_duration_exceeded"}}).catch(e=>{this.onError("Failed to end session after max_duration_exceeded",e)});return}this.onError(`Server error: ${o}`,{errorType:n,code:t?.code,debugMessage:t?.debug_message,details:t?.details})}onMessage=async e=>{switch(e.type){case"interruption":this.handleInterruption(e);return;case"agent_response":this.handleAgentResponse(e);return;case"agent_response_correction":this.handleAgentResponseCorrection(e);return;case"user_transcript":this.handleUserTranscript(e);return;case"internal_tentative_agent_response":this.handleTentativeAgentResponse(e);return;case"client_tool_call":try{await this.handleClientToolCall(e)}catch(t){this.onError(`Unexpected error in client tool call handling: ${t instanceof Error?t.message:String(t)}`,{clientToolName:e.client_tool_call.tool_name,toolCallId:e.client_tool_call.tool_call_id})}return;case"audio":this.handleAudio(e);return;case"vad_score":this.handleVadScore(e);return;case"ping":this.connection.sendMessage({type:"pong",event_id:e.ping_event.event_id}),this.handlePing(e);return;case"mcp_tool_call":this.handleMCPToolCall(e);return;case"mcp_connection_status":this.handleMCPConnectionStatus(e);return;case"agent_tool_request":this.handleAgentToolRequest(e);return;case"agent_tool_response":this.handleAgentToolResponse(e);return;case"agent_tool_response_full_payload":this.handleAgentToolResponseFullPayload(e);return;case"conversation_initiation_metadata":this.handleConversationMetadata(e);return;case"asr_initiation_metadata":this.handleAsrInitiationMetadata(e);return;case"agent_chat_response_part":this.handleAgentChatResponsePart(e);return;case"agent_reasoning_response_part":this.handleAgentReasoningResponsePart(e);return;case"guardrail_triggered":this.handleGuardrailTriggered(e);return;case"error":this.handleErrorEvent(e);return;case"agent_typing":this.handleAgentTyping(e);return;case"external_agent_connected":this.handleExternalAgentConnected(e);return;default:this.options.onDebug&&this.options.onDebug(e);return}};onError(e,t){console.error(e,t),this.options.onError&&this.options.onError(e,t)}getId(){return this.connection.conversationId}isOpen(){return"connected"===this.status}sendFeedback(e,t){if(!this.canSendFeedback){console.warn("Cannot send feedback: the conversation is not connected.");return}this.connection.sendMessage({type:"feedback",score:null!==e?e?"like":"dislike":null,event_id:t??this.currentEventId})}sendContextualUpdate(e,t){this.connection.sendMessage({type:"contextual_update",text:e,...t?.contextId?{context_id:t.contextId}:{}})}sendUserMessage(e){this.connection.sendMessage({type:"user_message",text:e})}sendUserActivity(){this.connection.sendMessage({type:"user_activity"})}sendMCPToolApprovalResult(e,t){this.connection.sendMessage({type:"mcp_tool_approval_result",tool_call_id:e,is_approved:t})}sendMultimodalMessage(e){this.connection.sendMessage({type:"multimodal_message",text:e.text?{type:"user_message",text:e.text}:void 0,file:e.fileId?{type:"file_input",file_id:e.fileId}:void 0})}async uploadFile(e){return J({conversationId:this.connection.conversationId,origin:this.options.origin,file:e})}}let Z=new Uint8Array(0);class ee extends K{type="text";setVolume(){throw Error("setVolume is not supported in text conversations")}setMicMuted(){throw Error("setMicMuted is not supported in text conversations")}getInputByteFrequencyData(){return Z}getOutputByteFrequencyData(){return Z}getInputVolume(){return 0}getOutputVolume(){return 0}static async startSession(e){let t=K.getFullOptions(e);t.onStatusChange&&t.onStatusChange({status:"connecting"}),t.onCanSendFeedbackChange&&t.onCanSendFeedbackChange({canSendFeedback:!1}),t.onModeChange&&t.onModeChange({mode:"listening"}),t.onCanSendFeedbackChange&&t.onCanSendFeedbackChange({canSendFeedback:!1});let n=null,o=null;try{return await N(V(t.connectionDelay)),n=await U(t),o=new ee(t,n),t.onConversationCreated?.(o),o.markConnected(),t.onConnect?.({conversationId:n.conversationId}),o}catch(e){throw o?await o.endSession().catch(()=>{}):(t.onStatusChange?.({status:"disconnected"}),n?.close()),e}}}class et extends K{input;output;playbackEventTarget;cleanUp;type="voice";static async startSession(e){let t=K.getFullOptions(e);t.onStatusChange&&t.onStatusChange({status:"connecting"}),t.onCanSendFeedbackChange&&t.onCanSendFeedbackChange({canSendFeedback:!1});let n=null,o=null;try{if(!a)throw Error('No voice session setup strategy registered. Import the platform-specific entry point (e.g. @elevenlabs/client via the "browser" export).');return o=await a(t),n=new et(t,o.connection,o.input,o.output,o.playbackEventTarget,o.detach),t.onConversationCreated?.(n),n.markConnected(),t.onConnect?.({conversationId:o.connection.conversationId}),n}catch(e){throw n?await n.endSession().catch(()=>{}):(o&&await o.detach().catch(()=>{}),t.onStatusChange?.({status:"disconnected"})),e}}inputFrequencyData;outputFrequencyData;handlePlaybackEvent=e=>{"process"===e.data.type&&this.updateMode(e.data.finished?"listening":"speaking")};constructor(e,t,n,o,a,i){super(e,t),this.input=n,this.output=o,this.playbackEventTarget=a,this.cleanUp=i,a?.addListener(this.handlePlaybackEvent)}async handleEndSession(){this.playbackEventTarget?.removeListener(this.handlePlaybackEvent),this.playbackEventTarget=null,await this.cleanUp(),await super.handleEndSession(),await this.input.close(),await this.output.close()}handleInterruption(e){super.handleInterruption(e),this.updateMode("listening"),this.output.interrupt()}handleAudio(e){super.handleAudio(e),e.audio_event.alignment&&this.options.onAudioAlignment&&this.options.onAudioAlignment(e.audio_event.alignment),this.lastInterruptTimestamp<=e.audio_event.event_id&&(e.audio_event.audio_base_64&&this.options.onAudio?.(e.audio_event.audio_base_64),this.currentEventId=e.audio_event.event_id,this.updateCanSendFeedback(),this.updateMode("speaking"))}static FREQUENCY_BIN_COUNT=1024;setMicMuted(e){this.input.setMuted(e).catch(e=>{this.options.onError?.("Failed to set input muted state",e)})}getInputByteFrequencyData(){return this.inputFrequencyData??=new Uint8Array(et.FREQUENCY_BIN_COUNT),this.input.getByteFrequencyData(this.inputFrequencyData),this.inputFrequencyData}
339getOutputByteFrequencyData(){return this.outputFrequencyData??=new Uint8Array(et.FREQUENCY_BIN_COUNT),this.output.getByteFrequencyData(this.outputFrequencyData),this.outputFrequencyData}getInputVolume(){return this.input.getVolume()}getOutputVolume(){return this.output.getVolume()}async changeInputDevice({sampleRate:e,format:t,preferHeadphonesForIosDevices:n,inputDeviceId:o}){try{await this.input.setDevice({inputDeviceId:o,sampleRate:e,format:t,preferHeadphonesForIosDevices:n})}catch(e){throw console.error("Error changing input device",e),e}}async changeOutputDevice({sampleRate:e,format:t,outputDeviceId:n}){try{await this.output.setDevice({outputDeviceId:n,sampleRate:e,format:t})}catch(e){throw console.error("Error changing output device",e),e}}setVolume=({volume:e})=>{let t=Number.isFinite(e)?Math.min(1,Math.max(0,e)):1;this.volume=t,this.output.setVolume(t)}}(h=g||(g={})).SESSION_STARTED="session_started",h.PARTIAL_TRANSCRIPT="partial_transcript",h.COMMITTED_TRANSCRIPT="committed_transcript",h.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS="committed_transcript_with_timestamps",h.AUTH_ERROR="auth_error",h.ERROR="error",h.OPEN="open",h.CLOSE="close",h.QUOTA_EXCEEDED="quota_exceeded",h.COMMIT_THROTTLED="commit_throttled",h.TRANSCRIBER_ERROR="transcriber_error",h.UNACCEPTED_TERMS="unaccepted_terms",h.RATE_LIMITED="rate_limited",h.INPUT_ERROR="input_error",h.QUEUE_OVERFLOW="queue_overflow",h.RESOURCE_EXHAUSTED="resource_exhausted",h.SESSION_TIME_LIMIT_EXCEEDED="session_time_limit_exceeded",h.CHUNK_SIZE_EXCEEDED="chunk_size_exceeded",h.INSUFFICIENT_AUDIO_ACTIVITY="insufficient_audio_activity",(p=f||(f={})).PCM_8000="pcm_8000",p.PCM_16000="pcm_16000",p.PCM_22050="pcm_22050",p.PCM_24000="pcm_24000",p.PCM_44100="pcm_44100",p.PCM_48000="pcm_48000",p.ULAW_8000="ulaw_8000",(m=v||(v={})).MANUAL="manual",m.VAD="vad";let en={startSession:async e=>(!function(){for(let e of["fetch","WebSocket","TextEncoder","TextDecoder","URL","btoa","atob"])if(void 0===globalThis[e])throw Error(`${e} is not available in this environment.`)}(),X(e)?ee.startSession(e):et.startSession(e))};!function(){if(!D()||W||"undefined"==typeof document)return;W=!0;let e=()=>{!function(){if(!D()||$)return;let e=new AudioContext;(function(e){let t=e.createBuffer(1,1,22050),n=e.createBufferSource();n.buffer=t,n.connect(e.destination),n.start(0),e.resume().catch(()=>{})})(e),$=e,B&&clearTimeout(B),B=setTimeout(()=>{B=null,j()},3e4)}()};for(let t of q)document.addEventListener(t,e,!0)}(),o=()=>new H}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.