@nextpa/chat-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/constants/defaults.d.ts +6 -0
  4. package/dist/constants/defaults.js +69 -0
  5. package/dist/core/chat-manager.d.ts +17 -0
  6. package/dist/core/chat-manager.js +39 -0
  7. package/dist/core/config-manager.d.ts +14 -0
  8. package/dist/core/config-manager.js +75 -0
  9. package/dist/core/connection-manager.d.ts +68 -0
  10. package/dist/core/connection-manager.js +273 -0
  11. package/dist/core/connection-retry-handler.d.ts +11 -0
  12. package/dist/core/connection-retry-handler.js +33 -0
  13. package/dist/core/consent-manager.d.ts +15 -0
  14. package/dist/core/consent-manager.js +40 -0
  15. package/dist/core/conversation-persistence.d.ts +23 -0
  16. package/dist/core/conversation-persistence.js +109 -0
  17. package/dist/core/event-emitter.d.ts +7 -0
  18. package/dist/core/event-emitter.js +27 -0
  19. package/dist/core/greeting-gate.d.ts +16 -0
  20. package/dist/core/greeting-gate.js +53 -0
  21. package/dist/core/index.d.ts +9 -0
  22. package/dist/core/index.js +7 -0
  23. package/dist/core/link-target.d.ts +15 -0
  24. package/dist/core/link-target.js +64 -0
  25. package/dist/core/local-storage-persistence.d.ts +11 -0
  26. package/dist/core/local-storage-persistence.js +111 -0
  27. package/dist/core/navigation-manager.d.ts +24 -0
  28. package/dist/core/navigation-manager.js +132 -0
  29. package/dist/core/popover-manager.d.ts +14 -0
  30. package/dist/core/popover-manager.js +36 -0
  31. package/dist/core/session-beacon.d.ts +11 -0
  32. package/dist/core/session-beacon.js +60 -0
  33. package/dist/core/text-connection-manager.d.ts +58 -0
  34. package/dist/core/text-connection-manager.js +200 -0
  35. package/dist/core/text-mode-manager.d.ts +50 -0
  36. package/dist/core/text-mode-manager.js +154 -0
  37. package/dist/core/text-types.d.ts +20 -0
  38. package/dist/core/text-types.js +1 -0
  39. package/dist/core/text-widget-controller.d.ts +47 -0
  40. package/dist/core/text-widget-controller.js +278 -0
  41. package/dist/core/theme-manager.d.ts +10 -0
  42. package/dist/core/theme-manager.js +25 -0
  43. package/dist/core/types.d.ts +50 -0
  44. package/dist/core/types.js +1 -0
  45. package/dist/core/voice-state-manager.d.ts +85 -0
  46. package/dist/core/voice-state-manager.js +317 -0
  47. package/dist/core/widget-controller.d.ts +58 -0
  48. package/dist/core/widget-controller.js +533 -0
  49. package/dist/core/widget-core.d.ts +51 -0
  50. package/dist/core/widget-core.js +160 -0
  51. package/dist/google.d.ts +1 -0
  52. package/dist/google.js +12 -0
  53. package/dist/index.d.ts +37 -0
  54. package/dist/index.js +40 -0
  55. package/dist/openai.d.ts +1 -0
  56. package/dist/openai.js +7 -0
  57. package/dist/services/api.d.ts +114 -0
  58. package/dist/services/api.js +336 -0
  59. package/dist/services/index.d.ts +3 -0
  60. package/dist/services/index.js +3 -0
  61. package/dist/services/page-interaction/constants.d.ts +1 -0
  62. package/dist/services/page-interaction/constants.js +1 -0
  63. package/dist/services/page-interaction/content-extractor.d.ts +2 -0
  64. package/dist/services/page-interaction/content-extractor.js +104 -0
  65. package/dist/services/page-interaction/deep-query.d.ts +8 -0
  66. package/dist/services/page-interaction/deep-query.js +44 -0
  67. package/dist/services/page-interaction/dom-executor.d.ts +7 -0
  68. package/dist/services/page-interaction/dom-executor.js +172 -0
  69. package/dist/services/page-interaction/dom-extractor.d.ts +8 -0
  70. package/dist/services/page-interaction/dom-extractor.js +252 -0
  71. package/dist/services/page-interaction/extension-bridge.d.ts +10 -0
  72. package/dist/services/page-interaction/extension-bridge.js +86 -0
  73. package/dist/services/page-interaction/iframe-navigation-manager.d.ts +28 -0
  74. package/dist/services/page-interaction/iframe-navigation-manager.js +154 -0
  75. package/dist/services/page-interaction/index.d.ts +5 -0
  76. package/dist/services/page-interaction/index.js +4 -0
  77. package/dist/services/page-interaction/page-interaction-handler.d.ts +21 -0
  78. package/dist/services/page-interaction/page-interaction-handler.js +129 -0
  79. package/dist/services/page-interaction/selector-generator.d.ts +1 -0
  80. package/dist/services/page-interaction/selector-generator.js +48 -0
  81. package/dist/services/page-interaction/types.d.ts +75 -0
  82. package/dist/services/page-interaction/types.js +1 -0
  83. package/dist/services/realtime/google/google-audio.d.ts +44 -0
  84. package/dist/services/realtime/google/google-audio.js +410 -0
  85. package/dist/services/realtime/google/google-provider.d.ts +47 -0
  86. package/dist/services/realtime/google/google-provider.js +465 -0
  87. package/dist/services/realtime/google/google-tool-mapper.d.ts +3 -0
  88. package/dist/services/realtime/google/google-tool-mapper.js +70 -0
  89. package/dist/services/realtime/google/index.d.ts +1 -0
  90. package/dist/services/realtime/google/index.js +1 -0
  91. package/dist/services/realtime/openai/index.d.ts +1 -0
  92. package/dist/services/realtime/openai/index.js +1 -0
  93. package/dist/services/realtime/openai/openai-audio-monitor.d.ts +1 -0
  94. package/dist/services/realtime/openai/openai-audio-monitor.js +55 -0
  95. package/dist/services/realtime/openai/openai-provider.d.ts +50 -0
  96. package/dist/services/realtime/openai/openai-provider.js +579 -0
  97. package/dist/services/realtime/openai/openai-tool-mapper.d.ts +15 -0
  98. package/dist/services/realtime/openai/openai-tool-mapper.js +14 -0
  99. package/dist/services/realtime/provider-factory.d.ts +4 -0
  100. package/dist/services/realtime/provider-factory.js +12 -0
  101. package/dist/services/realtime/types.d.ts +78 -0
  102. package/dist/services/realtime/types.js +1 -0
  103. package/dist/services/realtime/vertexai/index.d.ts +1 -0
  104. package/dist/services/realtime/vertexai/index.js +1 -0
  105. package/dist/services/realtime/vertexai/vertexai-provider.d.ts +53 -0
  106. package/dist/services/realtime/vertexai/vertexai-provider.js +561 -0
  107. package/dist/services/realtime/voice-session-tracker.d.ts +10 -0
  108. package/dist/services/realtime/voice-session-tracker.js +62 -0
  109. package/dist/services/signalr.d.ts +37 -0
  110. package/dist/services/signalr.js +145 -0
  111. package/dist/services/thinking-audio-pulse.d.ts +2 -0
  112. package/dist/services/thinking-audio-pulse.js +72 -0
  113. package/dist/services/thinking-audio.d.ts +2 -0
  114. package/dist/services/thinking-audio.js +105 -0
  115. package/dist/services/voice-health-watchdog.d.ts +42 -0
  116. package/dist/services/voice-health-watchdog.js +90 -0
  117. package/dist/services/webrtc-event-handler.d.ts +4 -0
  118. package/dist/services/webrtc-event-handler.js +42 -0
  119. package/dist/services/webrtc-greeting.d.ts +3 -0
  120. package/dist/services/webrtc-greeting.js +62 -0
  121. package/dist/services/webrtc-microphone.d.ts +15 -0
  122. package/dist/services/webrtc-microphone.js +64 -0
  123. package/dist/services/webrtc.d.ts +44 -0
  124. package/dist/services/webrtc.js +196 -0
  125. package/dist/types/index.d.ts +151 -0
  126. package/dist/types/index.js +1 -0
  127. package/dist/utils/audio-context.d.ts +11 -0
  128. package/dist/utils/audio-context.js +33 -0
  129. package/dist/utils/connect-chime.d.ts +11 -0
  130. package/dist/utils/connect-chime.js +230 -0
  131. package/dist/utils/consent.d.ts +4 -0
  132. package/dist/utils/consent.js +30 -0
  133. package/dist/utils/language-detection.d.ts +1 -0
  134. package/dist/utils/language-detection.js +17 -0
  135. package/dist/utils/logger.d.ts +13 -0
  136. package/dist/utils/logger.js +40 -0
  137. package/dist/utils/mic-level-analyser.d.ts +13 -0
  138. package/dist/utils/mic-level-analyser.js +50 -0
  139. package/dist/utils/proactive-events.d.ts +5 -0
  140. package/dist/utils/proactive-events.js +1 -0
  141. package/dist/utils/styles.d.ts +4 -0
  142. package/dist/utils/styles.js +35 -0
  143. package/dist/utils/theme-detection.d.ts +3 -0
  144. package/dist/utils/theme-detection.js +121 -0
  145. package/dist/utils/tool-status.d.ts +10 -0
  146. package/dist/utils/tool-status.js +61 -0
  147. package/dist/utils/ui-sounds.d.ts +3 -0
  148. package/dist/utils/ui-sounds.js +57 -0
  149. package/package.json +56 -0
@@ -0,0 +1,317 @@
1
+ import { logger } from '../utils/logger';
2
+ import { getToolStatusLabel, getSynthesizingStatus, resolveToolCallState } from '../utils/tool-status';
3
+ import { startThinkingAudio, stopThinkingAudio } from '../services/thinking-audio-pulse';
4
+ const STOP_CONVERSATION_TIMEOUT_MS = 30_000;
5
+ export class VoiceStateManager {
6
+ isUserSpeaking = false;
7
+ isAiThinking = false;
8
+ isMuted = false;
9
+ isMicrophoneReady = true;
10
+ isMicrophoneBlocked = false;
11
+ isTranscribing = false;
12
+ transcribingContent = '';
13
+ isStreaming = false;
14
+ isAssistantSpeaking = false;
15
+ streamContent = '';
16
+ agentStatus = null;
17
+ audioLevel = 0;
18
+ audioLevelLastTime = 0;
19
+ isDelegationActive = false;
20
+ connectionManager = null;
21
+ apiClient = null;
22
+ logPrefix = '';
23
+ language;
24
+ latestUsage = null;
25
+ accumulatedUsage = null;
26
+ pendingToolCalls = [];
27
+ thinkingStartedAt = null;
28
+ pendingStreamingUpdate = false;
29
+ toolAbortController = null;
30
+ onStateChanged;
31
+ constructor(onStateChanged) {
32
+ this.onStateChanged = onStateChanged;
33
+ }
34
+ setupEventHandlers(deps) {
35
+ this.connectionManager = deps.connectionManager;
36
+ this.apiClient = deps.apiClient;
37
+ this.logPrefix = deps.logPrefix;
38
+ this.setupSpeechHandlers(deps);
39
+ this.setupConnectionHandlers(deps);
40
+ this.setupActionHandlers(deps);
41
+ }
42
+ setLanguage(language) {
43
+ this.language = language;
44
+ }
45
+ toggleMute() {
46
+ if (!this.connectionManager)
47
+ return;
48
+ this.isMuted = !this.isMuted;
49
+ this.connectionManager.setMuted(this.isMuted);
50
+ this.onStateChanged();
51
+ }
52
+ /**
53
+ * User pressed stop while the assistant was busy. If a backend tool (e.g. a
54
+ * long web research) is in flight, abort its HTTP call so the server cancels
55
+ * it (RequestAborted) and let the model wrap up gracefully. Otherwise the
56
+ * assistant is thinking/talking — interrupt the response and drop the audio.
57
+ */
58
+ stop() {
59
+ if (this.toolAbortController) {
60
+ this.toolAbortController.abort();
61
+ return;
62
+ }
63
+ this.connectionManager?.interrupt();
64
+ this.isStreaming = false;
65
+ this.isAssistantSpeaking = false;
66
+ this.isAiThinking = false;
67
+ this.streamContent = '';
68
+ this.agentStatus = null;
69
+ this.isDelegationActive = false;
70
+ stopThinkingAudio();
71
+ this.onStateChanged();
72
+ }
73
+ /**
74
+ * The assistant transcript completes before its audio finishes playing.
75
+ * Hold the speaking flag until playback truly ends (audioDone + playback
76
+ * monitor) so the stop button stays visible while the user can still hear
77
+ * the assistant.
78
+ */
79
+ async trackAssistantPlayback() {
80
+ await this.connectionManager?.waitForResponseComplete();
81
+ this.isAssistantSpeaking = false;
82
+ this.onStateChanged();
83
+ }
84
+ resetState() {
85
+ this.isUserSpeaking = false;
86
+ this.isAiThinking = false;
87
+ this.isMicrophoneReady = true;
88
+ this.isTranscribing = false;
89
+ this.transcribingContent = '';
90
+ this.isStreaming = false;
91
+ this.isAssistantSpeaking = false;
92
+ this.streamContent = '';
93
+ this.agentStatus = null;
94
+ this.audioLevel = 0;
95
+ this.audioLevelLastTime = 0;
96
+ this.isDelegationActive = false;
97
+ stopThinkingAudio();
98
+ }
99
+ /**
100
+ * Asymmetric envelope follower over a dBFS-mapped input. Two stages:
101
+ *
102
+ * 1. dBFS perceptual map — raw RMS (0..1) lives mostly under 0.1 so a
103
+ * linear halo would barely move at normal volumes. Mapping through
104
+ * 20·log10(level) and clamping to roughly -50..0 dBFS spreads the
105
+ * normal-speech range across the visual.
106
+ * 2. One-pole IIR with split time constants — 10 ms attack so syllables
107
+ * pop, 150 ms release so the avatar doesn't twitch off between words.
108
+ *
109
+ * Sweet spots picked from common voice-visualisation guidance (attack
110
+ * 5–50 ms, release 100–300 ms, dBFS floor -60 .. -50, ceiling -10 .. 0).
111
+ */
112
+ smoothAudioLevel(level) {
113
+ const now = performance.now();
114
+ const dt = this.audioLevelLastTime ? Math.max(0, (now - this.audioLevelLastTime) / 1000) : 0.016;
115
+ this.audioLevelLastTime = now;
116
+ const db = 20 * Math.log10(Math.max(level, 0.001));
117
+ const perceptual = Math.max(0, Math.min(1, (db + 50) / 50));
118
+ const tau = perceptual > this.audioLevel ? 0.01 : 0.15;
119
+ const alpha = 1 - Math.exp(-dt / tau);
120
+ return this.audioLevel + alpha * (perceptual - this.audioLevel);
121
+ }
122
+ prepareForConnection() {
123
+ this.isMicrophoneBlocked = false;
124
+ this.isMuted = false;
125
+ this.isMicrophoneReady = false;
126
+ }
127
+ setupSpeechHandlers({ connectionManager, chatManager, persistence }) {
128
+ connectionManager.on('usageUpdated', (usage) => {
129
+ this.accumulateUsage(usage);
130
+ });
131
+ connectionManager.on('userSpeechStart', () => {
132
+ this.isUserSpeaking = true;
133
+ this.isAiThinking = false;
134
+ this.isAssistantSpeaking = false;
135
+ this.isTranscribing = false;
136
+ this.transcribingContent = '';
137
+ this.onStateChanged();
138
+ });
139
+ connectionManager.on('userSpeechStop', () => {
140
+ this.isUserSpeaking = false;
141
+ this.isAiThinking = true;
142
+ this.thinkingStartedAt = Date.now();
143
+ this.onStateChanged();
144
+ });
145
+ connectionManager.on('userSpeechEnd', () => {
146
+ this.isUserSpeaking = false;
147
+ this.onStateChanged();
148
+ });
149
+ connectionManager.on('audioLevel', (level) => {
150
+ this.audioLevel = this.smoothAudioLevel(level);
151
+ this.onStateChanged();
152
+ });
153
+ connectionManager.on('transcriptDelta', ({ isUser, delta }) => {
154
+ if (isUser) {
155
+ this.isTranscribing = true;
156
+ this.transcribingContent += delta;
157
+ }
158
+ else {
159
+ if (!this.isDelegationActive) {
160
+ this.agentStatus = null;
161
+ }
162
+ this.isStreaming = true;
163
+ this.isAiThinking = false;
164
+ this.streamContent += delta;
165
+ if (!this.isAssistantSpeaking) {
166
+ this.isAssistantSpeaking = true;
167
+ void this.trackAssistantPlayback();
168
+ }
169
+ }
170
+ this.scheduleStreamingUpdate();
171
+ });
172
+ connectionManager.on('transcriptReceived', ({ isUser, text }) => {
173
+ if (isUser) {
174
+ this.isTranscribing = false;
175
+ this.transcribingContent = '';
176
+ chatManager.addUserMessage(text);
177
+ persistence.persistMessage('User', text, this.language, undefined, undefined, undefined, 'Spoken');
178
+ this.onStateChanged();
179
+ return;
180
+ }
181
+ this.isAiThinking = false;
182
+ this.isStreaming = false;
183
+ this.streamContent = '';
184
+ chatManager.addAssistantMessage(text);
185
+ const usage = this.latestUsage;
186
+ this.latestUsage = null;
187
+ this.accumulatedUsage = null;
188
+ const toolCalls = this.pendingToolCalls.length > 0 ? [...this.pendingToolCalls] : undefined;
189
+ this.pendingToolCalls = [];
190
+ const responseLatencyMs = this.thinkingStartedAt
191
+ ? Math.round(Date.now() - this.thinkingStartedAt)
192
+ : undefined;
193
+ this.thinkingStartedAt = null;
194
+ persistence.persistMessage('Assistant', text, this.language, usage ?? undefined, toolCalls, responseLatencyMs);
195
+ });
196
+ }
197
+ setupConnectionHandlers({ connectionManager, logPrefix }) {
198
+ connectionManager.on('connectionStateChanged', () => this.onStateChanged());
199
+ connectionManager.on('error', (err) => {
200
+ logger.error(`${logPrefix} Connection error:`, err);
201
+ this.onStateChanged();
202
+ });
203
+ connectionManager.on('microphoneBlocked', () => {
204
+ logger.warn(`${logPrefix} Microphone permission blocked by browser`);
205
+ this.isMicrophoneBlocked = true;
206
+ this.onStateChanged();
207
+ });
208
+ connectionManager.on('microphoneReady', () => {
209
+ this.isMicrophoneReady = true;
210
+ this.onStateChanged();
211
+ });
212
+ }
213
+ setupActionHandlers({ connectionManager, navigationManager, onStopConversation }) {
214
+ connectionManager.on('functionCall', (call) => this.handleFunctionCall(call));
215
+ connectionManager.on('toolCall', ({ toolName, status }) => this.handleToolCall(toolName, status));
216
+ connectionManager.on('stopConversation', () => this.handleStopConversation(onStopConversation));
217
+ connectionManager.on('openUrl', (url) => navigationManager.openUrl(url));
218
+ connectionManager.on('openFile', (url) => navigationManager.openUrl(url));
219
+ }
220
+ handleToolCall(toolName, status) {
221
+ logger.debug(`${this.logPrefix} Tool call:`, toolName, status);
222
+ const previouslyActive = this.isDelegationActive;
223
+ const state = resolveToolCallState(toolName, status, this.isDelegationActive, this.language);
224
+ this.agentStatus = state.agentStatus;
225
+ this.isDelegationActive = state.isDelegationActive;
226
+ if (state.isDelegationActive && !previouslyActive) {
227
+ startThinkingAudio();
228
+ }
229
+ else if (!state.isDelegationActive && previouslyActive) {
230
+ stopThinkingAudio();
231
+ }
232
+ this.onStateChanged();
233
+ }
234
+ async handleFunctionCall(call) {
235
+ if (!this.connectionManager || !this.apiClient)
236
+ return;
237
+ logger.debug(`${this.logPrefix} Executing tool:`, call.name);
238
+ this.agentStatus = getToolStatusLabel(call.name, this.language);
239
+ this.isAiThinking = true;
240
+ this.onStateChanged();
241
+ startThinkingAudio();
242
+ const controller = new AbortController();
243
+ this.toolAbortController = controller;
244
+ const startTime = Date.now();
245
+ let succeeded = true;
246
+ try {
247
+ const result = await this.apiClient.executeTool(call.name, call.arguments, controller.signal);
248
+ await this.connectionManager.sendFunctionResult(call.callId, call.name, result);
249
+ logger.debug(`${this.logPrefix} Tool executed successfully:`, call.name);
250
+ }
251
+ catch (err) {
252
+ succeeded = false;
253
+ const errorMessage = err instanceof Error ? err.message : 'Tool execution failed';
254
+ const resultMsg = controller.signal.aborted
255
+ ? 'The user stopped this action. Abandon the current task and briefly ask how you can help instead.'
256
+ : `Error: ${errorMessage}`;
257
+ logger.debug(`${this.logPrefix} Tool ended:`, call.name, controller.signal.aborted ? 'aborted by user' : err);
258
+ try {
259
+ await this.connectionManager.sendFunctionResult(call.callId, call.name, resultMsg);
260
+ }
261
+ catch { /* ignore errors when sending result */ }
262
+ }
263
+ finally {
264
+ if (this.toolAbortController === controller) {
265
+ this.toolAbortController = null;
266
+ }
267
+ }
268
+ this.pendingToolCalls.push({
269
+ name: call.name,
270
+ durationMs: Math.round(Date.now() - startTime),
271
+ succeeded,
272
+ });
273
+ stopThinkingAudio();
274
+ this.agentStatus = getSynthesizingStatus(this.language);
275
+ this.onStateChanged();
276
+ }
277
+ async handleStopConversation(onDisconnect) {
278
+ if (!this.connectionManager)
279
+ return;
280
+ logger.debug(`${this.logPrefix} StopConversation received, muting and waiting for AI to finish...`);
281
+ this.connectionManager.setMuted(true);
282
+ await this.connectionManager.waitForResponseComplete(STOP_CONVERSATION_TIMEOUT_MS);
283
+ logger.debug(`${this.logPrefix} AI finished speaking, disconnecting`);
284
+ await onDisconnect();
285
+ }
286
+ accumulateUsage(usage) {
287
+ if (this.accumulatedUsage) {
288
+ this.accumulatedUsage = {
289
+ provider: usage.provider,
290
+ model: usage.model,
291
+ inputTokens: this.accumulatedUsage.inputTokens + usage.inputTokens,
292
+ outputTokens: this.accumulatedUsage.outputTokens + usage.outputTokens,
293
+ totalTokens: this.accumulatedUsage.totalTokens + usage.totalTokens,
294
+ cachedTokens: (this.accumulatedUsage.cachedTokens ?? 0) + (usage.cachedTokens ?? 0) || undefined,
295
+ textCachedInputTokens: (this.accumulatedUsage.textCachedInputTokens ?? 0) + (usage.textCachedInputTokens ?? 0) || undefined,
296
+ audioCachedInputTokens: (this.accumulatedUsage.audioCachedInputTokens ?? 0) + (usage.audioCachedInputTokens ?? 0) || undefined,
297
+ audioInputTokens: (this.accumulatedUsage.audioInputTokens ?? 0) + (usage.audioInputTokens ?? 0) || undefined,
298
+ audioOutputTokens: (this.accumulatedUsage.audioOutputTokens ?? 0) + (usage.audioOutputTokens ?? 0) || undefined,
299
+ textInputTokens: (this.accumulatedUsage.textInputTokens ?? 0) + (usage.textInputTokens ?? 0) || undefined,
300
+ textOutputTokens: (this.accumulatedUsage.textOutputTokens ?? 0) + (usage.textOutputTokens ?? 0) || undefined,
301
+ };
302
+ }
303
+ else {
304
+ this.accumulatedUsage = usage;
305
+ }
306
+ this.latestUsage = this.accumulatedUsage;
307
+ }
308
+ scheduleStreamingUpdate() {
309
+ if (this.pendingStreamingUpdate)
310
+ return;
311
+ this.pendingStreamingUpdate = true;
312
+ requestAnimationFrame(() => {
313
+ this.pendingStreamingUpdate = false;
314
+ this.onStateChanged();
315
+ });
316
+ }
317
+ }
@@ -0,0 +1,58 @@
1
+ import { EventEmitter } from './event-emitter';
2
+ import type { WidgetState, WidgetControllerOptions } from './types';
3
+ import type { ConnectOptions } from '../types';
4
+ interface WidgetControllerEvents {
5
+ stateChanged: (state: WidgetState) => void;
6
+ }
7
+ export declare class WidgetController extends EventEmitter<WidgetControllerEvents> {
8
+ private readonly core;
9
+ private readonly voiceConnectionManager;
10
+ private readonly voiceState;
11
+ private readonly textMode;
12
+ private readonly retryHandler;
13
+ private readonly sessionBeacon;
14
+ private currentMode;
15
+ private pendingConnectMode;
16
+ private isReconnecting;
17
+ private showReconnecting;
18
+ private voiceRecoveryAttempts;
19
+ private greetingOverride;
20
+ private get uiSoundsEnabled();
21
+ constructor(options: WidgetControllerOptions);
22
+ initialize(): Promise<void>;
23
+ connect(options?: ConnectOptions): Promise<void>;
24
+ private greetingEnabled;
25
+ private shouldSkipVoiceGreeting;
26
+ connectVoice(): Promise<void>;
27
+ connectText(skipGreeting?: boolean, waitForGreeting?: boolean): Promise<void>;
28
+ disconnect(trimFarewell?: boolean): Promise<void>;
29
+ endCall(): Promise<void>;
30
+ resetConversation(): Promise<void>;
31
+ submitSessionFeedback(rating: number): void;
32
+ submitFeedback(messageId: string, rating: number | undefined): void;
33
+ sendMessage(text: string): Promise<void>;
34
+ toggleMute(): void;
35
+ stopVoiceResponse(): void;
36
+ transcribe(audio: Blob, signal?: AbortSignal): Promise<string>;
37
+ toggleMinimized(): void;
38
+ setMinimized(minimized: boolean): void;
39
+ acceptTerms(): void;
40
+ declineTerms(): void;
41
+ dismissBlockedUrl(): void;
42
+ openBlockedUrl(): void;
43
+ dismissPopover(): void;
44
+ getState(): WidgetState;
45
+ dispose(): void;
46
+ private notifyStateChanged;
47
+ private getActiveConnectionState;
48
+ private handleRetryResult;
49
+ private handleSessionResumed;
50
+ private disconnectCurrentMode;
51
+ private handleUnexpectedDisconnect;
52
+ private handleVoiceUnhealthy;
53
+ private handleVoiceStopConversation;
54
+ private handleTextStopConversation;
55
+ private updateDocumentProviders;
56
+ private setupExtensionBridge;
57
+ }
58
+ export {};