@hamsa-ai/voice-agents-sdk 0.4.0-beta.9 → 0.4.1-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hamsa-ai/voice-agents-sdk",
3
- "version": "0.4.0-beta.9",
3
+ "version": "0.4.1-beta.1",
4
4
  "description": "Hamsa AI - Voice Agents JavaScript SDK",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -26,7 +26,8 @@
26
26
  "build": "npm run clean && npm run build:types && npm run build:rollup",
27
27
  "test": "jest",
28
28
  "test:watch": "jest --watch",
29
- "prepare": "npm run build"
29
+ "prepare": "npm run build",
30
+ "tag:push": "VERSION=$(node -p \"require('./package.json').version\") && TAG=v$VERSION && git fetch --tags -q && if git rev-parse -q --verify \"refs/tags/$TAG\" >/dev/null; then echo \"Tag $TAG already exists locally.\"; else git tag -a \"$TAG\" -m \"Release $TAG\"; fi && if git ls-remote --exit-code --tags origin \"$TAG\" >/dev/null 2>&1; then echo \"Tag $TAG already exists on origin.\"; else git push origin \"$TAG\"; fi && echo \"Done: $TAG\""
30
31
  },
31
32
  "author": "Hamsa AI Inc.",
32
33
  "license": "MIT",
@@ -166,6 +166,22 @@ export declare class LiveKitAnalytics extends EventEmitter {
166
166
  private room;
167
167
  /** Current connection state flag for controlling analytics collection */
168
168
  private isConnected;
169
+ /** Last recorded user audio level for dropout detection */
170
+ private lastUserAudioLevel;
171
+ /** Last recorded agent audio level for dropout detection */
172
+ private lastAgentAudioLevel;
173
+ /** Timestamp when user audio level dropped below threshold */
174
+ private userDropoutStartTime;
175
+ /** Timestamp when agent audio level dropped below threshold */
176
+ private agentDropoutStartTime;
177
+ /** Timestamp when user started speaking (VAD-based) */
178
+ private vadUserSpeakStart;
179
+ /** Timestamp when agent started speaking (VAD-based) */
180
+ private vadAgentSpeakStart;
181
+ /** Timestamp when user input was detected (for response time measurement) */
182
+ private lastUserInputTime;
183
+ /** Previous connection quality for jitter change detection (internal) */
184
+ private previousConnectionQuality;
169
185
  /**
170
186
  * Creates a new LiveKitAnalytics instance
171
187
  *
@@ -346,7 +362,7 @@ export declare class LiveKitAnalytics extends EventEmitter {
346
362
  */
347
363
  handleAudioPlaybackChanged(playing: boolean): void;
348
364
  /**
349
- * Gets current connection statistics
365
+ * Gets current connection statistics (customer-facing - verified data only)
350
366
  */
351
367
  getConnectionStats(): ConnectionStatsResult;
352
368
  /**
@@ -354,15 +370,57 @@ export declare class LiveKitAnalytics extends EventEmitter {
354
370
  */
355
371
  getAudioLevels(): AudioLevelsResult;
356
372
  /**
357
- * Gets current performance metrics
373
+ * Gets current performance metrics (customer-facing - verified data only)
358
374
  */
359
375
  getPerformanceMetrics(): PerformanceMetricsResult;
360
376
  /**
361
- * Gets comprehensive call analytics
377
+ * Manually records response time for agent interactions
378
+ *
379
+ * @param responseTime - Response time in milliseconds
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * // Record custom response time measurement
384
+ * const startTime = Date.now();
385
+ * // ... agent processing ...
386
+ * const responseTime = Date.now() - startTime;
387
+ * analytics.recordResponseTime(responseTime);
388
+ * ```
389
+ */
390
+ recordResponseTime(responseTime: number): void;
391
+ /**
392
+ * Gets current voice activity detection thresholds
393
+ */
394
+ getVADSettings(): {
395
+ audioThreshold: number;
396
+ minSpeakingDuration: number;
397
+ dropoutThreshold: number;
398
+ dropoutDetectionDuration: number;
399
+ };
400
+ /**
401
+ * Gets comprehensive call analytics (customer-facing - verified data only)
362
402
  */
363
403
  getCallAnalytics(participants: ParticipantData[], trackStats: TrackStatsResult, volume: number, isPaused: boolean): CallAnalyticsResult & {
364
404
  callDuration: number;
365
405
  };
406
+ /**
407
+ * Gets full connection statistics including estimated metrics (internal use only)
408
+ * @internal
409
+ */
410
+ getInternalConnectionStats(): ConnectionMetrics & {
411
+ connectionAttempts: number;
412
+ reconnectionAttempts: number;
413
+ connectionEstablishedTime: number;
414
+ isConnected: boolean;
415
+ };
416
+ /**
417
+ * Gets full performance metrics including estimated network latency (internal use only)
418
+ * @internal
419
+ */
420
+ getInternalPerformanceMetrics(): PerformanceMetrics & {
421
+ callDuration: number;
422
+ averageResponseTime: number;
423
+ };
366
424
  /**
367
425
  * Cleans up analytics resources
368
426
  */
@@ -314,14 +314,14 @@ export default class LiveKitManager extends EventEmitter {
314
314
  /**
315
315
  * Retrieves current network connection statistics and quality metrics
316
316
  *
317
- * @returns Object containing latency, packet loss, bandwidth, quality rating, and connection counts
317
+ * @returns Object containing connection quality, connection counts, and timing data
318
318
  *
319
319
  * @example
320
320
  * ```typescript
321
321
  * const stats = manager.getConnectionStats();
322
- * console.log(`Latency: ${stats.latency}ms`);
323
- * console.log(`Packet loss: ${stats.packetLoss}%`);
324
322
  * console.log(`Connection quality: ${stats.quality}`);
323
+ * console.log(`Connection attempts: ${stats.connectionAttempts}`);
324
+ * console.log(`Reconnections: ${stats.reconnectionAttempts}`);
325
325
  *
326
326
  * if (stats.quality === 'poor') {
327
327
  * showNetworkWarning();
@@ -354,7 +354,7 @@ export default class LiveKitManager extends EventEmitter {
354
354
  /**
355
355
  * Retrieves current performance metrics including response times and call duration
356
356
  *
357
- * @returns Object containing response times, network latency, call duration, and connection timing
357
+ * @returns Object containing response times, call duration, and connection timing
358
358
  *
359
359
  * @example
360
360
  * ```typescript
@@ -442,7 +442,7 @@ export default class LiveKitManager extends EventEmitter {
442
442
  * });
443
443
  *
444
444
  * // Check for quality issues
445
- * if (analytics.connectionStats.packetLoss > 5) {
445
+ * if (analytics.connectionStats.quality === 'poor') {
446
446
  * reportNetworkIssue(analytics.connectionStats);
447
447
  * }
448
448
  * ```
@@ -178,7 +178,7 @@
178
178
  * - Includes automatic cleanup and resource management
179
179
  */
180
180
  import { EventEmitter } from 'events';
181
- import { type Room } from 'livekit-client';
181
+ import type { Room } from 'livekit-client';
182
182
  import type { Tool } from './types';
183
183
  /**
184
184
  * LiveKitToolRegistry class for client-side tool management and RPC handling
@@ -445,71 +445,6 @@ export declare class LiveKitToolRegistry extends EventEmitter {
445
445
  text?: string;
446
446
  final?: boolean;
447
447
  }>): void;
448
- /**
449
- * Provides access to the local microphone audio stream for external processing
450
- *
451
- * Retrieves the local participant's microphone track and creates a MediaStream
452
- * for external audio processing applications. This enables advanced integrations
453
- * such as real-time audio analysis, recording, or additional audio effects
454
- * processing outside of the LiveKit pipeline.
455
- *
456
- * @fires localAudioStreamAvailable When local audio stream is successfully extracted
457
- *
458
- * @example
459
- * ```typescript
460
- * // Listen for local audio stream availability
461
- * registry.on('localAudioStreamAvailable', (stream) => {
462
- * console.log('Local audio stream is available');
463
- *
464
- * // Set up real-time audio analysis
465
- * const audioAnalyzer = new AudioAnalyzer(stream);
466
- * audioAnalyzer.on('volumeLevel', (level) => {
467
- * updateVolumeIndicator(level);
468
- * });
469
- *
470
- * // Enable noise gate functionality
471
- * const noiseGate = new NoiseGate(stream);
472
- * noiseGate.threshold = -40; // dB
473
- *
474
- * // Record conversation for quality assurance
475
- * if (recordingEnabled) {
476
- * const mediaRecorder = new MediaRecorder(stream);
477
- * mediaRecorder.start();
478
- *
479
- * mediaRecorder.ondataavailable = (event) => {
480
- * saveAudioChunk(event.data);
481
- * };
482
- * }
483
- * });
484
- *
485
- * // Call after connection is established
486
- * registry.emitLocalAudioStream();
487
- * ```
488
- *
489
- * @example Audio Processing Pipeline
490
- * ```typescript
491
- * registry.on('localAudioStreamAvailable', (stream) => {
492
- * // Create audio context for advanced processing
493
- * const audioContext = new AudioContext();
494
- * const source = audioContext.createMediaStreamSource(stream);
495
- *
496
- * // Add audio effects
497
- * const gainNode = audioContext.createGain();
498
- * const filterNode = audioContext.createBiquadFilter();
499
- *
500
- * // Connect processing chain
501
- * source.connect(gainNode);
502
- * gainNode.connect(filterNode);
503
- * filterNode.connect(audioContext.destination);
504
- *
505
- * // Configure effects
506
- * gainNode.gain.value = 1.2;
507
- * filterNode.type = 'highpass';
508
- * filterNode.frequency.value = 80;
509
- * });
510
- * ```
511
- */
512
- emitLocalAudioStream(): void;
513
448
  /**
514
449
  * Returns the count of currently registered tools
515
450
  *
@@ -98,18 +98,18 @@ export type CallStats = {
98
98
  };
99
99
  /**
100
100
  * Real-time network connection quality metrics.
101
- * Provides detailed information about network performance and reliability.
101
+ * Internal structure includes estimated values for future use.
102
102
  */
103
103
  export type ConnectionMetrics = {
104
- /** Current network latency in milliseconds */
104
+ /** Current network latency in milliseconds (internal - estimated) */
105
105
  latency: number;
106
- /** Packet loss percentage (0.0 to 100.0) */
106
+ /** Packet loss percentage (internal - estimated) */
107
107
  packetLoss: number;
108
- /** Current bandwidth usage in bytes per second */
108
+ /** Current bandwidth usage in bytes per second (internal - estimated) */
109
109
  bandwidth: number;
110
110
  /** Qualitative assessment of connection ('excellent', 'good', 'poor', 'lost') */
111
111
  quality: string;
112
- /** Network jitter measurement in milliseconds */
112
+ /** Network jitter measurement in milliseconds (internal - estimated) */
113
113
  jitter: number;
114
114
  };
115
115
  /**
@@ -132,12 +132,12 @@ export type AudioMetrics = {
132
132
  };
133
133
  /**
134
134
  * Performance metrics tracking response times and connection reliability.
135
- * Measures various aspects of system and network performance.
135
+ * Internal structure includes estimated network latency for future use.
136
136
  */
137
137
  export type PerformanceMetrics = {
138
138
  /** Total response time for agent interactions in milliseconds */
139
139
  responseTime: number;
140
- /** Current network latency measurement in milliseconds */
140
+ /** Current network latency measurement in milliseconds (internal - estimated) */
141
141
  networkLatency: number;
142
142
  /** Time taken to establish the initial connection in milliseconds */
143
143
  connectionEstablishedTime: number;
@@ -146,19 +146,11 @@ export type PerformanceMetrics = {
146
146
  };
147
147
  /**
148
148
  * Complete connection statistics result returned by getConnectionStats().
149
- * Combines real-time metrics with historical connection data.
149
+ * Only includes verified data - no estimated metrics exposed to customers.
150
150
  */
151
151
  export type ConnectionStatsResult = {
152
- /** Current network latency in milliseconds */
153
- latency: number;
154
- /** Current packet loss percentage */
155
- packetLoss: number;
156
- /** Current bandwidth usage in bytes per second */
157
- bandwidth: number;
158
- /** Current connection quality assessment */
152
+ /** Current connection quality assessment from LiveKit */
159
153
  quality: string;
160
- /** Current network jitter in milliseconds */
161
- jitter: number;
162
154
  /** Total connection attempts made */
163
155
  connectionAttempts: number;
164
156
  /** Total reconnection attempts made */
@@ -196,13 +188,11 @@ export type AudioLevelsResult = {
196
188
  };
197
189
  /**
198
190
  * Complete performance metrics result returned by getPerformanceMetrics().
199
- * Provides comprehensive system and network performance data.
191
+ * Only includes verified performance data - no estimated metrics exposed.
200
192
  */
201
193
  export type PerformanceMetricsResult = {
202
194
  /** Total response time in milliseconds */
203
195
  responseTime: number;
204
- /** Current network latency in milliseconds */
205
- networkLatency: number;
206
196
  /** Connection establishment time in milliseconds */
207
197
  connectionEstablishedTime: number;
208
198
  /** Total reconnection count */
@@ -264,10 +254,8 @@ export type ConnectionQualityData = {
264
254
  quality: ConnectionQuality;
265
255
  /** Identity of the participant this quality measurement applies to */
266
256
  participant: string;
267
- /** Detailed connection metrics including latency, packet loss, etc. */
257
+ /** Connection quality string from LiveKit (estimated metrics available internally) */
268
258
  metrics: {
269
- latency: number;
270
- packetLoss: number;
271
259
  quality: string;
272
260
  };
273
261
  };
package/types/main.d.ts CHANGED
@@ -1,6 +1,16 @@
1
1
  import { EventEmitter } from 'events';
2
+ import type { Room } from 'livekit-client';
2
3
  import LiveKitManager, { type AudioLevelsResult, type CallAnalyticsResult, type ConnectionStatsResult, type ParticipantData, type PerformanceMetricsResult, type TrackStatsResult } from './classes/livekit-manager';
3
4
  import ScreenWakeLock from './classes/screen-wake-lock';
5
+ /**
6
+ * Custom error class that includes both human-readable message and machine-readable messageKey
7
+ * for internationalization and programmatic error handling
8
+ */
9
+ declare class HamsaApiError extends Error {
10
+ /** Machine-readable error key for i18n or programmatic handling */
11
+ readonly messageKey?: string;
12
+ constructor(message: string, messageKey?: string);
13
+ }
4
14
  /**
5
15
  * Configuration options for the HamsaVoiceAgent constructor
6
16
  * Allows customization of API endpoints and other global settings
@@ -164,6 +174,32 @@ type JobDetails = {
164
174
  * // Get analytics snapshot anytime
165
175
  * const analytics = agent.getCallAnalytics();
166
176
  * ```
177
+ *
178
+ * @example Track-based Audio Processing
179
+ * ```typescript
180
+ * // Handle incoming audio tracks from voice agent
181
+ * agent.on('trackSubscribed', ({ track, publication, participant }) => {
182
+ * if (track.kind === 'audio') {
183
+ * // Option 1: Attach to DOM element (LiveKit way)
184
+ * track.attach(audioElement);
185
+ *
186
+ * // Option 2: Create MediaStream for custom processing
187
+ * const stream = new MediaStream([track.mediaStreamTrack]);
188
+ * const audioContext = new AudioContext();
189
+ * const source = audioContext.createMediaStreamSource(stream);
190
+ * // Add custom audio processing...
191
+ * }
192
+ * });
193
+ *
194
+ * // Handle local audio track availability
195
+ * agent.on('localTrackPublished', ({ track, publication }) => {
196
+ * if (track && track.source === 'microphone') {
197
+ * // Access local microphone track for recording/analysis
198
+ * const stream = new MediaStream([track.mediaStreamTrack]);
199
+ * setupVoiceAnalyzer(stream);
200
+ * }
201
+ * });
202
+ * ```
167
203
  */
168
204
  declare class HamsaVoiceAgent extends EventEmitter {
169
205
  #private;
@@ -181,6 +217,8 @@ declare class HamsaVoiceAgent extends EventEmitter {
181
217
  jobId: string | null;
182
218
  /** Screen wake lock manager to prevent device sleep during calls */
183
219
  wakeLockManager: ScreenWakeLock;
220
+ /** Flag to track if the user initiated the call end */
221
+ private userInitiatedEnd;
184
222
  /**
185
223
  * Creates a new HamsaVoiceAgent instance
186
224
  *
@@ -710,6 +748,41 @@ declare class HamsaVoiceAgent extends EventEmitter {
710
748
  * ```
711
749
  */
712
750
  getCallAnalytics(): CallAnalyticsResult | null;
751
+ /**
752
+ * Gets the LiveKit Room instance for React SDK integration
753
+ *
754
+ * Provides access to the underlying LiveKit Room object for use with
755
+ * LiveKit React components. This enables integration with the broader
756
+ * LiveKit React ecosystem while maintaining the benefits of the
757
+ * HamsaVoiceAgent abstraction.
758
+ *
759
+ * @internal - For use by @hamsa-ai/voice-agents-react only
760
+ * @returns LiveKit Room instance or null if not connected
761
+ *
762
+ * @example React SDK Integration
763
+ * ```typescript
764
+ * import { RoomContext } from '@livekit/components-react';
765
+ *
766
+ * function VoiceProvider({ agent, children }) {
767
+ * const [room, setRoom] = useState(null);
768
+ *
769
+ * useEffect(() => {
770
+ * agent.on('callStarted', () => {
771
+ * setRoom(agent.getRoom());
772
+ * });
773
+ * }, [agent]);
774
+ *
775
+ * if (!room) return children;
776
+ *
777
+ * return (
778
+ * <RoomContext.Provider value={room}>
779
+ * {children}
780
+ * </RoomContext.Provider>
781
+ * );
782
+ * }
783
+ * ```
784
+ */
785
+ getRoom(): Room | null;
713
786
  }
714
- export { HamsaVoiceAgent };
787
+ export { HamsaVoiceAgent, HamsaApiError };
715
788
  export default HamsaVoiceAgent;