@estuary-ai/sdk 0.1.7 → 0.1.8
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 +40 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +40 -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 {
|
|
@@ -9272,6 +9292,7 @@ var AudioPlayer = class {
|
|
|
9272
9292
|
return ctx;
|
|
9273
9293
|
}
|
|
9274
9294
|
playNext() {
|
|
9295
|
+
if (this._isCleared) return;
|
|
9275
9296
|
const ctx = this.getAudioContext();
|
|
9276
9297
|
if (!ctx || this.queue.length === 0) {
|
|
9277
9298
|
if (this.isPlaying && this.currentMessageId) {
|
|
@@ -9295,6 +9316,7 @@ var AudioPlayer = class {
|
|
|
9295
9316
|
source.connect(this.mediaStreamDest ?? ctx.destination);
|
|
9296
9317
|
this.currentSource = source;
|
|
9297
9318
|
source.onended = () => {
|
|
9319
|
+
if (this._isCleared) return;
|
|
9298
9320
|
this.currentSource = null;
|
|
9299
9321
|
this.playNext();
|
|
9300
9322
|
};
|
|
@@ -9406,6 +9428,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9406
9428
|
_memory;
|
|
9407
9429
|
_sessionInfo = null;
|
|
9408
9430
|
actionParsers = /* @__PURE__ */ new Map();
|
|
9431
|
+
_hasAutoInterrupted = false;
|
|
9409
9432
|
constructor(config) {
|
|
9410
9433
|
super();
|
|
9411
9434
|
this.config = config;
|
|
@@ -9456,6 +9479,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9456
9479
|
interrupt(messageId) {
|
|
9457
9480
|
this.ensureConnected();
|
|
9458
9481
|
this.socketManager.emitEvent("client_interrupt", { message_id: messageId });
|
|
9482
|
+
this.audioPlayer?.setInterruptedMessageId(messageId ?? this.audioPlayer.playingMessageId);
|
|
9459
9483
|
this.audioPlayer?.clear();
|
|
9460
9484
|
if (this.config.suppressMicDuringPlayback) {
|
|
9461
9485
|
this.voiceManager?.setSuppressed?.(false);
|
|
@@ -9497,6 +9521,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9497
9521
|
if (!this.audioPlayer && typeof AudioContext !== "undefined") {
|
|
9498
9522
|
this.audioPlayer = new AudioPlayer(sampleRate, (event) => {
|
|
9499
9523
|
if (event.type === "started") {
|
|
9524
|
+
this._hasAutoInterrupted = false;
|
|
9500
9525
|
this.emit("audioPlaybackStarted", event.messageId);
|
|
9501
9526
|
if (this.config.suppressMicDuringPlayback) {
|
|
9502
9527
|
this.voiceManager?.setSuppressed?.(true);
|
|
@@ -9557,10 +9582,15 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9557
9582
|
this.socketManager.on("connectionStateChanged", (state) => this.emit("connectionStateChanged", state));
|
|
9558
9583
|
this.socketManager.on("botResponse", (response) => this.handleBotResponse(response));
|
|
9559
9584
|
this.socketManager.on("botVoice", (voice) => this.handleBotVoice(voice));
|
|
9560
|
-
this.socketManager.on("sttResponse", (response) =>
|
|
9585
|
+
this.socketManager.on("sttResponse", (response) => {
|
|
9586
|
+
this.maybeAutoInterrupt(response);
|
|
9587
|
+
this.emit("sttResponse", response);
|
|
9588
|
+
});
|
|
9561
9589
|
this.socketManager.on("interrupt", (data) => {
|
|
9590
|
+
this.audioPlayer?.setInterruptedMessageId(data.messageId ?? null);
|
|
9562
9591
|
this.audioPlayer?.clear();
|
|
9563
9592
|
this.actionParsers.clear();
|
|
9593
|
+
this._hasAutoInterrupted = false;
|
|
9564
9594
|
if (this.config.suppressMicDuringPlayback) {
|
|
9565
9595
|
this.voiceManager?.setSuppressed?.(false);
|
|
9566
9596
|
}
|
|
@@ -9600,6 +9630,15 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9600
9630
|
this.emit("botVoice", voice);
|
|
9601
9631
|
this.audioPlayer?.enqueue(voice);
|
|
9602
9632
|
}
|
|
9633
|
+
maybeAutoInterrupt(stt) {
|
|
9634
|
+
if ((this.config.autoInterruptOnSpeech ?? true) === false) return;
|
|
9635
|
+
if (this.config.suppressMicDuringPlayback) return;
|
|
9636
|
+
if (stt.isFinal) return;
|
|
9637
|
+
if (!this.audioPlayer?.playing) return;
|
|
9638
|
+
if (this._hasAutoInterrupted) return;
|
|
9639
|
+
this._hasAutoInterrupted = true;
|
|
9640
|
+
this.interrupt();
|
|
9641
|
+
}
|
|
9603
9642
|
};
|
|
9604
9643
|
|
|
9605
9644
|
// src/index.ts
|