@livekit/agents 0.7.8 → 1.0.0-next.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 (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 -0
  21. package/dist/constants.cjs.map +1 -1
  22. package/dist/constants.d.cts +2 -0
  23. package/dist/constants.d.ts +2 -0
  24. package/dist/constants.d.ts.map +1 -1
  25. package/dist/constants.js +4 -0
  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 +98 -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 +99 -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 +101 -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 +102 -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 +157 -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 +157 -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 +281 -27
  333. package/dist/utils.cjs.map +1 -1
  334. package/dist/utils.d.cts +134 -9
  335. package/dist/utils.d.ts +134 -9
  336. package/dist/utils.d.ts.map +1 -1
  337. package/dist/utils.js +265 -26
  338. package/dist/utils.js.map +1 -1
  339. package/dist/utils.test.cjs +492 -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 +375 -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 +351 -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 +380 -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 +355 -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 +9 -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 -0
  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 +149 -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 +135 -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 +203 -21
  537. package/src/types.ts +42 -0
  538. package/src/utils.test.ts +658 -0
  539. package/src/utils.ts +375 -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 +474 -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 +478 -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 -451
  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 -425
  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 -849
  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 -826
  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 -555
  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 -1185
  627. package/src/pipeline/speech_handle.ts +0 -201
@@ -0,0 +1,755 @@
1
+ // SPDX-FileCopyrightText: 2025 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { delay } from '@std/async/delay';
5
+ import { ReadableStream } from 'node:stream/web';
6
+ import { describe, expect, it } from 'vitest';
7
+ import { DeferredReadableStream } from './deferred_stream.js';
8
+
9
+ describe('DeferredReadableStream', () => {
10
+ it('should create a readable stream that can be read after setting source', async () => {
11
+ const deferred = new DeferredReadableStream<string>();
12
+ const reader = deferred.stream.getReader();
13
+
14
+ // Create a source stream with test data
15
+ const testData = ['chunk1', 'chunk2', 'chunk3'];
16
+ const source = new ReadableStream<string>({
17
+ start(controller) {
18
+ for (const chunk of testData) {
19
+ controller.enqueue(chunk);
20
+ }
21
+ controller.close();
22
+ },
23
+ });
24
+
25
+ // Set the source
26
+ deferred.setSource(source);
27
+
28
+ // Read all data
29
+ const results: string[] = [];
30
+ let result = await reader.read();
31
+ while (!result.done) {
32
+ results.push(result.value);
33
+ result = await reader.read();
34
+ }
35
+
36
+ expect(results).toEqual(testData);
37
+ });
38
+
39
+ it('should allow reading from stream before source is set', async () => {
40
+ const deferred = new DeferredReadableStream<string>();
41
+ const reader = deferred.stream.getReader();
42
+
43
+ // Start reading before source is set (this should not resolve immediately)
44
+ const readPromise = reader.read();
45
+
46
+ // Wait a bit to ensure the read is pending
47
+ await delay(10);
48
+
49
+ // Now set the source
50
+ const source = new ReadableStream({
51
+ start(controller) {
52
+ controller.enqueue('test-value');
53
+ controller.close();
54
+ },
55
+ });
56
+
57
+ deferred.setSource(source);
58
+
59
+ // The read should now resolve
60
+ const result = await readPromise;
61
+ expect(result.done).toBe(false);
62
+ expect(result.value).toBe('test-value');
63
+
64
+ // Next read should indicate stream completion
65
+ const nextResult = await reader.read();
66
+ expect(nextResult.done).toBe(true);
67
+ });
68
+
69
+ it('should throw error when trying to set source on locked stream', async () => {
70
+ const deferred = new DeferredReadableStream<string>();
71
+
72
+ // Get a reader to lock the stream
73
+ const reader = deferred.stream.getReader();
74
+
75
+ const source = new ReadableStream({
76
+ start(controller) {
77
+ controller.enqueue('test');
78
+ controller.close();
79
+ },
80
+ });
81
+
82
+ const source2 = new ReadableStream({
83
+ start(controller) {
84
+ controller.enqueue('test2');
85
+ controller.close();
86
+ },
87
+ });
88
+
89
+ expect(() => deferred.setSource(source)).not.toThrow();
90
+ expect(() => deferred.setSource(source2)).toThrow('Stream source already set');
91
+
92
+ // Clean up
93
+ reader.releaseLock();
94
+ });
95
+
96
+ it('should handle multiple concurrent readers before source is set', async () => {
97
+ const deferred = new DeferredReadableStream<number>();
98
+
99
+ // Create multiple readers by using tee()
100
+ const [stream1, stream2] = deferred.stream.tee();
101
+ const reader1 = stream1.getReader();
102
+ const reader2 = stream2.getReader();
103
+
104
+ // Start reading from both streams concurrently
105
+ const read1Promise = reader1.read();
106
+ const read2Promise = reader2.read();
107
+
108
+ // Wait to ensure reads are pending
109
+ await delay(10);
110
+
111
+ // Set source with test data
112
+ const source = new ReadableStream({
113
+ start(controller) {
114
+ controller.enqueue(42);
115
+ controller.enqueue(84);
116
+ controller.close();
117
+ },
118
+ });
119
+
120
+ deferred.setSource(source);
121
+
122
+ // Both readers should receive the data
123
+ const [result1, result2] = await Promise.all([read1Promise, read2Promise]);
124
+
125
+ expect(result1.done).toBe(false);
126
+ expect(result1.value).toBe(42);
127
+ expect(result2.done).toBe(false);
128
+ expect(result2.value).toBe(42);
129
+
130
+ // Read second values
131
+ const [second1, second2] = await Promise.all([reader1.read(), reader2.read()]);
132
+ expect(second1.value).toBe(84);
133
+ expect(second2.value).toBe(84);
134
+ });
135
+
136
+ it('should handle concurrent reads and writes', async () => {
137
+ const deferred = new DeferredReadableStream<string>();
138
+ const reader = deferred.stream.getReader();
139
+
140
+ // Create a source that writes data over time
141
+ const chunks = ['a', 'b', 'c', 'd', 'e'];
142
+ let chunkIndex = 0;
143
+
144
+ const source = new ReadableStream({
145
+ start(controller) {
146
+ const writeNext = () => {
147
+ if (chunkIndex < chunks.length) {
148
+ controller.enqueue(chunks[chunkIndex++]);
149
+ setTimeout(writeNext, 5); // Write next chunk after small delay
150
+ } else {
151
+ controller.close();
152
+ }
153
+ };
154
+ writeNext();
155
+ },
156
+ });
157
+
158
+ // Set source and immediately start reading concurrently
159
+ deferred.setSource(source);
160
+
161
+ const results: string[] = [];
162
+ const readConcurrently = async () => {
163
+ let result = await reader.read();
164
+ while (!result.done) {
165
+ results.push(result.value);
166
+ result = await reader.read();
167
+ }
168
+ };
169
+
170
+ await readConcurrently();
171
+ expect(results).toEqual(chunks);
172
+ });
173
+
174
+ it('should handle race condition between setSource and getReader', async () => {
175
+ const deferred = new DeferredReadableStream<string>();
176
+
177
+ const source = new ReadableStream({
178
+ start(controller) {
179
+ controller.enqueue('race-test');
180
+ controller.close();
181
+ },
182
+ });
183
+
184
+ // Race between setting source and getting reader
185
+ const [, reader] = await Promise.all([
186
+ // Set source
187
+ Promise.resolve().then(() => deferred.setSource(source)),
188
+ // Get reader
189
+ Promise.resolve().then(() => deferred.stream.getReader()),
190
+ ]);
191
+
192
+ const result = await reader.read();
193
+ expect(result.value).toBe('race-test');
194
+ });
195
+
196
+ it('should handle empty source stream', async () => {
197
+ const deferred = new DeferredReadableStream<string>();
198
+ const reader = deferred.stream.getReader();
199
+
200
+ const emptySource = new ReadableStream({
201
+ start(controller) {
202
+ controller.close();
203
+ },
204
+ });
205
+
206
+ deferred.setSource(emptySource);
207
+
208
+ const result = await reader.read();
209
+ expect(result.done).toBe(true);
210
+ });
211
+
212
+ it('should handle source stream with errors', async () => {
213
+ const deferred = new DeferredReadableStream<string>();
214
+ const reader = deferred.stream.getReader();
215
+
216
+ const errorSource = new ReadableStream({
217
+ async start(controller) {
218
+ controller.enqueue('before-error');
219
+ // Use async/await to keep the error within the test scope
220
+ await new Promise((resolve) => setTimeout(resolve, 100));
221
+ controller.error(new Error('Source stream error'));
222
+ },
223
+ });
224
+
225
+ deferred.setSource(errorSource);
226
+
227
+ // Should read the value before error
228
+ const result1 = await reader.read();
229
+ expect(result1.value).toBe('before-error');
230
+
231
+ // Next read should throw the error
232
+ await expect(() => reader.read()).rejects.toThrow('Source stream error');
233
+ });
234
+
235
+ it('should handle multiple concurrent read operations', async () => {
236
+ const deferred = new DeferredReadableStream<number>();
237
+ const reader = deferred.stream.getReader();
238
+
239
+ // Start multiple read operations before setting source
240
+ const readPromises = Array.from({ length: 3 }, () => reader.read());
241
+
242
+ await delay(10);
243
+
244
+ const source = new ReadableStream({
245
+ start(controller) {
246
+ controller.enqueue(1);
247
+ controller.enqueue(2);
248
+ controller.enqueue(3);
249
+ controller.close();
250
+ },
251
+ });
252
+
253
+ deferred.setSource(source);
254
+
255
+ // All reads should resolve with the sequential values
256
+ const results = await Promise.all(readPromises);
257
+
258
+ expect(results[0]?.value).toBe(1);
259
+ expect(results[1]?.value).toBe(2);
260
+ expect(results[2]?.value).toBe(3);
261
+ expect(results.every((r) => !r.done)).toBe(true);
262
+
263
+ // Final read should indicate completion
264
+ const finalResult = await reader.read();
265
+ expect(finalResult.done).toBe(true);
266
+ });
267
+
268
+ it('should handle backpressure correctly', async () => {
269
+ const deferred = new DeferredReadableStream<string>();
270
+
271
+ // Create a source with large chunks to test backpressure
272
+ const largeChunks = Array.from({ length: 1000 }, (_, i) => `chunk-${i}`);
273
+
274
+ const source = new ReadableStream({
275
+ start(controller) {
276
+ for (const chunk of largeChunks) {
277
+ controller.enqueue(chunk);
278
+ }
279
+ controller.close();
280
+ },
281
+ });
282
+
283
+ deferred.setSource(source);
284
+
285
+ const reader = deferred.stream.getReader();
286
+ const results: string[] = [];
287
+
288
+ // Read all chunks
289
+ let result = await reader.read();
290
+ while (!result.done) {
291
+ results.push(result.value);
292
+ result = await reader.read();
293
+ }
294
+
295
+ expect(results).toEqual(largeChunks);
296
+ });
297
+
298
+ it('should handle concurrent setSource calls (second should fail)', async () => {
299
+ const deferred = new DeferredReadableStream<string>();
300
+
301
+ const source1 = new ReadableStream({
302
+ start(controller) {
303
+ controller.enqueue('first');
304
+ controller.close();
305
+ },
306
+ });
307
+
308
+ const source2 = new ReadableStream({
309
+ start(controller) {
310
+ controller.enqueue('second');
311
+ controller.close();
312
+ },
313
+ });
314
+
315
+ // First setSource should succeed
316
+ deferred.setSource(source1);
317
+
318
+ // Second setSource should fail because stream is now locked
319
+ expect(() => deferred.setSource(source2)).toThrow('Stream source already set');
320
+
321
+ // Verify we get data from the first source
322
+ const reader = deferred.stream.getReader();
323
+ const result = await reader.read();
324
+ expect(result.value).toBe('first');
325
+ });
326
+
327
+ it('should handle reader release and re-acquire before source is set', async () => {
328
+ const deferred = new DeferredReadableStream<string>();
329
+
330
+ // Get reader and immediately release it
331
+ const reader1 = deferred.stream.getReader();
332
+ reader1.releaseLock();
333
+
334
+ // Get a new reader
335
+ const reader2 = deferred.stream.getReader();
336
+
337
+ // Now set the source
338
+ const source = new ReadableStream({
339
+ start(controller) {
340
+ controller.enqueue('test-after-release');
341
+ controller.close();
342
+ },
343
+ });
344
+
345
+ deferred.setSource(source);
346
+
347
+ const result = await reader2.read();
348
+ expect(result.value).toBe('test-after-release');
349
+ });
350
+
351
+ it('should handle type safety with different data types', async () => {
352
+ interface TestData {
353
+ id: number;
354
+ name: string;
355
+ }
356
+
357
+ const deferred = new DeferredReadableStream<TestData>();
358
+ const reader = deferred.stream.getReader();
359
+
360
+ const testObject: TestData = { id: 1, name: 'test' };
361
+
362
+ const source = new ReadableStream<TestData>({
363
+ start(controller) {
364
+ controller.enqueue(testObject);
365
+ controller.close();
366
+ },
367
+ });
368
+
369
+ deferred.setSource(source);
370
+
371
+ const result = await reader.read();
372
+ expect(result.value).toEqual(testObject);
373
+ expect(result.value).toBeDefined();
374
+ expect(typeof result.value!.id).toBe('number');
375
+ expect(typeof result.value!.name).toBe('string');
376
+ });
377
+
378
+ it('should create a readable stream', () => {
379
+ const deferred = new DeferredReadableStream<string>();
380
+ expect(deferred.stream).toBeInstanceOf(ReadableStream);
381
+ });
382
+
383
+ it('should keep reader awaiting before source is set, then read after source is set', async () => {
384
+ const deferred = new DeferredReadableStream<string>();
385
+ const reader = deferred.stream.getReader();
386
+
387
+ // Track if read operation is still pending
388
+ let readCompleted = false;
389
+
390
+ // Start reading - this should hang until source is set
391
+ const readPromise = reader.read().then((result) => {
392
+ readCompleted = true;
393
+ return result;
394
+ });
395
+
396
+ // Give some time to ensure read doesn't complete immediately
397
+ await delay(50);
398
+ expect(readCompleted).toBe(false);
399
+
400
+ // Create and set the source
401
+ const sourceData = ['hello', 'world'];
402
+ const source = new ReadableStream<string>({
403
+ start(controller) {
404
+ sourceData.forEach((chunk) => controller.enqueue(chunk));
405
+ controller.close();
406
+ },
407
+ });
408
+
409
+ deferred.setSource(source);
410
+
411
+ // Now the read should complete
412
+ const result = await readPromise;
413
+ expect(readCompleted).toBe(true);
414
+ expect(result.done).toBe(false);
415
+ expect(result.value).toBe('hello');
416
+
417
+ // Read the second chunk
418
+ const result2 = await reader.read();
419
+ expect(result2.done).toBe(false);
420
+ expect(result2.value).toBe('world');
421
+
422
+ // Stream should be closed
423
+ const result3 = await reader.read();
424
+ expect(result3.done).toBe(true);
425
+ expect(result3.value).toBeUndefined();
426
+
427
+ reader.releaseLock();
428
+ });
429
+
430
+ it('should handle multiple chunks from source', async () => {
431
+ const deferred = new DeferredReadableStream<number>();
432
+ const chunks: number[] = [];
433
+
434
+ // Set up a reader that collects all chunks
435
+ const collectPromise = (async () => {
436
+ const reader = deferred.stream.getReader();
437
+ try {
438
+ while (true) {
439
+ const { done, value } = await reader.read();
440
+ if (done) break;
441
+ chunks.push(value);
442
+ }
443
+ } finally {
444
+ reader.releaseLock();
445
+ }
446
+ })();
447
+
448
+ // Create a source that emits multiple chunks over time
449
+ const source = new ReadableStream<number>({
450
+ async start(controller) {
451
+ for (let i = 0; i < 5; i++) {
452
+ controller.enqueue(i);
453
+ await delay(10);
454
+ }
455
+ controller.close();
456
+ },
457
+ });
458
+
459
+ // Set the source
460
+ deferred.setSource(source);
461
+
462
+ // Wait for all chunks to be collected
463
+ await collectPromise;
464
+
465
+ expect(chunks).toEqual([0, 1, 2, 3, 4]);
466
+ });
467
+
468
+ it('should propagate errors from source to reader', async () => {
469
+ const deferred = new DeferredReadableStream<string>();
470
+ const reader = deferred.stream.getReader();
471
+
472
+ // Start reading
473
+ const readPromise = reader.read();
474
+
475
+ // Create a source that errors
476
+ const errorMessage = 'Source error';
477
+ const source = new ReadableStream<string>({
478
+ async start(controller) {
479
+ controller.error(new Error(errorMessage));
480
+ },
481
+ cancel(reason) {
482
+ console.log('cancel', reason);
483
+ },
484
+ });
485
+
486
+ deferred.setSource(source);
487
+
488
+ // The read should reject with the error
489
+ try {
490
+ await readPromise;
491
+ expect.fail('readPromise should have rejected');
492
+ } catch (e: unknown) {
493
+ const error = e as Error;
494
+ expect(error).toBeInstanceOf(Error);
495
+ expect(error.message).toBe('Source error');
496
+ }
497
+
498
+ reader.releaseLock();
499
+ });
500
+
501
+ it('should throw error when trying to set source twice', () => {
502
+ const deferred = new DeferredReadableStream<string>();
503
+
504
+ const source1 = new ReadableStream<string>({
505
+ start(controller) {
506
+ controller.enqueue('first');
507
+ controller.close();
508
+ },
509
+ });
510
+
511
+ const source2 = new ReadableStream<string>({
512
+ start(controller) {
513
+ controller.enqueue('second');
514
+ controller.close();
515
+ },
516
+ });
517
+
518
+ // First setSource should work
519
+ deferred.setSource(source1);
520
+
521
+ // Second setSource should throw
522
+ expect(() => deferred.setSource(source2)).toThrow('Stream source already set');
523
+ });
524
+
525
+ it('should throw error when trying to detach source before setting it', async () => {
526
+ const deferred = new DeferredReadableStream<string>();
527
+
528
+ // Attempting to detach source before setting it should throw
529
+ await expect(deferred.detachSource()).rejects.toThrow('Source not set');
530
+ });
531
+
532
+ it('read returns undefined as soon as reader is cancelled', async () => {
533
+ const deferred = new DeferredReadableStream<string>();
534
+ const reader = deferred.stream.getReader();
535
+ const readPromise = reader.read();
536
+
537
+ const source = new ReadableStream<string>({
538
+ start(controller) {
539
+ controller.enqueue('data');
540
+ controller.close();
541
+ },
542
+ });
543
+
544
+ deferred.setSource(source);
545
+
546
+ await reader.cancel();
547
+
548
+ const result = await readPromise;
549
+ expect(result.done).toBe(true);
550
+ expect(result.value).toBeUndefined();
551
+
552
+ reader.releaseLock();
553
+ });
554
+
555
+ it('reads after detaching source should return undefined', async () => {
556
+ const deferred = new DeferredReadableStream<string>();
557
+ const reader = deferred.stream.getReader();
558
+ const readPromise = reader.read();
559
+
560
+ const source = new ReadableStream<string>({
561
+ start(controller) {
562
+ controller.enqueue('first');
563
+ controller.enqueue('second');
564
+ controller.close();
565
+ },
566
+ });
567
+
568
+ deferred.setSource(source);
569
+
570
+ // Detach the source
571
+ await deferred.detachSource();
572
+
573
+ const result = await readPromise;
574
+ expect(result.done).toBe(false);
575
+ expect(result.value).toBe('first');
576
+
577
+ const result2 = await reader.read();
578
+ expect(result2.done).toBe(true);
579
+ expect(result2.value).toBeUndefined();
580
+ reader.releaseLock();
581
+
582
+ const reader2 = source.getReader();
583
+ const result3 = await reader2.read();
584
+ expect(result3.done).toBe(false);
585
+ expect(result3.value).toBe('second');
586
+
587
+ const result4 = await reader2.read();
588
+ expect(result4.done).toBe(true);
589
+ expect(result4.value).toBeUndefined();
590
+ reader.releaseLock();
591
+ });
592
+
593
+ it('should handle empty source stream', async () => {
594
+ const deferred = new DeferredReadableStream<string>();
595
+ const reader = deferred.stream.getReader();
596
+
597
+ // Start reading
598
+ const readPromise = reader.read();
599
+
600
+ // Set an empty source
601
+ const source = new ReadableStream<string>({
602
+ start(controller) {
603
+ controller.close();
604
+ },
605
+ });
606
+
607
+ deferred.setSource(source);
608
+
609
+ // Read should indicate end of stream
610
+ const result = await readPromise;
611
+ expect(result.done).toBe(true);
612
+ expect(result.value).toBeUndefined();
613
+
614
+ reader.releaseLock();
615
+ });
616
+
617
+ it('source can be set by another deferred stream after calling detach', async () => {
618
+ const deferred = new DeferredReadableStream<string>();
619
+
620
+ // Create a new source stream
621
+ const source = new ReadableStream<string>({
622
+ start(controller) {
623
+ controller.enqueue('before-cancel');
624
+ controller.enqueue('after-cancel');
625
+ controller.close();
626
+ },
627
+ });
628
+
629
+ // read first chunk
630
+ deferred.setSource(source);
631
+ const reader = deferred.stream.getReader();
632
+ const result = await reader.read();
633
+ expect(result.done).toBe(false);
634
+ expect(result.value).toBe('before-cancel');
635
+
636
+ const result2Promise = reader.read();
637
+
638
+ // detach the source
639
+ await deferred.detachSource();
640
+
641
+ // read second chunk
642
+ const result2 = await result2Promise;
643
+ expect(result2.done).toBe(true);
644
+ expect(result2.value).toBeUndefined();
645
+
646
+ // we manually release the lock
647
+ reader.releaseLock();
648
+
649
+ // create a new deferred stream and set the source
650
+ const deferred2 = new DeferredReadableStream<string>();
651
+ deferred2.setSource(source);
652
+ const reader2 = deferred2.stream.getReader();
653
+
654
+ // read the second chunk
655
+ const result3 = await reader2.read();
656
+ expect(result3.done).toBe(false);
657
+ expect(result3.value).toBe('after-cancel');
658
+
659
+ // read the third chunk
660
+ const result4 = await reader2.read();
661
+ expect(result4.done).toBe(true);
662
+ expect(result4.value).toBeUndefined();
663
+ reader2.releaseLock();
664
+ });
665
+
666
+ it('a non-terminating source reader releases lock after detaching', async () => {
667
+ const deferred = new DeferredReadableStream<string>();
668
+ const reader = deferred.stream.getReader();
669
+ const readPromise = reader.read();
670
+ let resumeSource = false;
671
+
672
+ const source = new ReadableStream<string>({
673
+ async start(controller) {
674
+ while (!resumeSource) await delay(10);
675
+
676
+ controller.enqueue('data');
677
+ controller.close();
678
+ },
679
+ });
680
+
681
+ deferred.setSource(source);
682
+ await deferred.detachSource();
683
+ await delay(100);
684
+
685
+ // read before detach should return undefined since source never resumed
686
+ const result = await readPromise;
687
+ expect(result.done).toBe(true);
688
+ expect(result.value).toBeUndefined();
689
+
690
+ const reader2 = source.getReader();
691
+ resumeSource = true;
692
+
693
+ // read after detach should return correct order of data since source resumed
694
+ const result2 = await reader2.read();
695
+ expect(result2.done).toBe(false);
696
+ expect(result2.value).toBe('data');
697
+
698
+ const result3 = await reader2.read();
699
+ expect(result3.done).toBe(true);
700
+ expect(result3.value).toBeUndefined();
701
+
702
+ reader2.releaseLock();
703
+ });
704
+
705
+ it('should transfer source between deferred streams while reading is ongoing', async () => {
706
+ const deferred1 = new DeferredReadableStream<string>();
707
+ const deferred2 = new DeferredReadableStream<string>();
708
+
709
+ // Create a source that slowly emits data
710
+ const source = new ReadableStream<string>({
711
+ async start(controller) {
712
+ // Emit 5 chunks with delays
713
+ for (let i = 0; i < 4; i++) {
714
+ controller.enqueue(`chunk-${i}`);
715
+ await delay(20); // Small delay between chunks
716
+ }
717
+ controller.close();
718
+ },
719
+ });
720
+
721
+ deferred1.setSource(source);
722
+ const reader1 = deferred1.stream.getReader();
723
+ const result1 = await reader1.read();
724
+ expect(result1.done).toBe(false);
725
+ expect(result1.value).toBe('chunk-0');
726
+
727
+ const result2 = await reader1.read();
728
+ expect(result2.done).toBe(false);
729
+ expect(result2.value).toBe('chunk-1');
730
+ await delay(10);
731
+ await deferred1.detachSource();
732
+
733
+ // reader1 now done
734
+ const result3 = await reader1.read();
735
+ expect(result3.done).toBe(true);
736
+ expect(result3.value).toBeUndefined();
737
+
738
+ deferred2.setSource(source);
739
+ const reader2 = deferred2.stream.getReader();
740
+ const result4 = await reader2.read();
741
+ expect(result4.done).toBe(false);
742
+ expect(result4.value).toBe('chunk-2');
743
+
744
+ const result5 = await reader2.read();
745
+ expect(result5.done).toBe(false);
746
+ expect(result5.value).toBe('chunk-3');
747
+
748
+ const result6 = await reader2.read();
749
+ expect(result6.done).toBe(true);
750
+ expect(result6.value).toBeUndefined();
751
+
752
+ reader1.releaseLock();
753
+ reader2.releaseLock();
754
+ });
755
+ });