@framers/agentos 0.1.107 → 0.1.109

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 (62) hide show
  1. package/dist/memory/ingestion/ChunkingEngine.d.ts.map +1 -1
  2. package/dist/memory/ingestion/ChunkingEngine.js +5 -1
  3. package/dist/memory/ingestion/ChunkingEngine.js.map +1 -1
  4. package/dist/memory/ingestion/DocxLoader.d.ts.map +1 -1
  5. package/dist/memory/ingestion/DocxLoader.js +2 -1
  6. package/dist/memory/ingestion/DocxLoader.js.map +1 -1
  7. package/dist/memory/ingestion/FolderScanner.d.ts.map +1 -1
  8. package/dist/memory/ingestion/FolderScanner.js +6 -3
  9. package/dist/memory/ingestion/FolderScanner.js.map +1 -1
  10. package/dist/memory/ingestion/HtmlLoader.d.ts.map +1 -1
  11. package/dist/memory/ingestion/HtmlLoader.js +2 -1
  12. package/dist/memory/ingestion/HtmlLoader.js.map +1 -1
  13. package/dist/memory/ingestion/MarkdownLoader.d.ts.map +1 -1
  14. package/dist/memory/ingestion/MarkdownLoader.js +2 -1
  15. package/dist/memory/ingestion/MarkdownLoader.js.map +1 -1
  16. package/dist/memory/ingestion/PdfLoader.d.ts.map +1 -1
  17. package/dist/memory/ingestion/PdfLoader.js +2 -1
  18. package/dist/memory/ingestion/PdfLoader.js.map +1 -1
  19. package/dist/memory/ingestion/TextLoader.d.ts.map +1 -1
  20. package/dist/memory/ingestion/TextLoader.js +3 -2
  21. package/dist/memory/ingestion/TextLoader.js.map +1 -1
  22. package/dist/memory/ingestion/pathUtils.d.ts +40 -0
  23. package/dist/memory/ingestion/pathUtils.d.ts.map +1 -0
  24. package/dist/memory/ingestion/pathUtils.js +62 -0
  25. package/dist/memory/ingestion/pathUtils.js.map +1 -0
  26. package/dist/voice-pipeline/AcousticEndpointDetector.d.ts +95 -20
  27. package/dist/voice-pipeline/AcousticEndpointDetector.d.ts.map +1 -1
  28. package/dist/voice-pipeline/AcousticEndpointDetector.js +110 -24
  29. package/dist/voice-pipeline/AcousticEndpointDetector.js.map +1 -1
  30. package/dist/voice-pipeline/HardCutBargeinHandler.d.ts +66 -15
  31. package/dist/voice-pipeline/HardCutBargeinHandler.d.ts.map +1 -1
  32. package/dist/voice-pipeline/HardCutBargeinHandler.js +65 -13
  33. package/dist/voice-pipeline/HardCutBargeinHandler.js.map +1 -1
  34. package/dist/voice-pipeline/HeuristicEndpointDetector.d.ts +116 -42
  35. package/dist/voice-pipeline/HeuristicEndpointDetector.d.ts.map +1 -1
  36. package/dist/voice-pipeline/HeuristicEndpointDetector.js +159 -52
  37. package/dist/voice-pipeline/HeuristicEndpointDetector.js.map +1 -1
  38. package/dist/voice-pipeline/SoftFadeBargeinHandler.d.ts +89 -24
  39. package/dist/voice-pipeline/SoftFadeBargeinHandler.d.ts.map +1 -1
  40. package/dist/voice-pipeline/SoftFadeBargeinHandler.js +74 -20
  41. package/dist/voice-pipeline/SoftFadeBargeinHandler.js.map +1 -1
  42. package/dist/voice-pipeline/VoiceInterruptError.d.ts +68 -10
  43. package/dist/voice-pipeline/VoiceInterruptError.d.ts.map +1 -1
  44. package/dist/voice-pipeline/VoiceInterruptError.js +53 -6
  45. package/dist/voice-pipeline/VoiceInterruptError.js.map +1 -1
  46. package/dist/voice-pipeline/VoicePipelineOrchestrator.d.ts +190 -39
  47. package/dist/voice-pipeline/VoicePipelineOrchestrator.d.ts.map +1 -1
  48. package/dist/voice-pipeline/VoicePipelineOrchestrator.js +266 -53
  49. package/dist/voice-pipeline/VoicePipelineOrchestrator.js.map +1 -1
  50. package/dist/voice-pipeline/WebSocketStreamTransport.d.ts +135 -43
  51. package/dist/voice-pipeline/WebSocketStreamTransport.d.ts.map +1 -1
  52. package/dist/voice-pipeline/WebSocketStreamTransport.js +109 -47
  53. package/dist/voice-pipeline/WebSocketStreamTransport.js.map +1 -1
  54. package/dist/voice-pipeline/index.d.ts +34 -1
  55. package/dist/voice-pipeline/index.d.ts.map +1 -1
  56. package/dist/voice-pipeline/index.js +41 -1
  57. package/dist/voice-pipeline/index.js.map +1 -1
  58. package/dist/voice-pipeline/types.d.ts +432 -106
  59. package/dist/voice-pipeline/types.d.ts.map +1 -1
  60. package/dist/voice-pipeline/types.js +21 -9
  61. package/dist/voice-pipeline/types.js.map +1 -1
  62. package/package.json +1 -1
@@ -6,46 +6,105 @@
6
6
  * as Float32Array audio frames; text messages are parsed as
7
7
  * {@link ClientTextMessage} control envelopes.
8
8
  *
9
- * The transport is intentionally transport-agnostic: it accepts any object that
10
- * exposes the `ws` package's `WebSocket` interface (readyState, send, close, and
11
- * the standard event emitter surface). This makes it trivially testable with a
12
- * plain `EventEmitter` mock.
9
+ * ## Wire protocol
10
+ *
11
+ * ### Binary frames (inbound)
12
+ * Every binary WebSocket message is interpreted as a raw Float32Array of PCM
13
+ * samples. The sender (browser/client) must transmit audio as a `Float32Array`
14
+ * view serialised to its underlying `ArrayBuffer`. The transport reconstructs
15
+ * the `Float32Array` from the received `Buffer`, using `byteOffset` and
16
+ * `byteLength` to handle sliced buffers correctly.
17
+ *
18
+ * ### Text frames (inbound)
19
+ * Every text WebSocket message must be valid JSON conforming to
20
+ * {@link ClientTextMessage}. Malformed JSON emits an `'error'` event but does
21
+ * not crash the transport, allowing the session to continue.
22
+ *
23
+ * ### Binary frames (outbound)
24
+ * {@link sendAudio} sends the raw `Buffer` from an {@link EncodedAudioChunk}
25
+ * (or converts a `Float32Array` to a `Buffer` for raw {@link AudioFrame}s).
26
+ *
27
+ * ### Text frames (outbound)
28
+ * {@link sendControl} JSON-stringifies a {@link ServerTextMessage} and sends
29
+ * it as a text frame.
30
+ *
31
+ * ## Reconnection behaviour
32
+ * This transport does NOT implement automatic reconnection. If the underlying
33
+ * WebSocket closes, the transport transitions to `'closed'` and emits
34
+ * `'disconnected'`. The consumer (typically the orchestrator) is responsible
35
+ * for creating a new transport and session if reconnection is desired.
36
+ *
37
+ * ## Transport-agnostic design
38
+ * The transport accepts any object satisfying {@link WebSocketLike}, which is
39
+ * a minimal subset of the `ws` package's `WebSocket` interface. This makes it
40
+ * trivially testable with a plain `EventEmitter` mock and compatible with
41
+ * browser-style WebSocket polyfills.
13
42
  */
14
43
  import { EventEmitter } from 'node:events';
15
44
  import type { IStreamTransport, AudioFrame, EncodedAudioChunk, TransportControlMessage, ServerTextMessage } from './types.js';
16
45
  /**
17
46
  * Subset of the WebSocket API required by {@link WebSocketStreamTransport}.
18
47
  * Both the `ws` npm package and the browser's native WebSocket satisfy this.
48
+ *
49
+ * By depending on this minimal interface rather than the full `ws.WebSocket`
50
+ * type, the transport avoids a hard dependency on any specific WebSocket
51
+ * library and remains easily mockable in tests.
52
+ *
53
+ * @see {@link WebSocketStreamTransport} which consumes this interface.
19
54
  */
20
55
  export interface WebSocketLike extends NodeJS.EventEmitter {
21
- /** WebSocket ready-state constant for the OPEN state (= 1). */
56
+ /**
57
+ * WebSocket ready-state constant for the OPEN state.
58
+ * In the `ws` package this is `1`; in browsers it is also `1`.
59
+ * Optional because some mock implementations may not define it.
60
+ */
22
61
  readonly OPEN?: number;
23
- /** WebSocket ready-state constant for the CLOSED state (= 3). */
62
+ /**
63
+ * WebSocket ready-state constant for the CLOSED state.
64
+ * In the `ws` package this is `3`.
65
+ * Optional because some mock implementations may not define it.
66
+ */
24
67
  readonly CLOSED?: number;
25
- /** Current ready state of the socket. */
68
+ /**
69
+ * Current ready state of the socket.
70
+ * - `0` = CONNECTING
71
+ * - `1` = OPEN
72
+ * - `2` = CLOSING
73
+ * - `3` = CLOSED
74
+ */
26
75
  readonly readyState: number;
27
76
  /**
28
77
  * Send data over the socket.
29
78
  *
30
- * @param data Binary `Buffer` or text `string` payload.
31
- * @param cb Optional completion callback used by the `ws` library.
79
+ * @param data - Binary `Buffer` or text `string` payload.
80
+ * @param cb - Optional completion callback used by the `ws` library.
81
+ * The callback receives an optional `Error` if the send fails.
32
82
  */
33
83
  send(data: Buffer | string, cb?: (err?: Error) => void): void;
34
84
  /**
35
85
  * Initiate a graceful close handshake.
36
86
  *
37
- * @param code Optional numeric close code (default 1000).
38
- * @param reason Optional human-readable reason string.
87
+ * @param code - Optional numeric close code (default 1000 = normal closure).
88
+ * @param reason - Optional human-readable reason string.
39
89
  */
40
90
  close(code?: number, reason?: string): void;
41
91
  }
42
92
  /**
43
93
  * Constructor options for {@link WebSocketStreamTransport}.
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * const config: WebSocketStreamTransportConfig = { sampleRate: 16000 };
98
+ * const transport = new WebSocketStreamTransport(ws, config);
99
+ * ```
44
100
  */
45
101
  export interface WebSocketStreamTransportConfig {
46
102
  /**
47
103
  * Sample rate (in Hz) used to populate {@link AudioFrame.sampleRate} on
48
104
  * inbound binary messages. Must match the rate the remote client is sending.
105
+ *
106
+ * Common values: 16000 (telephony/STT), 24000 (TTS output), 48000 (high-fidelity).
107
+ *
49
108
  * @example 16000
50
109
  */
51
110
  sampleRate: number;
@@ -53,39 +112,64 @@ export interface WebSocketStreamTransportConfig {
53
112
  /**
54
113
  * Bidirectional voice pipeline transport backed by a WebSocket connection.
55
114
  *
56
- * ### Inbound wire format
57
- * - **Binary frame** → decoded as a `Float32Array` view, wrapped in an
58
- * {@link AudioFrame}, and re-emitted as `'audio_frame'`.
59
- * - **Text frame** → `JSON.parse()`d and re-emitted as `'control'` carrying
60
- * the raw {@link ClientTextMessage} object.
115
+ * ## Inbound wire format
116
+ *
117
+ * | Frame type | Processing |
118
+ * |------------|-----------------------------------------------------------|
119
+ * | Binary | Decoded as `Float32Array` PCM samples, wrapped in an {@link AudioFrame}, emitted as `'audio_frame'`. |
120
+ * | Text | `JSON.parse()`d as {@link ClientTextMessage}, emitted as `'control'`. |
121
+ *
122
+ * ## Outbound API
123
+ *
124
+ * | Method | Behaviour |
125
+ * |-----------------|--------------------------------------------------------|
126
+ * | {@link sendAudio} | Serialises audio to a binary `Buffer` and calls `ws.send()`. |
127
+ * | {@link sendControl} | JSON-stringifies the message and calls `ws.send()`. |
61
128
  *
62
- * ### Outbound API
63
- * - {@link sendAudio} — serialises an {@link EncodedAudioChunk} or
64
- * {@link AudioFrame} to a binary `Buffer` and calls `ws.send()`.
65
- * - {@link sendControl} — JSON-stringifies a {@link TransportControlMessage}
66
- * or {@link ServerTextMessage} and calls `ws.send()`.
129
+ * ## Lifecycle events (re-emitted on `this`)
67
130
  *
68
- * ### Lifecycle events (re-emitted on `this`)
69
131
  * | WS event | Transport emission |
70
132
  * |----------|--------------------|
71
133
  * | `open` | `'connected'` |
72
134
  * | `close` | `'disconnected'` |
73
135
  * | `error` | `'error'` |
74
136
  *
75
- * @fires audio_frame `(frame: AudioFrame)` for every inbound binary message.
76
- * @fires control `(msg: ClientTextMessage)` for every inbound text message.
77
- * @fires connected Socket transitioned to OPEN state.
78
- * @fires disconnected Socket has been fully closed.
79
- * @fires error Socket-level error occurred.
137
+ * @fires audio_frame - `(frame: AudioFrame)` for every inbound binary message.
138
+ * @fires control - `(msg: ClientTextMessage)` for every inbound text message.
139
+ * @fires connected - Socket transitioned to OPEN state.
140
+ * @fires disconnected - Socket has been fully closed.
141
+ * @fires error - Socket-level error occurred.
142
+ *
143
+ * @see {@link IStreamTransport} for the interface contract.
144
+ * @see {@link VoicePipelineOrchestrator} which consumes this transport.
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * import WebSocket from 'ws';
149
+ * const ws = new WebSocket('ws://localhost:8080/voice');
150
+ * const transport = new WebSocketStreamTransport(ws, { sampleRate: 16000 });
151
+ *
152
+ * transport.on('audio_frame', (frame) => sttSession.pushAudio(frame));
153
+ * transport.on('control', (msg) => handleClientMessage(msg));
154
+ * ```
80
155
  */
81
156
  export declare class WebSocketStreamTransport extends EventEmitter implements IStreamTransport {
82
- /** Stable UUID assigned at construction time. */
157
+ /**
158
+ * Stable UUID assigned at construction time.
159
+ * Used as a correlation key in logs and metrics.
160
+ */
83
161
  readonly id: string;
84
- /** Current connection state. Updated in response to WebSocket events. */
162
+ /**
163
+ * Current connection state. Updated internally by WebSocket event handlers.
164
+ * Read externally via the {@link state} getter.
165
+ */
85
166
  private _state;
86
167
  /** The underlying WebSocket connection. */
87
168
  private readonly _ws;
88
- /** Audio sample rate propagated into every decoded {@link AudioFrame}. */
169
+ /**
170
+ * Audio sample rate propagated into every decoded {@link AudioFrame}.
171
+ * Configured once at construction and never changed.
172
+ */
89
173
  private readonly _sampleRate;
90
174
  /**
91
175
  * Create a new transport wrapping an existing WebSocket connection.
@@ -95,8 +179,8 @@ export declare class WebSocketStreamTransport extends EventEmitter implements IS
95
179
  * is set to `'open'`; otherwise it is set to `'connecting'` and will
96
180
  * transition to `'open'` when the `'open'` event fires.
97
181
  *
98
- * @param ws WebSocket connection (or compatible mock).
99
- * @param config Transport-level configuration.
182
+ * @param ws - WebSocket connection (or compatible mock).
183
+ * @param config - Transport-level configuration (must include sampleRate).
100
184
  */
101
185
  constructor(ws: WebSocketLike, config: WebSocketStreamTransportConfig);
102
186
  /**
@@ -107,13 +191,15 @@ export declare class WebSocketStreamTransport extends EventEmitter implements IS
107
191
  /**
108
192
  * Send a synthesised audio chunk to the remote client for playback.
109
193
  *
110
- * If `chunk` carries an {@link EncodedAudioChunk} (has an `audio` Buffer
111
- * property), that buffer is sent directly. If it carries an {@link AudioFrame}
112
- * (has a `samples` Float32Array), the samples are copied into a new `Buffer`
113
- * and sent.
194
+ * If the payload is an {@link EncodedAudioChunk} (has an `audio` Buffer
195
+ * property), that buffer is sent directly as a binary frame. If it is an
196
+ * {@link AudioFrame} (has a `samples` Float32Array), the samples are copied
197
+ * into a new `Buffer` and sent.
114
198
  *
115
- * @param chunk Encoded audio chunk or raw PCM frame to deliver.
199
+ * @param chunk - Encoded audio chunk or raw PCM frame to deliver.
116
200
  * @returns Resolves once the data has been handed to the OS socket buffer.
201
+ *
202
+ * @throws {Error} If the underlying `ws.send()` fails (e.g. socket closed).
117
203
  */
118
204
  sendAudio(chunk: EncodedAudioChunk | AudioFrame): Promise<void>;
119
205
  /**
@@ -123,8 +209,10 @@ export declare class WebSocketStreamTransport extends EventEmitter implements IS
123
209
  * {@link TransportControlMessage} and {@link ServerTextMessage} are accepted
124
210
  * since they share the same serialisation path.
125
211
  *
126
- * @param msg Server-side protocol message.
212
+ * @param msg - Server-side protocol message.
127
213
  * @returns Resolves once the message has been handed to the OS socket buffer.
214
+ *
215
+ * @throws {Error} If the underlying `ws.send()` fails (e.g. socket closed).
128
216
  */
129
217
  sendControl(msg: TransportControlMessage | ServerTextMessage): Promise<void>;
130
218
  /**
@@ -134,14 +222,18 @@ export declare class WebSocketStreamTransport extends EventEmitter implements IS
134
222
  * underlying WebSocket's `close()` method. The `'disconnected'` event will
135
223
  * fire once the socket's `'close'` event is received.
136
224
  *
137
- * @param code Optional numeric WebSocket close code (default 1000).
138
- * @param reason Optional human-readable close reason.
225
+ * @param code - Optional numeric WebSocket close code (default 1000 = normal closure).
226
+ * @param reason - Optional human-readable close reason.
139
227
  */
140
228
  close(code?: number, reason?: string): void;
141
229
  /**
142
- * Attach listeners to the underlying WebSocket for the events that matter to
143
- * the voice pipeline. All listener state is contained here; no cleanup method
144
- * is currently needed since the transport's lifetime is tied to the socket's.
230
+ * Attach listeners to the underlying WebSocket for all events relevant to
231
+ * the voice pipeline.
232
+ *
233
+ * All listener state is contained here. No cleanup method is currently
234
+ * needed because the transport's lifetime is tied to the socket's --
235
+ * when the socket closes, the transport transitions to `'closed'` and
236
+ * no further events are expected.
145
237
  */
146
238
  private _attachWsListeners;
147
239
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketStreamTransport.d.ts","sourceRoot":"","sources":["../../src/voice-pipeline/WebSocketStreamTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,uBAAuB,EAEvB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAOpB;;;GAGG;AACH,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,YAAY;IACxD,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC9D;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAMD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,wBAAyB,SAAQ,YAAa,YAAW,gBAAgB;IAKpF,iDAAiD;IACjD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,yEAAyE;IACzE,OAAO,CAAC,MAAM,CAA+C;IAM7D,2CAA2C;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IAEpC,0EAA0E;IAC1E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAMrC;;;;;;;;;;OAUG;gBACS,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,8BAA8B;IAkBrE;;;OAGG;IACH,IAAI,KAAK,IAAI,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAExD;IAED;;;;;;;;;;OAUG;IACH,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB/D;;;;;;;;;OASG;IACH,WAAW,CAAC,GAAG,EAAE,uBAAuB,GAAG,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5E;;;;;;;;;OASG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAS3C;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;CAyD3B"}
1
+ {"version":3,"file":"WebSocketStreamTransport.d.ts","sourceRoot":"","sources":["../../src/voice-pipeline/WebSocketStreamTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,uBAAuB,EAEvB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAMpB;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,YAAY;IACxD;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAE9D;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAMD;;;;;;;;GAQG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,qBAAa,wBAAyB,SAAQ,YAAa,YAAW,gBAAgB;IAKpF;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAA+C;IAM7D,2CAA2C;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IAEpC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAMrC;;;;;;;;;;OAUG;gBACS,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,8BAA8B;IAmBrE;;;OAGG;IACH,IAAI,KAAK,IAAI,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAExD;IAED;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B/D;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,GAAG,EAAE,uBAAuB,GAAG,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5E;;;;;;;;;OASG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAS3C;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;CAoE3B"}
@@ -6,10 +6,39 @@
6
6
  * as Float32Array audio frames; text messages are parsed as
7
7
  * {@link ClientTextMessage} control envelopes.
8
8
  *
9
- * The transport is intentionally transport-agnostic: it accepts any object that
10
- * exposes the `ws` package's `WebSocket` interface (readyState, send, close, and
11
- * the standard event emitter surface). This makes it trivially testable with a
12
- * plain `EventEmitter` mock.
9
+ * ## Wire protocol
10
+ *
11
+ * ### Binary frames (inbound)
12
+ * Every binary WebSocket message is interpreted as a raw Float32Array of PCM
13
+ * samples. The sender (browser/client) must transmit audio as a `Float32Array`
14
+ * view serialised to its underlying `ArrayBuffer`. The transport reconstructs
15
+ * the `Float32Array` from the received `Buffer`, using `byteOffset` and
16
+ * `byteLength` to handle sliced buffers correctly.
17
+ *
18
+ * ### Text frames (inbound)
19
+ * Every text WebSocket message must be valid JSON conforming to
20
+ * {@link ClientTextMessage}. Malformed JSON emits an `'error'` event but does
21
+ * not crash the transport, allowing the session to continue.
22
+ *
23
+ * ### Binary frames (outbound)
24
+ * {@link sendAudio} sends the raw `Buffer` from an {@link EncodedAudioChunk}
25
+ * (or converts a `Float32Array` to a `Buffer` for raw {@link AudioFrame}s).
26
+ *
27
+ * ### Text frames (outbound)
28
+ * {@link sendControl} JSON-stringifies a {@link ServerTextMessage} and sends
29
+ * it as a text frame.
30
+ *
31
+ * ## Reconnection behaviour
32
+ * This transport does NOT implement automatic reconnection. If the underlying
33
+ * WebSocket closes, the transport transitions to `'closed'` and emits
34
+ * `'disconnected'`. The consumer (typically the orchestrator) is responsible
35
+ * for creating a new transport and session if reconnection is desired.
36
+ *
37
+ * ## Transport-agnostic design
38
+ * The transport accepts any object satisfying {@link WebSocketLike}, which is
39
+ * a minimal subset of the `ws` package's `WebSocket` interface. This makes it
40
+ * trivially testable with a plain `EventEmitter` mock and compatible with
41
+ * browser-style WebSocket polyfills.
13
42
  */
14
43
  import { EventEmitter } from 'node:events';
15
44
  import { randomUUID } from 'node:crypto';
@@ -19,30 +48,46 @@ import { randomUUID } from 'node:crypto';
19
48
  /**
20
49
  * Bidirectional voice pipeline transport backed by a WebSocket connection.
21
50
  *
22
- * ### Inbound wire format
23
- * - **Binary frame** → decoded as a `Float32Array` view, wrapped in an
24
- * {@link AudioFrame}, and re-emitted as `'audio_frame'`.
25
- * - **Text frame** → `JSON.parse()`d and re-emitted as `'control'` carrying
26
- * the raw {@link ClientTextMessage} object.
51
+ * ## Inbound wire format
52
+ *
53
+ * | Frame type | Processing |
54
+ * |------------|-----------------------------------------------------------|
55
+ * | Binary | Decoded as `Float32Array` PCM samples, wrapped in an {@link AudioFrame}, emitted as `'audio_frame'`. |
56
+ * | Text | `JSON.parse()`d as {@link ClientTextMessage}, emitted as `'control'`. |
57
+ *
58
+ * ## Outbound API
27
59
  *
28
- * ### Outbound API
29
- * - {@link sendAudio} — serialises an {@link EncodedAudioChunk} or
30
- * {@link AudioFrame} to a binary `Buffer` and calls `ws.send()`.
31
- * - {@link sendControl} JSON-stringifies a {@link TransportControlMessage}
32
- * or {@link ServerTextMessage} and calls `ws.send()`.
60
+ * | Method | Behaviour |
61
+ * |-----------------|--------------------------------------------------------|
62
+ * | {@link sendAudio} | Serialises audio to a binary `Buffer` and calls `ws.send()`. |
63
+ * | {@link sendControl} | JSON-stringifies the message and calls `ws.send()`. |
64
+ *
65
+ * ## Lifecycle events (re-emitted on `this`)
33
66
  *
34
- * ### Lifecycle events (re-emitted on `this`)
35
67
  * | WS event | Transport emission |
36
68
  * |----------|--------------------|
37
69
  * | `open` | `'connected'` |
38
70
  * | `close` | `'disconnected'` |
39
71
  * | `error` | `'error'` |
40
72
  *
41
- * @fires audio_frame `(frame: AudioFrame)` for every inbound binary message.
42
- * @fires control `(msg: ClientTextMessage)` for every inbound text message.
43
- * @fires connected Socket transitioned to OPEN state.
44
- * @fires disconnected Socket has been fully closed.
45
- * @fires error Socket-level error occurred.
73
+ * @fires audio_frame - `(frame: AudioFrame)` for every inbound binary message.
74
+ * @fires control - `(msg: ClientTextMessage)` for every inbound text message.
75
+ * @fires connected - Socket transitioned to OPEN state.
76
+ * @fires disconnected - Socket has been fully closed.
77
+ * @fires error - Socket-level error occurred.
78
+ *
79
+ * @see {@link IStreamTransport} for the interface contract.
80
+ * @see {@link VoicePipelineOrchestrator} which consumes this transport.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * import WebSocket from 'ws';
85
+ * const ws = new WebSocket('ws://localhost:8080/voice');
86
+ * const transport = new WebSocketStreamTransport(ws, { sampleRate: 16000 });
87
+ *
88
+ * transport.on('audio_frame', (frame) => sttSession.pushAudio(frame));
89
+ * transport.on('control', (msg) => handleClientMessage(msg));
90
+ * ```
46
91
  */
47
92
  export class WebSocketStreamTransport extends EventEmitter {
48
93
  // -------------------------------------------------------------------------
@@ -56,8 +101,8 @@ export class WebSocketStreamTransport extends EventEmitter {
56
101
  * is set to `'open'`; otherwise it is set to `'connecting'` and will
57
102
  * transition to `'open'` when the `'open'` event fires.
58
103
  *
59
- * @param ws WebSocket connection (or compatible mock).
60
- * @param config Transport-level configuration.
104
+ * @param ws - WebSocket connection (or compatible mock).
105
+ * @param config - Transport-level configuration (must include sampleRate).
61
106
  */
62
107
  constructor(ws, config) {
63
108
  super();
@@ -65,13 +110,14 @@ export class WebSocketStreamTransport extends EventEmitter {
65
110
  this._sampleRate = config.sampleRate;
66
111
  this.id = randomUUID();
67
112
  // Determine initial state from the socket's current ready-state value.
68
- // The `ws` package uses numeric constants; OPEN = 1, CLOSED = 3.
113
+ // The `ws` package uses numeric constants: OPEN = 1, CLOSED = 3.
114
+ // We default to 1 if the OPEN constant is not defined (e.g. in mocks).
69
115
  const OPEN_STATE = ws.OPEN ?? 1;
70
116
  this._state = ws.readyState === OPEN_STATE ? 'open' : 'connecting';
71
117
  this._attachWsListeners();
72
118
  }
73
119
  // -------------------------------------------------------------------------
74
- // IStreamTransport public surface
120
+ // IStreamTransport -- public surface
75
121
  // -------------------------------------------------------------------------
76
122
  /**
77
123
  * Current connection state of the underlying WebSocket.
@@ -83,23 +129,27 @@ export class WebSocketStreamTransport extends EventEmitter {
83
129
  /**
84
130
  * Send a synthesised audio chunk to the remote client for playback.
85
131
  *
86
- * If `chunk` carries an {@link EncodedAudioChunk} (has an `audio` Buffer
87
- * property), that buffer is sent directly. If it carries an {@link AudioFrame}
88
- * (has a `samples` Float32Array), the samples are copied into a new `Buffer`
89
- * and sent.
132
+ * If the payload is an {@link EncodedAudioChunk} (has an `audio` Buffer
133
+ * property), that buffer is sent directly as a binary frame. If it is an
134
+ * {@link AudioFrame} (has a `samples` Float32Array), the samples are copied
135
+ * into a new `Buffer` and sent.
90
136
  *
91
- * @param chunk Encoded audio chunk or raw PCM frame to deliver.
137
+ * @param chunk - Encoded audio chunk or raw PCM frame to deliver.
92
138
  * @returns Resolves once the data has been handed to the OS socket buffer.
139
+ *
140
+ * @throws {Error} If the underlying `ws.send()` fails (e.g. socket closed).
93
141
  */
94
142
  sendAudio(chunk) {
95
143
  return new Promise((resolve, reject) => {
96
144
  let binary;
97
145
  if ('audio' in chunk) {
98
- // EncodedAudioChunk already a Buffer
146
+ // EncodedAudioChunk path: the audio property is already a Buffer
99
147
  binary = chunk.audio;
100
148
  }
101
149
  else {
102
- // AudioFrame convert Float32Array samples to a byte Buffer
150
+ // AudioFrame path: convert Float32Array samples to a raw byte Buffer.
151
+ // We must use byteOffset and byteLength because the Float32Array may
152
+ // be a view into a larger SharedArrayBuffer or sliced Buffer.
103
153
  const frame = chunk;
104
154
  binary = Buffer.from(frame.samples.buffer, frame.samples.byteOffset, frame.samples.byteLength);
105
155
  }
@@ -118,8 +168,10 @@ export class WebSocketStreamTransport extends EventEmitter {
118
168
  * {@link TransportControlMessage} and {@link ServerTextMessage} are accepted
119
169
  * since they share the same serialisation path.
120
170
  *
121
- * @param msg Server-side protocol message.
171
+ * @param msg - Server-side protocol message.
122
172
  * @returns Resolves once the message has been handed to the OS socket buffer.
173
+ *
174
+ * @throws {Error} If the underlying `ws.send()` fails (e.g. socket closed).
123
175
  */
124
176
  sendControl(msg) {
125
177
  return new Promise((resolve, reject) => {
@@ -138,8 +190,8 @@ export class WebSocketStreamTransport extends EventEmitter {
138
190
  * underlying WebSocket's `close()` method. The `'disconnected'` event will
139
191
  * fire once the socket's `'close'` event is received.
140
192
  *
141
- * @param code Optional numeric WebSocket close code (default 1000).
142
- * @param reason Optional human-readable close reason.
193
+ * @param code - Optional numeric WebSocket close code (default 1000 = normal closure).
194
+ * @param reason - Optional human-readable close reason.
143
195
  */
144
196
  close(code, reason) {
145
197
  this._state = 'closing';
@@ -149,36 +201,45 @@ export class WebSocketStreamTransport extends EventEmitter {
149
201
  // Private helpers
150
202
  // -------------------------------------------------------------------------
151
203
  /**
152
- * Attach listeners to the underlying WebSocket for the events that matter to
153
- * the voice pipeline. All listener state is contained here; no cleanup method
154
- * is currently needed since the transport's lifetime is tied to the socket's.
204
+ * Attach listeners to the underlying WebSocket for all events relevant to
205
+ * the voice pipeline.
206
+ *
207
+ * All listener state is contained here. No cleanup method is currently
208
+ * needed because the transport's lifetime is tied to the socket's --
209
+ * when the socket closes, the transport transitions to `'closed'` and
210
+ * no further events are expected.
155
211
  */
156
212
  _attachWsListeners() {
157
- // `message` inbound data from the remote peer
213
+ // `message` -- inbound data from the remote peer
158
214
  this._ws.on('message', (data) => {
159
215
  if (typeof data === 'string') {
160
- // Text frame parse as ClientTextMessage and propagate as 'control'
216
+ // Text frame: parse as ClientTextMessage JSON and propagate as 'control'.
217
+ // Malformed JSON emits an error but does NOT crash the transport,
218
+ // allowing the session to recover from a single bad message.
161
219
  try {
162
220
  const msg = JSON.parse(data);
163
221
  this.emit('control', msg);
164
222
  }
165
223
  catch (err) {
166
- // Malformed JSON emit as an error but do not crash the transport
167
- this.emit('error', new Error(`WebSocketStreamTransport: failed to parse text message: ${String(err)}`));
224
+ this.emit('error', new Error(`WebSocketStreamTransport: failed to parse inbound text message as JSON: ${String(err)}`));
168
225
  }
169
226
  }
170
227
  else {
171
- // Binary frame interpret bytes as a Float32Array PCM sample buffer
228
+ // Binary frame: interpret bytes as a Float32Array PCM sample buffer.
229
+ // The `ws` package delivers binary as a Node.js Buffer; browser-style
230
+ // WebSocket polyfills may deliver an ArrayBuffer instead.
172
231
  let buffer;
173
232
  if (Buffer.isBuffer(data)) {
174
233
  buffer = data;
175
234
  }
176
235
  else {
177
- // ArrayBuffer (browser-style)
236
+ // ArrayBuffer (browser-style) -- wrap in a Node.js Buffer
178
237
  buffer = Buffer.from(data);
179
238
  }
180
239
  // Create a Float32Array view over the underlying ArrayBuffer.
181
- // We use byteOffset/length to handle sliced Buffers correctly.
240
+ // We use byteOffset and byteLength to handle sliced Buffers correctly,
241
+ // since Buffer.from() may return a view into Node's internal pool
242
+ // rather than a fresh allocation.
182
243
  const samples = new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / Float32Array.BYTES_PER_ELEMENT);
183
244
  const frame = {
184
245
  samples,
@@ -188,17 +249,18 @@ export class WebSocketStreamTransport extends EventEmitter {
188
249
  this.emit('audio_frame', frame);
189
250
  }
190
251
  });
191
- // `open` socket handshake complete
252
+ // `open` -- socket handshake complete (fires for late-open connections)
192
253
  this._ws.on('open', () => {
193
254
  this._state = 'open';
194
255
  this.emit('connected');
195
256
  });
196
- // `close` socket has been fully closed (either side)
257
+ // `close` -- socket has been fully closed (either side initiated)
197
258
  this._ws.on('close', () => {
198
259
  this._state = 'closed';
199
260
  this.emit('disconnected');
200
261
  });
201
- // `error` transport-level socket error
262
+ // `error` -- transport-level socket error. Re-emitted verbatim so the
263
+ // orchestrator can log it and decide whether to tear down the session.
202
264
  this._ws.on('error', (err) => {
203
265
  this.emit('error', err);
204
266
  });
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketStreamTransport.js","sourceRoot":"","sources":["../../src/voice-pipeline/WebSocketStreamTransport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WebSocketStreamTransport.js","sourceRoot":"","sources":["../../src/voice-pipeline/WebSocketStreamTransport.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,40 @@
1
1
  /**
2
+ * @module @framers/agentos/voice-pipeline
3
+ *
2
4
  * Barrel exports for the AgentOS streaming voice pipeline.
3
5
  *
4
- * @module @framers/agentos/voice-pipeline
6
+ * This module provides all the building blocks needed to assemble a real-time
7
+ * voice conversation system:
8
+ *
9
+ * - **Types** -- All interfaces and type aliases defining the pipeline's contracts
10
+ * ({@link AudioFrame}, {@link IStreamTransport}, {@link IEndpointDetector}, etc.).
11
+ *
12
+ * - **Orchestrator** -- {@link VoicePipelineOrchestrator} is the central state machine
13
+ * that wires transport, STT, endpoint detection, TTS, and barge-in handling into
14
+ * a coordinated conversation loop.
15
+ *
16
+ * - **Endpoint Detectors** -- Two strategies for detecting turn boundaries:
17
+ * - {@link HeuristicEndpointDetector}: Rule-based (punctuation + silence timeout).
18
+ * - {@link AcousticEndpointDetector}: Purely acoustic (silence-only, no transcript analysis).
19
+ *
20
+ * - **Barge-in Handlers** -- Two strategies for handling user interruptions:
21
+ * - {@link HardCutBargeinHandler}: Immediate stop above a speech duration threshold.
22
+ * - {@link SoftFadeBargeinHandler}: Three-tier (ignore/pause/cancel) with configurable fade.
23
+ *
24
+ * - **Transport** -- {@link WebSocketStreamTransport}: WebSocket-based bidirectional
25
+ * audio/text transport implementing {@link IStreamTransport}.
26
+ *
27
+ * - **Error** -- {@link VoiceInterruptError}: Typed error for barge-in interruptions.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * import {
32
+ * VoicePipelineOrchestrator,
33
+ * HeuristicEndpointDetector,
34
+ * HardCutBargeinHandler,
35
+ * WebSocketStreamTransport,
36
+ * } from '../voice-pipeline';
37
+ * ```
5
38
  */
6
39
  export * from './types.js';
7
40
  export { HardCutBargeinHandler } from './HardCutBargeinHandler.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voice-pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voice-pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,cAAc,YAAY,CAAC;AAG3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAGzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAGzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAG3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC"}