@livekit/agents 1.0.10 → 1.0.12

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 (69) hide show
  1. package/dist/audio.cjs +3 -3
  2. package/dist/audio.cjs.map +1 -1
  3. package/dist/audio.d.cts +1 -1
  4. package/dist/audio.d.ts +1 -1
  5. package/dist/audio.d.ts.map +1 -1
  6. package/dist/audio.js +2 -2
  7. package/dist/audio.js.map +1 -1
  8. package/dist/llm/llm.cjs +7 -4
  9. package/dist/llm/llm.cjs.map +1 -1
  10. package/dist/llm/llm.d.ts.map +1 -1
  11. package/dist/llm/llm.js +7 -4
  12. package/dist/llm/llm.js.map +1 -1
  13. package/dist/metrics/base.cjs.map +1 -1
  14. package/dist/metrics/base.d.cts +23 -18
  15. package/dist/metrics/base.d.ts +23 -18
  16. package/dist/metrics/base.d.ts.map +1 -1
  17. package/dist/metrics/index.cjs.map +1 -1
  18. package/dist/metrics/index.d.cts +1 -1
  19. package/dist/metrics/index.d.ts +1 -1
  20. package/dist/metrics/index.d.ts.map +1 -1
  21. package/dist/metrics/index.js.map +1 -1
  22. package/dist/metrics/usage_collector.cjs +2 -2
  23. package/dist/metrics/usage_collector.cjs.map +1 -1
  24. package/dist/metrics/usage_collector.d.cts +1 -1
  25. package/dist/metrics/usage_collector.d.ts +1 -1
  26. package/dist/metrics/usage_collector.d.ts.map +1 -1
  27. package/dist/metrics/usage_collector.js +2 -2
  28. package/dist/metrics/usage_collector.js.map +1 -1
  29. package/dist/metrics/utils.cjs +14 -7
  30. package/dist/metrics/utils.cjs.map +1 -1
  31. package/dist/metrics/utils.d.ts.map +1 -1
  32. package/dist/metrics/utils.js +14 -7
  33. package/dist/metrics/utils.js.map +1 -1
  34. package/dist/stt/stt.cjs +5 -5
  35. package/dist/stt/stt.cjs.map +1 -1
  36. package/dist/stt/stt.js +6 -6
  37. package/dist/stt/stt.js.map +1 -1
  38. package/dist/tts/tts.cjs +11 -10
  39. package/dist/tts/tts.cjs.map +1 -1
  40. package/dist/tts/tts.d.ts.map +1 -1
  41. package/dist/tts/tts.js +11 -10
  42. package/dist/tts/tts.js.map +1 -1
  43. package/dist/vad.cjs +5 -5
  44. package/dist/vad.cjs.map +1 -1
  45. package/dist/vad.js +5 -5
  46. package/dist/vad.js.map +1 -1
  47. package/dist/voice/agent_activity.cjs +3 -3
  48. package/dist/voice/agent_activity.cjs.map +1 -1
  49. package/dist/voice/agent_activity.js +3 -3
  50. package/dist/voice/agent_activity.js.map +1 -1
  51. package/dist/voice/index.cjs +3 -1
  52. package/dist/voice/index.cjs.map +1 -1
  53. package/dist/voice/index.d.cts +1 -0
  54. package/dist/voice/index.d.ts +1 -0
  55. package/dist/voice/index.d.ts.map +1 -1
  56. package/dist/voice/index.js +1 -0
  57. package/dist/voice/index.js.map +1 -1
  58. package/package.json +3 -3
  59. package/src/audio.ts +1 -1
  60. package/src/llm/llm.ts +7 -4
  61. package/src/metrics/base.ts +23 -18
  62. package/src/metrics/index.ts +1 -0
  63. package/src/metrics/usage_collector.ts +3 -3
  64. package/src/metrics/utils.ts +16 -7
  65. package/src/stt/stt.ts +6 -6
  66. package/src/tts/tts.ts +11 -10
  67. package/src/vad.ts +5 -5
  68. package/src/voice/agent_activity.ts +3 -3
  69. package/src/voice/index.ts +1 -0
package/dist/audio.cjs CHANGED
@@ -19,12 +19,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var audio_exports = {};
20
20
  __export(audio_exports, {
21
21
  AudioByteStream: () => AudioByteStream,
22
- calculateAudioDuration: () => calculateAudioDuration
22
+ calculateAudioDurationSeconds: () => calculateAudioDurationSeconds
23
23
  });
24
24
  module.exports = __toCommonJS(audio_exports);
25
25
  var import_rtc_node = require("@livekit/rtc-node");
26
26
  var import_log = require("./log.cjs");
27
- function calculateAudioDuration(frame) {
27
+ function calculateAudioDurationSeconds(frame) {
28
28
  return Array.isArray(frame) ? frame.reduce((sum, a) => sum + a.samplesPerChannel / a.sampleRate, 0) : frame.samplesPerChannel / frame.sampleRate;
29
29
  }
30
30
  class AudioByteStream {
@@ -79,6 +79,6 @@ class AudioByteStream {
79
79
  // Annotate the CommonJS export names for ESM import in node:
80
80
  0 && (module.exports = {
81
81
  AudioByteStream,
82
- calculateAudioDuration
82
+ calculateAudioDurationSeconds
83
83
  });
84
84
  //# sourceMappingURL=audio.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/audio.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioFrame } from '@livekit/rtc-node';\nimport { log } from './log.js';\nimport type { AudioBuffer } from './utils.js';\n\nexport function calculateAudioDuration(frame: AudioBuffer) {\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n return Array.isArray(frame)\n ? frame.reduce((sum, a) => sum + a.samplesPerChannel / a.sampleRate, 0)\n : frame.samplesPerChannel / frame.sampleRate;\n}\n\n/** AudioByteStream translates between LiveKit AudioFrame packets and raw byte data. */\nexport class AudioByteStream {\n #sampleRate: number;\n #numChannels: number;\n #bytesPerFrame: number;\n #buf: Int8Array;\n #logger = log();\n\n constructor(sampleRate: number, numChannels: number, samplesPerChannel: number | null = null) {\n this.#sampleRate = sampleRate;\n this.#numChannels = numChannels;\n\n if (samplesPerChannel === null) {\n samplesPerChannel = Math.floor(sampleRate / 10); // 100ms by default\n }\n\n this.#bytesPerFrame = numChannels * samplesPerChannel * 2; // 2 bytes per sample (Int16)\n this.#buf = new Int8Array();\n }\n\n write(data: ArrayBuffer): AudioFrame[] {\n this.#buf = new Int8Array([...this.#buf, ...new Int8Array(data)]);\n\n const frames: AudioFrame[] = [];\n while (this.#buf.length >= this.#bytesPerFrame) {\n const frameData = this.#buf.slice(0, this.#bytesPerFrame);\n this.#buf = this.#buf.slice(this.#bytesPerFrame);\n\n frames.push(\n new AudioFrame(\n new Int16Array(frameData.buffer),\n this.#sampleRate,\n this.#numChannels,\n frameData.length / 2,\n ),\n );\n }\n\n return frames;\n }\n\n flush(): AudioFrame[] {\n if (this.#buf.length % (2 * this.#numChannels) !== 0) {\n this.#logger.warn('AudioByteStream: incomplete frame during flush, dropping');\n return [];\n }\n\n const frames = [\n new AudioFrame(\n new Int16Array(this.#buf.buffer),\n this.#sampleRate,\n this.#numChannels,\n this.#buf.length / 2,\n ),\n ];\n\n this.#buf = new Int8Array(); // Clear buffer after flushing\n return frames;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,sBAA2B;AAC3B,iBAAoB;AAGb,SAAS,uBAAuB,OAAoB;AAEzD,SAAO,MAAM,QAAQ,KAAK,IACtB,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,oBAAoB,EAAE,YAAY,CAAC,IACpE,MAAM,oBAAoB,MAAM;AACtC;AAGO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAU,gBAAI;AAAA,EAEd,YAAY,YAAoB,aAAqB,oBAAmC,MAAM;AAC5F,SAAK,cAAc;AACnB,SAAK,eAAe;AAEpB,QAAI,sBAAsB,MAAM;AAC9B,0BAAoB,KAAK,MAAM,aAAa,EAAE;AAAA,IAChD;AAEA,SAAK,iBAAiB,cAAc,oBAAoB;AACxD,SAAK,OAAO,IAAI,UAAU;AAAA,EAC5B;AAAA,EAEA,MAAM,MAAiC;AACrC,SAAK,OAAO,IAAI,UAAU,CAAC,GAAG,KAAK,MAAM,GAAG,IAAI,UAAU,IAAI,CAAC,CAAC;AAEhE,UAAM,SAAuB,CAAC;AAC9B,WAAO,KAAK,KAAK,UAAU,KAAK,gBAAgB;AAC9C,YAAM,YAAY,KAAK,KAAK,MAAM,GAAG,KAAK,cAAc;AACxD,WAAK,OAAO,KAAK,KAAK,MAAM,KAAK,cAAc;AAE/C,aAAO;AAAA,QACL,IAAI;AAAA,UACF,IAAI,WAAW,UAAU,MAAM;AAAA,UAC/B,KAAK;AAAA,UACL,KAAK;AAAA,UACL,UAAU,SAAS;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,QAAsB;AACpB,QAAI,KAAK,KAAK,UAAU,IAAI,KAAK,kBAAkB,GAAG;AACpD,WAAK,QAAQ,KAAK,0DAA0D;AAC5E,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS;AAAA,MACb,IAAI;AAAA,QACF,IAAI,WAAW,KAAK,KAAK,MAAM;AAAA,QAC/B,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK,KAAK,SAAS;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,OAAO,IAAI,UAAU;AAC1B,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/audio.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioFrame } from '@livekit/rtc-node';\nimport { log } from './log.js';\nimport type { AudioBuffer } from './utils.js';\n\nexport function calculateAudioDurationSeconds(frame: AudioBuffer) {\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n return Array.isArray(frame)\n ? frame.reduce((sum, a) => sum + a.samplesPerChannel / a.sampleRate, 0)\n : frame.samplesPerChannel / frame.sampleRate;\n}\n\n/** AudioByteStream translates between LiveKit AudioFrame packets and raw byte data. */\nexport class AudioByteStream {\n #sampleRate: number;\n #numChannels: number;\n #bytesPerFrame: number;\n #buf: Int8Array;\n #logger = log();\n\n constructor(sampleRate: number, numChannels: number, samplesPerChannel: number | null = null) {\n this.#sampleRate = sampleRate;\n this.#numChannels = numChannels;\n\n if (samplesPerChannel === null) {\n samplesPerChannel = Math.floor(sampleRate / 10); // 100ms by default\n }\n\n this.#bytesPerFrame = numChannels * samplesPerChannel * 2; // 2 bytes per sample (Int16)\n this.#buf = new Int8Array();\n }\n\n write(data: ArrayBuffer): AudioFrame[] {\n this.#buf = new Int8Array([...this.#buf, ...new Int8Array(data)]);\n\n const frames: AudioFrame[] = [];\n while (this.#buf.length >= this.#bytesPerFrame) {\n const frameData = this.#buf.slice(0, this.#bytesPerFrame);\n this.#buf = this.#buf.slice(this.#bytesPerFrame);\n\n frames.push(\n new AudioFrame(\n new Int16Array(frameData.buffer),\n this.#sampleRate,\n this.#numChannels,\n frameData.length / 2,\n ),\n );\n }\n\n return frames;\n }\n\n flush(): AudioFrame[] {\n if (this.#buf.length % (2 * this.#numChannels) !== 0) {\n this.#logger.warn('AudioByteStream: incomplete frame during flush, dropping');\n return [];\n }\n\n const frames = [\n new AudioFrame(\n new Int16Array(this.#buf.buffer),\n this.#sampleRate,\n this.#numChannels,\n this.#buf.length / 2,\n ),\n ];\n\n this.#buf = new Int8Array(); // Clear buffer after flushing\n return frames;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,sBAA2B;AAC3B,iBAAoB;AAGb,SAAS,8BAA8B,OAAoB;AAEhE,SAAO,MAAM,QAAQ,KAAK,IACtB,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,oBAAoB,EAAE,YAAY,CAAC,IACpE,MAAM,oBAAoB,MAAM;AACtC;AAGO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAU,gBAAI;AAAA,EAEd,YAAY,YAAoB,aAAqB,oBAAmC,MAAM;AAC5F,SAAK,cAAc;AACnB,SAAK,eAAe;AAEpB,QAAI,sBAAsB,MAAM;AAC9B,0BAAoB,KAAK,MAAM,aAAa,EAAE;AAAA,IAChD;AAEA,SAAK,iBAAiB,cAAc,oBAAoB;AACxD,SAAK,OAAO,IAAI,UAAU;AAAA,EAC5B;AAAA,EAEA,MAAM,MAAiC;AACrC,SAAK,OAAO,IAAI,UAAU,CAAC,GAAG,KAAK,MAAM,GAAG,IAAI,UAAU,IAAI,CAAC,CAAC;AAEhE,UAAM,SAAuB,CAAC;AAC9B,WAAO,KAAK,KAAK,UAAU,KAAK,gBAAgB;AAC9C,YAAM,YAAY,KAAK,KAAK,MAAM,GAAG,KAAK,cAAc;AACxD,WAAK,OAAO,KAAK,KAAK,MAAM,KAAK,cAAc;AAE/C,aAAO;AAAA,QACL,IAAI;AAAA,UACF,IAAI,WAAW,UAAU,MAAM;AAAA,UAC/B,KAAK;AAAA,UACL,KAAK;AAAA,UACL,UAAU,SAAS;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,QAAsB;AACpB,QAAI,KAAK,KAAK,UAAU,IAAI,KAAK,kBAAkB,GAAG;AACpD,WAAK,QAAQ,KAAK,0DAA0D;AAC5E,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS;AAAA,MACb,IAAI;AAAA,QACF,IAAI,WAAW,KAAK,KAAK,MAAM;AAAA,QAC/B,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK,KAAK,SAAS;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,OAAO,IAAI,UAAU;AAC1B,WAAO;AAAA,EACT;AACF;","names":[]}
package/dist/audio.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AudioFrame } from '@livekit/rtc-node';
2
2
  import type { AudioBuffer } from './utils.js';
3
- export declare function calculateAudioDuration(frame: AudioBuffer): number;
3
+ export declare function calculateAudioDurationSeconds(frame: AudioBuffer): number;
4
4
  /** AudioByteStream translates between LiveKit AudioFrame packets and raw byte data. */
5
5
  export declare class AudioByteStream {
6
6
  #private;
package/dist/audio.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AudioFrame } from '@livekit/rtc-node';
2
2
  import type { AudioBuffer } from './utils.js';
3
- export declare function calculateAudioDuration(frame: AudioBuffer): number;
3
+ export declare function calculateAudioDurationSeconds(frame: AudioBuffer): number;
4
4
  /** AudioByteStream translates between LiveKit AudioFrame packets and raw byte data. */
5
5
  export declare class AudioByteStream {
6
6
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,UAKxD;AAED,uFAAuF;AACvF,qBAAa,eAAe;;gBAOd,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAE,MAAM,GAAG,IAAW;IAY5F,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,EAAE;IAqBtC,KAAK,IAAI,UAAU,EAAE;CAkBtB"}
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,WAAW,UAK/D;AAED,uFAAuF;AACvF,qBAAa,eAAe;;gBAOd,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAE,MAAM,GAAG,IAAW;IAY5F,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,EAAE;IAqBtC,KAAK,IAAI,UAAU,EAAE;CAkBtB"}
package/dist/audio.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AudioFrame } from "@livekit/rtc-node";
2
2
  import { log } from "./log.js";
3
- function calculateAudioDuration(frame) {
3
+ function calculateAudioDurationSeconds(frame) {
4
4
  return Array.isArray(frame) ? frame.reduce((sum, a) => sum + a.samplesPerChannel / a.sampleRate, 0) : frame.samplesPerChannel / frame.sampleRate;
5
5
  }
6
6
  class AudioByteStream {
@@ -54,6 +54,6 @@ class AudioByteStream {
54
54
  }
55
55
  export {
56
56
  AudioByteStream,
57
- calculateAudioDuration
57
+ calculateAudioDurationSeconds
58
58
  };
59
59
  //# sourceMappingURL=audio.js.map
package/dist/audio.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/audio.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioFrame } from '@livekit/rtc-node';\nimport { log } from './log.js';\nimport type { AudioBuffer } from './utils.js';\n\nexport function calculateAudioDuration(frame: AudioBuffer) {\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n return Array.isArray(frame)\n ? frame.reduce((sum, a) => sum + a.samplesPerChannel / a.sampleRate, 0)\n : frame.samplesPerChannel / frame.sampleRate;\n}\n\n/** AudioByteStream translates between LiveKit AudioFrame packets and raw byte data. */\nexport class AudioByteStream {\n #sampleRate: number;\n #numChannels: number;\n #bytesPerFrame: number;\n #buf: Int8Array;\n #logger = log();\n\n constructor(sampleRate: number, numChannels: number, samplesPerChannel: number | null = null) {\n this.#sampleRate = sampleRate;\n this.#numChannels = numChannels;\n\n if (samplesPerChannel === null) {\n samplesPerChannel = Math.floor(sampleRate / 10); // 100ms by default\n }\n\n this.#bytesPerFrame = numChannels * samplesPerChannel * 2; // 2 bytes per sample (Int16)\n this.#buf = new Int8Array();\n }\n\n write(data: ArrayBuffer): AudioFrame[] {\n this.#buf = new Int8Array([...this.#buf, ...new Int8Array(data)]);\n\n const frames: AudioFrame[] = [];\n while (this.#buf.length >= this.#bytesPerFrame) {\n const frameData = this.#buf.slice(0, this.#bytesPerFrame);\n this.#buf = this.#buf.slice(this.#bytesPerFrame);\n\n frames.push(\n new AudioFrame(\n new Int16Array(frameData.buffer),\n this.#sampleRate,\n this.#numChannels,\n frameData.length / 2,\n ),\n );\n }\n\n return frames;\n }\n\n flush(): AudioFrame[] {\n if (this.#buf.length % (2 * this.#numChannels) !== 0) {\n this.#logger.warn('AudioByteStream: incomplete frame during flush, dropping');\n return [];\n }\n\n const frames = [\n new AudioFrame(\n new Int16Array(this.#buf.buffer),\n this.#sampleRate,\n this.#numChannels,\n this.#buf.length / 2,\n ),\n ];\n\n this.#buf = new Int8Array(); // Clear buffer after flushing\n return frames;\n }\n}\n"],"mappings":"AAGA,SAAS,kBAAkB;AAC3B,SAAS,WAAW;AAGb,SAAS,uBAAuB,OAAoB;AAEzD,SAAO,MAAM,QAAQ,KAAK,IACtB,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,oBAAoB,EAAE,YAAY,CAAC,IACpE,MAAM,oBAAoB,MAAM;AACtC;AAGO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU,IAAI;AAAA,EAEd,YAAY,YAAoB,aAAqB,oBAAmC,MAAM;AAC5F,SAAK,cAAc;AACnB,SAAK,eAAe;AAEpB,QAAI,sBAAsB,MAAM;AAC9B,0BAAoB,KAAK,MAAM,aAAa,EAAE;AAAA,IAChD;AAEA,SAAK,iBAAiB,cAAc,oBAAoB;AACxD,SAAK,OAAO,IAAI,UAAU;AAAA,EAC5B;AAAA,EAEA,MAAM,MAAiC;AACrC,SAAK,OAAO,IAAI,UAAU,CAAC,GAAG,KAAK,MAAM,GAAG,IAAI,UAAU,IAAI,CAAC,CAAC;AAEhE,UAAM,SAAuB,CAAC;AAC9B,WAAO,KAAK,KAAK,UAAU,KAAK,gBAAgB;AAC9C,YAAM,YAAY,KAAK,KAAK,MAAM,GAAG,KAAK,cAAc;AACxD,WAAK,OAAO,KAAK,KAAK,MAAM,KAAK,cAAc;AAE/C,aAAO;AAAA,QACL,IAAI;AAAA,UACF,IAAI,WAAW,UAAU,MAAM;AAAA,UAC/B,KAAK;AAAA,UACL,KAAK;AAAA,UACL,UAAU,SAAS;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,QAAsB;AACpB,QAAI,KAAK,KAAK,UAAU,IAAI,KAAK,kBAAkB,GAAG;AACpD,WAAK,QAAQ,KAAK,0DAA0D;AAC5E,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS;AAAA,MACb,IAAI;AAAA,QACF,IAAI,WAAW,KAAK,KAAK,MAAM;AAAA,QAC/B,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK,KAAK,SAAS;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,OAAO,IAAI,UAAU;AAC1B,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/audio.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioFrame } from '@livekit/rtc-node';\nimport { log } from './log.js';\nimport type { AudioBuffer } from './utils.js';\n\nexport function calculateAudioDurationSeconds(frame: AudioBuffer) {\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n return Array.isArray(frame)\n ? frame.reduce((sum, a) => sum + a.samplesPerChannel / a.sampleRate, 0)\n : frame.samplesPerChannel / frame.sampleRate;\n}\n\n/** AudioByteStream translates between LiveKit AudioFrame packets and raw byte data. */\nexport class AudioByteStream {\n #sampleRate: number;\n #numChannels: number;\n #bytesPerFrame: number;\n #buf: Int8Array;\n #logger = log();\n\n constructor(sampleRate: number, numChannels: number, samplesPerChannel: number | null = null) {\n this.#sampleRate = sampleRate;\n this.#numChannels = numChannels;\n\n if (samplesPerChannel === null) {\n samplesPerChannel = Math.floor(sampleRate / 10); // 100ms by default\n }\n\n this.#bytesPerFrame = numChannels * samplesPerChannel * 2; // 2 bytes per sample (Int16)\n this.#buf = new Int8Array();\n }\n\n write(data: ArrayBuffer): AudioFrame[] {\n this.#buf = new Int8Array([...this.#buf, ...new Int8Array(data)]);\n\n const frames: AudioFrame[] = [];\n while (this.#buf.length >= this.#bytesPerFrame) {\n const frameData = this.#buf.slice(0, this.#bytesPerFrame);\n this.#buf = this.#buf.slice(this.#bytesPerFrame);\n\n frames.push(\n new AudioFrame(\n new Int16Array(frameData.buffer),\n this.#sampleRate,\n this.#numChannels,\n frameData.length / 2,\n ),\n );\n }\n\n return frames;\n }\n\n flush(): AudioFrame[] {\n if (this.#buf.length % (2 * this.#numChannels) !== 0) {\n this.#logger.warn('AudioByteStream: incomplete frame during flush, dropping');\n return [];\n }\n\n const frames = [\n new AudioFrame(\n new Int16Array(this.#buf.buffer),\n this.#sampleRate,\n this.#numChannels,\n this.#buf.length / 2,\n ),\n ];\n\n this.#buf = new Int8Array(); // Clear buffer after flushing\n return frames;\n }\n}\n"],"mappings":"AAGA,SAAS,kBAAkB;AAC3B,SAAS,WAAW;AAGb,SAAS,8BAA8B,OAAoB;AAEhE,SAAO,MAAM,QAAQ,KAAK,IACtB,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,oBAAoB,EAAE,YAAY,CAAC,IACpE,MAAM,oBAAoB,MAAM;AACtC;AAGO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU,IAAI;AAAA,EAEd,YAAY,YAAoB,aAAqB,oBAAmC,MAAM;AAC5F,SAAK,cAAc;AACnB,SAAK,eAAe;AAEpB,QAAI,sBAAsB,MAAM;AAC9B,0BAAoB,KAAK,MAAM,aAAa,EAAE;AAAA,IAChD;AAEA,SAAK,iBAAiB,cAAc,oBAAoB;AACxD,SAAK,OAAO,IAAI,UAAU;AAAA,EAC5B;AAAA,EAEA,MAAM,MAAiC;AACrC,SAAK,OAAO,IAAI,UAAU,CAAC,GAAG,KAAK,MAAM,GAAG,IAAI,UAAU,IAAI,CAAC,CAAC;AAEhE,UAAM,SAAuB,CAAC;AAC9B,WAAO,KAAK,KAAK,UAAU,KAAK,gBAAgB;AAC9C,YAAM,YAAY,KAAK,KAAK,MAAM,GAAG,KAAK,cAAc;AACxD,WAAK,OAAO,KAAK,KAAK,MAAM,KAAK,cAAc;AAE/C,aAAO;AAAA,QACL,IAAI;AAAA,UACF,IAAI,WAAW,UAAU,MAAM;AAAA,UAC/B,KAAK;AAAA,UACL,KAAK;AAAA,UACL,UAAU,SAAS;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,QAAsB;AACpB,QAAI,KAAK,KAAK,UAAU,IAAI,KAAK,kBAAkB,GAAG;AACpD,WAAK,QAAQ,KAAK,0DAA0D;AAC5E,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS;AAAA,MACb,IAAI;AAAA,QACF,IAAI,WAAW,KAAK,KAAK,MAAM;AAAA,QAC/B,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK,KAAK,SAAS;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,OAAO,IAAI,UAAU;AAC1B,WAAO;AAAA,EACT;AACF;","names":[]}
package/dist/llm/llm.cjs CHANGED
@@ -138,12 +138,13 @@ class LLMStream {
138
138
  }
139
139
  this.output.close();
140
140
  const duration = process.hrtime.bigint() - startTime;
141
+ const durationMs = Math.trunc(Number(duration / BigInt(1e6)));
141
142
  const metrics = {
142
143
  type: "llm_metrics",
143
144
  timestamp: Date.now(),
144
145
  requestId,
145
- ttft: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1e6))),
146
- duration: Math.trunc(Number(duration / BigInt(1e6))),
146
+ ttftMs: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1e6))),
147
+ durationMs,
147
148
  cancelled: this.abortController.signal.aborted,
148
149
  label: this.#llm.label(),
149
150
  completionTokens: (usage == null ? void 0 : usage.completionTokens) || 0,
@@ -151,8 +152,10 @@ class LLMStream {
151
152
  promptCachedTokens: (usage == null ? void 0 : usage.promptCachedTokens) || 0,
152
153
  totalTokens: (usage == null ? void 0 : usage.totalTokens) || 0,
153
154
  tokensPerSecond: (() => {
154
- const durationSeconds = Math.trunc(Number(duration / BigInt(1e9)));
155
- return durationSeconds > 0 ? ((usage == null ? void 0 : usage.completionTokens) || 0) / durationSeconds : 0;
155
+ if (durationMs <= 0) {
156
+ return 0;
157
+ }
158
+ return ((usage == null ? void 0 : usage.completionTokens) || 0) / (durationMs / 1e3);
156
159
  })()
157
160
  };
158
161
  this.#llm.emit("metrics_collected", metrics);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/llm/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport type { APIConnectOptions } from '../types.js';\nimport { AsyncIterableQueue, delay, startSoon, toError } from '../utils.js';\nimport { type ChatContext, type ChatRole, type FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport interface ChoiceDelta {\n role: ChatRole;\n content?: string;\n toolCalls?: FunctionCall[];\n}\n\nexport interface CompletionUsage {\n completionTokens: number;\n promptTokens: number;\n promptCachedTokens: number;\n totalTokens: number;\n}\n\nexport interface ChatChunk {\n id: string;\n delta?: ChoiceDelta;\n usage?: CompletionUsage;\n}\n\nexport interface LLMError {\n type: 'llm_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport type LLMCallbacks = {\n ['metrics_collected']: (metrics: LLMMetrics) => void;\n ['error']: (error: LLMError) => void;\n};\n\nexport abstract class LLM extends (EventEmitter as new () => TypedEmitter<LLMCallbacks>) {\n constructor() {\n super();\n }\n\n abstract label(): string;\n\n /**\n * Get the model name/identifier for this LLM instance.\n *\n * @returns The model name if available, \"unknown\" otherwise.\n *\n * @remarks\n * Plugins should override this property to provide their model information.\n */\n get model(): string {\n return 'unknown';\n }\n\n /**\n * Returns a {@link LLMStream} that can be used to push text and receive LLM responses.\n */\n abstract chat({\n chatCtx,\n toolCtx,\n connOptions,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: ToolChoice;\n extraKwargs?: Record<string, any>;\n }): LLMStream;\n\n /**\n * Pre-warm connection to the LLM service\n */\n prewarm(): void {\n // Default implementation - subclasses can override\n }\n\n async aclose(): Promise<void> {\n // Default implementation - subclasses can override\n }\n}\n\nexport abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {\n protected output = new AsyncIterableQueue<ChatChunk>();\n protected queue = new AsyncIterableQueue<ChatChunk>();\n protected closed = false;\n protected abortController = new AbortController();\n protected _connOptions: APIConnectOptions;\n protected logger = log();\n\n #llm: LLM;\n #chatCtx: ChatContext;\n #toolCtx?: ToolContext;\n\n constructor(\n llm: LLM,\n {\n chatCtx,\n toolCtx,\n connOptions,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions: APIConnectOptions;\n },\n ) {\n this.#llm = llm;\n this.#chatCtx = chatCtx;\n this.#toolCtx = toolCtx;\n this._connOptions = connOptions;\n this.monitorMetrics();\n this.abortController.signal.addEventListener('abort', () => {\n // TODO (AJS-37) clean this up when we refactor with streams\n this.output.close();\n this.closed = true;\n });\n\n // this is a hack to immitate asyncio.create_task so that mainTask\n // is run **after** the constructor has finished. Otherwise we get\n // runtime error when trying to access class variables in the\n // `run` method.\n startSoon(() => this.mainTask().then(() => this.queue.close()));\n }\n\n private async mainTask() {\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await this.run();\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = this._connOptions._intervalForRetry(i);\n\n if (this._connOptions.maxRetry === 0 || !error.retryable) {\n this.emitError({ error, recoverable: false });\n throw error;\n } else if (i === this._connOptions.maxRetry) {\n this.emitError({ error, recoverable: false });\n throw new APIConnectionError({\n message: `failed to generate LLM completion after ${this._connOptions.maxRetry + 1} attempts`,\n options: { retryable: false },\n });\n } else {\n this.emitError({ error, recoverable: true });\n this.logger.warn(\n { llm: this.#llm.label(), attempt: i + 1, error },\n `failed to generate LLM completion, retrying in ${retryInterval}s`,\n );\n }\n\n if (retryInterval > 0) {\n await delay(retryInterval);\n }\n } else {\n this.emitError({ error: toError(error), recoverable: false });\n throw error;\n }\n }\n }\n }\n\n private emitError({ error, recoverable }: { error: Error; recoverable: boolean }) {\n this.#llm.emit('error', {\n type: 'llm_error',\n timestamp: Date.now(),\n label: this.#llm.label(),\n error,\n recoverable,\n });\n }\n\n protected async monitorMetrics() {\n const startTime = process.hrtime.bigint();\n let ttft: bigint = BigInt(-1);\n let requestId = '';\n let usage: CompletionUsage | undefined;\n\n for await (const ev of this.queue) {\n if (this.abortController.signal.aborted) {\n break;\n }\n this.output.put(ev);\n requestId = ev.id;\n if (ttft === BigInt(-1)) {\n ttft = process.hrtime.bigint() - startTime;\n }\n if (ev.usage) {\n usage = ev.usage;\n }\n }\n this.output.close();\n\n const duration = process.hrtime.bigint() - startTime;\n const metrics: LLMMetrics = {\n type: 'llm_metrics',\n timestamp: Date.now(),\n requestId,\n ttft: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1000000))),\n duration: Math.trunc(Number(duration / BigInt(1000000))),\n cancelled: this.abortController.signal.aborted,\n label: this.#llm.label(),\n completionTokens: usage?.completionTokens || 0,\n promptTokens: usage?.promptTokens || 0,\n promptCachedTokens: usage?.promptCachedTokens || 0,\n totalTokens: usage?.totalTokens || 0,\n tokensPerSecond: (() => {\n const durationSeconds = Math.trunc(Number(duration / BigInt(1000000000)));\n return durationSeconds > 0 ? (usage?.completionTokens || 0) / durationSeconds : 0;\n })(),\n };\n this.#llm.emit('metrics_collected', metrics);\n }\n\n protected abstract run(): Promise<void>;\n\n /** The function context of this stream. */\n get toolCtx(): ToolContext | undefined {\n return this.#toolCtx;\n }\n\n /** The initial chat context of this stream. */\n get chatCtx(): ChatContext {\n return this.#chatCtx;\n }\n\n /** The connection options for this stream. */\n get connOptions(): APIConnectOptions {\n return this._connOptions;\n }\n\n next(): Promise<IteratorResult<ChatChunk>> {\n return this.output.next();\n }\n\n close() {\n this.abortController.abort();\n }\n\n [Symbol.asyncIterator](): LLMStream {\n return this;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/llm/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport type { APIConnectOptions } from '../types.js';\nimport { AsyncIterableQueue, delay, startSoon, toError } from '../utils.js';\nimport { type ChatContext, type ChatRole, type FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport interface ChoiceDelta {\n role: ChatRole;\n content?: string;\n toolCalls?: FunctionCall[];\n}\n\nexport interface CompletionUsage {\n completionTokens: number;\n promptTokens: number;\n promptCachedTokens: number;\n totalTokens: number;\n}\n\nexport interface ChatChunk {\n id: string;\n delta?: ChoiceDelta;\n usage?: CompletionUsage;\n}\n\nexport interface LLMError {\n type: 'llm_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport type LLMCallbacks = {\n ['metrics_collected']: (metrics: LLMMetrics) => void;\n ['error']: (error: LLMError) => void;\n};\n\nexport abstract class LLM extends (EventEmitter as new () => TypedEmitter<LLMCallbacks>) {\n constructor() {\n super();\n }\n\n abstract label(): string;\n\n /**\n * Get the model name/identifier for this LLM instance.\n *\n * @returns The model name if available, \"unknown\" otherwise.\n *\n * @remarks\n * Plugins should override this property to provide their model information.\n */\n get model(): string {\n return 'unknown';\n }\n\n /**\n * Returns a {@link LLMStream} that can be used to push text and receive LLM responses.\n */\n abstract chat({\n chatCtx,\n toolCtx,\n connOptions,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: ToolChoice;\n extraKwargs?: Record<string, any>;\n }): LLMStream;\n\n /**\n * Pre-warm connection to the LLM service\n */\n prewarm(): void {\n // Default implementation - subclasses can override\n }\n\n async aclose(): Promise<void> {\n // Default implementation - subclasses can override\n }\n}\n\nexport abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {\n protected output = new AsyncIterableQueue<ChatChunk>();\n protected queue = new AsyncIterableQueue<ChatChunk>();\n protected closed = false;\n protected abortController = new AbortController();\n protected _connOptions: APIConnectOptions;\n protected logger = log();\n\n #llm: LLM;\n #chatCtx: ChatContext;\n #toolCtx?: ToolContext;\n\n constructor(\n llm: LLM,\n {\n chatCtx,\n toolCtx,\n connOptions,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions: APIConnectOptions;\n },\n ) {\n this.#llm = llm;\n this.#chatCtx = chatCtx;\n this.#toolCtx = toolCtx;\n this._connOptions = connOptions;\n this.monitorMetrics();\n this.abortController.signal.addEventListener('abort', () => {\n // TODO (AJS-37) clean this up when we refactor with streams\n this.output.close();\n this.closed = true;\n });\n\n // this is a hack to immitate asyncio.create_task so that mainTask\n // is run **after** the constructor has finished. Otherwise we get\n // runtime error when trying to access class variables in the\n // `run` method.\n startSoon(() => this.mainTask().then(() => this.queue.close()));\n }\n\n private async mainTask() {\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await this.run();\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = this._connOptions._intervalForRetry(i);\n\n if (this._connOptions.maxRetry === 0 || !error.retryable) {\n this.emitError({ error, recoverable: false });\n throw error;\n } else if (i === this._connOptions.maxRetry) {\n this.emitError({ error, recoverable: false });\n throw new APIConnectionError({\n message: `failed to generate LLM completion after ${this._connOptions.maxRetry + 1} attempts`,\n options: { retryable: false },\n });\n } else {\n this.emitError({ error, recoverable: true });\n this.logger.warn(\n { llm: this.#llm.label(), attempt: i + 1, error },\n `failed to generate LLM completion, retrying in ${retryInterval}s`,\n );\n }\n\n if (retryInterval > 0) {\n await delay(retryInterval);\n }\n } else {\n this.emitError({ error: toError(error), recoverable: false });\n throw error;\n }\n }\n }\n }\n\n private emitError({ error, recoverable }: { error: Error; recoverable: boolean }) {\n this.#llm.emit('error', {\n type: 'llm_error',\n timestamp: Date.now(),\n label: this.#llm.label(),\n error,\n recoverable,\n });\n }\n\n protected async monitorMetrics() {\n const startTime = process.hrtime.bigint();\n let ttft: bigint = BigInt(-1);\n let requestId = '';\n let usage: CompletionUsage | undefined;\n\n for await (const ev of this.queue) {\n if (this.abortController.signal.aborted) {\n break;\n }\n this.output.put(ev);\n requestId = ev.id;\n if (ttft === BigInt(-1)) {\n ttft = process.hrtime.bigint() - startTime;\n }\n if (ev.usage) {\n usage = ev.usage;\n }\n }\n this.output.close();\n\n const duration = process.hrtime.bigint() - startTime;\n const durationMs = Math.trunc(Number(duration / BigInt(1000000)));\n const metrics: LLMMetrics = {\n type: 'llm_metrics',\n timestamp: Date.now(),\n requestId,\n ttftMs: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1000000))),\n durationMs,\n cancelled: this.abortController.signal.aborted,\n label: this.#llm.label(),\n completionTokens: usage?.completionTokens || 0,\n promptTokens: usage?.promptTokens || 0,\n promptCachedTokens: usage?.promptCachedTokens || 0,\n totalTokens: usage?.totalTokens || 0,\n tokensPerSecond: (() => {\n if (durationMs <= 0) {\n return 0;\n }\n return (usage?.completionTokens || 0) / (durationMs / 1000);\n })(),\n };\n this.#llm.emit('metrics_collected', metrics);\n }\n\n protected abstract run(): Promise<void>;\n\n /** The function context of this stream. */\n get toolCtx(): ToolContext | undefined {\n return this.#toolCtx;\n }\n\n /** The initial chat context of this stream. */\n get chatCtx(): ChatContext {\n return this.#chatCtx;\n }\n\n /** The connection options for this stream. */\n get connOptions(): APIConnectOptions {\n return this._connOptions;\n }\n\n next(): Promise<IteratorResult<ChatChunk>> {\n return this.output.next();\n }\n\n close() {\n this.abortController.abort();\n }\n\n [Symbol.asyncIterator](): LLMStream {\n return this;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/llm/llm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/llm/llm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAIhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAA6B,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACrD,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CACtC,CAAC;kCAE2D,aAAa,YAAY,CAAC;AAAvF,8BAAsB,GAAI,SAAQ,QAAsD;;IAKtF,QAAQ,CAAC,KAAK,IAAI,MAAM;IAExB;;;;;;;OAOG;IACH,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EACZ,OAAO,EACP,OAAO,EACP,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,WAAW,GACZ,EAAE;QACD,OAAO,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,WAAW,CAAC;QACtB,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,UAAU,CAAC,EAAE,UAAU,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACnC,GAAG,SAAS;IAEb;;OAEG;IACH,OAAO,IAAI,IAAI;IAIT,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAG9B;AAED,8BAAsB,SAAU,YAAW,qBAAqB,CAAC,SAAS,CAAC;;IACzE,SAAS,CAAC,MAAM,gCAAuC;IACvD,SAAS,CAAC,KAAK,gCAAuC;IACtD,SAAS,CAAC,MAAM,UAAS;IACzB,SAAS,CAAC,eAAe,kBAAyB;IAClD,SAAS,CAAC,YAAY,EAAE,iBAAiB,CAAC;IAC1C,SAAS,CAAC,MAAM,wBAAS;gBAOvB,GAAG,EAAE,GAAG,EACR,EACE,OAAO,EACP,OAAO,EACP,WAAW,GACZ,EAAE;QACD,OAAO,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,WAAW,CAAC;QACtB,WAAW,EAAE,iBAAiB,CAAC;KAChC;YAoBW,QAAQ;IAoCtB,OAAO,CAAC,SAAS;cAUD,cAAc;IA6C9B,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAEvC,2CAA2C;IAC3C,IAAI,OAAO,IAAI,WAAW,GAAG,SAAS,CAErC;IAED,+CAA+C;IAC/C,IAAI,OAAO,IAAI,WAAW,CAEzB;IAED,8CAA8C;IAC9C,IAAI,WAAW,IAAI,iBAAiB,CAEnC;IAED,IAAI,IAAI,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAI1C,KAAK;IAIL,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,SAAS;CAGpC"}
package/dist/llm/llm.js CHANGED
@@ -114,12 +114,13 @@ class LLMStream {
114
114
  }
115
115
  this.output.close();
116
116
  const duration = process.hrtime.bigint() - startTime;
117
+ const durationMs = Math.trunc(Number(duration / BigInt(1e6)));
117
118
  const metrics = {
118
119
  type: "llm_metrics",
119
120
  timestamp: Date.now(),
120
121
  requestId,
121
- ttft: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1e6))),
122
- duration: Math.trunc(Number(duration / BigInt(1e6))),
122
+ ttftMs: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1e6))),
123
+ durationMs,
123
124
  cancelled: this.abortController.signal.aborted,
124
125
  label: this.#llm.label(),
125
126
  completionTokens: (usage == null ? void 0 : usage.completionTokens) || 0,
@@ -127,8 +128,10 @@ class LLMStream {
127
128
  promptCachedTokens: (usage == null ? void 0 : usage.promptCachedTokens) || 0,
128
129
  totalTokens: (usage == null ? void 0 : usage.totalTokens) || 0,
129
130
  tokensPerSecond: (() => {
130
- const durationSeconds = Math.trunc(Number(duration / BigInt(1e9)));
131
- return durationSeconds > 0 ? ((usage == null ? void 0 : usage.completionTokens) || 0) / durationSeconds : 0;
131
+ if (durationMs <= 0) {
132
+ return 0;
133
+ }
134
+ return ((usage == null ? void 0 : usage.completionTokens) || 0) / (durationMs / 1e3);
132
135
  })()
133
136
  };
134
137
  this.#llm.emit("metrics_collected", metrics);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/llm/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport type { APIConnectOptions } from '../types.js';\nimport { AsyncIterableQueue, delay, startSoon, toError } from '../utils.js';\nimport { type ChatContext, type ChatRole, type FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport interface ChoiceDelta {\n role: ChatRole;\n content?: string;\n toolCalls?: FunctionCall[];\n}\n\nexport interface CompletionUsage {\n completionTokens: number;\n promptTokens: number;\n promptCachedTokens: number;\n totalTokens: number;\n}\n\nexport interface ChatChunk {\n id: string;\n delta?: ChoiceDelta;\n usage?: CompletionUsage;\n}\n\nexport interface LLMError {\n type: 'llm_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport type LLMCallbacks = {\n ['metrics_collected']: (metrics: LLMMetrics) => void;\n ['error']: (error: LLMError) => void;\n};\n\nexport abstract class LLM extends (EventEmitter as new () => TypedEmitter<LLMCallbacks>) {\n constructor() {\n super();\n }\n\n abstract label(): string;\n\n /**\n * Get the model name/identifier for this LLM instance.\n *\n * @returns The model name if available, \"unknown\" otherwise.\n *\n * @remarks\n * Plugins should override this property to provide their model information.\n */\n get model(): string {\n return 'unknown';\n }\n\n /**\n * Returns a {@link LLMStream} that can be used to push text and receive LLM responses.\n */\n abstract chat({\n chatCtx,\n toolCtx,\n connOptions,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: ToolChoice;\n extraKwargs?: Record<string, any>;\n }): LLMStream;\n\n /**\n * Pre-warm connection to the LLM service\n */\n prewarm(): void {\n // Default implementation - subclasses can override\n }\n\n async aclose(): Promise<void> {\n // Default implementation - subclasses can override\n }\n}\n\nexport abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {\n protected output = new AsyncIterableQueue<ChatChunk>();\n protected queue = new AsyncIterableQueue<ChatChunk>();\n protected closed = false;\n protected abortController = new AbortController();\n protected _connOptions: APIConnectOptions;\n protected logger = log();\n\n #llm: LLM;\n #chatCtx: ChatContext;\n #toolCtx?: ToolContext;\n\n constructor(\n llm: LLM,\n {\n chatCtx,\n toolCtx,\n connOptions,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions: APIConnectOptions;\n },\n ) {\n this.#llm = llm;\n this.#chatCtx = chatCtx;\n this.#toolCtx = toolCtx;\n this._connOptions = connOptions;\n this.monitorMetrics();\n this.abortController.signal.addEventListener('abort', () => {\n // TODO (AJS-37) clean this up when we refactor with streams\n this.output.close();\n this.closed = true;\n });\n\n // this is a hack to immitate asyncio.create_task so that mainTask\n // is run **after** the constructor has finished. Otherwise we get\n // runtime error when trying to access class variables in the\n // `run` method.\n startSoon(() => this.mainTask().then(() => this.queue.close()));\n }\n\n private async mainTask() {\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await this.run();\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = this._connOptions._intervalForRetry(i);\n\n if (this._connOptions.maxRetry === 0 || !error.retryable) {\n this.emitError({ error, recoverable: false });\n throw error;\n } else if (i === this._connOptions.maxRetry) {\n this.emitError({ error, recoverable: false });\n throw new APIConnectionError({\n message: `failed to generate LLM completion after ${this._connOptions.maxRetry + 1} attempts`,\n options: { retryable: false },\n });\n } else {\n this.emitError({ error, recoverable: true });\n this.logger.warn(\n { llm: this.#llm.label(), attempt: i + 1, error },\n `failed to generate LLM completion, retrying in ${retryInterval}s`,\n );\n }\n\n if (retryInterval > 0) {\n await delay(retryInterval);\n }\n } else {\n this.emitError({ error: toError(error), recoverable: false });\n throw error;\n }\n }\n }\n }\n\n private emitError({ error, recoverable }: { error: Error; recoverable: boolean }) {\n this.#llm.emit('error', {\n type: 'llm_error',\n timestamp: Date.now(),\n label: this.#llm.label(),\n error,\n recoverable,\n });\n }\n\n protected async monitorMetrics() {\n const startTime = process.hrtime.bigint();\n let ttft: bigint = BigInt(-1);\n let requestId = '';\n let usage: CompletionUsage | undefined;\n\n for await (const ev of this.queue) {\n if (this.abortController.signal.aborted) {\n break;\n }\n this.output.put(ev);\n requestId = ev.id;\n if (ttft === BigInt(-1)) {\n ttft = process.hrtime.bigint() - startTime;\n }\n if (ev.usage) {\n usage = ev.usage;\n }\n }\n this.output.close();\n\n const duration = process.hrtime.bigint() - startTime;\n const metrics: LLMMetrics = {\n type: 'llm_metrics',\n timestamp: Date.now(),\n requestId,\n ttft: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1000000))),\n duration: Math.trunc(Number(duration / BigInt(1000000))),\n cancelled: this.abortController.signal.aborted,\n label: this.#llm.label(),\n completionTokens: usage?.completionTokens || 0,\n promptTokens: usage?.promptTokens || 0,\n promptCachedTokens: usage?.promptCachedTokens || 0,\n totalTokens: usage?.totalTokens || 0,\n tokensPerSecond: (() => {\n const durationSeconds = Math.trunc(Number(duration / BigInt(1000000000)));\n return durationSeconds > 0 ? (usage?.completionTokens || 0) / durationSeconds : 0;\n })(),\n };\n this.#llm.emit('metrics_collected', metrics);\n }\n\n protected abstract run(): Promise<void>;\n\n /** The function context of this stream. */\n get toolCtx(): ToolContext | undefined {\n return this.#toolCtx;\n }\n\n /** The initial chat context of this stream. */\n get chatCtx(): ChatContext {\n return this.#chatCtx;\n }\n\n /** The connection options for this stream. */\n get connOptions(): APIConnectOptions {\n return this._connOptions;\n }\n\n next(): Promise<IteratorResult<ChatChunk>> {\n return this.output.next();\n }\n\n close() {\n this.abortController.abort();\n }\n\n [Symbol.asyncIterator](): LLMStream {\n return this;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/llm/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport type { APIConnectOptions } from '../types.js';\nimport { AsyncIterableQueue, delay, startSoon, toError } from '../utils.js';\nimport { type ChatContext, type ChatRole, type FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport interface ChoiceDelta {\n role: ChatRole;\n content?: string;\n toolCalls?: FunctionCall[];\n}\n\nexport interface CompletionUsage {\n completionTokens: number;\n promptTokens: number;\n promptCachedTokens: number;\n totalTokens: number;\n}\n\nexport interface ChatChunk {\n id: string;\n delta?: ChoiceDelta;\n usage?: CompletionUsage;\n}\n\nexport interface LLMError {\n type: 'llm_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport type LLMCallbacks = {\n ['metrics_collected']: (metrics: LLMMetrics) => void;\n ['error']: (error: LLMError) => void;\n};\n\nexport abstract class LLM extends (EventEmitter as new () => TypedEmitter<LLMCallbacks>) {\n constructor() {\n super();\n }\n\n abstract label(): string;\n\n /**\n * Get the model name/identifier for this LLM instance.\n *\n * @returns The model name if available, \"unknown\" otherwise.\n *\n * @remarks\n * Plugins should override this property to provide their model information.\n */\n get model(): string {\n return 'unknown';\n }\n\n /**\n * Returns a {@link LLMStream} that can be used to push text and receive LLM responses.\n */\n abstract chat({\n chatCtx,\n toolCtx,\n connOptions,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: ToolChoice;\n extraKwargs?: Record<string, any>;\n }): LLMStream;\n\n /**\n * Pre-warm connection to the LLM service\n */\n prewarm(): void {\n // Default implementation - subclasses can override\n }\n\n async aclose(): Promise<void> {\n // Default implementation - subclasses can override\n }\n}\n\nexport abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {\n protected output = new AsyncIterableQueue<ChatChunk>();\n protected queue = new AsyncIterableQueue<ChatChunk>();\n protected closed = false;\n protected abortController = new AbortController();\n protected _connOptions: APIConnectOptions;\n protected logger = log();\n\n #llm: LLM;\n #chatCtx: ChatContext;\n #toolCtx?: ToolContext;\n\n constructor(\n llm: LLM,\n {\n chatCtx,\n toolCtx,\n connOptions,\n }: {\n chatCtx: ChatContext;\n toolCtx?: ToolContext;\n connOptions: APIConnectOptions;\n },\n ) {\n this.#llm = llm;\n this.#chatCtx = chatCtx;\n this.#toolCtx = toolCtx;\n this._connOptions = connOptions;\n this.monitorMetrics();\n this.abortController.signal.addEventListener('abort', () => {\n // TODO (AJS-37) clean this up when we refactor with streams\n this.output.close();\n this.closed = true;\n });\n\n // this is a hack to immitate asyncio.create_task so that mainTask\n // is run **after** the constructor has finished. Otherwise we get\n // runtime error when trying to access class variables in the\n // `run` method.\n startSoon(() => this.mainTask().then(() => this.queue.close()));\n }\n\n private async mainTask() {\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await this.run();\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = this._connOptions._intervalForRetry(i);\n\n if (this._connOptions.maxRetry === 0 || !error.retryable) {\n this.emitError({ error, recoverable: false });\n throw error;\n } else if (i === this._connOptions.maxRetry) {\n this.emitError({ error, recoverable: false });\n throw new APIConnectionError({\n message: `failed to generate LLM completion after ${this._connOptions.maxRetry + 1} attempts`,\n options: { retryable: false },\n });\n } else {\n this.emitError({ error, recoverable: true });\n this.logger.warn(\n { llm: this.#llm.label(), attempt: i + 1, error },\n `failed to generate LLM completion, retrying in ${retryInterval}s`,\n );\n }\n\n if (retryInterval > 0) {\n await delay(retryInterval);\n }\n } else {\n this.emitError({ error: toError(error), recoverable: false });\n throw error;\n }\n }\n }\n }\n\n private emitError({ error, recoverable }: { error: Error; recoverable: boolean }) {\n this.#llm.emit('error', {\n type: 'llm_error',\n timestamp: Date.now(),\n label: this.#llm.label(),\n error,\n recoverable,\n });\n }\n\n protected async monitorMetrics() {\n const startTime = process.hrtime.bigint();\n let ttft: bigint = BigInt(-1);\n let requestId = '';\n let usage: CompletionUsage | undefined;\n\n for await (const ev of this.queue) {\n if (this.abortController.signal.aborted) {\n break;\n }\n this.output.put(ev);\n requestId = ev.id;\n if (ttft === BigInt(-1)) {\n ttft = process.hrtime.bigint() - startTime;\n }\n if (ev.usage) {\n usage = ev.usage;\n }\n }\n this.output.close();\n\n const duration = process.hrtime.bigint() - startTime;\n const durationMs = Math.trunc(Number(duration / BigInt(1000000)));\n const metrics: LLMMetrics = {\n type: 'llm_metrics',\n timestamp: Date.now(),\n requestId,\n ttftMs: ttft === BigInt(-1) ? -1 : Math.trunc(Number(ttft / BigInt(1000000))),\n durationMs,\n cancelled: this.abortController.signal.aborted,\n label: this.#llm.label(),\n completionTokens: usage?.completionTokens || 0,\n promptTokens: usage?.promptTokens || 0,\n promptCachedTokens: usage?.promptCachedTokens || 0,\n totalTokens: usage?.totalTokens || 0,\n tokensPerSecond: (() => {\n if (durationMs <= 0) {\n return 0;\n }\n return (usage?.completionTokens || 0) / (durationMs / 1000);\n })(),\n };\n this.#llm.emit('metrics_collected', metrics);\n }\n\n protected abstract run(): Promise<void>;\n\n /** The function context of this stream. */\n get toolCtx(): ToolContext | undefined {\n return this.#toolCtx;\n }\n\n /** The initial chat context of this stream. */\n get chatCtx(): ChatContext {\n return this.#chatCtx;\n }\n\n /** The connection options for this stream. */\n get connOptions(): APIConnectOptions {\n return this._connOptions;\n }\n\n next(): Promise<IteratorResult<ChatChunk>> {\n return this.output.next();\n }\n\n close() {\n this.abortController.abort();\n }\n\n [Symbol.asyncIterator](): LLMStream {\n return this;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/base.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type AgentMetrics =\n | STTMetrics\n | LLMMetrics\n | TTSMetrics\n | VADMetrics\n | EOUMetrics\n | RealtimeModelMetrics;\n\nexport type LLMMetrics = {\n type: 'llm_metrics';\n label: string;\n requestId: string;\n timestamp: number;\n duration: number;\n ttft: number;\n cancelled: boolean;\n completionTokens: number;\n promptTokens: number;\n promptCachedTokens: number;\n totalTokens: number;\n tokensPerSecond: number;\n speechId?: string;\n};\n\nexport type STTMetrics = {\n type: 'stt_metrics';\n label: string;\n requestId: string;\n timestamp: number;\n /**\n * The request duration in seconds, 0.0 if the STT is streaming.\n */\n duration: number;\n /**\n * The duration of the pushed audio in seconds.\n */\n audioDuration: number;\n /**\n * Whether the STT is streaming (e.g using websocket).\n */\n streamed: boolean;\n};\n\nexport type TTSMetrics = {\n type: 'tts_metrics';\n label: string;\n requestId: string;\n timestamp: number;\n ttfb: number;\n duration: number;\n audioDuration: number;\n cancelled: boolean;\n charactersCount: number;\n streamed: boolean;\n segmentId?: string;\n speechId?: string;\n};\n\nexport type VADMetrics = {\n type: 'vad_metrics';\n label: string;\n timestamp: number;\n idleTime: number;\n inferenceDurationTotal: number;\n inferenceCount: number;\n};\n\nexport type EOUMetrics = {\n type: 'eou_metrics';\n timestamp: number;\n /**\n * Amount of time between the end of speech from VAD and the decision to end the user's turn.\n * Set to 0.0 if the end of speech was not detected.\n */\n endOfUtteranceDelay: number;\n /**\n * Time taken to obtain the transcript after the end of the user's speech.\n * Set to 0.0 if the end of speech was not detected.\n */\n transcriptionDelay: number;\n /**\n * Time taken to invoke the user's `Agent.onUserTurnCompleted` callback.\n */\n onUserTurnCompletedDelay: number;\n speechId?: string;\n};\n\nexport type RealtimeModelMetricsCachedTokenDetails = {\n audioTokens: number;\n textTokens: number;\n imageTokens: number;\n};\n\nexport type RealtimeModelMetricsInputTokenDetails = {\n audioTokens: number;\n textTokens: number;\n imageTokens: number;\n cachedTokens: number;\n cachedTokensDetails?: RealtimeModelMetricsCachedTokenDetails;\n};\n\nexport type RealtimeModelMetricsOutputTokenDetails = {\n textTokens: number;\n audioTokens: number;\n imageTokens: number;\n};\n\nexport type RealtimeModelMetrics = {\n type: 'realtime_model_metrics';\n label: string;\n requestId: string;\n /**\n * The timestamp of the response creation.\n */\n timestamp: number;\n /**\n * The duration of the response from created to done in seconds.\n */\n duration: number;\n /**\n * Time to first audio token in seconds. -1 if no audio token was sent.\n */\n ttft: number;\n /**\n * Whether the request was cancelled.\n */\n cancelled: boolean;\n /**\n * The number of input tokens used in the Response, including text and audio tokens.\n */\n inputTokens: number;\n /**\n * The number of output tokens sent in the Response, including text and audio tokens.\n */\n outputTokens: number;\n /**\n * The total number of tokens in the Response.\n */\n totalTokens: number;\n /**\n * The number of tokens per second.\n */\n tokensPerSecond: number;\n /**\n * Details about the input tokens used in the Response.\n */\n inputTokenDetails: RealtimeModelMetricsInputTokenDetails;\n /**\n * Details about the output tokens used in the Response.\n */\n outputTokenDetails: RealtimeModelMetricsOutputTokenDetails;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../src/metrics/base.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type AgentMetrics =\n | STTMetrics\n | LLMMetrics\n | TTSMetrics\n | VADMetrics\n | EOUMetrics\n | RealtimeModelMetrics;\n\nexport type LLMMetrics = {\n type: 'llm_metrics';\n label: string;\n requestId: string;\n timestamp: number;\n /** Duration of the request in milliseconds. */\n durationMs: number;\n /** Time to first token in milliseconds. */\n ttftMs: number;\n cancelled: boolean;\n completionTokens: number;\n promptTokens: number;\n promptCachedTokens: number;\n totalTokens: number;\n tokensPerSecond: number;\n speechId?: string;\n};\n\nexport type STTMetrics = {\n type: 'stt_metrics';\n label: string;\n requestId: string;\n timestamp: number;\n /**\n * The request duration in milliseconds, 0.0 if the STT is streaming.\n */\n durationMs: number;\n /**\n * The duration of the pushed audio in milliseconds.\n */\n audioDurationMs: number;\n /**\n * Whether the STT is streaming (e.g using websocket).\n */\n streamed: boolean;\n};\n\nexport type TTSMetrics = {\n type: 'tts_metrics';\n label: string;\n requestId: string;\n timestamp: number;\n /** Time to first byte in milliseconds. */\n ttfbMs: number;\n /** Total synthesis duration in milliseconds. */\n durationMs: number;\n /** Generated audio duration in milliseconds. */\n audioDurationMs: number;\n cancelled: boolean;\n charactersCount: number;\n streamed: boolean;\n segmentId?: string;\n speechId?: string;\n};\n\nexport type VADMetrics = {\n type: 'vad_metrics';\n label: string;\n timestamp: number;\n idleTimeMs: number;\n inferenceDurationTotalMs: number;\n inferenceCount: number;\n};\n\nexport type EOUMetrics = {\n type: 'eou_metrics';\n timestamp: number;\n /**\n * Amount of time between the end of speech from VAD and the decision to end the user's turn.\n * Set to 0.0 if the end of speech was not detected.\n */\n endOfUtteranceDelayMs: number;\n /**\n * Time taken to obtain the transcript after the end of the user's speech.\n * Set to 0.0 if the end of speech was not detected.\n */\n transcriptionDelayMs: number;\n /**\n * Time taken to invoke the user's `Agent.onUserTurnCompleted` callback.\n */\n onUserTurnCompletedDelayMs: number;\n speechId?: string;\n};\n\nexport type RealtimeModelMetricsCachedTokenDetails = {\n audioTokens: number;\n textTokens: number;\n imageTokens: number;\n};\n\nexport type RealtimeModelMetricsInputTokenDetails = {\n audioTokens: number;\n textTokens: number;\n imageTokens: number;\n cachedTokens: number;\n cachedTokensDetails?: RealtimeModelMetricsCachedTokenDetails;\n};\n\nexport type RealtimeModelMetricsOutputTokenDetails = {\n textTokens: number;\n audioTokens: number;\n imageTokens: number;\n};\n\nexport type RealtimeModelMetrics = {\n type: 'realtime_model_metrics';\n label: string;\n requestId: string;\n /**\n * The timestamp of the response creation.\n */\n timestamp: number;\n /**\n * The duration of the response from created to done in milliseconds.\n */\n durationMs: number;\n /**\n * Time to first audio token in milliseconds. -1 if no audio token was sent.\n */\n ttftMs: number;\n /**\n * Whether the request was cancelled.\n */\n cancelled: boolean;\n /**\n * The number of input tokens used in the Response, including text and audio tokens.\n */\n inputTokens: number;\n /**\n * The number of output tokens sent in the Response, including text and audio tokens.\n */\n outputTokens: number;\n /**\n * The total number of tokens in the Response.\n */\n totalTokens: number;\n /**\n * The number of tokens per second.\n */\n tokensPerSecond: number;\n /**\n * Details about the input tokens used in the Response.\n */\n inputTokenDetails: RealtimeModelMetricsInputTokenDetails;\n /**\n * Details about the output tokens used in the Response.\n */\n outputTokenDetails: RealtimeModelMetricsOutputTokenDetails;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -4,8 +4,10 @@ export type LLMMetrics = {
4
4
  label: string;
5
5
  requestId: string;
6
6
  timestamp: number;
7
- duration: number;
8
- ttft: number;
7
+ /** Duration of the request in milliseconds. */
8
+ durationMs: number;
9
+ /** Time to first token in milliseconds. */
10
+ ttftMs: number;
9
11
  cancelled: boolean;
10
12
  completionTokens: number;
11
13
  promptTokens: number;
@@ -20,13 +22,13 @@ export type STTMetrics = {
20
22
  requestId: string;
21
23
  timestamp: number;
22
24
  /**
23
- * The request duration in seconds, 0.0 if the STT is streaming.
25
+ * The request duration in milliseconds, 0.0 if the STT is streaming.
24
26
  */
25
- duration: number;
27
+ durationMs: number;
26
28
  /**
27
- * The duration of the pushed audio in seconds.
29
+ * The duration of the pushed audio in milliseconds.
28
30
  */
29
- audioDuration: number;
31
+ audioDurationMs: number;
30
32
  /**
31
33
  * Whether the STT is streaming (e.g using websocket).
32
34
  */
@@ -37,9 +39,12 @@ export type TTSMetrics = {
37
39
  label: string;
38
40
  requestId: string;
39
41
  timestamp: number;
40
- ttfb: number;
41
- duration: number;
42
- audioDuration: number;
42
+ /** Time to first byte in milliseconds. */
43
+ ttfbMs: number;
44
+ /** Total synthesis duration in milliseconds. */
45
+ durationMs: number;
46
+ /** Generated audio duration in milliseconds. */
47
+ audioDurationMs: number;
43
48
  cancelled: boolean;
44
49
  charactersCount: number;
45
50
  streamed: boolean;
@@ -50,8 +55,8 @@ export type VADMetrics = {
50
55
  type: 'vad_metrics';
51
56
  label: string;
52
57
  timestamp: number;
53
- idleTime: number;
54
- inferenceDurationTotal: number;
58
+ idleTimeMs: number;
59
+ inferenceDurationTotalMs: number;
55
60
  inferenceCount: number;
56
61
  };
57
62
  export type EOUMetrics = {
@@ -61,16 +66,16 @@ export type EOUMetrics = {
61
66
  * Amount of time between the end of speech from VAD and the decision to end the user's turn.
62
67
  * Set to 0.0 if the end of speech was not detected.
63
68
  */
64
- endOfUtteranceDelay: number;
69
+ endOfUtteranceDelayMs: number;
65
70
  /**
66
71
  * Time taken to obtain the transcript after the end of the user's speech.
67
72
  * Set to 0.0 if the end of speech was not detected.
68
73
  */
69
- transcriptionDelay: number;
74
+ transcriptionDelayMs: number;
70
75
  /**
71
76
  * Time taken to invoke the user's `Agent.onUserTurnCompleted` callback.
72
77
  */
73
- onUserTurnCompletedDelay: number;
78
+ onUserTurnCompletedDelayMs: number;
74
79
  speechId?: string;
75
80
  };
76
81
  export type RealtimeModelMetricsCachedTokenDetails = {
@@ -99,13 +104,13 @@ export type RealtimeModelMetrics = {
99
104
  */
100
105
  timestamp: number;
101
106
  /**
102
- * The duration of the response from created to done in seconds.
107
+ * The duration of the response from created to done in milliseconds.
103
108
  */
104
- duration: number;
109
+ durationMs: number;
105
110
  /**
106
- * Time to first audio token in seconds. -1 if no audio token was sent.
111
+ * Time to first audio token in milliseconds. -1 if no audio token was sent.
107
112
  */
108
- ttft: number;
113
+ ttftMs: number;
109
114
  /**
110
115
  * Whether the request was cancelled.
111
116
  */
@@ -4,8 +4,10 @@ export type LLMMetrics = {
4
4
  label: string;
5
5
  requestId: string;
6
6
  timestamp: number;
7
- duration: number;
8
- ttft: number;
7
+ /** Duration of the request in milliseconds. */
8
+ durationMs: number;
9
+ /** Time to first token in milliseconds. */
10
+ ttftMs: number;
9
11
  cancelled: boolean;
10
12
  completionTokens: number;
11
13
  promptTokens: number;
@@ -20,13 +22,13 @@ export type STTMetrics = {
20
22
  requestId: string;
21
23
  timestamp: number;
22
24
  /**
23
- * The request duration in seconds, 0.0 if the STT is streaming.
25
+ * The request duration in milliseconds, 0.0 if the STT is streaming.
24
26
  */
25
- duration: number;
27
+ durationMs: number;
26
28
  /**
27
- * The duration of the pushed audio in seconds.
29
+ * The duration of the pushed audio in milliseconds.
28
30
  */
29
- audioDuration: number;
31
+ audioDurationMs: number;
30
32
  /**
31
33
  * Whether the STT is streaming (e.g using websocket).
32
34
  */
@@ -37,9 +39,12 @@ export type TTSMetrics = {
37
39
  label: string;
38
40
  requestId: string;
39
41
  timestamp: number;
40
- ttfb: number;
41
- duration: number;
42
- audioDuration: number;
42
+ /** Time to first byte in milliseconds. */
43
+ ttfbMs: number;
44
+ /** Total synthesis duration in milliseconds. */
45
+ durationMs: number;
46
+ /** Generated audio duration in milliseconds. */
47
+ audioDurationMs: number;
43
48
  cancelled: boolean;
44
49
  charactersCount: number;
45
50
  streamed: boolean;
@@ -50,8 +55,8 @@ export type VADMetrics = {
50
55
  type: 'vad_metrics';
51
56
  label: string;
52
57
  timestamp: number;
53
- idleTime: number;
54
- inferenceDurationTotal: number;
58
+ idleTimeMs: number;
59
+ inferenceDurationTotalMs: number;
55
60
  inferenceCount: number;
56
61
  };
57
62
  export type EOUMetrics = {
@@ -61,16 +66,16 @@ export type EOUMetrics = {
61
66
  * Amount of time between the end of speech from VAD and the decision to end the user's turn.
62
67
  * Set to 0.0 if the end of speech was not detected.
63
68
  */
64
- endOfUtteranceDelay: number;
69
+ endOfUtteranceDelayMs: number;
65
70
  /**
66
71
  * Time taken to obtain the transcript after the end of the user's speech.
67
72
  * Set to 0.0 if the end of speech was not detected.
68
73
  */
69
- transcriptionDelay: number;
74
+ transcriptionDelayMs: number;
70
75
  /**
71
76
  * Time taken to invoke the user's `Agent.onUserTurnCompleted` callback.
72
77
  */
73
- onUserTurnCompletedDelay: number;
78
+ onUserTurnCompletedDelayMs: number;
74
79
  speechId?: string;
75
80
  };
76
81
  export type RealtimeModelMetricsCachedTokenDetails = {
@@ -99,13 +104,13 @@ export type RealtimeModelMetrics = {
99
104
  */
100
105
  timestamp: number;
101
106
  /**
102
- * The duration of the response from created to done in seconds.
107
+ * The duration of the response from created to done in milliseconds.
103
108
  */
104
- duration: number;
109
+ durationMs: number;
105
110
  /**
106
- * Time to first audio token in seconds. -1 if no audio token was sent.
111
+ * Time to first audio token in milliseconds. -1 if no audio token was sent.
107
112
  */
108
- ttft: number;
113
+ ttftMs: number;
109
114
  /**
110
115
  * Whether the request was cancelled.
111
116
  */
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/metrics/base.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,YAAY,GACpB,UAAU,GACV,UAAU,GACV,UAAU,GACV,UAAU,GACV,UAAU,GACV,oBAAoB,CAAC;AAEzB,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,wBAAwB,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAAG;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,sCAAsC,CAAC;CAC9D,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,iBAAiB,EAAE,qCAAqC,CAAC;IACzD;;OAEG;IACH,kBAAkB,EAAE,sCAAsC,CAAC;CAC5D,CAAC"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/metrics/base.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type {\n AgentMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from './base.js';\nexport { UsageCollector, type UsageSummary } from './usage_collector.js';\nexport { logMetrics } from './utils.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,6BAAkD;AAClD,mBAA2B;","names":[]}
1
+ {"version":3,"sources":["../../src/metrics/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type {\n AgentMetrics,\n EOUMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from './base.js';\nexport { UsageCollector, type UsageSummary } from './usage_collector.js';\nexport { logMetrics } from './utils.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,6BAAkD;AAClD,mBAA2B;","names":[]}
@@ -1,4 +1,4 @@
1
- export type { AgentMetrics, LLMMetrics, RealtimeModelMetrics, STTMetrics, TTSMetrics, VADMetrics, } from './base.js';
1
+ export type { AgentMetrics, EOUMetrics, LLMMetrics, RealtimeModelMetrics, STTMetrics, TTSMetrics, VADMetrics, } from './base.js';
2
2
  export { UsageCollector, type UsageSummary } from './usage_collector.js';
3
3
  export { logMetrics } from './utils.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- export type { AgentMetrics, LLMMetrics, RealtimeModelMetrics, STTMetrics, TTSMetrics, VADMetrics, } from './base.js';
1
+ export type { AgentMetrics, EOUMetrics, LLMMetrics, RealtimeModelMetrics, STTMetrics, TTSMetrics, VADMetrics, } from './base.js';
2
2
  export { UsageCollector, type UsageSummary } from './usage_collector.js';
3
3
  export { logMetrics } from './utils.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,YAAY,EACZ,UAAU,EACV,oBAAoB,EACpB,UAAU,EACV,UAAU,EACV,UAAU,GACX,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,oBAAoB,EACpB,UAAU,EACV,UAAU,EACV,UAAU,GACX,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type {\n AgentMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from './base.js';\nexport { UsageCollector, type UsageSummary } from './usage_collector.js';\nexport { logMetrics } from './utils.js';\n"],"mappings":"AAYA,SAAS,sBAAyC;AAClD,SAAS,kBAAkB;","names":[]}
1
+ {"version":3,"sources":["../../src/metrics/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type {\n AgentMetrics,\n EOUMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from './base.js';\nexport { UsageCollector, type UsageSummary } from './usage_collector.js';\nexport { logMetrics } from './utils.js';\n"],"mappings":"AAaA,SAAS,sBAAyC;AAClD,SAAS,kBAAkB;","names":[]}
@@ -29,7 +29,7 @@ class UsageCollector {
29
29
  llmPromptCachedTokens: 0,
30
30
  llmCompletionTokens: 0,
31
31
  ttsCharactersCount: 0,
32
- sttAudioDuration: 0
32
+ sttAudioDurationMs: 0
33
33
  };
34
34
  }
35
35
  collect(metrics) {
@@ -44,7 +44,7 @@ class UsageCollector {
44
44
  } else if (metrics.type === "tts_metrics") {
45
45
  this.summary.ttsCharactersCount += metrics.charactersCount;
46
46
  } else if (metrics.type === "stt_metrics") {
47
- this.summary.sttAudioDuration += metrics.audioDuration;
47
+ this.summary.sttAudioDurationMs += metrics.audioDurationMs;
48
48
  }
49
49
  }
50
50
  getSummary() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/usage_collector.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AgentMetrics } from './base.js';\n\nexport interface UsageSummary {\n llmPromptTokens: number;\n llmPromptCachedTokens: number;\n llmCompletionTokens: number;\n ttsCharactersCount: number;\n sttAudioDuration: number;\n}\n\nexport class UsageCollector {\n private summary: UsageSummary;\n\n constructor() {\n this.summary = {\n llmPromptTokens: 0,\n llmPromptCachedTokens: 0,\n llmCompletionTokens: 0,\n ttsCharactersCount: 0,\n sttAudioDuration: 0,\n };\n }\n\n collect(metrics: AgentMetrics): void {\n if (metrics.type === 'llm_metrics') {\n this.summary.llmPromptTokens += metrics.promptTokens;\n this.summary.llmPromptCachedTokens += metrics.promptCachedTokens;\n this.summary.llmCompletionTokens += metrics.completionTokens;\n } else if (metrics.type === 'realtime_model_metrics') {\n this.summary.llmPromptTokens += metrics.inputTokens;\n this.summary.llmPromptCachedTokens += metrics.inputTokenDetails.cachedTokens;\n this.summary.llmCompletionTokens += metrics.outputTokens;\n } else if (metrics.type === 'tts_metrics') {\n this.summary.ttsCharactersCount += metrics.charactersCount;\n } else if (metrics.type === 'stt_metrics') {\n this.summary.sttAudioDuration += metrics.audioDuration;\n }\n }\n\n getSummary(): UsageSummary {\n return { ...this.summary };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAaO,MAAM,eAAe;AAAA,EAClB;AAAA,EAER,cAAc;AACZ,SAAK,UAAU;AAAA,MACb,iBAAiB;AAAA,MACjB,uBAAuB;AAAA,MACvB,qBAAqB;AAAA,MACrB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,QAAQ,SAA6B;AACnC,QAAI,QAAQ,SAAS,eAAe;AAClC,WAAK,QAAQ,mBAAmB,QAAQ;AACxC,WAAK,QAAQ,yBAAyB,QAAQ;AAC9C,WAAK,QAAQ,uBAAuB,QAAQ;AAAA,IAC9C,WAAW,QAAQ,SAAS,0BAA0B;AACpD,WAAK,QAAQ,mBAAmB,QAAQ;AACxC,WAAK,QAAQ,yBAAyB,QAAQ,kBAAkB;AAChE,WAAK,QAAQ,uBAAuB,QAAQ;AAAA,IAC9C,WAAW,QAAQ,SAAS,eAAe;AACzC,WAAK,QAAQ,sBAAsB,QAAQ;AAAA,IAC7C,WAAW,QAAQ,SAAS,eAAe;AACzC,WAAK,QAAQ,oBAAoB,QAAQ;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,aAA2B;AACzB,WAAO,EAAE,GAAG,KAAK,QAAQ;AAAA,EAC3B;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/metrics/usage_collector.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AgentMetrics } from './base.js';\n\nexport interface UsageSummary {\n llmPromptTokens: number;\n llmPromptCachedTokens: number;\n llmCompletionTokens: number;\n ttsCharactersCount: number;\n sttAudioDurationMs: number;\n}\n\nexport class UsageCollector {\n private summary: UsageSummary;\n\n constructor() {\n this.summary = {\n llmPromptTokens: 0,\n llmPromptCachedTokens: 0,\n llmCompletionTokens: 0,\n ttsCharactersCount: 0,\n sttAudioDurationMs: 0,\n };\n }\n\n collect(metrics: AgentMetrics): void {\n if (metrics.type === 'llm_metrics') {\n this.summary.llmPromptTokens += metrics.promptTokens;\n this.summary.llmPromptCachedTokens += metrics.promptCachedTokens;\n this.summary.llmCompletionTokens += metrics.completionTokens;\n } else if (metrics.type === 'realtime_model_metrics') {\n this.summary.llmPromptTokens += metrics.inputTokens;\n this.summary.llmPromptCachedTokens += metrics.inputTokenDetails.cachedTokens;\n this.summary.llmCompletionTokens += metrics.outputTokens;\n } else if (metrics.type === 'tts_metrics') {\n this.summary.ttsCharactersCount += metrics.charactersCount;\n } else if (metrics.type === 'stt_metrics') {\n this.summary.sttAudioDurationMs += metrics.audioDurationMs;\n }\n }\n\n getSummary(): UsageSummary {\n return { ...this.summary };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAaO,MAAM,eAAe;AAAA,EAClB;AAAA,EAER,cAAc;AACZ,SAAK,UAAU;AAAA,MACb,iBAAiB;AAAA,MACjB,uBAAuB;AAAA,MACvB,qBAAqB;AAAA,MACrB,oBAAoB;AAAA,MACpB,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,QAAQ,SAA6B;AACnC,QAAI,QAAQ,SAAS,eAAe;AAClC,WAAK,QAAQ,mBAAmB,QAAQ;AACxC,WAAK,QAAQ,yBAAyB,QAAQ;AAC9C,WAAK,QAAQ,uBAAuB,QAAQ;AAAA,IAC9C,WAAW,QAAQ,SAAS,0BAA0B;AACpD,WAAK,QAAQ,mBAAmB,QAAQ;AACxC,WAAK,QAAQ,yBAAyB,QAAQ,kBAAkB;AAChE,WAAK,QAAQ,uBAAuB,QAAQ;AAAA,IAC9C,WAAW,QAAQ,SAAS,eAAe;AACzC,WAAK,QAAQ,sBAAsB,QAAQ;AAAA,IAC7C,WAAW,QAAQ,SAAS,eAAe;AACzC,WAAK,QAAQ,sBAAsB,QAAQ;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,aAA2B;AACzB,WAAO,EAAE,GAAG,KAAK,QAAQ;AAAA,EAC3B;AACF;","names":[]}
@@ -4,7 +4,7 @@ export interface UsageSummary {
4
4
  llmPromptCachedTokens: number;
5
5
  llmCompletionTokens: number;
6
6
  ttsCharactersCount: number;
7
- sttAudioDuration: number;
7
+ sttAudioDurationMs: number;
8
8
  }
9
9
  export declare class UsageCollector {
10
10
  private summary;
@@ -4,7 +4,7 @@ export interface UsageSummary {
4
4
  llmPromptCachedTokens: number;
5
5
  llmCompletionTokens: number;
6
6
  ttsCharactersCount: number;
7
- sttAudioDuration: number;
7
+ sttAudioDurationMs: number;
8
8
  }
9
9
  export declare class UsageCollector {
10
10
  private summary;
@@ -1 +1 @@
1
- {"version":3,"file":"usage_collector.d.ts","sourceRoot":"","sources":["../../src/metrics/usage_collector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAe;;IAY9B,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAgBpC,UAAU,IAAI,YAAY;CAG3B"}
1
+ {"version":3,"file":"usage_collector.d.ts","sourceRoot":"","sources":["../../src/metrics/usage_collector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAe;;IAY9B,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAgBpC,UAAU,IAAI,YAAY;CAG3B"}