@estuary-ai/sdk 0.1.6 → 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 +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 {
|
|
@@ -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,9 +9316,12 @@ 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
|
};
|
|
9323
|
+
ctx.resume().catch(() => {
|
|
9324
|
+
});
|
|
9301
9325
|
source.start();
|
|
9302
9326
|
}
|
|
9303
9327
|
};
|
|
@@ -9404,6 +9428,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9404
9428
|
_memory;
|
|
9405
9429
|
_sessionInfo = null;
|
|
9406
9430
|
actionParsers = /* @__PURE__ */ new Map();
|
|
9431
|
+
_hasAutoInterrupted = false;
|
|
9407
9432
|
constructor(config) {
|
|
9408
9433
|
super();
|
|
9409
9434
|
this.config = config;
|
|
@@ -9454,6 +9479,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9454
9479
|
interrupt(messageId) {
|
|
9455
9480
|
this.ensureConnected();
|
|
9456
9481
|
this.socketManager.emitEvent("client_interrupt", { message_id: messageId });
|
|
9482
|
+
this.audioPlayer?.setInterruptedMessageId(messageId ?? this.audioPlayer.playingMessageId);
|
|
9457
9483
|
this.audioPlayer?.clear();
|
|
9458
9484
|
if (this.config.suppressMicDuringPlayback) {
|
|
9459
9485
|
this.voiceManager?.setSuppressed?.(false);
|
|
@@ -9495,6 +9521,7 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9495
9521
|
if (!this.audioPlayer && typeof AudioContext !== "undefined") {
|
|
9496
9522
|
this.audioPlayer = new AudioPlayer(sampleRate, (event) => {
|
|
9497
9523
|
if (event.type === "started") {
|
|
9524
|
+
this._hasAutoInterrupted = false;
|
|
9498
9525
|
this.emit("audioPlaybackStarted", event.messageId);
|
|
9499
9526
|
if (this.config.suppressMicDuringPlayback) {
|
|
9500
9527
|
this.voiceManager?.setSuppressed?.(true);
|
|
@@ -9555,10 +9582,15 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9555
9582
|
this.socketManager.on("connectionStateChanged", (state) => this.emit("connectionStateChanged", state));
|
|
9556
9583
|
this.socketManager.on("botResponse", (response) => this.handleBotResponse(response));
|
|
9557
9584
|
this.socketManager.on("botVoice", (voice) => this.handleBotVoice(voice));
|
|
9558
|
-
this.socketManager.on("sttResponse", (response) =>
|
|
9585
|
+
this.socketManager.on("sttResponse", (response) => {
|
|
9586
|
+
this.maybeAutoInterrupt(response);
|
|
9587
|
+
this.emit("sttResponse", response);
|
|
9588
|
+
});
|
|
9559
9589
|
this.socketManager.on("interrupt", (data) => {
|
|
9590
|
+
this.audioPlayer?.setInterruptedMessageId(data.messageId ?? null);
|
|
9560
9591
|
this.audioPlayer?.clear();
|
|
9561
9592
|
this.actionParsers.clear();
|
|
9593
|
+
this._hasAutoInterrupted = false;
|
|
9562
9594
|
if (this.config.suppressMicDuringPlayback) {
|
|
9563
9595
|
this.voiceManager?.setSuppressed?.(false);
|
|
9564
9596
|
}
|
|
@@ -9598,6 +9630,15 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9598
9630
|
this.emit("botVoice", voice);
|
|
9599
9631
|
this.audioPlayer?.enqueue(voice);
|
|
9600
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
|
+
}
|
|
9601
9642
|
};
|
|
9602
9643
|
|
|
9603
9644
|
// src/index.ts
|