@elevenlabs/react-native 0.5.12 → 1.0.0-rc.0

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.
Files changed (62) hide show
  1. package/.turbo/turbo-build.log +2 -12
  2. package/.turbo/turbo-check-types.log +1 -1
  3. package/.turbo/turbo-generate-version.log +1 -1
  4. package/.turbo/turbo-lint$colon$es.log +2 -2
  5. package/.turbo/turbo-lint$colon$prettier.log +1 -1
  6. package/CHANGELOG.md +88 -4
  7. package/README.md +42 -324
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +7 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/index.react-native.d.ts +2 -0
  13. package/dist/index.react-native.d.ts.map +1 -0
  14. package/dist/index.react-native.js +35 -0
  15. package/dist/index.react-native.js.map +1 -0
  16. package/dist/version.d.ts +2 -1
  17. package/dist/version.d.ts.map +1 -0
  18. package/dist/version.js +3 -0
  19. package/dist/version.js.map +1 -0
  20. package/package.json +13 -26
  21. package/src/index.react-native.ts +51 -0
  22. package/src/index.ts +25 -16
  23. package/src/version.ts +1 -1
  24. package/tsconfig.build.json +19 -0
  25. package/tsconfig.build.tsbuildinfo +1 -0
  26. package/tsconfig.json +5 -17
  27. package/dist/ElevenLabsProvider.d.ts +0 -30
  28. package/dist/ElevenLabsProvider.test.d.ts +0 -1
  29. package/dist/components/LiveKitRoomWrapper.d.ts +0 -23
  30. package/dist/components/MessageHandler.d.ts +0 -14
  31. package/dist/hooks/useConversationCallbacks.d.ts +0 -5
  32. package/dist/hooks/useConversationSession.d.ts +0 -33
  33. package/dist/hooks/useLiveKitRoom.d.ts +0 -12
  34. package/dist/hooks/useMessageSending.d.ts +0 -7
  35. package/dist/lib.js +0 -2
  36. package/dist/lib.js.map +0 -1
  37. package/dist/lib.modern.js +0 -2
  38. package/dist/lib.modern.js.map +0 -1
  39. package/dist/lib.module.js +0 -2
  40. package/dist/lib.module.js.map +0 -1
  41. package/dist/lib.umd.js +0 -2
  42. package/dist/lib.umd.js.map +0 -1
  43. package/dist/types.d.ts +0 -111
  44. package/dist/utils/constants.d.ts +0 -1
  45. package/dist/utils/overrides.d.ts +0 -2
  46. package/dist/utils/text-only.d.ts +0 -2
  47. package/dist/utils/tokenUtils.d.ts +0 -2
  48. package/jest.config.cjs +0 -263
  49. package/jest.rn-mock.js +0 -15
  50. package/src/ElevenLabsProvider.test.tsx +0 -257
  51. package/src/ElevenLabsProvider.tsx +0 -365
  52. package/src/components/LiveKitRoomWrapper.tsx +0 -94
  53. package/src/components/MessageHandler.tsx +0 -237
  54. package/src/hooks/useConversationCallbacks.ts +0 -15
  55. package/src/hooks/useConversationSession.ts +0 -130
  56. package/src/hooks/useLiveKitRoom.ts +0 -100
  57. package/src/hooks/useMessageSending.ts +0 -33
  58. package/src/types.ts +0 -170
  59. package/src/utils/constants.ts +0 -1
  60. package/src/utils/overrides.ts +0 -48
  61. package/src/utils/text-only.ts +0 -22
  62. package/src/utils/tokenUtils.ts +0 -52
@@ -1,15 +0,0 @@
1
- import { useRef, useCallback } from "react";
2
- import type { Callbacks } from "../types";
3
-
4
- export const useConversationCallbacks = () => {
5
- const callbacksRef = useRef<Callbacks>({});
6
-
7
- const setCallbacks = useCallback((callbacks: Callbacks) => {
8
- callbacksRef.current = callbacks;
9
- }, []);
10
-
11
- return {
12
- callbacksRef,
13
- setCallbacks,
14
- };
15
- };
@@ -1,130 +0,0 @@
1
- import { useState, useCallback } from "react";
2
- import type {
3
- ConversationConfig,
4
- ConversationStatus,
5
- Callbacks,
6
- } from "../types";
7
- import {
8
- getConversationToken,
9
- extractConversationIdFromToken,
10
- } from "../utils/tokenUtils";
11
- import { isTextOnly } from "../utils/text-only";
12
-
13
- export const useConversationSession = (
14
- callbacksRef: { current: Callbacks },
15
- setStatus: (status: ConversationStatus) => void,
16
- setConnect: (connect: boolean) => void,
17
- setToken: (token: string) => void,
18
- setConversationId: (conversationId: string) => void,
19
- tokenFetchUrl?: string
20
- ) => {
21
- const [overrides, setOverrides] = useState<ConversationConfig["overrides"]>(
22
- {}
23
- );
24
- const [customLlmExtraBody, setCustomLlmExtraBody] =
25
- useState<ConversationConfig["customLlmExtraBody"]>(null);
26
- const [dynamicVariables, setDynamicVariables] = useState<
27
- ConversationConfig["dynamicVariables"]
28
- >({});
29
- const [userId, setUserId] = useState<ConversationConfig["userId"]>(undefined);
30
- const [textOnly, setTextOnly] =
31
- useState<ConversationConfig["textOnly"]>(false);
32
-
33
- const startSession = useCallback(
34
- async (config: ConversationConfig) => {
35
- try {
36
- setStatus("connecting");
37
- callbacksRef.current.onStatusChange?.({ status: "connecting" });
38
-
39
- const textOnly = isTextOnly(config);
40
-
41
- setOverrides({
42
- ...config.overrides,
43
- conversation: {
44
- ...config.overrides?.conversation,
45
- textOnly,
46
- },
47
- });
48
- setCustomLlmExtraBody(config.customLlmExtraBody || null);
49
- setDynamicVariables(config.dynamicVariables || {});
50
- setUserId(config.userId);
51
- setTextOnly(textOnly);
52
-
53
- let conversationToken: string;
54
-
55
- if (config.conversationToken) {
56
- conversationToken = config.conversationToken;
57
- } else if (config.agentId) {
58
- console.info(
59
- "Getting conversation token for agentId:",
60
- config.agentId
61
- );
62
- // Use tokenFetchUrl from config first, then from hook parameter, then default
63
- const urlToUse = config.tokenFetchUrl || tokenFetchUrl;
64
- conversationToken = await getConversationToken(
65
- config.agentId,
66
- urlToUse,
67
- config.environment
68
- );
69
- } else {
70
- throw new Error("Either conversationToken or agentId is required");
71
- }
72
-
73
- const extractedConversationId =
74
- extractConversationIdFromToken(conversationToken);
75
- setConversationId(extractedConversationId);
76
-
77
- setToken(conversationToken);
78
- setConnect(true);
79
- } catch (error) {
80
- setStatus("disconnected");
81
- callbacksRef.current.onStatusChange?.({ status: "disconnected" });
82
- callbacksRef.current.onError?.(error as string);
83
- throw error;
84
- }
85
- },
86
- [
87
- callbacksRef,
88
- setStatus,
89
- setConnect,
90
- setToken,
91
- setConversationId,
92
- setTextOnly,
93
- tokenFetchUrl,
94
- ]
95
- );
96
-
97
- const endSession = useCallback(
98
- async (reason: "user" | "agent" = "user") => {
99
- try {
100
- setConnect(false);
101
- setToken("");
102
- setStatus("disconnected");
103
-
104
- // Reset session configuration state
105
- setOverrides({});
106
- setCustomLlmExtraBody(null);
107
- setDynamicVariables({});
108
- setUserId(undefined);
109
- setConversationId("");
110
-
111
- callbacksRef.current.onStatusChange?.({ status: "disconnected" });
112
- callbacksRef.current.onDisconnect?.({ reason });
113
- } catch (error) {
114
- callbacksRef.current.onError?.(error as string);
115
- throw error;
116
- }
117
- },
118
- [callbacksRef, setConnect, setToken, setStatus, setConversationId]
119
- );
120
-
121
- return {
122
- startSession,
123
- endSession,
124
- overrides,
125
- customLlmExtraBody,
126
- dynamicVariables,
127
- userId,
128
- textOnly,
129
- };
130
- };
@@ -1,100 +0,0 @@
1
- import { useState, useEffect, useCallback, useRef } from "react";
2
- import { AudioSession } from "@livekit/react-native";
3
- import type { LocalParticipant } from "livekit-client";
4
- import type { ConversationStatus, Callbacks } from "../types";
5
-
6
- export const useLiveKitRoom = (
7
- callbacksRef: { current: Callbacks },
8
- setStatus: (status: ConversationStatus) => void,
9
- conversationId: string,
10
- status: ConversationStatus,
11
- textOnly: boolean = false
12
- ) => {
13
- const [roomConnected, setRoomConnected] = useState(false);
14
- const [localParticipant, setLocalParticipant] =
15
- useState<LocalParticipant | null>(null);
16
- const hasCalledOnConnectRef = useRef(false);
17
- const audioSessionActiveRef = useRef(false);
18
-
19
- // Reset room state when conversationId changes (new session starting)
20
- useEffect(() => {
21
- if (conversationId) {
22
- setRoomConnected(false);
23
- setLocalParticipant(null);
24
- hasCalledOnConnectRef.current = false;
25
- }
26
- }, [conversationId]);
27
-
28
- useEffect(() => {
29
- const shouldHaveAudio = !textOnly && !!conversationId;
30
-
31
- if (shouldHaveAudio && !audioSessionActiveRef.current) {
32
- audioSessionActiveRef.current = true;
33
- AudioSession.startAudioSession();
34
- } else if (!shouldHaveAudio && audioSessionActiveRef.current) {
35
- audioSessionActiveRef.current = false;
36
- AudioSession.stopAudioSession();
37
- }
38
-
39
- return () => {
40
- if (audioSessionActiveRef.current) {
41
- audioSessionActiveRef.current = false;
42
- AudioSession.stopAudioSession();
43
- }
44
- };
45
- }, [textOnly, conversationId]);
46
-
47
- // Fire onConnect when both participant and room are fully ready
48
- useEffect(() => {
49
- if (localParticipant && roomConnected && !hasCalledOnConnectRef.current) {
50
- hasCalledOnConnectRef.current = true;
51
- callbacksRef.current.onConnect?.({ conversationId });
52
- }
53
- }, [localParticipant, roomConnected, conversationId, callbacksRef]);
54
-
55
- const handleParticipantReady = useCallback(
56
- (participant: LocalParticipant) => {
57
- if (localParticipant) {
58
- return;
59
- }
60
-
61
- setLocalParticipant(participant);
62
- setStatus("connected");
63
- },
64
- [localParticipant, setStatus]
65
- );
66
-
67
- const handleConnected = useCallback(() => {
68
- setRoomConnected(true);
69
- }, []);
70
-
71
- const handleDisconnected = useCallback(() => {
72
- // If already disconnected, endSession already handled the disconnect callback
73
- if (status === "disconnected") {
74
- return;
75
- }
76
-
77
- setRoomConnected(false);
78
- setStatus("disconnected");
79
- setLocalParticipant(null);
80
- hasCalledOnConnectRef.current = false;
81
- callbacksRef.current.onDisconnect?.({ reason: "user" });
82
- }, [callbacksRef, setStatus, status]);
83
-
84
- const handleError = useCallback(
85
- (error: Error) => {
86
- console.error("LiveKit error:", error);
87
- callbacksRef.current.onError?.(error.message, undefined);
88
- },
89
- [callbacksRef]
90
- );
91
-
92
- return {
93
- roomConnected,
94
- localParticipant,
95
- handleParticipantReady,
96
- handleConnected,
97
- handleDisconnected,
98
- handleError,
99
- };
100
- };
@@ -1,33 +0,0 @@
1
- import { useCallback } from "react";
2
- import type { LocalParticipant } from "livekit-client";
3
- import type { ConversationStatus, Callbacks } from "../types";
4
-
5
- export const useMessageSending = (
6
- status: ConversationStatus,
7
- localParticipant: LocalParticipant | null,
8
- callbacksRef: { current: Callbacks }
9
- ) => {
10
- const sendMessage = useCallback(
11
- async (message: unknown) => {
12
- if (status !== "connected" || !localParticipant) {
13
- console.warn(
14
- "Cannot send message: room not connected or no local participant"
15
- );
16
- return;
17
- }
18
- try {
19
- const encoder = new TextEncoder();
20
- const data = encoder.encode(JSON.stringify(message));
21
-
22
- await localParticipant.publishData(data, { reliable: true });
23
- } catch (error) {
24
- console.error("Failed to send message via WebRTC:", error);
25
- console.error("Error details:", error);
26
- callbacksRef.current.onError?.(error as string);
27
- }
28
- },
29
- [status, localParticipant, callbacksRef]
30
- );
31
-
32
- return { sendMessage };
33
- };
package/src/types.ts DELETED
@@ -1,170 +0,0 @@
1
- import type * as Types from "@elevenlabs/types";
2
- import type {
3
- AsrInitiationMetadataEvent as AsrMetadataEvent,
4
- AudioAlignmentEvent,
5
- Callbacks,
6
- ConversationMetadata,
7
- Mode as ConversationMode,
8
- Incoming,
9
- Interruption,
10
- Role as MessageRole,
11
- Outgoing,
12
- Ping,
13
- Status,
14
- } from "@elevenlabs/types";
15
- export type { Callbacks } from "@elevenlabs/types";
16
-
17
- /**
18
- * Role in the conversation
19
- */
20
- export type Role = MessageRole;
21
-
22
- /**
23
- * Current mode of the conversation
24
- */
25
- export type Mode = ConversationMode;
26
-
27
- export type ConversationStatus = Status;
28
-
29
- /**
30
- * Language support
31
- */
32
- export type Language = Types.ConversationConfigOverrideAgentLanguage;
33
-
34
- /**
35
- * Client tools configuration
36
- */
37
- export type ClientToolsConfig = {
38
- clientTools: Record<
39
- string,
40
- (
41
- parameters: unknown
42
- ) => Promise<string | number | undefined> | string | number | undefined
43
- >;
44
- };
45
-
46
- /**
47
- * Options for useConversation hook
48
- */
49
- export type ConversationOptions = {
50
- serverUrl?: string;
51
- tokenFetchUrl?: string;
52
- clientTools?: Record<
53
- string,
54
- (
55
- parameters: unknown
56
- ) => Promise<string | number | undefined> | string | number | undefined
57
- >;
58
- } & Partial<Callbacks>;
59
-
60
- export type ConversationConfig = {
61
- agentId?: string;
62
- conversationToken?: string;
63
- tokenFetchUrl?: string;
64
- overrides?: {
65
- agent?: {
66
- prompt?: {
67
- prompt?: string;
68
- };
69
- firstMessage?: string;
70
- language?: Language;
71
- };
72
- tts?: {
73
- voiceId?: string;
74
- speed?: number;
75
- stability?: number;
76
- similarityBoost?: number;
77
- };
78
- conversation?: {
79
- textOnly?: boolean;
80
- };
81
- client?: {
82
- source?: string;
83
- version?: string;
84
- };
85
- };
86
- customLlmExtraBody?: unknown;
87
- dynamicVariables?: Record<string, string | number | boolean>;
88
- textOnly?: boolean;
89
- userId?: string;
90
- environment?: string;
91
- };
92
-
93
- // Incoming event types
94
- export type UserTranscriptionEvent = Incoming.UserTranscriptionClientEvent;
95
- export type AgentResponseEvent = Incoming.AgentResponseClientEvent;
96
- export type AgentResponseCorrectionEvent =
97
- Incoming.AgentResponseCorrectionClientEvent;
98
- export type AgentAudioEvent = Incoming.AudioClientEvent;
99
- export type InterruptionEvent = Interruption;
100
- export type InternalTentativeAgentResponseEvent =
101
- Incoming.TentativeAgentResponseInternalClientEvent;
102
- export type ConfigEvent = ConversationMetadata;
103
- export type PingEvent = Ping;
104
- export type ClientToolCallEvent = Incoming.ClientToolCallClientEvent;
105
- export type VadScoreEvent = Incoming.VadScoreClientEvent;
106
- export type MCPToolCallClientEvent = Incoming.McpToolCallClientEvent;
107
- export type MCPConnectionStatusEvent = Incoming.McpConnectionStatusClientEvent;
108
- export type AgentToolRequestEvent = Incoming.AgentToolRequestClientEvent;
109
- export type AgentToolResponseEvent = Incoming.AgentToolResponseClientEvent;
110
- export type ConversationMetadataEvent = ConversationMetadata;
111
- export type AsrInitiationMetadataEvent = AsrMetadataEvent;
112
- export type AgentChatResponsePartEvent =
113
- Incoming.AgentChatResponsePartClientEvent;
114
- export type { AudioAlignmentEvent };
115
- export type AudioEventWithAlignment = {
116
- audio_base_64?: string;
117
- event_id: number;
118
- alignment?: AudioAlignmentEvent;
119
- };
120
-
121
- // Outgoing event types
122
- export type PongEvent = Outgoing.PongClientToOrchestratorEvent;
123
- export type UserAudioEvent = Outgoing.UserAudio;
124
- export type UserFeedbackEvent = Outgoing.UserFeedbackClientToOrchestratorEvent;
125
- export type ClientToolResultEvent =
126
- Outgoing.ClientToolResultClientToOrchestratorEvent;
127
- export type ContextualUpdateEvent =
128
- Outgoing.ContextualUpdateClientToOrchestratorEvent;
129
- export type UserMessageEvent = Outgoing.UserMessageClientToOrchestratorEvent;
130
- export type UserActivityEvent = Outgoing.UserActivityClientToOrchestratorEvent;
131
- export type MCPToolApprovalResultEvent =
132
- Outgoing.McpToolApprovalResultClientToOrchestratorEvent;
133
- export type InitiationClientDataEvent =
134
- Outgoing.ConversationInitiationClientToOrchestratorEvent;
135
-
136
- export type ConversationEvent =
137
- | UserTranscriptionEvent
138
- | AgentResponseEvent
139
- | AgentResponseCorrectionEvent
140
- | AgentAudioEvent
141
- | InterruptionEvent
142
- | InternalTentativeAgentResponseEvent
143
- | ConfigEvent
144
- | PingEvent
145
- | ClientToolCallEvent
146
- | VadScoreEvent
147
- | MCPToolCallClientEvent
148
- | MCPConnectionStatusEvent
149
- | AgentToolRequestEvent
150
- | AgentToolResponseEvent
151
- | ConversationMetadataEvent
152
- | AsrInitiationMetadataEvent
153
- | AgentChatResponsePartEvent;
154
-
155
- /**
156
- * Audio session configuration for controlling how the SDK handles audio
157
- */
158
- export interface AudioSessionConfig {
159
- /**
160
- * Whether audio should mix with other audio sources.
161
- * When true, the SDK will configure the audio session to allow
162
- * concurrent audio playback with other audio sources.
163
- *
164
- * iOS: Adds AVAudioSessionCategoryOptionMixWithOthers
165
- * Android: Uses AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
166
- *
167
- * @default false (exclusive audio session)
168
- */
169
- allowMixingWithOthers?: boolean;
170
- }
@@ -1 +0,0 @@
1
- export const DEFAULT_SERVER_URL = "wss://livekit.rtc.elevenlabs.io";
@@ -1,48 +0,0 @@
1
- import type { ConversationConfig, InitiationClientDataEvent } from "../types";
2
- import { PACKAGE_VERSION } from "../version";
3
-
4
- export function constructOverrides(
5
- config: ConversationConfig
6
- ): InitiationClientDataEvent {
7
- const overridesEvent: InitiationClientDataEvent = {
8
- type: "conversation_initiation_client_data",
9
- };
10
-
11
- if (config.overrides) {
12
- overridesEvent.conversation_config_override = {
13
- agent: {
14
- prompt: config.overrides.agent?.prompt,
15
- first_message: config.overrides.agent?.firstMessage,
16
- language: config.overrides.agent?.language,
17
- },
18
- tts: {
19
- voice_id: config.overrides.tts?.voiceId,
20
- speed: config.overrides.tts?.speed,
21
- stability: config.overrides.tts?.stability,
22
- similarity_boost: config.overrides.tts?.similarityBoost,
23
- },
24
- conversation: {
25
- text_only: config.overrides.conversation?.textOnly,
26
- },
27
- };
28
- }
29
-
30
- overridesEvent.source_info = {
31
- source: "react_native_sdk",
32
- version: config.overrides?.client?.version || PACKAGE_VERSION,
33
- };
34
-
35
- if (config.customLlmExtraBody) {
36
- overridesEvent.custom_llm_extra_body = config.customLlmExtraBody;
37
- }
38
-
39
- if (config.dynamicVariables) {
40
- overridesEvent.dynamic_variables = config.dynamicVariables;
41
- }
42
-
43
- if (config.userId) {
44
- overridesEvent.user_id = String(config.userId);
45
- }
46
-
47
- return overridesEvent;
48
- }
@@ -1,22 +0,0 @@
1
- import { ConversationConfig } from "../types";
2
-
3
- // Note: This function is copied from the client package (see BaseConversation.ts)
4
- export function isTextOnly(options: ConversationConfig): boolean | undefined {
5
- const { textOnly: textOnlyOverride } = options.overrides?.conversation ?? {};
6
- const { textOnly } = options;
7
- if (typeof textOnly === "boolean") {
8
- if (
9
- typeof textOnlyOverride === "boolean" &&
10
- textOnly !== textOnlyOverride
11
- ) {
12
- console.warn(
13
- `Conflicting textOnly options provided: ${textOnly} via options.textOnly (will be used) and ${textOnlyOverride} via options.overrides.conversation.textOnly (will be ignored)`
14
- );
15
- }
16
- return textOnly;
17
- } else if (typeof textOnlyOverride === "boolean") {
18
- return textOnlyOverride;
19
- } else {
20
- return undefined;
21
- }
22
- }
@@ -1,52 +0,0 @@
1
- import { PACKAGE_VERSION } from "../version";
2
-
3
- export const extractConversationIdFromToken = (token: string): string => {
4
- try {
5
- const tokenPayload = JSON.parse(atob(token.split(".")[1]));
6
- const roomId = tokenPayload.video?.room || "";
7
-
8
- return roomId.match(/(conv_[a-zA-Z0-9]+)/)?.[0] || "";
9
- } catch (error) {
10
- console.warn("Could not extract conversation ID from token");
11
- return "";
12
- }
13
- };
14
-
15
- export const getConversationToken = async (
16
- agentId: string,
17
- tokenFetchUrl?: string,
18
- environment?: string
19
- ): Promise<string> => {
20
- try {
21
- const baseUrl =
22
- tokenFetchUrl || "https://api.elevenlabs.io/v1/convai/conversation/token";
23
- let url = `${baseUrl}?agent_id=${agentId}&source=react_native_sdk&version=${PACKAGE_VERSION}`;
24
- if (environment) {
25
- url += `&environment=${encodeURIComponent(environment)}`;
26
- }
27
- const response = await fetch(url);
28
-
29
- const data = await response.json();
30
-
31
- if (!response.ok) {
32
- if (
33
- typeof data.detail === "object" &&
34
- data.detail !== null &&
35
- typeof data.detail.message === "string"
36
- ) {
37
- throw new Error(data.detail.message);
38
- }
39
- throw new Error("Missing error details or message");
40
- }
41
-
42
- if (!data.token) {
43
- throw new Error("No conversation token received from API");
44
- }
45
-
46
- return data.token;
47
- } catch (error) {
48
- throw new Error(
49
- `Failed to get conversation token: ${error instanceof Error ? error.message : "No message"}`
50
- );
51
- }
52
- };