@elevenlabs/react 0.14.3 → 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 (83) hide show
  1. package/README.md +33 -1085
  2. package/dist/conversation/ConversationClientTools.d.ts +39 -0
  3. package/dist/conversation/ConversationClientTools.d.ts.map +1 -0
  4. package/dist/conversation/ConversationClientTools.js +87 -0
  5. package/dist/conversation/ConversationClientTools.js.map +1 -0
  6. package/dist/conversation/ConversationContext.d.ts +47 -0
  7. package/dist/conversation/ConversationContext.d.ts.map +1 -0
  8. package/dist/conversation/ConversationContext.js +61 -0
  9. package/dist/conversation/ConversationContext.js.map +1 -0
  10. package/dist/conversation/ConversationControls.d.ts +34 -0
  11. package/dist/conversation/ConversationControls.d.ts.map +1 -0
  12. package/dist/conversation/ConversationControls.js +113 -0
  13. package/dist/conversation/ConversationControls.js.map +1 -0
  14. package/dist/conversation/ConversationFeedback.d.ts +19 -0
  15. package/dist/conversation/ConversationFeedback.d.ts.map +1 -0
  16. package/dist/conversation/ConversationFeedback.js +44 -0
  17. package/dist/conversation/ConversationFeedback.js.map +1 -0
  18. package/dist/conversation/ConversationInput.d.ts +18 -0
  19. package/dist/conversation/ConversationInput.d.ts.map +1 -0
  20. package/dist/conversation/ConversationInput.js +40 -0
  21. package/dist/conversation/ConversationInput.js.map +1 -0
  22. package/dist/conversation/ConversationMode.d.ts +19 -0
  23. package/dist/conversation/ConversationMode.d.ts.map +1 -0
  24. package/dist/conversation/ConversationMode.js +40 -0
  25. package/dist/conversation/ConversationMode.js.map +1 -0
  26. package/dist/conversation/ConversationProvider.d.ts +4 -0
  27. package/dist/conversation/ConversationProvider.d.ts.map +1 -0
  28. package/dist/conversation/ConversationProvider.js +127 -0
  29. package/dist/conversation/ConversationProvider.js.map +1 -0
  30. package/dist/conversation/ConversationStatus.d.ts +19 -0
  31. package/dist/conversation/ConversationStatus.d.ts.map +1 -0
  32. package/dist/conversation/ConversationStatus.js +44 -0
  33. package/dist/conversation/ConversationStatus.js.map +1 -0
  34. package/dist/conversation/ListenerMap.d.ts +29 -0
  35. package/dist/conversation/ListenerMap.d.ts.map +1 -0
  36. package/dist/conversation/ListenerMap.js +63 -0
  37. package/dist/conversation/ListenerMap.js.map +1 -0
  38. package/dist/conversation/ListenerSet.d.ts +7 -0
  39. package/dist/conversation/ListenerSet.d.ts.map +1 -0
  40. package/dist/conversation/ListenerSet.js +17 -0
  41. package/dist/conversation/ListenerSet.js.map +1 -0
  42. package/dist/conversation/types.d.ts +9 -0
  43. package/dist/conversation/types.d.ts.map +1 -0
  44. package/dist/conversation/types.js +2 -0
  45. package/dist/conversation/types.js.map +1 -0
  46. package/dist/conversation/useConversation.d.ts +45 -0
  47. package/dist/conversation/useConversation.d.ts.map +1 -0
  48. package/dist/conversation/useConversation.js +76 -0
  49. package/dist/conversation/useConversation.js.map +1 -0
  50. package/dist/conversation/useStableCallbacks.d.ts +13 -0
  51. package/dist/conversation/useStableCallbacks.d.ts.map +1 -0
  52. package/dist/conversation/useStableCallbacks.js +33 -0
  53. package/dist/conversation/useStableCallbacks.js.map +1 -0
  54. package/dist/index.d.ts +19 -51
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +17 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/lib.iife.js +984 -0
  59. package/dist/lib.iife.js.map +1 -0
  60. package/dist/scribe.d.ts +1 -0
  61. package/dist/scribe.d.ts.map +1 -0
  62. package/dist/scribe.js +307 -0
  63. package/dist/scribe.js.map +1 -0
  64. package/dist/version.d.ts +2 -1
  65. package/dist/version.d.ts.map +1 -0
  66. package/dist/version.js +3 -0
  67. package/dist/version.js.map +1 -0
  68. package/package.json +25 -20
  69. package/.turbo/turbo-build.log +0 -29
  70. package/.turbo/turbo-check-types.log +0 -4
  71. package/.turbo/turbo-generate-version.log +0 -4
  72. package/.turbo/turbo-lint$colon$es.log +0 -6
  73. package/.turbo/turbo-lint$colon$prettier.log +0 -6
  74. package/CHANGELOG.md +0 -53
  75. package/dist/lib.cjs +0 -2
  76. package/dist/lib.cjs.map +0 -1
  77. package/dist/lib.modern.js +0 -2
  78. package/dist/lib.modern.js.map +0 -1
  79. package/dist/lib.module.js +0 -2
  80. package/dist/lib.module.js.map +0 -1
  81. package/dist/lib.umd.js +0 -2
  82. package/dist/lib.umd.js.map +0 -1
  83. package/jest.config.cjs +0 -23
@@ -0,0 +1,127 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
3
+ import { Conversation } from "@elevenlabs/client";
4
+ import { CALLBACK_KEYS, mergeOptions, parseLocation, getOriginForLocation, getLivekitUrlForLocation, } from "@elevenlabs/client/internal";
5
+ import { ConversationContext, } from "./ConversationContext";
6
+ import { ConversationControlsProvider } from "./ConversationControls";
7
+ import { ConversationStatusProvider } from "./ConversationStatus";
8
+ import { ConversationInputProvider } from "./ConversationInput";
9
+ import { ConversationModeProvider } from "./ConversationMode";
10
+ import { ConversationFeedbackProvider } from "./ConversationFeedback";
11
+ import { ConversationClientToolsProvider, buildClientTools, } from "./ConversationClientTools";
12
+ import { ListenerMap } from "./ListenerMap";
13
+ import { useStableCallbacks } from "./useStableCallbacks";
14
+ const SUB_PROVIDERS = [
15
+ ConversationControlsProvider,
16
+ ConversationStatusProvider,
17
+ ConversationInputProvider,
18
+ ConversationModeProvider,
19
+ ConversationFeedbackProvider,
20
+ ConversationClientToolsProvider,
21
+ ];
22
+ export function ConversationProvider({ children, ...defaultOptions }) {
23
+ /** The active conversation instance, if any. */
24
+ const conversationRef = useRef(null);
25
+ /** In-flight startSession promise, used to prevent duplicate connections. */
26
+ const lockRef = useRef(null);
27
+ /** Signals that endSession was called while a connection was still pending. */
28
+ const shouldEndRef = useRef(false);
29
+ /** Registry of hook-registered client tools. Survives across sessions. */
30
+ const [clientToolsRegistry] = useState(() => new Map());
31
+ /** Ref to the live clientTools object currently held by BaseConversation. */
32
+ const clientToolsRef = useRef({});
33
+ /** Always holds the latest provider props, avoiding stale closures in callbacks. */
34
+ const defaultOptionsRef = useRef(defaultOptions);
35
+ // eslint-disable-next-line react-hooks/refs -- intentional sync during render for latest-ref pattern
36
+ defaultOptionsRef.current = defaultOptions;
37
+ /** Callback registry for sub-providers (status, mode, feedback, etc.). */
38
+ const [listenerMap] = useState(() => new ListenerMap(CALLBACK_KEYS));
39
+ /** Reactive mirror of conversationRef, triggers re-renders for context consumers. */
40
+ const [conversation, setConversation] = useState(null);
41
+ const stableCallbacks = useStableCallbacks(defaultOptions);
42
+ const registerCallbacks = useCallback((callbacks) => listenerMap.register(callbacks), [listenerMap]);
43
+ // Sync provider state when session ends externally (agent disconnect,
44
+ // raw instance endSession(), etc.). Uses the listener map so it composes
45
+ // with user-provided onDisconnect callbacks.
46
+ useLayoutEffect(() => {
47
+ return listenerMap.register({
48
+ onDisconnect: () => {
49
+ conversationRef.current = null;
50
+ setConversation(null);
51
+ },
52
+ });
53
+ }, [listenerMap]);
54
+ const startSession = useCallback((options) => {
55
+ if (conversationRef.current) {
56
+ return;
57
+ }
58
+ if (lockRef.current) {
59
+ return;
60
+ }
61
+ shouldEndRef.current = false;
62
+ const defaults = defaultOptionsRef.current;
63
+ const resolvedServerLocation = parseLocation(options?.serverLocation || defaults?.serverLocation);
64
+ const origin = getOriginForLocation(resolvedServerLocation);
65
+ const calculatedLivekitUrl = getLivekitUrlForLocation(resolvedServerLocation);
66
+ // Strip raw callbacks from defaults — stableCallbacks provides
67
+ // ref-backed versions that won't go stale across renders.
68
+ const defaultConfig = { ...defaults };
69
+ for (const key of CALLBACK_KEYS) {
70
+ delete defaultConfig[key];
71
+ }
72
+ const sessionOptions = mergeOptions({ livekitUrl: calculatedLivekitUrl }, defaultConfig, stableCallbacks, listenerMap.compose(), options ?? {}, { origin });
73
+ const clientTools = buildClientTools(sessionOptions.clientTools, clientToolsRegistry);
74
+ clientToolsRef.current = clientTools;
75
+ sessionOptions.clientTools = clientTools;
76
+ lockRef.current = Conversation.startSession(sessionOptions);
77
+ lockRef.current.then(conv => {
78
+ if (shouldEndRef.current) {
79
+ conv.endSession();
80
+ lockRef.current = null;
81
+ return;
82
+ }
83
+ conversationRef.current = conv;
84
+ setConversation(conv);
85
+ lockRef.current = null;
86
+ }, () => {
87
+ lockRef.current = null;
88
+ });
89
+ }, [stableCallbacks, listenerMap, clientToolsRegistry, clientToolsRef]);
90
+ const endSession = useCallback(() => {
91
+ shouldEndRef.current = true;
92
+ const pendingConnection = lockRef.current;
93
+ const conv = conversationRef.current;
94
+ conversationRef.current = null;
95
+ setConversation(null);
96
+ if (pendingConnection) {
97
+ pendingConnection.then(c => c.endSession());
98
+ }
99
+ else {
100
+ conv?.endSession();
101
+ }
102
+ }, []);
103
+ // Cleanup on unmount
104
+ useEffect(() => {
105
+ return () => {
106
+ shouldEndRef.current = true;
107
+ if (lockRef.current) {
108
+ lockRef.current.then(conv => conv.endSession());
109
+ }
110
+ else {
111
+ conversationRef.current?.endSession();
112
+ }
113
+ };
114
+ }, []);
115
+ const contextValue = useMemo(() => ({
116
+ conversation,
117
+ conversationRef,
118
+ startSession,
119
+ endSession,
120
+ registerCallbacks,
121
+ clientToolsRegistry,
122
+ clientToolsRef,
123
+ }), [conversation, conversationRef, startSession, endSession, registerCallbacks, clientToolsRegistry, clientToolsRef]);
124
+ const wrappedChildren = SUB_PROVIDERS.reduceRight((nested, Provider) => _jsx(Provider, { children: nested }), children);
125
+ return (_jsx(ConversationContext.Provider, { value: contextValue, children: wrappedChildren }));
126
+ }
127
+ //# sourceMappingURL=ConversationProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationProvider.js","sourceRoot":"","sources":["../../src/conversation/ConversationProvider.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export type ConversationStatus = "disconnected" | "connecting" | "connected" | "error";
2
+ export type ConversationStatusValue = {
3
+ status: ConversationStatus;
4
+ message?: string;
5
+ };
6
+ /**
7
+ * Reads from `ConversationContext` and registers `onStatusChange` + `onError`
8
+ * callbacks. Manages its own `status`/`message` state and provides it through
9
+ * `ConversationStatusContext`. Must be rendered inside a `ConversationProvider`.
10
+ */
11
+ export declare function ConversationStatusProvider({ children, }: React.PropsWithChildren): import("react/jsx-runtime").JSX.Element;
12
+ /**
13
+ * Returns the current conversation status and any error message.
14
+ * Re-renders when the connection status or error message changes.
15
+ *
16
+ * Must be used within a `ConversationProvider`.
17
+ */
18
+ export declare function useConversationStatus(): ConversationStatusValue;
19
+ //# sourceMappingURL=ConversationStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationStatus.d.ts","sourceRoot":"","sources":["../../src/conversation/ConversationStatus.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,YAAY,GACZ,WAAW,GACX,OAAO,CAAC;AAEZ,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAMF;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,GACT,EAAE,KAAK,CAAC,iBAAiB,2CA+BzB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,uBAAuB,CAQ/D"}
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo, useState } from "react";
3
+ import { useRegisterCallbacks } from "./ConversationContext";
4
+ const ConversationStatusContext = createContext(null);
5
+ /**
6
+ * Reads from `ConversationContext` and registers `onStatusChange` + `onError`
7
+ * callbacks. Manages its own `status`/`message` state and provides it through
8
+ * `ConversationStatusContext`. Must be rendered inside a `ConversationProvider`.
9
+ */
10
+ export function ConversationStatusProvider({ children, }) {
11
+ const [status, setStatus] = useState("disconnected");
12
+ const [message, setMessage] = useState(undefined);
13
+ useRegisterCallbacks({
14
+ onStatusChange({ status: newStatus }) {
15
+ if (newStatus === "disconnecting") {
16
+ // Transient state — keep current status
17
+ return;
18
+ }
19
+ setStatus(newStatus);
20
+ // Clear error message when transitioning to a non-error state
21
+ setMessage(undefined);
22
+ },
23
+ onError(errorMessage) {
24
+ setStatus("error");
25
+ setMessage(errorMessage);
26
+ },
27
+ });
28
+ const value = useMemo(() => ({ status, message }), [status, message]);
29
+ return (_jsx(ConversationStatusContext.Provider, { value: value, children: children }));
30
+ }
31
+ /**
32
+ * Returns the current conversation status and any error message.
33
+ * Re-renders when the connection status or error message changes.
34
+ *
35
+ * Must be used within a `ConversationProvider`.
36
+ */
37
+ export function useConversationStatus() {
38
+ const ctx = useContext(ConversationStatusContext);
39
+ if (!ctx) {
40
+ throw new Error("useConversationStatus must be used within a ConversationProvider");
41
+ }
42
+ return ctx;
43
+ }
44
+ //# sourceMappingURL=ConversationStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationStatus.js","sourceRoot":"","sources":["../../src/conversation/ConversationStatus.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAa7D,MAAM,yBAAyB,GAAG,aAAa,CAC7C,IAAI,CACL,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,EACzC,QAAQ,GACgB;IACxB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GACvB,QAAQ,CAAoC,cAAc,CAAC,CAAC;IAC9D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAqB,SAAS,CAAC,CAAC;IAEtE,oBAAoB,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE;YAClC,IAAI,SAAS,KAAK,eAAe,EAAE,CAAC;gBAClC,wCAAwC;gBACxC,OAAO;YACT,CAAC;YACD,SAAS,CAAC,SAAS,CAAC,CAAC;YACrB,8DAA8D;YAC9D,UAAU,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,CAAC,YAAY;YAClB,SAAS,CAAC,OAAO,CAAC,CAAC;YACnB,UAAU,CAAC,YAAY,CAAC,CAAC;QAC3B,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAC3B,CAAC,MAAM,EAAE,OAAO,CAAC,CAClB,CAAC;IAEF,OAAO,CACL,KAAC,yBAAyB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAC7C,QAAQ,GAC0B,CACtC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,GAAG,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAC;IAClD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * A map of named listener sets. Each key maps to a `ListenerSet` that can have
3
+ * multiple listeners registered. Typed through `T` so that `register` and
4
+ * `compose` preserve per-key callback signatures.
5
+ *
6
+ * All keys are pre-initialized in the constructor so `register` can validate
7
+ * keys. `compose()` only includes keys with at least one registered listener,
8
+ * preserving callback-presence semantics used by the client as feature guards.
9
+ * For included keys, composed functions delegate to the live listener set, so
10
+ * listeners added/removed after `compose()` still take effect. Keys with no
11
+ * listeners at compose time are omitted entirely; call `compose()` again after
12
+ * registering listeners to pick up newly populated keys.
13
+ */
14
+ export declare class ListenerMap<T extends Record<string, ((...args: never[]) => void) | undefined>> {
15
+ private sets;
16
+ constructor(keys: readonly (keyof T & string)[]);
17
+ /**
18
+ * Register listeners for one or more keys. Returns a function that removes
19
+ * all listeners added by this call.
20
+ */
21
+ register(callbacks: Partial<T>): () => void;
22
+ /**
23
+ * Compose all registered listeners into a single callbacks object. Each
24
+ * composed function delegates to the live listener set, so listeners
25
+ * added/removed after this call still take effect.
26
+ */
27
+ compose(): Partial<T>;
28
+ }
29
+ //# sourceMappingURL=ListenerMap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListenerMap.d.ts","sourceRoot":"","sources":["../../src/conversation/ListenerMap.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;GAYG;AACH,qBAAa,WAAW,CACtB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAElE,OAAO,CAAC,IAAI,CAA6C;gBAE7C,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE;IAM/C;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAgB3C;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC;CAYtB"}
@@ -0,0 +1,63 @@
1
+ import { ListenerSet } from "./ListenerSet";
2
+ function assertFunction(value, key) {
3
+ if (typeof value !== "function") {
4
+ throw new Error(`Expected function for key "${key}", got ${typeof value}`);
5
+ }
6
+ }
7
+ /**
8
+ * A map of named listener sets. Each key maps to a `ListenerSet` that can have
9
+ * multiple listeners registered. Typed through `T` so that `register` and
10
+ * `compose` preserve per-key callback signatures.
11
+ *
12
+ * All keys are pre-initialized in the constructor so `register` can validate
13
+ * keys. `compose()` only includes keys with at least one registered listener,
14
+ * preserving callback-presence semantics used by the client as feature guards.
15
+ * For included keys, composed functions delegate to the live listener set, so
16
+ * listeners added/removed after `compose()` still take effect. Keys with no
17
+ * listeners at compose time are omitted entirely; call `compose()` again after
18
+ * registering listeners to pick up newly populated keys.
19
+ */
20
+ export class ListenerMap {
21
+ sets = new Map();
22
+ constructor(keys) {
23
+ for (const key of keys) {
24
+ this.sets.set(key, new ListenerSet());
25
+ }
26
+ }
27
+ /**
28
+ * Register listeners for one or more keys. Returns a function that removes
29
+ * all listeners added by this call.
30
+ */
31
+ register(callbacks) {
32
+ const removers = Object.entries(callbacks)
33
+ .filter(([, fn]) => fn !== undefined)
34
+ .map(([key, fn]) => {
35
+ assertFunction(fn, key);
36
+ const set = this.sets.get(key);
37
+ if (!set) {
38
+ throw new Error(`Unknown callback key "${key}"`);
39
+ }
40
+ return set.add(fn);
41
+ });
42
+ return () => {
43
+ for (const remove of removers)
44
+ remove();
45
+ };
46
+ }
47
+ /**
48
+ * Compose all registered listeners into a single callbacks object. Each
49
+ * composed function delegates to the live listener set, so listeners
50
+ * added/removed after this call still take effect.
51
+ */
52
+ compose() {
53
+ return Object.fromEntries(Array.from(this.sets.entries())
54
+ .filter(([, set]) => set.size > 0)
55
+ .map(([key, set]) => [
56
+ key,
57
+ (...args) => {
58
+ set.invoke(...args);
59
+ },
60
+ ]));
61
+ }
62
+ }
63
+ //# sourceMappingURL=ListenerMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListenerMap.js","sourceRoot":"","sources":["../../src/conversation/ListenerMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,SAAS,cAAc,CACrB,KAAc,EACd,GAAW;IAEX,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,UAAU,OAAO,KAAK,EAAE,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,WAAW;IAGd,IAAI,GAAG,IAAI,GAAG,EAAkC,CAAC;IAEzD,YAAY,IAAmC;QAC7C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,WAAW,EAAa,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,QAAQ,CAAC,SAAqB;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;aACvC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC;aACpC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;YACjB,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,GAAG,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QACL,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,MAAM,IAAI,QAAQ;gBAAE,MAAM,EAAE,CAAC;QAC1C,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,OAAO;QACL,OAAO,MAAM,CAAC,WAAW,CACvB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;aAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;aACjC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;YACnB,GAAG;YACH,CAAC,GAAG,IAAa,EAAE,EAAE;gBACnB,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;YACtB,CAAC;SACF,CAAC,CACS,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export declare class ListenerSet<Args extends unknown[]> {
2
+ private listeners;
3
+ add(fn: (...args: Args) => void): () => void;
4
+ invoke(...args: Args): void;
5
+ get size(): number;
6
+ }
7
+ //# sourceMappingURL=ListenerSet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListenerSet.d.ts","sourceRoot":"","sources":["../../src/conversation/ListenerSet.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW,CAAC,IAAI,SAAS,OAAO,EAAE;IAC7C,OAAO,CAAC,SAAS,CAAsC;IAEvD,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI;IAO5C,MAAM,CAAC,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI;IAI3B,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,17 @@
1
+ export class ListenerSet {
2
+ listeners = new Set();
3
+ add(fn) {
4
+ this.listeners.add(fn);
5
+ return () => {
6
+ this.listeners.delete(fn);
7
+ };
8
+ }
9
+ invoke(...args) {
10
+ for (const fn of this.listeners)
11
+ fn(...args);
12
+ }
13
+ get size() {
14
+ return this.listeners.size;
15
+ }
16
+ }
17
+ //# sourceMappingURL=ListenerSet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListenerSet.js","sourceRoot":"","sources":["../../src/conversation/ListenerSet.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,WAAW;IACd,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEvD,GAAG,CAAC,EAA2B;QAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvB,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,GAAG,IAAU;QAClB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,SAAS;YAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { SessionConfig, ClientToolsConfig, InputConfig, AudioWorkletConfig, OutputConfig, FormatConfig, Callbacks, Location } from "@elevenlabs/client";
2
+ export type ClientToolResult = string | number | void;
3
+ export type ClientTool<Parameters extends Record<string, unknown> = Record<string, unknown>, Result extends ClientToolResult = ClientToolResult> = (parameters: Parameters) => Promise<Result> | Result;
4
+ export type ClientTools = Record<string, ClientTool>;
5
+ export type HookCallbacks = Pick<Callbacks, "onConnect" | "onDisconnect" | "onError" | "onMessage" | "onAudio" | "onModeChange" | "onStatusChange" | "onCanSendFeedbackChange" | "onDebug" | "onUnhandledClientToolCall" | "onVadScore" | "onInterruption" | "onAgentToolResponse" | "onAgentToolRequest" | "onConversationMetadata" | "onMCPToolCall" | "onMCPConnectionStatus" | "onAsrInitiationMetadata" | "onAgentChatResponsePart" | "onAudioAlignment">;
6
+ export type HookOptions = Partial<SessionConfig & HookCallbacks & ClientToolsConfig & InputConfig & OutputConfig & AudioWorkletConfig & FormatConfig & {
7
+ serverLocation?: Location | string;
8
+ }>;
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/conversation/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,QAAQ,EACT,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAEtD,MAAM,MAAM,UAAU,CACpB,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,MAAM,SAAS,gBAAgB,GAAG,gBAAgB,IAChD,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG,IAAI,CAC9B,SAAS,EACP,WAAW,GACX,cAAc,GACd,SAAS,GACT,WAAW,GACX,SAAS,GACT,cAAc,GACd,gBAAgB,GAChB,yBAAyB,GACzB,SAAS,GACT,2BAA2B,GAC3B,YAAY,GACZ,gBAAgB,GAChB,qBAAqB,GACrB,oBAAoB,GACpB,wBAAwB,GACxB,eAAe,GACf,uBAAuB,GACvB,yBAAyB,GACzB,yBAAyB,GACzB,kBAAkB,CACrB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,OAAO,CAC/B,aAAa,GACX,aAAa,GACb,iBAAiB,GACjB,WAAW,GACX,YAAY,GACZ,kBAAkB,GAClB,YAAY,GAAG;IACb,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CACpC,CACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/conversation/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,45 @@
1
+ import type { HookOptions } from "./types";
2
+ export type UseConversationOptions = HookOptions & {
3
+ micMuted?: boolean;
4
+ volume?: number;
5
+ };
6
+ /**
7
+ * Convenience hook that combines all granular conversation hooks into a single
8
+ * return value. Less performant than using individual hooks because any state
9
+ * change in any sub-context triggers a re-render of the consuming component.
10
+ *
11
+ * Accepts optional `micMuted`, `volume`, session config, and callback props.
12
+ * Session config and callbacks passed here are used as defaults when calling
13
+ * `startSession()` without arguments. Callbacks are also registered with the
14
+ * provider so they stay up-to-date across re-renders.
15
+ *
16
+ * Must be used within a `ConversationProvider`.
17
+ */
18
+ export declare function useConversation(props?: UseConversationOptions): {
19
+ startSession: (options?: HookOptions) => void;
20
+ status: import("./ConversationStatus").ConversationStatus;
21
+ message: string | undefined;
22
+ isMuted: boolean;
23
+ setMuted: (isMuted: boolean) => void;
24
+ mode: "speaking" | "listening";
25
+ isSpeaking: boolean;
26
+ isListening: boolean;
27
+ canSendFeedback: boolean;
28
+ sendFeedback: (like: boolean) => void;
29
+ endSession: () => void;
30
+ sendUserMessage: (text: string) => void;
31
+ sendContextualUpdate: (text: string) => void;
32
+ sendUserActivity: () => void;
33
+ sendMCPToolApprovalResult: (toolCallId: string, isApproved: boolean) => void;
34
+ setVolume: (options: {
35
+ volume: number;
36
+ }) => void;
37
+ changeInputDevice: (config: import("@elevenlabs/client").FormatConfig & import("@elevenlabs/client").InputDeviceConfig) => Promise<void>;
38
+ changeOutputDevice: (config: import("@elevenlabs/client").FormatConfig & import("@elevenlabs/client").OutputConfig) => Promise<void>;
39
+ getInputByteFrequencyData: () => Uint8Array;
40
+ getOutputByteFrequencyData: () => Uint8Array;
41
+ getInputVolume: () => number;
42
+ getOutputVolume: () => number;
43
+ getId: () => string;
44
+ };
45
+ //# sourceMappingURL=useConversation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConversation.d.ts","sourceRoot":"","sources":["../../src/conversation/useConversation.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,GAAE,sBAA2B;6BAiBnD,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;EA+CzB"}
@@ -0,0 +1,76 @@
1
+ import { useCallback, useEffect, useRef } from "react";
2
+ import { CALLBACK_KEYS } from "@elevenlabs/client/internal";
3
+ import { useConversationControls } from "./ConversationControls";
4
+ import { useConversationStatus } from "./ConversationStatus";
5
+ import { useConversationInput } from "./ConversationInput";
6
+ import { useConversationMode } from "./ConversationMode";
7
+ import { useConversationFeedback } from "./ConversationFeedback";
8
+ import { useRawConversation, useRegisterCallbacks, } from "./ConversationContext";
9
+ import { useStableCallbacks } from "./useStableCallbacks";
10
+ /**
11
+ * Convenience hook that combines all granular conversation hooks into a single
12
+ * return value. Less performant than using individual hooks because any state
13
+ * change in any sub-context triggers a re-render of the consuming component.
14
+ *
15
+ * Accepts optional `micMuted`, `volume`, session config, and callback props.
16
+ * Session config and callbacks passed here are used as defaults when calling
17
+ * `startSession()` without arguments. Callbacks are also registered with the
18
+ * provider so they stay up-to-date across re-renders.
19
+ *
20
+ * Must be used within a `ConversationProvider`.
21
+ */
22
+ export function useConversation(props = {}) {
23
+ const { micMuted, volume, ...hookOptions } = props;
24
+ const stableCallbacks = useStableCallbacks(hookOptions);
25
+ useRegisterCallbacks(stableCallbacks);
26
+ const hookOptionsRef = useRef(hookOptions);
27
+ // eslint-disable-next-line react-hooks/refs -- intentional sync during render for latest-ref pattern
28
+ hookOptionsRef.current = hookOptions;
29
+ const controls = useConversationControls();
30
+ const { status, message } = useConversationStatus();
31
+ const { isMuted, setMuted } = useConversationInput();
32
+ const { mode, isSpeaking, isListening } = useConversationMode();
33
+ const { canSendFeedback, sendFeedback } = useConversationFeedback();
34
+ const startSession = useCallback((options) => {
35
+ // Strip callbacks from the hook-level defaults: those are registered via
36
+ // useRegisterCallbacks and kept ref-stable across renders.
37
+ // NOTE: We intentionally do NOT strip callbacks from the `options` parameter
38
+ // here. Callbacks passed directly to startSession() are treated as one-shot
39
+ // per-session overrides, and may capture render-local state. This asymmetry
40
+ // (hook callbacks are ref-stable; startSession callbacks are one-shot) is
41
+ // intentional and relied on by the public API.
42
+ const sessionConfig = { ...hookOptionsRef.current };
43
+ for (const key of CALLBACK_KEYS) {
44
+ delete sessionConfig[key];
45
+ }
46
+ controls.startSession({
47
+ ...sessionConfig,
48
+ ...options,
49
+ });
50
+ }, [controls, hookOptionsRef]);
51
+ const conversation = useRawConversation();
52
+ useEffect(() => {
53
+ if (micMuted !== undefined && conversation) {
54
+ setMuted(micMuted);
55
+ }
56
+ }, [micMuted, conversation, setMuted]);
57
+ useEffect(() => {
58
+ if (volume !== undefined && conversation) {
59
+ conversation.setVolume({ volume });
60
+ }
61
+ }, [volume, conversation]);
62
+ return {
63
+ ...controls,
64
+ startSession,
65
+ status,
66
+ message,
67
+ isMuted: micMuted ?? isMuted,
68
+ setMuted,
69
+ mode,
70
+ isSpeaking,
71
+ isListening,
72
+ canSendFeedback,
73
+ sendFeedback,
74
+ };
75
+ }
76
+ //# sourceMappingURL=useConversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConversation.js","sourceRoot":"","sources":["../../src/conversation/useConversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAQ1D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgC,EAAE;IAChE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,GAAG,KAAK,CAAC;IAEnD,MAAM,eAAe,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACxD,oBAAoB,CAAC,eAAe,CAAC,CAAC;IAEtC,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3C,qGAAqG;IACrG,cAAc,CAAC,OAAO,GAAG,WAAW,CAAC;IAErC,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;IAC3C,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,qBAAqB,EAAE,CAAC;IACpD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,oBAAoB,EAAE,CAAC;IACrD,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,mBAAmB,EAAE,CAAC;IAChE,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,uBAAuB,EAAE,CAAC;IAEpE,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,OAAqB,EAAE,EAAE;QACxB,yEAAyE;QACzE,2DAA2D;QAC3D,6EAA6E;QAC7E,4EAA4E;QAC5E,4EAA4E;QAC5E,0EAA0E;QAC1E,+CAA+C;QAC/C,MAAM,aAAa,GAAG,EAAE,GAAG,cAAc,CAAC,OAAO,EAAE,CAAC;QACpD,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,OAAQ,aAAyC,CAAC,GAAG,CAAC,CAAC;QACzD,CAAC;QACD,QAAQ,CAAC,YAAY,CAAC;YACpB,GAAG,aAAa;YAChB,GAAG,OAAO;SACI,CAAC,CAAC;IACpB,CAAC,EACD,CAAC,QAAQ,EAAE,cAAc,CAAC,CAC3B,CAAC;IAEF,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;IAE1C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAQ,KAAK,SAAS,IAAI,YAAY,EAAE,CAAC;YAC3C,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,SAAS,IAAI,YAAY,EAAE,CAAC;YACzC,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAE3B,OAAO;QACL,GAAG,QAAQ;QACX,YAAY;QACZ,MAAM;QACN,OAAO;QACP,OAAO,EAAE,QAAQ,IAAI,OAAO;QAC5B,QAAQ;QACR,IAAI;QACJ,UAAU;QACV,WAAW;QACX,eAAe;QACf,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Callbacks } from "@elevenlabs/client";
2
+ import type { HookOptions } from "./types";
3
+ /**
4
+ * Wraps user-provided callback props in stable ref-backed functions,
5
+ * preventing stale closure bugs when the session outlives renders.
6
+ *
7
+ * Returns a `Partial<Callbacks>` containing only the keys the caller
8
+ * actually provided. Function references are stable per key across
9
+ * renders, but always invoke the latest prop value. The returned object
10
+ * reference is stable as long as the set of provided keys doesn't change.
11
+ */
12
+ export declare function useStableCallbacks(props: HookOptions): Partial<Callbacks>;
13
+ //# sourceMappingURL=useStableCallbacks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStableCallbacks.d.ts","sourceRoot":"","sources":["../../src/conversation/useStableCallbacks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CA6BzE"}
@@ -0,0 +1,33 @@
1
+ import { useMemo, useRef } from "react";
2
+ import { CALLBACK_KEYS } from "@elevenlabs/client/internal";
3
+ /**
4
+ * Wraps user-provided callback props in stable ref-backed functions,
5
+ * preventing stale closure bugs when the session outlives renders.
6
+ *
7
+ * Returns a `Partial<Callbacks>` containing only the keys the caller
8
+ * actually provided. Function references are stable per key across
9
+ * renders, but always invoke the latest prop value. The returned object
10
+ * reference is stable as long as the set of provided keys doesn't change.
11
+ */
12
+ export function useStableCallbacks(props) {
13
+ // Store the latest prop value for each callback in a ref.
14
+ // Uses Record<string, unknown> to avoid TypeScript's union-to-intersection
15
+ // issue when indexing Callbacks with a union of all its keys.
16
+ const callbackRefs = useRef({});
17
+ for (const key of CALLBACK_KEYS) {
18
+ callbackRefs.current[key] = props[key];
19
+ }
20
+ // Compute a stable scalar from the set of provided keys so we can
21
+ // memoize the result object.
22
+ const activeKeys = CALLBACK_KEYS.filter(key => props[key] !== undefined);
23
+ return useMemo(() => Object.fromEntries(activeKeys.map(key => [
24
+ key,
25
+ (...args) => {
26
+ const fn = callbackRefs.current[key];
27
+ fn?.(...args);
28
+ },
29
+ ])),
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- joined string is a stable scalar derived from activeKeys
31
+ [activeKeys.join("|")]);
32
+ }
33
+ //# sourceMappingURL=useStableCallbacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStableCallbacks.js","sourceRoot":"","sources":["../../src/conversation/useStableCallbacks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAG5D;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAkB;IACnD,0DAA0D;IAC1D,2EAA2E;IAC3E,8DAA8D;IAC9D,MAAM,YAAY,GAAG,MAAM,CAA0B,EAAE,CAAC,CAAC;IACzD,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,kEAAkE;IAClE,6BAA6B;IAC7B,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC;IAEzE,OAAO,OAAO,CACZ,GAAG,EAAE,CACH,MAAM,CAAC,WAAW,CAChB,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,GAAG;QACH,CAAC,GAAG,IAAe,EAAE,EAAE;YACrB,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAEtB,CAAC;YACd,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QAChB,CAAC;KACF,CAAC,CACmB;IACzB,mHAAmH;IACnH,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CACvB,CAAC;AACJ,CAAC"}