@memberjunction/ai-realtime-client 0.0.1 → 5.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +148 -28
  2. package/dist/audio/audioMeter.d.ts +101 -0
  3. package/dist/audio/audioMeter.d.ts.map +1 -0
  4. package/dist/audio/audioMeter.js +193 -0
  5. package/dist/audio/audioMeter.js.map +1 -0
  6. package/dist/audio/micCapture.d.ts +26 -0
  7. package/dist/audio/micCapture.d.ts.map +1 -0
  8. package/dist/audio/micCapture.js +69 -0
  9. package/dist/audio/micCapture.js.map +1 -0
  10. package/dist/audio/pcmPlayback.d.ts +73 -0
  11. package/dist/audio/pcmPlayback.d.ts.map +1 -0
  12. package/dist/audio/pcmPlayback.js +78 -0
  13. package/dist/audio/pcmPlayback.js.map +1 -0
  14. package/dist/audio/pcmUtils.d.ts +17 -0
  15. package/dist/audio/pcmUtils.d.ts.map +1 -0
  16. package/dist/audio/pcmUtils.js +46 -0
  17. package/dist/audio/pcmUtils.js.map +1 -0
  18. package/dist/drivers/assemblyAIRealtimeClient.d.ts +384 -0
  19. package/dist/drivers/assemblyAIRealtimeClient.d.ts.map +1 -0
  20. package/dist/drivers/assemblyAIRealtimeClient.js +732 -0
  21. package/dist/drivers/assemblyAIRealtimeClient.js.map +1 -0
  22. package/dist/drivers/elevenLabsRealtimeClient.d.ts +362 -0
  23. package/dist/drivers/elevenLabsRealtimeClient.d.ts.map +1 -0
  24. package/dist/drivers/elevenLabsRealtimeClient.js +686 -0
  25. package/dist/drivers/elevenLabsRealtimeClient.js.map +1 -0
  26. package/dist/drivers/geminiRealtimeClient.d.ts +406 -0
  27. package/dist/drivers/geminiRealtimeClient.d.ts.map +1 -0
  28. package/dist/drivers/geminiRealtimeClient.js +675 -0
  29. package/dist/drivers/geminiRealtimeClient.js.map +1 -0
  30. package/dist/drivers/openAIRealtimeClient.d.ts +381 -0
  31. package/dist/drivers/openAIRealtimeClient.d.ts.map +1 -0
  32. package/dist/drivers/openAIRealtimeClient.js +602 -0
  33. package/dist/drivers/openAIRealtimeClient.js.map +1 -0
  34. package/dist/drivers/xaiRealtimeClient.d.ts +430 -0
  35. package/dist/drivers/xaiRealtimeClient.d.ts.map +1 -0
  36. package/dist/drivers/xaiRealtimeClient.js +676 -0
  37. package/dist/drivers/xaiRealtimeClient.js.map +1 -0
  38. package/dist/generic/baseRealtimeClient.d.ts +401 -0
  39. package/dist/generic/baseRealtimeClient.d.ts.map +1 -0
  40. package/dist/generic/baseRealtimeClient.js +226 -0
  41. package/dist/generic/baseRealtimeClient.js.map +1 -0
  42. package/dist/index.d.ts +11 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +11 -0
  45. package/dist/index.js.map +1 -0
  46. package/package.json +28 -7
@@ -0,0 +1,602 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { RealtimeAudioMeter } from '../audio/audioMeter.js';
9
+ import { BaseRealtimeClient, } from '../generic/baseRealtimeClient.js';
10
+ /**
11
+ * OpenAI implementation of {@link BaseRealtimeClient}: a **browser-direct** WebRTC
12
+ * connection to OpenAI's Realtime API, authenticated with the server-minted ephemeral
13
+ * client secret.
14
+ *
15
+ * Registered with the ClassFactory under the key `'openai'` — the `Provider` string the
16
+ * server's `OpenAIRealtime` driver stamps on its `ClientRealtimeSessionConfig` — so hosts
17
+ * resolve it without referencing this class directly.
18
+ *
19
+ * Owns ALL OpenAI wire concerns extracted from the original voice-session orchestration:
20
+ * - WebRTC connect: mic tracks → peer connection, remote audio → hidden `<audio>` sink,
21
+ * the `'oai-events'` data channel, and the GA SDP handshake (see {@link performSdpHandshake}).
22
+ * - Event translation: GA + beta transcript event names, input transcription, tool calls,
23
+ * barge-in, playback-buffer events, and provider error frames.
24
+ * - The response state machine: `responseActive` set on `response.created` / cleared on
25
+ * `response.done`; tool-result `response.create`s queued while a response is in flight
26
+ * and flushed on `response.done` so the model ALWAYS voices delegated results.
27
+ * - Narration-kind tagging: {@link RequestSpokenUpdate} marks the NEXT response as
28
+ * `'narration'` so its transcripts are emitted with `Kind: 'narration'` (ephemeral).
29
+ * - Audible-playback tracking ({@link IsAudioPlaying}) from `output_audio_buffer.*` events.
30
+ */
31
+ let OpenAIRealtimeClient = class OpenAIRealtimeClient extends BaseRealtimeClient {
32
+ constructor() {
33
+ super(...arguments);
34
+ // ── Transport ──────────────────────────────────────────────────────────────
35
+ this.peerConnection = null;
36
+ /** Protected so test subclasses can inspect/inject; production code treats it as private. */
37
+ this.dataChannel = null;
38
+ this.remoteAudioEl = null;
39
+ this.micStream = null;
40
+ /**
41
+ * The server-built session config applied verbatim via `session.update` when the data
42
+ * channel opens. Protected so test subclasses can seed it without a full Connect.
43
+ */
44
+ this.sessionConfig = null;
45
+ // ── Response state machine ─────────────────────────────────────────────────
46
+ /** Accumulates the in-flight assistant transcript across delta frames. */
47
+ this.pendingAssistantText = '';
48
+ /** True while the model has a response in flight; gates narration + queues the tool result. */
49
+ this.responseActive = false;
50
+ /** Set when a tool result is ready while a response is active; sent on the next response.done. */
51
+ this.pendingResultResponse = false;
52
+ /**
53
+ * Set by {@link RequestSpokenUpdate} just before it sends its `response.create`, and
54
+ * CONSUMED by the very next `response.created` frame, which stamps
55
+ * {@link activeResponseKind} for that turn. Narration is only requested while the model
56
+ * is idle (hosts gate on {@link IsBusy}), so under normal ordering the next
57
+ * `response.created` is ours.
58
+ */
59
+ this.pendingNarrationKind = false;
60
+ /**
61
+ * The kind of the response currently in flight. Event ordering (confirmed against the
62
+ * live API): `response.created` → transcript deltas → `*_audio_transcript.done` →
63
+ * `response.done`. The transcript-done frame therefore arrives while the kind is still
64
+ * set, letting {@link onAssistantDone} classify the turn; `response.done` then resets
65
+ * the kind to `'normal'`.
66
+ */
67
+ this.activeResponseKind = 'normal';
68
+ /**
69
+ * True while the model's audio is audibly PLAYING in the browser (WebRTC
70
+ * `output_audio_buffer` started/stopped). Distinct from {@link responseActive} —
71
+ * generation finishes ahead of playback.
72
+ */
73
+ this.audioPlaying = false;
74
+ /**
75
+ * The client's own view of the session state — mirrors what {@link emitStateChange}
76
+ * last reported, EXCEPT after a tool call is emitted: the host typically shows its own
77
+ * busy state then, so the client silently leaves `'speaking'` (no emission) to preserve
78
+ * the host's indicator until the result reply starts (see {@link handleEvent}).
79
+ */
80
+ this.currentState = 'closed';
81
+ }
82
+ // ── BaseRealtimeClient: connection lifecycle ───────────────────────────────
83
+ /**
84
+ * Opens the client-direct OpenAI Realtime WebRTC connection: mic tracks onto a peer
85
+ * connection, a hidden remote-audio sink, the `'oai-events'` data channel, and the SDP
86
+ * handshake. `config.SessionConfig` is applied verbatim via `session.update` once the
87
+ * data channel opens; the client reports `'listening'` at that point.
88
+ */
89
+ async Connect(config, micStream) {
90
+ this.sessionConfig = config.SessionConfig;
91
+ this.micStream = micStream;
92
+ this.setState('connecting');
93
+ const pc = this.createPeerConnection();
94
+ this.peerConnection = pc;
95
+ this.attachMicrophone(pc, micStream);
96
+ this.attachRemoteAudio(pc);
97
+ this.adoptDataChannel(pc.createDataChannel('oai-events'));
98
+ // Audio-activity capability (base obligation #9): user side meters the mic stream
99
+ // now; the agent side attaches when the remote track arrives (attachRemoteAudio's
100
+ // ontrack). Null-safe — no-WebAudio environments leave the session un-metered.
101
+ this.attachInputAudioMeter(RealtimeAudioMeter.ForMicStream(micStream));
102
+ await this.performSdpHandshake(pc, config.EphemeralToken);
103
+ this.setState('connected');
104
+ }
105
+ /**
106
+ * Tears down the channel, peer connection, mic tracks, and audio sink, resets the
107
+ * response state machine, and emits a final `'closed'` (unless already `'error'`).
108
+ */
109
+ async Disconnect() {
110
+ this.closeAudioMeters();
111
+ this.micStream?.getTracks().forEach((t) => t.stop());
112
+ this.micStream = null;
113
+ if (this.dataChannel) {
114
+ try {
115
+ this.dataChannel.close();
116
+ }
117
+ catch { /* already closing */ }
118
+ this.dataChannel = null;
119
+ }
120
+ if (this.peerConnection) {
121
+ try {
122
+ this.peerConnection.close();
123
+ }
124
+ catch { /* already closing */ }
125
+ this.peerConnection = null;
126
+ }
127
+ if (this.remoteAudioEl) {
128
+ this.remoteAudioEl.srcObject = null;
129
+ this.remoteAudioEl.remove();
130
+ this.remoteAudioEl = null;
131
+ }
132
+ this.sessionConfig = null;
133
+ this.resetResponseState();
134
+ if (this.currentState !== 'error') {
135
+ this.setState('closed');
136
+ }
137
+ }
138
+ // ── BaseRealtimeClient: outbound actions ──────────────────────────────────
139
+ /**
140
+ * Injects typed text as a user-role `message` conversation item, then triggers a reply
141
+ * through the SAME collision-safe path tool results use ({@link requestResultResponse}).
142
+ * No-op when the data channel isn't open.
143
+ *
144
+ * **SendText implies barge-in** (base-contract rule): an active spoken response is
145
+ * cancelled via {@link CancelActiveResponse} before the text is injected, so the typed
146
+ * turn takes the floor immediately instead of waiting behind stale speech. When nothing
147
+ * is active the cancel is a no-op and the reply triggers immediately.
148
+ */
149
+ SendText(text) {
150
+ const channel = this.dataChannel;
151
+ if (!channel || channel.readyState !== 'open') {
152
+ return;
153
+ }
154
+ this.CancelActiveResponse();
155
+ this.sendEvent(channel, {
156
+ type: 'conversation.item.create',
157
+ item: {
158
+ type: 'message',
159
+ role: 'user',
160
+ content: [{ type: 'input_text', text }],
161
+ },
162
+ });
163
+ this.requestResultResponse();
164
+ }
165
+ /**
166
+ * @inheritdoc
167
+ *
168
+ * Sends `response.cancel` (only when a response is actually in flight) and — when audio
169
+ * is audibly playing — the WebRTC-only `output_audio_buffer.clear` client event so
170
+ * already-generated speech stops coming out of the speaker immediately. Resets the local
171
+ * response state machine (active flag, narration kind, accumulated transcript) but
172
+ * PRESERVES any queued tool-result trigger: delegated work is never affected by a
173
+ * floor-control cancel, and the queued trigger still fires on the cancelled response's
174
+ * trailing `response.done`. No-op when idle or when the channel is not open.
175
+ */
176
+ CancelActiveResponse() {
177
+ const channel = this.dataChannel;
178
+ if (!channel || channel.readyState !== 'open') {
179
+ return;
180
+ }
181
+ if (!this.responseActive && !this.audioPlaying) {
182
+ return; // nothing active — no-op by contract
183
+ }
184
+ if (this.responseActive) {
185
+ this.sendEvent(channel, { type: 'response.cancel' });
186
+ this.responseActive = false;
187
+ this.pendingNarrationKind = false;
188
+ this.activeResponseKind = 'normal';
189
+ this.pendingAssistantText = '';
190
+ }
191
+ if (this.audioPlaying) {
192
+ this.sendEvent(channel, { type: 'output_audio_buffer.clear' });
193
+ this.audioPlaying = false;
194
+ }
195
+ if (this.currentState === 'speaking') {
196
+ this.setState('listening');
197
+ }
198
+ }
199
+ /**
200
+ * Injects a system-role context item the model can draw on the next time it speaks,
201
+ * WITHOUT forcing a reply.
202
+ *
203
+ * NOTE: role must be 'system' — gpt-realtime rejects 'developer' items
204
+ * ("Developer messages are only supported for quicksilver sessions").
205
+ */
206
+ SendContextNote(text) {
207
+ const channel = this.dataChannel;
208
+ if (!channel) {
209
+ return;
210
+ }
211
+ this.sendEvent(channel, {
212
+ type: 'conversation.item.create',
213
+ item: {
214
+ type: 'message',
215
+ role: 'system',
216
+ content: [{ type: 'input_text', text }],
217
+ },
218
+ });
219
+ }
220
+ /**
221
+ * Triggers ONE short spoken update with the given instructions. Marks the upcoming
222
+ * response as `'narration'` (flag consumed by the next `response.created`) so its
223
+ * transcripts are emitted with `Kind: 'narration'` — ephemeral by contract. Sets
224
+ * {@link responseActive} eagerly so a tool result landing mid-narration queues
225
+ * instead of colliding.
226
+ *
227
+ * **Skips when busy** (base-contract collision rule — drivers MUST queue or skip):
228
+ * a `response.create` sent while a response is in flight would be rejected/garbled by
229
+ * the provider, and narration is disposable by contract, so the update is dropped with
230
+ * a debug log rather than queued to come out late and stale. Hosts SHOULD still gate
231
+ * on {@link IsBusy} / {@link IsAudioPlaying} for timing quality.
232
+ */
233
+ RequestSpokenUpdate(instructions) {
234
+ const channel = this.dataChannel;
235
+ if (!channel) {
236
+ return;
237
+ }
238
+ if (this.responseActive) {
239
+ console.debug('[OpenAIRealtimeClient] RequestSpokenUpdate skipped — a response is already in flight (narration is disposable).');
240
+ return;
241
+ }
242
+ this.responseActive = true;
243
+ this.pendingNarrationKind = true;
244
+ this.sendEvent(channel, {
245
+ type: 'response.create',
246
+ response: { instructions },
247
+ });
248
+ }
249
+ /**
250
+ * Sends the tool result back as a `function_call_output` conversation item, then
251
+ * triggers a reply — immediately if the model is idle, otherwise queued until the
252
+ * current response (e.g. a progress narration) finishes. Without the queueing the
253
+ * result's `response.create` would collide with an in-flight narration and be dropped,
254
+ * leaving the model silent when delegated work comes back.
255
+ */
256
+ SendToolResult(callID, outputJson) {
257
+ const channel = this.dataChannel;
258
+ if (!channel) {
259
+ return;
260
+ }
261
+ this.sendEvent(channel, {
262
+ type: 'conversation.item.create',
263
+ item: {
264
+ type: 'function_call_output',
265
+ call_id: callID,
266
+ output: outputJson,
267
+ },
268
+ });
269
+ this.requestResultResponse();
270
+ }
271
+ /** Mute / unmute by toggling the mic tracks' `enabled` flag (transport stays up). */
272
+ SetMuted(muted) {
273
+ const tracks = this.micStream?.getAudioTracks() ?? [];
274
+ for (const t of tracks) {
275
+ t.enabled = !muted;
276
+ }
277
+ }
278
+ /** @inheritdoc */
279
+ get IsBusy() {
280
+ return this.responseActive;
281
+ }
282
+ /** @inheritdoc */
283
+ get IsAudioPlaying() {
284
+ return this.audioPlaying;
285
+ }
286
+ // ── Overridable creation seams (tests inject fakes — no network / WebRTC) ──
287
+ /** Creates the peer connection. Production returns a real `RTCPeerConnection`. */
288
+ createPeerConnection() {
289
+ return new RTCPeerConnection();
290
+ }
291
+ /** Creates a hidden `<audio>` element to play the model's audio output. */
292
+ createAudioSink() {
293
+ const el = document.createElement('audio');
294
+ el.autoplay = true;
295
+ el.style.display = 'none';
296
+ document.body.appendChild(el);
297
+ return el;
298
+ }
299
+ /**
300
+ * POSTs the raw SDP offer to OpenAI's Realtime WebRTC endpoint and returns the answer SDP.
301
+ *
302
+ * GA browser flow (confirmed against the OpenAI Realtime WebRTC guide): POST to
303
+ * `https://api.openai.com/v1/realtime/calls` with **no** query params and **no**
304
+ * `OpenAI-Beta` header. The ephemeral client secret already encodes the model + session
305
+ * config (set server-side at mint), so the browser must not specify the model — passing
306
+ * `?model=` returns an empty 400. The answer comes back as raw `application/sdp`.
307
+ *
308
+ * @param offerSdp The local SDP offer.
309
+ * @param ephemeralToken The server-minted ephemeral client secret.
310
+ * @returns The answer SDP.
311
+ */
312
+ async postSdpOffer(offerSdp, ephemeralToken) {
313
+ const response = await fetch('https://api.openai.com/v1/realtime/calls', {
314
+ method: 'POST',
315
+ body: offerSdp,
316
+ headers: {
317
+ Authorization: `Bearer ${ephemeralToken}`,
318
+ 'Content-Type': 'application/sdp',
319
+ },
320
+ });
321
+ if (!response.ok) {
322
+ const detail = await response.text().catch(() => '');
323
+ throw new Error(`OpenAI WebRTC handshake failed (${response.status}): ${detail}`);
324
+ }
325
+ return response.text();
326
+ }
327
+ // ── Connection internals ───────────────────────────────────────────────────
328
+ /** Streams the mic tracks to the provider. */
329
+ attachMicrophone(pc, micStream) {
330
+ for (const track of micStream.getAudioTracks()) {
331
+ pc.addTrack(track, micStream);
332
+ }
333
+ }
334
+ /** Routes the provider's audio track into the hidden `<audio>` sink. */
335
+ attachRemoteAudio(pc) {
336
+ this.remoteAudioEl = this.createAudioSink();
337
+ pc.ontrack = (e) => {
338
+ if (this.remoteAudioEl && e.streams[0]) {
339
+ this.remoteAudioEl.srcObject = e.streams[0];
340
+ // Agent-side audio meter taps the remote stream (obligation #9). The
341
+ // analyser sinks nowhere — playback still flows through the <audio> element.
342
+ this.attachOutputAudioMeter(RealtimeAudioMeter.ForStream(e.streams[0]));
343
+ }
344
+ };
345
+ }
346
+ /**
347
+ * Adopts + wires the events data channel: applies the session config and reports
348
+ * `'listening'` on open; translates inbound frames; reports transport errors / closure.
349
+ * Protected so test subclasses can inject a fake channel directly.
350
+ */
351
+ adoptDataChannel(channel) {
352
+ this.dataChannel = channel;
353
+ channel.onopen = () => {
354
+ this.applySessionConfig(channel);
355
+ this.setState('listening');
356
+ };
357
+ channel.onmessage = (e) => {
358
+ this.handleChannelMessage(e);
359
+ };
360
+ channel.onerror = (e) => {
361
+ this.emitError({ Message: `Data channel error: ${String(e)}`, Fatal: true });
362
+ this.setState('error');
363
+ };
364
+ channel.onclose = () => {
365
+ if (this.currentState !== 'error') {
366
+ this.setState('closed');
367
+ }
368
+ };
369
+ }
370
+ /** Performs the offer/answer SDP exchange (POST seam: {@link postSdpOffer}). */
371
+ async performSdpHandshake(pc, ephemeralToken) {
372
+ const offer = await pc.createOffer();
373
+ await pc.setLocalDescription(offer);
374
+ const answerSdp = await this.postSdpOffer(offer.sdp ?? '', ephemeralToken);
375
+ await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp });
376
+ }
377
+ /**
378
+ * Sends the server-controlled session config (instructions + tools) as a
379
+ * `session.update` so the co-agent's identity and tool set apply. Skipped when the
380
+ * host supplied no config (e.g. it failed to parse the server payload — the host
381
+ * already logged that; sending an EMPTY `session.update` would be wrong).
382
+ */
383
+ applySessionConfig(channel) {
384
+ if (!this.sessionConfig || Object.keys(this.sessionConfig).length === 0) {
385
+ return;
386
+ }
387
+ this.sendEvent(channel, { type: 'session.update', session: this.sessionConfig });
388
+ }
389
+ // ── Inbound event translation ──────────────────────────────────────────────
390
+ /** Parses an inbound channel message and dispatches it to the typed handler. */
391
+ handleChannelMessage(e) {
392
+ let event;
393
+ try {
394
+ event = JSON.parse(e.data);
395
+ }
396
+ catch {
397
+ return; // non-JSON frame — ignore
398
+ }
399
+ if (event === null || typeof event !== 'object') {
400
+ return; // valid JSON but not an event object (e.g. "null", a number) — ignore
401
+ }
402
+ this.handleEvent(event);
403
+ }
404
+ /** Dispatches a typed OpenAI realtime server event to the appropriate behavior. */
405
+ handleEvent(event) {
406
+ switch (event.type) {
407
+ case 'response.output_audio_transcript.delta':
408
+ case 'response.audio_transcript.delta':
409
+ this.onAssistantDelta(event.delta);
410
+ break;
411
+ case 'response.output_audio_transcript.done':
412
+ case 'response.audio_transcript.done':
413
+ this.onAssistantDone(event.transcript);
414
+ break;
415
+ case 'conversation.item.input_audio_transcription.completed':
416
+ this.onUserTranscript(event.transcript);
417
+ break;
418
+ case 'response.function_call_arguments.done':
419
+ this.onToolCallFrame(event);
420
+ break;
421
+ case 'input_audio_buffer.speech_started':
422
+ // The user started speaking. This is a TRUE barge-in only when it cut off
423
+ // active model output (a response in flight or audio audibly playing) —
424
+ // a normal turn while the model is idle is NOT an interruption, so the
425
+ // emission is gated (base-contract rule). The provider handles cancelling
426
+ // its own turn; we reflect that the user has the floor again. NOTE: the
427
+ // trailing `output_audio_buffer.cleared` frame deliberately does NOT emit —
428
+ // it also follows our own CancelActiveResponse, and a self-initiated cancel
429
+ // must never look like a user barge-in (hosts abort delegated work on it).
430
+ if (this.responseActive || this.audioPlaying) {
431
+ this.emitInterruption();
432
+ }
433
+ this.setState('listening');
434
+ break;
435
+ case 'response.created':
436
+ this.responseActive = true;
437
+ // Stamp the kind of THIS response: 'narration' only when the flag was set by
438
+ // RequestSpokenUpdate immediately before its response.create (consumed here).
439
+ this.activeResponseKind = this.pendingNarrationKind ? 'narration' : 'normal';
440
+ this.pendingNarrationKind = false;
441
+ break;
442
+ case 'output_audio_buffer.started':
443
+ this.audioPlaying = true;
444
+ break;
445
+ case 'output_audio_buffer.stopped':
446
+ case 'output_audio_buffer.cleared':
447
+ this.audioPlaying = false;
448
+ if (this.currentState === 'speaking' && !this.responseActive) {
449
+ this.setState('listening');
450
+ }
451
+ break;
452
+ case 'response.done':
453
+ // A turn finished — release the lock and speak any queued tool result so the
454
+ // model always voices the answer when delegated work comes back.
455
+ // The transcript-done frame for this turn has already arrived (it precedes
456
+ // response.done), so it's safe to reset the response kind here.
457
+ this.responseActive = false;
458
+ this.activeResponseKind = 'normal';
459
+ this.emitResponseUsage(event);
460
+ this.flushPendingResultResponse();
461
+ if (this.currentState === 'speaking') {
462
+ this.setState('listening');
463
+ }
464
+ break;
465
+ case 'error':
466
+ this.onErrorFrame(event);
467
+ break;
468
+ default:
469
+ // Unhandled event types are expected (the provider emits many); no-op.
470
+ break;
471
+ }
472
+ }
473
+ /** Appends an assistant transcript delta, reflects `'speaking'`, and emits the delta. */
474
+ onAssistantDelta(delta) {
475
+ if (this.currentState !== 'speaking') {
476
+ this.setState('speaking');
477
+ }
478
+ this.pendingAssistantText += delta;
479
+ this.emitTranscript({ Role: 'Assistant', Text: delta, IsFinal: false, Kind: this.activeResponseKind });
480
+ }
481
+ /**
482
+ * Finalizes the assistant turn: emits the final transcript tagged with the ACTIVE
483
+ * response kind (the transcript-done frame arrives BEFORE `response.done`, so
484
+ * {@link activeResponseKind} still reflects this turn), then returns to `'listening'`.
485
+ * Empty turns emit nothing.
486
+ */
487
+ onAssistantDone(transcript) {
488
+ const finalText = transcript || this.pendingAssistantText;
489
+ this.pendingAssistantText = '';
490
+ if (finalText.trim().length > 0) {
491
+ this.emitTranscript({ Role: 'Assistant', Text: finalText, IsFinal: true, Kind: this.activeResponseKind });
492
+ }
493
+ if (this.currentState === 'speaking') {
494
+ this.setState('listening');
495
+ }
496
+ }
497
+ /** Emits the final transcription of the user's spoken input (always `Kind: 'normal'`). */
498
+ onUserTranscript(transcript) {
499
+ this.emitTranscript({ Role: 'User', Text: transcript, IsFinal: true, Kind: 'normal' });
500
+ }
501
+ /**
502
+ * Surfaces a completed tool call to the host. The client silently leaves the
503
+ * `'speaking'` state (NO emission) so a host-rendered busy indicator (e.g. "thinking")
504
+ * isn't clobbered by this turn's trailing `response.done` / playback-stopped frames —
505
+ * those only transition when the client still considers itself `'speaking'`.
506
+ */
507
+ onToolCallFrame(call) {
508
+ if (this.currentState === 'speaking') {
509
+ this.currentState = 'connected';
510
+ }
511
+ this.emitToolCall({ CallID: call.call_id, ToolName: call.name, ArgumentsJson: call.arguments });
512
+ }
513
+ /**
514
+ * Emits the completed response's usage to the host as a DELTA (the GA `response.done`
515
+ * usage payload covers exactly this response, so it is already incremental — the
516
+ * `OnUsage` contract's preferred shape). Frames without a usage payload emit nothing.
517
+ */
518
+ emitResponseUsage(event) {
519
+ const usage = event.response?.usage;
520
+ if (!usage) {
521
+ return;
522
+ }
523
+ this.emitUsage({
524
+ InputTokens: typeof usage.input_tokens === 'number' ? usage.input_tokens : undefined,
525
+ OutputTokens: typeof usage.output_tokens === 'number' ? usage.output_tokens : undefined,
526
+ Raw: usage,
527
+ });
528
+ }
529
+ /** Surfaces a provider error frame (non-fatal; the session continues). */
530
+ onErrorFrame(event) {
531
+ this.emitError({
532
+ Message: event.error?.message ?? 'Unknown provider error',
533
+ Code: event.error?.code,
534
+ Fatal: false,
535
+ });
536
+ }
537
+ // ── Response state machine ─────────────────────────────────────────────────
538
+ /**
539
+ * Asks the model to speak (a tool result or typed-text reply) — immediately if it's
540
+ * idle, otherwise queued until the current response finishes. An immediate trigger
541
+ * also CONSUMES any queued trigger debt: every payload item is already in the
542
+ * conversation, so one `response.create` voices everything (e.g. typed text barging
543
+ * in over a narration that had tool results queued behind it).
544
+ */
545
+ requestResultResponse() {
546
+ if (!this.dataChannel) {
547
+ return;
548
+ }
549
+ if (this.responseActive) {
550
+ this.pendingResultResponse = true;
551
+ return;
552
+ }
553
+ this.pendingResultResponse = false;
554
+ this.responseActive = true;
555
+ this.sendEvent(this.dataChannel, { type: 'response.create' });
556
+ this.setState('speaking');
557
+ }
558
+ /** On a turn completing, fire any queued tool-result response so the answer is spoken. */
559
+ flushPendingResultResponse() {
560
+ if (!this.pendingResultResponse || !this.dataChannel) {
561
+ return;
562
+ }
563
+ this.pendingResultResponse = false;
564
+ this.responseActive = true;
565
+ this.sendEvent(this.dataChannel, { type: 'response.create' });
566
+ this.setState('speaking');
567
+ }
568
+ /** Resets the per-session response state machine (used on Disconnect). */
569
+ resetResponseState() {
570
+ this.pendingAssistantText = '';
571
+ this.responseActive = false;
572
+ this.pendingResultResponse = false;
573
+ this.pendingNarrationKind = false;
574
+ this.activeResponseKind = 'normal';
575
+ this.audioPlaying = false;
576
+ }
577
+ // ── Helpers ────────────────────────────────────────────────────────────────
578
+ /** Updates the client's own state view and emits the change to the host. */
579
+ setState(state) {
580
+ this.currentState = state;
581
+ this.emitStateChange(state);
582
+ }
583
+ /** Serializes + sends a client event over the data channel (only when open). */
584
+ sendEvent(channel, event) {
585
+ if (channel.readyState === 'open') {
586
+ channel.send(JSON.stringify(event));
587
+ }
588
+ }
589
+ };
590
+ OpenAIRealtimeClient = __decorate([
591
+ RegisterClass(BaseRealtimeClient, 'openai')
592
+ ], OpenAIRealtimeClient);
593
+ export { OpenAIRealtimeClient };
594
+ /**
595
+ * Tree-shaking prevention: bundlers cannot see that {@link OpenAIRealtimeClient} is
596
+ * instantiated dynamically through the ClassFactory, so a consumer must call this no-op
597
+ * to create a static code path that keeps the `@RegisterClass` side effect alive.
598
+ */
599
+ export function LoadOpenAIRealtimeClient() {
600
+ // intentional no-op — the static import of this module is the point
601
+ }
602
+ //# sourceMappingURL=openAIRealtimeClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openAIRealtimeClient.js","sourceRoot":"","sources":["../../src/drivers/openAIRealtimeClient.ts"],"names":[],"mappings":"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"}