@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,373 @@
1
+ import * as React from 'react';
2
+ import { flushSync } from 'react-dom';
3
+ import { mergeStreamingTranscript, normalizeTranscriptKey, } from '../../api/voice';
4
+ import { appendServerHistoryIntoMessages } from './messageHistory';
5
+ import { useVoiceTranscriptMessages } from '../../../voice/useVoiceTranscriptMessages';
6
+ import { useWsRealtimeAudio } from '../../../voice/useWsRealtimeAudio';
7
+ const TURN_SETTLE_MS = 1500;
8
+ const VOICE_HISTORY_SYNC_LAST = 20;
9
+ const USER_TRANSCRIPT_BLOCKED = new Set([
10
+ 'thinking', 'generating', 'speaking',
11
+ ]);
12
+ const ASSISTANT_MIC_HOLD_STATUSES = new Set([
13
+ 'transcribing', 'thinking', 'generating', 'speaking',
14
+ ]);
15
+ export function useVoiceMode({ apiKey, apiSecret, pseudoId, externalId, aitId, walletAddress, aitToken, metadata, nxtlinqApi, getMessages, setMessages, onError, stopRecording, stopTextToSpeech, voiceTransport = 'ws-realtime', }) {
16
+ const [isVoiceMode, setIsVoiceMode] = React.useState(false);
17
+ const [voiceStatus, setVoiceStatus] = React.useState('idle');
18
+ const [isVoiceConnecting, setIsVoiceConnecting] = React.useState(false);
19
+ const [isMicMuted, setIsMicMuted] = React.useState(true);
20
+ const [isMicCaptureActive, setIsMicCaptureActive] = React.useState(false);
21
+ const [voiceSessionId, setVoiceSessionId] = React.useState(null);
22
+ const sessionRef = React.useRef(null);
23
+ const remoteAudioRef = React.useRef(null);
24
+ const voiceStatusRef = React.useRef('idle');
25
+ const activeTurnRef = React.useRef(false);
26
+ const historyRefreshInFlightRef = React.useRef(null);
27
+ const turnUserTextRef = React.useRef('');
28
+ const lastCommittedUserRef = React.useRef('');
29
+ const userMicMutedRef = React.useRef(true);
30
+ const userMicOptInRef = React.useRef(false);
31
+ const assistantMicHoldRef = React.useRef(false);
32
+ const voiceConnectGenerationRef = React.useRef(0);
33
+ const connectInFlightRef = React.useRef(false);
34
+ const turnSettleUntilRef = React.useRef(0);
35
+ const syncVoiceTurnHistory = React.useCallback(async (last = VOICE_HISTORY_SYNC_LAST) => {
36
+ if (historyRefreshInFlightRef.current)
37
+ return historyRefreshInFlightRef.current;
38
+ const run = (async () => {
39
+ const result = await nxtlinqApi.agent.getMessageHistory({
40
+ apiKey, apiSecret, pseudoId, externalId, last,
41
+ });
42
+ if ('error' in result) {
43
+ onError?.(new Error(result.error));
44
+ return;
45
+ }
46
+ flushSync(() => {
47
+ setMessages((prev) => appendServerHistoryIntoMessages(prev, result.messages));
48
+ });
49
+ })().finally(() => { historyRefreshInFlightRef.current = null; });
50
+ historyRefreshInFlightRef.current = run;
51
+ return run;
52
+ }, [apiKey, apiSecret, pseudoId, externalId, nxtlinqApi, setMessages, onError]);
53
+ const voiceSessionIdRef = React.useRef(null);
54
+ const transcriptApi = React.useMemo(() => ({
55
+ getMessages,
56
+ setMessages: (messages) => setMessages(messages),
57
+ syncVoiceTurnHistory: (opts) => syncVoiceTurnHistory(opts?.last),
58
+ }), [getMessages, setMessages, syncVoiceTurnHistory]);
59
+ const { handleTranscript: handleTranscriptUi, handleDone: handleDoneUi, clearVoiceStream } = useVoiceTranscriptMessages(transcriptApi, 'voice', voiceSessionId, () => voiceSessionIdRef.current);
60
+ const resetMicAfterTurn = React.useCallback(() => {
61
+ lastCommittedUserRef.current = turnUserTextRef.current.trim();
62
+ turnUserTextRef.current = '';
63
+ activeTurnRef.current = false;
64
+ turnSettleUntilRef.current = Date.now() + TURN_SETTLE_MS;
65
+ userMicMutedRef.current = true;
66
+ userMicOptInRef.current = false;
67
+ setIsMicCaptureActive(false);
68
+ applyMicStateRef.current();
69
+ }, []);
70
+ const applyMicState = React.useCallback(() => {
71
+ const shouldMute = userMicMutedRef.current || assistantMicHoldRef.current;
72
+ sessionRef.current?.muteMic(shouldMute);
73
+ setIsMicMuted(shouldMute);
74
+ const captureActive = isVoiceMode && !shouldMute && userMicOptInRef.current;
75
+ setIsMicCaptureActive(captureActive);
76
+ }, [isVoiceMode]);
77
+ const applyMicStateRef = React.useRef(applyMicState);
78
+ applyMicStateRef.current = applyMicState;
79
+ const wsAudio = useWsRealtimeAudio(isMicCaptureActive, isVoiceMode, {
80
+ voiceStatus,
81
+ muteAfterSilenceCommit: () => {
82
+ userMicMutedRef.current = true;
83
+ userMicOptInRef.current = false;
84
+ setIsMicCaptureActive(false);
85
+ applyMicStateRef.current();
86
+ },
87
+ });
88
+ const wsAudioRef = React.useRef(wsAudio);
89
+ wsAudioRef.current = wsAudio;
90
+ const setAssistantMicHold = React.useCallback((held) => {
91
+ if (assistantMicHoldRef.current === held)
92
+ return;
93
+ assistantMicHoldRef.current = held;
94
+ applyMicState();
95
+ }, [applyMicState]);
96
+ const attachRemoteAudio = React.useCallback(() => {
97
+ if (voiceTransport === 'ws-realtime')
98
+ return false;
99
+ const session = sessionRef.current;
100
+ const audio = remoteAudioRef.current;
101
+ if (!session || !audio)
102
+ return false;
103
+ const stream = session.getRemoteAudioStream();
104
+ if (stream) {
105
+ audio.srcObject = stream;
106
+ void audio.play().catch(() => { });
107
+ return true;
108
+ }
109
+ return false;
110
+ }, [voiceTransport]);
111
+ const beginTurn = React.useCallback(() => { activeTurnRef.current = true; }, []);
112
+ const handleTranscriptTurn = React.useCallback((event) => {
113
+ if (event.role !== 'user')
114
+ return;
115
+ if (Date.now() < turnSettleUntilRef.current)
116
+ return;
117
+ if (userMicMutedRef.current)
118
+ return;
119
+ if (!userMicOptInRef.current && !activeTurnRef.current)
120
+ return;
121
+ if (assistantMicHoldRef.current || USER_TRANSCRIPT_BLOCKED.has(voiceStatusRef.current))
122
+ return;
123
+ if (!activeTurnRef.current)
124
+ beginTurn();
125
+ const merged = (event.interim === false && event.text.trim())
126
+ ? event.text.trim()
127
+ : mergeStreamingTranscript(turnUserTextRef.current, event.text);
128
+ turnUserTextRef.current = merged;
129
+ if (lastCommittedUserRef.current &&
130
+ normalizeTranscriptKey(merged) === normalizeTranscriptKey(lastCommittedUserRef.current)) {
131
+ turnUserTextRef.current = '';
132
+ return;
133
+ }
134
+ if (!event.interim && event.text.trim())
135
+ lastCommittedUserRef.current = '';
136
+ }, [beginTurn]);
137
+ const handleStatus = React.useCallback((status) => {
138
+ const prev = voiceStatusRef.current;
139
+ if (status === 'listening' && userMicMutedRef.current && !activeTurnRef.current &&
140
+ Date.now() < turnSettleUntilRef.current)
141
+ return;
142
+ voiceStatusRef.current = status;
143
+ setVoiceStatus(status);
144
+ if (ASSISTANT_MIC_HOLD_STATUSES.has(status))
145
+ setAssistantMicHold(true);
146
+ else if (status === 'listening' || status === 'idle')
147
+ setAssistantMicHold(false);
148
+ if (status === 'transcribing' && prev === 'listening')
149
+ beginTurn();
150
+ if (status === 'generating' && prev !== 'generating')
151
+ beginTurn();
152
+ if (status === 'listening' && prev === 'speaking')
153
+ resetMicAfterTurn();
154
+ }, [beginTurn, resetMicAfterTurn, setAssistantMicHold]);
155
+ const handleDone = React.useCallback((event) => {
156
+ if (event.guardrailsBlocked || event.billingBlocked) {
157
+ activeTurnRef.current = false;
158
+ return;
159
+ }
160
+ if (event.error) {
161
+ onError?.(new Error(event.error));
162
+ return;
163
+ }
164
+ handleDoneUi(event);
165
+ resetMicAfterTurn();
166
+ }, [handleDoneUi, onError, resetMicAfterTurn]);
167
+ const voiceHandlersRef = React.useRef({
168
+ onStatus: (_status) => { },
169
+ onTranscript: (_event) => { },
170
+ onDone: (_event) => { },
171
+ });
172
+ const stopVoiceSession = React.useCallback(async (reason = 'unknown') => {
173
+ const session = sessionRef.current;
174
+ if (!session && !voiceSessionIdRef.current)
175
+ return;
176
+ sessionRef.current = null;
177
+ voiceSessionIdRef.current = null;
178
+ setVoiceSessionId(null);
179
+ clearVoiceStream();
180
+ if (voiceTransport === 'ws-realtime')
181
+ wsAudioRef.current.bindSession(null);
182
+ if (session) {
183
+ try {
184
+ await session.stop();
185
+ }
186
+ catch { /* best-effort */ }
187
+ }
188
+ const audio = remoteAudioRef.current;
189
+ if (audio)
190
+ audio.srcObject = null;
191
+ voiceStatusRef.current = 'idle';
192
+ setVoiceStatus('idle');
193
+ userMicMutedRef.current = true;
194
+ userMicOptInRef.current = false;
195
+ assistantMicHoldRef.current = false;
196
+ turnSettleUntilRef.current = 0;
197
+ setIsMicMuted(true);
198
+ setIsMicCaptureActive(false);
199
+ lastCommittedUserRef.current = '';
200
+ turnUserTextRef.current = '';
201
+ activeTurnRef.current = false;
202
+ }, [clearVoiceStream, voiceTransport]);
203
+ const stopVoiceSessionRef = React.useRef(stopVoiceSession);
204
+ stopVoiceSessionRef.current = stopVoiceSession;
205
+ const exitVoiceMode = React.useCallback(async () => {
206
+ voiceConnectGenerationRef.current += 1;
207
+ setIsVoiceMode(false);
208
+ setIsVoiceConnecting(false);
209
+ await stopVoiceSession('exitVoiceMode');
210
+ }, [stopVoiceSession]);
211
+ const enterVoiceMode = React.useCallback(async () => {
212
+ if (connectInFlightRef.current || sessionRef.current)
213
+ return;
214
+ connectInFlightRef.current = true;
215
+ const connectGeneration = voiceConnectGenerationRef.current + 1;
216
+ voiceConnectGenerationRef.current = connectGeneration;
217
+ const isConnectCancelled = () => connectGeneration !== voiceConnectGenerationRef.current;
218
+ stopRecording();
219
+ stopTextToSpeech();
220
+ setIsVoiceMode(true);
221
+ setIsVoiceConnecting(true);
222
+ clearVoiceStream();
223
+ lastCommittedUserRef.current = '';
224
+ turnUserTextRef.current = '';
225
+ voiceStatusRef.current = 'idle';
226
+ setVoiceStatus('idle');
227
+ userMicMutedRef.current = true;
228
+ userMicOptInRef.current = false;
229
+ assistantMicHoldRef.current = false;
230
+ turnSettleUntilRef.current = 0;
231
+ setIsMicMuted(true);
232
+ setIsMicCaptureActive(false);
233
+ activeTurnRef.current = false;
234
+ const wsCallbacks = voiceTransport === 'ws-realtime'
235
+ ? wsAudioRef.current.buildCallbacks({
236
+ onOpen: () => {
237
+ if (isConnectCancelled())
238
+ return;
239
+ voiceStatusRef.current = 'listening';
240
+ setVoiceStatus('listening');
241
+ assistantMicHoldRef.current = false;
242
+ applyMicState();
243
+ },
244
+ onClose: () => {
245
+ if (isConnectCancelled())
246
+ return;
247
+ voiceStatusRef.current = 'idle';
248
+ setVoiceStatus('idle');
249
+ connectInFlightRef.current = false;
250
+ },
251
+ onError: (err) => {
252
+ if (isConnectCancelled())
253
+ return;
254
+ onError?.(err);
255
+ },
256
+ })
257
+ : undefined;
258
+ try {
259
+ let session;
260
+ session = await nxtlinqApi.voice.startSession({
261
+ apiKey, apiSecret, pseudoId, externalId, aitId, walletAddress, aitToken,
262
+ voiceMode: 'realtime',
263
+ transport: voiceTransport,
264
+ startWithMicMuted: true,
265
+ metadata,
266
+ onAudioDelta: wsCallbacks?.onAudioDelta,
267
+ onOpen: wsCallbacks?.onOpen ?? (() => {
268
+ if (isConnectCancelled()) {
269
+ void session?.stop();
270
+ return;
271
+ }
272
+ voiceStatusRef.current = 'listening';
273
+ setVoiceStatus('listening');
274
+ assistantMicHoldRef.current = false;
275
+ applyMicState();
276
+ const tryAttach = () => { if (!attachRemoteAudio())
277
+ window.setTimeout(tryAttach, 100); };
278
+ tryAttach();
279
+ }),
280
+ onClose: wsCallbacks?.onClose ?? (() => {
281
+ if (isConnectCancelled())
282
+ return;
283
+ voiceStatusRef.current = 'idle';
284
+ setVoiceStatus('idle');
285
+ connectInFlightRef.current = false;
286
+ }),
287
+ onStatus: (status) => voiceHandlersRef.current.onStatus(status),
288
+ onTranscript: (event) => voiceHandlersRef.current.onTranscript(event),
289
+ onDone: (event) => voiceHandlersRef.current.onDone(event),
290
+ onError: (err) => {
291
+ if (isConnectCancelled())
292
+ return;
293
+ onError?.(err);
294
+ },
295
+ });
296
+ if (isConnectCancelled()) {
297
+ await session.stop();
298
+ return;
299
+ }
300
+ voiceSessionIdRef.current = session.id;
301
+ sessionRef.current = session;
302
+ setVoiceSessionId(session.id);
303
+ if (voiceTransport === 'ws-realtime') {
304
+ wsAudioRef.current.bindSession(session, false);
305
+ }
306
+ else {
307
+ session.muteMic(true);
308
+ const tryAttach = () => { if (!attachRemoteAudio())
309
+ window.setTimeout(tryAttach, 100); };
310
+ tryAttach();
311
+ }
312
+ }
313
+ catch (err) {
314
+ if (isConnectCancelled())
315
+ return;
316
+ onError?.(err instanceof Error ? err : new Error(String(err)));
317
+ setIsVoiceMode(false);
318
+ await stopVoiceSession('enterVoiceMode_error');
319
+ }
320
+ finally {
321
+ connectInFlightRef.current = false;
322
+ if (!isConnectCancelled())
323
+ setIsVoiceConnecting(false);
324
+ }
325
+ }, [
326
+ apiKey, apiSecret, pseudoId, externalId, aitId, walletAddress, aitToken, metadata,
327
+ nxtlinqApi, stopRecording, stopTextToSpeech, attachRemoteAudio,
328
+ onError, stopVoiceSession, applyMicState, voiceTransport, clearVoiceStream,
329
+ ]);
330
+ const toggleMicMute = React.useCallback(() => {
331
+ if (!sessionRef.current)
332
+ return;
333
+ if (assistantMicHoldRef.current && userMicMutedRef.current)
334
+ return;
335
+ if (assistantMicHoldRef.current) {
336
+ userMicMutedRef.current = true;
337
+ applyMicState();
338
+ return;
339
+ }
340
+ const nextMuted = !userMicMutedRef.current;
341
+ userMicMutedRef.current = nextMuted;
342
+ userMicOptInRef.current = !nextMuted;
343
+ if (!nextMuted)
344
+ turnSettleUntilRef.current = 0;
345
+ applyMicState();
346
+ }, [applyMicState]);
347
+ const interruptVoice = React.useCallback(() => {
348
+ sessionRef.current?.interrupt();
349
+ setAssistantMicHold(false);
350
+ }, [setAssistantMicHold]);
351
+ React.useEffect(() => {
352
+ voiceHandlersRef.current = {
353
+ onStatus: handleStatus,
354
+ onTranscript: (event) => {
355
+ handleTranscriptTurn(event);
356
+ handleTranscriptUi(event);
357
+ },
358
+ onDone: handleDone,
359
+ };
360
+ }, [handleStatus, handleTranscriptTurn, handleTranscriptUi, handleDone]);
361
+ React.useEffect(() => () => { void stopVoiceSessionRef.current('unmount'); }, []);
362
+ return {
363
+ isVoiceMode,
364
+ voiceStatus,
365
+ isVoiceConnecting,
366
+ isMicMuted,
367
+ remoteAudioRef,
368
+ enterVoiceMode,
369
+ exitVoiceMode,
370
+ toggleMicMute,
371
+ interruptVoice,
372
+ };
373
+ }
@@ -0,0 +1,4 @@
1
+ import { MetaKeep } from 'metakeep';
2
+ declare const metakeepClient: MetaKeep;
3
+ export default metakeepClient;
4
+ //# sourceMappingURL=metakeepClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metakeepClient.d.ts","sourceRoot":"","sources":["../../../src/legacy/core/metakeepClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,QAAA,MAAM,cAAc,UAOlB,CAAC;AAEH,eAAe,cAAc,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { MetaKeep } from 'metakeep';
2
+ const metakeepClient = new MetaKeep({
3
+ appId: 'e7d521f7-3eea-42d7-af42-4d8b962d9a6d',
4
+ chainId: 80002,
5
+ /* RPC node urls map */
6
+ rpcNodeUrls: {
7
+ 80002: 'https://rpc-amoy.polygon.technology'
8
+ }
9
+ });
10
+ export default metakeepClient;
@@ -0,0 +1,31 @@
1
+ export interface AITMetadata {
2
+ permissions: string[];
3
+ issuedBy: string;
4
+ }
5
+ export interface CreateAITParams {
6
+ aitId: string;
7
+ controller: string;
8
+ serviceId: string;
9
+ metadataHash: string;
10
+ metadataCid: string;
11
+ isFromAIAgent?: boolean;
12
+ parentAITId?: string;
13
+ }
14
+ export declare const generateAITId: (address: string) => string;
15
+ export declare const createAITMetadata: (permissions: string[], issuedBy: string) => AITMetadata;
16
+ export declare const generateMetadataHash: (metadata: AITMetadata) => string;
17
+ export declare const prepareAITCreation: (address: string, permissions: string[], serviceId: string, isFromAIAgent?: boolean, parentAITId?: string) => {
18
+ aitId: string;
19
+ metadata: AITMetadata;
20
+ metadataHash: string;
21
+ createAITParams: {
22
+ aitId: string;
23
+ controller: string;
24
+ serviceId: string;
25
+ metadataHash: string;
26
+ metadataCid: string;
27
+ isFromAIAgent: boolean;
28
+ parentAITId: string | undefined;
29
+ };
30
+ };
31
+ //# sourceMappingURL=aitUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aitUtils.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/utils/aitUtils.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,MAG/C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,EAAE,EAAE,UAAU,MAAM,KAAG,WAK3E,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,UAAU,WAAW,KAAG,MAG5D,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,aAAa,MAAM,EAAE,EAAE,WAAW,MAAM,EAAE,uBAAqB,EAAE,cAAc,MAAM;;;;;;;;;;;;;CAmBxI,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { ethers } from 'ethers';
2
+ import stringify from 'fast-json-stable-stringify';
3
+ export const generateAITId = (address) => {
4
+ const timestamp = Math.floor(Date.now() / 1000);
5
+ return `did:polygon:nxtlinq:${address}:${timestamp}`;
6
+ };
7
+ export const createAITMetadata = (permissions, issuedBy) => {
8
+ return {
9
+ permissions,
10
+ issuedBy,
11
+ };
12
+ };
13
+ export const generateMetadataHash = (metadata) => {
14
+ const metadataStr = stringify(metadata);
15
+ return ethers.keccak256(ethers.toUtf8Bytes(metadataStr));
16
+ };
17
+ export const prepareAITCreation = (address, permissions, serviceId, isFromAIAgent = false, parentAITId) => {
18
+ const aitId = generateAITId(address);
19
+ const metadata = createAITMetadata(permissions, address);
20
+ const metadataHash = generateMetadataHash(metadata);
21
+ return {
22
+ aitId,
23
+ metadata,
24
+ metadataHash,
25
+ createAITParams: {
26
+ aitId,
27
+ controller: address,
28
+ serviceId,
29
+ metadataHash,
30
+ metadataCid: '', // Will be set after metadata upload
31
+ isFromAIAgent,
32
+ parentAITId,
33
+ }
34
+ };
35
+ };
@@ -0,0 +1,8 @@
1
+ import { ethers } from 'ethers';
2
+ /**
3
+ * Safely get ethers library instance
4
+ * Tries imported ethers first, then falls back to window.ethers
5
+ * @throws Error if ethers is not available
6
+ */
7
+ export declare const getEthers: () => typeof ethers;
8
+ //# sourceMappingURL=ethersUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ethersUtils.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/utils/ethersUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAO,OAAO,MAgBnC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { ethers } from 'ethers';
2
+ /**
3
+ * Safely get ethers library instance
4
+ * Tries imported ethers first, then falls back to window.ethers
5
+ * @throws Error if ethers is not available
6
+ */
7
+ export const getEthers = () => {
8
+ // Try to use the imported ethers first (most common case)
9
+ if (ethers && typeof ethers === 'object') {
10
+ return ethers;
11
+ }
12
+ // Fallback: try to get from global window object (in case client site provides it)
13
+ if (typeof window !== 'undefined' && window.ethers) {
14
+ return window.ethers;
15
+ }
16
+ // Provide error message
17
+ console.error('[Nxtlinq SDK] Failed to get ethers library');
18
+ throw new Error('ethers library is not properly loaded. Please ensure ethers v6 is available.');
19
+ };
@@ -0,0 +1,3 @@
1
+ export declare const sleep: (ms: number) => Promise<unknown>;
2
+ export { getEthers } from './ethersUtils';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/utils/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,qBAE/B,CAAA;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ export const sleep = (ms) => {
2
+ return new Promise(resolve => setTimeout(resolve, ms));
3
+ };
4
+ export { getEthers } from './ethersUtils';
@@ -0,0 +1,29 @@
1
+ export type NotificationType = 'success' | 'error' | 'warning' | 'info';
2
+ export interface Notification {
3
+ show: boolean;
4
+ type: NotificationType;
5
+ message: string;
6
+ autoHide?: boolean;
7
+ duration?: number;
8
+ }
9
+ export declare const createNotification: (type: NotificationType, message: string, duration?: number) => Notification;
10
+ export declare const getNotificationIcon: (type: NotificationType) => string;
11
+ export declare const getNotificationStyles: (type: NotificationType) => {
12
+ background: string;
13
+ color: string;
14
+ position: "fixed";
15
+ bottom: number;
16
+ right: number;
17
+ padding: string;
18
+ borderRadius: number;
19
+ zIndex: number;
20
+ fontWeight: number;
21
+ boxShadow: string;
22
+ transition: string;
23
+ display: string;
24
+ alignItems: string;
25
+ gap: string;
26
+ minWidth: string;
27
+ maxWidth: string;
28
+ };
29
+ //# sourceMappingURL=notificationUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notificationUtils.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/utils/notificationUtils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAExE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,GAC7B,MAAM,gBAAgB,EACtB,SAAS,MAAM,EACf,iBAAe,KACd,YAMD,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,MAAM,gBAAgB,KAAG,MAW5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,MAAM,gBAAgB;;;;;;;;;;;;;;;;;CA4B3D,CAAC"}
@@ -0,0 +1,47 @@
1
+ export const createNotification = (type, message, duration = 5000) => ({
2
+ show: true,
3
+ type,
4
+ message,
5
+ autoHide: true,
6
+ duration
7
+ });
8
+ export const getNotificationIcon = (type) => {
9
+ switch (type) {
10
+ case 'success':
11
+ return '✅';
12
+ case 'error':
13
+ return '❌';
14
+ case 'warning':
15
+ return '⚠️';
16
+ default:
17
+ return 'ℹ️';
18
+ }
19
+ };
20
+ export const getNotificationStyles = (type) => {
21
+ const baseStyles = {
22
+ position: 'fixed',
23
+ bottom: 20,
24
+ right: 20,
25
+ padding: '12px 24px',
26
+ borderRadius: 8,
27
+ zIndex: 2000,
28
+ fontWeight: 600,
29
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
30
+ transition: 'all 0.3s ease',
31
+ display: 'flex',
32
+ alignItems: 'center',
33
+ gap: '12px',
34
+ minWidth: '300px',
35
+ maxWidth: '500px'
36
+ };
37
+ switch (type) {
38
+ case 'success':
39
+ return { ...baseStyles, background: '#4caf50', color: 'white' };
40
+ case 'error':
41
+ return { ...baseStyles, background: '#f44336', color: 'white' };
42
+ case 'warning':
43
+ return { ...baseStyles, background: '#ff9800', color: 'white' };
44
+ default:
45
+ return { ...baseStyles, background: '#2196f3', color: 'white' };
46
+ }
47
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * URL utility functions for detecting and converting URLs to clickable links
3
+ */
4
+ import * as React from 'react';
5
+ /**
6
+ * Check if a string contains URLs
7
+ * @param text - The text to check
8
+ * @returns boolean indicating if URLs are found
9
+ */
10
+ export declare const containsUrls: (text: string) => boolean;
11
+ /**
12
+ * Convert text with URLs to JSX elements with clickable links
13
+ * Supports both Markdown format [text](url) and plain URLs
14
+ * Also handles line breaks (\n)
15
+ * @param text - The text containing URLs
16
+ * @returns Array of JSX elements and strings
17
+ */
18
+ export declare const convertUrlsToLinks: (text: string) => (string | React.ReactElement)[];
19
+ /**
20
+ * Simple function to wrap URLs in anchor tags for basic HTML rendering
21
+ * @param text - The text containing URLs
22
+ * @returns HTML string with clickable links
23
+ */
24
+ export declare const convertUrlsToHtml: (text: string) => string;
25
+ //# sourceMappingURL=urlUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urlUtils.d.ts","sourceRoot":"","sources":["../../../../src/legacy/core/utils/urlUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,OAE3C,CAAC;AAwBF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,CAAC,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,EA2F9E,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MAKhD,CAAC"}