@primoia/vocall-react 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.
@@ -0,0 +1,530 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ declare enum FieldType {
5
+ Text = "text",
6
+ Number = "number",
7
+ Currency = "currency",
8
+ Date = "date",
9
+ Datetime = "datetime",
10
+ Email = "email",
11
+ Phone = "phone",
12
+ Masked = "masked",
13
+ Select = "select",
14
+ Autocomplete = "autocomplete",
15
+ Checkbox = "checkbox",
16
+ Radio = "radio",
17
+ Textarea = "textarea",
18
+ File = "file",
19
+ Hidden = "hidden"
20
+ }
21
+ interface SelectOption {
22
+ value: string;
23
+ label: string;
24
+ }
25
+ interface FieldDescriptor {
26
+ id: string;
27
+ type: FieldType | string;
28
+ label: string;
29
+ required?: boolean;
30
+ mask?: string;
31
+ placeholder?: string;
32
+ options?: SelectOption[];
33
+ source?: string;
34
+ min?: number;
35
+ max?: number;
36
+ maxLength?: number;
37
+ readOnly?: boolean;
38
+ }
39
+ interface ActionDescriptor {
40
+ id: string;
41
+ label: string;
42
+ destructive?: boolean;
43
+ requiresConfirmation?: boolean;
44
+ disabled?: boolean;
45
+ }
46
+ interface ModalDescriptor {
47
+ id: string;
48
+ label: string;
49
+ searchable?: boolean;
50
+ }
51
+ interface ScreenDescriptor {
52
+ id: string;
53
+ label: string;
54
+ route?: string;
55
+ fields?: FieldDescriptor[];
56
+ actions?: ActionDescriptor[];
57
+ modals?: ModalDescriptor[];
58
+ }
59
+ interface Persona {
60
+ name?: string;
61
+ role?: string;
62
+ instructions?: string;
63
+ }
64
+ interface UserInfo {
65
+ name?: string;
66
+ email?: string;
67
+ org?: string;
68
+ role?: string;
69
+ }
70
+ interface ManifestMessage {
71
+ type: 'manifest';
72
+ app: string;
73
+ screens: Record<string, ScreenDescriptor>;
74
+ version?: string;
75
+ currentScreen?: string;
76
+ user?: UserInfo;
77
+ context?: Record<string, unknown>;
78
+ persona?: Persona;
79
+ }
80
+ interface TextMessage {
81
+ type: 'text';
82
+ message: string;
83
+ }
84
+ interface ConfirmMessage {
85
+ type: 'confirm';
86
+ seq: number;
87
+ confirmed: boolean;
88
+ }
89
+ interface ActionResult {
90
+ index: number;
91
+ success: boolean;
92
+ error?: string;
93
+ }
94
+ interface FieldState {
95
+ value: unknown;
96
+ valid?: boolean;
97
+ error?: string;
98
+ dirty?: boolean;
99
+ }
100
+ interface StateMessage {
101
+ type: 'state';
102
+ screen: string;
103
+ fields?: Record<string, FieldState>;
104
+ canSubmit?: boolean;
105
+ }
106
+ interface ResultMessage {
107
+ type: 'result';
108
+ seq: number;
109
+ results: ActionResult[];
110
+ state?: StateMessage;
111
+ }
112
+ interface FeaturesConfig {
113
+ voice?: boolean;
114
+ chat?: boolean;
115
+ }
116
+ interface ConfigResponse {
117
+ type: 'config';
118
+ sessionId: string;
119
+ features?: FeaturesConfig;
120
+ }
121
+ interface UIAction {
122
+ do: string;
123
+ screen?: string;
124
+ field?: string;
125
+ action?: string;
126
+ modal?: string;
127
+ value?: unknown;
128
+ query?: string;
129
+ message?: string;
130
+ animate?: string;
131
+ speed?: number;
132
+ duration?: number;
133
+ level?: string;
134
+ }
135
+ interface CommandMessage {
136
+ type: 'command';
137
+ seq: number;
138
+ actions: UIAction[];
139
+ }
140
+ interface ChatMessageOut {
141
+ type: 'chat';
142
+ from: string;
143
+ message: string;
144
+ final?: boolean;
145
+ }
146
+ interface ChatTokenOut {
147
+ type: 'chat_token';
148
+ token: string;
149
+ }
150
+ interface ChatEndOut {
151
+ type: 'chat_end';
152
+ }
153
+ interface StatusOut {
154
+ type: 'status';
155
+ status: string;
156
+ }
157
+ interface ErrorOut {
158
+ type: 'error';
159
+ message: string;
160
+ code?: string;
161
+ }
162
+ declare enum ChatRole {
163
+ User = "user",
164
+ Agent = "agent",
165
+ System = "system"
166
+ }
167
+ interface ChatMessage {
168
+ role: ChatRole;
169
+ text: string;
170
+ timestamp: Date;
171
+ }
172
+ declare enum VocallStatus {
173
+ Disconnected = "disconnected",
174
+ Idle = "idle",
175
+ Listening = "listening",
176
+ Recording = "recording",
177
+ Thinking = "thinking",
178
+ Speaking = "speaking",
179
+ Executing = "executing"
180
+ }
181
+ type VoiceState$1 = 'idle' | 'listening' | 'recording' | 'thinking' | 'speaking';
182
+ type ServerMessage = ConfigResponse | ChatMessageOut | ChatTokenOut | ChatEndOut | StatusOut | CommandMessage | ErrorOut | {
183
+ type: string;
184
+ [key: string]: unknown;
185
+ };
186
+
187
+ interface FieldEntry {
188
+ /** The HTML input/select/textarea element */
189
+ element: HTMLElement;
190
+ /** Setter to update the value programmatically (triggers change detection) */
191
+ setValue: (value: string) => void;
192
+ /** Getter for the current value */
193
+ getValue: () => string;
194
+ }
195
+ type ActionCallback = () => void | Promise<void>;
196
+ type NavigateCallback = (screenId: string) => void;
197
+ type ModalOpenCallback = (modalId: string, query?: string) => void;
198
+ type ModalCloseCallback = () => void;
199
+ type ToastCallback = (message: string, level: string, duration?: number) => void;
200
+ type ConfirmCallback = (seq: number, message: string) => void;
201
+ type VocallChangeListener = () => void;
202
+ declare class VocallClient {
203
+ readonly serverUrl: string;
204
+ token?: string;
205
+ private _visitorId;
206
+ get visitorId(): string;
207
+ set visitorId(id: string);
208
+ private _status;
209
+ get status(): VocallStatus;
210
+ private _connected;
211
+ get connected(): boolean;
212
+ private _messages;
213
+ get messages(): readonly ChatMessage[];
214
+ private _sessionId;
215
+ get sessionId(): string | null;
216
+ private _voiceEnabled;
217
+ get voiceEnabled(): boolean;
218
+ /** Whether the platform supports voice capture (Web Audio API). */
219
+ get voiceSupported(): boolean;
220
+ private _voiceState;
221
+ get voiceState(): VoiceState$1;
222
+ private _recording;
223
+ get recording(): boolean;
224
+ private _partialTranscription;
225
+ get partialTranscription(): string | null;
226
+ private _audioLevel;
227
+ get audioLevel(): number;
228
+ private _voiceWs;
229
+ private _alwaysListening;
230
+ private _ttsActive;
231
+ private _ttsEndReceived;
232
+ private _llmDone;
233
+ private _pendingTtsChunks;
234
+ private _voice;
235
+ private _getVoice;
236
+ private _listeners;
237
+ subscribe(listener: VocallChangeListener): () => void;
238
+ private _notify;
239
+ onNavigate: NavigateCallback | null;
240
+ onToast: ToastCallback | null;
241
+ onConfirm: ConfirmCallback | null;
242
+ onOpenModal: ModalOpenCallback | null;
243
+ onCloseModal: ModalCloseCallback | null;
244
+ private _fields;
245
+ private _actions;
246
+ private _ws;
247
+ private _manifest;
248
+ private _tokenBuffer;
249
+ private _streamingMessage;
250
+ private _reconnectTimer;
251
+ private _reconnectAttempts;
252
+ private _intentionalDisconnect;
253
+ private _pendingConfirmSeq;
254
+ private static readonly MAX_RECONNECT_ATTEMPTS;
255
+ private static readonly RETRY_DELAY_MS;
256
+ private static readonly MAX_RETRIES;
257
+ private static readonly SEQUENTIAL_ACTIONS;
258
+ constructor(serverUrl: string, options?: {
259
+ token?: string;
260
+ visitorId?: string;
261
+ });
262
+ private static _generateUuid;
263
+ private static _loadOrCreateVisitorId;
264
+ registerField(screenId: string, fieldId: string, entry: FieldEntry): void;
265
+ unregisterField(screenId: string, fieldId: string): void;
266
+ unregisterScreen(screenId: string): void;
267
+ registerAction(screenId: string, actionId: string, callback: ActionCallback): void;
268
+ unregisterAction(screenId: string, actionId: string): void;
269
+ findField(fieldId: string): FieldEntry | undefined;
270
+ findAction(actionId: string): ActionCallback | undefined;
271
+ connect(manifest: ManifestMessage): void;
272
+ private _doConnect;
273
+ disconnect(intentional?: boolean): void;
274
+ sendText(text: string): void;
275
+ sendConfirm(seq: number, confirmed: boolean): void;
276
+ sendResult(seq: number, results: ActionResult[], state?: StateMessage): void;
277
+ sendState(state: StateMessage): void;
278
+ private _wsSend;
279
+ private _onMessage;
280
+ private _handleConfig;
281
+ private _handleHistory;
282
+ private _handleChat;
283
+ private _handleChatToken;
284
+ private _flushTokenBuffer;
285
+ private _handleStatus;
286
+ private _mapStatus;
287
+ private _handleError;
288
+ private _handleCommand;
289
+ private _executeAction;
290
+ private _execNavigate;
291
+ private _execFill;
292
+ private _typewriterFill;
293
+ private _execClear;
294
+ private _execSelect;
295
+ private _execClick;
296
+ private _execFocus;
297
+ private _execHighlight;
298
+ private _execScrollTo;
299
+ private _execShowToast;
300
+ private _execAskConfirm;
301
+ private _execOpenModal;
302
+ private _execCloseModal;
303
+ private _execEnable;
304
+ private _execDisable;
305
+ startAlwaysListening(): Promise<void>;
306
+ stopAlwaysListening(): void;
307
+ startRecording(): Promise<void>;
308
+ stopRecording(): void;
309
+ interrupt(): void;
310
+ private _openVoiceWs;
311
+ private _closeVoiceWs;
312
+ private _resetTtsState;
313
+ private _onVoiceStreamMessage;
314
+ private _onPlaybackComplete;
315
+ private _finalizeTts;
316
+ private _addMessage;
317
+ clearMessages(): void;
318
+ private _onDone;
319
+ private _onError;
320
+ private _scheduleReconnect;
321
+ private _sleep;
322
+ destroy(): void;
323
+ }
324
+
325
+ interface VocallProviderProps {
326
+ serverUrl: string;
327
+ token?: string;
328
+ visitorId?: string;
329
+ children: React.ReactNode;
330
+ }
331
+ declare function VocallProvider({ serverUrl, token, visitorId, children }: VocallProviderProps): react_jsx_runtime.JSX.Element;
332
+ declare function useVocallClient(): VocallClient;
333
+
334
+ interface UseVocallReturn {
335
+ client: ReturnType<typeof useVocallClient>;
336
+ status: VocallStatus;
337
+ messages: readonly ChatMessage[];
338
+ connected: boolean;
339
+ sessionId: string | null;
340
+ voiceEnabled: boolean;
341
+ voiceSupported: boolean;
342
+ voiceState: VoiceState$1;
343
+ recording: boolean;
344
+ partialTranscription: string | null;
345
+ sendText: (text: string) => void;
346
+ connect: (manifest: ManifestMessage) => void;
347
+ disconnect: () => void;
348
+ clearMessages: () => void;
349
+ }
350
+ declare function useVocall(): UseVocallReturn;
351
+
352
+ interface UseVocallFieldReturn {
353
+ /** Attach to the field element via ref={ref} */
354
+ ref: (element: HTMLElement | null) => void;
355
+ /** Whether the field is currently registered with the client */
356
+ registered: boolean;
357
+ }
358
+ declare function useVocallField(screenId: string, fieldId: string, options?: {
359
+ /** Custom setter (e.g. for React state-controlled inputs) */
360
+ setValue?: (value: string) => void;
361
+ /** Custom getter */
362
+ getValue?: () => string;
363
+ }): UseVocallFieldReturn;
364
+
365
+ /**
366
+ * Registers an action callback with the Vocall client.
367
+ *
368
+ * @param screenId - Screen that owns this action
369
+ * @param actionId - Action identifier (matches manifest)
370
+ * @param callback - Function invoked when the server sends a `click` command
371
+ */
372
+ declare function useVocallAction(screenId: string, actionId: string, callback: ActionCallback): void;
373
+
374
+ declare class FrameSplitter {
375
+ private readonly frameSizeBytes;
376
+ private buffer;
377
+ private offset;
378
+ constructor(frameSizeBytes?: number);
379
+ /**
380
+ * Feed arbitrary-length PCM bytes into the splitter.
381
+ * Whenever a full frame is assembled, `emit` is called with a copy.
382
+ */
383
+ feed(pcmBytes: Uint8Array, emit: (frame: Uint8Array) => void): void;
384
+ /** Reset the internal buffer, discarding any partial frame. */
385
+ reset(): void;
386
+ /** Number of bytes currently buffered (incomplete frame). */
387
+ get buffered(): number;
388
+ }
389
+
390
+ type AudioLevelCallback = (level: number) => void;
391
+ interface VoiceService {
392
+ /** Whether the browser supports getUserMedia / Web Audio API. */
393
+ readonly isSupported: boolean;
394
+ /** Whether audio capture is currently active. */
395
+ readonly isCapturing: boolean;
396
+ /** Whether audio playback is currently active. */
397
+ readonly isPlaying: boolean;
398
+ /** Whether monitor-only mode is active (capture without sending). */
399
+ readonly isMonitoring: boolean;
400
+ /** Called with the current RMS audio level (0-1) during capture. */
401
+ onAudioLevel: AudioLevelCallback | null;
402
+ /** Called when all queued audio chunks have finished playing. */
403
+ onPlaybackComplete: (() => void) | null;
404
+ /**
405
+ * Start capturing audio from the microphone.
406
+ * PCM S16LE 16kHz mono frames are delivered via `sendChunk`.
407
+ */
408
+ startCapture(sendChunk: (chunk: Uint8Array) => void): Promise<void>;
409
+ /** Stop capturing audio. */
410
+ stopCapture(): void;
411
+ /** Start monitor mode: capture pipeline runs but no data is sent. */
412
+ startMonitor(): Promise<void>;
413
+ /** Stop monitor mode. */
414
+ stopMonitor(): void;
415
+ /** Mute or unmute the microphone track. When muted, silent frames are sent. */
416
+ muteMic(muted: boolean): void;
417
+ /** Play a WAV audio chunk via the Web Audio API. Queues if already playing. */
418
+ playAudio(wavData: Uint8Array): void;
419
+ /** Stop all playback immediately. */
420
+ stopPlayback(): void;
421
+ /** Release all resources (streams, AudioContext, etc.). */
422
+ dispose(): void;
423
+ }
424
+
425
+ declare class WebVoiceService implements VoiceService {
426
+ onAudioLevel: AudioLevelCallback | null;
427
+ onPlaybackComplete: (() => void) | null;
428
+ private _isCapturing;
429
+ private _isPlaying;
430
+ private _isMonitoring;
431
+ private _isMuted;
432
+ get isSupported(): boolean;
433
+ get isCapturing(): boolean;
434
+ get isPlaying(): boolean;
435
+ get isMonitoring(): boolean;
436
+ private _audioCtx;
437
+ private _stream;
438
+ private _sourceNode;
439
+ private _scriptNode;
440
+ private _splitter;
441
+ private _sendChunk;
442
+ private _playbackCtx;
443
+ private _playbackQueue;
444
+ private _currentSource;
445
+ private _pendingDecodes;
446
+ startCapture(sendChunk: (chunk: Uint8Array) => void): Promise<void>;
447
+ stopCapture(): void;
448
+ startMonitor(): Promise<void>;
449
+ stopMonitor(): void;
450
+ muteMic(muted: boolean): void;
451
+ playAudio(wavData: Uint8Array): void;
452
+ stopPlayback(): void;
453
+ dispose(): void;
454
+ private _initCapturePipeline;
455
+ private _teardownCapturePipeline;
456
+ /**
457
+ * Downsample Float32 audio at native sample rate to S16LE at TARGET_SAMPLE_RATE
458
+ * using linear interpolation.
459
+ */
460
+ private _downsampleToS16LE;
461
+ /**
462
+ * Compute RMS level from Float32 audio samples.
463
+ * Result is scaled by 4 and clamped to [0, 1].
464
+ */
465
+ private _computeAndEmitLevel;
466
+ private _decodeAndEnqueue;
467
+ private _applyFadeIn;
468
+ private _playBuffer;
469
+ private _playNextChunk;
470
+ private _checkPlaybackComplete;
471
+ }
472
+
473
+ type VoiceState = 'idle' | 'listening' | 'recording' | 'thinking' | 'speaking';
474
+ interface UseVocallVoiceReturn {
475
+ /** Whether the server indicated voice is available for this session. */
476
+ voiceEnabled: boolean;
477
+ /** Current state of the voice state machine. */
478
+ voiceState: VoiceState;
479
+ /** Whether audio is currently being captured (direct mode). */
480
+ recording: boolean;
481
+ /** Partial transcription text from the server (live). */
482
+ partialTranscription: string | null;
483
+ /** Current microphone audio level (0-1). */
484
+ audioLevel: number;
485
+ /** Start always-listening mode (wake-word activated). */
486
+ startAlwaysListening: () => Promise<void>;
487
+ /** Stop always-listening mode. */
488
+ stopAlwaysListening: () => void;
489
+ /** Start direct recording (click-to-talk). */
490
+ startRecording: () => Promise<void>;
491
+ /** Stop direct recording and send EOF. */
492
+ stopRecording: () => void;
493
+ /** Interrupt TTS playback and notify the server. */
494
+ interrupt: () => void;
495
+ }
496
+ declare function useVocallVoice(): UseVocallVoiceReturn;
497
+
498
+ interface VocallChatProps {
499
+ /** Whether the chat panel is visible */
500
+ open: boolean;
501
+ /** Called when the user requests to close the panel */
502
+ onClose?: () => void;
503
+ /** Assistant name displayed in the header */
504
+ assistantName?: string;
505
+ /** CSS class for the container */
506
+ className?: string;
507
+ /** Inline styles for the container */
508
+ style?: React.CSSProperties;
509
+ }
510
+ declare function VocallChat({ open, onClose, assistantName, className, style, }: VocallChatProps): react_jsx_runtime.JSX.Element | null;
511
+
512
+ interface VocallFabProps {
513
+ /** Called when the FAB is clicked */
514
+ onClick?: () => void;
515
+ /** CSS class */
516
+ className?: string;
517
+ /** Inline styles */
518
+ style?: React.CSSProperties;
519
+ }
520
+ declare function VocallFab({ onClick, className, style }: VocallFabProps): react_jsx_runtime.JSX.Element;
521
+
522
+ interface VocallStatusProps {
523
+ /** CSS class */
524
+ className?: string;
525
+ /** Inline styles */
526
+ style?: React.CSSProperties;
527
+ }
528
+ declare function VocallStatusPill({ className, style }: VocallStatusProps): react_jsx_runtime.JSX.Element | null;
529
+
530
+ export { type ActionCallback, type ActionDescriptor, type ActionResult, type AudioLevelCallback, type ChatEndOut, type ChatMessage, type ChatMessageOut, ChatRole, type ChatTokenOut, type CommandMessage, type ConfigResponse, type ConfirmCallback, type ConfirmMessage, type ErrorOut, type FeaturesConfig, type FieldDescriptor, type FieldEntry, type FieldState, FieldType, FrameSplitter, type ManifestMessage, type ModalCloseCallback, type ModalDescriptor, type ModalOpenCallback, type NavigateCallback, type Persona, type ResultMessage, type ScreenDescriptor, type SelectOption, type ServerMessage, type StateMessage, type StatusOut, type TextMessage, type ToastCallback, type UIAction, type UseVocallFieldReturn, type UseVocallReturn, type UseVocallVoiceReturn, type UserInfo, type VocallChangeListener, VocallChat, type VocallChatProps, VocallClient, VocallFab, type VocallFabProps, VocallProvider, type VocallProviderProps, VocallStatus, VocallStatusPill, type VocallStatusProps, type VoiceService, type VoiceState$1 as VoiceState, WebVoiceService, useVocall, useVocallAction, useVocallClient, useVocallField, useVocallVoice };