@livekit/agents 0.7.9 → 1.0.0-next.1

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 (627) hide show
  1. package/dist/_exceptions.cjs +109 -0
  2. package/dist/_exceptions.cjs.map +1 -0
  3. package/dist/_exceptions.d.cts +64 -0
  4. package/dist/_exceptions.d.ts +64 -0
  5. package/dist/_exceptions.d.ts.map +1 -0
  6. package/dist/_exceptions.js +80 -0
  7. package/dist/_exceptions.js.map +1 -0
  8. package/dist/audio.cjs +10 -3
  9. package/dist/audio.cjs.map +1 -1
  10. package/dist/audio.d.cts +2 -0
  11. package/dist/audio.d.ts +2 -0
  12. package/dist/audio.d.ts.map +1 -1
  13. package/dist/audio.js +8 -2
  14. package/dist/audio.js.map +1 -1
  15. package/dist/cli.cjs +25 -0
  16. package/dist/cli.cjs.map +1 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +25 -0
  19. package/dist/cli.js.map +1 -1
  20. package/dist/constants.cjs +6 -3
  21. package/dist/constants.cjs.map +1 -1
  22. package/dist/constants.d.cts +2 -1
  23. package/dist/constants.d.ts +2 -1
  24. package/dist/constants.d.ts.map +1 -1
  25. package/dist/constants.js +4 -2
  26. package/dist/constants.js.map +1 -1
  27. package/dist/http_server.cjs.map +1 -1
  28. package/dist/http_server.d.cts +1 -0
  29. package/dist/http_server.d.ts +1 -0
  30. package/dist/http_server.d.ts.map +1 -1
  31. package/dist/http_server.js.map +1 -1
  32. package/dist/index.cjs +27 -20
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +13 -10
  35. package/dist/index.d.ts +13 -10
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +15 -11
  38. package/dist/index.js.map +1 -1
  39. package/dist/inference_runner.cjs +0 -1
  40. package/dist/inference_runner.cjs.map +1 -1
  41. package/dist/inference_runner.d.cts +2 -3
  42. package/dist/inference_runner.d.ts +2 -3
  43. package/dist/inference_runner.d.ts.map +1 -1
  44. package/dist/inference_runner.js +0 -1
  45. package/dist/inference_runner.js.map +1 -1
  46. package/dist/ipc/inference_proc_executor.cjs +2 -2
  47. package/dist/ipc/inference_proc_executor.cjs.map +1 -1
  48. package/dist/ipc/inference_proc_executor.js +2 -2
  49. package/dist/ipc/inference_proc_executor.js.map +1 -1
  50. package/dist/ipc/job_executor.cjs.map +1 -1
  51. package/dist/ipc/job_executor.js.map +1 -1
  52. package/dist/ipc/job_proc_executor.cjs +1 -0
  53. package/dist/ipc/job_proc_executor.cjs.map +1 -1
  54. package/dist/ipc/job_proc_executor.js +1 -0
  55. package/dist/ipc/job_proc_executor.js.map +1 -1
  56. package/dist/ipc/job_proc_lazy_main.cjs +1 -1
  57. package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
  58. package/dist/ipc/job_proc_lazy_main.js +1 -1
  59. package/dist/ipc/job_proc_lazy_main.js.map +1 -1
  60. package/dist/ipc/supervised_proc.d.cts +1 -1
  61. package/dist/ipc/supervised_proc.d.ts +1 -1
  62. package/dist/ipc/supervised_proc.d.ts.map +1 -1
  63. package/dist/job.cjs +14 -2
  64. package/dist/job.cjs.map +1 -1
  65. package/dist/job.d.cts +8 -0
  66. package/dist/job.d.ts +8 -0
  67. package/dist/job.d.ts.map +1 -1
  68. package/dist/job.js +12 -1
  69. package/dist/job.js.map +1 -1
  70. package/dist/llm/chat_context.cjs +332 -82
  71. package/dist/llm/chat_context.cjs.map +1 -1
  72. package/dist/llm/chat_context.d.cts +152 -48
  73. package/dist/llm/chat_context.d.ts +152 -48
  74. package/dist/llm/chat_context.d.ts.map +1 -1
  75. package/dist/llm/chat_context.js +327 -81
  76. package/dist/llm/chat_context.js.map +1 -1
  77. package/dist/llm/chat_context.test.cjs +380 -0
  78. package/dist/llm/chat_context.test.cjs.map +1 -0
  79. package/dist/llm/chat_context.test.js +385 -0
  80. package/dist/llm/chat_context.test.js.map +1 -0
  81. package/dist/llm/index.cjs +37 -8
  82. package/dist/llm/index.cjs.map +1 -1
  83. package/dist/llm/index.d.cts +7 -3
  84. package/dist/llm/index.d.ts +7 -3
  85. package/dist/llm/index.d.ts.map +1 -1
  86. package/dist/llm/index.js +39 -9
  87. package/dist/llm/index.js.map +1 -1
  88. package/dist/llm/llm.cjs +97 -33
  89. package/dist/llm/llm.cjs.map +1 -1
  90. package/dist/llm/llm.d.cts +50 -24
  91. package/dist/llm/llm.d.ts +50 -24
  92. package/dist/llm/llm.d.ts.map +1 -1
  93. package/dist/llm/llm.js +98 -33
  94. package/dist/llm/llm.js.map +1 -1
  95. package/dist/llm/provider_format/google.cjs +128 -0
  96. package/dist/llm/provider_format/google.cjs.map +1 -0
  97. package/dist/llm/provider_format/google.d.cts +6 -0
  98. package/dist/llm/provider_format/google.d.ts +6 -0
  99. package/dist/llm/provider_format/google.d.ts.map +1 -0
  100. package/dist/llm/provider_format/google.js +104 -0
  101. package/dist/llm/provider_format/google.js.map +1 -0
  102. package/dist/llm/provider_format/google.test.cjs +676 -0
  103. package/dist/llm/provider_format/google.test.cjs.map +1 -0
  104. package/dist/llm/provider_format/google.test.js +675 -0
  105. package/dist/llm/provider_format/google.test.js.map +1 -0
  106. package/dist/llm/provider_format/index.cjs +40 -0
  107. package/dist/llm/provider_format/index.cjs.map +1 -0
  108. package/dist/llm/provider_format/index.d.cts +4 -0
  109. package/dist/llm/provider_format/index.d.ts +4 -0
  110. package/dist/llm/provider_format/index.d.ts.map +1 -0
  111. package/dist/llm/provider_format/index.js +16 -0
  112. package/dist/llm/provider_format/index.js.map +1 -0
  113. package/dist/llm/provider_format/openai.cjs +116 -0
  114. package/dist/llm/provider_format/openai.cjs.map +1 -0
  115. package/dist/llm/provider_format/openai.d.cts +3 -0
  116. package/dist/llm/provider_format/openai.d.ts +3 -0
  117. package/dist/llm/provider_format/openai.d.ts.map +1 -0
  118. package/dist/llm/provider_format/openai.js +92 -0
  119. package/dist/llm/provider_format/openai.js.map +1 -0
  120. package/dist/llm/provider_format/openai.test.cjs +490 -0
  121. package/dist/llm/provider_format/openai.test.cjs.map +1 -0
  122. package/dist/llm/provider_format/openai.test.js +489 -0
  123. package/dist/llm/provider_format/openai.test.js.map +1 -0
  124. package/dist/llm/provider_format/utils.cjs +146 -0
  125. package/dist/llm/provider_format/utils.cjs.map +1 -0
  126. package/dist/llm/provider_format/utils.d.cts +38 -0
  127. package/dist/llm/provider_format/utils.d.ts +38 -0
  128. package/dist/llm/provider_format/utils.d.ts.map +1 -0
  129. package/dist/llm/provider_format/utils.js +122 -0
  130. package/dist/llm/provider_format/utils.js.map +1 -0
  131. package/dist/llm/realtime.cjs +77 -0
  132. package/dist/llm/realtime.cjs.map +1 -0
  133. package/dist/llm/realtime.d.cts +98 -0
  134. package/dist/llm/realtime.d.ts +98 -0
  135. package/dist/llm/realtime.d.ts.map +1 -0
  136. package/dist/llm/realtime.js +52 -0
  137. package/dist/llm/realtime.js.map +1 -0
  138. package/dist/llm/remote_chat_context.cjs +112 -0
  139. package/dist/llm/remote_chat_context.cjs.map +1 -0
  140. package/dist/llm/remote_chat_context.d.cts +23 -0
  141. package/dist/llm/remote_chat_context.d.ts +23 -0
  142. package/dist/llm/remote_chat_context.d.ts.map +1 -0
  143. package/dist/llm/remote_chat_context.js +88 -0
  144. package/dist/llm/remote_chat_context.js.map +1 -0
  145. package/dist/llm/remote_chat_context.test.cjs +225 -0
  146. package/dist/llm/remote_chat_context.test.cjs.map +1 -0
  147. package/dist/llm/remote_chat_context.test.js +224 -0
  148. package/dist/llm/remote_chat_context.test.js.map +1 -0
  149. package/dist/llm/tool_context.cjs +111 -0
  150. package/dist/llm/tool_context.cjs.map +1 -0
  151. package/dist/llm/tool_context.d.cts +125 -0
  152. package/dist/llm/tool_context.d.ts +125 -0
  153. package/dist/llm/tool_context.d.ts.map +1 -0
  154. package/dist/llm/tool_context.js +80 -0
  155. package/dist/llm/tool_context.js.map +1 -0
  156. package/dist/llm/tool_context.test.cjs +162 -0
  157. package/dist/llm/tool_context.test.cjs.map +1 -0
  158. package/dist/llm/tool_context.test.js +161 -0
  159. package/dist/llm/tool_context.test.js.map +1 -0
  160. package/dist/llm/tool_context.type.test.cjs +92 -0
  161. package/dist/llm/tool_context.type.test.cjs.map +1 -0
  162. package/dist/llm/tool_context.type.test.js +91 -0
  163. package/dist/llm/tool_context.type.test.js.map +1 -0
  164. package/dist/llm/utils.cjs +260 -0
  165. package/dist/llm/utils.cjs.map +1 -0
  166. package/dist/llm/utils.d.cts +42 -0
  167. package/dist/llm/utils.d.ts +42 -0
  168. package/dist/llm/utils.d.ts.map +1 -0
  169. package/dist/llm/utils.js +223 -0
  170. package/dist/llm/utils.js.map +1 -0
  171. package/dist/llm/utils.test.cjs +513 -0
  172. package/dist/llm/utils.test.cjs.map +1 -0
  173. package/dist/llm/utils.test.js +490 -0
  174. package/dist/llm/utils.test.js.map +1 -0
  175. package/dist/metrics/base.cjs +0 -27
  176. package/dist/metrics/base.cjs.map +1 -1
  177. package/dist/metrics/base.d.cts +105 -63
  178. package/dist/metrics/base.d.ts +105 -63
  179. package/dist/metrics/base.d.ts.map +1 -1
  180. package/dist/metrics/base.js +0 -19
  181. package/dist/metrics/base.js.map +1 -1
  182. package/dist/metrics/index.cjs +0 -3
  183. package/dist/metrics/index.cjs.map +1 -1
  184. package/dist/metrics/index.d.cts +2 -3
  185. package/dist/metrics/index.d.ts +2 -3
  186. package/dist/metrics/index.d.ts.map +1 -1
  187. package/dist/metrics/index.js +0 -2
  188. package/dist/metrics/index.js.map +1 -1
  189. package/dist/metrics/usage_collector.cjs +17 -12
  190. package/dist/metrics/usage_collector.cjs.map +1 -1
  191. package/dist/metrics/usage_collector.d.cts +3 -2
  192. package/dist/metrics/usage_collector.d.ts +3 -2
  193. package/dist/metrics/usage_collector.d.ts.map +1 -1
  194. package/dist/metrics/usage_collector.js +17 -12
  195. package/dist/metrics/usage_collector.js.map +1 -1
  196. package/dist/metrics/utils.cjs +22 -59
  197. package/dist/metrics/utils.cjs.map +1 -1
  198. package/dist/metrics/utils.d.cts +1 -8
  199. package/dist/metrics/utils.d.ts +1 -8
  200. package/dist/metrics/utils.d.ts.map +1 -1
  201. package/dist/metrics/utils.js +22 -52
  202. package/dist/metrics/utils.js.map +1 -1
  203. package/dist/multimodal/index.cjs +0 -2
  204. package/dist/multimodal/index.cjs.map +1 -1
  205. package/dist/multimodal/index.d.cts +0 -1
  206. package/dist/multimodal/index.d.ts +0 -1
  207. package/dist/multimodal/index.d.ts.map +1 -1
  208. package/dist/multimodal/index.js +0 -1
  209. package/dist/multimodal/index.js.map +1 -1
  210. package/dist/plugin.cjs +24 -8
  211. package/dist/plugin.cjs.map +1 -1
  212. package/dist/plugin.d.cts +18 -4
  213. package/dist/plugin.d.ts +18 -4
  214. package/dist/plugin.d.ts.map +1 -1
  215. package/dist/plugin.js +22 -7
  216. package/dist/plugin.js.map +1 -1
  217. package/dist/stream/deferred_stream.cjs +98 -0
  218. package/dist/stream/deferred_stream.cjs.map +1 -0
  219. package/dist/stream/deferred_stream.d.cts +27 -0
  220. package/dist/stream/deferred_stream.d.ts +27 -0
  221. package/dist/stream/deferred_stream.d.ts.map +1 -0
  222. package/dist/stream/deferred_stream.js +73 -0
  223. package/dist/stream/deferred_stream.js.map +1 -0
  224. package/dist/stream/deferred_stream.test.cjs +527 -0
  225. package/dist/stream/deferred_stream.test.cjs.map +1 -0
  226. package/dist/stream/deferred_stream.test.js +526 -0
  227. package/dist/stream/deferred_stream.test.js.map +1 -0
  228. package/dist/stream/identity_transform.cjs +42 -0
  229. package/dist/stream/identity_transform.cjs.map +1 -0
  230. package/dist/stream/identity_transform.d.cts +6 -0
  231. package/dist/stream/identity_transform.d.ts +6 -0
  232. package/dist/stream/identity_transform.d.ts.map +1 -0
  233. package/dist/stream/identity_transform.js +18 -0
  234. package/dist/stream/identity_transform.js.map +1 -0
  235. package/dist/stream/identity_transform.test.cjs +125 -0
  236. package/dist/stream/identity_transform.test.cjs.map +1 -0
  237. package/dist/stream/identity_transform.test.js +124 -0
  238. package/dist/stream/identity_transform.test.js.map +1 -0
  239. package/dist/stream/index.cjs +38 -0
  240. package/dist/stream/index.cjs.map +1 -0
  241. package/dist/stream/index.d.cts +5 -0
  242. package/dist/stream/index.d.ts +5 -0
  243. package/dist/stream/index.d.ts.map +1 -0
  244. package/dist/stream/index.js +11 -0
  245. package/dist/stream/index.js.map +1 -0
  246. package/dist/stream/merge_readable_streams.cjs +59 -0
  247. package/dist/stream/merge_readable_streams.cjs.map +1 -0
  248. package/dist/stream/merge_readable_streams.d.cts +4 -0
  249. package/dist/stream/merge_readable_streams.d.ts +4 -0
  250. package/dist/stream/merge_readable_streams.d.ts.map +1 -0
  251. package/dist/stream/merge_readable_streams.js +35 -0
  252. package/dist/stream/merge_readable_streams.js.map +1 -0
  253. package/dist/stream/stream_channel.cjs +47 -0
  254. package/dist/stream/stream_channel.cjs.map +1 -0
  255. package/dist/stream/stream_channel.d.cts +9 -0
  256. package/dist/stream/stream_channel.d.ts +9 -0
  257. package/dist/stream/stream_channel.d.ts.map +1 -0
  258. package/dist/stream/stream_channel.js +23 -0
  259. package/dist/stream/stream_channel.js.map +1 -0
  260. package/dist/stream/stream_channel.test.cjs +97 -0
  261. package/dist/stream/stream_channel.test.cjs.map +1 -0
  262. package/dist/stream/stream_channel.test.js +96 -0
  263. package/dist/stream/stream_channel.test.js.map +1 -0
  264. package/dist/stt/stream_adapter.cjs +3 -4
  265. package/dist/stt/stream_adapter.cjs.map +1 -1
  266. package/dist/stt/stream_adapter.d.cts +1 -0
  267. package/dist/stt/stream_adapter.d.ts +1 -0
  268. package/dist/stt/stream_adapter.d.ts.map +1 -1
  269. package/dist/stt/stream_adapter.js +3 -4
  270. package/dist/stt/stream_adapter.js.map +1 -1
  271. package/dist/stt/stt.cjs +100 -10
  272. package/dist/stt/stt.cjs.map +1 -1
  273. package/dist/stt/stt.d.cts +26 -5
  274. package/dist/stt/stt.d.ts +26 -5
  275. package/dist/stt/stt.d.ts.map +1 -1
  276. package/dist/stt/stt.js +101 -11
  277. package/dist/stt/stt.js.map +1 -1
  278. package/dist/tokenize/basic/basic.cjs +10 -5
  279. package/dist/tokenize/basic/basic.cjs.map +1 -1
  280. package/dist/tokenize/basic/basic.d.cts +7 -1
  281. package/dist/tokenize/basic/basic.d.ts +7 -1
  282. package/dist/tokenize/basic/basic.d.ts.map +1 -1
  283. package/dist/tokenize/basic/basic.js +10 -5
  284. package/dist/tokenize/basic/basic.js.map +1 -1
  285. package/dist/tokenize/basic/sentence.cjs +14 -6
  286. package/dist/tokenize/basic/sentence.cjs.map +1 -1
  287. package/dist/tokenize/basic/sentence.d.cts +1 -1
  288. package/dist/tokenize/basic/sentence.d.ts +1 -1
  289. package/dist/tokenize/basic/sentence.d.ts.map +1 -1
  290. package/dist/tokenize/basic/sentence.js +14 -6
  291. package/dist/tokenize/basic/sentence.js.map +1 -1
  292. package/dist/tokenize/token_stream.cjs +5 -3
  293. package/dist/tokenize/token_stream.cjs.map +1 -1
  294. package/dist/tokenize/token_stream.d.cts +1 -0
  295. package/dist/tokenize/token_stream.d.ts +1 -0
  296. package/dist/tokenize/token_stream.d.ts.map +1 -1
  297. package/dist/tokenize/token_stream.js +6 -4
  298. package/dist/tokenize/token_stream.js.map +1 -1
  299. package/dist/transcription.cjs +1 -2
  300. package/dist/transcription.cjs.map +1 -1
  301. package/dist/transcription.d.ts.map +1 -1
  302. package/dist/transcription.js +2 -3
  303. package/dist/transcription.js.map +1 -1
  304. package/dist/tts/index.cjs +2 -4
  305. package/dist/tts/index.cjs.map +1 -1
  306. package/dist/tts/index.d.cts +1 -1
  307. package/dist/tts/index.d.ts +1 -1
  308. package/dist/tts/index.d.ts.map +1 -1
  309. package/dist/tts/index.js +1 -3
  310. package/dist/tts/index.js.map +1 -1
  311. package/dist/tts/stream_adapter.cjs +26 -13
  312. package/dist/tts/stream_adapter.cjs.map +1 -1
  313. package/dist/tts/stream_adapter.d.cts +1 -1
  314. package/dist/tts/stream_adapter.d.ts +1 -1
  315. package/dist/tts/stream_adapter.d.ts.map +1 -1
  316. package/dist/tts/stream_adapter.js +27 -14
  317. package/dist/tts/stream_adapter.js.map +1 -1
  318. package/dist/tts/tts.cjs +156 -25
  319. package/dist/tts/tts.cjs.map +1 -1
  320. package/dist/tts/tts.d.cts +29 -5
  321. package/dist/tts/tts.d.ts +29 -5
  322. package/dist/tts/tts.d.ts.map +1 -1
  323. package/dist/tts/tts.js +156 -24
  324. package/dist/tts/tts.js.map +1 -1
  325. package/dist/types.cjs +60 -0
  326. package/dist/types.cjs.map +1 -0
  327. package/dist/types.d.cts +13 -0
  328. package/dist/types.d.ts +13 -0
  329. package/dist/types.d.ts.map +1 -0
  330. package/dist/types.js +35 -0
  331. package/dist/types.js.map +1 -0
  332. package/dist/utils.cjs +298 -27
  333. package/dist/utils.cjs.map +1 -1
  334. package/dist/utils.d.cts +145 -9
  335. package/dist/utils.d.ts +145 -9
  336. package/dist/utils.d.ts.map +1 -1
  337. package/dist/utils.js +281 -26
  338. package/dist/utils.js.map +1 -1
  339. package/dist/utils.test.cjs +491 -0
  340. package/dist/utils.test.cjs.map +1 -0
  341. package/dist/utils.test.js +498 -0
  342. package/dist/utils.test.js.map +1 -0
  343. package/dist/vad.cjs +76 -20
  344. package/dist/vad.cjs.map +1 -1
  345. package/dist/vad.d.cts +25 -5
  346. package/dist/vad.d.ts +25 -5
  347. package/dist/vad.d.ts.map +1 -1
  348. package/dist/vad.js +76 -20
  349. package/dist/vad.js.map +1 -1
  350. package/dist/voice/agent.cjs +245 -0
  351. package/dist/voice/agent.cjs.map +1 -0
  352. package/dist/voice/agent.d.cts +78 -0
  353. package/dist/voice/agent.d.ts +78 -0
  354. package/dist/voice/agent.d.ts.map +1 -0
  355. package/dist/voice/agent.js +220 -0
  356. package/dist/voice/agent.js.map +1 -0
  357. package/dist/voice/agent.test.cjs +61 -0
  358. package/dist/voice/agent.test.cjs.map +1 -0
  359. package/dist/voice/agent.test.js +60 -0
  360. package/dist/voice/agent.test.js.map +1 -0
  361. package/dist/voice/agent_activity.cjs +1453 -0
  362. package/dist/voice/agent_activity.cjs.map +1 -0
  363. package/dist/voice/agent_activity.d.cts +94 -0
  364. package/dist/voice/agent_activity.d.ts +94 -0
  365. package/dist/voice/agent_activity.d.ts.map +1 -0
  366. package/dist/voice/agent_activity.js +1449 -0
  367. package/dist/voice/agent_activity.js.map +1 -0
  368. package/dist/voice/agent_session.cjs +312 -0
  369. package/dist/voice/agent_session.cjs.map +1 -0
  370. package/dist/voice/agent_session.d.cts +121 -0
  371. package/dist/voice/agent_session.d.ts +121 -0
  372. package/dist/voice/agent_session.d.ts.map +1 -0
  373. package/dist/voice/agent_session.js +295 -0
  374. package/dist/voice/agent_session.js.map +1 -0
  375. package/dist/voice/audio_recognition.cjs +374 -0
  376. package/dist/voice/audio_recognition.cjs.map +1 -0
  377. package/dist/voice/audio_recognition.d.cts +80 -0
  378. package/dist/voice/audio_recognition.d.ts +80 -0
  379. package/dist/voice/audio_recognition.d.ts.map +1 -0
  380. package/dist/voice/audio_recognition.js +350 -0
  381. package/dist/voice/audio_recognition.js.map +1 -0
  382. package/dist/voice/events.cjs +145 -0
  383. package/dist/voice/events.cjs.map +1 -0
  384. package/dist/voice/events.d.cts +124 -0
  385. package/dist/voice/events.d.ts +124 -0
  386. package/dist/voice/events.d.ts.map +1 -0
  387. package/dist/voice/events.js +110 -0
  388. package/dist/voice/events.js.map +1 -0
  389. package/dist/voice/generation.cjs +700 -0
  390. package/dist/voice/generation.cjs.map +1 -0
  391. package/dist/voice/generation.d.cts +115 -0
  392. package/dist/voice/generation.d.ts +115 -0
  393. package/dist/voice/generation.d.ts.map +1 -0
  394. package/dist/voice/generation.js +672 -0
  395. package/dist/voice/generation.js.map +1 -0
  396. package/dist/voice/index.cjs +40 -0
  397. package/dist/voice/index.cjs.map +1 -0
  398. package/dist/voice/index.d.cts +5 -0
  399. package/dist/voice/index.d.ts +5 -0
  400. package/dist/voice/index.d.ts.map +1 -0
  401. package/dist/voice/index.js +11 -0
  402. package/dist/voice/index.js.map +1 -0
  403. package/dist/voice/io.cjs +245 -0
  404. package/dist/voice/io.cjs.map +1 -0
  405. package/dist/voice/io.d.cts +101 -0
  406. package/dist/voice/io.d.ts +101 -0
  407. package/dist/voice/io.d.ts.map +1 -0
  408. package/dist/voice/io.js +217 -0
  409. package/dist/voice/io.js.map +1 -0
  410. package/dist/voice/room_io/_input.cjs +121 -0
  411. package/dist/voice/room_io/_input.cjs.map +1 -0
  412. package/dist/voice/room_io/_input.d.cts +24 -0
  413. package/dist/voice/room_io/_input.d.ts +24 -0
  414. package/dist/voice/room_io/_input.d.ts.map +1 -0
  415. package/dist/voice/room_io/_input.js +102 -0
  416. package/dist/voice/room_io/_input.js.map +1 -0
  417. package/dist/voice/room_io/_output.cjs +358 -0
  418. package/dist/voice/room_io/_output.cjs.map +1 -0
  419. package/dist/voice/room_io/_output.d.cts +75 -0
  420. package/dist/voice/room_io/_output.d.ts +75 -0
  421. package/dist/voice/room_io/_output.d.ts.map +1 -0
  422. package/dist/voice/room_io/_output.js +342 -0
  423. package/dist/voice/room_io/_output.js.map +1 -0
  424. package/dist/voice/room_io/index.cjs +25 -0
  425. package/dist/voice/room_io/index.cjs.map +1 -0
  426. package/dist/voice/room_io/index.d.cts +3 -0
  427. package/dist/voice/room_io/index.d.ts +3 -0
  428. package/dist/voice/room_io/index.d.ts.map +1 -0
  429. package/dist/voice/room_io/index.js +3 -0
  430. package/dist/voice/room_io/index.js.map +1 -0
  431. package/dist/voice/room_io/room_io.cjs +370 -0
  432. package/dist/voice/room_io/room_io.cjs.map +1 -0
  433. package/dist/voice/room_io/room_io.d.cts +73 -0
  434. package/dist/voice/room_io/room_io.d.ts +73 -0
  435. package/dist/voice/room_io/room_io.d.ts.map +1 -0
  436. package/dist/voice/room_io/room_io.js +361 -0
  437. package/dist/voice/room_io/room_io.js.map +1 -0
  438. package/dist/{pipeline/index.cjs → voice/run_context.cjs} +16 -11
  439. package/dist/voice/run_context.cjs.map +1 -0
  440. package/dist/voice/run_context.d.cts +12 -0
  441. package/dist/voice/run_context.d.ts +12 -0
  442. package/dist/voice/run_context.d.ts.map +1 -0
  443. package/dist/voice/run_context.js +14 -0
  444. package/dist/voice/run_context.js.map +1 -0
  445. package/dist/voice/speech_handle.cjs +105 -0
  446. package/dist/voice/speech_handle.cjs.map +1 -0
  447. package/dist/voice/speech_handle.d.cts +46 -0
  448. package/dist/voice/speech_handle.d.ts +46 -0
  449. package/dist/voice/speech_handle.d.ts.map +1 -0
  450. package/dist/voice/speech_handle.js +81 -0
  451. package/dist/voice/speech_handle.js.map +1 -0
  452. package/dist/voice/transcription/_utils.cjs +45 -0
  453. package/dist/voice/transcription/_utils.cjs.map +1 -0
  454. package/dist/voice/transcription/_utils.d.cts +3 -0
  455. package/dist/voice/transcription/_utils.d.ts +3 -0
  456. package/dist/voice/transcription/_utils.d.ts.map +1 -0
  457. package/dist/voice/transcription/_utils.js +21 -0
  458. package/dist/voice/transcription/_utils.js.map +1 -0
  459. package/dist/voice/transcription/index.cjs +23 -0
  460. package/dist/voice/transcription/index.cjs.map +1 -0
  461. package/dist/voice/transcription/index.d.cts +2 -0
  462. package/dist/voice/transcription/index.d.ts +2 -0
  463. package/dist/voice/transcription/index.d.ts.map +1 -0
  464. package/dist/voice/transcription/index.js +2 -0
  465. package/dist/voice/transcription/index.js.map +1 -0
  466. package/dist/voice/transcription/synchronizer.cjs +379 -0
  467. package/dist/voice/transcription/synchronizer.cjs.map +1 -0
  468. package/dist/voice/transcription/synchronizer.d.cts +86 -0
  469. package/dist/voice/transcription/synchronizer.d.ts +86 -0
  470. package/dist/voice/transcription/synchronizer.d.ts.map +1 -0
  471. package/dist/voice/transcription/synchronizer.js +354 -0
  472. package/dist/voice/transcription/synchronizer.js.map +1 -0
  473. package/dist/worker.cjs +22 -4
  474. package/dist/worker.cjs.map +1 -1
  475. package/dist/worker.d.cts +1 -1
  476. package/dist/worker.d.ts +1 -1
  477. package/dist/worker.d.ts.map +1 -1
  478. package/dist/worker.js +22 -4
  479. package/dist/worker.js.map +1 -1
  480. package/package.json +8 -2
  481. package/src/_exceptions.ts +137 -0
  482. package/src/audio.ts +12 -1
  483. package/src/cli.ts +37 -0
  484. package/src/constants.ts +2 -1
  485. package/src/http_server.ts +1 -0
  486. package/src/index.ts +13 -10
  487. package/src/inference_runner.ts +2 -3
  488. package/src/ipc/inference_proc_executor.ts +2 -2
  489. package/src/ipc/job_executor.ts +1 -1
  490. package/src/ipc/job_proc_executor.ts +1 -1
  491. package/src/ipc/job_proc_lazy_main.ts +1 -1
  492. package/src/job.ts +18 -0
  493. package/src/llm/__snapshots__/chat_context.test.ts.snap +527 -0
  494. package/src/llm/__snapshots__/tool_context.test.ts.snap +177 -0
  495. package/src/llm/__snapshots__/utils.test.ts.snap +65 -0
  496. package/src/llm/chat_context.test.ts +450 -0
  497. package/src/llm/chat_context.ts +501 -103
  498. package/src/llm/index.ts +53 -18
  499. package/src/llm/llm.ts +148 -50
  500. package/src/llm/provider_format/google.test.ts +772 -0
  501. package/src/llm/provider_format/google.ts +130 -0
  502. package/src/llm/provider_format/index.ts +23 -0
  503. package/src/llm/provider_format/openai.test.ts +581 -0
  504. package/src/llm/provider_format/openai.ts +118 -0
  505. package/src/llm/provider_format/utils.ts +183 -0
  506. package/src/llm/realtime.ts +151 -0
  507. package/src/llm/remote_chat_context.test.ts +290 -0
  508. package/src/llm/remote_chat_context.ts +114 -0
  509. package/src/llm/tool_context.test.ts +198 -0
  510. package/src/llm/tool_context.ts +259 -0
  511. package/src/llm/tool_context.type.test.ts +115 -0
  512. package/src/llm/utils.test.ts +670 -0
  513. package/src/llm/utils.ts +324 -0
  514. package/src/metrics/base.ts +110 -78
  515. package/src/metrics/index.ts +3 -9
  516. package/src/metrics/usage_collector.ts +19 -13
  517. package/src/metrics/utils.ts +24 -69
  518. package/src/multimodal/index.ts +0 -1
  519. package/src/plugin.ts +26 -8
  520. package/src/stream/deferred_stream.test.ts +755 -0
  521. package/src/stream/deferred_stream.ts +110 -0
  522. package/src/stream/identity_transform.test.ts +179 -0
  523. package/src/stream/identity_transform.ts +18 -0
  524. package/src/stream/index.ts +7 -0
  525. package/src/stream/merge_readable_streams.ts +40 -0
  526. package/src/stream/stream_channel.test.ts +129 -0
  527. package/src/stream/stream_channel.ts +32 -0
  528. package/src/stt/stream_adapter.ts +3 -5
  529. package/src/stt/stt.ts +134 -17
  530. package/src/tokenize/basic/basic.ts +13 -5
  531. package/src/tokenize/basic/sentence.ts +20 -6
  532. package/src/tokenize/token_stream.ts +7 -4
  533. package/src/transcription.ts +2 -3
  534. package/src/tts/index.ts +0 -1
  535. package/src/tts/stream_adapter.ts +42 -16
  536. package/src/tts/tts.ts +202 -21
  537. package/src/types.ts +42 -0
  538. package/src/utils.test.ts +658 -0
  539. package/src/utils.ts +402 -44
  540. package/src/vad.ts +90 -22
  541. package/src/voice/agent.test.ts +80 -0
  542. package/src/voice/agent.ts +332 -0
  543. package/src/voice/agent_activity.ts +1913 -0
  544. package/src/voice/agent_session.ts +460 -0
  545. package/src/voice/audio_recognition.ts +473 -0
  546. package/src/voice/events.ts +252 -0
  547. package/src/voice/generation.ts +881 -0
  548. package/src/voice/index.ts +7 -0
  549. package/src/voice/io.ts +304 -0
  550. package/src/voice/room_io/_input.ts +144 -0
  551. package/src/voice/room_io/_output.ts +436 -0
  552. package/src/voice/room_io/index.ts +5 -0
  553. package/src/voice/room_io/room_io.ts +495 -0
  554. package/src/voice/run_context.ts +20 -0
  555. package/src/voice/speech_handle.ts +104 -0
  556. package/src/voice/transcription/_utils.ts +25 -0
  557. package/src/voice/transcription/index.ts +4 -0
  558. package/src/voice/transcription/synchronizer.ts +477 -0
  559. package/src/worker.ts +22 -2
  560. package/dist/llm/function_context.cjs +0 -103
  561. package/dist/llm/function_context.cjs.map +0 -1
  562. package/dist/llm/function_context.d.cts +0 -47
  563. package/dist/llm/function_context.d.ts +0 -47
  564. package/dist/llm/function_context.d.ts.map +0 -1
  565. package/dist/llm/function_context.js +0 -78
  566. package/dist/llm/function_context.js.map +0 -1
  567. package/dist/llm/function_context.test.cjs +0 -218
  568. package/dist/llm/function_context.test.cjs.map +0 -1
  569. package/dist/llm/function_context.test.js +0 -217
  570. package/dist/llm/function_context.test.js.map +0 -1
  571. package/dist/multimodal/multimodal_agent.cjs +0 -486
  572. package/dist/multimodal/multimodal_agent.cjs.map +0 -1
  573. package/dist/multimodal/multimodal_agent.d.cts +0 -48
  574. package/dist/multimodal/multimodal_agent.d.ts +0 -48
  575. package/dist/multimodal/multimodal_agent.d.ts.map +0 -1
  576. package/dist/multimodal/multimodal_agent.js +0 -461
  577. package/dist/multimodal/multimodal_agent.js.map +0 -1
  578. package/dist/pipeline/agent_output.cjs +0 -197
  579. package/dist/pipeline/agent_output.cjs.map +0 -1
  580. package/dist/pipeline/agent_output.d.cts +0 -33
  581. package/dist/pipeline/agent_output.d.ts +0 -33
  582. package/dist/pipeline/agent_output.d.ts.map +0 -1
  583. package/dist/pipeline/agent_output.js +0 -172
  584. package/dist/pipeline/agent_output.js.map +0 -1
  585. package/dist/pipeline/agent_playout.cjs +0 -175
  586. package/dist/pipeline/agent_playout.cjs.map +0 -1
  587. package/dist/pipeline/agent_playout.d.cts +0 -40
  588. package/dist/pipeline/agent_playout.d.ts +0 -40
  589. package/dist/pipeline/agent_playout.d.ts.map +0 -1
  590. package/dist/pipeline/agent_playout.js +0 -139
  591. package/dist/pipeline/agent_playout.js.map +0 -1
  592. package/dist/pipeline/human_input.cjs +0 -171
  593. package/dist/pipeline/human_input.cjs.map +0 -1
  594. package/dist/pipeline/human_input.d.cts +0 -30
  595. package/dist/pipeline/human_input.d.ts +0 -30
  596. package/dist/pipeline/human_input.d.ts.map +0 -1
  597. package/dist/pipeline/human_input.js +0 -146
  598. package/dist/pipeline/human_input.js.map +0 -1
  599. package/dist/pipeline/index.cjs.map +0 -1
  600. package/dist/pipeline/index.d.cts +0 -2
  601. package/dist/pipeline/index.d.ts +0 -2
  602. package/dist/pipeline/index.d.ts.map +0 -1
  603. package/dist/pipeline/index.js +0 -11
  604. package/dist/pipeline/index.js.map +0 -1
  605. package/dist/pipeline/pipeline_agent.cjs +0 -859
  606. package/dist/pipeline/pipeline_agent.cjs.map +0 -1
  607. package/dist/pipeline/pipeline_agent.d.cts +0 -150
  608. package/dist/pipeline/pipeline_agent.d.ts +0 -150
  609. package/dist/pipeline/pipeline_agent.d.ts.map +0 -1
  610. package/dist/pipeline/pipeline_agent.js +0 -837
  611. package/dist/pipeline/pipeline_agent.js.map +0 -1
  612. package/dist/pipeline/speech_handle.cjs +0 -176
  613. package/dist/pipeline/speech_handle.cjs.map +0 -1
  614. package/dist/pipeline/speech_handle.d.cts +0 -37
  615. package/dist/pipeline/speech_handle.d.ts +0 -37
  616. package/dist/pipeline/speech_handle.d.ts.map +0 -1
  617. package/dist/pipeline/speech_handle.js +0 -152
  618. package/dist/pipeline/speech_handle.js.map +0 -1
  619. package/src/llm/function_context.test.ts +0 -248
  620. package/src/llm/function_context.ts +0 -142
  621. package/src/multimodal/multimodal_agent.ts +0 -592
  622. package/src/pipeline/agent_output.ts +0 -219
  623. package/src/pipeline/agent_playout.ts +0 -192
  624. package/src/pipeline/human_input.ts +0 -188
  625. package/src/pipeline/index.ts +0 -15
  626. package/src/pipeline/pipeline_agent.ts +0 -1197
  627. package/src/pipeline/speech_handle.ts +0 -201
@@ -0,0 +1,881 @@
1
+ // SPDX-FileCopyrightText: 2025 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import type { AudioFrame } from '@livekit/rtc-node';
5
+ import { AudioResampler } from '@livekit/rtc-node';
6
+ import type { ReadableStream, ReadableStreamDefaultReader } from 'stream/web';
7
+ import { ZodObject } from 'zod';
8
+ import {
9
+ type ChatContext,
10
+ ChatMessage,
11
+ FunctionCall,
12
+ FunctionCallOutput,
13
+ } from '../llm/chat_context.js';
14
+ import type { ChatChunk } from '../llm/llm.js';
15
+ import {
16
+ type ToolChoice,
17
+ type ToolContext,
18
+ isAgentHandoff,
19
+ isFunctionTool,
20
+ isToolError,
21
+ } from '../llm/tool_context.js';
22
+ import { log } from '../log.js';
23
+ import { IdentityTransform } from '../stream/identity_transform.js';
24
+ import { Future, Task, shortuuid, toError } from '../utils.js';
25
+ import { type Agent, type ModelSettings, asyncLocalStorage, isStopResponse } from './agent.js';
26
+ import type { AgentSession } from './agent_session.js';
27
+ import type { AudioOutput, LLMNode, TTSNode, TextOutput } from './io.js';
28
+ import { RunContext } from './run_context.js';
29
+ import type { SpeechHandle } from './speech_handle.js';
30
+
31
+ /* @internal */
32
+ export class _LLMGenerationData {
33
+ generatedText: string = '';
34
+ generatedToolCalls: FunctionCall[];
35
+ id: string;
36
+
37
+ constructor(
38
+ public readonly textStream: ReadableStream<string>,
39
+ public readonly toolCallStream: ReadableStream<FunctionCall>,
40
+ ) {
41
+ this.id = shortuuid('item_');
42
+ this.generatedToolCalls = [];
43
+ }
44
+ }
45
+
46
+ // TODO(brian): remove this class in favor of ToolOutput
47
+ export class _ToolOutput {
48
+ output: _JsOutput[];
49
+ firstToolFut: Future;
50
+
51
+ constructor() {
52
+ this.output = [];
53
+ this.firstToolFut = new Future();
54
+ }
55
+ }
56
+
57
+ // TODO(brian): remove this class in favor of ToolExecutionOutput
58
+ export class _SanitizedOutput {
59
+ toolCall: FunctionCall;
60
+ toolCallOutput?: FunctionCallOutput;
61
+ replyRequired: boolean;
62
+ agentTask?: Agent;
63
+
64
+ constructor(
65
+ toolCall: FunctionCall,
66
+ toolCallOutput: FunctionCallOutput | undefined,
67
+ replyRequired: boolean,
68
+ agentTask: Agent | undefined,
69
+ ) {
70
+ this.toolCall = toolCall;
71
+ this.toolCallOutput = toolCallOutput;
72
+ this.replyRequired = replyRequired;
73
+ this.agentTask = agentTask;
74
+ }
75
+
76
+ static create(params: {
77
+ toolCall: FunctionCall;
78
+ toolCallOutput?: FunctionCallOutput;
79
+ replyRequired?: boolean;
80
+ agentTask?: Agent;
81
+ }) {
82
+ const { toolCall, toolCallOutput, replyRequired = true, agentTask } = params;
83
+ return new _SanitizedOutput(toolCall, toolCallOutput, replyRequired, agentTask);
84
+ }
85
+ }
86
+
87
+ function isValidToolOutput(toolOutput: unknown): boolean {
88
+ const validTypes = ['string', 'number', 'boolean'];
89
+
90
+ if (validTypes.includes(typeof toolOutput)) {
91
+ return true;
92
+ }
93
+
94
+ if (toolOutput === undefined || toolOutput === null) {
95
+ return true;
96
+ }
97
+
98
+ if (Array.isArray(toolOutput)) {
99
+ return toolOutput.every(isValidToolOutput);
100
+ }
101
+
102
+ if (toolOutput instanceof Set) {
103
+ return Array.from(toolOutput).every(isValidToolOutput);
104
+ }
105
+
106
+ if (toolOutput instanceof Map) {
107
+ return Array.from(toolOutput.values()).every(isValidToolOutput);
108
+ }
109
+
110
+ if (toolOutput instanceof Object) {
111
+ return Object.entries(toolOutput).every(
112
+ ([key, value]) => validTypes.includes(typeof key) && isValidToolOutput(value),
113
+ );
114
+ }
115
+
116
+ return false;
117
+ }
118
+
119
+ export class ToolExecutionOutput {
120
+ constructor(
121
+ public readonly toolCall: FunctionCall,
122
+ public readonly toolCallOutput: FunctionCallOutput | undefined,
123
+ public readonly agentTask: Agent | undefined,
124
+ public readonly rawOutput: unknown,
125
+ public readonly rawException: Error | undefined,
126
+ public readonly replyRequired: boolean,
127
+ ) {}
128
+
129
+ static create(params: {
130
+ toolCall: FunctionCall;
131
+ toolCallOutput?: FunctionCallOutput;
132
+ agentTask?: Agent;
133
+ rawOutput: unknown;
134
+ rawException?: Error;
135
+ replyRequired?: boolean;
136
+ }) {
137
+ const {
138
+ toolCall,
139
+ toolCallOutput,
140
+ agentTask,
141
+ rawOutput,
142
+ rawException,
143
+ replyRequired = true,
144
+ } = params;
145
+ return new ToolExecutionOutput(
146
+ toolCall,
147
+ toolCallOutput,
148
+ agentTask,
149
+ rawOutput,
150
+ rawException,
151
+ replyRequired,
152
+ );
153
+ }
154
+ }
155
+
156
+ export interface ToolOutput {
157
+ output: ToolExecutionOutput[];
158
+ firstToolStartedFuture: Future<void>;
159
+ }
160
+
161
+ // TODO(brian): remove this class in favor of ToolExecutionOutput
162
+ export class _JsOutput {
163
+ toolCall: FunctionCall;
164
+ output: unknown;
165
+ exception?: Error;
166
+
167
+ #logger = log();
168
+
169
+ constructor(toolCall: FunctionCall, output: unknown, exception: Error | undefined) {
170
+ this.toolCall = toolCall;
171
+ this.output = output;
172
+ this.exception = exception;
173
+ }
174
+
175
+ static create(params: { toolCall: FunctionCall; output?: unknown; exception?: Error }) {
176
+ const { toolCall, output = undefined, exception = undefined } = params;
177
+ return new _JsOutput(toolCall, output, exception);
178
+ }
179
+
180
+ sanitize(): _SanitizedOutput {
181
+ if (isToolError(this.exception)) {
182
+ return _SanitizedOutput.create({
183
+ toolCall: FunctionCall.create({ ...this.toolCall }),
184
+ toolCallOutput: FunctionCallOutput.create({
185
+ name: this.toolCall.name,
186
+ callId: this.toolCall.callId,
187
+ output: this.exception.message,
188
+ isError: true,
189
+ }),
190
+ });
191
+ }
192
+
193
+ if (isStopResponse(this.exception)) {
194
+ return _SanitizedOutput.create({
195
+ toolCall: FunctionCall.create({ ...this.toolCall }),
196
+ });
197
+ }
198
+
199
+ if (this.exception !== undefined) {
200
+ return _SanitizedOutput.create({
201
+ toolCall: FunctionCall.create({ ...this.toolCall }),
202
+ toolCallOutput: FunctionCallOutput.create({
203
+ name: this.toolCall.name,
204
+ callId: this.toolCall.callId,
205
+ output: 'An internal error occurred while executing the tool.', // Don't send the actual error message, as it may contain sensitive information
206
+ isError: true,
207
+ }),
208
+ });
209
+ }
210
+
211
+ let agentTask: Agent | undefined = undefined;
212
+ let toolOutput: unknown = this.output;
213
+ if (isAgentHandoff(this.output)) {
214
+ agentTask = this.output.agent;
215
+ toolOutput = this.output.returns;
216
+ }
217
+
218
+ if (!isValidToolOutput(toolOutput)) {
219
+ this.#logger.error(
220
+ {
221
+ callId: this.toolCall.callId,
222
+ function: this.toolCall.name,
223
+ },
224
+ `AI function ${this.toolCall.name} returned an invalid output`,
225
+ );
226
+ return _SanitizedOutput.create({
227
+ toolCall: FunctionCall.create({ ...this.toolCall }),
228
+ toolCallOutput: undefined,
229
+ });
230
+ }
231
+
232
+ return _SanitizedOutput.create({
233
+ toolCall: FunctionCall.create({ ...this.toolCall }),
234
+ toolCallOutput: FunctionCallOutput.create({
235
+ name: this.toolCall.name,
236
+ callId: this.toolCall.callId,
237
+ output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output
238
+ isError: false,
239
+ }),
240
+ replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output
241
+ agentTask,
242
+ });
243
+ }
244
+ }
245
+
246
+ export function createToolOutput(params: {
247
+ toolCall: FunctionCall;
248
+ output?: unknown;
249
+ exception?: Error;
250
+ }): ToolExecutionOutput {
251
+ const { toolCall, output, exception } = params;
252
+ const logger = log();
253
+
254
+ // support returning Exception instead of raising them (for devex purposes inside evals)
255
+ let finalOutput = output;
256
+ let finalException = exception;
257
+ if (output instanceof Error) {
258
+ finalException = output;
259
+ finalOutput = undefined;
260
+ }
261
+
262
+ if (isToolError(finalException)) {
263
+ return ToolExecutionOutput.create({
264
+ toolCall: FunctionCall.create({ ...toolCall }),
265
+ toolCallOutput: FunctionCallOutput.create({
266
+ name: toolCall.name,
267
+ callId: toolCall.callId,
268
+ output: finalException.message,
269
+ isError: true,
270
+ }),
271
+ rawOutput: finalOutput,
272
+ rawException: finalException,
273
+ });
274
+ }
275
+
276
+ if (isStopResponse(finalException)) {
277
+ return ToolExecutionOutput.create({
278
+ toolCall: FunctionCall.create({ ...toolCall }),
279
+ rawOutput: finalOutput,
280
+ rawException: finalException,
281
+ });
282
+ }
283
+
284
+ if (finalException !== undefined) {
285
+ return ToolExecutionOutput.create({
286
+ toolCall: FunctionCall.create({ ...toolCall }),
287
+ toolCallOutput: FunctionCallOutput.create({
288
+ name: toolCall.name,
289
+ callId: toolCall.callId,
290
+ output: 'An internal error occurred', // Don't send the actual error message, as it may contain sensitive information
291
+ isError: true,
292
+ }),
293
+ rawOutput: finalOutput,
294
+ rawException: finalException,
295
+ });
296
+ }
297
+
298
+ let agentTask: Agent | undefined = undefined;
299
+ let toolOutput: unknown = finalOutput;
300
+ if (isAgentHandoff(finalOutput)) {
301
+ agentTask = finalOutput.agent;
302
+ toolOutput = finalOutput.returns;
303
+ }
304
+
305
+ if (!isValidToolOutput(toolOutput)) {
306
+ logger.error(
307
+ {
308
+ callId: toolCall.callId,
309
+ output: finalOutput,
310
+ },
311
+ `AI function ${toolCall.name} returned an invalid output`,
312
+ );
313
+ return ToolExecutionOutput.create({
314
+ toolCall: FunctionCall.create({ ...toolCall }),
315
+ rawOutput: finalOutput,
316
+ rawException: finalException,
317
+ });
318
+ }
319
+
320
+ return ToolExecutionOutput.create({
321
+ toolCall: FunctionCall.create({ ...toolCall }),
322
+ toolCallOutput: FunctionCallOutput.create({
323
+ name: toolCall.name,
324
+ callId: toolCall.callId,
325
+ output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output
326
+ isError: false,
327
+ }),
328
+ replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output
329
+ agentTask,
330
+ rawOutput: finalOutput,
331
+ rawException: finalException,
332
+ });
333
+ }
334
+
335
+ const INSTRUCTIONS_MESSAGE_ID = 'lk.agent_task.instructions';
336
+
337
+ /**
338
+ * Update the instruction message in the chat context or insert a new one if missing.
339
+ *
340
+ * This function looks for an existing instruction message in the chat context using the identifier
341
+ * 'INSTRUCTIONS_MESSAGE_ID'.
342
+ *
343
+ * @param options - The options for updating the instructions.
344
+ * @param options.chatCtx - The chat context to update.
345
+ * @param options.instructions - The instructions to add.
346
+ * @param options.addIfMissing - Whether to add the instructions if they are missing.
347
+ */
348
+ export function updateInstructions(options: {
349
+ chatCtx: ChatContext;
350
+ instructions: string;
351
+ addIfMissing: boolean;
352
+ }) {
353
+ const { chatCtx, instructions, addIfMissing } = options;
354
+
355
+ const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);
356
+ if (idx !== undefined) {
357
+ if (chatCtx.items[idx]!.type === 'message') {
358
+ // create a new instance to avoid mutating the original
359
+ chatCtx.items[idx] = ChatMessage.create({
360
+ id: INSTRUCTIONS_MESSAGE_ID,
361
+ role: 'system',
362
+ content: [instructions],
363
+ createdAt: chatCtx.items[idx]!.createdAt,
364
+ });
365
+ } else {
366
+ throw new Error('expected the instructions inside the chatCtx to be of type "message"');
367
+ }
368
+ } else if (addIfMissing) {
369
+ // insert the instructions at the beginning of the chat context
370
+ chatCtx.items.unshift(
371
+ ChatMessage.create({
372
+ id: INSTRUCTIONS_MESSAGE_ID,
373
+ role: 'system',
374
+ content: [instructions],
375
+ }),
376
+ );
377
+ }
378
+ }
379
+
380
+ export function performLLMInference(
381
+ node: LLMNode,
382
+ chatCtx: ChatContext,
383
+ toolCtx: ToolContext,
384
+ modelSettings: ModelSettings,
385
+ controller: AbortController,
386
+ ): [Task<void>, _LLMGenerationData] {
387
+ const textStream = new IdentityTransform<string>();
388
+ const toolCallStream = new IdentityTransform<FunctionCall>();
389
+
390
+ const textWriter = textStream.writable.getWriter();
391
+ const toolCallWriter = toolCallStream.writable.getWriter();
392
+ const data = new _LLMGenerationData(textStream.readable, toolCallStream.readable);
393
+
394
+ const inferenceTask = async (signal: AbortSignal) => {
395
+ let llmStreamReader: ReadableStreamDefaultReader<string | ChatChunk> | null = null;
396
+ let llmStream: ReadableStream<string | ChatChunk> | null = null;
397
+
398
+ try {
399
+ llmStream = await node(chatCtx, toolCtx, modelSettings);
400
+ if (llmStream === null) {
401
+ await textWriter.close();
402
+ return;
403
+ }
404
+
405
+ // TODO(brian): add support for dynamic tools
406
+
407
+ llmStreamReader = llmStream.getReader();
408
+ while (true) {
409
+ if (signal.aborted) {
410
+ break;
411
+ }
412
+ const { done, value: chunk } = await llmStreamReader.read();
413
+ if (done) {
414
+ break;
415
+ }
416
+
417
+ if (typeof chunk === 'string') {
418
+ data.generatedText += chunk;
419
+ await textWriter.write(chunk);
420
+ // TODO(shubhra): better way to check??
421
+ } else {
422
+ if (chunk.delta === undefined) {
423
+ continue;
424
+ }
425
+
426
+ if (chunk.delta.toolCalls) {
427
+ for (const tool of chunk.delta.toolCalls) {
428
+ if (tool.type !== 'function_call') continue;
429
+
430
+ const toolCall = FunctionCall.create({
431
+ callId: `${data.id}/fnc_${data.generatedToolCalls.length}`,
432
+ name: tool.name,
433
+ args: tool.args,
434
+ });
435
+
436
+ data.generatedToolCalls.push(toolCall);
437
+ await toolCallWriter.write(toolCall);
438
+ }
439
+ }
440
+
441
+ if (chunk.delta.content) {
442
+ data.generatedText += chunk.delta.content;
443
+ await textWriter.write(chunk.delta.content);
444
+ }
445
+ }
446
+
447
+ // No need to check if chunk is of type other than ChatChunk or string like in
448
+ // Python since chunk is defined in the type ChatChunk | string in TypeScript
449
+ }
450
+ } catch (error) {
451
+ if (error instanceof DOMException && error.name === 'AbortError') {
452
+ // Abort signal was triggered, handle gracefully
453
+ return;
454
+ }
455
+ throw error;
456
+ } finally {
457
+ llmStreamReader?.releaseLock();
458
+ await llmStream?.cancel();
459
+ await textWriter.close();
460
+ await toolCallWriter.close();
461
+ }
462
+ };
463
+
464
+ return [
465
+ Task.from((controller) => inferenceTask(controller.signal), controller, 'performLLMInference'),
466
+ data,
467
+ ];
468
+ }
469
+
470
+ export function performTTSInference(
471
+ node: TTSNode,
472
+ text: ReadableStream<string>,
473
+ modelSettings: ModelSettings,
474
+ controller: AbortController,
475
+ ): [Task<void>, ReadableStream<AudioFrame>] {
476
+ const audioStream = new IdentityTransform<AudioFrame>();
477
+ const outputWriter = audioStream.writable.getWriter();
478
+ const audioOutputStream = audioStream.readable;
479
+
480
+ const inferenceTask = async (signal: AbortSignal) => {
481
+ let ttsStreamReader: ReadableStreamDefaultReader<AudioFrame> | null = null;
482
+ let ttsStream: ReadableStream<AudioFrame> | null = null;
483
+
484
+ try {
485
+ ttsStream = await node(text, modelSettings);
486
+ if (ttsStream === null) {
487
+ await outputWriter.close();
488
+ return;
489
+ }
490
+
491
+ ttsStreamReader = ttsStream.getReader();
492
+ while (true) {
493
+ if (signal.aborted) {
494
+ break;
495
+ }
496
+ const { done, value: chunk } = await ttsStreamReader.read();
497
+ if (done) {
498
+ break;
499
+ }
500
+ await outputWriter.write(chunk);
501
+ }
502
+ } catch (error) {
503
+ if (error instanceof DOMException && error.name === 'AbortError') {
504
+ // Abort signal was triggered, handle gracefully
505
+ return;
506
+ }
507
+ throw error;
508
+ } finally {
509
+ ttsStreamReader?.releaseLock();
510
+ await ttsStream?.cancel();
511
+ await outputWriter.close();
512
+ }
513
+ };
514
+
515
+ return [
516
+ Task.from((controller) => inferenceTask(controller.signal), controller, 'performTTSInference'),
517
+ audioOutputStream,
518
+ ];
519
+ }
520
+
521
+ export interface _TextOut {
522
+ text: string;
523
+ firstTextFut: Future;
524
+ }
525
+
526
+ async function forwardText(
527
+ source: ReadableStream<string>,
528
+ out: _TextOut,
529
+ signal: AbortSignal,
530
+ textOutput: TextOutput | null,
531
+ ): Promise<void> {
532
+ const reader = source.getReader();
533
+ try {
534
+ while (true) {
535
+ if (signal.aborted) {
536
+ break;
537
+ }
538
+ const { done, value: delta } = await reader.read();
539
+ if (done) break;
540
+ out.text += delta;
541
+ if (textOutput !== null) {
542
+ await textOutput.captureText(delta);
543
+ }
544
+ if (!out.firstTextFut.done) {
545
+ out.firstTextFut.resolve();
546
+ }
547
+ }
548
+ } finally {
549
+ if (textOutput !== null) {
550
+ textOutput.flush();
551
+ }
552
+ reader?.releaseLock();
553
+ }
554
+ }
555
+
556
+ export function performTextForwarding(
557
+ source: ReadableStream<string>,
558
+ controller: AbortController,
559
+ textOutput: TextOutput | null,
560
+ ): [Task<void>, _TextOut] {
561
+ const out = {
562
+ text: '',
563
+ firstTextFut: new Future(),
564
+ };
565
+ return [
566
+ Task.from(
567
+ (controller) => forwardText(source, out, controller.signal, textOutput),
568
+ controller,
569
+ 'performTextForwarding',
570
+ ),
571
+ out,
572
+ ];
573
+ }
574
+
575
+ export interface _AudioOut {
576
+ audio: Array<AudioFrame>;
577
+ firstFrameFut: Future;
578
+ }
579
+
580
+ async function forwardAudio(
581
+ ttsStream: ReadableStream<AudioFrame>,
582
+ audioOuput: AudioOutput,
583
+ out: _AudioOut,
584
+ signal?: AbortSignal,
585
+ ): Promise<void> {
586
+ const reader = ttsStream.getReader();
587
+ let resampler: AudioResampler | null = null;
588
+
589
+ try {
590
+ while (true) {
591
+ if (signal?.aborted) {
592
+ break;
593
+ }
594
+
595
+ const { done, value: frame } = await reader.read();
596
+ if (done) break;
597
+
598
+ out.audio.push(frame);
599
+
600
+ if (
601
+ !out.firstFrameFut.done &&
602
+ audioOuput.sampleRate &&
603
+ audioOuput.sampleRate !== frame.sampleRate &&
604
+ !resampler
605
+ ) {
606
+ resampler = new AudioResampler(frame.sampleRate, audioOuput.sampleRate, 1);
607
+ }
608
+
609
+ if (resampler) {
610
+ for (const f of resampler.push(frame)) {
611
+ await audioOuput.captureFrame(f);
612
+ }
613
+ } else {
614
+ await audioOuput.captureFrame(frame);
615
+ }
616
+
617
+ // set the first frame future if not already set
618
+ // (after completing the first frame)
619
+ if (!out.firstFrameFut.done) {
620
+ out.firstFrameFut.resolve();
621
+ }
622
+ }
623
+ } finally {
624
+ reader?.releaseLock();
625
+ if (resampler) {
626
+ for (const f of resampler.flush()) {
627
+ await audioOuput.captureFrame(f);
628
+ }
629
+ }
630
+ audioOuput.flush();
631
+ }
632
+ }
633
+
634
+ export function performAudioForwarding(
635
+ ttsStream: ReadableStream<AudioFrame>,
636
+ audioOutput: AudioOutput,
637
+ controller: AbortController,
638
+ ): [Task<void>, _AudioOut] {
639
+ const out = {
640
+ audio: [],
641
+ firstFrameFut: new Future(),
642
+ };
643
+ return [
644
+ Task.from(
645
+ (controller) => forwardAudio(ttsStream, audioOutput, out, controller.signal),
646
+ controller,
647
+ 'performAudioForwarding',
648
+ ),
649
+ out,
650
+ ];
651
+ }
652
+
653
+ export function performToolExecutions({
654
+ session,
655
+ speechHandle,
656
+ toolCtx,
657
+ toolChoice,
658
+ toolCallStream,
659
+ onToolExecutionStarted = () => {},
660
+ onToolExecutionCompleted = () => {},
661
+ controller,
662
+ }: {
663
+ session: AgentSession;
664
+ speechHandle: SpeechHandle;
665
+ toolCtx: ToolContext;
666
+ toolChoice?: ToolChoice;
667
+ toolCallStream: ReadableStream<FunctionCall>;
668
+ onToolExecutionStarted?: (toolCall: FunctionCall) => void;
669
+ onToolExecutionCompleted?: (toolExecutionOutput: ToolExecutionOutput) => void;
670
+ controller: AbortController;
671
+ }): [Task<void>, ToolOutput] {
672
+ const logger = log();
673
+ const toolOutput: ToolOutput = {
674
+ output: [],
675
+ firstToolStartedFuture: new Future(),
676
+ };
677
+
678
+ const toolCompleted = (out: ToolExecutionOutput) => {
679
+ onToolExecutionCompleted(out);
680
+ toolOutput.output.push(out);
681
+ };
682
+
683
+ const executeToolsTask = async (controller: AbortController) => {
684
+ const signal = controller.signal;
685
+ const reader = toolCallStream.getReader();
686
+
687
+ const tasks: Promise<any>[] = [];
688
+ while (!signal.aborted) {
689
+ const { done, value: toolCall } = await reader.read();
690
+ if (signal.aborted) break;
691
+ if (done) break;
692
+
693
+ if (toolChoice === 'none') {
694
+ logger.error(
695
+ {
696
+ function: toolCall.name,
697
+ speech_id: speechHandle.id,
698
+ },
699
+ "received a tool call with toolChoice set to 'none', ignoring",
700
+ );
701
+ continue;
702
+ }
703
+
704
+ // TODO(brian): assert other toolChoice values
705
+
706
+ const tool = toolCtx[toolCall.name];
707
+ if (!tool) {
708
+ logger.warn(
709
+ {
710
+ function: toolCall.name,
711
+ speech_id: speechHandle.id,
712
+ },
713
+ `unknown AI function ${toolCall.name}`,
714
+ );
715
+ continue;
716
+ }
717
+
718
+ if (!isFunctionTool(tool)) {
719
+ logger.error(
720
+ {
721
+ function: toolCall.name,
722
+ speech_id: speechHandle.id,
723
+ },
724
+ `unknown tool type: ${typeof tool}`,
725
+ );
726
+ continue;
727
+ }
728
+
729
+ let parsedArgs: object | undefined;
730
+
731
+ // Ensure valid arguments
732
+ try {
733
+ const jsonArgs = JSON.parse(toolCall.args);
734
+
735
+ if (tool.parameters instanceof ZodObject) {
736
+ parsedArgs = tool.parameters.parse(jsonArgs);
737
+ } else {
738
+ parsedArgs = jsonArgs;
739
+ }
740
+ } catch (rawError) {
741
+ const error = toError(rawError);
742
+ logger.error(
743
+ {
744
+ function: toolCall.name,
745
+ arguments: toolCall.args,
746
+ speech_id: speechHandle.id,
747
+ error: error.message,
748
+ },
749
+ `tried to call AI function ${toolCall.name} with invalid arguments`,
750
+ );
751
+ toolCompleted(
752
+ createToolOutput({
753
+ toolCall,
754
+ exception: error,
755
+ }),
756
+ );
757
+ continue;
758
+ }
759
+
760
+ if (!toolOutput.firstToolStartedFuture.done) {
761
+ toolOutput.firstToolStartedFuture.resolve();
762
+ }
763
+
764
+ onToolExecutionStarted(toolCall);
765
+
766
+ logger.info(
767
+ {
768
+ function: toolCall.name,
769
+ arguments: parsedArgs,
770
+ speech_id: speechHandle.id,
771
+ },
772
+ 'Executing LLM tool call',
773
+ );
774
+
775
+ const toolExecution = asyncLocalStorage.run({ functionCall: toolCall }, async () => {
776
+ return await tool.execute(parsedArgs, {
777
+ ctx: new RunContext(session, speechHandle, toolCall),
778
+ toolCallId: toolCall.callId,
779
+ abortSignal: signal,
780
+ });
781
+ });
782
+
783
+ const tracableToolExecution = async (toolExecTask: Promise<unknown>) => {
784
+ // TODO(brian): add tracing
785
+
786
+ // await for task to complete, if task is aborted, set exception
787
+ let toolOutput: ToolExecutionOutput | undefined;
788
+ try {
789
+ const { result, isAborted } = await waitUntilAborted(toolExecTask, signal);
790
+ toolOutput = createToolOutput({
791
+ toolCall,
792
+ exception: isAborted ? new Error('tool call was aborted') : undefined,
793
+ output: isAborted ? undefined : result,
794
+ });
795
+ } catch (rawError) {
796
+ logger.error(
797
+ {
798
+ function: toolCall.name,
799
+ speech_id: speechHandle.id,
800
+ error: toError(rawError).message,
801
+ },
802
+ 'exception occurred while executing tool',
803
+ );
804
+ toolOutput = createToolOutput({
805
+ toolCall,
806
+ exception: toError(rawError),
807
+ });
808
+ } finally {
809
+ if (!toolOutput) throw new Error('toolOutput is undefined');
810
+ toolCompleted(toolOutput);
811
+ }
812
+ };
813
+
814
+ // wait, not cancelling all tool calling tasks
815
+ tasks.push(tracableToolExecution(toolExecution));
816
+ }
817
+
818
+ await Promise.allSettled(tasks);
819
+ if (toolOutput.output.length > 0) {
820
+ logger.debug(
821
+ {
822
+ speech_id: speechHandle.id,
823
+ },
824
+ 'tools execution completed',
825
+ );
826
+ }
827
+ };
828
+
829
+ return [Task.from(executeToolsTask, controller, 'performToolExecutions'), toolOutput];
830
+ }
831
+
832
+ type Aborted<T> =
833
+ | {
834
+ result: T;
835
+ isAborted: false;
836
+ }
837
+ | {
838
+ result: undefined;
839
+ isAborted: true;
840
+ };
841
+
842
+ async function waitUntilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<Aborted<T>> {
843
+ const abortFut = new Future<Aborted<T>>();
844
+
845
+ const resolveAbort = () => {
846
+ if (!abortFut.done) {
847
+ abortFut.resolve({ result: undefined, isAborted: true });
848
+ }
849
+ };
850
+
851
+ signal.addEventListener('abort', resolveAbort);
852
+
853
+ promise
854
+ .then((r) => {
855
+ if (!abortFut.done) {
856
+ abortFut.resolve({ result: r, isAborted: false });
857
+ }
858
+ })
859
+ .catch((e) => {
860
+ if (!abortFut.done) {
861
+ abortFut.reject(e);
862
+ }
863
+ })
864
+ .finally(() => {
865
+ signal.removeEventListener('abort', resolveAbort);
866
+ });
867
+
868
+ return await abortFut.await;
869
+ }
870
+
871
+ export function removeInstructions(chatCtx: ChatContext) {
872
+ // loop in case there are items with the same id (shouldn't happen!)
873
+ while (true) {
874
+ const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);
875
+ if (idx !== undefined) {
876
+ chatCtx.items.splice(idx, 1);
877
+ } else {
878
+ break;
879
+ }
880
+ }
881
+ }