modular-voice-agent-sdk 2.5.1 → 2.6.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 (50) hide show
  1. package/dist/backends/agent/llm.d.ts.map +1 -1
  2. package/dist/backends/agent/llm.js +0 -4
  3. package/dist/backends/agent/llm.js.map +1 -1
  4. package/dist/backends/cloud/llm.d.ts.map +1 -1
  5. package/dist/backends/cloud/llm.js +2 -13
  6. package/dist/backends/cloud/llm.js.map +1 -1
  7. package/dist/backends/native/llm.d.ts.map +1 -1
  8. package/dist/backends/native/llm.js +0 -2
  9. package/dist/backends/native/llm.js.map +1 -1
  10. package/dist/backends/native/tts.d.ts.map +1 -1
  11. package/dist/backends/native/tts.js +0 -3
  12. package/dist/backends/native/tts.js.map +1 -1
  13. package/dist/backends/transformers/llm.d.ts.map +1 -1
  14. package/dist/backends/transformers/llm.js +0 -2
  15. package/dist/backends/transformers/llm.js.map +1 -1
  16. package/dist/backends/transformers/stt.d.ts.map +1 -1
  17. package/dist/backends/transformers/stt.js +0 -2
  18. package/dist/backends/transformers/stt.js.map +1 -1
  19. package/dist/backends/transformers/tts.d.ts.map +1 -1
  20. package/dist/backends/transformers/tts.js +0 -2
  21. package/dist/backends/transformers/tts.js.map +1 -1
  22. package/dist/client/index.d.ts +4 -0
  23. package/dist/client/index.d.ts.map +1 -1
  24. package/dist/client/index.js +2 -0
  25. package/dist/client/index.js.map +1 -1
  26. package/dist/client/transport.d.ts +58 -0
  27. package/dist/client/transport.d.ts.map +1 -0
  28. package/dist/client/transport.js +15 -0
  29. package/dist/client/transport.js.map +1 -0
  30. package/dist/client/transports/http-sse.d.ts +69 -0
  31. package/dist/client/transports/http-sse.d.ts.map +1 -0
  32. package/dist/client/transports/http-sse.js +134 -0
  33. package/dist/client/transports/http-sse.js.map +1 -0
  34. package/dist/client/transports/index.d.ts +4 -0
  35. package/dist/client/transports/index.d.ts.map +1 -0
  36. package/dist/client/transports/index.js +3 -0
  37. package/dist/client/transports/index.js.map +1 -0
  38. package/dist/client/transports/websocket.d.ts +29 -0
  39. package/dist/client/transports/websocket.d.ts.map +1 -0
  40. package/dist/client/transports/websocket.js +79 -0
  41. package/dist/client/transports/websocket.js.map +1 -0
  42. package/dist/client/voice-client.d.ts +38 -14
  43. package/dist/client/voice-client.d.ts.map +1 -1
  44. package/dist/client/voice-client.js +58 -47
  45. package/dist/client/voice-client.js.map +1 -1
  46. package/dist/services/llm-logger.d.ts +4 -43
  47. package/dist/services/llm-logger.d.ts.map +1 -1
  48. package/dist/services/llm-logger.js +24 -121
  49. package/dist/services/llm-logger.js.map +1 -1
  50. package/package.json +1 -1
@@ -0,0 +1,134 @@
1
+ /**
2
+ * HTTP + SSE Transport
3
+ *
4
+ * Transport that uses HTTP POST for client→server messages and
5
+ * Server-Sent Events (SSE) for server→client streaming.
6
+ *
7
+ * Useful for:
8
+ * - Environments where WebSocket isn't available or is blocked
9
+ * - Simpler server setups (standard HTTP endpoints)
10
+ * - Serverless/edge deployments that don't support long-lived connections
11
+ * - Debugging (HTTP requests are easier to inspect)
12
+ *
13
+ * Protocol:
14
+ * - POST /session → creates a session, returns { sessionId }
15
+ * - GET /events?sessionId=xxx → SSE stream of ServerEnvelope events
16
+ * - POST /message → sends a ClientEnvelope to the server
17
+ *
18
+ * Audio considerations:
19
+ * - Works best for text-only or hybrid (client-side STT/TTS) modes
20
+ * - Audio chunks are accumulated and sent as POST requests
21
+ * - Higher latency than WebSocket for real-time audio streaming
22
+ */
23
+ export class HttpSseTransport {
24
+ state = 'closed';
25
+ sessionId = null;
26
+ eventSource = null;
27
+ messageHandler = null;
28
+ errorHandler = null;
29
+ closeHandler = null;
30
+ baseUrl;
31
+ sessionPath;
32
+ eventsPath;
33
+ messagePath;
34
+ headers;
35
+ constructor(config) {
36
+ if (typeof config === 'string') {
37
+ config = { baseUrl: config };
38
+ }
39
+ // Strip trailing slash
40
+ this.baseUrl = config.baseUrl.replace(/\/$/, '');
41
+ this.sessionPath = config.sessionPath ?? '/session';
42
+ this.eventsPath = config.eventsPath ?? '/events';
43
+ this.messagePath = config.messagePath ?? '/message';
44
+ this.headers = config.headers ?? {};
45
+ }
46
+ get readyState() {
47
+ return this.state;
48
+ }
49
+ async connect() {
50
+ if (this.state === 'open')
51
+ return;
52
+ this.state = 'connecting';
53
+ try {
54
+ // Step 1: Create a session via POST
55
+ const response = await fetch(`${this.baseUrl}${this.sessionPath}`, {
56
+ method: 'POST',
57
+ headers: {
58
+ 'Content-Type': 'application/json',
59
+ ...this.headers,
60
+ },
61
+ });
62
+ if (!response.ok) {
63
+ throw new Error(`Session creation failed: ${response.status} ${response.statusText}`);
64
+ }
65
+ const data = await response.json();
66
+ this.sessionId = data.sessionId;
67
+ // Step 2: Open SSE stream for server→client messages
68
+ await this.connectEventSource();
69
+ this.state = 'open';
70
+ }
71
+ catch (error) {
72
+ this.state = 'closed';
73
+ throw error;
74
+ }
75
+ }
76
+ connectEventSource() {
77
+ return new Promise((resolve, reject) => {
78
+ const url = `${this.baseUrl}${this.eventsPath}?sessionId=${encodeURIComponent(this.sessionId)}`;
79
+ this.eventSource = new EventSource(url);
80
+ this.eventSource.onopen = () => {
81
+ resolve();
82
+ };
83
+ this.eventSource.onmessage = (event) => {
84
+ try {
85
+ const envelope = JSON.parse(event.data);
86
+ this.messageHandler?.(envelope);
87
+ }
88
+ catch {
89
+ this.errorHandler?.(new Error('Failed to parse SSE message'));
90
+ }
91
+ };
92
+ this.eventSource.onerror = () => {
93
+ if (this.state === 'connecting') {
94
+ reject(new Error('SSE connection failed'));
95
+ }
96
+ else if (this.state === 'open') {
97
+ this.state = 'closed';
98
+ this.errorHandler?.(new Error('SSE connection lost'));
99
+ this.closeHandler?.();
100
+ }
101
+ };
102
+ });
103
+ }
104
+ send(envelope) {
105
+ if (this.state !== 'open')
106
+ return;
107
+ fetch(`${this.baseUrl}${this.messagePath}`, {
108
+ method: 'POST',
109
+ headers: {
110
+ 'Content-Type': 'application/json',
111
+ ...this.headers,
112
+ },
113
+ body: JSON.stringify(envelope),
114
+ }).catch((error) => {
115
+ this.errorHandler?.(error instanceof Error ? error : new Error(String(error)));
116
+ });
117
+ }
118
+ onMessage(handler) {
119
+ this.messageHandler = handler;
120
+ }
121
+ onError(handler) {
122
+ this.errorHandler = handler;
123
+ }
124
+ onClose(handler) {
125
+ this.closeHandler = handler;
126
+ }
127
+ close() {
128
+ this.eventSource?.close();
129
+ this.eventSource = null;
130
+ this.sessionId = null;
131
+ this.state = 'closed';
132
+ }
133
+ }
134
+ //# sourceMappingURL=http-sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-sse.js","sourceRoot":"","sources":["../../../src/client/transports/http-sse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { WebSocketTransport } from './websocket';
2
+ export { HttpSseTransport } from './http-sse';
3
+ export type { HttpSseTransportConfig } from './http-sse';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/transports/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { WebSocketTransport } from './websocket';
2
+ export { HttpSseTransport } from './http-sse';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/transports/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * WebSocket Transport
3
+ *
4
+ * Standard WebSocket-based transport for voice pipeline communication.
5
+ * This is the default transport used by VoiceClient when a serverUrl is provided.
6
+ *
7
+ * Features:
8
+ * - Full-duplex communication
9
+ * - Real-time audio streaming
10
+ * - Low latency
11
+ */
12
+ import type { ClientEnvelope, ServerEnvelope } from '../protocol';
13
+ import type { Transport, TransportState } from '../transport';
14
+ export declare class WebSocketTransport implements Transport {
15
+ private url;
16
+ private ws;
17
+ private messageHandler;
18
+ private errorHandler;
19
+ private closeHandler;
20
+ constructor(url: string);
21
+ get readyState(): TransportState;
22
+ connect(): Promise<void>;
23
+ send(envelope: ClientEnvelope): void;
24
+ onMessage(handler: (envelope: ServerEnvelope) => void): void;
25
+ onError(handler: (error: Error) => void): void;
26
+ onClose(handler: () => void): void;
27
+ close(): void;
28
+ }
29
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/client/transports/websocket.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9D,qBAAa,kBAAmB,YAAW,SAAS;IAMtC,OAAO,CAAC,GAAG;IALvB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,cAAc,CAAqD;IAC3E,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,YAAY,CAA6B;gBAE7B,GAAG,EAAE,MAAM;IAE/B,IAAI,UAAU,IAAI,cAAc,CAO/B;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC9B,IAAI,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAMpC,SAAS,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAI5D,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAI9C,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIlC,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * WebSocket Transport
3
+ *
4
+ * Standard WebSocket-based transport for voice pipeline communication.
5
+ * This is the default transport used by VoiceClient when a serverUrl is provided.
6
+ *
7
+ * Features:
8
+ * - Full-duplex communication
9
+ * - Real-time audio streaming
10
+ * - Low latency
11
+ */
12
+ export class WebSocketTransport {
13
+ url;
14
+ ws = null;
15
+ messageHandler = null;
16
+ errorHandler = null;
17
+ closeHandler = null;
18
+ constructor(url) {
19
+ this.url = url;
20
+ }
21
+ get readyState() {
22
+ if (!this.ws)
23
+ return 'closed';
24
+ switch (this.ws.readyState) {
25
+ case WebSocket.CONNECTING: return 'connecting';
26
+ case WebSocket.OPEN: return 'open';
27
+ default: return 'closed';
28
+ }
29
+ }
30
+ async connect() {
31
+ if (this.ws?.readyState === WebSocket.OPEN)
32
+ return;
33
+ return new Promise((resolve, reject) => {
34
+ this.ws = new WebSocket(this.url);
35
+ this.ws.onopen = () => {
36
+ resolve();
37
+ };
38
+ this.ws.onclose = () => {
39
+ this.closeHandler?.();
40
+ };
41
+ this.ws.onerror = () => {
42
+ const error = new Error('WebSocket error');
43
+ this.errorHandler?.(error);
44
+ // Reject only if we haven't connected yet
45
+ if (this.ws?.readyState !== WebSocket.OPEN) {
46
+ reject(error);
47
+ }
48
+ };
49
+ this.ws.onmessage = (event) => {
50
+ try {
51
+ const envelope = JSON.parse(event.data);
52
+ this.messageHandler?.(envelope);
53
+ }
54
+ catch {
55
+ this.errorHandler?.(new Error('Failed to parse server message'));
56
+ }
57
+ };
58
+ });
59
+ }
60
+ send(envelope) {
61
+ if (this.ws?.readyState === WebSocket.OPEN) {
62
+ this.ws.send(JSON.stringify(envelope));
63
+ }
64
+ }
65
+ onMessage(handler) {
66
+ this.messageHandler = handler;
67
+ }
68
+ onError(handler) {
69
+ this.errorHandler = handler;
70
+ }
71
+ onClose(handler) {
72
+ this.closeHandler = handler;
73
+ }
74
+ close() {
75
+ this.ws?.close();
76
+ this.ws = null;
77
+ }
78
+ }
79
+ //# sourceMappingURL=websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/client/transports/websocket.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,OAAO,kBAAkB;IAMT;IALZ,EAAE,GAAqB,IAAI,CAAC;IAC5B,cAAc,GAAgD,IAAI,CAAC;IACnE,YAAY,GAAoC,IAAI,CAAC;IACrD,YAAY,GAAwB,IAAI,CAAC;IAEjD,YAAoB,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;IAAG,CAAC;IAEnC,IAAI,UAAU;QACZ,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,QAAQ,CAAC;QAC9B,QAAQ,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;YAC3B,KAAK,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,YAAY,CAAC;YAC/C,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC;YACnC,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,EAAE,EAAE,UAAU,KAAK,SAAS,CAAC,IAAI;YAAE,OAAO;QAEnD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,IAAI,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAElC,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,GAAG,EAAE;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBACrB,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACxB,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBACrB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBAC3C,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC3B,0CAA0C;gBAC1C,IAAI,IAAI,CAAC,EAAE,EAAE,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;oBAC3C,MAAM,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,SAAS,GAAG,CAAC,KAAK,EAAE,EAAE;gBAC5B,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;oBAC1D,IAAI,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC;gBAClC,CAAC;gBAAC,MAAM,CAAC;oBACP,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;gBACnE,CAAC;YACH,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,QAAwB;QAC3B,IAAI,IAAI,CAAC,EAAE,EAAE,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YAC3C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,SAAS,CAAC,OAA2C;QACnD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,OAA+B;QACrC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,OAAO,CAAC,OAAmB;QACzB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;IACjB,CAAC;CACF"}
@@ -4,17 +4,23 @@
4
4
  * Unified browser SDK for voice assistants.
5
5
  * Handles three modes:
6
6
  * 1. Fully local - all components run in browser, no server needed
7
- * 2. Fully remote - all processing on server via WebSocket
7
+ * 2. Fully remote - all processing on server via transport
8
8
  * 3. Hybrid - mix of local and server components
9
9
  *
10
10
  * Component logic:
11
11
  * - Component provided → runs locally
12
- * - Component is null + serverUrl → server handles it
13
- * - All components local → no WebSocket needed
12
+ * - Component is null + serverUrl/transport → server handles it
13
+ * - All components local → no server connection needed
14
+ *
15
+ * Transport:
16
+ * - Default: WebSocketTransport (when serverUrl is provided)
17
+ * - Custom: Pass any Transport implementation via the transport option
18
+ * - Built-in alternatives: HttpSseTransport (HTTP POST + SSE)
14
19
  */
15
20
  import type { STTPipeline, LLMPipeline, TTSPipeline } from '../types';
16
21
  import { WebSpeechSTT } from './web-speech-stt';
17
22
  import { WebSpeechTTS } from './web-speech-tts';
23
+ import type { Transport } from './transport';
18
24
  export interface BrowserSupport {
19
25
  /** Web Speech API speech recognition (Chrome, Edge, Safari only) */
20
26
  webSpeechSTT: boolean;
@@ -64,9 +70,26 @@ export interface ClientComponents {
64
70
  */
65
71
  systemPrompt?: string;
66
72
  /**
67
- * WebSocket server URL (required if any component is null)
73
+ * Server URL (required if any component is null).
74
+ * When no custom transport is provided, this creates a WebSocketTransport.
75
+ * For WebSocket: 'ws://localhost:3000'
76
+ * For HTTP+SSE: use a custom transport instead
68
77
  */
69
78
  serverUrl?: string;
79
+ /**
80
+ * Custom transport for server communication.
81
+ * Overrides serverUrl when provided.
82
+ * Use this for non-WebSocket transports (HTTP+SSE, postMessage, etc.)
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * import { HttpSseTransport } from 'modular-voice-agent-sdk/client';
87
+ * {
88
+ * transport: new HttpSseTransport('http://localhost:3000'),
89
+ * }
90
+ * ```
91
+ */
92
+ transport?: Transport;
70
93
  }
71
94
  import type { ModelStore } from '../voice-pipeline';
72
95
  /**
@@ -184,7 +207,7 @@ export declare class VoiceClient {
184
207
  private localLLM;
185
208
  private localTTS;
186
209
  private localPipeline;
187
- private ws;
210
+ private transport;
188
211
  private recorder;
189
212
  private player;
190
213
  private status;
@@ -210,7 +233,7 @@ export declare class VoiceClient {
210
233
  */
211
234
  connect(): Promise<void>;
212
235
  private initializeLocalComponents;
213
- private connectWebSocket;
236
+ private connectTransport;
214
237
  /**
215
238
  * Disconnect and clean up
216
239
  */
@@ -276,10 +299,17 @@ export declare class VoiceClient {
276
299
  * Returns null if no request is in progress
277
300
  */
278
301
  getCurrentRequestId(): string | null;
302
+ /**
303
+ * Get the underlying transport.
304
+ * Useful for inspecting the transport state or for advanced use cases.
305
+ * Returns null if not using server mode.
306
+ */
307
+ getTransport(): Transport | null;
279
308
  /**
280
309
  * Get the underlying WebSocket connection.
281
- * Useful for sending/receiving custom app-specific messages outside the voice protocol.
282
- * Returns null if not using server mode or not connected.
310
+ * Returns null if not using server mode, not connected, or not using WebSocket transport.
311
+ *
312
+ * @deprecated Use getTransport() instead for transport-agnostic code.
283
313
  *
284
314
  * @example
285
315
  * ```typescript
@@ -290,12 +320,6 @@ export declare class VoiceClient {
290
320
  * message: { type: 'my_custom_message', data: {...} } as any,
291
321
  * };
292
322
  * client.getWebSocket()?.send(JSON.stringify(envelope));
293
- *
294
- * // Listen for custom messages
295
- * client.getWebSocket()?.addEventListener('message', (event) => {
296
- * const envelope = JSON.parse(event.data) as ServerEnvelope;
297
- * if (envelope.message.type === 'my_custom_response') { ... }
298
- * });
299
323
  * ```
300
324
  */
301
325
  getWebSocket(): WebSocket | null;
@@ -1 +1 @@
1
- {"version":3,"file":"voice-client.d.ts","sourceRoot":"","sources":["../../src/client/voice-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"voice-client.d.ts","sourceRoot":"","sources":["../../src/client/voice-client.ts"],"names":[],"mappings":"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"}
@@ -4,13 +4,18 @@
4
4
  * Unified browser SDK for voice assistants.
5
5
  * Handles three modes:
6
6
  * 1. Fully local - all components run in browser, no server needed
7
- * 2. Fully remote - all processing on server via WebSocket
7
+ * 2. Fully remote - all processing on server via transport
8
8
  * 3. Hybrid - mix of local and server components
9
9
  *
10
10
  * Component logic:
11
11
  * - Component provided → runs locally
12
- * - Component is null + serverUrl → server handles it
13
- * - All components local → no WebSocket needed
12
+ * - Component is null + serverUrl/transport → server handles it
13
+ * - All components local → no server connection needed
14
+ *
15
+ * Transport:
16
+ * - Default: WebSocketTransport (when serverUrl is provided)
17
+ * - Custom: Pass any Transport implementation via the transport option
18
+ * - Built-in alternatives: HttpSseTransport (HTTP POST + SSE)
14
19
  */
15
20
  import { VoicePipeline } from '../voice-pipeline';
16
21
  import { AudioRecorder } from './audio-recorder';
@@ -18,6 +23,7 @@ import { AudioPlayer } from './audio-player';
18
23
  import { WebSpeechSTT } from './web-speech-stt';
19
24
  import { WebSpeechTTS } from './web-speech-tts';
20
25
  import { float32ToBase64, base64ToFloat32, generateId, } from './protocol';
26
+ import { WebSocketTransport } from './transports/websocket';
21
27
  // ============ Helpers ============
22
28
  function isWebSpeechSTT(obj) {
23
29
  return obj instanceof WebSpeechSTT;
@@ -99,7 +105,7 @@ export class VoiceClient {
99
105
  localTTS = null;
100
106
  localPipeline = null;
101
107
  // Remote/hybrid components
102
- ws = null;
108
+ transport = null;
103
109
  recorder = null;
104
110
  player = null;
105
111
  // State
@@ -142,9 +148,16 @@ export class VoiceClient {
142
148
  this.mode = 'hybrid';
143
149
  }
144
150
  // Validate config
145
- if (this.needsServer && !components.serverUrl) {
146
- throw new Error('serverUrl is required when any component (stt, llm, tts) is null. ' +
147
- 'Either provide all components for fully-local mode, or specify a serverUrl.');
151
+ if (this.needsServer && !components.serverUrl && !components.transport) {
152
+ throw new Error('serverUrl or transport is required when any component (stt, llm, tts) is null. ' +
153
+ 'Either provide all components for fully-local mode, or specify a serverUrl or custom transport.');
154
+ }
155
+ // Create transport from serverUrl if no custom transport provided
156
+ if (components.transport) {
157
+ this.transport = components.transport;
158
+ }
159
+ else if (components.serverUrl) {
160
+ this.transport = new WebSocketTransport(components.serverUrl);
148
161
  }
149
162
  if (hasLocalLLM && !components.systemPrompt) {
150
163
  throw new Error('systemPrompt is required when using a local LLM');
@@ -258,7 +271,7 @@ export class VoiceClient {
258
271
  }
259
272
  // Connect to server if needed
260
273
  if (this.needsServer) {
261
- await this.connectWebSocket();
274
+ await this.connectTransport();
262
275
  }
263
276
  else {
264
277
  this.setStatus('ready');
@@ -296,37 +309,28 @@ export class VoiceClient {
296
309
  }
297
310
  await Promise.all(promises);
298
311
  }
299
- async connectWebSocket() {
300
- if (!this.config.serverUrl)
312
+ async connectTransport() {
313
+ if (!this.transport)
301
314
  return;
302
- if (this.ws?.readyState === WebSocket.OPEN)
315
+ if (this.transport.readyState === 'open')
303
316
  return;
304
317
  this.setStatus('connecting');
305
- this.ws = new WebSocket(this.config.serverUrl);
306
- this.ws.onopen = () => {
307
- // Wait for session_init before sending capabilities
308
- // The server will send session_init immediately on connect
309
- };
310
- this.ws.onclose = () => {
318
+ // Register handlers before connecting
319
+ this.transport.onMessage((envelope) => {
320
+ this.handleServerEnvelope(envelope);
321
+ });
322
+ this.transport.onClose(() => {
311
323
  this.sessionId = null;
312
324
  this.currentRequestId = null;
313
325
  this.setStatus('disconnected');
314
326
  if (this.config.autoReconnect && this.needsServer) {
315
327
  this.scheduleReconnect();
316
328
  }
317
- };
318
- this.ws.onerror = () => {
319
- this.emit('error', new Error('WebSocket error'), createLocalMeta(this.currentRequestId));
320
- };
321
- this.ws.onmessage = (event) => {
322
- try {
323
- const envelope = JSON.parse(event.data);
324
- this.handleServerEnvelope(envelope);
325
- }
326
- catch {
327
- this.emit('error', new Error('Failed to parse server message'), createLocalMeta(this.currentRequestId));
328
- }
329
- };
329
+ });
330
+ this.transport.onError((error) => {
331
+ this.emit('error', error, createLocalMeta(this.currentRequestId));
332
+ });
333
+ await this.transport.connect();
330
334
  }
331
335
  /**
332
336
  * Disconnect and clean up
@@ -337,8 +341,7 @@ export class VoiceClient {
337
341
  clearTimeout(this.reconnectTimer);
338
342
  this.reconnectTimer = null;
339
343
  }
340
- this.ws?.close();
341
- this.ws = null;
344
+ this.transport?.close();
342
345
  // Stop any TTS
343
346
  if (isWebSpeechTTS(this.localTTS)) {
344
347
  this.localTTS.stop();
@@ -583,7 +586,7 @@ export class VoiceClient {
583
586
  if (this.mode === 'local') {
584
587
  return this.localPipeline?.isReady() ?? false;
585
588
  }
586
- return this.ws?.readyState === WebSocket.OPEN;
589
+ return this.transport?.readyState === 'open';
587
590
  }
588
591
  /**
589
592
  * Check if currently recording
@@ -651,10 +654,19 @@ export class VoiceClient {
651
654
  getCurrentRequestId() {
652
655
  return this.currentRequestId;
653
656
  }
657
+ /**
658
+ * Get the underlying transport.
659
+ * Useful for inspecting the transport state or for advanced use cases.
660
+ * Returns null if not using server mode.
661
+ */
662
+ getTransport() {
663
+ return this.transport;
664
+ }
654
665
  /**
655
666
  * Get the underlying WebSocket connection.
656
- * Useful for sending/receiving custom app-specific messages outside the voice protocol.
657
- * Returns null if not using server mode or not connected.
667
+ * Returns null if not using server mode, not connected, or not using WebSocket transport.
668
+ *
669
+ * @deprecated Use getTransport() instead for transport-agnostic code.
658
670
  *
659
671
  * @example
660
672
  * ```typescript
@@ -665,16 +677,15 @@ export class VoiceClient {
665
677
  * message: { type: 'my_custom_message', data: {...} } as any,
666
678
  * };
667
679
  * client.getWebSocket()?.send(JSON.stringify(envelope));
668
- *
669
- * // Listen for custom messages
670
- * client.getWebSocket()?.addEventListener('message', (event) => {
671
- * const envelope = JSON.parse(event.data) as ServerEnvelope;
672
- * if (envelope.message.type === 'my_custom_response') { ... }
673
- * });
674
680
  * ```
675
681
  */
676
682
  getWebSocket() {
677
- return this.ws;
683
+ if (this.transport instanceof WebSocketTransport) {
684
+ // WebSocketTransport doesn't expose the raw WS; return null
685
+ // Users should migrate to getTransport()
686
+ return null;
687
+ }
688
+ return null;
678
689
  }
679
690
  /**
680
691
  * Subscribe to events
@@ -705,13 +716,13 @@ export class VoiceClient {
705
716
  }
706
717
  // ============ Private Methods ============
707
718
  send(msg) {
708
- if (this.ws?.readyState === WebSocket.OPEN && this.sessionId && this.currentRequestId) {
719
+ if (this.transport?.readyState === 'open' && this.sessionId && this.currentRequestId) {
709
720
  const envelope = {
710
721
  sessionId: this.sessionId,
711
722
  requestId: this.currentRequestId,
712
723
  message: msg,
713
724
  };
714
- this.ws.send(JSON.stringify(envelope));
725
+ this.transport.send(envelope);
715
726
  }
716
727
  }
717
728
  handleServerEnvelope(envelope) {
@@ -901,9 +912,9 @@ export class VoiceClient {
901
912
  ' 2. The browser does not support getUserMedia\n' +
902
913
  ' 3. Microphone permissions were denied');
903
914
  }
904
- // Check WebSocket if using server
905
- if (components.serverUrl && !support.webSocket) {
906
- throw new Error('WebSocket is not supported in this browser.');
915
+ // Check WebSocket if using server with default transport (no custom transport)
916
+ if (components.serverUrl && !components.transport && !support.webSocket) {
917
+ throw new Error('WebSocket is not supported in this browser. Consider using a custom transport (e.g., HttpSseTransport).');
907
918
  }
908
919
  // Check AudioContext for audio processing
909
920
  if (!support.audioContext) {