@livekit/agents 1.0.0 → 1.0.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.
Files changed (44) hide show
  1. package/dist/ipc/job_proc_lazy_main.cjs +1 -2
  2. package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
  3. package/dist/ipc/job_proc_lazy_main.js +2 -3
  4. package/dist/ipc/job_proc_lazy_main.js.map +1 -1
  5. package/dist/ipc/proc_pool.cjs +14 -2
  6. package/dist/ipc/proc_pool.cjs.map +1 -1
  7. package/dist/ipc/proc_pool.d.ts.map +1 -1
  8. package/dist/ipc/proc_pool.js +14 -2
  9. package/dist/ipc/proc_pool.js.map +1 -1
  10. package/dist/ipc/supervised_proc.cjs +32 -10
  11. package/dist/ipc/supervised_proc.cjs.map +1 -1
  12. package/dist/ipc/supervised_proc.d.cts +2 -0
  13. package/dist/ipc/supervised_proc.d.ts +2 -0
  14. package/dist/ipc/supervised_proc.d.ts.map +1 -1
  15. package/dist/ipc/supervised_proc.js +22 -10
  16. package/dist/ipc/supervised_proc.js.map +1 -1
  17. package/dist/llm/llm.cjs +4 -1
  18. package/dist/llm/llm.cjs.map +1 -1
  19. package/dist/llm/llm.d.ts.map +1 -1
  20. package/dist/llm/llm.js +4 -1
  21. package/dist/llm/llm.js.map +1 -1
  22. package/dist/vad.cjs +3 -0
  23. package/dist/vad.cjs.map +1 -1
  24. package/dist/vad.d.ts.map +1 -1
  25. package/dist/vad.js +3 -0
  26. package/dist/vad.js.map +1 -1
  27. package/dist/voice/audio_recognition.cjs +3 -0
  28. package/dist/voice/audio_recognition.cjs.map +1 -1
  29. package/dist/voice/audio_recognition.d.ts.map +1 -1
  30. package/dist/voice/audio_recognition.js +3 -0
  31. package/dist/voice/audio_recognition.js.map +1 -1
  32. package/dist/worker.cjs +25 -4
  33. package/dist/worker.cjs.map +1 -1
  34. package/dist/worker.d.ts.map +1 -1
  35. package/dist/worker.js +25 -4
  36. package/dist/worker.js.map +1 -1
  37. package/package.json +4 -2
  38. package/src/ipc/job_proc_lazy_main.ts +2 -3
  39. package/src/ipc/proc_pool.ts +14 -2
  40. package/src/ipc/supervised_proc.ts +23 -10
  41. package/src/llm/llm.ts +4 -2
  42. package/src/vad.ts +3 -0
  43. package/src/voice/audio_recognition.ts +5 -0
  44. package/src/worker.ts +25 -4
@@ -3,6 +3,7 @@
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import type { ChildProcess } from 'node:child_process';
5
5
  import { once } from 'node:events';
6
+ import pidusage from 'pidusage';
6
7
  import type { RunningJobInfo } from '../job.js';
7
8
  import { log, loggerOptions } from '../log.js';
8
9
  import { Future } from '../utils.js';
@@ -25,7 +26,7 @@ export abstract class SupervisedProc {
25
26
  #runningJob?: RunningJobInfo = undefined;
26
27
  proc?: ChildProcess;
27
28
  #pingInterval?: ReturnType<typeof setInterval>;
28
- #memoryWatch?: ReturnType<typeof setInterval>;
29
+ #memoryMonitorInterval?: ReturnType<typeof setInterval>;
29
30
  #pongTimeout?: ReturnType<typeof setTimeout>;
30
31
  protected init = new Future();
31
32
  #join = new Future();
@@ -90,8 +91,8 @@ export abstract class SupervisedProc {
90
91
  this.#join.resolve();
91
92
  }, this.#opts.pingTimeout);
92
93
 
93
- this.#memoryWatch = setInterval(() => {
94
- const memoryMB = process.memoryUsage().heapUsed / (1024 * 1024);
94
+ this.#memoryMonitorInterval = setInterval(async () => {
95
+ const memoryMB = await this.getChildMemoryUsageMB();
95
96
  if (this.#opts.memoryLimitMB > 0 && memoryMB > this.#opts.memoryLimitMB) {
96
97
  this.#logger
97
98
  .child({ memoryUsageMB: memoryMB, memoryLimitMB: this.#opts.memoryLimitMB })
@@ -104,9 +105,9 @@ export abstract class SupervisedProc {
104
105
  memoryWarnMB: this.#opts.memoryWarnMB,
105
106
  memoryLimitMB: this.#opts.memoryLimitMB,
106
107
  })
107
- .error('process memory usage is high');
108
+ .warn('process memory usage is high');
108
109
  }
109
- });
110
+ }, 5000);
110
111
 
111
112
  const listener = (msg: IPCMessage) => {
112
113
  switch (msg.case) {
@@ -135,9 +136,7 @@ export abstract class SupervisedProc {
135
136
  this.#logger
136
137
  .child({ err })
137
138
  .warn('job process exited unexpectedly; this likely means the error above caused a crash');
138
- clearTimeout(this.#pongTimeout);
139
- clearInterval(this.#pingInterval);
140
- clearInterval(this.#memoryWatch);
139
+ this.clearTimers();
141
140
  this.#join.resolve();
142
141
  });
143
142
 
@@ -196,8 +195,7 @@ export abstract class SupervisedProc {
196
195
  }, this.#opts.closeTimeout);
197
196
  await this.#join.await.then(() => {
198
197
  clearTimeout(timer);
199
- clearTimeout(this.#pongTimeout);
200
- clearInterval(this.#pingInterval);
198
+ this.clearTimers();
201
199
  });
202
200
  }
203
201
 
@@ -208,4 +206,19 @@ export abstract class SupervisedProc {
208
206
  this.#runningJob = info;
209
207
  this.proc!.send({ case: 'startJobRequest', value: { runningJob: info } });
210
208
  }
209
+
210
+ private async getChildMemoryUsageMB(): Promise<number> {
211
+ const pid = this.proc?.pid;
212
+ if (!pid) {
213
+ return 0;
214
+ }
215
+ const stats = await pidusage(pid);
216
+ return stats.memory / (1024 * 1024); // Convert bytes to MB
217
+ }
218
+
219
+ private clearTimers() {
220
+ clearTimeout(this.#pongTimeout);
221
+ clearInterval(this.#pingInterval);
222
+ clearInterval(this.#memoryMonitorInterval);
223
+ }
211
224
  }
package/src/llm/llm.ts CHANGED
@@ -215,8 +215,10 @@ export abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {
215
215
  promptTokens: usage?.promptTokens || 0,
216
216
  promptCachedTokens: usage?.promptCachedTokens || 0,
217
217
  totalTokens: usage?.totalTokens || 0,
218
- tokensPerSecond:
219
- (usage?.completionTokens || 0) / Math.trunc(Number(duration / BigInt(1000000000))),
218
+ tokensPerSecond: (() => {
219
+ const durationSeconds = Math.trunc(Number(duration / BigInt(1000000000)));
220
+ return durationSeconds > 0 ? (usage?.completionTokens || 0) / durationSeconds : 0;
221
+ })(),
220
222
  };
221
223
  this.#llm.emit('metrics_collected', metrics);
222
224
  }
package/src/vad.ts CHANGED
@@ -167,6 +167,9 @@ export abstract class VADStream implements AsyncIterableIterator<VADEvent> {
167
167
  }
168
168
  break;
169
169
  case VADEventType.INFERENCE_DONE:
170
+ inferenceDurationTotal += value.inferenceDuration;
171
+ this.#lastActivityTime = process.hrtime.bigint();
172
+ break;
170
173
  case VADEventType.END_OF_SPEECH:
171
174
  this.#lastActivityTime = process.hrtime.bigint();
172
175
  break;
@@ -367,6 +367,11 @@ export class AudioRecognition {
367
367
  this.hooks.onStartOfSpeech(ev);
368
368
  this.speaking = true;
369
369
 
370
+ // Capture sample rate from the first VAD event if not already set
371
+ if (ev.frames.length > 0 && ev.frames[0]) {
372
+ this.sampleRate = ev.frames[0].sampleRate;
373
+ }
374
+
370
375
  this.bounceEOUTask?.cancel();
371
376
  break;
372
377
  case VADEventType.INFERENCE_DONE:
package/src/worker.ts CHANGED
@@ -190,7 +190,7 @@ export class WorkerOptions {
190
190
  port = undefined,
191
191
  logLevel = 'info',
192
192
  production = false,
193
- jobMemoryWarnMB = 300,
193
+ jobMemoryWarnMB = 500,
194
194
  jobMemoryLimitMB = 0,
195
195
  }: {
196
196
  /**
@@ -567,7 +567,14 @@ export class Worker {
567
567
  if (!msg.message.value.job) return;
568
568
  const task = this.#availability(msg.message.value);
569
569
  this.#tasks.push(task);
570
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
570
+ task.finally(() => {
571
+ const taskIndex = this.#tasks.indexOf(task);
572
+ if (taskIndex !== -1) {
573
+ this.#tasks.splice(taskIndex, 1);
574
+ } else {
575
+ throw new Error(`task ${task} not found in tasks`);
576
+ }
577
+ });
571
578
  break;
572
579
  }
573
580
  case 'assignment': {
@@ -585,7 +592,14 @@ export class Worker {
585
592
  case 'termination': {
586
593
  const task = this.#termination(msg.message.value);
587
594
  this.#tasks.push(task);
588
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
595
+ task.finally(() => {
596
+ const taskIndex = this.#tasks.indexOf(task);
597
+ if (taskIndex !== -1) {
598
+ this.#tasks.splice(taskIndex, 1);
599
+ } else {
600
+ throw new Error(`task ${task} not found in tasks`);
601
+ }
602
+ });
589
603
  break;
590
604
  }
591
605
  }
@@ -737,7 +751,14 @@ export class Worker {
737
751
 
738
752
  const task = jobRequestTask();
739
753
  this.#tasks.push(task);
740
- task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
754
+ task.finally(() => {
755
+ const taskIndex = this.#tasks.indexOf(task);
756
+ if (taskIndex !== -1) {
757
+ this.#tasks.splice(taskIndex, 1);
758
+ } else {
759
+ throw new Error(`task ${task} not found in tasks`);
760
+ }
761
+ });
741
762
  }
742
763
 
743
764
  async #termination(msg: JobTermination) {