@livekit/agents 1.0.48 → 1.1.0-dev.0

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 (373) hide show
  1. package/dist/constants.cjs +27 -0
  2. package/dist/constants.cjs.map +1 -1
  3. package/dist/constants.d.cts +9 -0
  4. package/dist/constants.d.ts +9 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +18 -0
  7. package/dist/constants.js.map +1 -1
  8. package/dist/inference/api_protos.d.cts +71 -71
  9. package/dist/inference/api_protos.d.ts +71 -71
  10. package/dist/inference/interruption/defaults.cjs +81 -0
  11. package/dist/inference/interruption/defaults.cjs.map +1 -0
  12. package/dist/inference/interruption/defaults.d.cts +19 -0
  13. package/dist/inference/interruption/defaults.d.ts +19 -0
  14. package/dist/inference/interruption/defaults.d.ts.map +1 -0
  15. package/dist/inference/interruption/defaults.js +46 -0
  16. package/dist/inference/interruption/defaults.js.map +1 -0
  17. package/dist/inference/interruption/errors.cjs +44 -0
  18. package/dist/inference/interruption/errors.cjs.map +1 -0
  19. package/dist/inference/interruption/errors.d.cts +12 -0
  20. package/dist/inference/interruption/errors.d.ts +12 -0
  21. package/dist/inference/interruption/errors.d.ts.map +1 -0
  22. package/dist/inference/interruption/errors.js +20 -0
  23. package/dist/inference/interruption/errors.js.map +1 -0
  24. package/dist/inference/interruption/http_transport.cjs +147 -0
  25. package/dist/inference/interruption/http_transport.cjs.map +1 -0
  26. package/dist/inference/interruption/http_transport.d.cts +63 -0
  27. package/dist/inference/interruption/http_transport.d.ts +63 -0
  28. package/dist/inference/interruption/http_transport.d.ts.map +1 -0
  29. package/dist/inference/interruption/http_transport.js +121 -0
  30. package/dist/inference/interruption/http_transport.js.map +1 -0
  31. package/dist/inference/interruption/interruption_cache_entry.cjs +58 -0
  32. package/dist/inference/interruption/interruption_cache_entry.cjs.map +1 -0
  33. package/dist/inference/interruption/interruption_cache_entry.d.cts +30 -0
  34. package/dist/inference/interruption/interruption_cache_entry.d.ts +30 -0
  35. package/dist/inference/interruption/interruption_cache_entry.d.ts.map +1 -0
  36. package/dist/inference/interruption/interruption_cache_entry.js +34 -0
  37. package/dist/inference/interruption/interruption_cache_entry.js.map +1 -0
  38. package/dist/inference/interruption/interruption_detector.cjs +181 -0
  39. package/dist/inference/interruption/interruption_detector.cjs.map +1 -0
  40. package/dist/inference/interruption/interruption_detector.d.cts +59 -0
  41. package/dist/inference/interruption/interruption_detector.d.ts +59 -0
  42. package/dist/inference/interruption/interruption_detector.d.ts.map +1 -0
  43. package/dist/inference/interruption/interruption_detector.js +147 -0
  44. package/dist/inference/interruption/interruption_detector.js.map +1 -0
  45. package/dist/inference/interruption/interruption_stream.cjs +368 -0
  46. package/dist/inference/interruption/interruption_stream.cjs.map +1 -0
  47. package/dist/inference/interruption/interruption_stream.d.cts +46 -0
  48. package/dist/inference/interruption/interruption_stream.d.ts +46 -0
  49. package/dist/inference/interruption/interruption_stream.d.ts.map +1 -0
  50. package/dist/inference/interruption/interruption_stream.js +344 -0
  51. package/dist/inference/interruption/interruption_stream.js.map +1 -0
  52. package/dist/inference/interruption/types.cjs +17 -0
  53. package/dist/inference/interruption/types.cjs.map +1 -0
  54. package/dist/inference/interruption/types.d.cts +66 -0
  55. package/dist/inference/interruption/types.d.ts +66 -0
  56. package/dist/inference/interruption/types.d.ts.map +1 -0
  57. package/dist/inference/interruption/types.js +1 -0
  58. package/dist/inference/interruption/types.js.map +1 -0
  59. package/dist/inference/interruption/utils.cjs +130 -0
  60. package/dist/inference/interruption/utils.cjs.map +1 -0
  61. package/dist/inference/interruption/utils.d.cts +41 -0
  62. package/dist/inference/interruption/utils.d.ts +41 -0
  63. package/dist/inference/interruption/utils.d.ts.map +1 -0
  64. package/dist/inference/interruption/utils.js +105 -0
  65. package/dist/inference/interruption/utils.js.map +1 -0
  66. package/dist/inference/interruption/utils.test.cjs +105 -0
  67. package/dist/inference/interruption/utils.test.cjs.map +1 -0
  68. package/dist/inference/interruption/utils.test.js +104 -0
  69. package/dist/inference/interruption/utils.test.js.map +1 -0
  70. package/dist/inference/interruption/ws_transport.cjs +329 -0
  71. package/dist/inference/interruption/ws_transport.cjs.map +1 -0
  72. package/dist/inference/interruption/ws_transport.d.cts +33 -0
  73. package/dist/inference/interruption/ws_transport.d.ts +33 -0
  74. package/dist/inference/interruption/ws_transport.d.ts.map +1 -0
  75. package/dist/inference/interruption/ws_transport.js +295 -0
  76. package/dist/inference/interruption/ws_transport.js.map +1 -0
  77. package/dist/inference/llm.cjs +14 -10
  78. package/dist/inference/llm.cjs.map +1 -1
  79. package/dist/inference/llm.d.cts +2 -1
  80. package/dist/inference/llm.d.ts +2 -1
  81. package/dist/inference/llm.d.ts.map +1 -1
  82. package/dist/inference/llm.js +8 -10
  83. package/dist/inference/llm.js.map +1 -1
  84. package/dist/inference/stt.cjs +7 -2
  85. package/dist/inference/stt.cjs.map +1 -1
  86. package/dist/inference/stt.d.cts +2 -0
  87. package/dist/inference/stt.d.ts +2 -0
  88. package/dist/inference/stt.d.ts.map +1 -1
  89. package/dist/inference/stt.js +8 -3
  90. package/dist/inference/stt.js.map +1 -1
  91. package/dist/inference/tts.cjs +7 -2
  92. package/dist/inference/tts.cjs.map +1 -1
  93. package/dist/inference/tts.d.cts +2 -0
  94. package/dist/inference/tts.d.ts +2 -0
  95. package/dist/inference/tts.d.ts.map +1 -1
  96. package/dist/inference/tts.js +8 -3
  97. package/dist/inference/tts.js.map +1 -1
  98. package/dist/inference/utils.cjs +26 -7
  99. package/dist/inference/utils.cjs.map +1 -1
  100. package/dist/inference/utils.d.cts +13 -0
  101. package/dist/inference/utils.d.ts +13 -0
  102. package/dist/inference/utils.d.ts.map +1 -1
  103. package/dist/inference/utils.js +18 -2
  104. package/dist/inference/utils.js.map +1 -1
  105. package/dist/llm/chat_context.cjs +20 -2
  106. package/dist/llm/chat_context.cjs.map +1 -1
  107. package/dist/llm/chat_context.d.cts +19 -1
  108. package/dist/llm/chat_context.d.ts +19 -1
  109. package/dist/llm/chat_context.d.ts.map +1 -1
  110. package/dist/llm/chat_context.js +20 -2
  111. package/dist/llm/chat_context.js.map +1 -1
  112. package/dist/llm/index.cjs.map +1 -1
  113. package/dist/llm/index.d.cts +1 -1
  114. package/dist/llm/index.d.ts +1 -1
  115. package/dist/llm/index.d.ts.map +1 -1
  116. package/dist/llm/index.js.map +1 -1
  117. package/dist/llm/llm.cjs +16 -1
  118. package/dist/llm/llm.cjs.map +1 -1
  119. package/dist/llm/llm.d.cts +9 -0
  120. package/dist/llm/llm.d.ts +9 -0
  121. package/dist/llm/llm.d.ts.map +1 -1
  122. package/dist/llm/llm.js +16 -1
  123. package/dist/llm/llm.js.map +1 -1
  124. package/dist/llm/realtime.cjs +3 -0
  125. package/dist/llm/realtime.cjs.map +1 -1
  126. package/dist/llm/realtime.d.cts +1 -0
  127. package/dist/llm/realtime.d.ts +1 -0
  128. package/dist/llm/realtime.d.ts.map +1 -1
  129. package/dist/llm/realtime.js +3 -0
  130. package/dist/llm/realtime.js.map +1 -1
  131. package/dist/metrics/base.cjs.map +1 -1
  132. package/dist/metrics/base.d.cts +45 -1
  133. package/dist/metrics/base.d.ts +45 -1
  134. package/dist/metrics/base.d.ts.map +1 -1
  135. package/dist/metrics/index.cjs +5 -0
  136. package/dist/metrics/index.cjs.map +1 -1
  137. package/dist/metrics/index.d.cts +2 -1
  138. package/dist/metrics/index.d.ts +2 -1
  139. package/dist/metrics/index.d.ts.map +1 -1
  140. package/dist/metrics/index.js +6 -0
  141. package/dist/metrics/index.js.map +1 -1
  142. package/dist/metrics/model_usage.cjs +189 -0
  143. package/dist/metrics/model_usage.cjs.map +1 -0
  144. package/dist/metrics/model_usage.d.cts +92 -0
  145. package/dist/metrics/model_usage.d.ts +92 -0
  146. package/dist/metrics/model_usage.d.ts.map +1 -0
  147. package/dist/metrics/model_usage.js +164 -0
  148. package/dist/metrics/model_usage.js.map +1 -0
  149. package/dist/metrics/model_usage.test.cjs +474 -0
  150. package/dist/metrics/model_usage.test.cjs.map +1 -0
  151. package/dist/metrics/model_usage.test.js +476 -0
  152. package/dist/metrics/model_usage.test.js.map +1 -0
  153. package/dist/metrics/usage_collector.cjs +3 -0
  154. package/dist/metrics/usage_collector.cjs.map +1 -1
  155. package/dist/metrics/usage_collector.d.cts +9 -0
  156. package/dist/metrics/usage_collector.d.ts +9 -0
  157. package/dist/metrics/usage_collector.d.ts.map +1 -1
  158. package/dist/metrics/usage_collector.js +3 -0
  159. package/dist/metrics/usage_collector.js.map +1 -1
  160. package/dist/metrics/utils.cjs +9 -0
  161. package/dist/metrics/utils.cjs.map +1 -1
  162. package/dist/metrics/utils.d.ts.map +1 -1
  163. package/dist/metrics/utils.js +9 -0
  164. package/dist/metrics/utils.js.map +1 -1
  165. package/dist/stream/multi_input_stream.test.cjs +4 -0
  166. package/dist/stream/multi_input_stream.test.cjs.map +1 -1
  167. package/dist/stream/multi_input_stream.test.js +5 -1
  168. package/dist/stream/multi_input_stream.test.js.map +1 -1
  169. package/dist/stream/stream_channel.cjs +31 -0
  170. package/dist/stream/stream_channel.cjs.map +1 -1
  171. package/dist/stream/stream_channel.d.cts +4 -2
  172. package/dist/stream/stream_channel.d.ts +4 -2
  173. package/dist/stream/stream_channel.d.ts.map +1 -1
  174. package/dist/stream/stream_channel.js +31 -0
  175. package/dist/stream/stream_channel.js.map +1 -1
  176. package/dist/stt/stt.cjs +34 -2
  177. package/dist/stt/stt.cjs.map +1 -1
  178. package/dist/stt/stt.d.cts +22 -0
  179. package/dist/stt/stt.d.ts +22 -0
  180. package/dist/stt/stt.d.ts.map +1 -1
  181. package/dist/stt/stt.js +34 -2
  182. package/dist/stt/stt.js.map +1 -1
  183. package/dist/telemetry/otel_http_exporter.cjs +24 -5
  184. package/dist/telemetry/otel_http_exporter.cjs.map +1 -1
  185. package/dist/telemetry/otel_http_exporter.d.cts +1 -0
  186. package/dist/telemetry/otel_http_exporter.d.ts +1 -0
  187. package/dist/telemetry/otel_http_exporter.d.ts.map +1 -1
  188. package/dist/telemetry/otel_http_exporter.js +24 -5
  189. package/dist/telemetry/otel_http_exporter.js.map +1 -1
  190. package/dist/telemetry/trace_types.cjs +5 -5
  191. package/dist/telemetry/trace_types.cjs.map +1 -1
  192. package/dist/telemetry/trace_types.d.cts +9 -5
  193. package/dist/telemetry/trace_types.d.ts +9 -5
  194. package/dist/telemetry/trace_types.d.ts.map +1 -1
  195. package/dist/telemetry/trace_types.js +5 -5
  196. package/dist/telemetry/trace_types.js.map +1 -1
  197. package/dist/telemetry/traces.cjs +47 -8
  198. package/dist/telemetry/traces.cjs.map +1 -1
  199. package/dist/telemetry/traces.d.ts.map +1 -1
  200. package/dist/telemetry/traces.js +47 -8
  201. package/dist/telemetry/traces.js.map +1 -1
  202. package/dist/tts/tts.cjs +64 -2
  203. package/dist/tts/tts.cjs.map +1 -1
  204. package/dist/tts/tts.d.cts +34 -0
  205. package/dist/tts/tts.d.ts +34 -0
  206. package/dist/tts/tts.d.ts.map +1 -1
  207. package/dist/tts/tts.js +64 -2
  208. package/dist/tts/tts.js.map +1 -1
  209. package/dist/version.cjs +1 -1
  210. package/dist/version.js +1 -1
  211. package/dist/voice/agent.cjs +25 -4
  212. package/dist/voice/agent.cjs.map +1 -1
  213. package/dist/voice/agent.d.cts +10 -2
  214. package/dist/voice/agent.d.ts +10 -2
  215. package/dist/voice/agent.d.ts.map +1 -1
  216. package/dist/voice/agent.js +25 -4
  217. package/dist/voice/agent.js.map +1 -1
  218. package/dist/voice/agent_activity.cjs +261 -36
  219. package/dist/voice/agent_activity.cjs.map +1 -1
  220. package/dist/voice/agent_activity.d.cts +20 -6
  221. package/dist/voice/agent_activity.d.ts +20 -6
  222. package/dist/voice/agent_activity.d.ts.map +1 -1
  223. package/dist/voice/agent_activity.js +262 -37
  224. package/dist/voice/agent_activity.js.map +1 -1
  225. package/dist/voice/agent_session.cjs +105 -48
  226. package/dist/voice/agent_session.cjs.map +1 -1
  227. package/dist/voice/agent_session.d.cts +90 -20
  228. package/dist/voice/agent_session.d.ts +90 -20
  229. package/dist/voice/agent_session.d.ts.map +1 -1
  230. package/dist/voice/agent_session.js +105 -46
  231. package/dist/voice/agent_session.js.map +1 -1
  232. package/dist/voice/audio_recognition.cjs +287 -6
  233. package/dist/voice/audio_recognition.cjs.map +1 -1
  234. package/dist/voice/audio_recognition.d.cts +42 -3
  235. package/dist/voice/audio_recognition.d.ts +42 -3
  236. package/dist/voice/audio_recognition.d.ts.map +1 -1
  237. package/dist/voice/audio_recognition.js +289 -7
  238. package/dist/voice/audio_recognition.js.map +1 -1
  239. package/dist/voice/client_events.cjs +554 -0
  240. package/dist/voice/client_events.cjs.map +1 -0
  241. package/dist/voice/client_events.d.cts +195 -0
  242. package/dist/voice/client_events.d.ts +195 -0
  243. package/dist/voice/client_events.d.ts.map +1 -0
  244. package/dist/voice/client_events.js +548 -0
  245. package/dist/voice/client_events.js.map +1 -0
  246. package/dist/voice/events.cjs +1 -0
  247. package/dist/voice/events.cjs.map +1 -1
  248. package/dist/voice/events.d.cts +8 -5
  249. package/dist/voice/events.d.ts +8 -5
  250. package/dist/voice/events.d.ts.map +1 -1
  251. package/dist/voice/events.js +1 -0
  252. package/dist/voice/events.js.map +1 -1
  253. package/dist/voice/generation.cjs +43 -8
  254. package/dist/voice/generation.cjs.map +1 -1
  255. package/dist/voice/generation.d.cts +3 -3
  256. package/dist/voice/generation.d.ts +3 -3
  257. package/dist/voice/generation.d.ts.map +1 -1
  258. package/dist/voice/generation.js +43 -8
  259. package/dist/voice/generation.js.map +1 -1
  260. package/dist/voice/index.cjs +1 -0
  261. package/dist/voice/index.cjs.map +1 -1
  262. package/dist/voice/index.d.cts +1 -0
  263. package/dist/voice/index.d.ts +1 -0
  264. package/dist/voice/index.d.ts.map +1 -1
  265. package/dist/voice/index.js +1 -0
  266. package/dist/voice/index.js.map +1 -1
  267. package/dist/voice/report.cjs +20 -8
  268. package/dist/voice/report.cjs.map +1 -1
  269. package/dist/voice/report.d.cts +5 -0
  270. package/dist/voice/report.d.ts +5 -0
  271. package/dist/voice/report.d.ts.map +1 -1
  272. package/dist/voice/report.js +20 -8
  273. package/dist/voice/report.js.map +1 -1
  274. package/dist/voice/report.test.cjs +106 -0
  275. package/dist/voice/report.test.cjs.map +1 -0
  276. package/dist/voice/report.test.js +105 -0
  277. package/dist/voice/report.test.js.map +1 -0
  278. package/dist/voice/room_io/room_io.cjs +5 -39
  279. package/dist/voice/room_io/room_io.cjs.map +1 -1
  280. package/dist/voice/room_io/room_io.d.cts +4 -9
  281. package/dist/voice/room_io/room_io.d.ts +4 -9
  282. package/dist/voice/room_io/room_io.d.ts.map +1 -1
  283. package/dist/voice/room_io/room_io.js +5 -40
  284. package/dist/voice/room_io/room_io.js.map +1 -1
  285. package/dist/voice/turn_config/endpointing.cjs +33 -0
  286. package/dist/voice/turn_config/endpointing.cjs.map +1 -0
  287. package/dist/voice/turn_config/endpointing.d.cts +30 -0
  288. package/dist/voice/turn_config/endpointing.d.ts +30 -0
  289. package/dist/voice/turn_config/endpointing.d.ts.map +1 -0
  290. package/dist/voice/turn_config/endpointing.js +9 -0
  291. package/dist/voice/turn_config/endpointing.js.map +1 -0
  292. package/dist/voice/turn_config/interruption.cjs +37 -0
  293. package/dist/voice/turn_config/interruption.cjs.map +1 -0
  294. package/dist/voice/turn_config/interruption.d.cts +53 -0
  295. package/dist/voice/turn_config/interruption.d.ts +53 -0
  296. package/dist/voice/turn_config/interruption.d.ts.map +1 -0
  297. package/dist/voice/turn_config/interruption.js +13 -0
  298. package/dist/voice/turn_config/interruption.js.map +1 -0
  299. package/dist/voice/turn_config/turn_handling.cjs +35 -0
  300. package/dist/voice/turn_config/turn_handling.cjs.map +1 -0
  301. package/dist/voice/turn_config/turn_handling.d.cts +36 -0
  302. package/dist/voice/turn_config/turn_handling.d.ts +36 -0
  303. package/dist/voice/turn_config/turn_handling.d.ts.map +1 -0
  304. package/dist/voice/turn_config/turn_handling.js +11 -0
  305. package/dist/voice/turn_config/turn_handling.js.map +1 -0
  306. package/dist/voice/turn_config/utils.cjs +97 -0
  307. package/dist/voice/turn_config/utils.cjs.map +1 -0
  308. package/dist/voice/turn_config/utils.d.cts +25 -0
  309. package/dist/voice/turn_config/utils.d.ts +25 -0
  310. package/dist/voice/turn_config/utils.d.ts.map +1 -0
  311. package/dist/voice/turn_config/utils.js +73 -0
  312. package/dist/voice/turn_config/utils.js.map +1 -0
  313. package/dist/voice/turn_config/utils.test.cjs +86 -0
  314. package/dist/voice/turn_config/utils.test.cjs.map +1 -0
  315. package/dist/voice/turn_config/utils.test.js +85 -0
  316. package/dist/voice/turn_config/utils.test.js.map +1 -0
  317. package/dist/voice/wire_format.cjs +798 -0
  318. package/dist/voice/wire_format.cjs.map +1 -0
  319. package/dist/voice/wire_format.d.cts +5503 -0
  320. package/dist/voice/wire_format.d.ts +5503 -0
  321. package/dist/voice/wire_format.d.ts.map +1 -0
  322. package/dist/voice/wire_format.js +728 -0
  323. package/dist/voice/wire_format.js.map +1 -0
  324. package/package.json +2 -1
  325. package/src/constants.ts +13 -0
  326. package/src/inference/interruption/defaults.ts +51 -0
  327. package/src/inference/interruption/errors.ts +25 -0
  328. package/src/inference/interruption/http_transport.ts +187 -0
  329. package/src/inference/interruption/interruption_cache_entry.ts +50 -0
  330. package/src/inference/interruption/interruption_detector.ts +188 -0
  331. package/src/inference/interruption/interruption_stream.ts +467 -0
  332. package/src/inference/interruption/types.ts +84 -0
  333. package/src/inference/interruption/utils.test.ts +132 -0
  334. package/src/inference/interruption/utils.ts +137 -0
  335. package/src/inference/interruption/ws_transport.ts +402 -0
  336. package/src/inference/llm.ts +9 -12
  337. package/src/inference/stt.ts +10 -3
  338. package/src/inference/tts.ts +10 -3
  339. package/src/inference/utils.ts +29 -1
  340. package/src/llm/chat_context.ts +40 -2
  341. package/src/llm/index.ts +1 -0
  342. package/src/llm/llm.ts +16 -0
  343. package/src/llm/realtime.ts +4 -0
  344. package/src/metrics/base.ts +48 -1
  345. package/src/metrics/index.ts +11 -0
  346. package/src/metrics/model_usage.test.ts +545 -0
  347. package/src/metrics/model_usage.ts +262 -0
  348. package/src/metrics/usage_collector.ts +11 -0
  349. package/src/metrics/utils.ts +11 -0
  350. package/src/stream/multi_input_stream.test.ts +6 -1
  351. package/src/stream/stream_channel.ts +34 -2
  352. package/src/stt/stt.ts +38 -0
  353. package/src/telemetry/otel_http_exporter.ts +28 -5
  354. package/src/telemetry/trace_types.ts +11 -8
  355. package/src/telemetry/traces.ts +111 -54
  356. package/src/tts/tts.ts +69 -1
  357. package/src/voice/agent.ts +30 -3
  358. package/src/voice/agent_activity.ts +327 -28
  359. package/src/voice/agent_session.ts +207 -59
  360. package/src/voice/audio_recognition.ts +385 -9
  361. package/src/voice/client_events.ts +838 -0
  362. package/src/voice/events.ts +14 -4
  363. package/src/voice/generation.ts +52 -9
  364. package/src/voice/index.ts +1 -0
  365. package/src/voice/report.test.ts +117 -0
  366. package/src/voice/report.ts +29 -6
  367. package/src/voice/room_io/room_io.ts +7 -61
  368. package/src/voice/turn_config/endpointing.ts +33 -0
  369. package/src/voice/turn_config/interruption.ts +56 -0
  370. package/src/voice/turn_config/turn_handling.ts +45 -0
  371. package/src/voice/turn_config/utils.test.ts +100 -0
  372. package/src/voice/turn_config/utils.ts +103 -0
  373. package/src/voice/wire_format.ts +827 -0
@@ -1,5 +1,5 @@
1
1
  export { handoff, isFunctionTool, tool, ToolError, ToolFlag, type AgentHandoff, type FunctionTool, type ProviderDefinedTool, type Tool, type ToolChoice, type ToolContext, type ToolOptions, type ToolType, } from './tool_context.js';
2
- export { AgentHandoffItem, ChatContext, ChatMessage, createAudioContent, createImageContent, FunctionCall, FunctionCallOutput, type AudioContent, type ChatContent, type ChatItem, type ChatRole, type ImageContent, } from './chat_context.js';
2
+ export { AgentHandoffItem, ChatContext, ChatMessage, createAudioContent, createImageContent, FunctionCall, FunctionCallOutput, type AudioContent, type ChatContent, type ChatItem, type ChatRole, type ImageContent, type MetricsReport, } from './chat_context.js';
3
3
  export type { ProviderFormat } from './provider_format/index.js';
4
4
  export { LLM, LLMStream, type ChatChunk, type ChoiceDelta, type CompletionUsage, type LLMCallbacks, } from './llm.js';
5
5
  export { RealtimeModel, RealtimeSession, type GenerationCreatedEvent, type InputSpeechStartedEvent, type InputSpeechStoppedEvent, type InputTranscriptionCompleted, type MessageGeneration, type RealtimeCapabilities, type RealtimeModelError, type RealtimeSessionReconnectedEvent, } from './realtime.js';
@@ -1,5 +1,5 @@
1
1
  export { handoff, isFunctionTool, tool, ToolError, ToolFlag, type AgentHandoff, type FunctionTool, type ProviderDefinedTool, type Tool, type ToolChoice, type ToolContext, type ToolOptions, type ToolType, } from './tool_context.js';
2
- export { AgentHandoffItem, ChatContext, ChatMessage, createAudioContent, createImageContent, FunctionCall, FunctionCallOutput, type AudioContent, type ChatContent, type ChatItem, type ChatRole, type ImageContent, } from './chat_context.js';
2
+ export { AgentHandoffItem, ChatContext, ChatMessage, createAudioContent, createImageContent, FunctionCall, FunctionCallOutput, type AudioContent, type ChatContent, type ChatItem, type ChatRole, type ImageContent, type MetricsReport, } from './chat_context.js';
3
3
  export type { ProviderFormat } from './provider_format/index.js';
4
4
  export { LLM, LLMStream, type ChatChunk, type ChoiceDelta, type CompletionUsage, type LLMCallbacks, } from './llm.js';
5
5
  export { RealtimeModel, RealtimeSession, type GenerationCreatedEvent, type InputSpeechStartedEvent, type InputSpeechStoppedEvent, type InputTranscriptionCompleted, type MessageGeneration, type RealtimeCapabilities, type RealtimeModelError, type RealtimeSessionReconnectedEvent, } from './realtime.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,OAAO,EACP,cAAc,EACd,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,IAAI,EACT,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,EACL,GAAG,EACH,SAAS,EACT,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,+BAA+B,GACrC,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,YAAY,EACZ,KAAK,wBAAwB,GAC9B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,eAAe,EACf,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,OAAO,EACP,cAAc,EACd,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,IAAI,EACT,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,EACL,GAAG,EACH,SAAS,EACT,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,+BAA+B,GACrC,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,YAAY,EACZ,KAAK,wBAAwB,GAC9B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,eAAe,EACf,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,uBAAuB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/llm/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport {\n handoff,\n isFunctionTool,\n tool,\n ToolError,\n ToolFlag,\n type AgentHandoff,\n type FunctionTool,\n type ProviderDefinedTool,\n type Tool,\n type ToolChoice,\n type ToolContext,\n type ToolOptions,\n type ToolType,\n} from './tool_context.js';\n\nexport {\n AgentHandoffItem,\n ChatContext,\n ChatMessage,\n createAudioContent,\n createImageContent,\n FunctionCall,\n FunctionCallOutput,\n type AudioContent,\n type ChatContent,\n type ChatItem,\n type ChatRole,\n type ImageContent,\n} from './chat_context.js';\n\nexport type { ProviderFormat } from './provider_format/index.js';\n\nexport {\n LLM,\n LLMStream,\n type ChatChunk,\n type ChoiceDelta,\n type CompletionUsage,\n type LLMCallbacks,\n} from './llm.js';\n\nexport {\n RealtimeModel,\n RealtimeSession,\n type GenerationCreatedEvent,\n type InputSpeechStartedEvent,\n type InputSpeechStoppedEvent,\n type InputTranscriptionCompleted,\n type MessageGeneration,\n type RealtimeCapabilities,\n type RealtimeModelError,\n type RealtimeSessionReconnectedEvent,\n} from './realtime.js';\n\nexport { RemoteChatContext } from './remote_chat_context.js';\n\nexport {\n computeChatCtxDiff,\n createToolOptions,\n executeToolCall,\n oaiBuildFunctionInfo,\n oaiParams,\n toJsonSchema,\n type OpenAIFunctionParameters,\n} from './utils.js';\n\nexport {\n FallbackAdapter,\n type AvailabilityChangedEvent,\n type FallbackAdapterOptions,\n} from './fallback_adapter.js';\n"],"mappings":"AAGA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OASK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,OASK;AAEP,SAAS,yBAAyB;AAElC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP;AAAA,EACE;AAAA,OAGK;","names":[]}
1
+ {"version":3,"sources":["../../src/llm/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport {\n handoff,\n isFunctionTool,\n tool,\n ToolError,\n ToolFlag,\n type AgentHandoff,\n type FunctionTool,\n type ProviderDefinedTool,\n type Tool,\n type ToolChoice,\n type ToolContext,\n type ToolOptions,\n type ToolType,\n} from './tool_context.js';\n\nexport {\n AgentHandoffItem,\n ChatContext,\n ChatMessage,\n createAudioContent,\n createImageContent,\n FunctionCall,\n FunctionCallOutput,\n type AudioContent,\n type ChatContent,\n type ChatItem,\n type ChatRole,\n type ImageContent,\n type MetricsReport,\n} from './chat_context.js';\n\nexport type { ProviderFormat } from './provider_format/index.js';\n\nexport {\n LLM,\n LLMStream,\n type ChatChunk,\n type ChoiceDelta,\n type CompletionUsage,\n type LLMCallbacks,\n} from './llm.js';\n\nexport {\n RealtimeModel,\n RealtimeSession,\n type GenerationCreatedEvent,\n type InputSpeechStartedEvent,\n type InputSpeechStoppedEvent,\n type InputTranscriptionCompleted,\n type MessageGeneration,\n type RealtimeCapabilities,\n type RealtimeModelError,\n type RealtimeSessionReconnectedEvent,\n} from './realtime.js';\n\nexport { RemoteChatContext } from './remote_chat_context.js';\n\nexport {\n computeChatCtxDiff,\n createToolOptions,\n executeToolCall,\n oaiBuildFunctionInfo,\n oaiParams,\n toJsonSchema,\n type OpenAIFunctionParameters,\n} from './utils.js';\n\nexport {\n FallbackAdapter,\n type AvailabilityChangedEvent,\n type FallbackAdapterOptions,\n} from './fallback_adapter.js';\n"],"mappings":"AAGA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OASK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAOK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,OASK;AAEP,SAAS,yBAAyB;AAElC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP;AAAA,EACE;AAAA,OAGK;","names":[]}
package/dist/llm/llm.cjs CHANGED
@@ -44,6 +44,17 @@ class LLM extends import_node_events.EventEmitter {
44
44
  get model() {
45
45
  return "unknown";
46
46
  }
47
+ /**
48
+ * Get the provider name for this LLM instance.
49
+ *
50
+ * @returns The provider name if available, "unknown" otherwise.
51
+ *
52
+ * @remarks
53
+ * Plugins should override this property to provide their provider information.
54
+ */
55
+ get provider() {
56
+ return "unknown";
57
+ }
47
58
  /**
48
59
  * Pre-warm connection to the LLM service
49
60
  */
@@ -178,7 +189,11 @@ class LLMStream {
178
189
  return 0;
179
190
  }
180
191
  return ((usage == null ? void 0 : usage.completionTokens) || 0) / (durationMs / 1e3);
181
- })()
192
+ })(),
193
+ metadata: {
194
+ modelProvider: this.#llm.provider,
195
+ modelName: this.#llm.model
196
+ }
182
197
  };
183
198
  if (this.#llmRequestSpan) {
184
199
  this.#llmRequestSpan.setAttribute(import_telemetry.traceTypes.ATTR_LLM_METRICS, JSON.stringify(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 type { Span } from '@opentelemetry/api';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport { recordException, traceTypes, tracer } from '../telemetry/index.js';\nimport { type APIConnectOptions, intervalForRetry } 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 extra?: Record<string, unknown>;\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, unknown>;\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 #llmRequestSpan?: Span;\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().finally(() => this.queue.close()));\n }\n\n private _mainTaskImpl = async (span: Span) => {\n this.#llmRequestSpan = span;\n span.setAttribute(traceTypes.ATTR_GEN_AI_REQUEST_MODEL, this.#llm.model);\n\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await tracer.startActiveSpan(\n async (attemptSpan) => {\n attemptSpan.setAttribute(traceTypes.ATTR_RETRY_COUNT, i);\n try {\n return await this.run();\n } catch (error) {\n recordException(attemptSpan, toError(error));\n throw error;\n }\n },\n { name: 'llm_request_run' },\n );\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = intervalForRetry(this._connOptions, 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}ms`,\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 mainTask = async () =>\n tracer.startActiveSpan(async (span) => this._mainTaskImpl(span), {\n name: 'llm_request',\n endOnExit: false,\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 let completionStartTime: string | 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 completionStartTime = new Date().toISOString();\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\n if (this.#llmRequestSpan) {\n this.#llmRequestSpan.setAttribute(traceTypes.ATTR_LLM_METRICS, JSON.stringify(metrics));\n\n this.#llmRequestSpan.setAttributes({\n [traceTypes.ATTR_GEN_AI_USAGE_INPUT_TOKENS]: metrics.promptTokens,\n [traceTypes.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: metrics.completionTokens,\n });\n\n if (completionStartTime) {\n this.#llmRequestSpan.setAttribute(\n traceTypes.ATTR_LANGFUSE_COMPLETION_START_TIME,\n completionStartTime,\n );\n }\n\n // End the span now that metrics are collected\n this.#llmRequestSpan.end();\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 type { Span } from '@opentelemetry/api';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport { recordException, traceTypes, tracer } from '../telemetry/index.js';\nimport { type APIConnectOptions, intervalForRetry } 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 extra?: Record<string, unknown>;\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 * Get the provider name for this LLM instance.\n *\n * @returns The provider name if available, \"unknown\" otherwise.\n *\n * @remarks\n * Plugins should override this property to provide their provider information.\n */\n get provider(): 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, unknown>;\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 #llmRequestSpan?: Span;\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().finally(() => this.queue.close()));\n }\n\n private _mainTaskImpl = async (span: Span) => {\n this.#llmRequestSpan = span;\n span.setAttribute(traceTypes.ATTR_GEN_AI_REQUEST_MODEL, this.#llm.model);\n\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await tracer.startActiveSpan(\n async (attemptSpan) => {\n attemptSpan.setAttribute(traceTypes.ATTR_RETRY_COUNT, i);\n try {\n return await this.run();\n } catch (error) {\n recordException(attemptSpan, toError(error));\n throw error;\n }\n },\n { name: 'llm_request_run' },\n );\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = intervalForRetry(this._connOptions, 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}ms`,\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 mainTask = async () =>\n tracer.startActiveSpan(async (span) => this._mainTaskImpl(span), {\n name: 'llm_request',\n endOnExit: false,\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 let completionStartTime: string | 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 completionStartTime = new Date().toISOString();\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 metadata: {\n modelProvider: this.#llm.provider,\n modelName: this.#llm.model,\n },\n };\n\n if (this.#llmRequestSpan) {\n this.#llmRequestSpan.setAttribute(traceTypes.ATTR_LLM_METRICS, JSON.stringify(metrics));\n\n this.#llmRequestSpan.setAttributes({\n [traceTypes.ATTR_GEN_AI_USAGE_INPUT_TOKENS]: metrics.promptTokens,\n [traceTypes.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: metrics.completionTokens,\n });\n\n if (completionStartTime) {\n this.#llmRequestSpan.setAttribute(\n traceTypes.ATTR_LANGFUSE_COMPLETION_START_TIME,\n completionStartTime,\n );\n }\n\n // End the span now that metrics are collected\n this.#llmRequestSpan.end();\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":[]}
@@ -45,6 +45,15 @@ export declare abstract class LLM extends LLM_base {
45
45
  * Plugins should override this property to provide their model information.
46
46
  */
47
47
  get model(): string;
48
+ /**
49
+ * Get the provider name for this LLM instance.
50
+ *
51
+ * @returns The provider name if available, "unknown" otherwise.
52
+ *
53
+ * @remarks
54
+ * Plugins should override this property to provide their provider information.
55
+ */
56
+ get provider(): string;
48
57
  /**
49
58
  * Returns a {@link LLMStream} that can be used to push text and receive LLM responses.
50
59
  */
package/dist/llm/llm.d.ts CHANGED
@@ -45,6 +45,15 @@ export declare abstract class LLM extends LLM_base {
45
45
  * Plugins should override this property to provide their model information.
46
46
  */
47
47
  get model(): string;
48
+ /**
49
+ * Get the provider name for this LLM instance.
50
+ *
51
+ * @returns The provider name if available, "unknown" otherwise.
52
+ *
53
+ * @remarks
54
+ * Plugins should override this property to provide their provider information.
55
+ */
56
+ get provider(): string;
48
57
  /**
49
58
  * Returns a {@link LLMStream} that can be used to push text and receive LLM responses.
50
59
  */
@@ -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":"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"}
package/dist/llm/llm.js CHANGED
@@ -20,6 +20,17 @@ class LLM extends EventEmitter {
20
20
  get model() {
21
21
  return "unknown";
22
22
  }
23
+ /**
24
+ * Get the provider name for this LLM instance.
25
+ *
26
+ * @returns The provider name if available, "unknown" otherwise.
27
+ *
28
+ * @remarks
29
+ * Plugins should override this property to provide their provider information.
30
+ */
31
+ get provider() {
32
+ return "unknown";
33
+ }
23
34
  /**
24
35
  * Pre-warm connection to the LLM service
25
36
  */
@@ -154,7 +165,11 @@ class LLMStream {
154
165
  return 0;
155
166
  }
156
167
  return ((usage == null ? void 0 : usage.completionTokens) || 0) / (durationMs / 1e3);
157
- })()
168
+ })(),
169
+ metadata: {
170
+ modelProvider: this.#llm.provider,
171
+ modelName: this.#llm.model
172
+ }
158
173
  };
159
174
  if (this.#llmRequestSpan) {
160
175
  this.#llmRequestSpan.setAttribute(traceTypes.ATTR_LLM_METRICS, JSON.stringify(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 type { Span } from '@opentelemetry/api';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport { recordException, traceTypes, tracer } from '../telemetry/index.js';\nimport { type APIConnectOptions, intervalForRetry } 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 extra?: Record<string, unknown>;\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, unknown>;\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 #llmRequestSpan?: Span;\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().finally(() => this.queue.close()));\n }\n\n private _mainTaskImpl = async (span: Span) => {\n this.#llmRequestSpan = span;\n span.setAttribute(traceTypes.ATTR_GEN_AI_REQUEST_MODEL, this.#llm.model);\n\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await tracer.startActiveSpan(\n async (attemptSpan) => {\n attemptSpan.setAttribute(traceTypes.ATTR_RETRY_COUNT, i);\n try {\n return await this.run();\n } catch (error) {\n recordException(attemptSpan, toError(error));\n throw error;\n }\n },\n { name: 'llm_request_run' },\n );\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = intervalForRetry(this._connOptions, 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}ms`,\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 mainTask = async () =>\n tracer.startActiveSpan(async (span) => this._mainTaskImpl(span), {\n name: 'llm_request',\n endOnExit: false,\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 let completionStartTime: string | 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 completionStartTime = new Date().toISOString();\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\n if (this.#llmRequestSpan) {\n this.#llmRequestSpan.setAttribute(traceTypes.ATTR_LLM_METRICS, JSON.stringify(metrics));\n\n this.#llmRequestSpan.setAttributes({\n [traceTypes.ATTR_GEN_AI_USAGE_INPUT_TOKENS]: metrics.promptTokens,\n [traceTypes.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: metrics.completionTokens,\n });\n\n if (completionStartTime) {\n this.#llmRequestSpan.setAttribute(\n traceTypes.ATTR_LANGFUSE_COMPLETION_START_TIME,\n completionStartTime,\n );\n }\n\n // End the span now that metrics are collected\n this.#llmRequestSpan.end();\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 type { Span } from '@opentelemetry/api';\nimport { EventEmitter } from 'node:events';\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { LLMMetrics } from '../metrics/base.js';\nimport { recordException, traceTypes, tracer } from '../telemetry/index.js';\nimport { type APIConnectOptions, intervalForRetry } 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 extra?: Record<string, unknown>;\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 * Get the provider name for this LLM instance.\n *\n * @returns The provider name if available, \"unknown\" otherwise.\n *\n * @remarks\n * Plugins should override this property to provide their provider information.\n */\n get provider(): 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, unknown>;\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 #llmRequestSpan?: Span;\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().finally(() => this.queue.close()));\n }\n\n private _mainTaskImpl = async (span: Span) => {\n this.#llmRequestSpan = span;\n span.setAttribute(traceTypes.ATTR_GEN_AI_REQUEST_MODEL, this.#llm.model);\n\n for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {\n try {\n return await tracer.startActiveSpan(\n async (attemptSpan) => {\n attemptSpan.setAttribute(traceTypes.ATTR_RETRY_COUNT, i);\n try {\n return await this.run();\n } catch (error) {\n recordException(attemptSpan, toError(error));\n throw error;\n }\n },\n { name: 'llm_request_run' },\n );\n } catch (error) {\n if (error instanceof APIError) {\n const retryInterval = intervalForRetry(this._connOptions, 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}ms`,\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 mainTask = async () =>\n tracer.startActiveSpan(async (span) => this._mainTaskImpl(span), {\n name: 'llm_request',\n endOnExit: false,\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 let completionStartTime: string | 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 completionStartTime = new Date().toISOString();\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 metadata: {\n modelProvider: this.#llm.provider,\n modelName: this.#llm.model,\n },\n };\n\n if (this.#llmRequestSpan) {\n this.#llmRequestSpan.setAttribute(traceTypes.ATTR_LLM_METRICS, JSON.stringify(metrics));\n\n this.#llmRequestSpan.setAttributes({\n [traceTypes.ATTR_GEN_AI_USAGE_INPUT_TOKENS]: metrics.promptTokens,\n [traceTypes.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: metrics.completionTokens,\n });\n\n if (completionStartTime) {\n this.#llmRequestSpan.setAttribute(\n traceTypes.ATTR_LANGFUSE_COMPLETION_START_TIME,\n completionStartTime,\n );\n }\n\n // End the span now that metrics are collected\n this.#llmRequestSpan.end();\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":[]}
@@ -33,6 +33,9 @@ class RealtimeModel {
33
33
  get capabilities() {
34
34
  return this._capabilities;
35
35
  }
36
+ get provider() {
37
+ return "unknown";
38
+ }
36
39
  }
37
40
  class RealtimeSession extends import_events.EventEmitter {
38
41
  _realtimeModel;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/llm/realtime.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'events';\nimport type { ReadableStream } from 'node:stream/web';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { Task } from '../utils.js';\nimport type { TimedString } from '../voice/io.js';\nimport type { ChatContext, FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport type InputSpeechStartedEvent = object;\n\nexport interface InputSpeechStoppedEvent {\n userTranscriptionEnabled: boolean;\n}\n\nexport interface MessageGeneration {\n messageId: string;\n /**\n * Text stream that may contain plain strings or TimedString objects with timestamps.\n */\n textStream: ReadableStream<string | TimedString>;\n audioStream: ReadableStream<AudioFrame>;\n modalities?: Promise<('text' | 'audio')[]>;\n}\n\nexport interface GenerationCreatedEvent {\n messageStream: ReadableStream<MessageGeneration>;\n functionStream: ReadableStream<FunctionCall>;\n userInitiated: boolean;\n /** Response ID for correlating metrics with spans */\n responseId?: string;\n}\n\nexport interface RealtimeModelError {\n type: 'realtime_model_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport interface RealtimeCapabilities {\n messageTruncation: boolean;\n turnDetection: boolean;\n userTranscription: boolean;\n autoToolReplyGeneration: boolean;\n audioOutput: boolean;\n manualFunctionCalls: boolean;\n}\n\nexport interface InputTranscriptionCompleted {\n itemId: string;\n transcript: string;\n isFinal: boolean;\n}\n\nexport interface RealtimeSessionReconnectedEvent {}\n\nexport abstract class RealtimeModel {\n private _capabilities: RealtimeCapabilities;\n\n constructor(capabilities: RealtimeCapabilities) {\n this._capabilities = capabilities;\n }\n\n get capabilities() {\n return this._capabilities;\n }\n\n /** The model name/identifier used by this realtime model */\n abstract get model(): string;\n\n abstract session(): RealtimeSession;\n\n abstract close(): Promise<void>;\n}\n\nexport abstract class RealtimeSession extends EventEmitter {\n protected _realtimeModel: RealtimeModel;\n private deferredInputStream = new DeferredReadableStream<AudioFrame>();\n private _mainTask: Task<void>;\n\n constructor(realtimeModel: RealtimeModel) {\n super();\n this._realtimeModel = realtimeModel;\n this._mainTask = Task.from((controller) => this._mainTaskImpl(controller.signal));\n }\n\n get realtimeModel() {\n return this._realtimeModel;\n }\n\n abstract get chatCtx(): ChatContext;\n\n abstract get tools(): ToolContext;\n\n abstract updateInstructions(instructions: string): Promise<void>;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract updateChatCtx(chatCtx: ChatContext): Promise<void>;\n\n abstract updateTools(tools: ToolContext): Promise<void>;\n\n abstract updateOptions(options: { toolChoice?: ToolChoice | null }): void;\n\n abstract pushAudio(frame: AudioFrame): void;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract generateReply(instructions?: string): Promise<GenerationCreatedEvent>;\n\n /**\n * Commit the input audio buffer to the server\n */\n abstract commitAudio(): Promise<void>;\n\n /**\n * Clear the input audio buffer to the server\n */\n abstract clearAudio(): Promise<void>;\n\n /**\n * Cancel the current generation (do nothing if no generation is in progress)\n */\n abstract interrupt(): Promise<void>;\n\n /**\n * Truncate the message at the given audio end time\n */\n abstract truncate(options: {\n messageId: string;\n audioEndMs: number;\n modalities?: ('text' | 'audio')[];\n audioTranscript?: string;\n }): Promise<void>;\n\n async close(): Promise<void> {\n this._mainTask.cancel();\n }\n\n /**\n * Notifies the model that user activity has started\n */\n startUserActivity(): void {\n return;\n }\n\n private async _mainTaskImpl(signal: AbortSignal): Promise<void> {\n const reader = this.deferredInputStream.stream.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done || signal.aborted) {\n break;\n }\n this.pushAudio(value);\n }\n }\n\n setInputAudioStream(audioStream: ReadableStream<AudioFrame>): void {\n this.deferredInputStream.setSource(audioStream);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAA6B;AAE7B,6BAAuC;AACvC,mBAAqB;AAsDd,MAAe,cAAc;AAAA,EAC1B;AAAA,EAER,YAAY,cAAoC;AAC9C,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,IAAI,eAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAQF;AAEO,MAAe,wBAAwB,2BAAa;AAAA,EAC/C;AAAA,EACF,sBAAsB,IAAI,8CAAmC;AAAA,EAC7D;AAAA,EAER,YAAY,eAA8B;AACxC,UAAM;AACN,SAAK,iBAAiB;AACtB,SAAK,YAAY,kBAAK,KAAK,CAAC,eAAe,KAAK,cAAc,WAAW,MAAM,CAAC;AAAA,EAClF;AAAA,EAEA,IAAI,gBAAgB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAiDA,MAAM,QAAuB;AAC3B,SAAK,UAAU,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,QAAoC;AAC9D,UAAM,SAAS,KAAK,oBAAoB,OAAO,UAAU;AACzD,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,QAAQ,OAAO,SAAS;AAC1B;AAAA,MACF;AACA,WAAK,UAAU,KAAK;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,oBAAoB,aAA+C;AACjE,SAAK,oBAAoB,UAAU,WAAW;AAAA,EAChD;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/llm/realtime.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'events';\nimport type { ReadableStream } from 'node:stream/web';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { Task } from '../utils.js';\nimport type { TimedString } from '../voice/io.js';\nimport type { ChatContext, FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport type InputSpeechStartedEvent = object;\n\nexport interface InputSpeechStoppedEvent {\n userTranscriptionEnabled: boolean;\n}\n\nexport interface MessageGeneration {\n messageId: string;\n /**\n * Text stream that may contain plain strings or TimedString objects with timestamps.\n */\n textStream: ReadableStream<string | TimedString>;\n audioStream: ReadableStream<AudioFrame>;\n modalities?: Promise<('text' | 'audio')[]>;\n}\n\nexport interface GenerationCreatedEvent {\n messageStream: ReadableStream<MessageGeneration>;\n functionStream: ReadableStream<FunctionCall>;\n userInitiated: boolean;\n /** Response ID for correlating metrics with spans */\n responseId?: string;\n}\n\nexport interface RealtimeModelError {\n type: 'realtime_model_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport interface RealtimeCapabilities {\n messageTruncation: boolean;\n turnDetection: boolean;\n userTranscription: boolean;\n autoToolReplyGeneration: boolean;\n audioOutput: boolean;\n manualFunctionCalls: boolean;\n}\n\nexport interface InputTranscriptionCompleted {\n itemId: string;\n transcript: string;\n isFinal: boolean;\n}\n\nexport interface RealtimeSessionReconnectedEvent {}\n\nexport abstract class RealtimeModel {\n private _capabilities: RealtimeCapabilities;\n\n constructor(capabilities: RealtimeCapabilities) {\n this._capabilities = capabilities;\n }\n\n get capabilities() {\n return this._capabilities;\n }\n\n /** The model name/identifier used by this realtime model */\n abstract get model(): string;\n\n get provider(): string {\n return 'unknown';\n }\n\n abstract session(): RealtimeSession;\n\n abstract close(): Promise<void>;\n}\n\nexport abstract class RealtimeSession extends EventEmitter {\n protected _realtimeModel: RealtimeModel;\n private deferredInputStream = new DeferredReadableStream<AudioFrame>();\n private _mainTask: Task<void>;\n\n constructor(realtimeModel: RealtimeModel) {\n super();\n this._realtimeModel = realtimeModel;\n this._mainTask = Task.from((controller) => this._mainTaskImpl(controller.signal));\n }\n\n get realtimeModel() {\n return this._realtimeModel;\n }\n\n abstract get chatCtx(): ChatContext;\n\n abstract get tools(): ToolContext;\n\n abstract updateInstructions(instructions: string): Promise<void>;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract updateChatCtx(chatCtx: ChatContext): Promise<void>;\n\n abstract updateTools(tools: ToolContext): Promise<void>;\n\n abstract updateOptions(options: { toolChoice?: ToolChoice | null }): void;\n\n abstract pushAudio(frame: AudioFrame): void;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract generateReply(instructions?: string): Promise<GenerationCreatedEvent>;\n\n /**\n * Commit the input audio buffer to the server\n */\n abstract commitAudio(): Promise<void>;\n\n /**\n * Clear the input audio buffer to the server\n */\n abstract clearAudio(): Promise<void>;\n\n /**\n * Cancel the current generation (do nothing if no generation is in progress)\n */\n abstract interrupt(): Promise<void>;\n\n /**\n * Truncate the message at the given audio end time\n */\n abstract truncate(options: {\n messageId: string;\n audioEndMs: number;\n modalities?: ('text' | 'audio')[];\n audioTranscript?: string;\n }): Promise<void>;\n\n async close(): Promise<void> {\n this._mainTask.cancel();\n }\n\n /**\n * Notifies the model that user activity has started\n */\n startUserActivity(): void {\n return;\n }\n\n private async _mainTaskImpl(signal: AbortSignal): Promise<void> {\n const reader = this.deferredInputStream.stream.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done || signal.aborted) {\n break;\n }\n this.pushAudio(value);\n }\n }\n\n setInputAudioStream(audioStream: ReadableStream<AudioFrame>): void {\n this.deferredInputStream.setSource(audioStream);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAA6B;AAE7B,6BAAuC;AACvC,mBAAqB;AAsDd,MAAe,cAAc;AAAA,EAC1B;AAAA,EAER,YAAY,cAAoC;AAC9C,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,IAAI,eAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAKA,IAAI,WAAmB;AACrB,WAAO;AAAA,EACT;AAKF;AAEO,MAAe,wBAAwB,2BAAa;AAAA,EAC/C;AAAA,EACF,sBAAsB,IAAI,8CAAmC;AAAA,EAC7D;AAAA,EAER,YAAY,eAA8B;AACxC,UAAM;AACN,SAAK,iBAAiB;AACtB,SAAK,YAAY,kBAAK,KAAK,CAAC,eAAe,KAAK,cAAc,WAAW,MAAM,CAAC;AAAA,EAClF;AAAA,EAEA,IAAI,gBAAgB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAiDA,MAAM,QAAuB;AAC3B,SAAK,UAAU,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,QAAoC;AAC9D,UAAM,SAAS,KAAK,oBAAoB,OAAO,UAAU;AACzD,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,QAAQ,OAAO,SAAS;AAC1B;AAAA,MACF;AACA,WAAK,UAAU,KAAK;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,oBAAoB,aAA+C;AACjE,SAAK,oBAAoB,UAAU,WAAW;AAAA,EAChD;AACF;","names":[]}
@@ -54,6 +54,7 @@ export declare abstract class RealtimeModel {
54
54
  get capabilities(): RealtimeCapabilities;
55
55
  /** The model name/identifier used by this realtime model */
56
56
  abstract get model(): string;
57
+ get provider(): string;
57
58
  abstract session(): RealtimeSession;
58
59
  abstract close(): Promise<void>;
59
60
  }
@@ -54,6 +54,7 @@ export declare abstract class RealtimeModel {
54
54
  get capabilities(): RealtimeCapabilities;
55
55
  /** The model name/identifier used by this realtime model */
56
56
  abstract get model(): string;
57
+ get provider(): string;
57
58
  abstract session(): RealtimeSession;
58
59
  abstract close(): Promise<void>;
59
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/llm/realtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/llm/realtime.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,9 @@ class RealtimeModel {
9
9
  get capabilities() {
10
10
  return this._capabilities;
11
11
  }
12
+ get provider() {
13
+ return "unknown";
14
+ }
12
15
  }
13
16
  class RealtimeSession extends EventEmitter {
14
17
  _realtimeModel;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/llm/realtime.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'events';\nimport type { ReadableStream } from 'node:stream/web';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { Task } from '../utils.js';\nimport type { TimedString } from '../voice/io.js';\nimport type { ChatContext, FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport type InputSpeechStartedEvent = object;\n\nexport interface InputSpeechStoppedEvent {\n userTranscriptionEnabled: boolean;\n}\n\nexport interface MessageGeneration {\n messageId: string;\n /**\n * Text stream that may contain plain strings or TimedString objects with timestamps.\n */\n textStream: ReadableStream<string | TimedString>;\n audioStream: ReadableStream<AudioFrame>;\n modalities?: Promise<('text' | 'audio')[]>;\n}\n\nexport interface GenerationCreatedEvent {\n messageStream: ReadableStream<MessageGeneration>;\n functionStream: ReadableStream<FunctionCall>;\n userInitiated: boolean;\n /** Response ID for correlating metrics with spans */\n responseId?: string;\n}\n\nexport interface RealtimeModelError {\n type: 'realtime_model_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport interface RealtimeCapabilities {\n messageTruncation: boolean;\n turnDetection: boolean;\n userTranscription: boolean;\n autoToolReplyGeneration: boolean;\n audioOutput: boolean;\n manualFunctionCalls: boolean;\n}\n\nexport interface InputTranscriptionCompleted {\n itemId: string;\n transcript: string;\n isFinal: boolean;\n}\n\nexport interface RealtimeSessionReconnectedEvent {}\n\nexport abstract class RealtimeModel {\n private _capabilities: RealtimeCapabilities;\n\n constructor(capabilities: RealtimeCapabilities) {\n this._capabilities = capabilities;\n }\n\n get capabilities() {\n return this._capabilities;\n }\n\n /** The model name/identifier used by this realtime model */\n abstract get model(): string;\n\n abstract session(): RealtimeSession;\n\n abstract close(): Promise<void>;\n}\n\nexport abstract class RealtimeSession extends EventEmitter {\n protected _realtimeModel: RealtimeModel;\n private deferredInputStream = new DeferredReadableStream<AudioFrame>();\n private _mainTask: Task<void>;\n\n constructor(realtimeModel: RealtimeModel) {\n super();\n this._realtimeModel = realtimeModel;\n this._mainTask = Task.from((controller) => this._mainTaskImpl(controller.signal));\n }\n\n get realtimeModel() {\n return this._realtimeModel;\n }\n\n abstract get chatCtx(): ChatContext;\n\n abstract get tools(): ToolContext;\n\n abstract updateInstructions(instructions: string): Promise<void>;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract updateChatCtx(chatCtx: ChatContext): Promise<void>;\n\n abstract updateTools(tools: ToolContext): Promise<void>;\n\n abstract updateOptions(options: { toolChoice?: ToolChoice | null }): void;\n\n abstract pushAudio(frame: AudioFrame): void;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract generateReply(instructions?: string): Promise<GenerationCreatedEvent>;\n\n /**\n * Commit the input audio buffer to the server\n */\n abstract commitAudio(): Promise<void>;\n\n /**\n * Clear the input audio buffer to the server\n */\n abstract clearAudio(): Promise<void>;\n\n /**\n * Cancel the current generation (do nothing if no generation is in progress)\n */\n abstract interrupt(): Promise<void>;\n\n /**\n * Truncate the message at the given audio end time\n */\n abstract truncate(options: {\n messageId: string;\n audioEndMs: number;\n modalities?: ('text' | 'audio')[];\n audioTranscript?: string;\n }): Promise<void>;\n\n async close(): Promise<void> {\n this._mainTask.cancel();\n }\n\n /**\n * Notifies the model that user activity has started\n */\n startUserActivity(): void {\n return;\n }\n\n private async _mainTaskImpl(signal: AbortSignal): Promise<void> {\n const reader = this.deferredInputStream.stream.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done || signal.aborted) {\n break;\n }\n this.pushAudio(value);\n }\n }\n\n setInputAudioStream(audioStream: ReadableStream<AudioFrame>): void {\n this.deferredInputStream.setSource(audioStream);\n }\n}\n"],"mappings":"AAIA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AACvC,SAAS,YAAY;AAsDd,MAAe,cAAc;AAAA,EAC1B;AAAA,EAER,YAAY,cAAoC;AAC9C,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,IAAI,eAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAQF;AAEO,MAAe,wBAAwB,aAAa;AAAA,EAC/C;AAAA,EACF,sBAAsB,IAAI,uBAAmC;AAAA,EAC7D;AAAA,EAER,YAAY,eAA8B;AACxC,UAAM;AACN,SAAK,iBAAiB;AACtB,SAAK,YAAY,KAAK,KAAK,CAAC,eAAe,KAAK,cAAc,WAAW,MAAM,CAAC;AAAA,EAClF;AAAA,EAEA,IAAI,gBAAgB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAiDA,MAAM,QAAuB;AAC3B,SAAK,UAAU,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,QAAoC;AAC9D,UAAM,SAAS,KAAK,oBAAoB,OAAO,UAAU;AACzD,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,QAAQ,OAAO,SAAS;AAC1B;AAAA,MACF;AACA,WAAK,UAAU,KAAK;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,oBAAoB,aAA+C;AACjE,SAAK,oBAAoB,UAAU,WAAW;AAAA,EAChD;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/llm/realtime.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'events';\nimport type { ReadableStream } from 'node:stream/web';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { Task } from '../utils.js';\nimport type { TimedString } from '../voice/io.js';\nimport type { ChatContext, FunctionCall } from './chat_context.js';\nimport type { ToolChoice, ToolContext } from './tool_context.js';\n\nexport type InputSpeechStartedEvent = object;\n\nexport interface InputSpeechStoppedEvent {\n userTranscriptionEnabled: boolean;\n}\n\nexport interface MessageGeneration {\n messageId: string;\n /**\n * Text stream that may contain plain strings or TimedString objects with timestamps.\n */\n textStream: ReadableStream<string | TimedString>;\n audioStream: ReadableStream<AudioFrame>;\n modalities?: Promise<('text' | 'audio')[]>;\n}\n\nexport interface GenerationCreatedEvent {\n messageStream: ReadableStream<MessageGeneration>;\n functionStream: ReadableStream<FunctionCall>;\n userInitiated: boolean;\n /** Response ID for correlating metrics with spans */\n responseId?: string;\n}\n\nexport interface RealtimeModelError {\n type: 'realtime_model_error';\n timestamp: number;\n label: string;\n error: Error;\n recoverable: boolean;\n}\n\nexport interface RealtimeCapabilities {\n messageTruncation: boolean;\n turnDetection: boolean;\n userTranscription: boolean;\n autoToolReplyGeneration: boolean;\n audioOutput: boolean;\n manualFunctionCalls: boolean;\n}\n\nexport interface InputTranscriptionCompleted {\n itemId: string;\n transcript: string;\n isFinal: boolean;\n}\n\nexport interface RealtimeSessionReconnectedEvent {}\n\nexport abstract class RealtimeModel {\n private _capabilities: RealtimeCapabilities;\n\n constructor(capabilities: RealtimeCapabilities) {\n this._capabilities = capabilities;\n }\n\n get capabilities() {\n return this._capabilities;\n }\n\n /** The model name/identifier used by this realtime model */\n abstract get model(): string;\n\n get provider(): string {\n return 'unknown';\n }\n\n abstract session(): RealtimeSession;\n\n abstract close(): Promise<void>;\n}\n\nexport abstract class RealtimeSession extends EventEmitter {\n protected _realtimeModel: RealtimeModel;\n private deferredInputStream = new DeferredReadableStream<AudioFrame>();\n private _mainTask: Task<void>;\n\n constructor(realtimeModel: RealtimeModel) {\n super();\n this._realtimeModel = realtimeModel;\n this._mainTask = Task.from((controller) => this._mainTaskImpl(controller.signal));\n }\n\n get realtimeModel() {\n return this._realtimeModel;\n }\n\n abstract get chatCtx(): ChatContext;\n\n abstract get tools(): ToolContext;\n\n abstract updateInstructions(instructions: string): Promise<void>;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract updateChatCtx(chatCtx: ChatContext): Promise<void>;\n\n abstract updateTools(tools: ToolContext): Promise<void>;\n\n abstract updateOptions(options: { toolChoice?: ToolChoice | null }): void;\n\n abstract pushAudio(frame: AudioFrame): void;\n\n /**\n * @throws RealtimeError on Timeout\n */\n abstract generateReply(instructions?: string): Promise<GenerationCreatedEvent>;\n\n /**\n * Commit the input audio buffer to the server\n */\n abstract commitAudio(): Promise<void>;\n\n /**\n * Clear the input audio buffer to the server\n */\n abstract clearAudio(): Promise<void>;\n\n /**\n * Cancel the current generation (do nothing if no generation is in progress)\n */\n abstract interrupt(): Promise<void>;\n\n /**\n * Truncate the message at the given audio end time\n */\n abstract truncate(options: {\n messageId: string;\n audioEndMs: number;\n modalities?: ('text' | 'audio')[];\n audioTranscript?: string;\n }): Promise<void>;\n\n async close(): Promise<void> {\n this._mainTask.cancel();\n }\n\n /**\n * Notifies the model that user activity has started\n */\n startUserActivity(): void {\n return;\n }\n\n private async _mainTaskImpl(signal: AbortSignal): Promise<void> {\n const reader = this.deferredInputStream.stream.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done || signal.aborted) {\n break;\n }\n this.pushAudio(value);\n }\n }\n\n setInputAudioStream(audioStream: ReadableStream<AudioFrame>): void {\n this.deferredInputStream.setSource(audioStream);\n }\n}\n"],"mappings":"AAIA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AACvC,SAAS,YAAY;AAsDd,MAAe,cAAc;AAAA,EAC1B;AAAA,EAER,YAAY,cAAoC;AAC9C,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,IAAI,eAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAKA,IAAI,WAAmB;AACrB,WAAO;AAAA,EACT;AAKF;AAEO,MAAe,wBAAwB,aAAa;AAAA,EAC/C;AAAA,EACF,sBAAsB,IAAI,uBAAmC;AAAA,EAC7D;AAAA,EAER,YAAY,eAA8B;AACxC,UAAM;AACN,SAAK,iBAAiB;AACtB,SAAK,YAAY,KAAK,KAAK,CAAC,eAAe,KAAK,cAAc,WAAW,MAAM,CAAC;AAAA,EAClF;AAAA,EAEA,IAAI,gBAAgB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAiDA,MAAM,QAAuB;AAC3B,SAAK,UAAU,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,QAAoC;AAC9D,UAAM,SAAS,KAAK,oBAAoB,OAAO,UAAU;AACzD,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,QAAQ,OAAO,SAAS;AAC1B;AAAA,MACF;AACA,WAAK,UAAU,KAAK;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,oBAAoB,aAA+C;AACjE,SAAK,oBAAoB,UAAU,WAAW;AAAA,EAChD;AACF;","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 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 /**\n * The time the user stopped speaking.\n */\n lastSpeakingTimeMs: number;\n /**\n * The ID of the speech handle.\n */\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":[]}
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 MetricsMetadata = {\n /** The provider name (e.g., 'openai', 'anthropic'). */\n modelProvider?: string;\n /** The model name (e.g., 'gpt-4o', 'claude-3-5-sonnet'). */\n modelName?: string;\n};\n\nexport type AgentMetrics =\n | STTMetrics\n | LLMMetrics\n | TTSMetrics\n | VADMetrics\n | EOUMetrics\n | RealtimeModelMetrics\n | InterruptionMetrics;\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 /** Metadata for model provider and name tracking. */\n metadata?: MetricsMetadata;\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 /** Input audio tokens (for token-based billing). */\n inputTokens?: number;\n /** Output text tokens (for token-based billing). */\n outputTokens?: number;\n /**\n * Whether the STT is streaming (e.g using websocket).\n */\n streamed: boolean;\n /** Metadata for model provider and name tracking. */\n metadata?: MetricsMetadata;\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 /** Number of characters synthesized (for character-based billing). */\n charactersCount: number;\n /** Input text tokens (for token-based billing, e.g., OpenAI TTS). */\n inputTokens?: number;\n /** Output audio tokens (for token-based billing, e.g., OpenAI TTS). */\n outputTokens?: number;\n streamed: boolean;\n segmentId?: string;\n speechId?: string;\n /** Metadata for model provider and name tracking. */\n metadata?: MetricsMetadata;\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 /**\n * The time the user stopped speaking.\n */\n lastSpeakingTimeMs: number;\n /**\n * The ID of the speech handle.\n */\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 * The duration of the session connection in milliseconds (for session-based billing like xAI).\n */\n sessionDurationMs?: 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 /** Metadata for model provider and name tracking. */\n metadata?: MetricsMetadata;\n};\n\nexport type InterruptionMetrics = {\n type: 'interruption_metrics';\n timestamp: number;\n /** Latest RTT time taken to perform inference, in milliseconds. */\n totalDuration: number;\n /** Latest time taken by the model side, in milliseconds. */\n predictionDuration: number;\n /** Latest total time from onset of speech to final prediction, in milliseconds. */\n detectionDelay: number;\n /** Number of interruptions detected (incremental). */\n numInterruptions: number;\n /** Number of backchannels detected (incremental). */\n numBackchannels: number;\n /** Number of requests sent to the model (incremental). */\n numRequests: number;\n metadata?: MetricsMetadata;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -1,4 +1,10 @@
1
- export type AgentMetrics = STTMetrics | LLMMetrics | TTSMetrics | VADMetrics | EOUMetrics | RealtimeModelMetrics;
1
+ export type MetricsMetadata = {
2
+ /** The provider name (e.g., 'openai', 'anthropic'). */
3
+ modelProvider?: string;
4
+ /** The model name (e.g., 'gpt-4o', 'claude-3-5-sonnet'). */
5
+ modelName?: string;
6
+ };
7
+ export type AgentMetrics = STTMetrics | LLMMetrics | TTSMetrics | VADMetrics | EOUMetrics | RealtimeModelMetrics | InterruptionMetrics;
2
8
  export type LLMMetrics = {
3
9
  type: 'llm_metrics';
4
10
  label: string;
@@ -15,6 +21,8 @@ export type LLMMetrics = {
15
21
  totalTokens: number;
16
22
  tokensPerSecond: number;
17
23
  speechId?: string;
24
+ /** Metadata for model provider and name tracking. */
25
+ metadata?: MetricsMetadata;
18
26
  };
19
27
  export type STTMetrics = {
20
28
  type: 'stt_metrics';
@@ -29,10 +37,16 @@ export type STTMetrics = {
29
37
  * The duration of the pushed audio in milliseconds.
30
38
  */
31
39
  audioDurationMs: number;
40
+ /** Input audio tokens (for token-based billing). */
41
+ inputTokens?: number;
42
+ /** Output text tokens (for token-based billing). */
43
+ outputTokens?: number;
32
44
  /**
33
45
  * Whether the STT is streaming (e.g using websocket).
34
46
  */
35
47
  streamed: boolean;
48
+ /** Metadata for model provider and name tracking. */
49
+ metadata?: MetricsMetadata;
36
50
  };
37
51
  export type TTSMetrics = {
38
52
  type: 'tts_metrics';
@@ -46,10 +60,17 @@ export type TTSMetrics = {
46
60
  /** Generated audio duration in milliseconds. */
47
61
  audioDurationMs: number;
48
62
  cancelled: boolean;
63
+ /** Number of characters synthesized (for character-based billing). */
49
64
  charactersCount: number;
65
+ /** Input text tokens (for token-based billing, e.g., OpenAI TTS). */
66
+ inputTokens?: number;
67
+ /** Output audio tokens (for token-based billing, e.g., OpenAI TTS). */
68
+ outputTokens?: number;
50
69
  streamed: boolean;
51
70
  segmentId?: string;
52
71
  speechId?: string;
72
+ /** Metadata for model provider and name tracking. */
73
+ metadata?: MetricsMetadata;
53
74
  };
54
75
  export type VADMetrics = {
55
76
  type: 'vad_metrics';
@@ -114,6 +135,10 @@ export type RealtimeModelMetrics = {
114
135
  * The duration of the response from created to done in milliseconds.
115
136
  */
116
137
  durationMs: number;
138
+ /**
139
+ * The duration of the session connection in milliseconds (for session-based billing like xAI).
140
+ */
141
+ sessionDurationMs?: number;
117
142
  /**
118
143
  * Time to first audio token in milliseconds. -1 if no audio token was sent.
119
144
  */
@@ -146,5 +171,24 @@ export type RealtimeModelMetrics = {
146
171
  * Details about the output tokens used in the Response.
147
172
  */
148
173
  outputTokenDetails: RealtimeModelMetricsOutputTokenDetails;
174
+ /** Metadata for model provider and name tracking. */
175
+ metadata?: MetricsMetadata;
176
+ };
177
+ export type InterruptionMetrics = {
178
+ type: 'interruption_metrics';
179
+ timestamp: number;
180
+ /** Latest RTT time taken to perform inference, in milliseconds. */
181
+ totalDuration: number;
182
+ /** Latest time taken by the model side, in milliseconds. */
183
+ predictionDuration: number;
184
+ /** Latest total time from onset of speech to final prediction, in milliseconds. */
185
+ detectionDelay: number;
186
+ /** Number of interruptions detected (incremental). */
187
+ numInterruptions: number;
188
+ /** Number of backchannels detected (incremental). */
189
+ numBackchannels: number;
190
+ /** Number of requests sent to the model (incremental). */
191
+ numRequests: number;
192
+ metadata?: MetricsMetadata;
149
193
  };
150
194
  //# sourceMappingURL=base.d.ts.map
@@ -1,4 +1,10 @@
1
- export type AgentMetrics = STTMetrics | LLMMetrics | TTSMetrics | VADMetrics | EOUMetrics | RealtimeModelMetrics;
1
+ export type MetricsMetadata = {
2
+ /** The provider name (e.g., 'openai', 'anthropic'). */
3
+ modelProvider?: string;
4
+ /** The model name (e.g., 'gpt-4o', 'claude-3-5-sonnet'). */
5
+ modelName?: string;
6
+ };
7
+ export type AgentMetrics = STTMetrics | LLMMetrics | TTSMetrics | VADMetrics | EOUMetrics | RealtimeModelMetrics | InterruptionMetrics;
2
8
  export type LLMMetrics = {
3
9
  type: 'llm_metrics';
4
10
  label: string;
@@ -15,6 +21,8 @@ export type LLMMetrics = {
15
21
  totalTokens: number;
16
22
  tokensPerSecond: number;
17
23
  speechId?: string;
24
+ /** Metadata for model provider and name tracking. */
25
+ metadata?: MetricsMetadata;
18
26
  };
19
27
  export type STTMetrics = {
20
28
  type: 'stt_metrics';
@@ -29,10 +37,16 @@ export type STTMetrics = {
29
37
  * The duration of the pushed audio in milliseconds.
30
38
  */
31
39
  audioDurationMs: number;
40
+ /** Input audio tokens (for token-based billing). */
41
+ inputTokens?: number;
42
+ /** Output text tokens (for token-based billing). */
43
+ outputTokens?: number;
32
44
  /**
33
45
  * Whether the STT is streaming (e.g using websocket).
34
46
  */
35
47
  streamed: boolean;
48
+ /** Metadata for model provider and name tracking. */
49
+ metadata?: MetricsMetadata;
36
50
  };
37
51
  export type TTSMetrics = {
38
52
  type: 'tts_metrics';
@@ -46,10 +60,17 @@ export type TTSMetrics = {
46
60
  /** Generated audio duration in milliseconds. */
47
61
  audioDurationMs: number;
48
62
  cancelled: boolean;
63
+ /** Number of characters synthesized (for character-based billing). */
49
64
  charactersCount: number;
65
+ /** Input text tokens (for token-based billing, e.g., OpenAI TTS). */
66
+ inputTokens?: number;
67
+ /** Output audio tokens (for token-based billing, e.g., OpenAI TTS). */
68
+ outputTokens?: number;
50
69
  streamed: boolean;
51
70
  segmentId?: string;
52
71
  speechId?: string;
72
+ /** Metadata for model provider and name tracking. */
73
+ metadata?: MetricsMetadata;
53
74
  };
54
75
  export type VADMetrics = {
55
76
  type: 'vad_metrics';
@@ -114,6 +135,10 @@ export type RealtimeModelMetrics = {
114
135
  * The duration of the response from created to done in milliseconds.
115
136
  */
116
137
  durationMs: number;
138
+ /**
139
+ * The duration of the session connection in milliseconds (for session-based billing like xAI).
140
+ */
141
+ sessionDurationMs?: number;
117
142
  /**
118
143
  * Time to first audio token in milliseconds. -1 if no audio token was sent.
119
144
  */
@@ -146,5 +171,24 @@ export type RealtimeModelMetrics = {
146
171
  * Details about the output tokens used in the Response.
147
172
  */
148
173
  outputTokenDetails: RealtimeModelMetricsOutputTokenDetails;
174
+ /** Metadata for model provider and name tracking. */
175
+ metadata?: MetricsMetadata;
176
+ };
177
+ export type InterruptionMetrics = {
178
+ type: 'interruption_metrics';
179
+ timestamp: number;
180
+ /** Latest RTT time taken to perform inference, in milliseconds. */
181
+ totalDuration: number;
182
+ /** Latest time taken by the model side, in milliseconds. */
183
+ predictionDuration: number;
184
+ /** Latest total time from onset of speech to final prediction, in milliseconds. */
185
+ detectionDelay: number;
186
+ /** Number of interruptions detected (incremental). */
187
+ numInterruptions: number;
188
+ /** Number of backchannels detected (incremental). */
189
+ numBackchannels: number;
190
+ /** Number of requests sent to the model (incremental). */
191
+ numRequests: number;
192
+ metadata?: MetricsMetadata;
149
193
  };
150
194
  //# sourceMappingURL=base.d.ts.map