@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,73 @@
1
+ import type {
2
+ Message,
3
+ NxtlinqAgentSnapshot,
4
+ PostTextTtsResult,
5
+ SendMessageOptions,
6
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
7
+ import { useCallback, useSyncExternalStore } from 'react';
8
+ import { useNxtlinqAgentContext } from '../context/NxtlinqAgentContext';
9
+
10
+ export type UseNxtlinqAgentResult = NxtlinqAgentSnapshot & {
11
+ agent: ReturnType<typeof useNxtlinqAgentContext>;
12
+ sendMessage: (
13
+ text: string,
14
+ options?: Omit<SendMessageOptions, 'text'>,
15
+ ) => Promise<void>;
16
+ loadHistory: (options?: { last?: number }) => Promise<void>;
17
+ syncVoiceTurnHistory: (options?: { last?: number }) => Promise<void>;
18
+ setMessages: (messages: Message[]) => void;
19
+ postTextTts: (text: string) => Promise<PostTextTtsResult>;
20
+ buildTextTtsPlaybackUri: (result: PostTextTtsResult) => string;
21
+ };
22
+
23
+ /** Subscribe to {@link NxtlinqAgent} state for custom Web chat UIs. */
24
+ export function useNxtlinqAgent(): UseNxtlinqAgentResult {
25
+ const agent = useNxtlinqAgentContext();
26
+ const snapshot = useSyncExternalStore(
27
+ (onStoreChange) => agent.subscribe(onStoreChange),
28
+ () => agent.getSnapshot(),
29
+ () => agent.getSnapshot(),
30
+ );
31
+
32
+ const sendMessage = useCallback(
33
+ (text: string, options?: Omit<SendMessageOptions, 'text'>) =>
34
+ agent.sendMessage(text, options),
35
+ [agent],
36
+ );
37
+
38
+ const loadHistory = useCallback(
39
+ (options?: { last?: number }) => agent.loadHistory(options),
40
+ [agent],
41
+ );
42
+
43
+ const syncVoiceTurnHistory = useCallback(
44
+ (options?: { last?: number }) => agent.syncVoiceTurnHistory(options),
45
+ [agent],
46
+ );
47
+
48
+ const setMessages = useCallback(
49
+ (messages: Message[]) => agent.setMessages(messages),
50
+ [agent],
51
+ );
52
+
53
+ const postTextTts = useCallback(
54
+ (text: string) => agent.postTextTts(text),
55
+ [agent],
56
+ );
57
+
58
+ const buildTextTtsPlaybackUri = useCallback(
59
+ (result: PostTextTtsResult) => agent.buildTextTtsPlaybackUri(result),
60
+ [agent],
61
+ );
62
+
63
+ return {
64
+ agent,
65
+ ...snapshot,
66
+ sendMessage,
67
+ loadHistory,
68
+ syncVoiceTurnHistory,
69
+ setMessages,
70
+ postTextTts,
71
+ buildTextTtsPlaybackUri,
72
+ };
73
+ }
@@ -0,0 +1,143 @@
1
+ import type {
2
+ StartVoiceSessionOptions,
3
+ VoiceGreetingOptions,
4
+ VoiceSession,
5
+ VoiceStatus,
6
+ VoiceUserInputOptions,
7
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
8
+ import { VoiceNotSupportedError } from '@bytexbyte/nxtlinq-ai-agent-core-development';
9
+ import { useCallback, useMemo, useRef, useSyncExternalStore } from 'react';
10
+ import { useNxtlinqAgentContext } from '../context/NxtlinqAgentContext';
11
+
12
+ export type UseNxtlinqVoiceOptions = Partial<
13
+ Omit<StartVoiceSessionOptions, 'apiKey' | 'apiSecret' | 'pseudoId'>
14
+ >;
15
+
16
+ export type UseNxtlinqVoiceResult = {
17
+ voiceStatus: VoiceStatus;
18
+ voiceSessionId: string | null;
19
+ isVoiceActive: boolean;
20
+ startVoice: (options?: UseNxtlinqVoiceOptions) => Promise<VoiceSession>;
21
+ stopVoice: (reason?: string) => Promise<void>;
22
+ muteMic: (muted: boolean) => void;
23
+ interrupt: () => void;
24
+ getRemoteAudioStream: () => MediaStream | null;
25
+ getOutputAudioLevel: () => number;
26
+ sendVoiceUserInput: (options: VoiceUserInputOptions) => void;
27
+ triggerVoiceGreeting: (
28
+ options: VoiceGreetingOptions,
29
+ greetOptions?: { waitForChannel?: boolean; timeoutMs?: number },
30
+ ) => Promise<void>;
31
+ };
32
+
33
+ /** Voice controls for custom Web UIs (browser WebRTC). */
34
+ export function useNxtlinqVoice(): UseNxtlinqVoiceResult {
35
+ const agent = useNxtlinqAgentContext();
36
+ const sessionRef = useRef<VoiceSession | null>(null);
37
+ const snapshot = useSyncExternalStore(
38
+ (onStoreChange) => agent.subscribe(onStoreChange),
39
+ () => agent.getSnapshot(),
40
+ () => agent.getSnapshot(),
41
+ );
42
+
43
+ const refreshSessionRef = useCallback(() => {
44
+ sessionRef.current = agent.getVoiceSession();
45
+ }, [agent]);
46
+
47
+ const startVoice = useCallback(
48
+ async (options?: UseNxtlinqVoiceOptions) => {
49
+ try {
50
+ const session = await agent.startVoice(options);
51
+ sessionRef.current = session;
52
+ return session;
53
+ } catch (err) {
54
+ if (err instanceof VoiceNotSupportedError) {
55
+ throw new Error(
56
+ 'Voice is not available — check NxtlinqAgentProvider config and pseudoId.',
57
+ );
58
+ }
59
+ throw err;
60
+ }
61
+ },
62
+ [agent],
63
+ );
64
+
65
+ const stopVoice = useCallback(
66
+ async (reason?: string) => {
67
+ await agent.stopVoice(reason);
68
+ sessionRef.current = null;
69
+ },
70
+ [agent],
71
+ );
72
+
73
+ const muteMic = useCallback(
74
+ (muted: boolean) => {
75
+ refreshSessionRef();
76
+ sessionRef.current?.muteMic(muted);
77
+ },
78
+ [refreshSessionRef],
79
+ );
80
+
81
+ const interrupt = useCallback(() => {
82
+ refreshSessionRef();
83
+ sessionRef.current?.interrupt();
84
+ }, [refreshSessionRef]);
85
+
86
+ const getRemoteAudioStream = useCallback(
87
+ () => agent.getVoiceSession()?.getRemoteAudioStream() ?? null,
88
+ [agent],
89
+ );
90
+
91
+ const getOutputAudioLevel = useCallback(() => {
92
+ refreshSessionRef();
93
+ return sessionRef.current?.getOutputAudioLevel() ?? agent.getOutputAudioLevel();
94
+ }, [refreshSessionRef, agent]);
95
+
96
+ const sendVoiceUserInput = useCallback(
97
+ (options: VoiceUserInputOptions) => {
98
+ refreshSessionRef();
99
+ if (sessionRef.current) {
100
+ sessionRef.current.sendVoiceUserInput(options);
101
+ return;
102
+ }
103
+ agent.sendVoiceUserInput(options);
104
+ },
105
+ [refreshSessionRef, agent],
106
+ );
107
+
108
+ const triggerVoiceGreeting = useCallback(
109
+ (
110
+ options: VoiceGreetingOptions,
111
+ greetOptions?: { waitForChannel?: boolean; timeoutMs?: number },
112
+ ) => agent.triggerVoiceGreeting(options, greetOptions),
113
+ [agent],
114
+ );
115
+
116
+ return useMemo(
117
+ () => ({
118
+ voiceStatus: snapshot.voiceStatus,
119
+ voiceSessionId: snapshot.voiceSessionId,
120
+ isVoiceActive: snapshot.voiceSessionId != null,
121
+ startVoice,
122
+ stopVoice,
123
+ muteMic,
124
+ interrupt,
125
+ getRemoteAudioStream,
126
+ getOutputAudioLevel,
127
+ sendVoiceUserInput,
128
+ triggerVoiceGreeting,
129
+ }),
130
+ [
131
+ snapshot.voiceStatus,
132
+ snapshot.voiceSessionId,
133
+ startVoice,
134
+ stopVoice,
135
+ muteMic,
136
+ interrupt,
137
+ getRemoteAudioStream,
138
+ getOutputAudioLevel,
139
+ sendVoiceUserInput,
140
+ triggerVoiceGreeting,
141
+ ],
142
+ );
143
+ }
package/src/index.ts ADDED
@@ -0,0 +1,84 @@
1
+ export {
2
+ createNxtlinqAgentWeb,
3
+ type CreateNxtlinqAgentWebOptions,
4
+ } from './createNxtlinqAgent';
5
+
6
+ export {
7
+ NxtlinqAgentProvider,
8
+ useNxtlinqAgentContext,
9
+ type NxtlinqAgentProviderProps,
10
+ type AgentConfig,
11
+ } from './context/NxtlinqAgentContext';
12
+
13
+ export { useNxtlinqAgent, type UseNxtlinqAgentResult } from './hooks/useNxtlinqAgent';
14
+ export {
15
+ useNxtlinqVoice,
16
+ type UseNxtlinqVoiceResult,
17
+ type UseNxtlinqVoiceOptions,
18
+ } from './hooks/useNxtlinqVoice';
19
+
20
+ export {
21
+ createWebPlatformPorts,
22
+ type CreateWebPlatformPortsOptions,
23
+ } from './ports/createWebPlatformPorts';
24
+ export { WEB_AGENT_DEFAULTS, applyWebAgentDefaults } from './webAgentDefaults';
25
+ export { fileToAttachment } from './utils/fileToAttachment';
26
+
27
+ export type {
28
+ Message,
29
+ Attachment,
30
+ AgentResponse,
31
+ SendMessageOptions,
32
+ NxtlinqAgentSnapshot,
33
+ ToolUse,
34
+ StartVoiceSessionOptions,
35
+ VoiceSession,
36
+ VoiceStatus,
37
+ VoiceTranscriptEvent,
38
+ VoiceDoneEvent,
39
+ VoiceUserInputOptions,
40
+ VoiceGreetingOptions,
41
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
42
+
43
+ export {
44
+ NxtlinqAgent,
45
+ setApiHosts,
46
+ createBrowserWebRTCPort,
47
+ createBrowserStoragePort,
48
+ createDefaultHttpPort,
49
+ VoiceNotSupportedError,
50
+ mapServerHistoryToMessages,
51
+ appendServerHistoryIntoMessages,
52
+ STORAGE_KEYS,
53
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
54
+
55
+ export {
56
+ createNxtlinqApi,
57
+ getAiAgentApiHost,
58
+ startVoiceSession,
59
+ createVoiceApi,
60
+ useDraggable,
61
+ useLocalStorage,
62
+ useSessionStorage,
63
+ useResizable,
64
+ synthesizeSpeechToBuffer,
65
+ useSpeechToTextFromMic,
66
+ useVoiceMode,
67
+ metakeepClient,
68
+ getEthers,
69
+ sleep,
70
+ walletTextUtils,
71
+ connectWallet,
72
+ disconnectWallet,
73
+ validateToken,
74
+ createAITMetadata,
75
+ generateAITId,
76
+ prepareAITCreation,
77
+ createNotification,
78
+ getNotificationIcon,
79
+ containsUrls,
80
+ convertUrlsToLinks,
81
+ convertUrlsToHtml,
82
+ } from './legacy';
83
+
84
+ export type { ResizeCorner } from './legacy';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Web SDK wrapper: default browser storage + voice API from browser module.
3
+ */
4
+ import type { AITApi } from '@bytexbyte/nxtlinq-ai-agent-core-development';
5
+ import {
6
+ createBrowserStoragePort,
7
+ createDefaultHttpPort,
8
+ createNxtlinqApiWithDeps,
9
+ getAiAgentApiHost,
10
+ setApiHosts,
11
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
12
+ import { createVoiceApi } from './voice';
13
+
14
+ export {
15
+ setApiHosts,
16
+ getAiAgentApiHost,
17
+ createNxtlinqApiWithDeps,
18
+ createBrowserStoragePort,
19
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
20
+
21
+ export type { CoreAITApi, ApiClientDeps } from '@bytexbyte/nxtlinq-ai-agent-core-development';
22
+
23
+ export const createNxtlinqApi = (apiKey: string, apiSecret: string): AITApi => {
24
+ const core = createNxtlinqApiWithDeps(apiKey, apiSecret, {
25
+ storage: createBrowserStoragePort(),
26
+ http: createDefaultHttpPort(),
27
+ });
28
+ return {
29
+ ...core,
30
+ voice: createVoiceApi(() => getAiAgentApiHost()),
31
+ };
32
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Web voice client — thin wrapper over core {@link startVoiceSessionWithPort}.
3
+ */
4
+ import {
5
+ createBrowserWebRTCPort,
6
+ startVoiceSessionWithPort,
7
+ startWsRealtimeSession,
8
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
9
+
10
+ export {
11
+ normalizeTranscriptKey,
12
+ mergeStreamingTranscript,
13
+ appendTranscriptSegment,
14
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
15
+
16
+ export type {
17
+ VoicePhase,
18
+ VoiceStatus,
19
+ VoicePhaseExtra,
20
+ VoiceTranscriptEvent,
21
+ VoiceToolCallEvent,
22
+ VoiceToolResultEvent,
23
+ VoicePermissionRequiredEvent,
24
+ VoiceBillingBlockedEvent,
25
+ VoiceTtsWordEvent,
26
+ VoiceDoneEvent,
27
+ StartVoiceSessionOptions,
28
+ VoiceSession,
29
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
30
+
31
+ import type { StartVoiceSessionOptions, VoiceSession } from '@bytexbyte/nxtlinq-ai-agent-core-development';
32
+
33
+ /**
34
+ * Start a cascade voice agent session. Browser-only (uses {@link createBrowserWebRTCPort}).
35
+ */
36
+ export async function startVoiceSession(
37
+ apiAgentHost: string,
38
+ options: StartVoiceSessionOptions,
39
+ ): Promise<VoiceSession> {
40
+ const baseUrl = (options.baseUrl ?? apiAgentHost ?? '').replace(/\/+$/, '');
41
+ if (!baseUrl) {
42
+ throw new Error(
43
+ 'startVoiceSession: API host is empty. Did you forget to call setApiHosts() before createNxtlinqApi()?',
44
+ );
45
+ }
46
+
47
+ const transport = options.transport ?? 'ws-realtime';
48
+
49
+ if (transport === 'ws-realtime') {
50
+ return startWsRealtimeSession(
51
+ { baseUrl, fetchFn: fetch },
52
+ { ...options, baseUrl, transport },
53
+ );
54
+ }
55
+
56
+ return startVoiceSessionWithPort(
57
+ {
58
+ baseUrl,
59
+ webrtc: createBrowserWebRTCPort(),
60
+ fetchFn: fetch,
61
+ },
62
+ { ...options, baseUrl },
63
+ );
64
+ }
65
+
66
+ export const createVoiceApi = (apiAgentHost: string | (() => string)) => ({
67
+ startSession: (options: StartVoiceSessionOptions): Promise<VoiceSession> =>
68
+ startVoiceSession(
69
+ typeof apiAgentHost === 'function' ? apiAgentHost() : apiAgentHost,
70
+ options,
71
+ ),
72
+ });
@@ -0,0 +1,6 @@
1
+ export {
2
+ appendServerHistoryIntoMessages,
3
+ isVoicePlaceholderMessage,
4
+ mapServerHistoryToMessages,
5
+ type ServerHistoryMessage,
6
+ } from '@bytexbyte/nxtlinq-ai-agent-core-development';
@@ -0,0 +1,127 @@
1
+ import { SpeechConfig, SpeechSynthesisResult, SpeechSynthesizer } from 'microsoft-cognitiveservices-speech-sdk';
2
+ import { getAiAgentApiHost } from '../../api/nxtlinq-api';
3
+ import type { ClientTtsVoiceSettings } from '@bytexbyte/nxtlinq-ai-agent-core-development';
4
+
5
+ const DEFAULT_AZURE_VOICE = 'en-US-JennyNeural';
6
+
7
+ async function fetchAzureTokenFromAgent(
8
+ agentHost: string,
9
+ apiKey: string,
10
+ apiSecret: string,
11
+ ): Promise<{ token: string; region: string } | { error: string }> {
12
+ try {
13
+ const res = await fetch(`${agentHost}/api/cognitive/token`, {
14
+ method: 'GET',
15
+ headers: {
16
+ 'X-API-Key': apiKey,
17
+ 'X-API-Secret': apiSecret,
18
+ },
19
+ });
20
+ const data = (await res.json()) as { token?: string; region?: string; error?: string };
21
+ if (!res.ok || !data.token || !data.region) {
22
+ return { error: data.error || 'Failed to get speech token' };
23
+ }
24
+ return { token: data.token, region: data.region };
25
+ } catch (e) {
26
+ return { error: e instanceof Error ? e.message : 'Network error' };
27
+ }
28
+ }
29
+
30
+ async function synthesizeAzureToBuffer(
31
+ text: string,
32
+ authToken: string,
33
+ region: string,
34
+ voiceName?: string,
35
+ ): Promise<ArrayBuffer | undefined> {
36
+ const speechConfig = SpeechConfig.fromAuthorizationToken(authToken, region) as SpeechConfig;
37
+ speechConfig.speechSynthesisVoiceName =
38
+ voiceName?.trim() ? voiceName.trim() : DEFAULT_AZURE_VOICE;
39
+
40
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
41
+ // @ts-ignore — SDK typing allows null audio config
42
+ const synthesizer = new SpeechSynthesizer(speechConfig, null);
43
+
44
+ const res = await new Promise<SpeechSynthesisResult | string>((resolve) => {
45
+ synthesizer.speakTextAsync(
46
+ text,
47
+ (result) => {
48
+ resolve(result);
49
+ },
50
+ (err) => resolve(err),
51
+ );
52
+ });
53
+
54
+ synthesizer.close();
55
+
56
+ if (typeof res === 'string') {
57
+ console.error('Text-to-speech error:', res);
58
+ return undefined;
59
+ }
60
+
61
+ return res.audioData;
62
+ }
63
+
64
+ async function synthesizeOpenAiToBuffer(
65
+ agentHost: string,
66
+ apiKey: string,
67
+ apiSecret: string,
68
+ text: string,
69
+ ): Promise<ArrayBuffer | undefined> {
70
+ const res = await fetch(`${agentHost}/api/tts/openai`, {
71
+ method: 'POST',
72
+ headers: { 'Content-Type': 'application/json' },
73
+ body: JSON.stringify({ apiKey, apiSecret, text }),
74
+ });
75
+ if (!res.ok) {
76
+ return undefined;
77
+ }
78
+ return res.arrayBuffer();
79
+ }
80
+
81
+ /**
82
+ * TTS for chat playback: Azure (browser Speech SDK + token from Agent) or OpenAI (audio via Agent proxy).
83
+ */
84
+ export async function synthesizeSpeechToBuffer(params: {
85
+ text: string;
86
+ apiKey: string;
87
+ apiSecret: string;
88
+ settings?: ClientTtsVoiceSettings;
89
+ }): Promise<{ buffer: ArrayBuffer; mimeType: string } | undefined> {
90
+ const agentHost = getAiAgentApiHost();
91
+ if (!agentHost) {
92
+ console.error('AI Agent API host is not set (call setApiHosts first)');
93
+ return undefined;
94
+ }
95
+
96
+ const provider = params.settings?.provider ?? 'azure';
97
+ const resolvedVoice = params.settings?.resolvedVoice?.trim();
98
+
99
+ if (provider === 'openai' && resolvedVoice) {
100
+ const buffer = await synthesizeOpenAiToBuffer(
101
+ agentHost,
102
+ params.apiKey,
103
+ params.apiSecret,
104
+ params.text,
105
+ );
106
+ if (!buffer) {
107
+ console.warn('OpenAI TTS failed, falling back to Azure');
108
+ } else {
109
+ return { buffer, mimeType: 'audio/mpeg' };
110
+ }
111
+ }
112
+
113
+ const tok = await fetchAzureTokenFromAgent(agentHost, params.apiKey, params.apiSecret);
114
+ if ('error' in tok) {
115
+ console.error('Azure speech token:', tok.error);
116
+ return undefined;
117
+ }
118
+
119
+ const buffer = await synthesizeAzureToBuffer(
120
+ params.text,
121
+ tok.token,
122
+ tok.region,
123
+ provider === 'azure' ? resolvedVoice : undefined,
124
+ );
125
+ if (!buffer) return undefined;
126
+ return { buffer, mimeType: 'audio/wav' };
127
+ }