@livekit/agents 1.0.47 → 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 (444) hide show
  1. package/dist/beta/index.cjs +29 -0
  2. package/dist/beta/index.cjs.map +1 -0
  3. package/dist/beta/index.d.cts +2 -0
  4. package/dist/beta/index.d.ts +2 -0
  5. package/dist/beta/index.d.ts.map +1 -0
  6. package/dist/beta/index.js +7 -0
  7. package/dist/beta/index.js.map +1 -0
  8. package/dist/beta/workflows/index.cjs +29 -0
  9. package/dist/beta/workflows/index.cjs.map +1 -0
  10. package/dist/beta/workflows/index.d.cts +2 -0
  11. package/dist/beta/workflows/index.d.ts +2 -0
  12. package/dist/beta/workflows/index.d.ts.map +1 -0
  13. package/dist/beta/workflows/index.js +7 -0
  14. package/dist/beta/workflows/index.js.map +1 -0
  15. package/dist/beta/workflows/task_group.cjs +162 -0
  16. package/dist/beta/workflows/task_group.cjs.map +1 -0
  17. package/dist/beta/workflows/task_group.d.cts +32 -0
  18. package/dist/beta/workflows/task_group.d.ts +32 -0
  19. package/dist/beta/workflows/task_group.d.ts.map +1 -0
  20. package/dist/beta/workflows/task_group.js +138 -0
  21. package/dist/beta/workflows/task_group.js.map +1 -0
  22. package/dist/constants.cjs +27 -0
  23. package/dist/constants.cjs.map +1 -1
  24. package/dist/constants.d.cts +9 -0
  25. package/dist/constants.d.ts +9 -0
  26. package/dist/constants.d.ts.map +1 -1
  27. package/dist/constants.js +18 -0
  28. package/dist/constants.js.map +1 -1
  29. package/dist/index.cjs +3 -0
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +2 -1
  32. package/dist/index.d.ts +2 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +2 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/inference/api_protos.d.cts +12 -12
  37. package/dist/inference/api_protos.d.ts +12 -12
  38. package/dist/inference/interruption/defaults.cjs +81 -0
  39. package/dist/inference/interruption/defaults.cjs.map +1 -0
  40. package/dist/inference/interruption/defaults.d.cts +19 -0
  41. package/dist/inference/interruption/defaults.d.ts +19 -0
  42. package/dist/inference/interruption/defaults.d.ts.map +1 -0
  43. package/dist/inference/interruption/defaults.js +46 -0
  44. package/dist/inference/interruption/defaults.js.map +1 -0
  45. package/dist/inference/interruption/errors.cjs +44 -0
  46. package/dist/inference/interruption/errors.cjs.map +1 -0
  47. package/dist/inference/interruption/errors.d.cts +12 -0
  48. package/dist/inference/interruption/errors.d.ts +12 -0
  49. package/dist/inference/interruption/errors.d.ts.map +1 -0
  50. package/dist/inference/interruption/errors.js +20 -0
  51. package/dist/inference/interruption/errors.js.map +1 -0
  52. package/dist/inference/interruption/http_transport.cjs +147 -0
  53. package/dist/inference/interruption/http_transport.cjs.map +1 -0
  54. package/dist/inference/interruption/http_transport.d.cts +63 -0
  55. package/dist/inference/interruption/http_transport.d.ts +63 -0
  56. package/dist/inference/interruption/http_transport.d.ts.map +1 -0
  57. package/dist/inference/interruption/http_transport.js +121 -0
  58. package/dist/inference/interruption/http_transport.js.map +1 -0
  59. package/dist/inference/interruption/interruption_cache_entry.cjs +58 -0
  60. package/dist/inference/interruption/interruption_cache_entry.cjs.map +1 -0
  61. package/dist/inference/interruption/interruption_cache_entry.d.cts +30 -0
  62. package/dist/inference/interruption/interruption_cache_entry.d.ts +30 -0
  63. package/dist/inference/interruption/interruption_cache_entry.d.ts.map +1 -0
  64. package/dist/inference/interruption/interruption_cache_entry.js +34 -0
  65. package/dist/inference/interruption/interruption_cache_entry.js.map +1 -0
  66. package/dist/inference/interruption/interruption_detector.cjs +181 -0
  67. package/dist/inference/interruption/interruption_detector.cjs.map +1 -0
  68. package/dist/inference/interruption/interruption_detector.d.cts +59 -0
  69. package/dist/inference/interruption/interruption_detector.d.ts +59 -0
  70. package/dist/inference/interruption/interruption_detector.d.ts.map +1 -0
  71. package/dist/inference/interruption/interruption_detector.js +147 -0
  72. package/dist/inference/interruption/interruption_detector.js.map +1 -0
  73. package/dist/inference/interruption/interruption_stream.cjs +368 -0
  74. package/dist/inference/interruption/interruption_stream.cjs.map +1 -0
  75. package/dist/inference/interruption/interruption_stream.d.cts +46 -0
  76. package/dist/inference/interruption/interruption_stream.d.ts +46 -0
  77. package/dist/inference/interruption/interruption_stream.d.ts.map +1 -0
  78. package/dist/inference/interruption/interruption_stream.js +344 -0
  79. package/dist/inference/interruption/interruption_stream.js.map +1 -0
  80. package/dist/inference/interruption/types.cjs +17 -0
  81. package/dist/inference/interruption/types.cjs.map +1 -0
  82. package/dist/inference/interruption/types.d.cts +66 -0
  83. package/dist/inference/interruption/types.d.ts +66 -0
  84. package/dist/inference/interruption/types.d.ts.map +1 -0
  85. package/dist/inference/interruption/types.js +1 -0
  86. package/dist/inference/interruption/types.js.map +1 -0
  87. package/dist/inference/interruption/utils.cjs +130 -0
  88. package/dist/inference/interruption/utils.cjs.map +1 -0
  89. package/dist/inference/interruption/utils.d.cts +41 -0
  90. package/dist/inference/interruption/utils.d.ts +41 -0
  91. package/dist/inference/interruption/utils.d.ts.map +1 -0
  92. package/dist/inference/interruption/utils.js +105 -0
  93. package/dist/inference/interruption/utils.js.map +1 -0
  94. package/dist/inference/interruption/utils.test.cjs +105 -0
  95. package/dist/inference/interruption/utils.test.cjs.map +1 -0
  96. package/dist/inference/interruption/utils.test.js +104 -0
  97. package/dist/inference/interruption/utils.test.js.map +1 -0
  98. package/dist/inference/interruption/ws_transport.cjs +329 -0
  99. package/dist/inference/interruption/ws_transport.cjs.map +1 -0
  100. package/dist/inference/interruption/ws_transport.d.cts +33 -0
  101. package/dist/inference/interruption/ws_transport.d.ts +33 -0
  102. package/dist/inference/interruption/ws_transport.d.ts.map +1 -0
  103. package/dist/inference/interruption/ws_transport.js +295 -0
  104. package/dist/inference/interruption/ws_transport.js.map +1 -0
  105. package/dist/inference/llm.cjs +14 -10
  106. package/dist/inference/llm.cjs.map +1 -1
  107. package/dist/inference/llm.d.cts +2 -1
  108. package/dist/inference/llm.d.ts +2 -1
  109. package/dist/inference/llm.d.ts.map +1 -1
  110. package/dist/inference/llm.js +8 -10
  111. package/dist/inference/llm.js.map +1 -1
  112. package/dist/inference/stt.cjs +7 -2
  113. package/dist/inference/stt.cjs.map +1 -1
  114. package/dist/inference/stt.d.cts +2 -0
  115. package/dist/inference/stt.d.ts +2 -0
  116. package/dist/inference/stt.d.ts.map +1 -1
  117. package/dist/inference/stt.js +8 -3
  118. package/dist/inference/stt.js.map +1 -1
  119. package/dist/inference/tts.cjs +7 -2
  120. package/dist/inference/tts.cjs.map +1 -1
  121. package/dist/inference/tts.d.cts +2 -0
  122. package/dist/inference/tts.d.ts +2 -0
  123. package/dist/inference/tts.d.ts.map +1 -1
  124. package/dist/inference/tts.js +8 -3
  125. package/dist/inference/tts.js.map +1 -1
  126. package/dist/inference/utils.cjs +26 -7
  127. package/dist/inference/utils.cjs.map +1 -1
  128. package/dist/inference/utils.d.cts +13 -0
  129. package/dist/inference/utils.d.ts +13 -0
  130. package/dist/inference/utils.d.ts.map +1 -1
  131. package/dist/inference/utils.js +18 -2
  132. package/dist/inference/utils.js.map +1 -1
  133. package/dist/llm/chat_context.cjs +108 -2
  134. package/dist/llm/chat_context.cjs.map +1 -1
  135. package/dist/llm/chat_context.d.cts +28 -1
  136. package/dist/llm/chat_context.d.ts +28 -1
  137. package/dist/llm/chat_context.d.ts.map +1 -1
  138. package/dist/llm/chat_context.js +108 -2
  139. package/dist/llm/chat_context.js.map +1 -1
  140. package/dist/llm/chat_context.test.cjs +43 -0
  141. package/dist/llm/chat_context.test.cjs.map +1 -1
  142. package/dist/llm/chat_context.test.js +43 -0
  143. package/dist/llm/chat_context.test.js.map +1 -1
  144. package/dist/llm/index.cjs +2 -0
  145. package/dist/llm/index.cjs.map +1 -1
  146. package/dist/llm/index.d.cts +2 -2
  147. package/dist/llm/index.d.ts +2 -2
  148. package/dist/llm/index.d.ts.map +1 -1
  149. package/dist/llm/index.js +3 -1
  150. package/dist/llm/index.js.map +1 -1
  151. package/dist/llm/llm.cjs +16 -1
  152. package/dist/llm/llm.cjs.map +1 -1
  153. package/dist/llm/llm.d.cts +9 -0
  154. package/dist/llm/llm.d.ts +9 -0
  155. package/dist/llm/llm.d.ts.map +1 -1
  156. package/dist/llm/llm.js +16 -1
  157. package/dist/llm/llm.js.map +1 -1
  158. package/dist/llm/provider_format/index.d.cts +1 -1
  159. package/dist/llm/provider_format/index.d.ts +1 -1
  160. package/dist/llm/realtime.cjs +3 -0
  161. package/dist/llm/realtime.cjs.map +1 -1
  162. package/dist/llm/realtime.d.cts +1 -0
  163. package/dist/llm/realtime.d.ts +1 -0
  164. package/dist/llm/realtime.d.ts.map +1 -1
  165. package/dist/llm/realtime.js +3 -0
  166. package/dist/llm/realtime.js.map +1 -1
  167. package/dist/llm/tool_context.cjs +7 -0
  168. package/dist/llm/tool_context.cjs.map +1 -1
  169. package/dist/llm/tool_context.d.cts +10 -2
  170. package/dist/llm/tool_context.d.ts +10 -2
  171. package/dist/llm/tool_context.d.ts.map +1 -1
  172. package/dist/llm/tool_context.js +6 -0
  173. package/dist/llm/tool_context.js.map +1 -1
  174. package/dist/metrics/base.cjs.map +1 -1
  175. package/dist/metrics/base.d.cts +45 -1
  176. package/dist/metrics/base.d.ts +45 -1
  177. package/dist/metrics/base.d.ts.map +1 -1
  178. package/dist/metrics/index.cjs +5 -0
  179. package/dist/metrics/index.cjs.map +1 -1
  180. package/dist/metrics/index.d.cts +2 -1
  181. package/dist/metrics/index.d.ts +2 -1
  182. package/dist/metrics/index.d.ts.map +1 -1
  183. package/dist/metrics/index.js +6 -0
  184. package/dist/metrics/index.js.map +1 -1
  185. package/dist/metrics/model_usage.cjs +189 -0
  186. package/dist/metrics/model_usage.cjs.map +1 -0
  187. package/dist/metrics/model_usage.d.cts +92 -0
  188. package/dist/metrics/model_usage.d.ts +92 -0
  189. package/dist/metrics/model_usage.d.ts.map +1 -0
  190. package/dist/metrics/model_usage.js +164 -0
  191. package/dist/metrics/model_usage.js.map +1 -0
  192. package/dist/metrics/model_usage.test.cjs +474 -0
  193. package/dist/metrics/model_usage.test.cjs.map +1 -0
  194. package/dist/metrics/model_usage.test.js +476 -0
  195. package/dist/metrics/model_usage.test.js.map +1 -0
  196. package/dist/metrics/usage_collector.cjs +3 -0
  197. package/dist/metrics/usage_collector.cjs.map +1 -1
  198. package/dist/metrics/usage_collector.d.cts +9 -0
  199. package/dist/metrics/usage_collector.d.ts +9 -0
  200. package/dist/metrics/usage_collector.d.ts.map +1 -1
  201. package/dist/metrics/usage_collector.js +3 -0
  202. package/dist/metrics/usage_collector.js.map +1 -1
  203. package/dist/metrics/utils.cjs +9 -0
  204. package/dist/metrics/utils.cjs.map +1 -1
  205. package/dist/metrics/utils.d.ts.map +1 -1
  206. package/dist/metrics/utils.js +9 -0
  207. package/dist/metrics/utils.js.map +1 -1
  208. package/dist/stream/multi_input_stream.test.cjs +4 -0
  209. package/dist/stream/multi_input_stream.test.cjs.map +1 -1
  210. package/dist/stream/multi_input_stream.test.js +5 -1
  211. package/dist/stream/multi_input_stream.test.js.map +1 -1
  212. package/dist/stream/stream_channel.cjs +31 -0
  213. package/dist/stream/stream_channel.cjs.map +1 -1
  214. package/dist/stream/stream_channel.d.cts +4 -2
  215. package/dist/stream/stream_channel.d.ts +4 -2
  216. package/dist/stream/stream_channel.d.ts.map +1 -1
  217. package/dist/stream/stream_channel.js +31 -0
  218. package/dist/stream/stream_channel.js.map +1 -1
  219. package/dist/stt/stt.cjs +34 -2
  220. package/dist/stt/stt.cjs.map +1 -1
  221. package/dist/stt/stt.d.cts +22 -0
  222. package/dist/stt/stt.d.ts +22 -0
  223. package/dist/stt/stt.d.ts.map +1 -1
  224. package/dist/stt/stt.js +34 -2
  225. package/dist/stt/stt.js.map +1 -1
  226. package/dist/telemetry/otel_http_exporter.cjs +24 -5
  227. package/dist/telemetry/otel_http_exporter.cjs.map +1 -1
  228. package/dist/telemetry/otel_http_exporter.d.cts +1 -0
  229. package/dist/telemetry/otel_http_exporter.d.ts +1 -0
  230. package/dist/telemetry/otel_http_exporter.d.ts.map +1 -1
  231. package/dist/telemetry/otel_http_exporter.js +24 -5
  232. package/dist/telemetry/otel_http_exporter.js.map +1 -1
  233. package/dist/telemetry/trace_types.cjs +5 -5
  234. package/dist/telemetry/trace_types.cjs.map +1 -1
  235. package/dist/telemetry/trace_types.d.cts +9 -5
  236. package/dist/telemetry/trace_types.d.ts +9 -5
  237. package/dist/telemetry/trace_types.d.ts.map +1 -1
  238. package/dist/telemetry/trace_types.js +5 -5
  239. package/dist/telemetry/trace_types.js.map +1 -1
  240. package/dist/telemetry/traces.cjs +47 -8
  241. package/dist/telemetry/traces.cjs.map +1 -1
  242. package/dist/telemetry/traces.d.ts.map +1 -1
  243. package/dist/telemetry/traces.js +47 -8
  244. package/dist/telemetry/traces.js.map +1 -1
  245. package/dist/tts/tts.cjs +64 -2
  246. package/dist/tts/tts.cjs.map +1 -1
  247. package/dist/tts/tts.d.cts +34 -0
  248. package/dist/tts/tts.d.ts +34 -0
  249. package/dist/tts/tts.d.ts.map +1 -1
  250. package/dist/tts/tts.js +64 -2
  251. package/dist/tts/tts.js.map +1 -1
  252. package/dist/utils.cjs +1 -0
  253. package/dist/utils.cjs.map +1 -1
  254. package/dist/utils.d.ts.map +1 -1
  255. package/dist/utils.js +1 -0
  256. package/dist/utils.js.map +1 -1
  257. package/dist/version.cjs +1 -1
  258. package/dist/version.js +1 -1
  259. package/dist/voice/agent.cjs +34 -4
  260. package/dist/voice/agent.cjs.map +1 -1
  261. package/dist/voice/agent.d.cts +11 -2
  262. package/dist/voice/agent.d.ts +11 -2
  263. package/dist/voice/agent.d.ts.map +1 -1
  264. package/dist/voice/agent.js +34 -4
  265. package/dist/voice/agent.js.map +1 -1
  266. package/dist/voice/agent_activity.cjs +292 -44
  267. package/dist/voice/agent_activity.cjs.map +1 -1
  268. package/dist/voice/agent_activity.d.cts +27 -6
  269. package/dist/voice/agent_activity.d.ts +27 -6
  270. package/dist/voice/agent_activity.d.ts.map +1 -1
  271. package/dist/voice/agent_activity.js +293 -45
  272. package/dist/voice/agent_activity.js.map +1 -1
  273. package/dist/voice/agent_session.cjs +105 -48
  274. package/dist/voice/agent_session.cjs.map +1 -1
  275. package/dist/voice/agent_session.d.cts +90 -20
  276. package/dist/voice/agent_session.d.ts +90 -20
  277. package/dist/voice/agent_session.d.ts.map +1 -1
  278. package/dist/voice/agent_session.js +105 -46
  279. package/dist/voice/agent_session.js.map +1 -1
  280. package/dist/voice/audio_recognition.cjs +287 -6
  281. package/dist/voice/audio_recognition.cjs.map +1 -1
  282. package/dist/voice/audio_recognition.d.cts +42 -3
  283. package/dist/voice/audio_recognition.d.ts +42 -3
  284. package/dist/voice/audio_recognition.d.ts.map +1 -1
  285. package/dist/voice/audio_recognition.js +289 -7
  286. package/dist/voice/audio_recognition.js.map +1 -1
  287. package/dist/voice/client_events.cjs +554 -0
  288. package/dist/voice/client_events.cjs.map +1 -0
  289. package/dist/voice/client_events.d.cts +195 -0
  290. package/dist/voice/client_events.d.ts +195 -0
  291. package/dist/voice/client_events.d.ts.map +1 -0
  292. package/dist/voice/client_events.js +548 -0
  293. package/dist/voice/client_events.js.map +1 -0
  294. package/dist/voice/events.cjs +1 -0
  295. package/dist/voice/events.cjs.map +1 -1
  296. package/dist/voice/events.d.cts +8 -5
  297. package/dist/voice/events.d.ts +8 -5
  298. package/dist/voice/events.d.ts.map +1 -1
  299. package/dist/voice/events.js +1 -0
  300. package/dist/voice/events.js.map +1 -1
  301. package/dist/voice/generation.cjs +43 -8
  302. package/dist/voice/generation.cjs.map +1 -1
  303. package/dist/voice/generation.d.cts +3 -3
  304. package/dist/voice/generation.d.ts +3 -3
  305. package/dist/voice/generation.d.ts.map +1 -1
  306. package/dist/voice/generation.js +43 -8
  307. package/dist/voice/generation.js.map +1 -1
  308. package/dist/voice/index.cjs +1 -0
  309. package/dist/voice/index.cjs.map +1 -1
  310. package/dist/voice/index.d.cts +1 -0
  311. package/dist/voice/index.d.ts +1 -0
  312. package/dist/voice/index.d.ts.map +1 -1
  313. package/dist/voice/index.js +1 -0
  314. package/dist/voice/index.js.map +1 -1
  315. package/dist/voice/report.cjs +20 -8
  316. package/dist/voice/report.cjs.map +1 -1
  317. package/dist/voice/report.d.cts +5 -0
  318. package/dist/voice/report.d.ts +5 -0
  319. package/dist/voice/report.d.ts.map +1 -1
  320. package/dist/voice/report.js +20 -8
  321. package/dist/voice/report.js.map +1 -1
  322. package/dist/voice/report.test.cjs +106 -0
  323. package/dist/voice/report.test.cjs.map +1 -0
  324. package/dist/voice/report.test.js +105 -0
  325. package/dist/voice/report.test.js.map +1 -0
  326. package/dist/voice/room_io/room_io.cjs +16 -41
  327. package/dist/voice/room_io/room_io.cjs.map +1 -1
  328. package/dist/voice/room_io/room_io.d.cts +4 -9
  329. package/dist/voice/room_io/room_io.d.ts +4 -9
  330. package/dist/voice/room_io/room_io.d.ts.map +1 -1
  331. package/dist/voice/room_io/room_io.js +17 -43
  332. package/dist/voice/room_io/room_io.js.map +1 -1
  333. package/dist/voice/testing/fake_llm.cjs +127 -0
  334. package/dist/voice/testing/fake_llm.cjs.map +1 -0
  335. package/dist/voice/testing/fake_llm.d.cts +30 -0
  336. package/dist/voice/testing/fake_llm.d.ts +30 -0
  337. package/dist/voice/testing/fake_llm.d.ts.map +1 -0
  338. package/dist/voice/testing/fake_llm.js +103 -0
  339. package/dist/voice/testing/fake_llm.js.map +1 -0
  340. package/dist/voice/testing/index.cjs +3 -0
  341. package/dist/voice/testing/index.cjs.map +1 -1
  342. package/dist/voice/testing/index.d.cts +1 -0
  343. package/dist/voice/testing/index.d.ts +1 -0
  344. package/dist/voice/testing/index.d.ts.map +1 -1
  345. package/dist/voice/testing/index.js +2 -0
  346. package/dist/voice/testing/index.js.map +1 -1
  347. package/dist/voice/turn_config/endpointing.cjs +33 -0
  348. package/dist/voice/turn_config/endpointing.cjs.map +1 -0
  349. package/dist/voice/turn_config/endpointing.d.cts +30 -0
  350. package/dist/voice/turn_config/endpointing.d.ts +30 -0
  351. package/dist/voice/turn_config/endpointing.d.ts.map +1 -0
  352. package/dist/voice/turn_config/endpointing.js +9 -0
  353. package/dist/voice/turn_config/endpointing.js.map +1 -0
  354. package/dist/voice/turn_config/interruption.cjs +37 -0
  355. package/dist/voice/turn_config/interruption.cjs.map +1 -0
  356. package/dist/voice/turn_config/interruption.d.cts +53 -0
  357. package/dist/voice/turn_config/interruption.d.ts +53 -0
  358. package/dist/voice/turn_config/interruption.d.ts.map +1 -0
  359. package/dist/voice/turn_config/interruption.js +13 -0
  360. package/dist/voice/turn_config/interruption.js.map +1 -0
  361. package/dist/voice/turn_config/turn_handling.cjs +35 -0
  362. package/dist/voice/turn_config/turn_handling.cjs.map +1 -0
  363. package/dist/voice/turn_config/turn_handling.d.cts +36 -0
  364. package/dist/voice/turn_config/turn_handling.d.ts +36 -0
  365. package/dist/voice/turn_config/turn_handling.d.ts.map +1 -0
  366. package/dist/voice/turn_config/turn_handling.js +11 -0
  367. package/dist/voice/turn_config/turn_handling.js.map +1 -0
  368. package/dist/voice/turn_config/utils.cjs +97 -0
  369. package/dist/voice/turn_config/utils.cjs.map +1 -0
  370. package/dist/voice/turn_config/utils.d.cts +25 -0
  371. package/dist/voice/turn_config/utils.d.ts +25 -0
  372. package/dist/voice/turn_config/utils.d.ts.map +1 -0
  373. package/dist/voice/turn_config/utils.js +73 -0
  374. package/dist/voice/turn_config/utils.js.map +1 -0
  375. package/dist/voice/turn_config/utils.test.cjs +86 -0
  376. package/dist/voice/turn_config/utils.test.cjs.map +1 -0
  377. package/dist/voice/turn_config/utils.test.js +85 -0
  378. package/dist/voice/turn_config/utils.test.js.map +1 -0
  379. package/dist/voice/wire_format.cjs +798 -0
  380. package/dist/voice/wire_format.cjs.map +1 -0
  381. package/dist/voice/wire_format.d.cts +5503 -0
  382. package/dist/voice/wire_format.d.ts +5503 -0
  383. package/dist/voice/wire_format.d.ts.map +1 -0
  384. package/dist/voice/wire_format.js +728 -0
  385. package/dist/voice/wire_format.js.map +1 -0
  386. package/package.json +2 -1
  387. package/src/beta/index.ts +9 -0
  388. package/src/beta/workflows/index.ts +9 -0
  389. package/src/beta/workflows/task_group.ts +194 -0
  390. package/src/constants.ts +13 -0
  391. package/src/index.ts +2 -1
  392. package/src/inference/interruption/defaults.ts +51 -0
  393. package/src/inference/interruption/errors.ts +25 -0
  394. package/src/inference/interruption/http_transport.ts +187 -0
  395. package/src/inference/interruption/interruption_cache_entry.ts +50 -0
  396. package/src/inference/interruption/interruption_detector.ts +188 -0
  397. package/src/inference/interruption/interruption_stream.ts +467 -0
  398. package/src/inference/interruption/types.ts +84 -0
  399. package/src/inference/interruption/utils.test.ts +132 -0
  400. package/src/inference/interruption/utils.ts +137 -0
  401. package/src/inference/interruption/ws_transport.ts +402 -0
  402. package/src/inference/llm.ts +9 -12
  403. package/src/inference/stt.ts +10 -3
  404. package/src/inference/tts.ts +10 -3
  405. package/src/inference/utils.ts +29 -1
  406. package/src/llm/chat_context.test.ts +48 -0
  407. package/src/llm/chat_context.ts +161 -0
  408. package/src/llm/index.ts +2 -0
  409. package/src/llm/llm.ts +16 -0
  410. package/src/llm/realtime.ts +4 -0
  411. package/src/llm/tool_context.ts +14 -0
  412. package/src/metrics/base.ts +48 -1
  413. package/src/metrics/index.ts +11 -0
  414. package/src/metrics/model_usage.test.ts +545 -0
  415. package/src/metrics/model_usage.ts +262 -0
  416. package/src/metrics/usage_collector.ts +11 -0
  417. package/src/metrics/utils.ts +11 -0
  418. package/src/stream/multi_input_stream.test.ts +6 -1
  419. package/src/stream/stream_channel.ts +34 -2
  420. package/src/stt/stt.ts +38 -0
  421. package/src/telemetry/otel_http_exporter.ts +28 -5
  422. package/src/telemetry/trace_types.ts +11 -8
  423. package/src/telemetry/traces.ts +111 -54
  424. package/src/tts/tts.ts +69 -1
  425. package/src/utils.ts +5 -0
  426. package/src/voice/agent.ts +41 -3
  427. package/src/voice/agent_activity.ts +371 -34
  428. package/src/voice/agent_session.ts +207 -59
  429. package/src/voice/audio_recognition.ts +385 -9
  430. package/src/voice/client_events.ts +838 -0
  431. package/src/voice/events.ts +14 -4
  432. package/src/voice/generation.ts +52 -9
  433. package/src/voice/index.ts +1 -0
  434. package/src/voice/report.test.ts +117 -0
  435. package/src/voice/report.ts +29 -6
  436. package/src/voice/room_io/room_io.ts +21 -64
  437. package/src/voice/testing/fake_llm.ts +138 -0
  438. package/src/voice/testing/index.ts +2 -0
  439. package/src/voice/turn_config/endpointing.ts +33 -0
  440. package/src/voice/turn_config/interruption.ts +56 -0
  441. package/src/voice/turn_config/turn_handling.ts +45 -0
  442. package/src/voice/turn_config/utils.test.ts +100 -0
  443. package/src/voice/turn_config/utils.ts +103 -0
  444. package/src/voice/wire_format.ts +827 -0
@@ -0,0 +1,402 @@
1
+ // SPDX-FileCopyrightText: 2025 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { TransformStream } from 'stream/web';
5
+ import WebSocket from 'ws';
6
+ import { z } from 'zod';
7
+ import { log } from '../../log.js';
8
+ import { createAccessToken } from '../utils.js';
9
+ import { intervalForRetry } from './defaults.js';
10
+ import { InterruptionCacheEntry } from './interruption_cache_entry.js';
11
+ import type { OverlappingSpeechEvent } from './types.js';
12
+ import type { BoundedCache } from './utils.js';
13
+
14
+ // WebSocket message types
15
+ const MSG_SESSION_CREATE = 'session.create';
16
+ const MSG_SESSION_CLOSE = 'session.close';
17
+ const MSG_SESSION_CREATED = 'session.created';
18
+ const MSG_SESSION_CLOSED = 'session.closed';
19
+ const MSG_INTERRUPTION_DETECTED = 'bargein_detected';
20
+ const MSG_INFERENCE_DONE = 'inference_done';
21
+ const MSG_ERROR = 'error';
22
+
23
+ export interface WsTransportOptions {
24
+ baseUrl: string;
25
+ apiKey: string;
26
+ apiSecret: string;
27
+ sampleRate: number;
28
+ threshold: number;
29
+ minFrames: number;
30
+ timeout: number;
31
+ maxRetries?: number;
32
+ }
33
+
34
+ export interface WsTransportState {
35
+ overlapSpeechStarted: boolean;
36
+ overlapSpeechStartedAt: number | undefined;
37
+ cache: BoundedCache<number, InterruptionCacheEntry>;
38
+ }
39
+
40
+ const wsMessageSchema = z.discriminatedUnion('type', [
41
+ z.object({
42
+ type: z.literal(MSG_SESSION_CREATED),
43
+ }),
44
+ z.object({
45
+ type: z.literal(MSG_SESSION_CLOSED),
46
+ }),
47
+ z.object({
48
+ type: z.literal(MSG_INTERRUPTION_DETECTED),
49
+ created_at: z.number(),
50
+ probabilities: z.array(z.number()).default([]),
51
+ prediction_duration: z.number().default(0),
52
+ }),
53
+ z.object({
54
+ type: z.literal(MSG_INFERENCE_DONE),
55
+ created_at: z.number(),
56
+ probabilities: z.array(z.number()).default([]),
57
+ prediction_duration: z.number().default(0),
58
+ is_bargein: z.boolean().optional(),
59
+ }),
60
+ z.object({
61
+ type: z.literal(MSG_ERROR),
62
+ message: z.string(),
63
+ code: z.number().optional(),
64
+ session_id: z.string().optional(),
65
+ }),
66
+ ]);
67
+
68
+ type WsMessage = z.infer<typeof wsMessageSchema>;
69
+
70
+ /**
71
+ * Creates a WebSocket connection and waits for it to open.
72
+ */
73
+ async function connectWebSocket(options: WsTransportOptions): Promise<WebSocket> {
74
+ const baseUrl = options.baseUrl.replace(/^http/, 'ws');
75
+ const token = await createAccessToken(options.apiKey, options.apiSecret);
76
+ const url = `${baseUrl}/bargein`;
77
+
78
+ const ws = new WebSocket(url, {
79
+ headers: { Authorization: `Bearer ${token}` },
80
+ });
81
+
82
+ await new Promise<void>((resolve, reject) => {
83
+ const timeout = setTimeout(() => {
84
+ ws.terminate();
85
+ reject(new Error('WebSocket connection timeout'));
86
+ }, options.timeout);
87
+ ws.once('open', () => {
88
+ clearTimeout(timeout);
89
+ resolve();
90
+ });
91
+ ws.once('error', (err: Error) => {
92
+ clearTimeout(timeout);
93
+ ws.terminate();
94
+ reject(err);
95
+ });
96
+ });
97
+
98
+ return ws;
99
+ }
100
+
101
+ export interface WsTransportResult {
102
+ transport: TransformStream<Int16Array | OverlappingSpeechEvent, OverlappingSpeechEvent>;
103
+ reconnect: () => Promise<void>;
104
+ }
105
+
106
+ /**
107
+ * Creates a WebSocket transport TransformStream for interruption detection.
108
+ *
109
+ * This transport receives Int16Array audio slices and outputs InterruptionEvents.
110
+ * It maintains a persistent WebSocket connection with automatic retry on failure.
111
+ * Returns both the transport and a reconnect function for option updates.
112
+ */
113
+ export function createWsTransport(
114
+ options: WsTransportOptions,
115
+ getState: () => WsTransportState,
116
+ setState: (partial: Partial<WsTransportState>) => void,
117
+ updateUserSpeakingSpan?: (entry: InterruptionCacheEntry) => void,
118
+ onRequestSent?: () => void,
119
+ getAndResetNumRequests?: () => number,
120
+ ): WsTransportResult {
121
+ const logger = log();
122
+ let ws: WebSocket | null = null;
123
+ let outputController: TransformStreamDefaultController<OverlappingSpeechEvent> | null = null;
124
+
125
+ function setupMessageHandler(socket: WebSocket): void {
126
+ socket.on('message', (data: WebSocket.Data) => {
127
+ try {
128
+ const message = wsMessageSchema.parse(JSON.parse(data.toString()));
129
+ handleMessage(message);
130
+ } catch {
131
+ logger.warn({ data: data.toString() }, 'Failed to parse WebSocket message');
132
+ }
133
+ });
134
+
135
+ socket.on('error', (err: Error) => {
136
+ logger.error({ err }, 'WebSocket error');
137
+ });
138
+
139
+ socket.on('close', (code: number, reason: Buffer) => {
140
+ logger.debug({ code, reason: reason.toString() }, 'WebSocket closed');
141
+ });
142
+ }
143
+
144
+ async function ensureConnection(): Promise<void> {
145
+ if (ws && ws.readyState === WebSocket.OPEN) return;
146
+
147
+ const maxRetries = options.maxRetries ?? 3;
148
+ let lastError: Error | null = null;
149
+
150
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
151
+ try {
152
+ ws = await connectWebSocket(options);
153
+ setupMessageHandler(ws);
154
+
155
+ // Send session.create message
156
+ const sessionCreateMsg = JSON.stringify({
157
+ type: MSG_SESSION_CREATE,
158
+ settings: {
159
+ sample_rate: options.sampleRate,
160
+ num_channels: 1,
161
+ threshold: options.threshold,
162
+ min_frames: options.minFrames,
163
+ encoding: 's16le',
164
+ },
165
+ });
166
+ ws.send(sessionCreateMsg);
167
+ return;
168
+ } catch (err) {
169
+ lastError = err instanceof Error ? err : new Error(String(err));
170
+ if (attempt < maxRetries) {
171
+ const delay = intervalForRetry(attempt);
172
+ logger.debug(
173
+ { attempt, delay, err: lastError.message },
174
+ 'WebSocket connection failed, retrying',
175
+ );
176
+ await new Promise((resolve) => setTimeout(resolve, delay));
177
+ }
178
+ }
179
+ }
180
+
181
+ throw lastError ?? new Error('Failed to connect to WebSocket after retries');
182
+ }
183
+
184
+ function handleMessage(message: WsMessage): void {
185
+ const state = getState();
186
+
187
+ switch (message.type) {
188
+ case MSG_SESSION_CREATED:
189
+ logger.debug('WebSocket session created');
190
+ break;
191
+
192
+ case MSG_INTERRUPTION_DETECTED: {
193
+ const createdAt = message.created_at;
194
+ const overlapSpeechStartedAt = state.overlapSpeechStartedAt;
195
+ if (state.overlapSpeechStarted && overlapSpeechStartedAt !== undefined) {
196
+ const existing = state.cache.get(createdAt);
197
+
198
+ const totalDurationInS =
199
+ existing?.requestStartedAt !== undefined
200
+ ? (performance.now() - existing.requestStartedAt) / 1000
201
+ : (performance.now() - createdAt) / 1000;
202
+
203
+ const entry = state.cache.setOrUpdate(
204
+ createdAt,
205
+ () => new InterruptionCacheEntry({ createdAt }),
206
+ {
207
+ speechInput: existing?.speechInput,
208
+ requestStartedAt: existing?.requestStartedAt,
209
+ totalDurationInS,
210
+ probabilities: message.probabilities,
211
+ isInterruption: true,
212
+ predictionDurationInS: message.prediction_duration,
213
+ detectionDelayInS: (Date.now() - overlapSpeechStartedAt) / 1000,
214
+ },
215
+ );
216
+
217
+ if (updateUserSpeakingSpan) {
218
+ updateUserSpeakingSpan(entry);
219
+ }
220
+
221
+ logger.debug(
222
+ {
223
+ totalDuration: entry.totalDurationInS,
224
+ predictionDuration: entry.predictionDurationInS,
225
+ detectionDelay: entry.detectionDelayInS,
226
+ probability: entry.probability,
227
+ },
228
+ 'interruption detected',
229
+ );
230
+
231
+ const event: OverlappingSpeechEvent = {
232
+ type: 'user_overlapping_speech',
233
+ timestamp: Date.now(),
234
+ isInterruption: true,
235
+ totalDurationInS: entry.totalDurationInS,
236
+ predictionDurationInS: entry.predictionDurationInS,
237
+ overlapStartedAt: overlapSpeechStartedAt,
238
+ speechInput: entry.speechInput,
239
+ probabilities: entry.probabilities,
240
+ detectionDelayInS: entry.detectionDelayInS,
241
+ probability: entry.probability,
242
+ numRequests: getAndResetNumRequests?.() ?? 0,
243
+ };
244
+
245
+ outputController?.enqueue(event);
246
+ setState({ overlapSpeechStarted: false });
247
+ }
248
+ break;
249
+ }
250
+
251
+ case MSG_INFERENCE_DONE: {
252
+ const createdAt = message.created_at;
253
+ const overlapSpeechStartedAt = state.overlapSpeechStartedAt;
254
+ if (state.overlapSpeechStarted && overlapSpeechStartedAt !== undefined) {
255
+ const existing = state.cache.get(createdAt);
256
+ const totalDurationInS =
257
+ existing?.requestStartedAt !== undefined
258
+ ? (performance.now() - existing.requestStartedAt) / 1000
259
+ : (performance.now() - createdAt) / 1000;
260
+ const entry = state.cache.setOrUpdate(
261
+ createdAt,
262
+ () => new InterruptionCacheEntry({ createdAt }),
263
+ {
264
+ speechInput: existing?.speechInput,
265
+ requestStartedAt: existing?.requestStartedAt,
266
+ totalDurationInS,
267
+ predictionDurationInS: message.prediction_duration,
268
+ probabilities: message.probabilities,
269
+ isInterruption: message.is_bargein ?? false,
270
+ detectionDelayInS: (Date.now() - overlapSpeechStartedAt) / 1000,
271
+ },
272
+ );
273
+
274
+ logger.debug(
275
+ {
276
+ totalDurationInS: entry.totalDurationInS,
277
+ predictionDurationInS: entry.predictionDurationInS,
278
+ },
279
+ 'interruption inference done',
280
+ );
281
+ }
282
+ break;
283
+ }
284
+
285
+ case MSG_SESSION_CLOSED:
286
+ logger.debug('WebSocket session closed');
287
+ break;
288
+
289
+ case MSG_ERROR:
290
+ outputController?.error(
291
+ new Error(
292
+ `LiveKit Adaptive Interruption error${
293
+ message.code !== undefined ? ` (${message.code})` : ''
294
+ }: ${message.message}`,
295
+ ),
296
+ );
297
+ break;
298
+ }
299
+ }
300
+
301
+ function sendAudioData(audioSlice: Int16Array): void {
302
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
303
+ throw new Error('WebSocket not connected');
304
+ }
305
+
306
+ const state = getState();
307
+ // Use truncated timestamp consistently for both cache key and header
308
+ // This ensures the server's response created_at matches our cache key
309
+ const createdAt = Math.floor(performance.now());
310
+
311
+ // Store the audio data in cache with truncated timestamp
312
+ state.cache.set(
313
+ createdAt,
314
+ new InterruptionCacheEntry({
315
+ createdAt,
316
+ requestStartedAt: performance.now(),
317
+ speechInput: audioSlice,
318
+ }),
319
+ );
320
+
321
+ // Create header: 8-byte little-endian uint64 timestamp (milliseconds as integer)
322
+ const header = new ArrayBuffer(8);
323
+ const view = new DataView(header);
324
+ view.setUint32(0, createdAt >>> 0, true);
325
+ view.setUint32(4, Math.floor(createdAt / 0x100000000) >>> 0, true);
326
+
327
+ // Combine header and audio data
328
+ const audioBytes = new Uint8Array(
329
+ audioSlice.buffer,
330
+ audioSlice.byteOffset,
331
+ audioSlice.byteLength,
332
+ );
333
+ const combined = new Uint8Array(8 + audioBytes.length);
334
+ combined.set(new Uint8Array(header), 0);
335
+ combined.set(audioBytes, 8);
336
+
337
+ try {
338
+ ws.send(combined);
339
+ onRequestSent?.();
340
+ } catch (e: unknown) {
341
+ logger.error(e, `failed to send audio via websocket`);
342
+ }
343
+ }
344
+
345
+ function close(): void {
346
+ if (ws?.readyState === WebSocket.OPEN) {
347
+ const closeMsg = JSON.stringify({ type: MSG_SESSION_CLOSE });
348
+ try {
349
+ ws.send(closeMsg);
350
+ } catch (e: unknown) {
351
+ logger.error(e, 'failed to send close message');
352
+ }
353
+ }
354
+ ws?.close(1000); // signal normal websocket closure
355
+ ws = null;
356
+ }
357
+
358
+ /**
359
+ * Reconnect the WebSocket with updated options.
360
+ * This is called when options are updated via updateOptions().
361
+ */
362
+ async function reconnect(): Promise<void> {
363
+ close();
364
+ }
365
+
366
+ const transport = new TransformStream<
367
+ Int16Array | OverlappingSpeechEvent,
368
+ OverlappingSpeechEvent
369
+ >(
370
+ {
371
+ async start(controller) {
372
+ outputController = controller;
373
+ await ensureConnection();
374
+ },
375
+
376
+ transform(chunk, controller) {
377
+ if (!(chunk instanceof Int16Array)) {
378
+ controller.enqueue(chunk);
379
+ return;
380
+ }
381
+
382
+ // Only forwards buffered audio while overlap speech is actively on.
383
+ const state = getState();
384
+ if (!state.overlapSpeechStartedAt || !state.overlapSpeechStarted) return;
385
+
386
+ try {
387
+ sendAudioData(chunk);
388
+ } catch (err) {
389
+ logger.error({ err }, 'Failed to send audio data over WebSocket');
390
+ }
391
+ },
392
+
393
+ flush() {
394
+ close();
395
+ },
396
+ },
397
+ { highWaterMark: 2 },
398
+ { highWaterMark: 2 },
399
+ );
400
+
401
+ return { transport, reconnect };
402
+ }
@@ -2,19 +2,12 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import OpenAI from 'openai';
5
- import {
6
- APIConnectionError,
7
- APIStatusError,
8
- APITimeoutError,
9
- DEFAULT_API_CONNECT_OPTIONS,
10
- type Expand,
11
- toError,
12
- } from '../index.js';
5
+ import { APIConnectionError, APIStatusError, APITimeoutError } from '../_exceptions.js';
13
6
  import * as llm from '../llm/index.js';
7
+ import { DEFAULT_API_CONNECT_OPTIONS } from '../types.js';
14
8
  import type { APIConnectOptions } from '../types.js';
15
- import { type AnyString, createAccessToken } from './utils.js';
16
-
17
- const DEFAULT_BASE_URL = 'https://agent-gateway.livekit.cloud/v1';
9
+ import { type Expand, toError } from '../utils.js';
10
+ import { type AnyString, createAccessToken, getDefaultInferenceUrl } from './utils.js';
18
11
 
19
12
  export type OpenAIModels =
20
13
  | 'openai/gpt-5.2'
@@ -127,7 +120,7 @@ export class LLM extends llm.LLM {
127
120
  strictToolSchema = false,
128
121
  } = opts;
129
122
 
130
- const lkBaseURL = baseURL || process.env.LIVEKIT_INFERENCE_URL || DEFAULT_BASE_URL;
123
+ const lkBaseURL = baseURL || getDefaultInferenceUrl();
131
124
  const lkApiKey = apiKey || process.env.LIVEKIT_INFERENCE_API_KEY || process.env.LIVEKIT_API_KEY;
132
125
  if (!lkApiKey) {
133
126
  throw new Error('apiKey is required: pass apiKey or set LIVEKIT_API_KEY');
@@ -163,6 +156,10 @@ export class LLM extends llm.LLM {
163
156
  return this.opts.model;
164
157
  }
165
158
 
159
+ get provider(): string {
160
+ return 'livekit';
161
+ }
162
+
166
163
  static fromModelString(modelString: string): LLM {
167
164
  return new LLM({ model: modelString });
168
165
  }
@@ -22,7 +22,7 @@ import {
22
22
  type SttTranscriptEvent,
23
23
  sttServerEventSchema,
24
24
  } from './api_protos.js';
25
- import { type AnyString, connectWs, createAccessToken } from './utils.js';
25
+ import { type AnyString, connectWs, createAccessToken, getDefaultInferenceUrl } from './utils.js';
26
26
 
27
27
  export type DeepgramModels =
28
28
  | 'deepgram/flux-general'
@@ -151,7 +151,6 @@ export type STTEncoding = 'pcm_s16le';
151
151
 
152
152
  const DEFAULT_ENCODING: STTEncoding = 'pcm_s16le';
153
153
  const DEFAULT_SAMPLE_RATE = 16000;
154
- const DEFAULT_BASE_URL = 'wss://agent-gateway.livekit.cloud/v1';
155
154
  const DEFAULT_CANCEL_TIMEOUT = 5000;
156
155
 
157
156
  export interface InferenceSTTOptions<TModel extends STTModels> {
@@ -203,7 +202,7 @@ export class STT<TModel extends STTModels> extends BaseSTT {
203
202
  connOptions,
204
203
  } = opts || {};
205
204
 
206
- const lkBaseURL = baseURL || process.env.LIVEKIT_INFERENCE_URL || DEFAULT_BASE_URL;
205
+ const lkBaseURL = baseURL || getDefaultInferenceUrl();
207
206
  const lkApiKey = apiKey || process.env.LIVEKIT_INFERENCE_API_KEY || process.env.LIVEKIT_API_KEY;
208
207
  if (!lkApiKey) {
209
208
  throw new Error('apiKey is required: pass apiKey or set LIVEKIT_API_KEY');
@@ -253,6 +252,14 @@ export class STT<TModel extends STTModels> extends BaseSTT {
253
252
  return 'inference.STT';
254
253
  }
255
254
 
255
+ get model(): string {
256
+ return this.opts.model ?? 'auto';
257
+ }
258
+
259
+ get provider(): string {
260
+ return 'livekit';
261
+ }
262
+
256
263
  static fromModelString(modelString: string): STT<AnyString> {
257
264
  const [model, language] = parseSTTModelString(modelString);
258
265
  return new STT({ model, language });
@@ -19,7 +19,7 @@ import {
19
19
  ttsClientEventSchema,
20
20
  ttsServerEventSchema,
21
21
  } from './api_protos.js';
22
- import { type AnyString, connectWs, createAccessToken } from './utils.js';
22
+ import { type AnyString, connectWs, createAccessToken, getDefaultInferenceUrl } from './utils.js';
23
23
 
24
24
  export type CartesiaModels =
25
25
  | 'cartesia/sonic-3'
@@ -136,7 +136,6 @@ type TTSEncoding = 'pcm_s16le';
136
136
 
137
137
  const DEFAULT_ENCODING: TTSEncoding = 'pcm_s16le';
138
138
  const DEFAULT_SAMPLE_RATE = 16000;
139
- const DEFAULT_BASE_URL = 'https://agent-gateway.livekit.cloud/v1';
140
139
  const NUM_CHANNELS = 1;
141
140
  const DEFAULT_LANGUAGE = 'en';
142
141
 
@@ -193,7 +192,7 @@ export class TTS<TModel extends TTSModels> extends BaseTTS {
193
192
  connOptions,
194
193
  } = opts || {};
195
194
 
196
- const lkBaseURL = baseURL || process.env.LIVEKIT_INFERENCE_URL || DEFAULT_BASE_URL;
195
+ const lkBaseURL = baseURL || getDefaultInferenceUrl();
197
196
  const lkApiKey = apiKey || process.env.LIVEKIT_INFERENCE_API_KEY || process.env.LIVEKIT_API_KEY;
198
197
  if (!lkApiKey) {
199
198
  throw new Error('apiKey is required: pass apiKey or set LIVEKIT_API_KEY');
@@ -254,6 +253,14 @@ export class TTS<TModel extends TTSModels> extends BaseTTS {
254
253
  return 'inference.TTS';
255
254
  }
256
255
 
256
+ get model(): string {
257
+ return this.opts.model ?? 'unknown';
258
+ }
259
+
260
+ get provider(): string {
261
+ return 'livekit';
262
+ }
263
+
257
264
  static fromModelString(modelString: string): TTS<AnyString> {
258
265
  const [model, voice] = parseTTSModelString(modelString);
259
266
  return new TTS({ model, voice: voice || undefined });
@@ -3,10 +3,38 @@
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { AccessToken } from 'livekit-server-sdk';
5
5
  import { WebSocket } from 'ws';
6
- import { APIConnectionError, APIStatusError } from '../index.js';
6
+ import { APIConnectionError, APIStatusError } from '../_exceptions.js';
7
7
 
8
8
  export type AnyString = string & NonNullable<unknown>;
9
9
 
10
+ /** Default production inference URL */
11
+ export const DEFAULT_INFERENCE_URL = 'https://agent-gateway.livekit.cloud/v1';
12
+
13
+ /** Staging inference URL */
14
+ export const STAGING_INFERENCE_URL = 'https://agent-gateway.staging.livekit.cloud/v1';
15
+
16
+ /**
17
+ * Get the default inference URL based on the environment.
18
+ *
19
+ * Priority:
20
+ * 1. LIVEKIT_INFERENCE_URL if set
21
+ * 2. If LIVEKIT_URL contains '.staging.livekit.cloud', use staging gateway
22
+ * 3. Otherwise, use production gateway
23
+ */
24
+ export function getDefaultInferenceUrl(): string {
25
+ const inferenceUrl = process.env.LIVEKIT_INFERENCE_URL;
26
+ if (inferenceUrl) {
27
+ return inferenceUrl;
28
+ }
29
+
30
+ const livekitUrl = process.env.LIVEKIT_URL || '';
31
+ if (livekitUrl.includes('.staging.livekit.cloud')) {
32
+ return STAGING_INFERENCE_URL;
33
+ }
34
+
35
+ return DEFAULT_INFERENCE_URL;
36
+ }
37
+
10
38
  export async function createAccessToken(
11
39
  apiKey: string,
12
40
  apiSecret: string,
@@ -2,6 +2,8 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { describe, expect, it } from 'vitest';
5
+ import { initializeLogger } from '../log.js';
6
+ import { FakeLLM } from '../voice/testing/fake_llm.js';
5
7
  import {
6
8
  type AudioContent,
7
9
  ChatContext,
@@ -13,6 +15,8 @@ import {
13
15
  ReadonlyChatContext,
14
16
  } from './chat_context.js';
15
17
 
18
+ initializeLogger({ pretty: false, level: 'error' });
19
+
16
20
  describe('ChatContext.toJSON', () => {
17
21
  it('should match snapshot for empty context', () => {
18
22
  const context = new ChatContext();
@@ -283,6 +287,50 @@ describe('ChatContext.toJSON', () => {
283
287
  });
284
288
  });
285
289
 
290
+ describe('ChatContext._summarize', () => {
291
+ it('keeps chronological timestamps with summary + tail', async () => {
292
+ const ctx = new ChatContext();
293
+ ctx.addMessage({ role: 'system', content: 'System prompt', createdAt: 0 });
294
+ ctx.addMessage({ role: 'user', content: 'hello', createdAt: 1000 });
295
+ ctx.addMessage({ role: 'assistant', content: 'hi there', createdAt: 2000 });
296
+ ctx.insert(
297
+ new FunctionCallOutput({
298
+ callId: 'call_1',
299
+ name: 'lookup',
300
+ output: '{"ok":true}',
301
+ isError: false,
302
+ createdAt: 3500,
303
+ }),
304
+ );
305
+ ctx.addMessage({ role: 'user', content: 'my color is blue', createdAt: 3000 });
306
+ ctx.addMessage({ role: 'assistant', content: 'noted', createdAt: 4000 });
307
+
308
+ const fake = new FakeLLM([
309
+ {
310
+ input: 'Conversation to summarize:\n\nuser: hello\nassistant: hi there',
311
+ content: 'condensed head',
312
+ },
313
+ ]);
314
+
315
+ await ctx._summarize(fake, { keepLastTurns: 1 });
316
+
317
+ const summary = ctx.items.find(
318
+ (item) =>
319
+ item.type === 'message' && item.role === 'assistant' && item.extra?.is_summary === true,
320
+ );
321
+ expect(summary).toBeDefined();
322
+ if (!summary || summary.type !== 'message') {
323
+ throw new Error('summary message is missing');
324
+ }
325
+
326
+ expect(summary.createdAt).toBeCloseTo(2999.999, 6);
327
+
328
+ const createdAts = ctx.items.map((item) => item.createdAt);
329
+ const sorted = [...createdAts].sort((a, b) => a - b);
330
+ expect(createdAts).toEqual(sorted);
331
+ });
332
+ });
333
+
286
334
  describe('ReadonlyChatContext with immutable array', () => {
287
335
  it('should have readonly property set to true', () => {
288
336
  const items: ChatItem[] = [