@bytexbyte/nxtlinq-ai-agent-web-development 0.1.1

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 (149) hide show
  1. package/dist/context/NxtlinqAgentContext.d.ts +12 -0
  2. package/dist/context/NxtlinqAgentContext.d.ts.map +1 -0
  3. package/dist/context/NxtlinqAgentContext.js +33 -0
  4. package/dist/createNxtlinqAgent.d.ts +9 -0
  5. package/dist/createNxtlinqAgent.d.ts.map +1 -0
  6. package/dist/createNxtlinqAgent.js +19 -0
  7. package/dist/hooks/useNxtlinqAgent.d.ts +18 -0
  8. package/dist/hooks/useNxtlinqAgent.d.ts.map +1 -0
  9. package/dist/hooks/useNxtlinqAgent.js +23 -0
  10. package/dist/hooks/useNxtlinqVoice.d.ts +21 -0
  11. package/dist/hooks/useNxtlinqVoice.d.ts.map +1 -0
  12. package/dist/hooks/useNxtlinqVoice.js +75 -0
  13. package/dist/index.d.ts +12 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +9 -0
  16. package/dist/legacy/api/nxtlinq-api.d.ts +8 -0
  17. package/dist/legacy/api/nxtlinq-api.d.ts.map +1 -0
  18. package/dist/legacy/api/nxtlinq-api.js +13 -0
  19. package/dist/legacy/api/voice.d.ts +11 -0
  20. package/dist/legacy/api/voice.d.ts.map +1 -0
  21. package/dist/legacy/api/voice.js +26 -0
  22. package/dist/legacy/core/lib/messageHistory.d.ts +2 -0
  23. package/dist/legacy/core/lib/messageHistory.d.ts.map +1 -0
  24. package/dist/legacy/core/lib/messageHistory.js +1 -0
  25. package/dist/legacy/core/lib/textToSpeech.d.ts +14 -0
  26. package/dist/legacy/core/lib/textToSpeech.d.ts.map +1 -0
  27. package/dist/legacy/core/lib/textToSpeech.js +82 -0
  28. package/dist/legacy/core/lib/useDraggable.d.ts +15 -0
  29. package/dist/legacy/core/lib/useDraggable.d.ts.map +1 -0
  30. package/dist/legacy/core/lib/useDraggable.js +158 -0
  31. package/dist/legacy/core/lib/useLocalStorage.d.ts +11 -0
  32. package/dist/legacy/core/lib/useLocalStorage.d.ts.map +1 -0
  33. package/dist/legacy/core/lib/useLocalStorage.js +83 -0
  34. package/dist/legacy/core/lib/useResizable.d.ts +17 -0
  35. package/dist/legacy/core/lib/useResizable.d.ts.map +1 -0
  36. package/dist/legacy/core/lib/useResizable.js +203 -0
  37. package/dist/legacy/core/lib/useSessionStorage.d.ts +11 -0
  38. package/dist/legacy/core/lib/useSessionStorage.d.ts.map +1 -0
  39. package/dist/legacy/core/lib/useSessionStorage.js +37 -0
  40. package/dist/legacy/core/lib/useSpeechToTextFromMic/helper.d.ts +26 -0
  41. package/dist/legacy/core/lib/useSpeechToTextFromMic/helper.d.ts.map +1 -0
  42. package/dist/legacy/core/lib/useSpeechToTextFromMic/helper.js +102 -0
  43. package/dist/legacy/core/lib/useSpeechToTextFromMic/index.d.ts +16 -0
  44. package/dist/legacy/core/lib/useSpeechToTextFromMic/index.d.ts.map +1 -0
  45. package/dist/legacy/core/lib/useSpeechToTextFromMic/index.js +92 -0
  46. package/dist/legacy/core/lib/useVoiceMode.d.ts +32 -0
  47. package/dist/legacy/core/lib/useVoiceMode.d.ts.map +1 -0
  48. package/dist/legacy/core/lib/useVoiceMode.js +373 -0
  49. package/dist/legacy/core/metakeepClient.d.ts +4 -0
  50. package/dist/legacy/core/metakeepClient.d.ts.map +1 -0
  51. package/dist/legacy/core/metakeepClient.js +10 -0
  52. package/dist/legacy/core/utils/aitUtils.d.ts +31 -0
  53. package/dist/legacy/core/utils/aitUtils.d.ts.map +1 -0
  54. package/dist/legacy/core/utils/aitUtils.js +35 -0
  55. package/dist/legacy/core/utils/ethersUtils.d.ts +8 -0
  56. package/dist/legacy/core/utils/ethersUtils.d.ts.map +1 -0
  57. package/dist/legacy/core/utils/ethersUtils.js +19 -0
  58. package/dist/legacy/core/utils/index.d.ts +3 -0
  59. package/dist/legacy/core/utils/index.d.ts.map +1 -0
  60. package/dist/legacy/core/utils/index.js +4 -0
  61. package/dist/legacy/core/utils/notificationUtils.d.ts +29 -0
  62. package/dist/legacy/core/utils/notificationUtils.d.ts.map +1 -0
  63. package/dist/legacy/core/utils/notificationUtils.js +47 -0
  64. package/dist/legacy/core/utils/urlUtils.d.ts +25 -0
  65. package/dist/legacy/core/utils/urlUtils.d.ts.map +1 -0
  66. package/dist/legacy/core/utils/urlUtils.js +135 -0
  67. package/dist/legacy/core/utils/walletTextUtils.d.ts +14 -0
  68. package/dist/legacy/core/utils/walletTextUtils.d.ts.map +1 -0
  69. package/dist/legacy/core/utils/walletTextUtils.js +23 -0
  70. package/dist/legacy/core/utils/walletUtils.d.ts +10 -0
  71. package/dist/legacy/core/utils/walletUtils.d.ts.map +1 -0
  72. package/dist/legacy/core/utils/walletUtils.js +38 -0
  73. package/dist/legacy/index.d.ts +19 -0
  74. package/dist/legacy/index.d.ts.map +1 -0
  75. package/dist/legacy/index.js +16 -0
  76. package/dist/ports/createWebPlatformPorts.d.ts +13 -0
  77. package/dist/ports/createWebPlatformPorts.d.ts.map +1 -0
  78. package/dist/ports/createWebPlatformPorts.js +25 -0
  79. package/dist/utils/fileToAttachment.d.ts +4 -0
  80. package/dist/utils/fileToAttachment.d.ts.map +1 -0
  81. package/dist/utils/fileToAttachment.js +28 -0
  82. package/dist/voice/useVoiceSilenceCommit.d.ts +11 -0
  83. package/dist/voice/useVoiceSilenceCommit.d.ts.map +1 -0
  84. package/dist/voice/useVoiceSilenceCommit.js +68 -0
  85. package/dist/voice/useVoiceTranscriptMessages.d.ts +16 -0
  86. package/dist/voice/useVoiceTranscriptMessages.d.ts.map +1 -0
  87. package/dist/voice/useVoiceTranscriptMessages.js +134 -0
  88. package/dist/voice/useWsRealtimeAudio.d.ts +18 -0
  89. package/dist/voice/useWsRealtimeAudio.d.ts.map +1 -0
  90. package/dist/voice/useWsRealtimeAudio.js +115 -0
  91. package/dist/voice/voiceMicConstants.d.ts +4 -0
  92. package/dist/voice/voiceMicConstants.d.ts.map +1 -0
  93. package/dist/voice/voiceMicConstants.js +10 -0
  94. package/dist/voice/ws/BrowserWsPcmPlayer.d.ts +23 -0
  95. package/dist/voice/ws/BrowserWsPcmPlayer.d.ts.map +1 -0
  96. package/dist/voice/ws/BrowserWsPcmPlayer.js +138 -0
  97. package/dist/voice/ws/BrowserWsPcmRecorder.d.ts +19 -0
  98. package/dist/voice/ws/BrowserWsPcmRecorder.d.ts.map +1 -0
  99. package/dist/voice/ws/BrowserWsPcmRecorder.js +76 -0
  100. package/dist/voice/ws/float32ToPcm16.d.ts +2 -0
  101. package/dist/voice/ws/float32ToPcm16.d.ts.map +1 -0
  102. package/dist/voice/ws/float32ToPcm16.js +8 -0
  103. package/dist/voice/ws/voiceSilenceConstants.d.ts +5 -0
  104. package/dist/voice/ws/voiceSilenceConstants.d.ts.map +1 -0
  105. package/dist/voice/ws/voiceSilenceConstants.js +4 -0
  106. package/dist/voice/ws/wsRealtimeConstants.d.ts +2 -0
  107. package/dist/voice/ws/wsRealtimeConstants.d.ts.map +1 -0
  108. package/dist/voice/ws/wsRealtimeConstants.js +1 -0
  109. package/dist/webAgentDefaults.d.ts +9 -0
  110. package/dist/webAgentDefaults.d.ts.map +1 -0
  111. package/dist/webAgentDefaults.js +9 -0
  112. package/package.json +55 -0
  113. package/src/context/NxtlinqAgentContext.tsx +79 -0
  114. package/src/createNxtlinqAgent.ts +36 -0
  115. package/src/hooks/useNxtlinqAgent.ts +73 -0
  116. package/src/hooks/useNxtlinqVoice.ts +143 -0
  117. package/src/index.ts +84 -0
  118. package/src/legacy/api/nxtlinq-api.ts +32 -0
  119. package/src/legacy/api/voice.ts +72 -0
  120. package/src/legacy/core/lib/messageHistory.ts +6 -0
  121. package/src/legacy/core/lib/textToSpeech.ts +127 -0
  122. package/src/legacy/core/lib/useDraggable.ts +193 -0
  123. package/src/legacy/core/lib/useLocalStorage.ts +89 -0
  124. package/src/legacy/core/lib/useResizable.ts +256 -0
  125. package/src/legacy/core/lib/useSessionStorage.ts +43 -0
  126. package/src/legacy/core/lib/useSpeechToTextFromMic/helper.ts +132 -0
  127. package/src/legacy/core/lib/useSpeechToTextFromMic/index.ts +126 -0
  128. package/src/legacy/core/lib/useVoiceMode.ts +407 -0
  129. package/src/legacy/core/metakeepClient.ts +12 -0
  130. package/src/legacy/core/utils/aitUtils.ts +55 -0
  131. package/src/legacy/core/utils/ethersUtils.ts +24 -0
  132. package/src/legacy/core/utils/index.ts +5 -0
  133. package/src/legacy/core/utils/notificationUtils.ts +64 -0
  134. package/src/legacy/core/utils/urlUtils.ts +160 -0
  135. package/src/legacy/core/utils/walletTextUtils.ts +26 -0
  136. package/src/legacy/core/utils/walletUtils.ts +53 -0
  137. package/src/legacy/index.ts +35 -0
  138. package/src/ports/createWebPlatformPorts.ts +44 -0
  139. package/src/utils/fileToAttachment.ts +32 -0
  140. package/src/voice/useVoiceSilenceCommit.ts +84 -0
  141. package/src/voice/useVoiceTranscriptMessages.ts +184 -0
  142. package/src/voice/useWsRealtimeAudio.ts +141 -0
  143. package/src/voice/voiceMicConstants.ts +13 -0
  144. package/src/voice/ws/BrowserWsPcmPlayer.ts +139 -0
  145. package/src/voice/ws/BrowserWsPcmRecorder.ts +83 -0
  146. package/src/voice/ws/float32ToPcm16.ts +8 -0
  147. package/src/voice/ws/voiceSilenceConstants.ts +4 -0
  148. package/src/voice/ws/wsRealtimeConstants.ts +1 -0
  149. package/src/webAgentDefaults.ts +12 -0
@@ -0,0 +1,11 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ /**
3
+ * Custom hook for managing localStorage with React state and cross-tab synchronization
4
+ * Automatically syncs changes across browser tabs using StorageEvent
5
+ *
6
+ * @param key - The key to store the value under in localStorage
7
+ * @param defaultValue - The default value to use if no value is stored
8
+ * @returns [storedValue, setStoredValue, isInitialized]
9
+ */
10
+ export default function useLocalStorage<T>(key: string, defaultValue: T): [T, Dispatch<SetStateAction<T>>, boolean];
11
+ //# sourceMappingURL=useLocalStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLocalStorage.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/lib/useLocalStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAA+B,MAAM,OAAO,CAAC;AAE9E;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CA8ElH"}
@@ -0,0 +1,83 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ /**
3
+ * Custom hook for managing localStorage with React state and cross-tab synchronization
4
+ * Automatically syncs changes across browser tabs using StorageEvent
5
+ *
6
+ * @param key - The key to store the value under in localStorage
7
+ * @param defaultValue - The default value to use if no value is stored
8
+ * @returns [storedValue, setStoredValue, isInitialized]
9
+ */
10
+ export default function useLocalStorage(key, defaultValue) {
11
+ const [storedValue, setStoredValue] = useState(defaultValue);
12
+ const [isInitialized, setIsInitialized] = useState(false);
13
+ // Ref to track if we're currently processing a storage event (to prevent loops)
14
+ // Note: StorageEvent only fires in OTHER tabs, not the current tab, so this ref
15
+ // is mainly used to prevent any edge cases
16
+ const isProcessingStorageEventRef = useRef(false);
17
+ // Initialize from localStorage
18
+ useEffect(() => {
19
+ try {
20
+ const storageValue = localStorage.getItem(key);
21
+ if (storageValue !== null) {
22
+ const parsed = JSON.parse(storageValue);
23
+ setStoredValue(parsed);
24
+ }
25
+ }
26
+ catch (error) {
27
+ console.warn(`Error reading from localStorage key "${key}":`, error);
28
+ }
29
+ setIsInitialized(true);
30
+ }, [key]);
31
+ // Save to localStorage when value changes
32
+ useEffect(() => {
33
+ if (!isInitialized || isProcessingStorageEventRef.current)
34
+ return;
35
+ try {
36
+ const serialized = JSON.stringify(storedValue);
37
+ const currentValue = localStorage.getItem(key);
38
+ // Only write if the value actually changed (avoid unnecessary writes)
39
+ if (currentValue !== serialized) {
40
+ localStorage.setItem(key, serialized);
41
+ }
42
+ }
43
+ catch (error) {
44
+ console.warn(`Error writing to localStorage key "${key}":`, error);
45
+ }
46
+ }, [storedValue, isInitialized, key]);
47
+ // Listen for storage changes from other tabs (cross-tab synchronization)
48
+ useEffect(() => {
49
+ const handleStorageChange = (e) => {
50
+ // Only handle events for this key and ignore events from the current tab
51
+ if (e.key !== key || e.storageArea !== localStorage) {
52
+ return;
53
+ }
54
+ // StorageEvent only fires in OTHER tabs, not the tab that made the change
55
+ // So we can safely update the state here
56
+ try {
57
+ isProcessingStorageEventRef.current = true;
58
+ if (e.newValue !== null) {
59
+ const newValue = JSON.parse(e.newValue);
60
+ setStoredValue(newValue);
61
+ }
62
+ else {
63
+ // If newValue is null, it means the item was removed
64
+ setStoredValue(defaultValue);
65
+ }
66
+ }
67
+ catch (error) {
68
+ console.warn(`Error parsing storage event for key "${key}":`, error);
69
+ }
70
+ finally {
71
+ // Reset the flag after a brief delay to allow state updates to complete
72
+ setTimeout(() => {
73
+ isProcessingStorageEventRef.current = false;
74
+ }, 0);
75
+ }
76
+ };
77
+ window.addEventListener('storage', handleStorageChange);
78
+ return () => {
79
+ window.removeEventListener('storage', handleStorageChange);
80
+ };
81
+ }, [key, defaultValue]);
82
+ return [storedValue, setStoredValue, isInitialized];
83
+ }
@@ -0,0 +1,17 @@
1
+ import { RefObject } from 'react';
2
+ export type ResizeCorner = 'nw' | 'ne' | 'sw' | 'se';
3
+ interface Position {
4
+ x: number;
5
+ y: number;
6
+ }
7
+ interface Dimensions {
8
+ width: number;
9
+ height: number;
10
+ }
11
+ export declare const useResizable: (currentPositionRef?: RefObject<Position>) => {
12
+ dimensions: Dimensions;
13
+ handleResizeStart: (corner: ResizeCorner) => (event: React.PointerEvent<HTMLDivElement>) => void;
14
+ positionAdjustment: Position | null;
15
+ };
16
+ export {};
17
+ //# sourceMappingURL=useResizable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useResizable.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/lib/useResizable.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,SAAS,EAAE,MAAM,OAAO,CAAC;AAqB5E,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAErD,UAAU,QAAQ;IAChB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AASD,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,YAAY,GAAI,qBAAqB,SAAS,CAAC,QAAQ,CAAC;;gCA6ExD,YAAY,aAAa,KAAK,CAAC,YAAY,CAAC,cAAc,CAAC;;CA0IvE,CAAC"}
@@ -0,0 +1,203 @@
1
+ import { useState, useRef, useCallback, useEffect } from 'react';
2
+ import useLocalStorage from './useLocalStorage';
3
+ // Resizable chat window defaults
4
+ const DEFAULT_WIDTH = 500;
5
+ const DEFAULT_HEIGHT = 600;
6
+ const ASPECT_RATIO = DEFAULT_WIDTH / DEFAULT_HEIGHT;
7
+ const MIN_WIDTH = 320;
8
+ const MIN_HEIGHT = 380;
9
+ const VIEWPORT_MARGIN = 40; // Keep space from viewport edges
10
+ const MOBILE_BREAKPOINT = 768;
11
+ const MOBILE_EDGE_MARGIN = 12;
12
+ const isMobileViewport = () => typeof window !== 'undefined' && window.innerWidth <= MOBILE_BREAKPOINT;
13
+ const getMobileFullscreenDimensions = () => ({
14
+ width: Math.max(MIN_WIDTH, window.innerWidth - MOBILE_EDGE_MARGIN * 2),
15
+ height: Math.max(MIN_HEIGHT, window.innerHeight - MOBILE_EDGE_MARGIN * 2),
16
+ });
17
+ export const useResizable = (currentPositionRef) => {
18
+ const resizeState = useRef(null);
19
+ const [positionAdjustment, setPositionAdjustment] = useState(null);
20
+ const [savedDimensions, setSavedDimensions, isDimensionsInitialized] = useLocalStorage('chat-window-dimensions', null);
21
+ const [isResizing, setIsResizing] = useState(false);
22
+ const clampDimensions = useCallback((width, height) => {
23
+ if (typeof window === 'undefined') {
24
+ return { width, height };
25
+ }
26
+ if (isMobileViewport()) {
27
+ return getMobileFullscreenDimensions();
28
+ }
29
+ const maxWidth = Math.max(MIN_WIDTH, window.innerWidth - VIEWPORT_MARGIN);
30
+ const maxHeight = Math.max(MIN_HEIGHT, window.innerHeight - VIEWPORT_MARGIN);
31
+ const clampedWidth = Math.min(Math.max(width, MIN_WIDTH), maxWidth);
32
+ let clampedHeight = clampedWidth / ASPECT_RATIO;
33
+ if (clampedHeight > maxHeight) {
34
+ clampedHeight = maxHeight;
35
+ const adjustedWidth = clampedHeight * ASPECT_RATIO;
36
+ return { width: adjustedWidth, height: clampedHeight };
37
+ }
38
+ if (clampedHeight < MIN_HEIGHT) {
39
+ clampedHeight = MIN_HEIGHT;
40
+ const adjustedWidth = clampedHeight * ASPECT_RATIO;
41
+ return { width: adjustedWidth, height: clampedHeight };
42
+ }
43
+ return { width: clampedWidth, height: clampedHeight };
44
+ }, []);
45
+ const calculateDimensions = useCallback((savedDims) => {
46
+ if (typeof window === 'undefined') {
47
+ return { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
48
+ }
49
+ const baseDimensions = savedDims || { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
50
+ return clampDimensions(baseDimensions.width, baseDimensions.height);
51
+ }, [clampDimensions]);
52
+ const [dimensions, setDimensions] = useState(() => {
53
+ if (typeof window === 'undefined') {
54
+ return { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
55
+ }
56
+ if (isMobileViewport()) {
57
+ return getMobileFullscreenDimensions();
58
+ }
59
+ const maxWidth = Math.max(MIN_WIDTH, window.innerWidth - VIEWPORT_MARGIN);
60
+ const maxHeight = Math.max(MIN_HEIGHT, window.innerHeight - VIEWPORT_MARGIN);
61
+ let width = Math.min(Math.max(DEFAULT_WIDTH, MIN_WIDTH), maxWidth);
62
+ let height = width / ASPECT_RATIO;
63
+ if (height > maxHeight) {
64
+ height = maxHeight;
65
+ width = height * ASPECT_RATIO;
66
+ }
67
+ if (height < MIN_HEIGHT) {
68
+ height = MIN_HEIGHT;
69
+ width = height * ASPECT_RATIO;
70
+ }
71
+ return { width, height };
72
+ });
73
+ const hasLoadedFromStorage = useRef(false);
74
+ useEffect(() => {
75
+ if (isDimensionsInitialized && !hasLoadedFromStorage.current) {
76
+ const newDimensions = calculateDimensions(savedDimensions);
77
+ setDimensions(newDimensions);
78
+ hasLoadedFromStorage.current = true;
79
+ }
80
+ }, [isDimensionsInitialized, savedDimensions, calculateDimensions]);
81
+ const handleResizeStart = useCallback((corner) => (event) => {
82
+ event.preventDefault();
83
+ event.stopPropagation();
84
+ const currentPos = currentPositionRef?.current;
85
+ if (!currentPos) {
86
+ return;
87
+ }
88
+ const anchorTL = { x: currentPos.x, y: currentPos.y };
89
+ const anchorBR = {
90
+ x: currentPos.x + dimensions.width,
91
+ y: currentPos.y + dimensions.height
92
+ };
93
+ resizeState.current = { corner, anchorTL, anchorBR };
94
+ setIsResizing(true);
95
+ setPositionAdjustment(null);
96
+ document.body.style.userSelect = 'none';
97
+ }, [currentPositionRef, dimensions.width, dimensions.height]);
98
+ useEffect(() => {
99
+ if (!isResizing) {
100
+ return;
101
+ }
102
+ const handlePointerMove = (event) => {
103
+ const state = resizeState.current;
104
+ if (!state) {
105
+ return;
106
+ }
107
+ const { corner, anchorTL, anchorBR } = state;
108
+ const anchorBL = { x: anchorTL.x, y: anchorBR.y };
109
+ const anchorTR = { x: anchorBR.x, y: anchorTL.y };
110
+ let targetFromX;
111
+ let targetFromY;
112
+ switch (corner) {
113
+ case 'nw': {
114
+ const deltaX = anchorBR.x - event.clientX;
115
+ const deltaY = anchorBR.y - event.clientY;
116
+ targetFromX = deltaX;
117
+ targetFromY = deltaY * ASPECT_RATIO;
118
+ break;
119
+ }
120
+ case 'se': {
121
+ targetFromX = event.clientX - anchorTL.x;
122
+ targetFromY = (event.clientY - anchorTL.y) * ASPECT_RATIO;
123
+ break;
124
+ }
125
+ case 'ne': {
126
+ targetFromX = event.clientX - anchorBL.x;
127
+ targetFromY = (anchorBL.y - event.clientY) * ASPECT_RATIO;
128
+ break;
129
+ }
130
+ case 'sw': {
131
+ targetFromX = anchorTR.x - event.clientX;
132
+ targetFromY = (event.clientY - anchorTR.y) * ASPECT_RATIO;
133
+ break;
134
+ }
135
+ default:
136
+ return;
137
+ }
138
+ const nextWidth = (targetFromX + targetFromY) / 2;
139
+ const newDimensions = clampDimensions(nextWidth, nextWidth / ASPECT_RATIO);
140
+ let newPos;
141
+ switch (corner) {
142
+ case 'nw':
143
+ newPos = {
144
+ x: anchorBR.x - newDimensions.width,
145
+ y: anchorBR.y - newDimensions.height
146
+ };
147
+ break;
148
+ case 'se':
149
+ newPos = { x: anchorTL.x, y: anchorTL.y };
150
+ break;
151
+ case 'ne':
152
+ newPos = {
153
+ x: anchorBL.x,
154
+ y: anchorBL.y - newDimensions.height
155
+ };
156
+ break;
157
+ case 'sw':
158
+ newPos = {
159
+ x: anchorTR.x - newDimensions.width,
160
+ y: anchorTR.y
161
+ };
162
+ break;
163
+ default:
164
+ newPos = anchorTL;
165
+ }
166
+ setDimensions(newDimensions);
167
+ setPositionAdjustment(newPos);
168
+ };
169
+ const handlePointerUp = () => {
170
+ setIsResizing(false);
171
+ resizeState.current = null;
172
+ setPositionAdjustment(null);
173
+ document.body.style.userSelect = '';
174
+ };
175
+ document.addEventListener('pointermove', handlePointerMove);
176
+ document.addEventListener('pointerup', handlePointerUp);
177
+ return () => {
178
+ document.removeEventListener('pointermove', handlePointerMove);
179
+ document.removeEventListener('pointerup', handlePointerUp);
180
+ document.body.style.userSelect = '';
181
+ };
182
+ }, [clampDimensions, isResizing]);
183
+ useEffect(() => {
184
+ if (!isResizing && isDimensionsInitialized && hasLoadedFromStorage.current) {
185
+ setSavedDimensions(dimensions);
186
+ }
187
+ }, [dimensions, isResizing, isDimensionsInitialized, setSavedDimensions]);
188
+ useEffect(() => {
189
+ const handleResize = () => {
190
+ setDimensions((current) => {
191
+ const clamped = clampDimensions(current.width, current.height);
192
+ return clamped;
193
+ });
194
+ };
195
+ window.addEventListener('resize', handleResize);
196
+ return () => window.removeEventListener('resize', handleResize);
197
+ }, [clampDimensions]);
198
+ return {
199
+ dimensions,
200
+ handleResizeStart,
201
+ positionAdjustment
202
+ };
203
+ };
@@ -0,0 +1,11 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ /**
3
+ * Custom hook for managing sessionStorage with React state
4
+ * Similar to useLocalStorage but uses sessionStorage instead
5
+ *
6
+ * @param key - The key to store the value under in sessionStorage
7
+ * @param defaultValue - The default value to use if no value is stored
8
+ * @returns [storedValue, setStoredValue, isInitialized]
9
+ */
10
+ export default function useSessionStorage<T>(key: string, defaultValue: T): [T, Dispatch<SetStateAction<T>>, boolean];
11
+ //# sourceMappingURL=useSessionStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSessionStorage.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/lib/useSessionStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAuB,MAAM,OAAO,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,CAAC,EACzC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,CAAC,GACd,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CA6B3C"}
@@ -0,0 +1,37 @@
1
+ import { useEffect, useState } from 'react';
2
+ /**
3
+ * Custom hook for managing sessionStorage with React state
4
+ * Similar to useLocalStorage but uses sessionStorage instead
5
+ *
6
+ * @param key - The key to store the value under in sessionStorage
7
+ * @param defaultValue - The default value to use if no value is stored
8
+ * @returns [storedValue, setStoredValue, isInitialized]
9
+ */
10
+ export default function useSessionStorage(key, defaultValue) {
11
+ const [storedValue, setStoredValue] = useState(defaultValue);
12
+ const [isInitialized, setIsInitialized] = useState(false);
13
+ useEffect(() => {
14
+ try {
15
+ const storageValue = sessionStorage.getItem(key);
16
+ if (storageValue !== null) {
17
+ setStoredValue(JSON.parse(storageValue));
18
+ }
19
+ }
20
+ catch (error) {
21
+ console.warn(`Error reading from sessionStorage key "${key}":`, error);
22
+ // If there's an error, keep the default value
23
+ }
24
+ setIsInitialized(true);
25
+ }, [key]);
26
+ useEffect(() => {
27
+ if (isInitialized) {
28
+ try {
29
+ sessionStorage.setItem(key, JSON.stringify(storedValue));
30
+ }
31
+ catch (error) {
32
+ console.warn(`Error writing to sessionStorage key "${key}":`, error);
33
+ }
34
+ }
35
+ }, [storedValue, isInitialized, key]);
36
+ return [storedValue, setStoredValue, isInitialized];
37
+ }
@@ -0,0 +1,26 @@
1
+ import { SpeechRecognizer } from 'microsoft-cognitiveservices-speech-sdk';
2
+ import { Dispatch, SetStateAction } from 'react';
3
+ /**
4
+ * Start speech recognition
5
+ * - partialTranscript: temporary partial transcription (recognizing)
6
+ * - setSpeechToTextArray: finalized sentence array (recognized)
7
+ */
8
+ export declare const startSpeechToTextFromMic: (setSpeechToTextArray: Dispatch<SetStateAction<string[]>>, // finalized sentences
9
+ config: {
10
+ apiKey: string;
11
+ apiSecret: string;
12
+ }, historyRef: React.MutableRefObject<string[]>, indexRef: React.MutableRefObject<number>, setPartialTranscript?: Dispatch<SetStateAction<string>>) => Promise<SpeechRecognizer | undefined>;
13
+ /**
14
+ * Stop speech recognition
15
+ */
16
+ export declare const stopRecognition: (recognizer: SpeechRecognizer | undefined) => void;
17
+ export declare function getTokenOrRefresh(apiKey: string, apiSecret: string): Promise<{
18
+ authToken: null;
19
+ error: string;
20
+ region?: undefined;
21
+ } | {
22
+ authToken: any;
23
+ region: any;
24
+ error?: undefined;
25
+ }>;
26
+ //# sourceMappingURL=helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../../../../src/legacy/core/lib/useSpeechToTextFromMic/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,gBAAgB,EACjB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAIjD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACnC,sBAAsB,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,EAAI,sBAAsB;AAClF,QAAQ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC7C,YAAY,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,EAC5C,UAAU,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,EACxC,uBAAuB,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KACtD,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAyEtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,YAAY,gBAAgB,GAAG,SAAS,SAIvE,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;GAwBxE"}
@@ -0,0 +1,102 @@
1
+ import { AudioConfig, CancellationReason, PropertyId, ResultReason, SpeechConfig, SpeechRecognizer, } from 'microsoft-cognitiveservices-speech-sdk';
2
+ import Cookie from 'universal-cookie';
3
+ import { createNxtlinqApi } from '../../../api/nxtlinq-api';
4
+ /**
5
+ * Start speech recognition
6
+ * - partialTranscript: temporary partial transcription (recognizing)
7
+ * - setSpeechToTextArray: finalized sentence array (recognized)
8
+ */
9
+ export const startSpeechToTextFromMic = async (setSpeechToTextArray, // finalized sentences
10
+ config, historyRef, indexRef, setPartialTranscript // temporary partial transcription state updater
11
+ ) => {
12
+ const tokenRes = await getTokenOrRefresh(config.apiKey, config.apiSecret);
13
+ if (!tokenRes.authToken || !tokenRes.region) {
14
+ console.error('Speech token retrieval failed:', tokenRes.error);
15
+ return;
16
+ }
17
+ const speechConfig = SpeechConfig.fromAuthorizationToken(tokenRes.authToken, tokenRes.region);
18
+ speechConfig.speechRecognitionLanguage = 'en-US';
19
+ // silence detection and segmentation configuration
20
+ speechConfig.setProperty(PropertyId.SpeechServiceConnection_InitialSilenceTimeoutMs, '10000');
21
+ speechConfig.setProperty(PropertyId.SpeechServiceConnection_EndSilenceTimeoutMs, '86400000');
22
+ speechConfig.setProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, '3000');
23
+ const audioConfig = AudioConfig.fromDefaultMicrophoneInput();
24
+ const recognizer = new SpeechRecognizer(speechConfig, audioConfig);
25
+ // temporary partial transcription
26
+ recognizer.recognizing = (_s, e) => {
27
+ if (setPartialTranscript) {
28
+ setPartialTranscript(e.result.text);
29
+ }
30
+ };
31
+ // finalized sentences
32
+ recognizer.recognized = (_s, e) => {
33
+ if (e.result.reason === ResultReason.RecognizedSpeech) {
34
+ const text = e.result.text.trim();
35
+ // Filter out very short text (likely background noise or false positives)
36
+ // Minimum 3 characters to reduce sensitivity to background sounds
37
+ if (text.length < 3) {
38
+ return;
39
+ }
40
+ // Check confidence if available (some SDK versions provide this)
41
+ // Lower confidence results are more likely to be background noise
42
+ // Increased threshold to 0.4 to better filter out low-volume background noise
43
+ const confidence = e.result.confidence;
44
+ if (confidence !== undefined && confidence < 0.4) {
45
+ return;
46
+ }
47
+ historyRef.current[indexRef.current] = text;
48
+ indexRef.current += 1;
49
+ // return only the latest finalized sentence to the UI
50
+ setSpeechToTextArray([text]);
51
+ if (setPartialTranscript)
52
+ setPartialTranscript('');
53
+ }
54
+ };
55
+ recognizer.canceled = (_s, e) => {
56
+ console.warn('Speech recognition canceled:', e.reason);
57
+ if (e.reason === CancellationReason.Error) {
58
+ console.error(`Error code: ${e.errorCode}`);
59
+ console.error(`Error details: ${e.errorDetails}`);
60
+ }
61
+ };
62
+ await new Promise((resolve, reject) => {
63
+ recognizer.startContinuousRecognitionAsync(() => resolve(), error => {
64
+ console.error('Failed to start continuous speech recognition:', error);
65
+ reject(error);
66
+ });
67
+ });
68
+ return recognizer;
69
+ };
70
+ /**
71
+ * Stop speech recognition
72
+ */
73
+ export const stopRecognition = (recognizer) => {
74
+ if (recognizer) {
75
+ recognizer.stopContinuousRecognitionAsync();
76
+ }
77
+ };
78
+ export async function getTokenOrRefresh(apiKey, apiSecret) {
79
+ const nxtlinqApi = createNxtlinqApi(apiKey, apiSecret);
80
+ const cookie = new Cookie();
81
+ const speechToken = cookie.get('speech-token');
82
+ if (speechToken === undefined) {
83
+ try {
84
+ const res = await nxtlinqApi.cognitive.getCognitiveToken();
85
+ if ('error' in res) {
86
+ throw new Error(res.error);
87
+ }
88
+ const token = res.token;
89
+ const region = res.region;
90
+ cookie.set('speech-token', region + ':' + token, { maxAge: 540, path: '/' });
91
+ return { authToken: token, region: region };
92
+ }
93
+ catch (e) {
94
+ const err = e;
95
+ return { authToken: null, error: err.response.data };
96
+ }
97
+ }
98
+ else {
99
+ const idx = speechToken.indexOf(':');
100
+ return { authToken: speechToken.slice(idx + 1), region: speechToken.slice(0, idx) };
101
+ }
102
+ }
@@ -0,0 +1,16 @@
1
+ interface Props {
2
+ apiKey: string;
3
+ apiSecret: string;
4
+ autoClearTranscript?: boolean;
5
+ }
6
+ type UseSpeechToTextFromMicResult = {
7
+ start: () => Promise<void>;
8
+ stop: () => void;
9
+ clear: () => void;
10
+ isMicEnabled: boolean;
11
+ transcript: string;
12
+ partialTranscript: string;
13
+ };
14
+ export declare function useSpeechToTextFromMic({ apiKey, apiSecret, autoClearTranscript, }: Props): UseSpeechToTextFromMicResult;
15
+ export {};
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/legacy/core/lib/useSpeechToTextFromMic/index.ts"],"names":[],"mappings":"AAIA,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,KAAK,4BAA4B,GAAG;IAClC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,SAAS,EACT,mBAA0B,GAC3B,EAAE,KAAK,GAAG,4BAA4B,CAsGtC"}
@@ -0,0 +1,92 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { startSpeechToTextFromMic, stopRecognition } from './helper';
3
+ export function useSpeechToTextFromMic({ apiKey, apiSecret, autoClearTranscript = true, }) {
4
+ const [isMicEnabled, setIsMicEnabled] = useState(false);
5
+ const [transcriptArray, setTranscriptArray] = useState([]);
6
+ const [partialTranscript, setPartialTranscript] = useState('');
7
+ const [recognizer, setRecognizer] = useState();
8
+ const wakelock = useRef();
9
+ const historyRef = useRef([]);
10
+ const indexRef = useRef(0);
11
+ const lockWakeState = useCallback(async () => {
12
+ if (typeof navigator === 'undefined' || !('wakeLock' in navigator))
13
+ return;
14
+ try {
15
+ wakelock.current = await navigator.wakeLock.request('screen');
16
+ wakelock.current.addEventListener('release', () => {
17
+ // Wake lock was released by the system
18
+ });
19
+ }
20
+ catch (err) {
21
+ console.error('Wake lock error:', err);
22
+ }
23
+ }, []);
24
+ const clear = useCallback(() => {
25
+ historyRef.current = [];
26
+ indexRef.current = 0;
27
+ setTranscriptArray([]);
28
+ setPartialTranscript('');
29
+ }, [setPartialTranscript, setTranscriptArray]);
30
+ const start = useCallback(async () => {
31
+ clear();
32
+ await lockWakeState();
33
+ try {
34
+ const recognizerInstance = await startSpeechToTextFromMic(setTranscriptArray, { apiKey, apiSecret }, historyRef, indexRef, setPartialTranscript);
35
+ setRecognizer(recognizerInstance);
36
+ setIsMicEnabled(true);
37
+ }
38
+ catch (error) {
39
+ wakelock.current?.release();
40
+ setIsMicEnabled(false);
41
+ console.error('Failed to start speech recognition:', error);
42
+ throw error;
43
+ }
44
+ }, [apiKey, apiSecret, clear, lockWakeState, setPartialTranscript, setTranscriptArray]);
45
+ const stop = useCallback(() => {
46
+ wakelock.current?.release();
47
+ stopRecognition(recognizer);
48
+ setIsMicEnabled(false);
49
+ setRecognizer(undefined);
50
+ }, [recognizer, setRecognizer]);
51
+ // Keep UI state in sync if recognizer stops or gets canceled by the SDK/browser
52
+ useEffect(() => {
53
+ if (!recognizer)
54
+ return;
55
+ const prevCanceled = recognizer.canceled;
56
+ const prevSessionStopped = recognizer.sessionStopped;
57
+ recognizer.canceled = (s, e) => {
58
+ setIsMicEnabled(false);
59
+ if (prevCanceled)
60
+ prevCanceled(s, e);
61
+ };
62
+ recognizer.sessionStopped = (s, e) => {
63
+ setIsMicEnabled(false);
64
+ if (prevSessionStopped)
65
+ prevSessionStopped(s, e);
66
+ };
67
+ return () => {
68
+ // No explicit detach API; restoring previous handlers to avoid leaks
69
+ if (recognizer) {
70
+ recognizer.canceled = prevCanceled;
71
+ recognizer.sessionStopped = prevSessionStopped;
72
+ }
73
+ };
74
+ }, [recognizer]);
75
+ useEffect(() => {
76
+ if (autoClearTranscript && transcriptArray.length > 0) {
77
+ const timer = setTimeout(() => {
78
+ setTranscriptArray([]);
79
+ }, 100);
80
+ return () => clearTimeout(timer);
81
+ }
82
+ }, [transcriptArray, autoClearTranscript]);
83
+ const transcript = transcriptArray.join(' ');
84
+ return {
85
+ start,
86
+ stop,
87
+ clear,
88
+ isMicEnabled,
89
+ transcript,
90
+ partialTranscript,
91
+ };
92
+ }
@@ -0,0 +1,32 @@
1
+ import * as React from 'react';
2
+ import type { AITApi, Message, VoiceTransport } from '@bytexbyte/nxtlinq-ai-agent-core-development';
3
+ import { type VoiceStatus } from '../../api/voice';
4
+ export type UseVoiceModeOptions = {
5
+ apiKey: string;
6
+ apiSecret: string;
7
+ pseudoId: string;
8
+ externalId?: string;
9
+ aitId?: string;
10
+ walletAddress?: string;
11
+ aitToken?: string;
12
+ metadata?: Record<string, unknown>;
13
+ nxtlinqApi: AITApi;
14
+ getMessages: () => Message[];
15
+ setMessages: React.Dispatch<React.SetStateAction<Message[]>>;
16
+ onError?: (error: Error) => void;
17
+ stopRecording: () => void;
18
+ stopTextToSpeech: () => void;
19
+ voiceTransport?: VoiceTransport;
20
+ };
21
+ export declare function useVoiceMode({ apiKey, apiSecret, pseudoId, externalId, aitId, walletAddress, aitToken, metadata, nxtlinqApi, getMessages, setMessages, onError, stopRecording, stopTextToSpeech, voiceTransport, }: UseVoiceModeOptions): {
22
+ isVoiceMode: boolean;
23
+ voiceStatus: VoiceStatus;
24
+ isVoiceConnecting: boolean;
25
+ isMicMuted: boolean;
26
+ remoteAudioRef: React.MutableRefObject<HTMLAudioElement | null>;
27
+ enterVoiceMode: () => Promise<void>;
28
+ exitVoiceMode: () => Promise<void>;
29
+ toggleMicMute: () => void;
30
+ interruptVoice: () => void;
31
+ };
32
+ //# sourceMappingURL=useVoiceMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVoiceMode.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/lib/useVoiceMode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAC;AACpG,OAAO,EAKL,KAAK,WAAW,EAEjB,MAAM,iBAAiB,CAAC;AAgBzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,OAAO,EAAE,CAAC;IAC7B,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,QAAQ,EACR,UAAU,EACV,KAAK,EACL,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,cAA8B,GAC/B,EAAE,mBAAmB;;;;;;;;;;EA0VrB"}