@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.
@@ -1,6 +1,7 @@
1
1
  import { useEffect } from "react";
2
- import { useLocalParticipant, useDataChannel } from "@livekit/react-native";
3
- import type { LocalParticipant } from "livekit-client";
2
+ import { useLocalParticipant, useDataChannel, useRoomContext } from "@livekit/react-native";
3
+ import { RoomEvent } from "livekit-client";
4
+ import type { LocalParticipant, RemoteParticipant } from "livekit-client";
4
5
  import type {
5
6
  Callbacks,
6
7
  ClientToolsConfig,
@@ -44,10 +45,34 @@ export const MessageHandler = ({
44
45
  onEndSession,
45
46
  }: MessageHandlerProps) => {
46
47
  const { localParticipant } = useLocalParticipant();
48
+ const room = useRoomContext();
47
49
 
48
50
  // Track agent response count for synthetic event IDs (WebRTC mode)
49
51
  const agentResponseCountRef = React.useRef(1);
50
52
 
53
+ // Refs for callbacks to avoid unnecessary effect re-runs
54
+ const onEndSessionRef = React.useRef(onEndSession);
55
+ onEndSessionRef.current = onEndSession;
56
+ const onReadyRef = React.useRef(onReady);
57
+ onReadyRef.current = onReady;
58
+ const callbacksRef = React.useRef(callbacks);
59
+ callbacksRef.current = callbacks;
60
+
61
+ // Detect agent disconnection
62
+ useEffect(() => {
63
+ const handleParticipantDisconnected = (participant: RemoteParticipant) => {
64
+ if (participant.identity?.startsWith("agent")) {
65
+ onEndSessionRef.current("agent");
66
+ }
67
+ };
68
+
69
+ room.on(RoomEvent.ParticipantDisconnected, handleParticipantDisconnected);
70
+
71
+ return () => {
72
+ room.off(RoomEvent.ParticipantDisconnected, handleParticipantDisconnected);
73
+ };
74
+ }, [room]);
75
+
51
76
  // Reset agent response count when connection status changes
52
77
  useEffect(() => {
53
78
  if (!isConnected) {
@@ -57,9 +82,9 @@ export const MessageHandler = ({
57
82
 
58
83
  useEffect(() => {
59
84
  if (isConnected && localParticipant) {
60
- onReady(localParticipant);
85
+ onReadyRef.current(localParticipant);
61
86
  }
62
- }, [isConnected, localParticipant, onReady]);
87
+ }, [isConnected, localParticipant]);
63
88
 
64
89
  const handleClientToolCall = async (clientToolCall: ClientToolCallEvent) => {
65
90
  if (clientToolCall.client_tool_call.tool_name in clientTools) {
@@ -81,7 +106,7 @@ export const MessageHandler = ({
81
106
  });
82
107
  } catch (e) {
83
108
  const errorMessage = `Client tool execution failed with following error: ${(e as Error)?.message}`;
84
- callbacks.onError?.(errorMessage, {
109
+ callbacksRef.current.onError?.(errorMessage, {
85
110
  clientToolName: clientToolCall.client_tool_call.tool_name,
86
111
  });
87
112
  sendMessage({
@@ -92,13 +117,13 @@ export const MessageHandler = ({
92
117
  });
93
118
  }
94
119
  } else {
95
- if (callbacks.onUnhandledClientToolCall) {
96
- callbacks.onUnhandledClientToolCall(clientToolCall.client_tool_call);
120
+ if (callbacksRef.current.onUnhandledClientToolCall) {
121
+ callbacksRef.current.onUnhandledClientToolCall(clientToolCall.client_tool_call);
97
122
  return;
98
123
  }
99
124
 
100
125
  const errorMessage = `Client tool with name ${clientToolCall.client_tool_call.tool_name} is not defined on client`;
101
- callbacks.onError?.(errorMessage, {
126
+ callbacksRef.current.onError?.(errorMessage, {
102
127
  clientToolName: clientToolCall.client_tool_call.tool_name,
103
128
  });
104
129
  sendMessage({
@@ -115,7 +140,7 @@ export const MessageHandler = ({
115
140
  const message = JSON.parse(decoder.decode(msg.payload));
116
141
 
117
142
  if (!isValidEvent(message)) {
118
- callbacks.onDebug?.({
143
+ callbacksRef.current.onDebug?.({
119
144
  type: "invalid_event",
120
145
  message,
121
146
  });
@@ -124,14 +149,15 @@ export const MessageHandler = ({
124
149
 
125
150
  const messageText = extractMessageText(message);
126
151
  if (messageText !== null) {
127
- callbacks.onMessage?.({
152
+ callbacksRef.current.onMessage?.({
128
153
  message: messageText,
129
154
  source: message.type === "user_transcript" ? "user" : "ai",
155
+ role: message.type === "user_transcript" ? "user" : "agent",
130
156
  });
131
157
  }
132
158
 
133
159
  if (msg.from?.isAgent) {
134
- callbacks.onModeChange?.({
160
+ callbacksRef.current.onModeChange?.({
135
161
  mode: msg.from?.isSpeaking ? "speaking" : "listening",
136
162
  });
137
163
 
@@ -153,48 +179,48 @@ export const MessageHandler = ({
153
179
  handleClientToolCall(message);
154
180
  break;
155
181
  case "audio":
156
- callbacks.onAudio?.(message.audio_event.audio_base_64);
182
+ callbacksRef.current.onAudio?.(message.audio_event.audio_base_64);
157
183
  break;
158
184
  case "vad_score":
159
- callbacks.onVadScore?.({
185
+ callbacksRef.current.onVadScore?.({
160
186
  vadScore: message.vad_score_event.vad_score,
161
187
  });
162
188
  break;
163
189
  case "interruption":
164
- callbacks.onInterruption?.(message.interruption_event);
190
+ callbacksRef.current.onInterruption?.(message.interruption_event);
165
191
  break;
166
192
  case "mcp_tool_call":
167
- callbacks.onMCPToolCall?.(message.mcp_tool_call);
193
+ callbacksRef.current.onMCPToolCall?.(message.mcp_tool_call);
168
194
  break;
169
195
  case "mcp_connection_status":
170
- callbacks.onMCPConnectionStatus?.(message.mcp_connection_status);
196
+ callbacksRef.current.onMCPConnectionStatus?.(message.mcp_connection_status);
171
197
  break;
172
198
  case "agent_tool_request":
173
- callbacks.onAgentToolRequest?.(message.agent_tool_request);
199
+ callbacksRef.current.onAgentToolRequest?.(message.agent_tool_request);
174
200
  break;
175
201
  case "agent_tool_response":
176
- callbacks.onAgentToolResponse?.(message.agent_tool_response);
202
+ callbacksRef.current.onAgentToolResponse?.(message.agent_tool_response);
177
203
 
178
204
  if (message.agent_tool_response.tool_name === "end_call") {
179
205
  // End the call
180
- onEndSession("agent");
206
+ onEndSessionRef.current("agent");
181
207
  }
182
208
  break;
183
209
  case "conversation_initiation_metadata":
184
- callbacks.onConversationMetadata?.(
210
+ callbacksRef.current.onConversationMetadata?.(
185
211
  message.conversation_initiation_metadata_event
186
212
  );
187
213
  break;
188
214
  case "asr_initiation_metadata":
189
- callbacks.onAsrInitiationMetadata?.(
215
+ callbacksRef.current.onAsrInitiationMetadata?.(
190
216
  message.asr_initiation_metadata_event
191
217
  );
192
218
  break;
193
219
  case "agent_chat_response_part":
194
- callbacks.onAgentChatResponsePart?.(message.text_response_part);
220
+ callbacksRef.current.onAgentChatResponsePart?.(message.text_response_part);
195
221
  break;
196
222
  default:
197
- callbacks.onDebug?.(message);
223
+ callbacksRef.current.onDebug?.(message);
198
224
  break;
199
225
  }
200
226
  });
package/src/index.ts CHANGED
@@ -12,4 +12,5 @@ export type {
12
12
  ConversationOptions,
13
13
  ConversationConfig,
14
14
  ConversationEvent,
15
+ AudioSessionConfig,
15
16
  } from "./types";
package/src/types.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import type * as Types from "@elevenlabs/types";
2
2
  import type {
3
+ AsrInitiationMetadataEvent as AsrMetadataEvent,
4
+ Callbacks,
5
+ ConversationMetadata,
6
+ Mode as ConversationMode,
3
7
  Incoming,
4
- Outgoing,
5
8
  Interruption,
6
- ConversationMetadata,
7
- Ping,
8
9
  Role as MessageRole,
9
- Mode as ConversationMode,
10
+ Outgoing,
11
+ Ping,
10
12
  Status,
11
- Callbacks,
12
- AsrInitiationMetadataEvent as AsrMetadataEvent,
13
13
  } from "@elevenlabs/types";
14
14
  export type { Callbacks } from "@elevenlabs/types";
15
15
 
@@ -70,6 +70,7 @@ export type ConversationConfig = {
70
70
  };
71
71
  tts?: {
72
72
  voiceId?: string;
73
+ speed?: number;
73
74
  };
74
75
  conversation?: {
75
76
  textOnly?: boolean;
@@ -139,3 +140,20 @@ export type ConversationEvent =
139
140
  | ConversationMetadataEvent
140
141
  | AsrInitiationMetadataEvent
141
142
  | AgentChatResponsePartEvent;
143
+
144
+ /**
145
+ * Audio session configuration for controlling how the SDK handles audio
146
+ */
147
+ export interface AudioSessionConfig {
148
+ /**
149
+ * Whether audio should mix with other audio sources.
150
+ * When true, the SDK will configure the audio session to allow
151
+ * concurrent audio playback with other audio sources.
152
+ *
153
+ * iOS: Adds AVAudioSessionCategoryOptionMixWithOthers
154
+ * Android: Uses AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
155
+ *
156
+ * @default false (exclusive audio session)
157
+ */
158
+ allowMixingWithOthers?: boolean;
159
+ }
@@ -17,6 +17,7 @@ export function constructOverrides(
17
17
  },
18
18
  tts: {
19
19
  voice_id: config.overrides.tts?.voiceId,
20
+ speed: config.overrides.tts?.speed,
20
21
  },
21
22
  conversation: {
22
23
  text_only: config.overrides.conversation?.textOnly,
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated during build
2
- export const PACKAGE_VERSION = "0.5.4";
2
+ export const PACKAGE_VERSION = "0.5.6";