@livekit/agents-plugin-deepgram 1.5.0 → 1.5.2

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/src/stt_v2.ts CHANGED
@@ -98,6 +98,10 @@ export class STTv2 extends stt.STT {
98
98
  #opts: STTv2Options;
99
99
  #apiKey: string;
100
100
  #logger = log();
101
+ // session keyterm propagation)
102
+ #streams = new Set<WeakRef<SpeechStreamv2>>();
103
+ #userKeyterms: string[];
104
+ #sessionKeyterms: string[] = [];
101
105
 
102
106
  /**
103
107
  * Create a new Deepgram STTv2 instance.
@@ -120,6 +124,7 @@ export class STTv2 extends stt.STT {
120
124
  streaming: true,
121
125
  interimResults: true,
122
126
  alignedTranscript: 'word',
127
+ keyterms: true,
123
128
  });
124
129
 
125
130
  this.#opts = {
@@ -127,6 +132,7 @@ export class STTv2 extends stt.STT {
127
132
  ...opts,
128
133
  language: opts.language ? normalizeLanguage(opts.language) : defaultSTTv2Options.language,
129
134
  };
135
+ this.#userKeyterms = [...this.#opts.keyterms];
130
136
 
131
137
  const apiKey = opts.apiKey || process.env.DEEPGRAM_API_KEY;
132
138
  if (!apiKey) {
@@ -176,7 +182,9 @@ export class STTv2 extends stt.STT {
176
182
  */
177
183
  stream(options?: { connOptions?: APIConnectOptions }): stt.SpeechStream {
178
184
  const streamOpts = { ...this.#opts, apiKey: this.#apiKey };
179
- return new SpeechStreamv2(this, streamOpts, options?.connOptions);
185
+ const stream = new SpeechStreamv2(this, streamOpts, options?.connOptions);
186
+ this.#streams.add(new WeakRef(stream));
187
+ return stream;
180
188
  }
181
189
 
182
190
  /**
@@ -185,9 +193,14 @@ export class STTv2 extends stt.STT {
185
193
  * @param opts - Partial options to update
186
194
  */
187
195
  updateOptions(opts: Partial<STTv2Options>) {
196
+ const nextOpts = { ...opts };
197
+ if (nextOpts.keyterms !== undefined) {
198
+ this.#userKeyterms = [...nextOpts.keyterms];
199
+ nextOpts.keyterms = [...new Set([...this.#userKeyterms, ...this.#sessionKeyterms])];
200
+ }
188
201
  this.#opts = {
189
202
  ...this.#opts,
190
- ...opts,
203
+ ...nextOpts,
191
204
  language:
192
205
  opts.language !== undefined ? normalizeLanguage(opts.language) : this.#opts.language,
193
206
  };
@@ -205,6 +218,31 @@ export class STTv2 extends stt.STT {
205
218
  }
206
219
  this.#logger.debug('Updated STTv2 options');
207
220
  }
221
+
222
+ override _updateSessionKeyterms(keyterms: string[]): void {
223
+ if (
224
+ keyterms.length === this.#sessionKeyterms.length &&
225
+ keyterms.every((t, i) => t === this.#sessionKeyterms[i])
226
+ ) {
227
+ return;
228
+ }
229
+ this.#sessionKeyterms = [...keyterms];
230
+ const merged = [...new Set([...this.#userKeyterms, ...keyterms])];
231
+ this.#opts.keyterms = merged;
232
+ for (const ref of this.#streams) {
233
+ const stream = ref.deref();
234
+ if (!stream) {
235
+ this.#streams.delete(ref);
236
+ continue;
237
+ }
238
+ if (stream._speaking) {
239
+ // defer the reconnect to the end of the utterance so we don't cut it off
240
+ stream._pendingKeyterm = merged;
241
+ } else {
242
+ stream.updateOptions({ keyterms: merged });
243
+ }
244
+ }
245
+ }
208
246
  }
209
247
 
210
248
  // --- Stream Implementation ---
@@ -222,6 +260,10 @@ class SpeechStreamv2 extends stt.SpeechStream {
222
260
  // Parity: _reconnect_event - using existing Event class from @livekit/agents
223
261
  #reconnectEvent = new Event();
224
262
 
263
+ // keyterms set while the user is speaking; applied at END_OF_SPEECH (latest wins)
264
+ /** @internal */
265
+ _pendingKeyterm: string[] | null = null;
266
+
225
267
  constructor(
226
268
  sttInstance: STTv2,
227
269
  opts: STTv2Options & { apiKey: string },
@@ -236,6 +278,11 @@ class SpeechStreamv2 extends stt.SpeechStream {
236
278
  );
237
279
  }
238
280
 
281
+ /** @internal */
282
+ get _speaking(): boolean {
283
+ return this.#speaking;
284
+ }
285
+
239
286
  updateOptions(opts: Partial<STTv2Options>) {
240
287
  this.#logger.debug('Stream received option update', opts);
241
288
  this.#opts = {
@@ -245,11 +292,21 @@ class SpeechStreamv2 extends stt.SpeechStream {
245
292
  opts.language !== undefined ? normalizeLanguage(opts.language) : this.#opts.language,
246
293
  };
247
294
  if (opts.tags) this.#opts.tags = validateTags(opts.tags);
295
+ if (opts.keyterms !== undefined) {
296
+ this._pendingKeyterm = null;
297
+ }
248
298
 
249
299
  // Trigger reconnection loop
250
300
  this.#reconnectEvent.set();
251
301
  }
252
302
 
303
+ #onEndOfSpeech() {
304
+ if (this._pendingKeyterm !== null) {
305
+ this.updateOptions({ keyterms: this._pendingKeyterm });
306
+ this._pendingKeyterm = null;
307
+ }
308
+ }
309
+
253
310
  protected async run() {
254
311
  // Outer Loop: Handles reconnections (Configuration updates)
255
312
  while (!this.closed) {
@@ -444,6 +501,7 @@ class SpeechStreamv2 extends stt.SpeechStream {
444
501
  type: stt.SpeechEventType.END_OF_SPEECH,
445
502
  requestId: this.#requestId,
446
503
  });
504
+ this.#onEndOfSpeech();
447
505
  }
448
506
  } else if (data.type === 'Error') {
449
507
  this.#logger.warn('deepgram sent an error', { data });
package/src/tts.ts CHANGED
@@ -351,6 +351,7 @@ export class SynthesizeStream extends tts.SynthesizeStream {
351
351
  text: text,
352
352
  });
353
353
 
354
+ this.markStarted();
354
355
  ws.send(message);
355
356
  markInputSent();
356
357
  }