@bytexbyte/nxtlinq-ai-agent-ui-react-development 0.4.0 → 0.4.2

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 (146) hide show
  1. package/dist/context/ChatBotContext.d.ts.map +1 -1
  2. package/dist/context/ChatBotContext.js +84 -405
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/permissionState.d.ts +53 -0
  7. package/dist/permissionState.d.ts.map +1 -0
  8. package/dist/permissionState.js +217 -0
  9. package/dist/types/ChatBotTypes.d.ts +0 -5
  10. package/dist/types/ChatBotTypes.d.ts.map +1 -1
  11. package/dist/ui/ChatBotHeader.d.ts.map +1 -1
  12. package/dist/ui/ChatBotHeader.js +6 -2
  13. package/dist/ui/ChatBotUI.d.ts.map +1 -1
  14. package/dist/ui/ChatBotUI.js +13 -4
  15. package/dist/ui/MessageList.d.ts.map +1 -1
  16. package/dist/ui/MessageList.js +11 -6
  17. package/dist/ui/PermissionForm.d.ts.map +1 -1
  18. package/dist/ui/PermissionForm.js +6 -9
  19. package/dist/ui/styles/isolatedStyles.d.ts.map +1 -1
  20. package/dist/ui/styles/isolatedStyles.js +1 -0
  21. package/package.json +3 -3
  22. package/src/context/ChatBotContext.tsx +92 -437
  23. package/src/index.ts +5 -0
  24. package/src/types/ChatBotTypes.ts +2 -6
  25. package/src/ui/ChatBotHeader.tsx +9 -3
  26. package/src/ui/ChatBotUI.tsx +14 -5
  27. package/src/ui/MessageList.tsx +6 -0
  28. package/src/ui/PermissionForm.tsx +7 -12
  29. package/src/ui/styles/isolatedStyles.ts +1 -0
  30. package/dist/NxtlinqAgentChat.d.ts +0 -26
  31. package/dist/NxtlinqAgentChat.d.ts.map +0 -1
  32. package/dist/NxtlinqAgentChat.js +0 -28
  33. package/dist/components/AgentAssistantShell.d.ts +0 -5
  34. package/dist/components/AgentAssistantShell.d.ts.map +0 -1
  35. package/dist/components/AgentAssistantShell.js +0 -52
  36. package/dist/components/AgentComposer.d.ts +0 -3
  37. package/dist/components/AgentComposer.d.ts.map +0 -1
  38. package/dist/components/AgentComposer.js +0 -60
  39. package/dist/components/AgentMessageList.d.ts +0 -3
  40. package/dist/components/AgentMessageList.d.ts.map +0 -1
  41. package/dist/components/AgentMessageList.js +0 -37
  42. package/dist/components/AgentRemoteAudio.d.ts +0 -4
  43. package/dist/components/AgentRemoteAudio.d.ts.map +0 -1
  44. package/dist/components/AgentRemoteAudio.js +0 -34
  45. package/dist/components/AgentVoiceBar.d.ts +0 -3
  46. package/dist/components/AgentVoiceBar.d.ts.map +0 -1
  47. package/dist/components/AgentVoiceBar.js +0 -91
  48. package/dist/components/PresetMessageChips.d.ts +0 -3
  49. package/dist/components/PresetMessageChips.d.ts.map +0 -1
  50. package/dist/components/PresetMessageChips.js +0 -23
  51. package/dist/context/AgentAssistantContext.d.ts +0 -32
  52. package/dist/context/AgentAssistantContext.d.ts.map +0 -1
  53. package/dist/context/AgentAssistantContext.js +0 -179
  54. package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts +0 -2
  55. package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts.map +0 -1
  56. package/dist/legacy/assets/images/adiSideItalicDataUri.js +0 -1
  57. package/dist/legacy/chatbot/ChatBot.d.ts +0 -5
  58. package/dist/legacy/chatbot/ChatBot.d.ts.map +0 -1
  59. package/dist/legacy/chatbot/ChatBot.js +0 -35
  60. package/dist/legacy/chatbot/context/ChatBotContext.d.ts +0 -5
  61. package/dist/legacy/chatbot/context/ChatBotContext.d.ts.map +0 -1
  62. package/dist/legacy/chatbot/context/ChatBotContext.js +0 -2922
  63. package/dist/legacy/chatbot/types/ChatBotTypes.d.ts +0 -166
  64. package/dist/legacy/chatbot/types/ChatBotTypes.d.ts.map +0 -1
  65. package/dist/legacy/chatbot/types/ChatBotTypes.js +0 -1
  66. package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts +0 -17
  67. package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts.map +0 -1
  68. package/dist/legacy/chatbot/ui/BerifyMeModal.js +0 -110
  69. package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts +0 -15
  70. package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts.map +0 -1
  71. package/dist/legacy/chatbot/ui/ChatBotHeader.js +0 -62
  72. package/dist/legacy/chatbot/ui/ChatBotUI.d.ts +0 -3
  73. package/dist/legacy/chatbot/ui/ChatBotUI.d.ts.map +0 -1
  74. package/dist/legacy/chatbot/ui/ChatBotUI.js +0 -557
  75. package/dist/legacy/chatbot/ui/MessageInput.d.ts +0 -3
  76. package/dist/legacy/chatbot/ui/MessageInput.d.ts.map +0 -1
  77. package/dist/legacy/chatbot/ui/MessageInput.js +0 -321
  78. package/dist/legacy/chatbot/ui/MessageList.d.ts +0 -4
  79. package/dist/legacy/chatbot/ui/MessageList.d.ts.map +0 -1
  80. package/dist/legacy/chatbot/ui/MessageList.js +0 -455
  81. package/dist/legacy/chatbot/ui/ModelSelector.d.ts +0 -4
  82. package/dist/legacy/chatbot/ui/ModelSelector.d.ts.map +0 -1
  83. package/dist/legacy/chatbot/ui/ModelSelector.js +0 -122
  84. package/dist/legacy/chatbot/ui/NotificationModal.d.ts +0 -15
  85. package/dist/legacy/chatbot/ui/NotificationModal.d.ts.map +0 -1
  86. package/dist/legacy/chatbot/ui/NotificationModal.js +0 -53
  87. package/dist/legacy/chatbot/ui/PermissionForm.d.ts +0 -8
  88. package/dist/legacy/chatbot/ui/PermissionForm.d.ts.map +0 -1
  89. package/dist/legacy/chatbot/ui/PermissionForm.js +0 -465
  90. package/dist/legacy/chatbot/ui/PresetMessages.d.ts +0 -4
  91. package/dist/legacy/chatbot/ui/PresetMessages.d.ts.map +0 -1
  92. package/dist/legacy/chatbot/ui/PresetMessages.js +0 -33
  93. package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts +0 -3
  94. package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts.map +0 -1
  95. package/dist/legacy/chatbot/ui/VoiceModePanel.js +0 -95
  96. package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts +0 -15
  97. package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts.map +0 -1
  98. package/dist/legacy/chatbot/ui/chatBotHeaderParts.js +0 -50
  99. package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts +0 -73
  100. package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts.map +0 -1
  101. package/dist/legacy/chatbot/ui/styles/isolatedStyles.js +0 -985
  102. package/dist/legacy/index.d.ts +0 -14
  103. package/dist/legacy/index.d.ts.map +0 -1
  104. package/dist/legacy/index.js +0 -12
  105. package/dist/theme/defaultTheme.d.ts +0 -3
  106. package/dist/theme/defaultTheme.d.ts.map +0 -1
  107. package/dist/theme/defaultTheme.js +0 -20
  108. package/dist/types.d.ts +0 -62
  109. package/dist/types.d.ts.map +0 -1
  110. package/dist/types.js +0 -1
  111. package/dist/voice/useVoiceConnectOrchestration.d.ts +0 -21
  112. package/dist/voice/useVoiceConnectOrchestration.d.ts.map +0 -1
  113. package/dist/voice/useVoiceConnectOrchestration.js +0 -86
  114. package/dist/voice/useVoiceMicState.d.ts +0 -15
  115. package/dist/voice/useVoiceMicState.d.ts.map +0 -1
  116. package/dist/voice/useVoiceMicState.js +0 -94
  117. package/dist/voice/useVoiceSilenceCommit.d.ts +0 -10
  118. package/dist/voice/useVoiceSilenceCommit.d.ts.map +0 -1
  119. package/dist/voice/useVoiceSilenceCommit.js +0 -67
  120. package/dist/voice/useVoiceTranscriptMessages.d.ts +0 -18
  121. package/dist/voice/useVoiceTranscriptMessages.d.ts.map +0 -1
  122. package/dist/voice/useVoiceTranscriptMessages.js +0 -132
  123. package/dist/voice/useWsRealtimeAudio.d.ts +0 -18
  124. package/dist/voice/useWsRealtimeAudio.d.ts.map +0 -1
  125. package/dist/voice/useWsRealtimeAudio.js +0 -102
  126. package/dist/voice/voiceMicConstants.d.ts +0 -4
  127. package/dist/voice/voiceMicConstants.d.ts.map +0 -1
  128. package/dist/voice/voiceMicConstants.js +0 -10
  129. package/dist/voice/voiceUserBubble.d.ts +0 -10
  130. package/dist/voice/voiceUserBubble.d.ts.map +0 -1
  131. package/dist/voice/voiceUserBubble.js +0 -52
  132. package/dist/voice/ws/BrowserWsPcmPlayer.d.ts +0 -23
  133. package/dist/voice/ws/BrowserWsPcmPlayer.d.ts.map +0 -1
  134. package/dist/voice/ws/BrowserWsPcmPlayer.js +0 -137
  135. package/dist/voice/ws/BrowserWsPcmRecorder.d.ts +0 -17
  136. package/dist/voice/ws/BrowserWsPcmRecorder.d.ts.map +0 -1
  137. package/dist/voice/ws/BrowserWsPcmRecorder.js +0 -71
  138. package/dist/voice/ws/float32ToPcm16.d.ts +0 -2
  139. package/dist/voice/ws/float32ToPcm16.d.ts.map +0 -1
  140. package/dist/voice/ws/float32ToPcm16.js +0 -8
  141. package/dist/voice/ws/voiceSilenceConstants.d.ts +0 -5
  142. package/dist/voice/ws/voiceSilenceConstants.d.ts.map +0 -1
  143. package/dist/voice/ws/voiceSilenceConstants.js +0 -4
  144. package/dist/voice/ws/wsRealtimeConstants.d.ts +0 -2
  145. package/dist/voice/ws/wsRealtimeConstants.d.ts.map +0 -1
  146. package/dist/voice/ws/wsRealtimeConstants.js +0 -1
@@ -1,102 +0,0 @@
1
- import { useCallback, useEffect, useRef } from 'react';
2
- import { BrowserWsPcmPlayer } from './ws/BrowserWsPcmPlayer';
3
- import { BrowserWsPcmRecorder } from './ws/BrowserWsPcmRecorder';
4
- import { useVoiceSilenceCommit } from './useVoiceSilenceCommit';
5
- export function useWsRealtimeAudio(isCaptureActive, isVoiceActive, options) {
6
- const playerRef = useRef(null);
7
- const recorderRef = useRef(null);
8
- const sessionRef = useRef(null);
9
- const isCaptureActiveRef = useRef(isCaptureActive);
10
- isCaptureActiveRef.current = isCaptureActive;
11
- const prevCaptureActiveRef = useRef(isCaptureActive);
12
- const getSession = useCallback(() => sessionRef.current, []);
13
- const muteAfterSilenceCommitRef = useRef(options.muteAfterSilenceCommit);
14
- muteAfterSilenceCommitRef.current = options.muteAfterSilenceCommit;
15
- const silence = useVoiceSilenceCommit(getSession, () => muteAfterSilenceCommitRef.current(), options.voiceStatus);
16
- const silenceRef = useRef(silence);
17
- silenceRef.current = silence;
18
- const ensurePlayer = useCallback(async () => {
19
- if (!playerRef.current) {
20
- playerRef.current = new BrowserWsPcmPlayer();
21
- playerRef.current.prewarm();
22
- }
23
- await playerRef.current.ensureRunning();
24
- }, []);
25
- const stopCapture = useCallback((commit) => {
26
- const s = silenceRef.current;
27
- s.clearPoll();
28
- recorderRef.current?.stop();
29
- if (!commit)
30
- return;
31
- if (s.consumeSkipCommitOnMute())
32
- return;
33
- s.tryCommit('manual');
34
- }, []);
35
- const startCapture = useCallback(async () => {
36
- const session = sessionRef.current;
37
- if (!session)
38
- return;
39
- const s = silenceRef.current;
40
- if (!recorderRef.current)
41
- recorderRef.current = new BrowserWsPcmRecorder();
42
- playerRef.current?.clearQueue();
43
- recorderRef.current.bindSession(session);
44
- recorderRef.current.setOnRms(s.onSpeechRms);
45
- s.resetTurn();
46
- try {
47
- await recorderRef.current.start();
48
- s.startPoll();
49
- }
50
- catch (err) {
51
- s.clearPoll();
52
- console.error('[nxtlinq] mic capture start failed', err);
53
- }
54
- }, []);
55
- const cleanup = useCallback(() => {
56
- silenceRef.current.clearPoll();
57
- recorderRef.current?.cleanup();
58
- recorderRef.current = null;
59
- playerRef.current?.cleanup();
60
- playerRef.current = null;
61
- sessionRef.current = null;
62
- }, []);
63
- const bindSession = useCallback((session, captureWhenUnmuted = false) => {
64
- sessionRef.current = session;
65
- recorderRef.current?.bindSession(session);
66
- if (session && captureWhenUnmuted && isCaptureActiveRef.current) {
67
- void startCapture();
68
- }
69
- }, [startCapture]);
70
- const buildCallbacks = useCallback((overrides) => ({
71
- onOpen: () => {
72
- void ensurePlayer();
73
- overrides?.onOpen?.();
74
- },
75
- onAudioDelta: (pcm16) => {
76
- void ensurePlayer().then(() => playerRef.current?.addAudio(pcm16));
77
- overrides?.onAudioDelta?.(pcm16);
78
- },
79
- onClose: (reason) => {
80
- cleanup();
81
- overrides?.onClose?.(reason);
82
- },
83
- onError: (err) => {
84
- cleanup();
85
- overrides?.onError?.(err);
86
- },
87
- }), [cleanup, ensurePlayer]);
88
- useEffect(() => {
89
- if (!isVoiceActive) {
90
- prevCaptureActiveRef.current = false;
91
- cleanup();
92
- return;
93
- }
94
- const prev = prevCaptureActiveRef.current;
95
- prevCaptureActiveRef.current = isCaptureActive;
96
- if (isCaptureActive && !prev)
97
- void startCapture();
98
- else if (!isCaptureActive && prev)
99
- stopCapture(true);
100
- }, [isCaptureActive, isVoiceActive, startCapture, stopCapture, cleanup]);
101
- return { bindSession, buildCallbacks, getOutputAudioLevel: () => playerRef.current?.getAudioLevel() ?? 0 };
102
- }
@@ -1,4 +0,0 @@
1
- import type { VoiceStatus } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
- export declare const ASSISTANT_MIC_HOLD_STATUSES: ReadonlySet<VoiceStatus>;
3
- export declare const SPEAKER_ACTIVE_STATUSES: ReadonlySet<VoiceStatus>;
4
- //# sourceMappingURL=voiceMicConstants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"voiceMicConstants.d.ts","sourceRoot":"","sources":["../../src/voice/voiceMicConstants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8CAA8C,CAAC;AAEhF,eAAO,MAAM,2BAA2B,EAAE,WAAW,CAAC,WAAW,CAK/D,CAAC;AAEH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,WAAW,CAG3D,CAAC"}
@@ -1,10 +0,0 @@
1
- export const ASSISTANT_MIC_HOLD_STATUSES = new Set([
2
- 'transcribing',
3
- 'thinking',
4
- 'generating',
5
- 'speaking',
6
- ]);
7
- export const SPEAKER_ACTIVE_STATUSES = new Set([
8
- 'generating',
9
- 'speaking',
10
- ]);
@@ -1,10 +0,0 @@
1
- import type { Message } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
- export declare const VOICE_USER_INPUT_PLACEHOLDER = "(Voice input)";
3
- type VoiceMeta = {
4
- voiceRealtime: true;
5
- voiceSessionId?: string;
6
- };
7
- /** Ensure a user bubble exists before the in-flight assistant reply for this turn. */
8
- export declare function ensureUserBubbleForVoiceTurn(messages: Message[], userText: string, userMessageId: string | null | undefined, metaForPlaceholder: VoiceMeta | undefined): Message[];
9
- export {};
10
- //# sourceMappingURL=voiceUserBubble.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"voiceUserBubble.d.ts","sourceRoot":"","sources":["../../src/voice/voiceUserBubble.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8CAA8C,CAAC;AAE5E,eAAO,MAAM,4BAA4B,kBAAkB,CAAC;AAE5D,KAAK,SAAS,GAAG;IACf,aAAa,EAAE,IAAI,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,sFAAsF;AACtF,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,kBAAkB,EAAE,SAAS,GAAG,SAAS,GACxC,OAAO,EAAE,CAuDX"}
@@ -1,52 +0,0 @@
1
- export const VOICE_USER_INPUT_PLACEHOLDER = '(Voice input)';
2
- /** Ensure a user bubble exists before the in-flight assistant reply for this turn. */
3
- export function ensureUserBubbleForVoiceTurn(messages, userText, userMessageId, metaForPlaceholder) {
4
- const streamIdx = messages.findIndex((m) => m.isStreaming && m.role === 'assistant');
5
- const insertAt = streamIdx >= 0 ? streamIdx : messages.length;
6
- const before = messages.slice(0, insertAt);
7
- const lastAsstIdx = (() => {
8
- for (let i = before.length - 1; i >= 0; i -= 1) {
9
- const m = before[i];
10
- if (m.role === 'assistant' && !m.isStreaming && Boolean(m.content?.trim()))
11
- return i;
12
- }
13
- return -1;
14
- })();
15
- const lastUserIdx = (() => {
16
- for (let i = before.length - 1; i >= 0; i -= 1) {
17
- if (before[i].role === 'user')
18
- return i;
19
- }
20
- return -1;
21
- })();
22
- const hasUserForTurn = lastUserIdx >= 0 && lastUserIdx > lastAsstIdx;
23
- const trimmed = userText.trim();
24
- const displayText = trimmed || VOICE_USER_INPUT_PLACEHOLDER;
25
- if (hasUserForTurn) {
26
- const existing = before[lastUserIdx];
27
- const shouldUpgrade = trimmed &&
28
- existing.content !== trimmed &&
29
- (existing.content === VOICE_USER_INPUT_PLACEHOLDER || !existing.content.trim());
30
- if (!shouldUpgrade)
31
- return messages;
32
- const upgraded = before.map((m, i) => i === lastUserIdx
33
- ? {
34
- ...m,
35
- content: trimmed,
36
- id: userMessageId ?? m.id,
37
- metadata: userMessageId ? undefined : m.metadata,
38
- }
39
- : m);
40
- return [...upgraded, ...messages.slice(insertAt)];
41
- }
42
- const userMsg = {
43
- id: userMessageId ?? `voice-user-${Date.now()}`,
44
- role: 'user',
45
- content: displayText,
46
- timestamp: new Date().toISOString(),
47
- metadata: userMessageId ? undefined : metaForPlaceholder,
48
- };
49
- const next = [...messages];
50
- next.splice(insertAt, 0, userMsg);
51
- return next;
52
- }
@@ -1,23 +0,0 @@
1
- export declare class BrowserWsPcmPlayer {
2
- private readonly sampleRate;
3
- private readonly fadeSamples;
4
- private audioContext;
5
- private gainNode;
6
- private analyserNode;
7
- private analyserBuffer;
8
- private readonly activeSources;
9
- private queue;
10
- private isPlaying;
11
- private playHead;
12
- private lastChunkRms;
13
- private lastChunkAt;
14
- ensureRunning(): Promise<void>;
15
- prewarm(): void;
16
- addAudio(pcm16: Int16Array | ArrayBuffer): void;
17
- getAudioLevel(): number;
18
- clearQueue(): void;
19
- cleanup(): void;
20
- private ensureContext;
21
- private pipelineQueue;
22
- }
23
- //# sourceMappingURL=BrowserWsPcmPlayer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BrowserWsPcmPlayer.d.ts","sourceRoot":"","sources":["../../../src/voice/ws/BrowserWsPcmPlayer.ts"],"names":[],"mappings":"AAeA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IACtD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmD;IAC/E,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoC;IAClE,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAK;IAElB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAMpC,OAAO,IAAI,IAAI;IAIf,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI;IAqB/C,aAAa,IAAI,MAAM;IAevB,UAAU,IAAI,IAAI;IAWlB,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,aAAa;CA2BtB"}
@@ -1,137 +0,0 @@
1
- import { WS_REALTIME_SAMPLE_RATE } from './wsRealtimeConstants';
2
- const LEVEL_SCALE = 3.2;
3
- const LOOKAHEAD_SECONDS = 0.02;
4
- const CROSSFADE_SECONDS = 0.04;
5
- function applyFade(buffer, fadeSamples) {
6
- const fade = Math.min(fadeSamples, Math.floor(buffer.length / 2));
7
- if (fade <= 0)
8
- return;
9
- for (let i = 0; i < fade; i += 1) {
10
- buffer[i] *= i / fade;
11
- buffer[buffer.length - 1 - i] *= (fade - i) / fade;
12
- }
13
- }
14
- export class BrowserWsPcmPlayer {
15
- constructor() {
16
- this.sampleRate = WS_REALTIME_SAMPLE_RATE;
17
- this.fadeSamples = Math.max(1, Math.floor(this.sampleRate * 0.01));
18
- this.audioContext = null;
19
- this.gainNode = null;
20
- this.analyserNode = null;
21
- this.analyserBuffer = null;
22
- this.activeSources = new Set();
23
- this.queue = [];
24
- this.isPlaying = true;
25
- this.playHead = 0;
26
- this.lastChunkRms = 0;
27
- this.lastChunkAt = 0;
28
- }
29
- async ensureRunning() {
30
- const ctx = this.ensureContext();
31
- if (ctx.state === 'suspended')
32
- await ctx.resume();
33
- this.isPlaying = true;
34
- }
35
- prewarm() {
36
- this.ensureContext();
37
- }
38
- addAudio(pcm16) {
39
- const ctx = this.ensureContext();
40
- const int16 = pcm16 instanceof ArrayBuffer ? new Int16Array(pcm16) : pcm16;
41
- if (int16.length === 0)
42
- return;
43
- const floats = new Float32Array(int16.length);
44
- let sumSq = 0;
45
- for (let i = 0; i < int16.length; i += 1) {
46
- const sample = int16[i] / 32768;
47
- floats[i] = Math.max(-1, Math.min(1, sample));
48
- sumSq += sample * sample;
49
- }
50
- applyFade(floats, this.fadeSamples);
51
- this.lastChunkRms = Math.min(1, Math.sqrt(sumSq / int16.length) * LEVEL_SCALE);
52
- this.lastChunkAt = Date.now();
53
- const buffer = ctx.createBuffer(1, floats.length, this.sampleRate);
54
- buffer.getChannelData(0).set(floats);
55
- this.queue.push(buffer);
56
- this.isPlaying = true;
57
- this.pipelineQueue();
58
- }
59
- getAudioLevel() {
60
- const analyser = this.analyserNode;
61
- const buf = this.analyserBuffer;
62
- if (analyser && buf && this.activeSources.size > 0) {
63
- analyser.getFloatTimeDomainData(buf);
64
- let sumSq = 0;
65
- for (let i = 0; i < buf.length; i += 1) {
66
- const v = buf[i];
67
- sumSq += v * v;
68
- }
69
- return Math.min(1, Math.sqrt(sumSq / buf.length) * LEVEL_SCALE);
70
- }
71
- return Date.now() - this.lastChunkAt < 500 ? this.lastChunkRms : 0;
72
- }
73
- clearQueue() {
74
- for (const source of this.activeSources) {
75
- try {
76
- source.stop();
77
- }
78
- catch { /* noop */ }
79
- }
80
- this.activeSources.clear();
81
- this.queue = [];
82
- this.playHead = this.audioContext?.currentTime ?? 0;
83
- this.lastChunkRms = 0;
84
- this.lastChunkAt = 0;
85
- }
86
- cleanup() {
87
- this.clearQueue();
88
- this.isPlaying = false;
89
- void this.audioContext?.close();
90
- this.analyserNode = null;
91
- this.analyserBuffer = null;
92
- this.gainNode = null;
93
- this.audioContext = null;
94
- }
95
- ensureContext() {
96
- if (!this.audioContext) {
97
- this.audioContext = new AudioContext({ sampleRate: this.sampleRate });
98
- this.gainNode = this.audioContext.createGain();
99
- this.analyserNode = this.audioContext.createAnalyser();
100
- this.analyserNode.fftSize = 512;
101
- this.analyserBuffer = new Float32Array(this.analyserNode.fftSize);
102
- this.gainNode.connect(this.analyserNode);
103
- this.analyserNode.connect(this.audioContext.destination);
104
- this.playHead = this.audioContext.currentTime;
105
- }
106
- return this.audioContext;
107
- }
108
- pipelineQueue() {
109
- const ctx = this.audioContext;
110
- const gain = this.gainNode;
111
- if (!ctx || !gain || !this.isPlaying)
112
- return;
113
- while (this.queue.length > 0) {
114
- const audioBuffer = this.queue.shift();
115
- if (!audioBuffer)
116
- return;
117
- const source = ctx.createBufferSource();
118
- source.buffer = audioBuffer;
119
- const perSourceGain = ctx.createGain();
120
- source.connect(perSourceGain);
121
- perSourceGain.connect(gain);
122
- const now = ctx.currentTime;
123
- const startAt = Math.max((this.playHead || now) - CROSSFADE_SECONDS * 0.75, now + LOOKAHEAD_SECONDS);
124
- const duration = audioBuffer.duration;
125
- const endAt = startAt + duration;
126
- const fade = Math.min(CROSSFADE_SECONDS, duration / 2);
127
- perSourceGain.gain.setValueAtTime(0, startAt);
128
- perSourceGain.gain.linearRampToValueAtTime(1, startAt + fade);
129
- perSourceGain.gain.setValueAtTime(1, endAt - fade);
130
- perSourceGain.gain.linearRampToValueAtTime(0, endAt);
131
- this.playHead = endAt;
132
- this.activeSources.add(source);
133
- source.start(startAt);
134
- source.onended = () => this.activeSources.delete(source);
135
- }
136
- }
137
- }
@@ -1,17 +0,0 @@
1
- import type { VoiceSession } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
- /** getUserMedia only on start() — Berify hold-to-talk aligned. */
3
- export declare class BrowserWsPcmRecorder {
4
- private session;
5
- private onRms?;
6
- private stream;
7
- private audioContext;
8
- private processor;
9
- private source;
10
- private silentGain;
11
- bindSession(session: VoiceSession | null): void;
12
- setOnRms(handler: (rms: number) => void): void;
13
- start(): Promise<void>;
14
- stop(): void;
15
- cleanup(): void;
16
- }
17
- //# sourceMappingURL=BrowserWsPcmRecorder.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BrowserWsPcmRecorder.d.ts","sourceRoot":"","sources":["../../../src/voice/ws/BrowserWsPcmRecorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAajF,kEAAkE;AAClE,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,KAAK,CAAC,CAAwB;IACtC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,MAAM,CAA2C;IACzD,OAAO,CAAC,UAAU,CAAyB;IAE3C,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI;IAI/C,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB5B,IAAI,IAAI,IAAI;IAgBZ,OAAO,IAAI,IAAI;CAIhB"}
@@ -1,71 +0,0 @@
1
- import { float32ToPcm16 } from './float32ToPcm16';
2
- import { WS_REALTIME_SAMPLE_RATE } from './wsRealtimeConstants';
3
- function computeRms(channel) {
4
- let sum = 0;
5
- for (let i = 0; i < channel.length; i += 1) {
6
- const v = channel[i];
7
- sum += v * v;
8
- }
9
- return channel.length > 0 ? Math.sqrt(sum / channel.length) : 0;
10
- }
11
- /** getUserMedia only on start() — Berify hold-to-talk aligned. */
12
- export class BrowserWsPcmRecorder {
13
- constructor() {
14
- this.session = null;
15
- this.stream = null;
16
- this.audioContext = null;
17
- this.processor = null;
18
- this.source = null;
19
- this.silentGain = null;
20
- }
21
- bindSession(session) {
22
- this.session = session;
23
- }
24
- setOnRms(handler) {
25
- this.onRms = handler;
26
- }
27
- async start() {
28
- if (this.processor)
29
- return;
30
- this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
31
- const ctx = new AudioContext({ sampleRate: WS_REALTIME_SAMPLE_RATE });
32
- this.audioContext = ctx;
33
- this.source = ctx.createMediaStreamSource(this.stream);
34
- this.processor = ctx.createScriptProcessor(4096, 1, 1);
35
- this.silentGain = ctx.createGain();
36
- this.silentGain.gain.value = 0;
37
- this.source.connect(this.processor);
38
- this.processor.connect(this.silentGain);
39
- this.silentGain.connect(ctx.destination);
40
- this.processor.onaudioprocess = (event) => {
41
- if (!this.session?.appendInputAudio)
42
- return;
43
- const channel = event.inputBuffer.getChannelData(0);
44
- const rms = computeRms(channel);
45
- this.onRms?.(rms);
46
- this.session.appendInputAudio(float32ToPcm16(channel));
47
- };
48
- if (ctx.state === 'suspended') {
49
- await ctx.resume();
50
- }
51
- }
52
- stop() {
53
- this.processor?.disconnect();
54
- this.source?.disconnect();
55
- this.silentGain?.disconnect();
56
- this.processor = null;
57
- this.source = null;
58
- this.silentGain = null;
59
- for (const track of this.stream?.getTracks() ?? []) {
60
- track.stop();
61
- }
62
- this.stream = null;
63
- void this.audioContext?.close();
64
- this.audioContext = null;
65
- this.session?.clearInputAudio?.();
66
- }
67
- cleanup() {
68
- this.stop();
69
- this.session = null;
70
- }
71
- }
@@ -1,2 +0,0 @@
1
- export declare function float32ToPcm16(input: Float32Array): Int16Array;
2
- //# sourceMappingURL=float32ToPcm16.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"float32ToPcm16.d.ts","sourceRoot":"","sources":["../../../src/voice/ws/float32ToPcm16.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,UAAU,CAO9D"}
@@ -1,8 +0,0 @@
1
- export function float32ToPcm16(input) {
2
- const out = new Int16Array(input.length);
3
- for (let i = 0; i < input.length; i += 1) {
4
- const sample = Math.max(-1, Math.min(1, input[i]));
5
- out[i] = sample < 0 ? sample * 0x8000 : sample * 0x7fff;
6
- }
7
- return out;
8
- }
@@ -1,5 +0,0 @@
1
- export declare const MIC_SPEECH_RMS_THRESHOLD = 0.008;
2
- export declare const MIC_BARGE_IN_RMS_THRESHOLD = 0.045;
3
- export declare const MIC_SILENCE_COMMIT_MS = 400;
4
- export declare const MIC_SILENCE_POLL_MS = 100;
5
- //# sourceMappingURL=voiceSilenceConstants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"voiceSilenceConstants.d.ts","sourceRoot":"","sources":["../../../src/voice/ws/voiceSilenceConstants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,QAAQ,CAAC;AAC9C,eAAO,MAAM,0BAA0B,QAAQ,CAAC;AAChD,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,mBAAmB,MAAM,CAAC"}
@@ -1,4 +0,0 @@
1
- export const MIC_SPEECH_RMS_THRESHOLD = 0.008;
2
- export const MIC_BARGE_IN_RMS_THRESHOLD = 0.045;
3
- export const MIC_SILENCE_COMMIT_MS = 400;
4
- export const MIC_SILENCE_POLL_MS = 100;
@@ -1,2 +0,0 @@
1
- export declare const WS_REALTIME_SAMPLE_RATE = 24000;
2
- //# sourceMappingURL=wsRealtimeConstants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"wsRealtimeConstants.d.ts","sourceRoot":"","sources":["../../../src/voice/ws/wsRealtimeConstants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,QAAQ,CAAC"}
@@ -1 +0,0 @@
1
- export const WS_REALTIME_SAMPLE_RATE = 24000;