@estuary-ai/sdk 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +4 -0
- package/dist/index.js +42 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +42 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -23,6 +23,8 @@ interface EstuaryConfig {
|
|
|
23
23
|
realtimeMemory?: boolean;
|
|
24
24
|
/** Suppress mic during TTS playback (software AEC fallback, disables barge-in). Default: false */
|
|
25
25
|
suppressMicDuringPlayback?: boolean;
|
|
26
|
+
/** Proactively interrupt bot audio when user starts speaking (default: true) */
|
|
27
|
+
autoInterruptOnSpeech?: boolean;
|
|
26
28
|
}
|
|
27
29
|
type VoiceTransport = 'websocket' | 'livekit' | 'auto';
|
|
28
30
|
declare enum ConnectionState {
|
|
@@ -243,6 +245,7 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
|
|
|
243
245
|
private _memory;
|
|
244
246
|
private _sessionInfo;
|
|
245
247
|
private actionParsers;
|
|
248
|
+
private _hasAutoInterrupted;
|
|
246
249
|
constructor(config: EstuaryConfig);
|
|
247
250
|
/** Memory API client for querying memories, graphs, and facts */
|
|
248
251
|
get memory(): MemoryClient;
|
|
@@ -282,6 +285,7 @@ declare class EstuaryClient extends TypedEventEmitter<EstuaryEventMap> {
|
|
|
282
285
|
private forwardSocketEvents;
|
|
283
286
|
private handleBotResponse;
|
|
284
287
|
private handleBotVoice;
|
|
288
|
+
private maybeAutoInterrupt;
|
|
285
289
|
}
|
|
286
290
|
|
|
287
291
|
declare enum ErrorCode {
|
package/dist/index.js
CHANGED
|
@@ -9203,11 +9203,30 @@ var AudioPlayer = class {
|
|
|
9203
9203
|
currentSource = null;
|
|
9204
9204
|
currentMessageId = null;
|
|
9205
9205
|
isPlaying = false;
|
|
9206
|
+
_isCleared = false;
|
|
9207
|
+
_interruptedMessageId = null;
|
|
9206
9208
|
constructor(sampleRate, onEvent) {
|
|
9207
9209
|
this.sampleRate = sampleRate;
|
|
9208
9210
|
this.onEvent = onEvent;
|
|
9209
9211
|
}
|
|
9212
|
+
/** Whether audio is currently playing */
|
|
9213
|
+
get playing() {
|
|
9214
|
+
return this.isPlaying;
|
|
9215
|
+
}
|
|
9216
|
+
/** The messageId of the currently playing audio, or null */
|
|
9217
|
+
get playingMessageId() {
|
|
9218
|
+
return this.currentMessageId;
|
|
9219
|
+
}
|
|
9220
|
+
/** Mark a messageId as interrupted so late-arriving chunks are dropped */
|
|
9221
|
+
setInterruptedMessageId(id) {
|
|
9222
|
+
this._interruptedMessageId = id;
|
|
9223
|
+
}
|
|
9210
9224
|
enqueue(voice) {
|
|
9225
|
+
if (voice.messageId === this._interruptedMessageId) return;
|
|
9226
|
+
if (this._interruptedMessageId && voice.messageId !== this._interruptedMessageId) {
|
|
9227
|
+
this._interruptedMessageId = null;
|
|
9228
|
+
}
|
|
9229
|
+
this._isCleared = false;
|
|
9211
9230
|
const ctx = this.getAudioContext();
|
|
9212
9231
|
if (!ctx) return;
|
|
9213
9232
|
const pcm16 = base64ToInt16Array(voice.audio);
|
|
@@ -9220,6 +9239,7 @@ var AudioPlayer = class {
|
|
|
9220
9239
|
}
|
|
9221
9240
|
}
|
|
9222
9241
|
clear() {
|
|
9242
|
+
this._isCleared = true;
|
|
9223
9243
|
this.queue.length = 0;
|
|
9224
9244
|
if (this.currentSource) {
|
|
9225
9245
|
try {
|
|
@@ -9229,6 +9249,7 @@ var AudioPlayer = class {
|
|
|
9229
9249
|
}
|
|
9230
9250
|
this.currentSource = null;
|
|
9231
9251
|
}
|
|
9252
|
+
if (this.audioElement) this.audioElement.muted = true;
|
|
9232
9253
|
this.isPlaying = false;
|
|
9233
9254
|
this.currentMessageId = null;
|
|
9234
9255
|
}
|
|
@@ -9272,6 +9293,7 @@ var AudioPlayer = class {
|
|
|
9272
9293
|
return ctx;
|
|
9273
9294
|
}
|
|
9274
9295
|
playNext() {
|
|
9296
|
+
if (this._isCleared) return;
|
|
9275
9297
|
const ctx = this.getAudioContext();
|
|
9276
9298
|
if (!ctx || this.queue.length === 0) {
|
|
9277
9299
|
if (this.isPlaying && this.currentMessageId) {
|
|
@@ -9295,9 +9317,11 @@ var AudioPlayer = class {
|
|
|
9295
9317
|
source.connect(this.mediaStreamDest ?? ctx.destination);
|
|
9296
9318
|
this.currentSource = source;
|
|
9297
9319
|
source.onended = () => {
|
|
9320
|
+
if (this._isCleared) return;
|
|
9298
9321
|
this.currentSource = null;
|
|
9299
9322
|
this.playNext();
|
|
9300
9323
|
};
|
|
9324
|
+
if (this.audioElement) this.audioElement.muted = false;
|
|
9301
9325
|
ctx.resume().catch(() => {
|
|
9302
9326
|
});
|
|
9303
9327
|
source.start();
|
|
@@ -9406,6 +9430,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9406
9430
|
_memory;
|
|
9407
9431
|
_sessionInfo = null;
|
|
9408
9432
|
actionParsers = /* @__PURE__ */ new Map();
|
|
9433
|
+
_hasAutoInterrupted = false;
|
|
9409
9434
|
constructor(config) {
|
|
9410
9435
|
super();
|
|
9411
9436
|
this.config = config;
|
|
@@ -9456,6 +9481,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9456
9481
|
interrupt(messageId) {
|
|
9457
9482
|
this.ensureConnected();
|
|
9458
9483
|
this.socketManager.emitEvent("client_interrupt", { message_id: messageId });
|
|
9484
|
+
this.audioPlayer?.setInterruptedMessageId(messageId ?? this.audioPlayer.playingMessageId);
|
|
9459
9485
|
this.audioPlayer?.clear();
|
|
9460
9486
|
if (this.config.suppressMicDuringPlayback) {
|
|
9461
9487
|
this.voiceManager?.setSuppressed?.(false);
|
|
@@ -9497,6 +9523,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9497
9523
|
if (!this.audioPlayer && typeof AudioContext !== "undefined") {
|
|
9498
9524
|
this.audioPlayer = new AudioPlayer(sampleRate, (event) => {
|
|
9499
9525
|
if (event.type === "started") {
|
|
9526
|
+
this._hasAutoInterrupted = false;
|
|
9500
9527
|
this.emit("audioPlaybackStarted", event.messageId);
|
|
9501
9528
|
if (this.config.suppressMicDuringPlayback) {
|
|
9502
9529
|
this.voiceManager?.setSuppressed?.(true);
|
|
@@ -9557,10 +9584,15 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9557
9584
|
this.socketManager.on("connectionStateChanged", (state) => this.emit("connectionStateChanged", state));
|
|
9558
9585
|
this.socketManager.on("botResponse", (response) => this.handleBotResponse(response));
|
|
9559
9586
|
this.socketManager.on("botVoice", (voice) => this.handleBotVoice(voice));
|
|
9560
|
-
this.socketManager.on("sttResponse", (response) =>
|
|
9587
|
+
this.socketManager.on("sttResponse", (response) => {
|
|
9588
|
+
this.maybeAutoInterrupt(response);
|
|
9589
|
+
this.emit("sttResponse", response);
|
|
9590
|
+
});
|
|
9561
9591
|
this.socketManager.on("interrupt", (data) => {
|
|
9592
|
+
this.audioPlayer?.setInterruptedMessageId(data.messageId ?? null);
|
|
9562
9593
|
this.audioPlayer?.clear();
|
|
9563
9594
|
this.actionParsers.clear();
|
|
9595
|
+
this._hasAutoInterrupted = false;
|
|
9564
9596
|
if (this.config.suppressMicDuringPlayback) {
|
|
9565
9597
|
this.voiceManager?.setSuppressed?.(false);
|
|
9566
9598
|
}
|
|
@@ -9600,6 +9632,15 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9600
9632
|
this.emit("botVoice", voice);
|
|
9601
9633
|
this.audioPlayer?.enqueue(voice);
|
|
9602
9634
|
}
|
|
9635
|
+
maybeAutoInterrupt(stt) {
|
|
9636
|
+
if ((this.config.autoInterruptOnSpeech ?? true) === false) return;
|
|
9637
|
+
if (this.config.suppressMicDuringPlayback) return;
|
|
9638
|
+
if (stt.isFinal) return;
|
|
9639
|
+
if (!this.audioPlayer?.playing) return;
|
|
9640
|
+
if (this._hasAutoInterrupted) return;
|
|
9641
|
+
this._hasAutoInterrupted = true;
|
|
9642
|
+
this.interrupt();
|
|
9643
|
+
}
|
|
9603
9644
|
};
|
|
9604
9645
|
|
|
9605
9646
|
// src/index.ts
|