@elevenlabs/react-native 0.5.4 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react"),require("@livekit/react-native")):"function"==typeof define&&define.amd?define(["exports","react","@livekit/react-native"],n):n((e||self).reactNative={},e.react,e.reactNative)}(this,function(e,n,t){function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=/*#__PURE__*/o(n);function a(){return a=Object.assign?Object.assign.bind():function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var o in t)({}).hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e},a.apply(null,arguments)}var l="0.5.4",c=function(e){var o=e.onReady,a=e.isConnected,l=e.callbacks,c=e.sendMessage,s=e.clientTools,i=void 0===s?{}:s,u=e.updateCurrentEventId,d=e.onEndSession,f=t.useLocalParticipant().localParticipant,v=r.default.useRef(1);return n.useEffect(function(){a||(v.current=1)},[a]),n.useEffect(function(){a&&f&&o(f)},[a,f,o]),t.useDataChannel(function(e){var n,t=new TextDecoder,o=JSON.parse(t.decode(e.payload));if("object"==typeof(r=o)&&null!==r&&"type"in r){var r,a,s=function(e){switch(e.type){case"user_transcript":return e.user_transcription_event.user_transcript;case"agent_response":return e.agent_response_event.agent_response;default:return null}}(o);if(null!==s&&(null==l.onMessage||l.onMessage({message:s,source:"user_transcript"===o.type?"user":"ai"})),null!=(n=e.from)&&n.isAgent&&(null==l.onModeChange||l.onModeChange({mode:null!=(a=e.from)&&a.isSpeaking?"speaking":"listening"}),"agent_response"===o.type&&u)){var f=v.current++;u(f)}switch(o.type){case"ping":c({type:"pong",event_id:o.ping_event.event_id});break;case"client_tool_call":!function(e){try{return Promise.resolve(function(){if(e.client_tool_call.tool_name in i){var n=function(n,t){try{var o=Promise.resolve(i[e.client_tool_call.tool_name](e.client_tool_call.parameters)).then(function(n){var t="object"==typeof n?JSON.stringify(n):String(n);c({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:t,is_error:!1})})}catch(e){return t(e)}return o&&o.then?o.then(void 0,t):o}(0,function(n){null==l.onError||l.onError("Client tool execution failed with following error: "+(null==n?void 0:n.message),{clientToolName:e.client_tool_call.tool_name}),c({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:"Client tool execution failed: "+(null==n?void 0:n.message),is_error:!0})});if(n&&n.then)return n.then(function(){})}else{if(l.onUnhandledClientToolCall)return void l.onUnhandledClientToolCall(e.client_tool_call);var t="Client tool with name "+e.client_tool_call.tool_name+" is not defined on client";null==l.onError||l.onError(t,{clientToolName:e.client_tool_call.tool_name}),c({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:t,is_error:!0})}}())}catch(e){return Promise.reject(e)}}(o);break;case"audio":null==l.onAudio||l.onAudio(o.audio_event.audio_base_64);break;case"vad_score":null==l.onVadScore||l.onVadScore({vadScore:o.vad_score_event.vad_score});break;case"interruption":null==l.onInterruption||l.onInterruption(o.interruption_event);break;case"mcp_tool_call":null==l.onMCPToolCall||l.onMCPToolCall(o.mcp_tool_call);break;case"mcp_connection_status":null==l.onMCPConnectionStatus||l.onMCPConnectionStatus(o.mcp_connection_status);break;case"agent_tool_request":null==l.onAgentToolRequest||l.onAgentToolRequest(o.agent_tool_request);break;case"agent_tool_response":null==l.onAgentToolResponse||l.onAgentToolResponse(o.agent_tool_response),"end_call"===o.agent_tool_response.tool_name&&d("agent");break;case"conversation_initiation_metadata":null==l.onConversationMetadata||l.onConversationMetadata(o.conversation_initiation_metadata_event);break;case"asr_initiation_metadata":null==l.onAsrInitiationMetadata||l.onAsrInitiationMetadata(o.asr_initiation_metadata_event);break;case"agent_chat_response_part":null==l.onAgentChatResponsePart||l.onAgentChatResponsePart(o.text_response_part);break;default:null==l.onDebug||l.onDebug(o)}}else null==l.onDebug||l.onDebug({type:"invalid_event",message:o})}),null},s=function(e){var n=e.children;/*#__PURE__*/return r.default.createElement(t.LiveKitRoom,{serverUrl:e.serverUrl,token:e.token,connect:e.connect,audio:!0,video:!1,options:{adaptiveStream:{pixelDensity:"screen"}},onConnected:e.onConnected,onDisconnected:e.onDisconnected,onError:e.onError},/*#__PURE__*/r.default.createElement(c,{onReady:e.onParticipantReady,isConnected:e.roomConnected,callbacks:e.callbacks,sendMessage:e.sendMessage,clientTools:e.clientTools,updateCurrentEventId:e.updateCurrentEventId,onEndSession:e.onEndSession}),n)},i=["serverUrl","tokenFetchUrl","clientTools"],u=/*#__PURE__*/n.createContext(null);e.ElevenLabsProvider=function(e){var o=e.children;t.registerGlobals();var c=n.useState(""),i=c[0],d=c[1],f=n.useState(!1),v=f[0],_=f[1],p=n.useState("disconnected"),g=p[0],h=p[1],m=n.useState("wss://livekit.rtc.elevenlabs.io"),C=m[0],b=m[1],k=n.useState(void 0),y=k[0],S=k[1],E=n.useState(""),P=E[0],T=E[1],M=n.useState(!1),x=M[0],w=M[1],I=n.useState(!1),R=I[0],D=I[1],U=r.default.useRef(1),A=r.default.useRef(1),F=r.default.useRef({}),j=function(){var e=n.useRef({}),t=n.useCallback(function(n){e.current=n},[]);return{callbacksRef:e,setCallbacks:t}}(),L=j.callbacksRef,N=j.setCallbacks,O=r.default.useCallback(function(e){var n=a({},e,{onModeChange:function(n){w("speaking"===n.mode),null==e.onModeChange||e.onModeChange(n)}});N(n)},[N]),V=function(e,t,o,r,a,c){var s=n.useState({}),i=s[0],u=s[1],d=n.useState(null),f=d[0],v=d[1],_=n.useState({}),p=_[0],g=_[1],h=n.useState(void 0),m=h[0],C=h[1];return{startSession:n.useCallback(function(n){try{return Promise.resolve(function(s,i){try{var d=function(){function s(e){var n=function(e){try{var n,t;return(null==(t=((null==(n=JSON.parse(atob(e.split(".")[1])).video)?void 0:n.room)||"").match(/(conv_[a-zA-Z0-9]+)/))?void 0:t[0])||""}catch(e){return console.warn("Could not extract conversation ID from token"),""}}(i);a(n),r(i),o(!0)}var i;t("connecting"),null==e.current.onStatusChange||e.current.onStatusChange({status:"connecting"}),u(n.overrides||{}),v(n.customLlmExtraBody||null),g(n.dynamicVariables||{}),C(n.userId);var d=function(){if(!n.conversationToken)return function(){if(n.agentId)return console.info("Getting conversation token for agentId:",n.agentId),Promise.resolve(function(e,n){try{return Promise.resolve(fetch((n||"https://api.elevenlabs.io/v1/convai/conversation/token")+"?agent_id="+e+"&source=react_native_sdk&version="+l)).then(function(e){return Promise.resolve(e.json()).then(function(n){if(!e.ok)throw new Error("Failed to get conversation token: "+n.detail.message);if(!n.token)throw new Error("No conversation token received from API");return n.token})})}catch(e){return Promise.reject(e)}}(n.agentId,n.tokenFetchUrl||c)).then(function(e){i=e});throw new Error("Either conversationToken or agentId is required")}();i=n.conversationToken}();return d&&d.then?d.then(s):s()}()}catch(e){return i(e)}return d&&d.then?d.then(void 0,i):d}(0,function(n){throw t("disconnected"),null==e.current.onStatusChange||e.current.onStatusChange({status:"disconnected"}),null==e.current.onError||e.current.onError(n),n}))}catch(e){return Promise.reject(e)}},[e,t,o,r,a,c]),endSession:n.useCallback(function(n){void 0===n&&(n="user");try{try{o(!1),r(""),t("disconnected"),u({}),v(null),g({}),C(void 0),a(""),null==e.current.onStatusChange||e.current.onStatusChange({status:"disconnected"}),null==e.current.onDisconnect||e.current.onDisconnect({reason:n})}catch(n){throw null==e.current.onError||e.current.onError(n),n}return Promise.resolve()}catch(e){return Promise.reject(e)}},[e,o,r,t,a]),overrides:i,customLlmExtraBody:f,dynamicVariables:p,userId:m}}(L,h,_,d,T,y),q=V.startSession,B=V.endSession,J=V.overrides,K=V.customLlmExtraBody,G=V.dynamicVariables,z=V.userId,W=function(e,o,r,a){var l=n.useState(!1),c=l[0],s=l[1],i=n.useState(null),u=i[0],d=i[1],f=n.useRef(!1);n.useEffect(function(){r&&(s(!1),d(null),f.current=!1)},[r]),n.useEffect(function(){return function(){try{return Promise.resolve(t.AudioSession.startAudioSession()).then(function(){})}catch(e){return Promise.reject(e)}}(),function(){t.AudioSession.stopAudioSession()}},[]),n.useEffect(function(){u&&c&&!f.current&&(f.current=!0,null==e.current.onConnect||e.current.onConnect({conversationId:r}))},[u,c,r,e]);var v=n.useCallback(function(e){u||(d(e),o("connected"))},[u,o]),_=n.useCallback(function(){s(!0)},[]),p=n.useCallback(function(){"disconnected"!==a&&(s(!1),o("disconnected"),d(null),f.current=!1,null==e.current.onDisconnect||e.current.onDisconnect({reason:"user"}))},[e,o,a]),g=n.useCallback(function(n){console.error("LiveKit error:",n),null==e.current.onError||e.current.onError(n.message,void 0)},[e]);return{roomConnected:c,localParticipant:u,handleParticipantReady:v,handleConnected:_,handleDisconnected:p,handleError:g}}(L,h,P,g),Z=W.roomConnected,H=W.localParticipant,Q=W.handleParticipantReady,X=W.handleConnected,Y=W.handleDisconnected,$=W.handleError,ee=r.default.useCallback(function(){U.current=1,A.current=1,D(!1),null==L.current.onCanSendFeedbackChange||L.current.onCanSendFeedbackChange({canSendFeedback:!1}),X()},[X,L]),ne=r.default.useCallback(function(){D(!1),w(!1),Y()},[Y]),te=function(e,t,o){return{sendMessage:n.useCallback(function(n){try{if("connected"!==e||!t)return console.warn("Cannot send message: room not connected or no local participant"),Promise.resolve();var r=function(e,o){try{var r=(a=(new TextEncoder).encode(JSON.stringify(n)),Promise.resolve(t.publishData(a,{reliable:!0})).then(function(){}))}catch(e){return o(e)}var a;return r&&r.then?r.then(void 0,o):r}(0,function(e){console.error("Failed to send message via WebRTC:",e),console.error("Error details:",e),null==o.current.onError||o.current.onError(e)});return Promise.resolve(r&&r.then?r.then(function(){}):void 0)}catch(e){return Promise.reject(e)}},[e,t,o])}}(g,H,L),oe=te.sendMessage,re=r.default.useCallback(function(){var e=U.current!==A.current;R!==e&&(D(e),null==L.current.onCanSendFeedbackChange||L.current.onCanSendFeedbackChange({canSendFeedback:e}))},[R,L]),ae=r.default.useCallback(function(e){R?(oe({type:"feedback",score:e?"like":"dislike",event_id:U.current}),A.current=U.current,re()):console.warn(0===A.current?"Cannot send feedback: the conversation has not started yet.":"Cannot send feedback: feedback has already been sent for the current response.")},[R,oe,re]);r.default.useCallback(function(e){console.warn("setVolume is not yet implemented in React Native SDK")},[]);var le=r.default.useCallback(function(){return P},[P]),ce=r.default.useCallback(function(e){H&&H.setMicrophoneEnabled(!e)},[H]),se=r.default.useCallback(function(e){U.current=e,re()},[re]),ie=r.default.useCallback(function(e){Q(e);var n=function(e){var n,t,o,r,a,c,s={type:"conversation_initiation_client_data"};return e.overrides&&(s.conversation_config_override={agent:{prompt:null==(t=e.overrides.agent)?void 0:t.prompt,first_message:null==(o=e.overrides.agent)?void 0:o.firstMessage,language:null==(r=e.overrides.agent)?void 0:r.language},tts:{voice_id:null==(a=e.overrides.tts)?void 0:a.voiceId},conversation:{text_only:null==(c=e.overrides.conversation)?void 0:c.textOnly}}),s.source_info={source:"react_native_sdk",version:(null==(n=e.overrides)||null==(n=n.client)?void 0:n.version)||l},e.customLlmExtraBody&&(s.custom_llm_extra_body=e.customLlmExtraBody),e.dynamicVariables&&(s.dynamic_variables=e.dynamicVariables),e.userId&&(s.user_id=String(e.userId)),s}({overrides:J,customLlmExtraBody:K,dynamicVariables:G,userId:z});if(n)try{var t=(new TextEncoder).encode(JSON.stringify(n));e.publishData(t,{reliable:!0})}catch(e){console.error("Failed to send overrides:",e),null==L.current.onError||L.current.onError(e)}},[Q,J,K,G,z,L]),ue=r.default.useCallback(function(e){F.current=e},[]),de=r.default.useCallback(function(e){oe({type:"contextual_update",text:e})},[oe]),fe=r.default.useCallback(function(e){oe({type:"user_message",text:e})},[oe]),ve=r.default.useCallback(function(){oe({type:"user_activity"})},[oe]),_e=r.default.useMemo(function(){return{startSession:q,endSession:B,status:g,isSpeaking:x,canSendFeedback:R,getId:le,setMicMuted:ce,sendFeedback:ae,sendContextualUpdate:de,sendUserMessage:fe,sendUserActivity:ve}},[q,B,g,x,R,le,ce,ae,de,fe,ve]),pe=r.default.useMemo(function(){return{conversation:_e,callbacksRef:L,serverUrl:C,tokenFetchUrl:y,clientTools:F.current,setCallbacks:O,setServerUrl:b,setTokenFetchUrl:S,setClientTools:ue}},[_e,L,C,y,O,ue]);/*#__PURE__*/return r.default.createElement(u.Provider,{value:pe},/*#__PURE__*/r.default.createElement(s,{key:P||"disconnected",serverUrl:C,token:i,connect:v,onConnected:ee,onDisconnected:ne,onError:$,roomConnected:Z,callbacks:L.current,onParticipantReady:ie,sendMessage:oe,clientTools:F.current,updateCurrentEventId:se,onEndSession:B},o))},e.useConversation=function(e){void 0===e&&(e={});var t=n.useContext(u);if(!t)throw new Error("useConversation must be used within ElevenLabsProvider");var o=e.serverUrl,a=e.tokenFetchUrl,l=e.clientTools,c=function(e,n){if(null==e)return{};var t={};for(var o in e)if({}.hasOwnProperty.call(e,o)){if(-1!==n.indexOf(o))continue;t[o]=e[o]}return t}(e,i);return r.default.useEffect(function(){o&&t.setServerUrl(o)},[t,o]),r.default.useEffect(function(){a&&t.setTokenFetchUrl(a)},[t,a]),r.default.useEffect(function(){l&&t.setClientTools(l)},[t,l]),t.setCallbacks(c),t.conversation}});
1
+ !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react"),require("@livekit/react-native"),require("livekit-client")):"function"==typeof define&&define.amd?define(["exports","react","@livekit/react-native","livekit-client"],n):n((e||self).reactNative={},e.react,e.reactNative,e.livekitClient)}(this,function(e,n,t,r){function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var a=/*#__PURE__*/o(n);function c(){return c=Object.assign?Object.assign.bind():function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)({}).hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e},c.apply(null,arguments)}var s="0.5.6",i=function(e){var o=e.onReady,c=e.isConnected,s=e.callbacks,i=e.sendMessage,u=e.clientTools,l=void 0===u?{}:u,d=e.updateCurrentEventId,f=e.onEndSession,v=t.useLocalParticipant().localParticipant,_=t.useRoomContext(),g=a.default.useRef(1),p=a.default.useRef(f);p.current=f;var C=a.default.useRef(o);C.current=o;var h=a.default.useRef(s);return h.current=s,n.useEffect(function(){var e=function(e){var n;null!=(n=e.identity)&&n.startsWith("agent")&&p.current("agent")};return _.on(r.RoomEvent.ParticipantDisconnected,e),function(){_.off(r.RoomEvent.ParticipantDisconnected,e)}},[_]),n.useEffect(function(){c||(g.current=1)},[c]),n.useEffect(function(){c&&v&&C.current(v)},[c,v]),t.useDataChannel(function(e){var n,t=new TextDecoder,r=JSON.parse(t.decode(e.payload));if("object"==typeof(o=r)&&null!==o&&"type"in o){var o,a,c=function(e){switch(e.type){case"user_transcript":return e.user_transcription_event.user_transcript;case"agent_response":return e.agent_response_event.agent_response;default:return null}}(r);if(null!==c&&(null==h.current.onMessage||h.current.onMessage({message:c,source:"user_transcript"===r.type?"user":"ai",role:"user_transcript"===r.type?"user":"agent"})),null!=(n=e.from)&&n.isAgent&&(null==h.current.onModeChange||h.current.onModeChange({mode:null!=(a=e.from)&&a.isSpeaking?"speaking":"listening"}),"agent_response"===r.type&&d)){var s=g.current++;d(s)}switch(r.type){case"ping":i({type:"pong",event_id:r.ping_event.event_id});break;case"client_tool_call":!function(e){try{return Promise.resolve(function(){if(e.client_tool_call.tool_name in l){var n=function(n,t){try{var r=Promise.resolve(l[e.client_tool_call.tool_name](e.client_tool_call.parameters)).then(function(n){var t="object"==typeof n?JSON.stringify(n):String(n);i({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:t,is_error:!1})})}catch(e){return t(e)}return r&&r.then?r.then(void 0,t):r}(0,function(n){null==h.current.onError||h.current.onError("Client tool execution failed with following error: "+(null==n?void 0:n.message),{clientToolName:e.client_tool_call.tool_name}),i({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:"Client tool execution failed: "+(null==n?void 0:n.message),is_error:!0})});if(n&&n.then)return n.then(function(){})}else{if(h.current.onUnhandledClientToolCall)return void h.current.onUnhandledClientToolCall(e.client_tool_call);var t="Client tool with name "+e.client_tool_call.tool_name+" is not defined on client";null==h.current.onError||h.current.onError(t,{clientToolName:e.client_tool_call.tool_name}),i({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:t,is_error:!0})}}())}catch(e){return Promise.reject(e)}}(r);break;case"audio":null==h.current.onAudio||h.current.onAudio(r.audio_event.audio_base_64);break;case"vad_score":null==h.current.onVadScore||h.current.onVadScore({vadScore:r.vad_score_event.vad_score});break;case"interruption":null==h.current.onInterruption||h.current.onInterruption(r.interruption_event);break;case"mcp_tool_call":null==h.current.onMCPToolCall||h.current.onMCPToolCall(r.mcp_tool_call);break;case"mcp_connection_status":null==h.current.onMCPConnectionStatus||h.current.onMCPConnectionStatus(r.mcp_connection_status);break;case"agent_tool_request":null==h.current.onAgentToolRequest||h.current.onAgentToolRequest(r.agent_tool_request);break;case"agent_tool_response":null==h.current.onAgentToolResponse||h.current.onAgentToolResponse(r.agent_tool_response),"end_call"===r.agent_tool_response.tool_name&&p.current("agent");break;case"conversation_initiation_metadata":null==h.current.onConversationMetadata||h.current.onConversationMetadata(r.conversation_initiation_metadata_event);break;case"asr_initiation_metadata":null==h.current.onAsrInitiationMetadata||h.current.onAsrInitiationMetadata(r.asr_initiation_metadata_event);break;case"agent_chat_response_part":null==h.current.onAgentChatResponsePart||h.current.onAgentChatResponsePart(r.text_response_part);break;default:null==h.current.onDebug||h.current.onDebug(r)}}else null==h.current.onDebug||h.current.onDebug({type:"invalid_event",message:r})}),null},u=function(e){var n=e.children,r=e.serverUrl,o=e.token,c=e.connect,s=e.onConnected,u=e.onDisconnected,l=e.onError,d=e.roomConnected,f=e.callbacks,v=e.onParticipantReady,_=e.sendMessage,g=e.clientTools,p=e.updateCurrentEventId,C=e.onEndSession,h=e.audioSessionConfig,k=a.default.useMemo(function(){return null==h||!h.allowMixingWithOthers||{audio:{noiseSuppression:!0,echoCancellation:!0},audioSessionConfiguration:{allowMixingWithOthers:!0}}},[h]);/*#__PURE__*/return a.default.createElement(t.LiveKitRoom,{serverUrl:r,token:o,connect:c,audio:k,video:!1,options:{adaptiveStream:{pixelDensity:"screen"}},onConnected:s,onDisconnected:u,onError:l},/*#__PURE__*/a.default.createElement(i,{onReady:v,isConnected:d,callbacks:f,sendMessage:_,clientTools:g,updateCurrentEventId:p,onEndSession:C}),n)},l=["serverUrl","tokenFetchUrl","clientTools"],d=/*#__PURE__*/n.createContext(null);e.ElevenLabsProvider=function(e){var r=e.children,o=e.audioSessionConfig;t.registerGlobals();var i=n.useState(""),l=i[0],f=i[1],v=n.useState(!1),_=v[0],g=v[1],p=n.useState("disconnected"),C=p[0],h=p[1],k=n.useState("wss://livekit.rtc.elevenlabs.io"),b=k[0],m=k[1],S=n.useState(void 0),y=S[0],E=S[1],M=n.useState(""),P=M[0],x=M[1],R=n.useState(!1),T=R[0],w=R[1],U=n.useState(!1),I=U[0],F=U[1],D=a.default.useRef(1),A=a.default.useRef(1),j=a.default.useRef({}),O=function(){var e=n.useRef({}),t=n.useCallback(function(n){e.current=n},[]);return{callbacksRef:e,setCallbacks:t}}(),L=O.callbacksRef,N=O.setCallbacks,V=a.default.useCallback(function(e){var n=c({},e,{onModeChange:function(n){w("speaking"===n.mode),null==e.onModeChange||e.onModeChange(n)}});N(n)},[N]),q=function(e,t,r,o,a,c){var i=n.useState({}),u=i[0],l=i[1],d=n.useState(null),f=d[0],v=d[1],_=n.useState({}),g=_[0],p=_[1],C=n.useState(void 0),h=C[0],k=C[1];return{startSession:n.useCallback(function(n){try{return Promise.resolve(function(i,u){try{var d=function(){function i(e){var n=function(e){try{var n,t;return(null==(t=((null==(n=JSON.parse(atob(e.split(".")[1])).video)?void 0:n.room)||"").match(/(conv_[a-zA-Z0-9]+)/))?void 0:t[0])||""}catch(e){return console.warn("Could not extract conversation ID from token"),""}}(u);a(n),o(u),r(!0)}var u;t("connecting"),null==e.current.onStatusChange||e.current.onStatusChange({status:"connecting"}),l(n.overrides||{}),v(n.customLlmExtraBody||null),p(n.dynamicVariables||{}),k(n.userId);var d=function(){if(!n.conversationToken)return function(){if(n.agentId)return console.info("Getting conversation token for agentId:",n.agentId),Promise.resolve(function(e,n){try{return Promise.resolve(fetch((n||"https://api.elevenlabs.io/v1/convai/conversation/token")+"?agent_id="+e+"&source=react_native_sdk&version="+s)).then(function(e){return Promise.resolve(e.json()).then(function(n){if(!e.ok)throw new Error("Failed to get conversation token: "+n.detail.message);if(!n.token)throw new Error("No conversation token received from API");return n.token})})}catch(e){return Promise.reject(e)}}(n.agentId,n.tokenFetchUrl||c)).then(function(e){u=e});throw new Error("Either conversationToken or agentId is required")}();u=n.conversationToken}();return d&&d.then?d.then(i):i()}()}catch(e){return u(e)}return d&&d.then?d.then(void 0,u):d}(0,function(n){throw t("disconnected"),null==e.current.onStatusChange||e.current.onStatusChange({status:"disconnected"}),null==e.current.onError||e.current.onError(n),n}))}catch(e){return Promise.reject(e)}},[e,t,r,o,a,c]),endSession:n.useCallback(function(n){void 0===n&&(n="user");try{try{r(!1),o(""),t("disconnected"),l({}),v(null),p({}),k(void 0),a(""),null==e.current.onStatusChange||e.current.onStatusChange({status:"disconnected"}),null==e.current.onDisconnect||e.current.onDisconnect({reason:n})}catch(n){throw null==e.current.onError||e.current.onError(n),n}return Promise.resolve()}catch(e){return Promise.reject(e)}},[e,r,o,t,a]),overrides:u,customLlmExtraBody:f,dynamicVariables:g,userId:h}}(L,h,g,f,x,y),B=q.startSession,J=q.endSession,W=q.overrides,K=q.customLlmExtraBody,G=q.dynamicVariables,z=q.userId,Z=function(e,r,o,a){var c=n.useState(!1),s=c[0],i=c[1],u=n.useState(null),l=u[0],d=u[1],f=n.useRef(!1);n.useEffect(function(){o&&(i(!1),d(null),f.current=!1)},[o]),n.useEffect(function(){return function(){try{return Promise.resolve(t.AudioSession.startAudioSession()).then(function(){})}catch(e){return Promise.reject(e)}}(),function(){t.AudioSession.stopAudioSession()}},[]),n.useEffect(function(){l&&s&&!f.current&&(f.current=!0,null==e.current.onConnect||e.current.onConnect({conversationId:o}))},[l,s,o,e]);var v=n.useCallback(function(e){l||(d(e),r("connected"))},[l,r]),_=n.useCallback(function(){i(!0)},[]),g=n.useCallback(function(){"disconnected"!==a&&(i(!1),r("disconnected"),d(null),f.current=!1,null==e.current.onDisconnect||e.current.onDisconnect({reason:"user"}))},[e,r,a]),p=n.useCallback(function(n){console.error("LiveKit error:",n),null==e.current.onError||e.current.onError(n.message,void 0)},[e]);return{roomConnected:s,localParticipant:l,handleParticipantReady:v,handleConnected:_,handleDisconnected:g,handleError:p}}(L,h,P,C),H=Z.roomConnected,Q=Z.localParticipant,X=Z.handleParticipantReady,Y=Z.handleConnected,$=Z.handleDisconnected,ee=Z.handleError,ne=a.default.useCallback(function(){D.current=1,A.current=1,F(!1),null==L.current.onCanSendFeedbackChange||L.current.onCanSendFeedbackChange({canSendFeedback:!1}),Y()},[Y,L]),te=a.default.useCallback(function(){F(!1),w(!1),$()},[$]),re=function(e,t,r){return{sendMessage:n.useCallback(function(n){try{if("connected"!==e||!t)return console.warn("Cannot send message: room not connected or no local participant"),Promise.resolve();var o=function(e,r){try{var o=(a=(new TextEncoder).encode(JSON.stringify(n)),Promise.resolve(t.publishData(a,{reliable:!0})).then(function(){}))}catch(e){return r(e)}var a;return o&&o.then?o.then(void 0,r):o}(0,function(e){console.error("Failed to send message via WebRTC:",e),console.error("Error details:",e),null==r.current.onError||r.current.onError(e)});return Promise.resolve(o&&o.then?o.then(function(){}):void 0)}catch(e){return Promise.reject(e)}},[e,t,r])}}(C,Q,L),oe=re.sendMessage,ae=a.default.useCallback(function(){var e=D.current!==A.current;I!==e&&(F(e),null==L.current.onCanSendFeedbackChange||L.current.onCanSendFeedbackChange({canSendFeedback:e}))},[I,L]),ce=a.default.useCallback(function(e){I?(oe({type:"feedback",score:e?"like":"dislike",event_id:D.current}),A.current=D.current,ae()):console.warn(0===A.current?"Cannot send feedback: the conversation has not started yet.":"Cannot send feedback: feedback has already been sent for the current response.")},[I,oe,ae]);a.default.useCallback(function(e){console.warn("setVolume is not yet implemented in React Native SDK")},[]);var se=a.default.useCallback(function(){return P},[P]),ie=a.default.useCallback(function(e){Q&&Q.setMicrophoneEnabled(!e)},[Q]),ue=a.default.useCallback(function(e){D.current=e,ae()},[ae]),le=a.default.useCallback(function(e){X(e);var n=function(e){var n,t,r,o,a,c,i,u={type:"conversation_initiation_client_data"};return e.overrides&&(u.conversation_config_override={agent:{prompt:null==(t=e.overrides.agent)?void 0:t.prompt,first_message:null==(r=e.overrides.agent)?void 0:r.firstMessage,language:null==(o=e.overrides.agent)?void 0:o.language},tts:{voice_id:null==(a=e.overrides.tts)?void 0:a.voiceId,speed:null==(c=e.overrides.tts)?void 0:c.speed},conversation:{text_only:null==(i=e.overrides.conversation)?void 0:i.textOnly}}),u.source_info={source:"react_native_sdk",version:(null==(n=e.overrides)||null==(n=n.client)?void 0:n.version)||s},e.customLlmExtraBody&&(u.custom_llm_extra_body=e.customLlmExtraBody),e.dynamicVariables&&(u.dynamic_variables=e.dynamicVariables),e.userId&&(u.user_id=String(e.userId)),u}({overrides:W,customLlmExtraBody:K,dynamicVariables:G,userId:z});if(n)try{var t=(new TextEncoder).encode(JSON.stringify(n));e.publishData(t,{reliable:!0})}catch(e){console.error("Failed to send overrides:",e),null==L.current.onError||L.current.onError(e)}},[X,W,K,G,z,L]),de=a.default.useCallback(function(e){j.current=e},[]),fe=a.default.useCallback(function(e){oe({type:"contextual_update",text:e})},[oe]),ve=a.default.useCallback(function(e){oe({type:"user_message",text:e})},[oe]),_e=a.default.useCallback(function(){oe({type:"user_activity"})},[oe]),ge=a.default.useRef({startSession:B,endSession:J,status:C,isSpeaking:T,canSendFeedback:I,getId:se,setMicMuted:ie,sendFeedback:ce,sendContextualUpdate:fe,sendUserMessage:ve,sendUserActivity:_e});ge.current={startSession:B,endSession:J,status:C,isSpeaking:T,canSendFeedback:I,getId:se,setMicMuted:ie,sendFeedback:ce,sendContextualUpdate:fe,sendUserMessage:ve,sendUserActivity:_e};var pe=a.default.useMemo(function(){return{get startSession(){return ge.current.startSession},get endSession(){return ge.current.endSession},get status(){return ge.current.status},get isSpeaking(){return ge.current.isSpeaking},get canSendFeedback(){return ge.current.canSendFeedback},get getId(){return ge.current.getId},get setMicMuted(){return ge.current.setMicMuted},get sendFeedback(){return ge.current.sendFeedback},get sendContextualUpdate(){return ge.current.sendContextualUpdate},get sendUserMessage(){return ge.current.sendUserMessage},get sendUserActivity(){return ge.current.sendUserActivity}}},[]),Ce=a.default.useMemo(function(){return{conversation:pe,callbacksRef:L,serverUrl:b,tokenFetchUrl:y,clientTools:j.current,setCallbacks:V,setServerUrl:m,setTokenFetchUrl:E,setClientTools:de}},[pe,L,b,y,V,de]);/*#__PURE__*/return a.default.createElement(d.Provider,{value:Ce},/*#__PURE__*/a.default.createElement(u,{serverUrl:b,token:l,connect:_,onConnected:ne,onDisconnected:te,onError:ee,roomConnected:H,callbacks:L.current,onParticipantReady:le,sendMessage:oe,clientTools:j.current,updateCurrentEventId:ue,onEndSession:J,audioSessionConfig:o},r))},e.useConversation=function(e){void 0===e&&(e={});var t=n.useContext(d);if(!t)throw new Error("useConversation must be used within ElevenLabsProvider");var r=e.serverUrl,o=e.tokenFetchUrl,c=e.clientTools,s=function(e,n){if(null==e)return{};var t={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(-1!==n.indexOf(r))continue;t[r]=e[r]}return t}(e,l);return a.default.useEffect(function(){r&&t.setServerUrl(r)},[t,r]),a.default.useEffect(function(){o&&t.setTokenFetchUrl(o)},[t,o]),a.default.useEffect(function(){c&&t.setClientTools(c)},[t,c]),t.setCallbacks(s),t.conversation}});
2
2
  //# sourceMappingURL=lib.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lib.umd.js","sources":["../src/version.ts","../src/components/MessageHandler.tsx","../src/components/LiveKitRoomWrapper.tsx","../src/ElevenLabsProvider.tsx","../src/utils/constants.ts","../src/hooks/useConversationCallbacks.ts","../src/hooks/useConversationSession.ts","../src/utils/tokenUtils.ts","../src/hooks/useLiveKitRoom.ts","../src/hooks/useMessageSending.ts","../src/utils/overrides.ts"],"sourcesContent":["// This file is auto-generated during build\nexport const PACKAGE_VERSION = \"0.5.4\";\n","import { useEffect } from \"react\";\nimport { useLocalParticipant, useDataChannel } from \"@livekit/react-native\";\nimport type { LocalParticipant } from \"livekit-client\";\nimport type {\n Callbacks,\n ClientToolsConfig,\n ClientToolCallEvent,\n ConversationEvent,\n} from \"../types\";\nimport React from \"react\";\n\ninterface MessageHandlerProps {\n onReady: (participant: LocalParticipant) => void;\n isConnected: boolean;\n callbacks: Callbacks;\n sendMessage: (message: unknown) => void;\n onEndSession: (reason: \"user\" | \"agent\") => void;\n clientTools?: ClientToolsConfig[\"clientTools\"];\n updateCurrentEventId?: (eventId: number) => void;\n}\n\nexport function isValidEvent(event: unknown): event is ConversationEvent {\n return typeof event === \"object\" && event !== null && \"type\" in event;\n}\n\nfunction extractMessageText(event: ConversationEvent): string | null {\n switch (event.type) {\n case \"user_transcript\":\n return event.user_transcription_event.user_transcript;\n case \"agent_response\":\n return event.agent_response_event.agent_response;\n default:\n return null;\n }\n}\n\nexport const MessageHandler = ({\n onReady,\n isConnected,\n callbacks,\n sendMessage,\n clientTools = {},\n updateCurrentEventId,\n onEndSession,\n}: MessageHandlerProps) => {\n const { localParticipant } = useLocalParticipant();\n\n // Track agent response count for synthetic event IDs (WebRTC mode)\n const agentResponseCountRef = React.useRef(1);\n\n // Reset agent response count when connection status changes\n useEffect(() => {\n if (!isConnected) {\n agentResponseCountRef.current = 1;\n }\n }, [isConnected]);\n\n useEffect(() => {\n if (isConnected && localParticipant) {\n onReady(localParticipant);\n }\n }, [isConnected, localParticipant, onReady]);\n\n const handleClientToolCall = async (clientToolCall: ClientToolCallEvent) => {\n if (clientToolCall.client_tool_call.tool_name in clientTools) {\n try {\n const result =\n (await clientTools[clientToolCall.client_tool_call.tool_name](\n clientToolCall.client_tool_call.parameters\n )) ?? \"Client tool execution successful.\"; // default client-tool call response\n\n // The API expects result to be a string, so we need to convert it if it's not already a string\n const formattedResult =\n typeof result === \"object\" ? JSON.stringify(result) : String(result);\n\n sendMessage({\n type: \"client_tool_result\",\n tool_call_id: clientToolCall.client_tool_call.tool_call_id,\n result: formattedResult,\n is_error: false,\n });\n } catch (e) {\n const errorMessage = `Client tool execution failed with following error: ${(e as Error)?.message}`;\n callbacks.onError?.(errorMessage, {\n clientToolName: clientToolCall.client_tool_call.tool_name,\n });\n sendMessage({\n type: \"client_tool_result\",\n tool_call_id: clientToolCall.client_tool_call.tool_call_id,\n result: `Client tool execution failed: ${(e as Error)?.message}`,\n is_error: true,\n });\n }\n } else {\n if (callbacks.onUnhandledClientToolCall) {\n callbacks.onUnhandledClientToolCall(clientToolCall.client_tool_call);\n return;\n }\n\n const errorMessage = `Client tool with name ${clientToolCall.client_tool_call.tool_name} is not defined on client`;\n callbacks.onError?.(errorMessage, {\n clientToolName: clientToolCall.client_tool_call.tool_name,\n });\n sendMessage({\n type: \"client_tool_result\",\n tool_call_id: clientToolCall.client_tool_call.tool_call_id,\n result: errorMessage,\n is_error: true,\n });\n }\n };\n\n const _ = useDataChannel(msg => {\n const decoder = new TextDecoder();\n const message = JSON.parse(decoder.decode(msg.payload));\n\n if (!isValidEvent(message)) {\n callbacks.onDebug?.({\n type: \"invalid_event\",\n message,\n });\n return;\n }\n\n const messageText = extractMessageText(message);\n if (messageText !== null) {\n callbacks.onMessage?.({\n message: messageText,\n source: message.type === \"user_transcript\" ? \"user\" : \"ai\",\n });\n }\n\n if (msg.from?.isAgent) {\n callbacks.onModeChange?.({\n mode: msg.from?.isSpeaking ? \"speaking\" : \"listening\",\n });\n\n // Track agent responses for feedback (WebRTC mode needs synthetic event IDs)\n if (message.type === \"agent_response\" && updateCurrentEventId) {\n const eventId = agentResponseCountRef.current++;\n updateCurrentEventId(eventId);\n }\n }\n\n switch (message.type) {\n case \"ping\":\n sendMessage({\n type: \"pong\",\n event_id: message.ping_event.event_id,\n });\n break;\n case \"client_tool_call\":\n handleClientToolCall(message);\n break;\n case \"audio\":\n callbacks.onAudio?.(message.audio_event.audio_base_64);\n break;\n case \"vad_score\":\n callbacks.onVadScore?.({\n vadScore: message.vad_score_event.vad_score,\n });\n break;\n case \"interruption\":\n callbacks.onInterruption?.(message.interruption_event);\n break;\n case \"mcp_tool_call\":\n callbacks.onMCPToolCall?.(message.mcp_tool_call);\n break;\n case \"mcp_connection_status\":\n callbacks.onMCPConnectionStatus?.(message.mcp_connection_status);\n break;\n case \"agent_tool_request\":\n callbacks.onAgentToolRequest?.(message.agent_tool_request);\n break;\n case \"agent_tool_response\":\n callbacks.onAgentToolResponse?.(message.agent_tool_response);\n\n if (message.agent_tool_response.tool_name === \"end_call\") {\n // End the call\n onEndSession(\"agent\");\n }\n break;\n case \"conversation_initiation_metadata\":\n callbacks.onConversationMetadata?.(\n message.conversation_initiation_metadata_event\n );\n break;\n case \"asr_initiation_metadata\":\n callbacks.onAsrInitiationMetadata?.(\n message.asr_initiation_metadata_event\n );\n break;\n case \"agent_chat_response_part\":\n callbacks.onAgentChatResponsePart?.(message.text_response_part);\n break;\n default:\n callbacks.onDebug?.(message);\n break;\n }\n });\n\n return null;\n};\n","// @ts-nocheck - pnpm hoisting causes duplicate React type definitions\nimport React from 'react';\nimport { LiveKitRoom } from '@livekit/react-native';\nimport type { LocalParticipant } from 'livekit-client';\nimport type { Callbacks, ClientToolsConfig } from '../types';\nimport { MessageHandler } from './MessageHandler';\n\ninterface LiveKitRoomWrapperProps {\n children: React.ReactNode;\n serverUrl: string;\n token: string;\n connect: boolean;\n onConnected: () => void;\n onDisconnected: () => void;\n onError: (error: Error) => void;\n roomConnected: boolean;\n callbacks: Callbacks;\n onParticipantReady: (participant: LocalParticipant) => void;\n sendMessage: (message: unknown) => void;\n clientTools: ClientToolsConfig['clientTools'];\n onEndSession: (reason?: \"user\" | \"agent\") => void;\n updateCurrentEventId?: (eventId: number) => void;\n}\n\nexport const LiveKitRoomWrapper = ({\n children,\n serverUrl,\n token,\n connect,\n onConnected,\n onDisconnected,\n onError,\n roomConnected,\n callbacks,\n onParticipantReady,\n sendMessage,\n clientTools,\n updateCurrentEventId,\n onEndSession,\n}: LiveKitRoomWrapperProps) => {\n return (\n <LiveKitRoom\n serverUrl={serverUrl}\n token={token}\n connect={connect}\n audio={true}\n video={false}\n options={{\n adaptiveStream: { pixelDensity: 'screen' },\n }}\n onConnected={onConnected}\n onDisconnected={onDisconnected}\n onError={onError}\n >\n <MessageHandler\n onReady={onParticipantReady}\n isConnected={roomConnected}\n callbacks={callbacks}\n sendMessage={sendMessage}\n clientTools={clientTools}\n updateCurrentEventId={updateCurrentEventId}\n onEndSession={onEndSession}\n />\n {children as any}\n </LiveKitRoom>\n );\n};","import React from 'react';\nimport { createContext, useContext, useState } from 'react';\nimport { registerGlobals } from '@livekit/react-native';\nimport type { LocalParticipant } from 'livekit-client';\nimport type { Callbacks, ConversationConfig, ConversationStatus, ClientToolsConfig } from './types';\nimport { constructOverrides } from './utils/overrides';\nimport { DEFAULT_SERVER_URL } from './utils/constants';\nimport { useConversationCallbacks } from './hooks/useConversationCallbacks';\nimport { useConversationSession } from './hooks/useConversationSession';\nimport { useLiveKitRoom } from './hooks/useLiveKitRoom';\nimport { useMessageSending } from './hooks/useMessageSending';\nimport { LiveKitRoomWrapper } from './components/LiveKitRoomWrapper';\n\ninterface ConversationOptions extends Callbacks, Partial<ClientToolsConfig> {\n serverUrl?: string;\n tokenFetchUrl?: string;\n}\n\nexport interface Conversation {\n startSession: (config: ConversationConfig) => Promise<void>;\n endSession: (reason?: \"user\" | \"agent\") => Promise<void>;\n status: ConversationStatus;\n isSpeaking: boolean;\n // TODO: Implement setVolume when LiveKit React Native supports it\n // setVolume: (volume: number) => void;\n canSendFeedback: boolean;\n getId: () => string;\n sendFeedback: (like: boolean) => void;\n sendContextualUpdate: (text: string) => void;\n sendUserMessage: (text: string) => void;\n sendUserActivity: () => void;\n setMicMuted: (muted: boolean) => void;\n}\n\ninterface ElevenLabsContextType {\n conversation: Conversation;\n callbacksRef: { current: Callbacks };\n serverUrl: string;\n tokenFetchUrl?: string;\n clientTools: ClientToolsConfig['clientTools'];\n setCallbacks: (callbacks: Callbacks) => void;\n setServerUrl: (url: string) => void;\n setTokenFetchUrl: (url: string) => void;\n setClientTools: (tools: ClientToolsConfig['clientTools']) => void;\n}\n\nconst ElevenLabsContext = createContext<ElevenLabsContextType | null>(null);\n\nexport const useConversation = (options: ConversationOptions = {}): Conversation => {\n const context = useContext(ElevenLabsContext);\n if (!context) {\n throw new Error('useConversation must be used within ElevenLabsProvider');\n }\n\n const { serverUrl, tokenFetchUrl, clientTools, ...callbacks } = options;\n\n React.useEffect(() => {\n if (serverUrl) {\n context.setServerUrl(serverUrl);\n }\n }, [context, serverUrl]);\n\n React.useEffect(() => {\n if (tokenFetchUrl) {\n context.setTokenFetchUrl(tokenFetchUrl);\n }\n }, [context, tokenFetchUrl]);\n\n React.useEffect(() => {\n if (clientTools) {\n context.setClientTools(clientTools);\n }\n }, [context, clientTools]);\n\n // Update callbacks - since this only updates a ref, it's safe to call on every render\n // and doesn't cause re-renders of the provider or its consumers\n context.setCallbacks(callbacks);\n\n return context.conversation;\n};\n\ninterface ElevenLabsProviderProps {\n children: React.ReactNode;\n}\n\nexport const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children }) => {\n // Initialize globals on mount\n registerGlobals();\n\n // State management\n const [token, setToken] = useState('');\n const [connect, setConnect] = useState(false);\n const [status, setStatus] = useState<ConversationStatus>('disconnected');\n const [serverUrl, setServerUrl] = useState(DEFAULT_SERVER_URL);\n const [tokenFetchUrl, setTokenFetchUrl] = useState<string | undefined>(undefined);\n const [conversationId, setConversationId] = useState<string>('');\n const [isSpeaking, setIsSpeaking] = useState(false);\n const [canSendFeedback, setCanSendFeedback] = useState(false);\n\n // Feedback state tracking\n const currentEventIdRef = React.useRef(1);\n const lastFeedbackEventIdRef = React.useRef(1);\n\n // Use ref for clientTools to avoid re-renders (like callbacks)\n const clientToolsRef = React.useRef<ClientToolsConfig['clientTools']>({});\n\n // Custom hooks\n const { callbacksRef, setCallbacks: setCallbacksBase } = useConversationCallbacks();\n\n // Enhanced setCallbacks that wraps onModeChange to update isSpeaking state\n const setCallbacks = React.useCallback((callbacks: Callbacks) => {\n const wrappedCallbacks = {\n ...callbacks,\n onModeChange: (event: { mode: 'speaking' | 'listening' }) => {\n setIsSpeaking(event.mode === 'speaking');\n callbacks.onModeChange?.(event);\n }\n };\n setCallbacksBase(wrappedCallbacks);\n }, [setCallbacksBase]);\n\n const {\n startSession,\n endSession,\n overrides,\n customLlmExtraBody,\n dynamicVariables,\n userId,\n } = useConversationSession(callbacksRef, setStatus, setConnect, setToken, setConversationId, tokenFetchUrl);\n\n const {\n roomConnected,\n localParticipant,\n handleParticipantReady,\n handleConnected,\n handleDisconnected,\n handleError,\n } = useLiveKitRoom(callbacksRef, setStatus, conversationId, status);\n\n // Enhanced connection handler to initialize feedback state\n const handleConnectedWithFeedback = React.useCallback(() => {\n // Reset feedback state when connecting\n currentEventIdRef.current = 1;\n lastFeedbackEventIdRef.current = 1;\n setCanSendFeedback(false);\n callbacksRef.current.onCanSendFeedbackChange?.({ canSendFeedback: false });\n\n handleConnected();\n }, [handleConnected, callbacksRef]);\n\n // Enhanced disconnection handler to reset feedback state\n const handleDisconnectedWithFeedback = React.useCallback(() => {\n setCanSendFeedback(false);\n setIsSpeaking(false);\n handleDisconnected();\n }, [handleDisconnected]);\n\n const { sendMessage } = useMessageSending(status, localParticipant, callbacksRef);\n\n const updateCanSendFeedback = React.useCallback(() => {\n const newCanSendFeedback = currentEventIdRef.current !== lastFeedbackEventIdRef.current;\n\n if (canSendFeedback !== newCanSendFeedback) {\n setCanSendFeedback(newCanSendFeedback);\n callbacksRef.current.onCanSendFeedbackChange?.({ canSendFeedback: newCanSendFeedback });\n }\n }, [canSendFeedback, callbacksRef]);\n\n const sendFeedback = React.useCallback((like: boolean) => {\n if (!canSendFeedback) {\n console.warn(\n lastFeedbackEventIdRef.current === 0\n ? \"Cannot send feedback: the conversation has not started yet.\"\n : \"Cannot send feedback: feedback has already been sent for the current response.\"\n );\n return;\n }\n\n const feedbackMessage = {\n type: \"feedback\",\n score: like ? \"like\" : \"dislike\",\n event_id: currentEventIdRef.current,\n };\n\n sendMessage(feedbackMessage);\n lastFeedbackEventIdRef.current = currentEventIdRef.current;\n updateCanSendFeedback();\n }, [canSendFeedback, sendMessage, updateCanSendFeedback]);\n\n // setVolume placeholder (to be implemented when LiveKit supports it)\n const setVolume = React.useCallback((volume: number) => {\n console.warn('setVolume is not yet implemented in React Native SDK');\n }, []);\n\n const getId = React.useCallback(() => conversationId, [conversationId]);\n\n const setMicMuted = React.useCallback((muted: boolean) => {\n if (localParticipant) {\n localParticipant.setMicrophoneEnabled(!muted);\n }\n }, [localParticipant]);\n\n // Update current event ID for feedback tracking\n const updateCurrentEventId = React.useCallback((eventId: number) => {\n currentEventIdRef.current = eventId;\n updateCanSendFeedback();\n }, [updateCanSendFeedback]);\n\n // Handle participant ready with overrides\n const handleParticipantReadyWithOverrides = React.useCallback((participant: LocalParticipant) => {\n handleParticipantReady(participant);\n\n const overridesEvent = constructOverrides({\n overrides,\n customLlmExtraBody,\n dynamicVariables,\n userId,\n });\n\n if (overridesEvent) {\n try {\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify(overridesEvent));\n participant.publishData(data, { reliable: true });\n } catch (error) {\n console.error(\"Failed to send overrides:\", error);\n callbacksRef.current.onError?.(error as string);\n }\n }\n }, [handleParticipantReady, overrides, customLlmExtraBody, dynamicVariables, userId, callbacksRef]);\n\n // Create setClientTools function that only updates ref\n const setClientTools = React.useCallback((tools: ClientToolsConfig['clientTools']) => {\n clientToolsRef.current = tools;\n }, []);\n\n // Memoize inline callback functions\n const sendContextualUpdate = React.useCallback((text: string) => {\n sendMessage({\n type: \"contextual_update\",\n text,\n });\n }, [sendMessage]);\n\n const sendUserMessage = React.useCallback((text: string) => {\n sendMessage({\n type: \"user_message\",\n text,\n });\n }, [sendMessage]);\n\n const sendUserActivity = React.useCallback(() => {\n sendMessage({\n type: \"user_activity\",\n });\n }, [sendMessage]);\n\n // Memoize the conversation object to prevent unnecessary re-renders\n const conversation = React.useMemo<Conversation>(() => ({\n startSession,\n endSession,\n status,\n isSpeaking,\n canSendFeedback,\n getId,\n setMicMuted,\n sendFeedback,\n sendContextualUpdate,\n sendUserMessage,\n sendUserActivity,\n }), [\n startSession,\n endSession,\n status,\n isSpeaking,\n canSendFeedback,\n getId,\n setMicMuted,\n sendFeedback,\n sendContextualUpdate,\n sendUserMessage,\n sendUserActivity,\n ]);\n\n // Memoize the context value to prevent unnecessary re-renders of consumers\n const contextValue = React.useMemo<ElevenLabsContextType>(() => ({\n conversation,\n callbacksRef,\n serverUrl,\n tokenFetchUrl,\n clientTools: clientToolsRef.current,\n setCallbacks,\n setServerUrl,\n setTokenFetchUrl,\n setClientTools,\n }), [\n conversation,\n callbacksRef,\n serverUrl,\n tokenFetchUrl,\n setCallbacks,\n setClientTools,\n ]);\n\n return (\n <ElevenLabsContext.Provider value={contextValue}>\n <LiveKitRoomWrapper\n key={conversationId || 'disconnected'}\n serverUrl={serverUrl}\n token={token}\n connect={connect}\n onConnected={handleConnectedWithFeedback}\n onDisconnected={handleDisconnectedWithFeedback}\n onError={handleError}\n roomConnected={roomConnected}\n callbacks={callbacksRef.current}\n onParticipantReady={handleParticipantReadyWithOverrides}\n sendMessage={sendMessage}\n clientTools={clientToolsRef.current}\n updateCurrentEventId={updateCurrentEventId}\n onEndSession={endSession}\n >\n {children}\n </LiveKitRoomWrapper>\n </ElevenLabsContext.Provider>\n );\n};\n","export const DEFAULT_SERVER_URL = \"wss://livekit.rtc.elevenlabs.io\";\n","import { useRef, useCallback } from \"react\";\nimport type { Callbacks } from \"../types\";\n\nexport const useConversationCallbacks = () => {\n const callbacksRef = useRef<Callbacks>({});\n\n const setCallbacks = useCallback((callbacks: Callbacks) => {\n callbacksRef.current = callbacks;\n }, []);\n\n return {\n callbacksRef,\n setCallbacks,\n };\n};\n","import { useState, useCallback } from \"react\";\nimport type {\n ConversationConfig,\n ConversationStatus,\n Callbacks,\n} from \"../types\";\nimport {\n getConversationToken,\n extractConversationIdFromToken,\n} from \"../utils/tokenUtils\";\n\nexport const useConversationSession = (\n callbacksRef: { current: Callbacks },\n setStatus: (status: ConversationStatus) => void,\n setConnect: (connect: boolean) => void,\n setToken: (token: string) => void,\n setConversationId: (conversationId: string) => void,\n tokenFetchUrl?: string\n) => {\n const [overrides, setOverrides] = useState<ConversationConfig[\"overrides\"]>(\n {}\n );\n const [customLlmExtraBody, setCustomLlmExtraBody] =\n useState<ConversationConfig[\"customLlmExtraBody\"]>(null);\n const [dynamicVariables, setDynamicVariables] = useState<\n ConversationConfig[\"dynamicVariables\"]\n >({});\n const [userId, setUserId] = useState<ConversationConfig[\"userId\"]>(undefined);\n\n const startSession = useCallback(\n async (config: ConversationConfig) => {\n try {\n setStatus(\"connecting\");\n callbacksRef.current.onStatusChange?.({ status: \"connecting\" });\n\n setOverrides(config.overrides || {});\n setCustomLlmExtraBody(config.customLlmExtraBody || null);\n setDynamicVariables(config.dynamicVariables || {});\n setUserId(config.userId);\n\n let conversationToken: string;\n\n if (config.conversationToken) {\n conversationToken = config.conversationToken;\n } else if (config.agentId) {\n console.info(\n \"Getting conversation token for agentId:\",\n config.agentId\n );\n // Use tokenFetchUrl from config first, then from hook parameter, then default\n const urlToUse = config.tokenFetchUrl || tokenFetchUrl;\n conversationToken = await getConversationToken(\n config.agentId,\n urlToUse\n );\n } else {\n throw new Error(\"Either conversationToken or agentId is required\");\n }\n\n const extractedConversationId =\n extractConversationIdFromToken(conversationToken);\n setConversationId(extractedConversationId);\n\n setToken(conversationToken);\n setConnect(true);\n } catch (error) {\n setStatus(\"disconnected\");\n callbacksRef.current.onStatusChange?.({ status: \"disconnected\" });\n callbacksRef.current.onError?.(error as string);\n throw error;\n }\n },\n [\n callbacksRef,\n setStatus,\n setConnect,\n setToken,\n setConversationId,\n tokenFetchUrl,\n ]\n );\n\n const endSession = useCallback(\n async (reason: \"user\" | \"agent\" = \"user\") => {\n try {\n setConnect(false);\n setToken(\"\");\n setStatus(\"disconnected\");\n\n // Reset session configuration state\n setOverrides({});\n setCustomLlmExtraBody(null);\n setDynamicVariables({});\n setUserId(undefined);\n setConversationId(\"\");\n\n callbacksRef.current.onStatusChange?.({ status: \"disconnected\" });\n callbacksRef.current.onDisconnect?.({ reason });\n } catch (error) {\n callbacksRef.current.onError?.(error as string);\n throw error;\n }\n },\n [callbacksRef, setConnect, setToken, setStatus, setConversationId]\n );\n\n return {\n startSession,\n endSession,\n overrides,\n customLlmExtraBody,\n dynamicVariables,\n userId,\n };\n};\n","import { PACKAGE_VERSION } from \"../version\";\n\nexport const extractConversationIdFromToken = (token: string): string => {\n try {\n const tokenPayload = JSON.parse(atob(token.split(\".\")[1]));\n const roomId = tokenPayload.video?.room || \"\";\n\n return roomId.match(/(conv_[a-zA-Z0-9]+)/)?.[0] || \"\";\n } catch (error) {\n console.warn(\"Could not extract conversation ID from token\");\n return \"\";\n }\n};\n\nexport const getConversationToken = async (\n agentId: string,\n tokenFetchUrl?: string\n): Promise<string> => {\n const baseUrl =\n tokenFetchUrl || \"https://api.elevenlabs.io/v1/convai/conversation/token\";\n const response = await fetch(\n `${baseUrl}?agent_id=${agentId}&source=react_native_sdk&version=${PACKAGE_VERSION}`\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n throw new Error(`Failed to get conversation token: ${data.detail.message}`);\n }\n\n if (!data.token) {\n throw new Error(\"No conversation token received from API\");\n }\n\n return data.token;\n};\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { AudioSession } from \"@livekit/react-native\";\nimport type { LocalParticipant } from \"livekit-client\";\nimport type { ConversationStatus, Callbacks } from \"../types\";\n\nexport const useLiveKitRoom = (\n callbacksRef: { current: Callbacks },\n setStatus: (status: ConversationStatus) => void,\n conversationId: string,\n status: ConversationStatus\n) => {\n const [roomConnected, setRoomConnected] = useState(false);\n const [localParticipant, setLocalParticipant] =\n useState<LocalParticipant | null>(null);\n const hasCalledOnConnectRef = useRef(false);\n\n // Reset room state when conversationId changes (new session starting)\n useEffect(() => {\n if (conversationId) {\n setRoomConnected(false);\n setLocalParticipant(null);\n hasCalledOnConnectRef.current = false;\n }\n }, [conversationId]);\n\n useEffect(() => {\n const start = async () => {\n await AudioSession.startAudioSession();\n };\n\n start();\n return () => {\n AudioSession.stopAudioSession();\n };\n }, []);\n\n // Fire onConnect when both participant and room are fully ready\n useEffect(() => {\n if (localParticipant && roomConnected && !hasCalledOnConnectRef.current) {\n hasCalledOnConnectRef.current = true;\n callbacksRef.current.onConnect?.({ conversationId });\n }\n }, [localParticipant, roomConnected, conversationId, callbacksRef]);\n\n const handleParticipantReady = useCallback(\n (participant: LocalParticipant) => {\n if (localParticipant) {\n return;\n }\n\n setLocalParticipant(participant);\n setStatus(\"connected\");\n },\n [localParticipant, setStatus]\n );\n\n const handleConnected = useCallback(() => {\n setRoomConnected(true);\n }, []);\n\n const handleDisconnected = useCallback(() => {\n // If already disconnected, endSession already handled the disconnect callback\n if (status === \"disconnected\") {\n return;\n }\n\n setRoomConnected(false);\n setStatus(\"disconnected\");\n setLocalParticipant(null);\n hasCalledOnConnectRef.current = false;\n callbacksRef.current.onDisconnect?.({ reason: \"user\" });\n }, [callbacksRef, setStatus, status]);\n\n const handleError = useCallback(\n (error: Error) => {\n console.error(\"LiveKit error:\", error);\n callbacksRef.current.onError?.(error.message, undefined);\n },\n [callbacksRef]\n );\n\n return {\n roomConnected,\n localParticipant,\n handleParticipantReady,\n handleConnected,\n handleDisconnected,\n handleError,\n };\n};\n","import { useCallback } from \"react\";\nimport type { LocalParticipant } from \"livekit-client\";\nimport type { ConversationStatus, Callbacks } from \"../types\";\n\nexport const useMessageSending = (\n status: ConversationStatus,\n localParticipant: LocalParticipant | null,\n callbacksRef: { current: Callbacks }\n) => {\n const sendMessage = useCallback(\n async (message: unknown) => {\n if (status !== \"connected\" || !localParticipant) {\n console.warn(\n \"Cannot send message: room not connected or no local participant\"\n );\n return;\n }\n try {\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify(message));\n\n await localParticipant.publishData(data, { reliable: true });\n } catch (error) {\n console.error(\"Failed to send message via WebRTC:\", error);\n console.error(\"Error details:\", error);\n callbacksRef.current.onError?.(error as string);\n }\n },\n [status, localParticipant, callbacksRef]\n );\n\n return { sendMessage };\n};\n","import type { ConversationConfig, InitiationClientDataEvent } from \"../types\";\nimport { PACKAGE_VERSION } from \"../version\";\n\nexport function constructOverrides(\n config: ConversationConfig\n): InitiationClientDataEvent {\n const overridesEvent: InitiationClientDataEvent = {\n type: \"conversation_initiation_client_data\",\n };\n\n if (config.overrides) {\n overridesEvent.conversation_config_override = {\n agent: {\n prompt: config.overrides.agent?.prompt,\n first_message: config.overrides.agent?.firstMessage,\n language: config.overrides.agent?.language,\n },\n tts: {\n voice_id: config.overrides.tts?.voiceId,\n },\n conversation: {\n text_only: config.overrides.conversation?.textOnly,\n },\n };\n }\n\n overridesEvent.source_info = {\n source: \"react_native_sdk\",\n version: config.overrides?.client?.version || PACKAGE_VERSION,\n };\n\n if (config.customLlmExtraBody) {\n overridesEvent.custom_llm_extra_body = config.customLlmExtraBody;\n }\n\n if (config.dynamicVariables) {\n overridesEvent.dynamic_variables = config.dynamicVariables;\n }\n\n if (config.userId) {\n overridesEvent.user_id = String(config.userId);\n }\n\n return overridesEvent;\n}\n"],"names":["PACKAGE_VERSION","MessageHandler","_ref","onReady","isConnected","callbacks","sendMessage","_ref$clientTools","clientTools","updateCurrentEventId","onEndSession","localParticipant","useLocalParticipant","agentResponseCountRef","React","useRef","useEffect","current","useDataChannel","msg","_msg$from","decoder","TextDecoder","message","JSON","parse","decode","payload","event","_msg$from2","messageText","type","user_transcription_event","user_transcript","agent_response_event","agent_response","extractMessageText","onMessage","source","from","isAgent","onModeChange","mode","isSpeaking","eventId","event_id","ping_event","clientToolCall","Promise","resolve","client_tool_call","tool_name","_temp","parameters","then","result","formattedResult","stringify","String","tool_call_id","is_error","_catch","e","onError","clientToolName","onUnhandledClientToolCall","errorMessage","reject","handleClientToolCall","onAudio","audio_event","audio_base_64","onVadScore","vadScore","vad_score_event","vad_score","onInterruption","interruption_event","onMCPToolCall","mcp_tool_call","onMCPConnectionStatus","mcp_connection_status","onAgentToolRequest","agent_tool_request","onAgentToolResponse","agent_tool_response","onConversationMetadata","conversation_initiation_metadata_event","onAsrInitiationMetadata","asr_initiation_metadata_event","onAgentChatResponsePart","text_response_part","onDebug","LiveKitRoomWrapper","children","createElement","LiveKitRoom","serverUrl","token","connect","audio","video","options","adaptiveStream","pixelDensity","onConnected","onDisconnected","onParticipantReady","roomConnected","_excluded","ElevenLabsContext","createContext","registerGlobals","_useState","useState","setToken","_useState2","setConnect","_useState3","status","setStatus","_useState4","setServerUrl","_useState5","undefined","tokenFetchUrl","setTokenFetchUrl","_useState6","conversationId","setConversationId","_useState7","setIsSpeaking","_useState8","canSendFeedback","setCanSendFeedback","currentEventIdRef","lastFeedbackEventIdRef","clientToolsRef","_useConversationCallb","callbacksRef","setCallbacks","useCallback","useConversationCallbacks","setCallbacksBase","wrappedCallbacks","_extends","_useConversationSessi","overrides","setOverrides","customLlmExtraBody","setCustomLlmExtraBody","dynamicVariables","setDynamicVariables","userId","setUserId","startSession","config","_temp2","_result2","extractedConversationId","_tokenPayload$video","_roomId$match","atob","split","room","match","error","console","warn","extractConversationIdFromToken","conversationToken","onStatusChange","agentId","info","fetch","response","json","data","ok","Error","detail","getConversationToken","_getConversationToken","endSession","reason","onDisconnect","useConversationSession","_useLiveKitRoom","setRoomConnected","setLocalParticipant","hasCalledOnConnectRef","AudioSession","startAudioSession","start","stopAudioSession","onConnect","handleParticipantReady","participant","handleConnected","handleDisconnected","handleError","useLiveKitRoom","handleConnectedWithFeedback","onCanSendFeedbackChange","handleDisconnectedWithFeedback","_useMessageSending","TextEncoder","encode","publishData","reliable","useMessageSending","updateCanSendFeedback","newCanSendFeedback","sendFeedback","like","score","volume","getId","setMicMuted","muted","setMicrophoneEnabled","handleParticipantReadyWithOverrides","overridesEvent","_config$overrides","_config$overrides$age","_config$overrides$age2","_config$overrides$age3","_config$overrides$tts","_config$overrides$con","conversation_config_override","agent","prompt","first_message","firstMessage","language","tts","voice_id","voiceId","conversation","text_only","textOnly","source_info","version","client","custom_llm_extra_body","dynamic_variables","user_id","constructOverrides","setClientTools","tools","sendContextualUpdate","text","sendUserMessage","sendUserActivity","useMemo","contextValue","Provider","value","key","context","useContext","_objectWithoutPropertiesLoose"],"mappings":"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"}
1
+ {"version":3,"file":"lib.umd.js","sources":["../src/version.ts","../src/components/MessageHandler.tsx","../src/components/LiveKitRoomWrapper.tsx","../src/ElevenLabsProvider.tsx","../src/utils/constants.ts","../src/hooks/useConversationCallbacks.ts","../src/hooks/useConversationSession.ts","../src/utils/tokenUtils.ts","../src/hooks/useLiveKitRoom.ts","../src/hooks/useMessageSending.ts","../src/utils/overrides.ts"],"sourcesContent":["// This file is auto-generated during build\nexport const PACKAGE_VERSION = \"0.5.6\";\n","import { useEffect } from \"react\";\nimport { useLocalParticipant, useDataChannel, useRoomContext } from \"@livekit/react-native\";\nimport { RoomEvent } from \"livekit-client\";\nimport type { LocalParticipant, RemoteParticipant } from \"livekit-client\";\nimport type {\n Callbacks,\n ClientToolsConfig,\n ClientToolCallEvent,\n ConversationEvent,\n} from \"../types\";\nimport React from \"react\";\n\ninterface MessageHandlerProps {\n onReady: (participant: LocalParticipant) => void;\n isConnected: boolean;\n callbacks: Callbacks;\n sendMessage: (message: unknown) => void;\n onEndSession: (reason: \"user\" | \"agent\") => void;\n clientTools?: ClientToolsConfig[\"clientTools\"];\n updateCurrentEventId?: (eventId: number) => void;\n}\n\nexport function isValidEvent(event: unknown): event is ConversationEvent {\n return typeof event === \"object\" && event !== null && \"type\" in event;\n}\n\nfunction extractMessageText(event: ConversationEvent): string | null {\n switch (event.type) {\n case \"user_transcript\":\n return event.user_transcription_event.user_transcript;\n case \"agent_response\":\n return event.agent_response_event.agent_response;\n default:\n return null;\n }\n}\n\nexport const MessageHandler = ({\n onReady,\n isConnected,\n callbacks,\n sendMessage,\n clientTools = {},\n updateCurrentEventId,\n onEndSession,\n}: MessageHandlerProps) => {\n const { localParticipant } = useLocalParticipant();\n const room = useRoomContext();\n\n // Track agent response count for synthetic event IDs (WebRTC mode)\n const agentResponseCountRef = React.useRef(1);\n\n // Refs for callbacks to avoid unnecessary effect re-runs\n const onEndSessionRef = React.useRef(onEndSession);\n onEndSessionRef.current = onEndSession;\n const onReadyRef = React.useRef(onReady);\n onReadyRef.current = onReady;\n const callbacksRef = React.useRef(callbacks);\n callbacksRef.current = callbacks;\n\n // Detect agent disconnection\n useEffect(() => {\n const handleParticipantDisconnected = (participant: RemoteParticipant) => {\n if (participant.identity?.startsWith(\"agent\")) {\n onEndSessionRef.current(\"agent\");\n }\n };\n\n room.on(RoomEvent.ParticipantDisconnected, handleParticipantDisconnected);\n\n return () => {\n room.off(RoomEvent.ParticipantDisconnected, handleParticipantDisconnected);\n };\n }, [room]);\n\n // Reset agent response count when connection status changes\n useEffect(() => {\n if (!isConnected) {\n agentResponseCountRef.current = 1;\n }\n }, [isConnected]);\n\n useEffect(() => {\n if (isConnected && localParticipant) {\n onReadyRef.current(localParticipant);\n }\n }, [isConnected, localParticipant]);\n\n const handleClientToolCall = async (clientToolCall: ClientToolCallEvent) => {\n if (clientToolCall.client_tool_call.tool_name in clientTools) {\n try {\n const result =\n (await clientTools[clientToolCall.client_tool_call.tool_name](\n clientToolCall.client_tool_call.parameters\n )) ?? \"Client tool execution successful.\"; // default client-tool call response\n\n // The API expects result to be a string, so we need to convert it if it's not already a string\n const formattedResult =\n typeof result === \"object\" ? JSON.stringify(result) : String(result);\n\n sendMessage({\n type: \"client_tool_result\",\n tool_call_id: clientToolCall.client_tool_call.tool_call_id,\n result: formattedResult,\n is_error: false,\n });\n } catch (e) {\n const errorMessage = `Client tool execution failed with following error: ${(e as Error)?.message}`;\n callbacksRef.current.onError?.(errorMessage, {\n clientToolName: clientToolCall.client_tool_call.tool_name,\n });\n sendMessage({\n type: \"client_tool_result\",\n tool_call_id: clientToolCall.client_tool_call.tool_call_id,\n result: `Client tool execution failed: ${(e as Error)?.message}`,\n is_error: true,\n });\n }\n } else {\n if (callbacksRef.current.onUnhandledClientToolCall) {\n callbacksRef.current.onUnhandledClientToolCall(clientToolCall.client_tool_call);\n return;\n }\n\n const errorMessage = `Client tool with name ${clientToolCall.client_tool_call.tool_name} is not defined on client`;\n callbacksRef.current.onError?.(errorMessage, {\n clientToolName: clientToolCall.client_tool_call.tool_name,\n });\n sendMessage({\n type: \"client_tool_result\",\n tool_call_id: clientToolCall.client_tool_call.tool_call_id,\n result: errorMessage,\n is_error: true,\n });\n }\n };\n\n const _ = useDataChannel(msg => {\n const decoder = new TextDecoder();\n const message = JSON.parse(decoder.decode(msg.payload));\n\n if (!isValidEvent(message)) {\n callbacksRef.current.onDebug?.({\n type: \"invalid_event\",\n message,\n });\n return;\n }\n\n const messageText = extractMessageText(message);\n if (messageText !== null) {\n callbacksRef.current.onMessage?.({\n message: messageText,\n source: message.type === \"user_transcript\" ? \"user\" : \"ai\",\n role: message.type === \"user_transcript\" ? \"user\" : \"agent\",\n });\n }\n\n if (msg.from?.isAgent) {\n callbacksRef.current.onModeChange?.({\n mode: msg.from?.isSpeaking ? \"speaking\" : \"listening\",\n });\n\n // Track agent responses for feedback (WebRTC mode needs synthetic event IDs)\n if (message.type === \"agent_response\" && updateCurrentEventId) {\n const eventId = agentResponseCountRef.current++;\n updateCurrentEventId(eventId);\n }\n }\n\n switch (message.type) {\n case \"ping\":\n sendMessage({\n type: \"pong\",\n event_id: message.ping_event.event_id,\n });\n break;\n case \"client_tool_call\":\n handleClientToolCall(message);\n break;\n case \"audio\":\n callbacksRef.current.onAudio?.(message.audio_event.audio_base_64);\n break;\n case \"vad_score\":\n callbacksRef.current.onVadScore?.({\n vadScore: message.vad_score_event.vad_score,\n });\n break;\n case \"interruption\":\n callbacksRef.current.onInterruption?.(message.interruption_event);\n break;\n case \"mcp_tool_call\":\n callbacksRef.current.onMCPToolCall?.(message.mcp_tool_call);\n break;\n case \"mcp_connection_status\":\n callbacksRef.current.onMCPConnectionStatus?.(message.mcp_connection_status);\n break;\n case \"agent_tool_request\":\n callbacksRef.current.onAgentToolRequest?.(message.agent_tool_request);\n break;\n case \"agent_tool_response\":\n callbacksRef.current.onAgentToolResponse?.(message.agent_tool_response);\n\n if (message.agent_tool_response.tool_name === \"end_call\") {\n // End the call\n onEndSessionRef.current(\"agent\");\n }\n break;\n case \"conversation_initiation_metadata\":\n callbacksRef.current.onConversationMetadata?.(\n message.conversation_initiation_metadata_event\n );\n break;\n case \"asr_initiation_metadata\":\n callbacksRef.current.onAsrInitiationMetadata?.(\n message.asr_initiation_metadata_event\n );\n break;\n case \"agent_chat_response_part\":\n callbacksRef.current.onAgentChatResponsePart?.(message.text_response_part);\n break;\n default:\n callbacksRef.current.onDebug?.(message);\n break;\n }\n });\n\n return null;\n};\n","// @ts-nocheck - pnpm hoisting causes duplicate React type definitions\nimport React from 'react';\nimport { LiveKitRoom } from '@livekit/react-native';\nimport type { LocalParticipant } from 'livekit-client';\nimport type { Callbacks, ClientToolsConfig, AudioSessionConfig } from '../types';\nimport { MessageHandler } from './MessageHandler';\n\ninterface LiveKitRoomWrapperProps {\n children: React.ReactNode;\n serverUrl: string;\n token: string;\n connect: boolean;\n onConnected: () => void;\n onDisconnected: () => void;\n onError: (error: Error) => void;\n roomConnected: boolean;\n callbacks: Callbacks;\n onParticipantReady: (participant: LocalParticipant) => void;\n sendMessage: (message: unknown) => void;\n clientTools: ClientToolsConfig['clientTools'];\n onEndSession: (reason?: \"user\" | \"agent\") => void;\n updateCurrentEventId?: (eventId: number) => void;\n audioSessionConfig?: AudioSessionConfig;\n}\n\nexport const LiveKitRoomWrapper = ({\n children,\n serverUrl,\n token,\n connect,\n onConnected,\n onDisconnected,\n onError,\n roomConnected,\n callbacks,\n onParticipantReady,\n sendMessage,\n clientTools,\n updateCurrentEventId,\n onEndSession,\n audioSessionConfig,\n}: LiveKitRoomWrapperProps) => {\n // Configure audio options based on audioSessionConfig\n const audioOptions = React.useMemo(() => {\n if (!audioSessionConfig?.allowMixingWithOthers) {\n return true;\n }\n\n // When mixing is enabled, configure audio to allow concurrent playback\n return {\n audio: {\n noiseSuppression: true,\n echoCancellation: true,\n },\n audioSessionConfiguration: {\n allowMixingWithOthers: true,\n },\n };\n }, [audioSessionConfig]);\n\n return (\n <LiveKitRoom\n serverUrl={serverUrl}\n token={token}\n connect={connect}\n audio={audioOptions}\n video={false}\n options={{\n adaptiveStream: { pixelDensity: 'screen' },\n }}\n onConnected={onConnected}\n onDisconnected={onDisconnected}\n onError={onError}\n >\n <MessageHandler\n onReady={onParticipantReady}\n isConnected={roomConnected}\n callbacks={callbacks}\n sendMessage={sendMessage}\n clientTools={clientTools}\n updateCurrentEventId={updateCurrentEventId}\n onEndSession={onEndSession}\n />\n {children as any}\n </LiveKitRoom>\n );\n};","import React from 'react';\nimport { createContext, useContext, useState } from 'react';\nimport { registerGlobals } from '@livekit/react-native';\nimport type { LocalParticipant } from 'livekit-client';\nimport type { Callbacks, ConversationConfig, ConversationStatus, ClientToolsConfig, AudioSessionConfig } from './types';\nimport { constructOverrides } from './utils/overrides';\nimport { DEFAULT_SERVER_URL } from './utils/constants';\nimport { useConversationCallbacks } from './hooks/useConversationCallbacks';\nimport { useConversationSession } from './hooks/useConversationSession';\nimport { useLiveKitRoom } from './hooks/useLiveKitRoom';\nimport { useMessageSending } from './hooks/useMessageSending';\nimport { LiveKitRoomWrapper } from './components/LiveKitRoomWrapper';\n\ninterface ConversationOptions extends Callbacks, Partial<ClientToolsConfig> {\n serverUrl?: string;\n tokenFetchUrl?: string;\n}\n\nexport interface Conversation {\n startSession: (config: ConversationConfig) => Promise<void>;\n endSession: (reason?: \"user\" | \"agent\") => Promise<void>;\n status: ConversationStatus;\n isSpeaking: boolean;\n // TODO: Implement setVolume when LiveKit React Native supports it\n // setVolume: (volume: number) => void;\n canSendFeedback: boolean;\n getId: () => string;\n sendFeedback: (like: boolean) => void;\n sendContextualUpdate: (text: string) => void;\n sendUserMessage: (text: string) => void;\n sendUserActivity: () => void;\n setMicMuted: (muted: boolean) => void;\n}\n\ninterface ElevenLabsContextType {\n conversation: Conversation;\n callbacksRef: { current: Callbacks };\n serverUrl: string;\n tokenFetchUrl?: string;\n clientTools: ClientToolsConfig['clientTools'];\n setCallbacks: (callbacks: Callbacks) => void;\n setServerUrl: (url: string) => void;\n setTokenFetchUrl: (url: string) => void;\n setClientTools: (tools: ClientToolsConfig['clientTools']) => void;\n}\n\nconst ElevenLabsContext = createContext<ElevenLabsContextType | null>(null);\n\nexport const useConversation = (options: ConversationOptions = {}): Conversation => {\n const context = useContext(ElevenLabsContext);\n if (!context) {\n throw new Error('useConversation must be used within ElevenLabsProvider');\n }\n\n const { serverUrl, tokenFetchUrl, clientTools, ...callbacks } = options;\n\n React.useEffect(() => {\n if (serverUrl) {\n context.setServerUrl(serverUrl);\n }\n }, [context, serverUrl]);\n\n React.useEffect(() => {\n if (tokenFetchUrl) {\n context.setTokenFetchUrl(tokenFetchUrl);\n }\n }, [context, tokenFetchUrl]);\n\n React.useEffect(() => {\n if (clientTools) {\n context.setClientTools(clientTools);\n }\n }, [context, clientTools]);\n\n // Update callbacks - since this only updates a ref, it's safe to call on every render\n // and doesn't cause re-renders of the provider or its consumers\n context.setCallbacks(callbacks);\n\n return context.conversation;\n};\n\ninterface ElevenLabsProviderProps {\n children: React.ReactNode;\n audioSessionConfig?: AudioSessionConfig;\n}\n\nexport const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children, audioSessionConfig }) => {\n // Initialize globals on mount\n registerGlobals();\n\n // State management\n const [token, setToken] = useState('');\n const [connect, setConnect] = useState(false);\n const [status, setStatus] = useState<ConversationStatus>('disconnected');\n const [serverUrl, setServerUrl] = useState(DEFAULT_SERVER_URL);\n const [tokenFetchUrl, setTokenFetchUrl] = useState<string | undefined>(undefined);\n const [conversationId, setConversationId] = useState<string>('');\n const [isSpeaking, setIsSpeaking] = useState(false);\n const [canSendFeedback, setCanSendFeedback] = useState(false);\n\n // Feedback state tracking\n const currentEventIdRef = React.useRef(1);\n const lastFeedbackEventIdRef = React.useRef(1);\n\n // Use ref for clientTools to avoid re-renders (like callbacks)\n const clientToolsRef = React.useRef<ClientToolsConfig['clientTools']>({});\n\n // Custom hooks\n const { callbacksRef, setCallbacks: setCallbacksBase } = useConversationCallbacks();\n\n // Enhanced setCallbacks that wraps onModeChange to update isSpeaking state\n const setCallbacks = React.useCallback((callbacks: Callbacks) => {\n const wrappedCallbacks = {\n ...callbacks,\n onModeChange: (event: { mode: 'speaking' | 'listening' }) => {\n setIsSpeaking(event.mode === 'speaking');\n callbacks.onModeChange?.(event);\n }\n };\n setCallbacksBase(wrappedCallbacks);\n }, [setCallbacksBase]);\n\n const {\n startSession,\n endSession,\n overrides,\n customLlmExtraBody,\n dynamicVariables,\n userId,\n } = useConversationSession(callbacksRef, setStatus, setConnect, setToken, setConversationId, tokenFetchUrl);\n\n const {\n roomConnected,\n localParticipant,\n handleParticipantReady,\n handleConnected,\n handleDisconnected,\n handleError,\n } = useLiveKitRoom(callbacksRef, setStatus, conversationId, status);\n\n // Enhanced connection handler to initialize feedback state\n const handleConnectedWithFeedback = React.useCallback(() => {\n // Reset feedback state when connecting\n currentEventIdRef.current = 1;\n lastFeedbackEventIdRef.current = 1;\n setCanSendFeedback(false);\n callbacksRef.current.onCanSendFeedbackChange?.({ canSendFeedback: false });\n\n handleConnected();\n }, [handleConnected, callbacksRef]);\n\n // Enhanced disconnection handler to reset feedback state\n const handleDisconnectedWithFeedback = React.useCallback(() => {\n setCanSendFeedback(false);\n setIsSpeaking(false);\n handleDisconnected();\n }, [handleDisconnected]);\n\n const { sendMessage } = useMessageSending(status, localParticipant, callbacksRef);\n\n const updateCanSendFeedback = React.useCallback(() => {\n const newCanSendFeedback = currentEventIdRef.current !== lastFeedbackEventIdRef.current;\n\n if (canSendFeedback !== newCanSendFeedback) {\n setCanSendFeedback(newCanSendFeedback);\n callbacksRef.current.onCanSendFeedbackChange?.({ canSendFeedback: newCanSendFeedback });\n }\n }, [canSendFeedback, callbacksRef]);\n\n const sendFeedback = React.useCallback((like: boolean) => {\n if (!canSendFeedback) {\n console.warn(\n lastFeedbackEventIdRef.current === 0\n ? \"Cannot send feedback: the conversation has not started yet.\"\n : \"Cannot send feedback: feedback has already been sent for the current response.\"\n );\n return;\n }\n\n const feedbackMessage = {\n type: \"feedback\",\n score: like ? \"like\" : \"dislike\",\n event_id: currentEventIdRef.current,\n };\n\n sendMessage(feedbackMessage);\n lastFeedbackEventIdRef.current = currentEventIdRef.current;\n updateCanSendFeedback();\n }, [canSendFeedback, sendMessage, updateCanSendFeedback]);\n\n // setVolume placeholder (to be implemented when LiveKit supports it)\n const setVolume = React.useCallback((volume: number) => {\n console.warn('setVolume is not yet implemented in React Native SDK');\n }, []);\n\n const getId = React.useCallback(() => conversationId, [conversationId]);\n\n const setMicMuted = React.useCallback((muted: boolean) => {\n if (localParticipant) {\n localParticipant.setMicrophoneEnabled(!muted);\n }\n }, [localParticipant]);\n\n // Update current event ID for feedback tracking\n const updateCurrentEventId = React.useCallback((eventId: number) => {\n currentEventIdRef.current = eventId;\n updateCanSendFeedback();\n }, [updateCanSendFeedback]);\n\n // Handle participant ready with overrides\n const handleParticipantReadyWithOverrides = React.useCallback((participant: LocalParticipant) => {\n handleParticipantReady(participant);\n\n const overridesEvent = constructOverrides({\n overrides,\n customLlmExtraBody,\n dynamicVariables,\n userId,\n });\n\n if (overridesEvent) {\n try {\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify(overridesEvent));\n participant.publishData(data, { reliable: true });\n } catch (error) {\n console.error(\"Failed to send overrides:\", error);\n callbacksRef.current.onError?.(error as string);\n }\n }\n }, [handleParticipantReady, overrides, customLlmExtraBody, dynamicVariables, userId, callbacksRef]);\n\n // Create setClientTools function that only updates ref\n const setClientTools = React.useCallback((tools: ClientToolsConfig['clientTools']) => {\n clientToolsRef.current = tools;\n }, []);\n\n // Memoize inline callback functions\n const sendContextualUpdate = React.useCallback((text: string) => {\n sendMessage({\n type: \"contextual_update\",\n text,\n });\n }, [sendMessage]);\n\n const sendUserMessage = React.useCallback((text: string) => {\n sendMessage({\n type: \"user_message\",\n text,\n });\n }, [sendMessage]);\n\n const sendUserActivity = React.useCallback(() => {\n sendMessage({\n type: \"user_activity\",\n });\n }, [sendMessage]);\n\n // Store all conversation values/functions in refs for stable access\n const conversationValuesRef = React.useRef({\n startSession,\n endSession,\n status,\n isSpeaking,\n canSendFeedback,\n getId,\n setMicMuted,\n sendFeedback,\n sendContextualUpdate,\n sendUserMessage,\n sendUserActivity,\n });\n\n // Update ref on every render\n conversationValuesRef.current = {\n startSession,\n endSession,\n status,\n isSpeaking,\n canSendFeedback,\n getId,\n setMicMuted,\n sendFeedback,\n sendContextualUpdate,\n sendUserMessage,\n sendUserActivity,\n };\n\n // Create a stable conversation object that never changes reference\n // This prevents infinite loops when conversation is used in useEffect dependencies\n const conversation = React.useMemo<Conversation>(() => ({\n get startSession() { return conversationValuesRef.current.startSession; },\n get endSession() { return conversationValuesRef.current.endSession; },\n get status() { return conversationValuesRef.current.status; },\n get isSpeaking() { return conversationValuesRef.current.isSpeaking; },\n get canSendFeedback() { return conversationValuesRef.current.canSendFeedback; },\n get getId() { return conversationValuesRef.current.getId; },\n get setMicMuted() { return conversationValuesRef.current.setMicMuted; },\n get sendFeedback() { return conversationValuesRef.current.sendFeedback; },\n get sendContextualUpdate() { return conversationValuesRef.current.sendContextualUpdate; },\n get sendUserMessage() { return conversationValuesRef.current.sendUserMessage; },\n get sendUserActivity() { return conversationValuesRef.current.sendUserActivity; },\n }), []); // Empty deps - object is created once and never recreated\n\n // Memoize the context value to prevent unnecessary re-renders of consumers\n const contextValue = React.useMemo<ElevenLabsContextType>(() => ({\n conversation,\n callbacksRef,\n serverUrl,\n tokenFetchUrl,\n clientTools: clientToolsRef.current,\n setCallbacks,\n setServerUrl,\n setTokenFetchUrl,\n setClientTools,\n }), [\n conversation,\n callbacksRef,\n serverUrl,\n tokenFetchUrl,\n setCallbacks,\n setClientTools,\n ]);\n\n return (\n <ElevenLabsContext.Provider value={contextValue}>\n <LiveKitRoomWrapper\n serverUrl={serverUrl}\n token={token}\n connect={connect}\n onConnected={handleConnectedWithFeedback}\n onDisconnected={handleDisconnectedWithFeedback}\n onError={handleError}\n roomConnected={roomConnected}\n callbacks={callbacksRef.current}\n onParticipantReady={handleParticipantReadyWithOverrides}\n sendMessage={sendMessage}\n clientTools={clientToolsRef.current}\n updateCurrentEventId={updateCurrentEventId}\n onEndSession={endSession}\n audioSessionConfig={audioSessionConfig}\n >\n {children}\n </LiveKitRoomWrapper>\n </ElevenLabsContext.Provider>\n );\n};\n","export const DEFAULT_SERVER_URL = \"wss://livekit.rtc.elevenlabs.io\";\n","import { useRef, useCallback } from \"react\";\nimport type { Callbacks } from \"../types\";\n\nexport const useConversationCallbacks = () => {\n const callbacksRef = useRef<Callbacks>({});\n\n const setCallbacks = useCallback((callbacks: Callbacks) => {\n callbacksRef.current = callbacks;\n }, []);\n\n return {\n callbacksRef,\n setCallbacks,\n };\n};\n","import { useState, useCallback } from \"react\";\nimport type {\n ConversationConfig,\n ConversationStatus,\n Callbacks,\n} from \"../types\";\nimport {\n getConversationToken,\n extractConversationIdFromToken,\n} from \"../utils/tokenUtils\";\n\nexport const useConversationSession = (\n callbacksRef: { current: Callbacks },\n setStatus: (status: ConversationStatus) => void,\n setConnect: (connect: boolean) => void,\n setToken: (token: string) => void,\n setConversationId: (conversationId: string) => void,\n tokenFetchUrl?: string\n) => {\n const [overrides, setOverrides] = useState<ConversationConfig[\"overrides\"]>(\n {}\n );\n const [customLlmExtraBody, setCustomLlmExtraBody] =\n useState<ConversationConfig[\"customLlmExtraBody\"]>(null);\n const [dynamicVariables, setDynamicVariables] = useState<\n ConversationConfig[\"dynamicVariables\"]\n >({});\n const [userId, setUserId] = useState<ConversationConfig[\"userId\"]>(undefined);\n\n const startSession = useCallback(\n async (config: ConversationConfig) => {\n try {\n setStatus(\"connecting\");\n callbacksRef.current.onStatusChange?.({ status: \"connecting\" });\n\n setOverrides(config.overrides || {});\n setCustomLlmExtraBody(config.customLlmExtraBody || null);\n setDynamicVariables(config.dynamicVariables || {});\n setUserId(config.userId);\n\n let conversationToken: string;\n\n if (config.conversationToken) {\n conversationToken = config.conversationToken;\n } else if (config.agentId) {\n console.info(\n \"Getting conversation token for agentId:\",\n config.agentId\n );\n // Use tokenFetchUrl from config first, then from hook parameter, then default\n const urlToUse = config.tokenFetchUrl || tokenFetchUrl;\n conversationToken = await getConversationToken(\n config.agentId,\n urlToUse\n );\n } else {\n throw new Error(\"Either conversationToken or agentId is required\");\n }\n\n const extractedConversationId =\n extractConversationIdFromToken(conversationToken);\n setConversationId(extractedConversationId);\n\n setToken(conversationToken);\n setConnect(true);\n } catch (error) {\n setStatus(\"disconnected\");\n callbacksRef.current.onStatusChange?.({ status: \"disconnected\" });\n callbacksRef.current.onError?.(error as string);\n throw error;\n }\n },\n [\n callbacksRef,\n setStatus,\n setConnect,\n setToken,\n setConversationId,\n tokenFetchUrl,\n ]\n );\n\n const endSession = useCallback(\n async (reason: \"user\" | \"agent\" = \"user\") => {\n try {\n setConnect(false);\n setToken(\"\");\n setStatus(\"disconnected\");\n\n // Reset session configuration state\n setOverrides({});\n setCustomLlmExtraBody(null);\n setDynamicVariables({});\n setUserId(undefined);\n setConversationId(\"\");\n\n callbacksRef.current.onStatusChange?.({ status: \"disconnected\" });\n callbacksRef.current.onDisconnect?.({ reason });\n } catch (error) {\n callbacksRef.current.onError?.(error as string);\n throw error;\n }\n },\n [callbacksRef, setConnect, setToken, setStatus, setConversationId]\n );\n\n return {\n startSession,\n endSession,\n overrides,\n customLlmExtraBody,\n dynamicVariables,\n userId,\n };\n};\n","import { PACKAGE_VERSION } from \"../version\";\n\nexport const extractConversationIdFromToken = (token: string): string => {\n try {\n const tokenPayload = JSON.parse(atob(token.split(\".\")[1]));\n const roomId = tokenPayload.video?.room || \"\";\n\n return roomId.match(/(conv_[a-zA-Z0-9]+)/)?.[0] || \"\";\n } catch (error) {\n console.warn(\"Could not extract conversation ID from token\");\n return \"\";\n }\n};\n\nexport const getConversationToken = async (\n agentId: string,\n tokenFetchUrl?: string\n): Promise<string> => {\n const baseUrl =\n tokenFetchUrl || \"https://api.elevenlabs.io/v1/convai/conversation/token\";\n const response = await fetch(\n `${baseUrl}?agent_id=${agentId}&source=react_native_sdk&version=${PACKAGE_VERSION}`\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n throw new Error(`Failed to get conversation token: ${data.detail.message}`);\n }\n\n if (!data.token) {\n throw new Error(\"No conversation token received from API\");\n }\n\n return data.token;\n};\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { AudioSession } from \"@livekit/react-native\";\nimport type { LocalParticipant } from \"livekit-client\";\nimport type { ConversationStatus, Callbacks } from \"../types\";\n\nexport const useLiveKitRoom = (\n callbacksRef: { current: Callbacks },\n setStatus: (status: ConversationStatus) => void,\n conversationId: string,\n status: ConversationStatus\n) => {\n const [roomConnected, setRoomConnected] = useState(false);\n const [localParticipant, setLocalParticipant] =\n useState<LocalParticipant | null>(null);\n const hasCalledOnConnectRef = useRef(false);\n\n // Reset room state when conversationId changes (new session starting)\n useEffect(() => {\n if (conversationId) {\n setRoomConnected(false);\n setLocalParticipant(null);\n hasCalledOnConnectRef.current = false;\n }\n }, [conversationId]);\n\n useEffect(() => {\n const start = async () => {\n await AudioSession.startAudioSession();\n };\n\n start();\n return () => {\n AudioSession.stopAudioSession();\n };\n }, []);\n\n // Fire onConnect when both participant and room are fully ready\n useEffect(() => {\n if (localParticipant && roomConnected && !hasCalledOnConnectRef.current) {\n hasCalledOnConnectRef.current = true;\n callbacksRef.current.onConnect?.({ conversationId });\n }\n }, [localParticipant, roomConnected, conversationId, callbacksRef]);\n\n const handleParticipantReady = useCallback(\n (participant: LocalParticipant) => {\n if (localParticipant) {\n return;\n }\n\n setLocalParticipant(participant);\n setStatus(\"connected\");\n },\n [localParticipant, setStatus]\n );\n\n const handleConnected = useCallback(() => {\n setRoomConnected(true);\n }, []);\n\n const handleDisconnected = useCallback(() => {\n // If already disconnected, endSession already handled the disconnect callback\n if (status === \"disconnected\") {\n return;\n }\n\n setRoomConnected(false);\n setStatus(\"disconnected\");\n setLocalParticipant(null);\n hasCalledOnConnectRef.current = false;\n callbacksRef.current.onDisconnect?.({ reason: \"user\" });\n }, [callbacksRef, setStatus, status]);\n\n const handleError = useCallback(\n (error: Error) => {\n console.error(\"LiveKit error:\", error);\n callbacksRef.current.onError?.(error.message, undefined);\n },\n [callbacksRef]\n );\n\n return {\n roomConnected,\n localParticipant,\n handleParticipantReady,\n handleConnected,\n handleDisconnected,\n handleError,\n };\n};\n","import { useCallback } from \"react\";\nimport type { LocalParticipant } from \"livekit-client\";\nimport type { ConversationStatus, Callbacks } from \"../types\";\n\nexport const useMessageSending = (\n status: ConversationStatus,\n localParticipant: LocalParticipant | null,\n callbacksRef: { current: Callbacks }\n) => {\n const sendMessage = useCallback(\n async (message: unknown) => {\n if (status !== \"connected\" || !localParticipant) {\n console.warn(\n \"Cannot send message: room not connected or no local participant\"\n );\n return;\n }\n try {\n const encoder = new TextEncoder();\n const data = encoder.encode(JSON.stringify(message));\n\n await localParticipant.publishData(data, { reliable: true });\n } catch (error) {\n console.error(\"Failed to send message via WebRTC:\", error);\n console.error(\"Error details:\", error);\n callbacksRef.current.onError?.(error as string);\n }\n },\n [status, localParticipant, callbacksRef]\n );\n\n return { sendMessage };\n};\n","import type { ConversationConfig, InitiationClientDataEvent } from \"../types\";\nimport { PACKAGE_VERSION } from \"../version\";\n\nexport function constructOverrides(\n config: ConversationConfig\n): InitiationClientDataEvent {\n const overridesEvent: InitiationClientDataEvent = {\n type: \"conversation_initiation_client_data\",\n };\n\n if (config.overrides) {\n overridesEvent.conversation_config_override = {\n agent: {\n prompt: config.overrides.agent?.prompt,\n first_message: config.overrides.agent?.firstMessage,\n language: config.overrides.agent?.language,\n },\n tts: {\n voice_id: config.overrides.tts?.voiceId,\n speed: config.overrides.tts?.speed,\n },\n conversation: {\n text_only: config.overrides.conversation?.textOnly,\n },\n };\n }\n\n overridesEvent.source_info = {\n source: \"react_native_sdk\",\n version: config.overrides?.client?.version || PACKAGE_VERSION,\n };\n\n if (config.customLlmExtraBody) {\n overridesEvent.custom_llm_extra_body = config.customLlmExtraBody;\n }\n\n if (config.dynamicVariables) {\n overridesEvent.dynamic_variables = config.dynamicVariables;\n }\n\n if (config.userId) {\n overridesEvent.user_id = String(config.userId);\n }\n\n return overridesEvent;\n}\n"],"names":["PACKAGE_VERSION","MessageHandler","_ref","onReady","isConnected","callbacks","sendMessage","_ref$clientTools","clientTools","updateCurrentEventId","onEndSession","localParticipant","useLocalParticipant","room","useRoomContext","agentResponseCountRef","React","useRef","onEndSessionRef","current","onReadyRef","callbacksRef","useEffect","handleParticipantDisconnected","participant","_participant$identity","identity","startsWith","on","RoomEvent","ParticipantDisconnected","off","useDataChannel","msg","_msg$from","decoder","TextDecoder","message","JSON","parse","decode","payload","event","_msg$from2","messageText","type","user_transcription_event","user_transcript","agent_response_event","agent_response","extractMessageText","onMessage","source","role","from","isAgent","onModeChange","mode","isSpeaking","eventId","event_id","ping_event","clientToolCall","Promise","resolve","client_tool_call","tool_name","_temp","parameters","then","result","formattedResult","stringify","String","tool_call_id","is_error","_catch","e","onError","clientToolName","onUnhandledClientToolCall","errorMessage","reject","handleClientToolCall","onAudio","audio_event","audio_base_64","onVadScore","vadScore","vad_score_event","vad_score","onInterruption","interruption_event","onMCPToolCall","mcp_tool_call","onMCPConnectionStatus","mcp_connection_status","onAgentToolRequest","agent_tool_request","onAgentToolResponse","agent_tool_response","onConversationMetadata","conversation_initiation_metadata_event","onAsrInitiationMetadata","asr_initiation_metadata_event","onAgentChatResponsePart","text_response_part","onDebug","LiveKitRoomWrapper","children","serverUrl","token","connect","onConnected","onDisconnected","roomConnected","onParticipantReady","audioSessionConfig","audioOptions","useMemo","allowMixingWithOthers","audio","noiseSuppression","echoCancellation","audioSessionConfiguration","createElement","LiveKitRoom","video","options","adaptiveStream","pixelDensity","ElevenLabsContext","createContext","registerGlobals","_useState","useState","setToken","_useState2","setConnect","_useState3","status","setStatus","_useState4","setServerUrl","_useState5","undefined","tokenFetchUrl","setTokenFetchUrl","_useState6","conversationId","setConversationId","_useState7","setIsSpeaking","_useState8","canSendFeedback","setCanSendFeedback","currentEventIdRef","lastFeedbackEventIdRef","clientToolsRef","_useConversationCallb","setCallbacks","useCallback","useConversationCallbacks","setCallbacksBase","wrappedCallbacks","_extends","_useConversationSessi","overrides","setOverrides","customLlmExtraBody","setCustomLlmExtraBody","dynamicVariables","setDynamicVariables","userId","setUserId","startSession","config","_temp2","_result2","extractedConversationId","_tokenPayload$video","_roomId$match","atob","split","match","error","console","warn","extractConversationIdFromToken","conversationToken","onStatusChange","agentId","info","fetch","response","json","data","ok","Error","detail","getConversationToken","_getConversationToken","endSession","reason","onDisconnect","useConversationSession","_useLiveKitRoom","setRoomConnected","setLocalParticipant","hasCalledOnConnectRef","AudioSession","startAudioSession","start","stopAudioSession","onConnect","handleParticipantReady","handleConnected","handleDisconnected","handleError","useLiveKitRoom","handleConnectedWithFeedback","onCanSendFeedbackChange","handleDisconnectedWithFeedback","_useMessageSending","TextEncoder","encode","publishData","reliable","useMessageSending","updateCanSendFeedback","newCanSendFeedback","sendFeedback","like","score","volume","getId","setMicMuted","muted","setMicrophoneEnabled","handleParticipantReadyWithOverrides","overridesEvent","_config$overrides","_config$overrides$age","_config$overrides$age2","_config$overrides$age3","_config$overrides$tts","_config$overrides$tts2","_config$overrides$con","conversation_config_override","agent","prompt","first_message","firstMessage","language","tts","voice_id","voiceId","speed","conversation","text_only","textOnly","source_info","version","client","custom_llm_extra_body","dynamic_variables","user_id","constructOverrides","setClientTools","tools","sendContextualUpdate","text","sendUserMessage","sendUserActivity","conversationValuesRef","contextValue","Provider","value","context","useContext","_objectWithoutPropertiesLoose","_excluded"],"mappings":"ssBACa,IAAAA,EAAkB,QCoClBC,EAAiB,SAAHC,GAQD,IAPxBC,EAAOD,EAAPC,QACAC,EAAWF,EAAXE,YACAC,EAASH,EAATG,UACAC,EAAWJ,EAAXI,YAAWC,EAAAL,EACXM,YAAAA,OAAc,IAAHD,EAAG,CAAE,EAAAA,EAChBE,EAAoBP,EAApBO,qBACAC,EAAYR,EAAZQ,aAEQC,EAAqBC,EAAAA,sBAArBD,iBACFE,EAAOC,EAAAA,iBAGPC,EAAwBC,EAAK,QAACC,OAAO,GAGrCC,EAAkBF,EAAK,QAACC,OAAOP,GACrCQ,EAAgBC,QAAUT,EAC1B,IAAMU,EAAaJ,EAAK,QAACC,OAAOd,GAChCiB,EAAWD,QAAUhB,EACrB,IAAMkB,EAAeL,UAAMC,OAAOZ,GA0KlC,OAzKAgB,EAAaF,QAAUd,EAGvBiB,EAASA,UAAC,WACR,IAAMC,EAAgC,SAACC,GAAkC,IAAAC,EAC/C,OAAxBA,EAAID,EAAYE,WAAZD,EAAsBE,WAAW,UACnCT,EAAgBC,QAAQ,QAE5B,EAIA,OAFAN,EAAKe,GAAGC,EAASA,UAACC,wBAAyBP,GAE/B,WACVV,EAAKkB,IAAIF,EAASA,UAACC,wBAAyBP,EAC9C,CACF,EAAG,CAACV,IAGJS,EAASA,UAAC,WACHlB,IACHW,EAAsBI,QAAU,EAEpC,EAAG,CAACf,IAEJkB,EAAAA,UAAU,WACJlB,GAAeO,GACjBS,EAAWD,QAAQR,EAEvB,EAAG,CAACP,EAAaO,IAmDPqB,EAAcA,eAAC,SAAAC,GAAMC,IAAAA,EACvBC,EAAU,IAAIC,YACdC,EAAUC,KAAKC,MAAMJ,EAAQK,OAAOP,EAAIQ,UAE9C,GAtHsB,iBADGC,EAuHPL,IAtH0B,OAAVK,GAAkB,SAAUA,EAsH9D,KAvHyBA,EAwIFC,EATjBC,EA3HV,SAA4BF,GAC1B,OAAQA,EAAMG,MACZ,IAAK,kBACH,OAAOH,EAAMI,yBAAyBC,gBACxC,IAAK,iBACH,OAAOL,EAAMM,qBAAqBC,eACpC,QACE,OAAO,KAEb,CAkHwBC,CAAmBb,GASvC,GARoB,OAAhBO,IACFvB,MAAAA,EAAaF,QAAQgC,WAArB9B,EAAaF,QAAQgC,UAAY,CAC/Bd,QAASO,EACTQ,OAAyB,oBAAjBf,EAAQQ,KAA6B,OAAS,KACtDQ,KAAuB,oBAAjBhB,EAAQQ,KAA6B,OAAS,WAIpDX,OAAJA,EAAID,EAAIqB,OAAJpB,EAAUqB,UACZlC,MAAAA,EAAaF,QAAQqC,cAArBnC,EAAaF,QAAQqC,aAAe,CAClCC,KAAc,OAARd,EAAAV,EAAIqB,OAAJX,EAAUe,WAAa,WAAa,cAIvB,mBAAjBrB,EAAQQ,MAA6BpC,GAAsB,CAC7D,IAAMkD,EAAU5C,EAAsBI,UACtCV,EAAqBkD,EACvB,CAGF,OAAQtB,EAAQQ,MACd,IAAK,OACHvC,EAAY,CACVuC,KAAM,OACNe,SAAUvB,EAAQwB,WAAWD,WAE/B,MACF,IAAK,oBAzFiB,SAAUE,GAAuC,IAAA,OAAAC,QAAAC,QACrEF,WAAAA,GAAAA,EAAeG,iBAAiBC,aAAa1D,EAAW2D,CAAAA,IAAAA,0BACtDJ,QAAAC,QAEOxD,EAAYsD,EAAeG,iBAAiBC,WACjDJ,EAAeG,iBAAiBG,aACjCC,KAAA,SAHGC,GAMN,IAAMC,EACc,iBAAXD,EAAsBhC,KAAKkC,UAAUF,GAAUG,OAAOH,GAE/DhE,EAAY,CACVuC,KAAM,qBACN6B,aAAcZ,EAAeG,iBAAiBS,aAC9CJ,OAAQC,EACRI,UAAU,GACT,4DAhBqDC,CAAA,EAiBjDC,SAAAA,SAEPxD,EAAaF,QAAQ2D,SAArBzD,EAAaF,QAAQ2D,QADuDD,uDAAAA,MAAAA,OAAAA,EAAAA,EAAaxC,SAC5C,CAC3C0C,eAAgBjB,EAAeG,iBAAiBC,YAElD5D,EAAY,CACVuC,KAAM,qBACN6B,aAAcZ,EAAeG,iBAAiBS,aAC9CJ,OAAM,kCAAoCO,MAAAA,OAAAA,EAAAA,EAAaxC,SACvDsC,UAAU,GAEd,GAAC,GAAAR,GAAAA,EAAAE,YAAAF,EAAAE,KAAA,WAAA,EAAA,KAAA,CAED,GAAIhD,EAAaF,QAAQ6D,0BAEvB,YADA3D,EAAaF,QAAQ6D,0BAA0BlB,EAAeG,kBAIhE,IAAMgB,EAAY,yBAA4BnB,EAAeG,iBAAiBC,UAAS,4BAC3D,MAA5B7C,EAAaF,QAAQ2D,SAArBzD,EAAaF,QAAQ2D,QAAUG,EAAc,CAC3CF,eAAgBjB,EAAeG,iBAAiBC,YAElD5D,EAAY,CACVuC,KAAM,qBACN6B,aAAcZ,EAAeG,iBAAiBS,aAC9CJ,OAAQW,EACRN,UAAU,GACT,CAAA,CA5CDb,GA8CN,CAAC,MAAAe,GAAA,OAAAd,QAAAmB,OAAAL,EAED,CAAA,CAyCMM,CAAqB9C,GACrB,MACF,IAAK,QACHhB,MAAAA,EAAaF,QAAQiE,SAArB/D,EAAaF,QAAQiE,QAAU/C,EAAQgD,YAAYC,eACnD,MACF,IAAK,YACHjE,MAAAA,EAAaF,QAAQoE,YAArBlE,EAAaF,QAAQoE,WAAa,CAChCC,SAAUnD,EAAQoD,gBAAgBC,YAEpC,MACF,IAAK,eACHrE,MAAAA,EAAaF,QAAQwE,gBAArBtE,EAAaF,QAAQwE,eAAiBtD,EAAQuD,oBAC9C,MACF,IAAK,gBACHvE,MAAAA,EAAaF,QAAQ0E,eAArBxE,EAAaF,QAAQ0E,cAAgBxD,EAAQyD,eAC7C,MACF,IAAK,wBACHzE,MAAAA,EAAaF,QAAQ4E,uBAArB1E,EAAaF,QAAQ4E,sBAAwB1D,EAAQ2D,uBACrD,MACF,IAAK,qBACH3E,MAAAA,EAAaF,QAAQ8E,oBAArB5E,EAAaF,QAAQ8E,mBAAqB5D,EAAQ6D,oBAClD,MACF,IAAK,sBACH7E,MAAAA,EAAaF,QAAQgF,qBAArB9E,EAAaF,QAAQgF,oBAAsB9D,EAAQ+D,qBAEL,aAA1C/D,EAAQ+D,oBAAoBlC,WAE9BhD,EAAgBC,QAAQ,SAE1B,MACF,IAAK,mCACwC,MAA3CE,EAAaF,QAAQkF,wBAArBhF,EAAaF,QAAQkF,uBACnBhE,EAAQiE,wCAEV,MACF,IAAK,gCACHjF,EAAaF,QAAQoF,yBAArBlF,EAAaF,QAAQoF,wBACnBlE,EAAQmE,+BAEV,MACF,IAAK,2BACyC,MAA5CnF,EAAaF,QAAQsF,yBAArBpF,EAAaF,QAAQsF,wBAA0BpE,EAAQqE,oBACvD,MACF,QACErF,MAAAA,EAAaF,QAAQwF,SAArBtF,EAAaF,QAAQwF,QAAUtE,GA3EnC,MALEhB,MAAAA,EAAaF,QAAQwF,SAArBtF,EAAaF,QAAQwF,QAAU,CAC7B9D,KAAM,gBACNR,QAAAA,GAiFN,OAGF,EC3MauE,EAAqB,SAAH1G,GAC7B,IAAA2G,EAAQ3G,EAAR2G,SACAC,EAAS5G,EAAT4G,UACAC,EAAK7G,EAAL6G,MACAC,EAAO9G,EAAP8G,QACAC,EAAW/G,EAAX+G,YACAC,EAAchH,EAAdgH,eACApC,EAAO5E,EAAP4E,QACAqC,EAAajH,EAAbiH,cACA9G,EAASH,EAATG,UACA+G,EAAkBlH,EAAlBkH,mBACA9G,EAAWJ,EAAXI,YACAE,EAAWN,EAAXM,YACAC,EAAoBP,EAApBO,qBACAC,EAAYR,EAAZQ,aACA2G,EAAkBnH,EAAlBmH,mBAGMC,EAAetG,EAAK,QAACuG,QAAQ,WACjC,OAAuB,MAAlBF,IAAAA,EAAoBG,uBAKlB,CACLC,MAAO,CACLC,kBAAkB,EAClBC,kBAAkB,GAEpBC,0BAA2B,CACzBJ,uBAAuB,GAG7B,EAAG,CAACH,iBAEJ,OACErG,UAAC6G,cAAAC,EAAAA,YACC,CAAAhB,UAAWA,EACXC,MAAOA,EACPC,QAASA,EACTS,MAAOH,EACPS,OAAO,EACPC,QAAS,CACPC,eAAgB,CAAEC,aAAc,WAElCjB,YAAaA,EACbC,eAAgBA,EAChBpC,QAASA,gBAET9D,EAAA,QAAA6G,cAAC5H,EAAc,CACbE,QAASiH,EACThH,YAAa+G,EACb9G,UAAWA,EACXC,YAAaA,EACbE,YAAaA,EACbC,qBAAsBA,EACtBC,aAAcA,IAEfmG,EAGP,gDCxCMsB,eAAoBC,gBAA4C,2BAwCD,SAAtClI,GAAyC,IAAA2G,EAAQ3G,EAAR2G,SAAUQ,EAAkBnH,EAAlBmH,mBAEhFgB,EAAeA,kBAGf,IAAAC,EAA0BC,EAAQA,SAAC,IAA5BxB,EAAKuB,EAAA,GAAEE,EAAQF,KACtBG,EAA8BF,EAAAA,UAAS,GAAhCvB,EAAOyB,EAAA,GAAEC,EAAUD,EAC1B,GAAAE,EAA4BJ,EAAAA,SAA6B,gBAAlDK,EAAMD,EAAA,GAAEE,EAASF,EAAA,GACxBG,EAAkCP,WC9FF,mCD8FzBzB,EAASgC,EAAA,GAAEC,EAAYD,KAC9BE,EAA0CT,gBAA6BU,GAAhEC,EAAaF,EAAA,GAAEG,EAAgBH,KACtCI,EAA4Cb,EAAQA,SAAS,IAAtDc,EAAcD,EAAA,GAAEE,EAAiBF,EACxC,GAAAG,EAAoChB,EAAQA,UAAC,GAAtC7E,EAAU6F,EAAA,GAAEC,EAAaD,KAChCE,EAA8ClB,EAAAA,UAAS,GAAhDmB,EAAeD,EAAA,GAAEE,EAAkBF,KAGpCG,EAAoB5I,EAAAA,QAAMC,OAAO,GACjC4I,EAAyB7I,EAAAA,QAAMC,OAAO,GAGtC6I,EAAiB9I,UAAMC,OAAyC,CAAE,GAGxE8I,EEzGsC,WACtC,IAAM1I,EAAeJ,SAAkB,CAAA,GAEjC+I,EAAeC,EAAAA,YAAY,SAAC5J,GAChCgB,EAAaF,QAAUd,CACzB,EAAG,IAEH,MAAO,CACLgB,aAAAA,EACA2I,aAAAA,EAEJ,CF8F2DE,GAAjD7I,EAAY0I,EAAZ1I,aAA4B8I,EAAgBJ,EAA9BC,aAGhBA,EAAehJ,EAAK,QAACiJ,YAAY,SAAC5J,GACtC,IAAM+J,EAAgBC,EAAA,CAAA,EACjBhK,EAAS,CACZmD,aAAc,SAACd,GACb8G,EAA6B,aAAf9G,EAAMe,MACpBpD,MAAAA,EAAUmD,cAAVnD,EAAUmD,aAAed,EAC3B,IAEFyH,EAAiBC,EACnB,EAAG,CAACD,IAEJG,EG/GoC,SACpCjJ,EACAwH,EACAH,EACAF,EACAc,EACAJ,GAEA,IAAAZ,EAAkCC,EAAQA,SACxC,IADKgC,EAASjC,EAAA,GAAEkC,EAAYlC,EAG9B,GAAAG,EACEF,EAAAA,SAAmD,MAD9CkC,EAAkBhC,EAAA,GAAEiC,EAAqBjC,EAEhD,GAAAE,EAAgDJ,EAAQA,SAEtD,IAFKoC,EAAgBhC,EAAA,GAAEiC,EAAmBjC,EAG5C,GAAAG,EAA4BP,EAAAA,cAAuCU,GAA5D4B,EAAM/B,EAAEgC,GAAAA,EAAShC,EAExB,GA6EA,MAAO,CACLiC,aA9EmBd,EAAWA,YAAA,SACvBe,GAA0B,WAAIjH,QAAAC,gCAAA,WAC/BiH,SAAAA,EAAAC,GA4BF,IAAMC,ECzDgC,SAACpE,GAC7C,IAAIqE,IAAAA,EAAAC,EAIF,OAAOA,OAAAA,WAFQD,EADM9I,KAAKC,MAAM+I,KAAKvE,EAAMwE,MAAM,KAAK,KAC1BxD,cAAbqD,EAAoBvK,OAAQ,IAE7B2K,MAAM,6BAAbH,EAAAA,EAAsC,KAAM,EACrD,CAAE,MAAOI,GAEP,OADAC,QAAQC,KAAK,gDACN,EACT,CACF,CDgDUC,CAA+BC,GACjCvC,EAAkB6B,GAElB3C,EAASqD,GACTnD,GAAW,EAAM,CAxBjB,IAAImD,EARJhD,EAAU,cACyB,MAAnCxH,EAAaF,QAAQ2K,gBAArBzK,EAAaF,QAAQ2K,eAAiB,CAAElD,OAAQ,eAEhD4B,EAAaQ,EAAOT,WAAa,CAAE,GACnCG,EAAsBM,EAAOP,oBAAsB,MACnDG,EAAoBI,EAAOL,kBAAoB,CAAE,GACjDG,EAAUE,EAAOH,QAEa,IAAA1G,EAE1B6G,WAAAA,IAAAA,EAAOa,kBAEAb,OAAAA,WAAAA,GAAAA,EAAOe,QAMuC,OALvDL,QAAQM,KACN,0CACAhB,EAAOe,SAG8ChI,QAAAC,QCpCpD,SACX+H,EACA7C,GAAsB,IAGsD,OAAAnF,QAAAC,QACrDiI,OADrB/C,GAAiB,0DAEM6C,aAAAA,sCAA2C/L,IACnEqE,KAAA,SAFK6H,GAAQnI,OAAAA,QAAAC,QAIKkI,EAASC,QAAM9H,KAAA,SAA5B+H,GAEN,IAAKF,EAASG,GACZ,MAAM,IAAIC,MAAK,qCAAsCF,EAAKG,OAAOlK,SAGnE,IAAK+J,EAAKrF,MACR,MAAM,IAAIuF,MAAM,2CAGlB,OAAOF,EAAKrF,KAAM,EAAA,EACpB,CAAC,MAAAlC,UAAAd,QAAAmB,OAAAL,EAAA,CAAA,CDgBmC2H,CACxBxB,EAAOe,QAFQf,EAAO9B,eAAiBA,IAIxC7E,KAAAoI,SAAAA,GAHDZ,EAAiBY,CAGf,GAEF,MAAM,IAAIH,MAAM,mDAZPtB,GADTa,EAAoBb,EAAOa,kBADzBb,UAciE7G,GAAAA,EAAAE,KAAAF,EAAAE,KAAA4G,GAAAA,GASvE,6DAnCmCrG,CAAA,EAmClC,SAAQ6G,GAIP,MAHA5C,EAAU,gBACyB,MAAnCxH,EAAaF,QAAQ2K,gBAArBzK,EAAaF,QAAQ2K,eAAiB,CAAElD,OAAQ,iBACpB,MAA5BvH,EAAaF,QAAQ2D,SAArBzD,EAAaF,QAAQ2D,QAAU2G,GACzBA,CACR,GACF,CAAC,MAAA5G,GAAA,OAAAd,QAAAmB,OAAAL,KACD,CACExD,EACAwH,EACAH,EACAF,EACAc,EACAJ,IA8BFwD,WA1BiBzC,EAAWA,YAAA,SACrB0C,QAAA,IAAAA,IAAAA,EAA2B,QAAU,IAC1C,IACEjE,GAAW,GACXF,EAAS,IACTK,EAAU,gBAGV2B,EAAa,CAAE,GACfE,EAAsB,MACtBE,EAAoB,CAAE,GACtBE,OAAU7B,GACVK,EAAkB,IAElBjI,MAAAA,EAAaF,QAAQ2K,gBAArBzK,EAAaF,QAAQ2K,eAAiB,CAAElD,OAAQ,iBAChDvH,MAAAA,EAAaF,QAAQyL,cAArBvL,EAAaF,QAAQyL,aAAe,CAAED,OAAAA,GACxC,CAAE,MAAOlB,GAEP,YADApK,EAAaF,QAAQ2D,SAArBzD,EAAaF,QAAQ2D,QAAU2G,GACzBA,CACR,CAAC,OAAA1H,QAAAC,SACH,CAAC,MAAAa,GAAAd,OAAAA,QAAAmB,OAAAL,EAAA,CAAA,EACD,CAACxD,EAAcqH,EAAYF,EAAUK,EAAWS,IAMhDiB,UAAAA,EACAE,mBAAAA,EACAE,iBAAAA,EACAE,OAAAA,EAEJ,CHeMgC,CAAuBxL,EAAcwH,EAAWH,EAAYF,EAAUc,EAAmBJ,GAN3F6B,EAAYT,EAAZS,aACA2B,EAAUpC,EAAVoC,WACAnC,EAASD,EAATC,UACAE,EAAkBH,EAAlBG,mBACAE,EAAgBL,EAAhBK,iBACAE,EAAMP,EAANO,OAGFiC,EK9H4B,SAC5BzL,EACAwH,EACAQ,EACAT,GAEA,IAAAN,EAA0CC,EAAQA,UAAC,GAA5CpB,EAAamB,EAAEyE,GAAAA,EAAgBzE,KACtCG,EACEF,EAAQA,SAA0B,MAD7B5H,EAAgB8H,KAAEuE,EAAmBvE,EAE5C,GAAMwE,EAAwBhM,EAAMA,QAAC,GAGrCK,YAAU,WACJ+H,IACF0D,GAAiB,GACjBC,EAAoB,MACpBC,EAAsB9L,SAAU,EAEpC,EAAG,CAACkI,IAEJ/H,EAAAA,UAAU,WAMR,OALW,eAAcyC,OAAAA,QAAAC,QACjBkJ,EAAAA,aAAaC,qBAAmB9I,kBACxC,CAAC,MAAAQ,GAAAd,OAAAA,QAAAmB,OAAAL,EAEDuI,CAAAA,CAAAA,GACO,WACLF,EAAAA,aAAaG,kBACf,CACF,EAAG,IAGH/L,YAAU,WACJX,GAAoBwG,IAAkB8F,EAAsB9L,UAC9D8L,EAAsB9L,SAAU,EAChCE,MAAAA,EAAaF,QAAQmM,WAArBjM,EAAaF,QAAQmM,UAAY,CAAEjE,eAAAA,IAEvC,EAAG,CAAC1I,EAAkBwG,EAAekC,EAAgBhI,IAErD,IAAMkM,EAAyBtD,EAAWA,YACxC,SAACzI,GACKb,IAIJqM,EAAoBxL,GACpBqH,EAAU,aACZ,EACA,CAAClI,EAAkBkI,IAGf2E,EAAkBvD,EAAAA,YAAY,WAClC8C,GAAiB,EACnB,EAAG,IAEGU,EAAqBxD,cAAY,WAEtB,iBAAXrB,IAIJmE,GAAiB,GACjBlE,EAAU,gBACVmE,EAAoB,MACpBC,EAAsB9L,SAAU,EACC,MAAjCE,EAAaF,QAAQyL,cAArBvL,EAAaF,QAAQyL,aAAe,CAAED,OAAQ,SAChD,EAAG,CAACtL,EAAcwH,EAAWD,IAEvB8E,EAAczD,cAClB,SAACwB,GACCC,QAAQD,MAAM,iBAAkBA,SAChCpK,EAAaF,QAAQ2D,SAArBzD,EAAaF,QAAQ2D,QAAU2G,EAAMpJ,aAAS4G,EAChD,EACA,CAAC5H,IAGH,MAAO,CACL8F,cAAAA,EACAxG,iBAAAA,EACA4M,uBAAAA,EACAC,gBAAAA,EACAC,mBAAAA,EACAC,YAAAA,EAEJ,CLiDMC,CAAetM,EAAcwH,EAAWQ,EAAgBT,GAN1DzB,EAAa2F,EAAb3F,cACAxG,EAAgBmM,EAAhBnM,iBACA4M,EAAsBT,EAAtBS,uBACAC,EAAeV,EAAfU,gBACAC,EAAkBX,EAAlBW,mBACAC,GAAWZ,EAAXY,YAIIE,GAA8B5M,UAAMiJ,YAAY,WAEpDL,EAAkBzI,QAAU,EAC5B0I,EAAuB1I,QAAU,EACjCwI,GAAmB,SACnBtI,EAAaF,QAAQ0M,yBAArBxM,EAAaF,QAAQ0M,wBAA0B,CAAEnE,iBAAiB,IAElE8D,GACF,EAAG,CAACA,EAAiBnM,IAGfyM,GAAiC9M,UAAMiJ,YAAY,WACvDN,GAAmB,GACnBH,GAAc,GACdiE,GACF,EAAG,CAACA,IAEJM,GM1J+B,SAC/BnF,EACAjI,EACAU,GAwBA,MAAO,CAAEf,YAtBW2J,EAAAA,YACX5H,SAAAA,GAAoB,IACzB,GAAe,cAAXuG,IAA2BjI,EAI7B,OAHA+K,QAAQC,KACN,mEAEF5H,QAAAC,UACD,IAAAG,2BAGOiI,GADU,IAAI4B,aACCC,OAAO3L,KAAKkC,UAAUnC,IAAU0B,QAAAC,QAE/CrD,EAAiBuN,YAAY9B,EAAM,CAAE+B,UAAU,KAAO9J,KAAA,WAAA,yBAJ1D,IAEI+H,sCAHPxH,CACG,EAKH,SAAQ6G,GACPC,QAAQD,MAAM,qCAAsCA,GACpDC,QAAQD,MAAM,iBAAkBA,SAChCpK,EAAaF,QAAQ2D,SAArBzD,EAAaF,QAAQ2D,QAAU2G,EACjC,GAAC1H,OAAAA,QAAAC,QAAAG,GAAAA,EAAAE,KAAAF,EAAAE,KAAA,WAAA,QAAA,EACH,CAAC,MAAAQ,GAAA,OAAAd,QAAAmB,OAAAL,EAAA,CAAA,EACD,CAAC+D,EAAQjI,EAAkBU,IAI/B,CN8H0B+M,CAAkBxF,EAAQjI,EAAkBU,GAA5Df,GAAWyN,GAAXzN,YAEF+N,GAAwBrN,UAAMiJ,YAAY,WAC9C,IAAMqE,EAAqB1E,EAAkBzI,UAAY0I,EAAuB1I,QAE5EuI,IAAoB4E,IACtB3E,EAAmB2E,GACyB,MAA5CjN,EAAaF,QAAQ0M,yBAArBxM,EAAaF,QAAQ0M,wBAA0B,CAAEnE,gBAAiB4E,IAEtE,EAAG,CAAC5E,EAAiBrI,IAEfkN,GAAevN,EAAAA,QAAMiJ,YAAY,SAACuE,GACjC9E,GAeLpJ,GANwB,CACtBuC,KAAM,WACN4L,MAAOD,EAAO,OAAS,UACvB5K,SAAUgG,EAAkBzI,UAI9B0I,EAAuB1I,QAAUyI,EAAkBzI,QACnDkN,MAhBE3C,QAAQC,KAC6B,IAAnC9B,EAAuB1I,QACnB,8DACA,iFAcV,EAAG,CAACuI,EAAiBpJ,GAAa+N,KAGhBrN,EAAK,QAACiJ,YAAY,SAACyE,GACnChD,QAAQC,KAAK,uDACf,EAAG,IAEH,IAAMgD,GAAQ3N,EAAK,QAACiJ,YAAY,WAAA,OAAMZ,CAAc,EAAE,CAACA,IAEjDuF,GAAc5N,UAAMiJ,YAAY,SAAC4E,GACjClO,GACFA,EAAiBmO,sBAAsBD,EAE3C,EAAG,CAAClO,IAGEF,GAAuBO,UAAMiJ,YAAY,SAACtG,GAC9CiG,EAAkBzI,QAAUwC,EAC5B0K,IACF,EAAG,CAACA,KAGEU,GAAsC/N,EAAK,QAACiJ,YAAY,SAACzI,GAC7D+L,EAAuB/L,GAEvB,IAAMwN,WOjNRhE,GAA0B,IAAAiE,EAMJC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAJhBP,EAA4C,CAChDnM,KAAM,uCAqCR,OAlCImI,EAAOT,YACTyE,EAAeQ,6BAA+B,CAC5CC,MAAO,CACLC,OAAQR,OAAFA,EAAElE,EAAOT,UAAUkF,YAAjBP,EAAAA,EAAwBQ,OAChCC,cAAeR,OAAFA,EAAEnE,EAAOT,UAAUkF,YAAjBN,EAAAA,EAAwBS,aACvCC,SAAUT,OAAFA,EAAEpE,EAAOT,UAAUkF,YAAjBL,EAAAA,EAAwBS,UAEpCC,IAAK,CACHC,SAAUV,OAAFA,EAAErE,EAAOT,UAAUuF,UAAjBT,EAAAA,EAAsBW,QAChCC,MAAOX,OAAFA,EAAEtE,EAAOT,UAAUuF,UAAjBR,EAAAA,EAAsBW,OAE/BC,aAAc,CACZC,UAAWZ,OAAFA,EAAEvE,EAAOT,UAAU2F,mBAAjBX,EAAAA,EAA+Ba,YAKhDpB,EAAeqB,YAAc,CAC3BjN,OAAQ,mBACRkN,SAAyBrB,OAAhBA,EAAAjE,EAAOT,mBAAS0E,EAAhBA,EAAkBsB,eAAlBtB,EAA0BqB,UAAWtQ,GAG5CgL,EAAOP,qBACTuE,EAAewB,sBAAwBxF,EAAOP,oBAG5CO,EAAOL,mBACTqE,EAAeyB,kBAAoBzF,EAAOL,kBAGxCK,EAAOH,SACTmE,EAAe0B,QAAUjM,OAAOuG,EAAOH,SAGlCmE,CACT,CPwK2B2B,CAAmB,CACxCpG,UAAAA,EACAE,mBAAAA,EACAE,iBAAAA,EACAE,OAAAA,IAGF,GAAImE,EACF,IACE,IACM5C,GADU,IAAI4B,aACCC,OAAO3L,KAAKkC,UAAUwK,IAC3CxN,EAAY0M,YAAY9B,EAAM,CAAE+B,UAAU,GAC5C,CAAE,MAAO1C,GACPC,QAAQD,MAAM,4BAA6BA,SAC3CpK,EAAaF,QAAQ2D,SAArBzD,EAAaF,QAAQ2D,QAAU2G,EACjC,CAEJ,EAAG,CAAC8B,EAAwBhD,EAAWE,EAAoBE,EAAkBE,EAAQxJ,IAG/EuP,GAAiB5P,UAAMiJ,YAAY,SAAC4G,GACxC/G,EAAe3I,QAAU0P,CAC3B,EAAG,IAGGC,GAAuB9P,EAAAA,QAAMiJ,YAAY,SAAC8G,GAC9CzQ,GAAY,CACVuC,KAAM,oBACNkO,KAAAA,GAEJ,EAAG,CAACzQ,KAEE0Q,GAAkBhQ,EAAAA,QAAMiJ,YAAY,SAAC8G,GACzCzQ,GAAY,CACVuC,KAAM,eACNkO,KAAAA,GAEJ,EAAG,CAACzQ,KAEE2Q,GAAmBjQ,EAAK,QAACiJ,YAAY,WACzC3J,GAAY,CACVuC,KAAM,iBAEV,EAAG,CAACvC,KAGE4Q,GAAwBlQ,UAAMC,OAAO,CACzC8J,aAAAA,EACA2B,WAAAA,EACA9D,OAAAA,EACAlF,WAAAA,EACAgG,gBAAAA,EACAiF,MAAAA,GACAC,YAAAA,GACAL,aAAAA,GACAuC,qBAAAA,GACAE,gBAAAA,GACAC,iBAAAA,KAIFC,GAAsB/P,QAAU,CAC9B4J,aAAAA,EACA2B,WAAAA,EACA9D,OAAAA,EACAlF,WAAAA,EACAgG,gBAAAA,EACAiF,MAAAA,GACAC,YAAAA,GACAL,aAAAA,GACAuC,qBAAAA,GACAE,gBAAAA,GACAC,iBAAAA,IAKF,IAAMf,GAAelP,EAAAA,QAAMuG,QAAsB,WAAA,MAAO,CACtD,gBAAIwD,GAAiB,OAAOmG,GAAsB/P,QAAQ4J,YAAc,EACxE,cAAI2B,GAAe,OAAOwE,GAAsB/P,QAAQuL,UAAY,EACpE,UAAI9D,GAAW,OAAOsI,GAAsB/P,QAAQyH,MAAQ,EAC5D,cAAIlF,GAAe,OAAOwN,GAAsB/P,QAAQuC,UAAY,EACpE,mBAAIgG,GAAoB,OAAOwH,GAAsB/P,QAAQuI,eAAiB,EAC9E,SAAIiF,GAAU,OAAOuC,GAAsB/P,QAAQwN,KAAO,EAC1D,eAAIC,GAAgB,OAAOsC,GAAsB/P,QAAQyN,WAAa,EACtE,gBAAIL,GAAiB,OAAO2C,GAAsB/P,QAAQoN,YAAc,EACxE,wBAAIuC,GAAyB,OAAOI,GAAsB/P,QAAQ2P,oBAAsB,EACxF,mBAAIE,GAAoB,OAAOE,GAAsB/P,QAAQ6P,eAAiB,EAC9E,oBAAIC,GAAqB,OAAOC,GAAsB/P,QAAQ8P,gBAAkB,EACjF,EAAG,IAGEE,GAAenQ,EAAAA,QAAMuG,QAA+B,iBAAO,CAC/D2I,aAAAA,GACA7O,aAAAA,EACAyF,UAAAA,EACAoC,cAAAA,EACA1I,YAAasJ,EAAe3I,QAC5B6I,aAAAA,EACAjB,aAAAA,EACAI,iBAAAA,EACAyH,eAAAA,GACD,EAAG,CACFV,GACA7O,EACAyF,EACAoC,EACAc,EACA4G,kBAGF,OACE5P,wBAACmH,EAAkBiJ,SAAS,CAAAC,MAAOF,iBACjCnQ,UAAA6G,cAACjB,EAAkB,CACjBE,UAAWA,EACXC,MAAOA,EACPC,QAASA,EACTC,YAAa2G,GACb1G,eAAgB4G,GAChBhJ,QAAS4I,GACTvG,cAAeA,EACf9G,UAAWgB,EAAaF,QACxBiG,mBAAoB2H,GACpBzO,YAAaA,GACbE,YAAasJ,EAAe3I,QAC5BV,qBAAsBA,GACtBC,aAAcgM,EACdrF,mBAAoBA,GAEnBR,GAIT,oBA1S+B,SAACmB,QAA+B,IAA/BA,IAAAA,EAA+B,CAAA,GAC7D,IAAMsJ,EAAUC,EAAUA,WAACpJ,GAC3B,IAAKmJ,EACH,MAAM,IAAIhF,MAAM,0DAGlB,IAAQxF,EAAwDkB,EAAxDlB,UAAWoC,EAA6ClB,EAA7CkB,cAAe1I,EAA8BwH,EAA9BxH,YAAgBH,6IAASmR,CAAKxJ,EAALyJ,GAwB3D,OAtBAzQ,EAAK,QAACM,UAAU,WACVwF,GACFwK,EAAQvI,aAAajC,EAEzB,EAAG,CAACwK,EAASxK,IAEb9F,EAAAA,QAAMM,UAAU,WACV4H,GACFoI,EAAQnI,iBAAiBD,EAE7B,EAAG,CAACoI,EAASpI,IAEblI,EAAAA,QAAMM,UAAU,WACVd,GACF8Q,EAAQV,eAAepQ,EAE3B,EAAG,CAAC8Q,EAAS9Q,IAIb8Q,EAAQtH,aAAa3J,GAEdiR,EAAQpB,YACjB"}
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type * as Types from "@elevenlabs/types";
2
- import type { Incoming, Outgoing, Interruption, ConversationMetadata, Ping, Role as MessageRole, Mode as ConversationMode, Status, Callbacks, AsrInitiationMetadataEvent as AsrMetadataEvent } from "@elevenlabs/types";
2
+ import type { AsrInitiationMetadataEvent as AsrMetadataEvent, Callbacks, ConversationMetadata, Mode as ConversationMode, Incoming, Interruption, Role as MessageRole, Outgoing, Ping, Status } from "@elevenlabs/types";
3
3
  export type { Callbacks } from "@elevenlabs/types";
4
4
  /**
5
5
  * Role in the conversation
@@ -42,6 +42,7 @@ export type ConversationConfig = {
42
42
  };
43
43
  tts?: {
44
44
  voiceId?: string;
45
+ speed?: number;
45
46
  };
46
47
  conversation?: {
47
48
  textOnly?: boolean;
@@ -82,3 +83,19 @@ export type UserActivityEvent = Outgoing.UserActivityClientToOrchestratorEvent;
82
83
  export type MCPToolApprovalResultEvent = Outgoing.McpToolApprovalResultClientToOrchestratorEvent;
83
84
  export type InitiationClientDataEvent = Outgoing.ConversationInitiationClientToOrchestratorEvent;
84
85
  export type ConversationEvent = UserTranscriptionEvent | AgentResponseEvent | AgentResponseCorrectionEvent | AgentAudioEvent | InterruptionEvent | InternalTentativeAgentResponseEvent | ConfigEvent | PingEvent | ClientToolCallEvent | VadScoreEvent | MCPToolCallClientEvent | MCPConnectionStatusEvent | AgentToolRequestEvent | AgentToolResponseEvent | ConversationMetadataEvent | AsrInitiationMetadataEvent | AgentChatResponsePartEvent;
86
+ /**
87
+ * Audio session configuration for controlling how the SDK handles audio
88
+ */
89
+ export interface AudioSessionConfig {
90
+ /**
91
+ * Whether audio should mix with other audio sources.
92
+ * When true, the SDK will configure the audio session to allow
93
+ * concurrent audio playback with other audio sources.
94
+ *
95
+ * iOS: Adds AVAudioSessionCategoryOptionMixWithOthers
96
+ * Android: Uses AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
97
+ *
98
+ * @default false (exclusive audio session)
99
+ */
100
+ allowMixingWithOthers?: boolean;
101
+ }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "0.5.4";
1
+ export declare const PACKAGE_VERSION = "0.5.6";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevenlabs/react-native",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "ElevenLabs React Native SDK for Conversational AI",
5
5
  "main": "./dist/lib.js",
6
6
  "module": "./dist/lib.module.js",
@@ -32,13 +32,13 @@
32
32
  "react-native": ">=0.70.0"
33
33
  },
34
34
  "dependencies": {
35
- "@elevenlabs/types": "0.3.1"
35
+ "@elevenlabs/types": "0.4.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@testing-library/jest-native": "^5.4.3",
39
39
  "@testing-library/react-native": "^13.2.0",
40
40
  "@types/jest": "^29.5.12",
41
- "@types/react": "^19.0.0",
41
+ "@types/react": "^19.1.1",
42
42
  "@types/react-native": "^0.73.0",
43
43
  "eslint": "^9.8.0",
44
44
  "jest": "^29.7.0",
@@ -78,7 +78,11 @@ jest.mock('./components/MessageHandler', () => ({
78
78
  }));
79
79
 
80
80
  jest.mock('./components/LiveKitRoomWrapper', () => ({
81
- LiveKitRoomWrapper: ({ children }: { children: ReactNode }) => <>{children}</>,
81
+ LiveKitRoomWrapper: ({ children }: { children: ReactNode }) => (
82
+ // The actual LiveKitRoomWrapper receives key prop from parent (ElevenLabsProvider)
83
+ // Children are passed through and should not remount when key changes
84
+ <div>{children}</div>
85
+ ),
82
86
  }));
83
87
 
84
88
  describe('ElevenLabsProvider', () => {
@@ -190,5 +194,64 @@ describe('ElevenLabsProvider', () => {
190
194
  );
191
195
  }).not.toThrow();
192
196
  });
197
+
198
+ it('should maintain stable conversation object reference to prevent infinite loops', () => {
199
+ const useEffectCallCount = jest.fn();
200
+ const conversationRefs: any[] = [];
201
+ let capturedConversation: any = null;
202
+
203
+ const TestComponent = () => {
204
+ const conversation = useConversation();
205
+
206
+ // Capture conversation for external testing
207
+ capturedConversation = conversation;
208
+
209
+ // Track the conversation object reference on each render
210
+ conversationRefs.push(conversation);
211
+
212
+ // Using conversation in useEffect deps should not cause an infinite loop
213
+ React.useEffect(() => {
214
+ useEffectCallCount();
215
+ // Simulate calling startSession which triggers state changes
216
+ // In real usage, this would call conversation.startSession(...)
217
+ }, [conversation]);
218
+
219
+ return <TestText>Test component</TestText>;
220
+ };
221
+
222
+ const { rerender } = render(
223
+ <ElevenLabsProvider>
224
+ <TestComponent />
225
+ </ElevenLabsProvider>
226
+ );
227
+
228
+ // Initial render - effect should run once
229
+ expect(useEffectCallCount).toHaveBeenCalledTimes(1);
230
+ const firstConversationRef = conversationRefs[0];
231
+
232
+ // Verify the conversation object has all required properties
233
+ expect(firstConversationRef).toHaveProperty('startSession');
234
+ expect(firstConversationRef).toHaveProperty('endSession');
235
+ expect(firstConversationRef).toHaveProperty('status');
236
+ expect(firstConversationRef).toHaveProperty('isSpeaking');
237
+
238
+ // Force a re-render by calling rerender
239
+ rerender(
240
+ <ElevenLabsProvider>
241
+ <TestComponent />
242
+ </ElevenLabsProvider>
243
+ );
244
+
245
+ // After re-render, verify conversation reference is still the same
246
+ expect(conversationRefs[conversationRefs.length - 1]).toBe(firstConversationRef);
247
+
248
+ // Effect should NOT run again because conversation reference is stable
249
+ expect(useEffectCallCount).toHaveBeenCalledTimes(1);
250
+
251
+ // Verify ALL conversation references collected are the same object
252
+ conversationRefs.forEach((ref, index) => {
253
+ expect(ref).toBe(firstConversationRef);
254
+ });
255
+ });
193
256
  });
194
257
  });
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { createContext, useContext, useState } from 'react';
3
3
  import { registerGlobals } from '@livekit/react-native';
4
4
  import type { LocalParticipant } from 'livekit-client';
5
- import type { Callbacks, ConversationConfig, ConversationStatus, ClientToolsConfig } from './types';
5
+ import type { Callbacks, ConversationConfig, ConversationStatus, ClientToolsConfig, AudioSessionConfig } from './types';
6
6
  import { constructOverrides } from './utils/overrides';
7
7
  import { DEFAULT_SERVER_URL } from './utils/constants';
8
8
  import { useConversationCallbacks } from './hooks/useConversationCallbacks';
@@ -81,9 +81,10 @@ export const useConversation = (options: ConversationOptions = {}): Conversation
81
81
 
82
82
  interface ElevenLabsProviderProps {
83
83
  children: React.ReactNode;
84
+ audioSessionConfig?: AudioSessionConfig;
84
85
  }
85
86
 
86
- export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children }) => {
87
+ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children, audioSessionConfig }) => {
87
88
  // Initialize globals on mount
88
89
  registerGlobals();
89
90
 
@@ -255,8 +256,8 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
255
256
  });
256
257
  }, [sendMessage]);
257
258
 
258
- // Memoize the conversation object to prevent unnecessary re-renders
259
- const conversation = React.useMemo<Conversation>(() => ({
259
+ // Store all conversation values/functions in refs for stable access
260
+ const conversationValuesRef = React.useRef({
260
261
  startSession,
261
262
  endSession,
262
263
  status,
@@ -268,7 +269,10 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
268
269
  sendContextualUpdate,
269
270
  sendUserMessage,
270
271
  sendUserActivity,
271
- }), [
272
+ });
273
+
274
+ // Update ref on every render
275
+ conversationValuesRef.current = {
272
276
  startSession,
273
277
  endSession,
274
278
  status,
@@ -280,7 +284,23 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
280
284
  sendContextualUpdate,
281
285
  sendUserMessage,
282
286
  sendUserActivity,
283
- ]);
287
+ };
288
+
289
+ // Create a stable conversation object that never changes reference
290
+ // This prevents infinite loops when conversation is used in useEffect dependencies
291
+ const conversation = React.useMemo<Conversation>(() => ({
292
+ get startSession() { return conversationValuesRef.current.startSession; },
293
+ get endSession() { return conversationValuesRef.current.endSession; },
294
+ get status() { return conversationValuesRef.current.status; },
295
+ get isSpeaking() { return conversationValuesRef.current.isSpeaking; },
296
+ get canSendFeedback() { return conversationValuesRef.current.canSendFeedback; },
297
+ get getId() { return conversationValuesRef.current.getId; },
298
+ get setMicMuted() { return conversationValuesRef.current.setMicMuted; },
299
+ get sendFeedback() { return conversationValuesRef.current.sendFeedback; },
300
+ get sendContextualUpdate() { return conversationValuesRef.current.sendContextualUpdate; },
301
+ get sendUserMessage() { return conversationValuesRef.current.sendUserMessage; },
302
+ get sendUserActivity() { return conversationValuesRef.current.sendUserActivity; },
303
+ }), []); // Empty deps - object is created once and never recreated
284
304
 
285
305
  // Memoize the context value to prevent unnecessary re-renders of consumers
286
306
  const contextValue = React.useMemo<ElevenLabsContextType>(() => ({
@@ -305,7 +325,6 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
305
325
  return (
306
326
  <ElevenLabsContext.Provider value={contextValue}>
307
327
  <LiveKitRoomWrapper
308
- key={conversationId || 'disconnected'}
309
328
  serverUrl={serverUrl}
310
329
  token={token}
311
330
  connect={connect}
@@ -319,6 +338,7 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
319
338
  clientTools={clientToolsRef.current}
320
339
  updateCurrentEventId={updateCurrentEventId}
321
340
  onEndSession={endSession}
341
+ audioSessionConfig={audioSessionConfig}
322
342
  >
323
343
  {children}
324
344
  </LiveKitRoomWrapper>
@@ -2,7 +2,7 @@
2
2
  import React from 'react';
3
3
  import { LiveKitRoom } from '@livekit/react-native';
4
4
  import type { LocalParticipant } from 'livekit-client';
5
- import type { Callbacks, ClientToolsConfig } from '../types';
5
+ import type { Callbacks, ClientToolsConfig, AudioSessionConfig } from '../types';
6
6
  import { MessageHandler } from './MessageHandler';
7
7
 
8
8
  interface LiveKitRoomWrapperProps {
@@ -20,6 +20,7 @@ interface LiveKitRoomWrapperProps {
20
20
  clientTools: ClientToolsConfig['clientTools'];
21
21
  onEndSession: (reason?: "user" | "agent") => void;
22
22
  updateCurrentEventId?: (eventId: number) => void;
23
+ audioSessionConfig?: AudioSessionConfig;
23
24
  }
24
25
 
25
26
  export const LiveKitRoomWrapper = ({
@@ -37,13 +38,32 @@ export const LiveKitRoomWrapper = ({
37
38
  clientTools,
38
39
  updateCurrentEventId,
39
40
  onEndSession,
41
+ audioSessionConfig,
40
42
  }: LiveKitRoomWrapperProps) => {
43
+ // Configure audio options based on audioSessionConfig
44
+ const audioOptions = React.useMemo(() => {
45
+ if (!audioSessionConfig?.allowMixingWithOthers) {
46
+ return true;
47
+ }
48
+
49
+ // When mixing is enabled, configure audio to allow concurrent playback
50
+ return {
51
+ audio: {
52
+ noiseSuppression: true,
53
+ echoCancellation: true,
54
+ },
55
+ audioSessionConfiguration: {
56
+ allowMixingWithOthers: true,
57
+ },
58
+ };
59
+ }, [audioSessionConfig]);
60
+
41
61
  return (
42
62
  <LiveKitRoom
43
63
  serverUrl={serverUrl}
44
64
  token={token}
45
65
  connect={connect}
46
- audio={true}
66
+ audio={audioOptions}
47
67
  video={false}
48
68
  options={{
49
69
  adaptiveStream: { pixelDensity: 'screen' },