@livekit/agents 1.1.0-dev.0 → 1.2.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 (292) hide show
  1. package/dist/cli.cjs +2 -0
  2. package/dist/cli.cjs.map +1 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +2 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/constants.cjs +3 -0
  7. package/dist/constants.cjs.map +1 -1
  8. package/dist/constants.d.cts +1 -0
  9. package/dist/constants.d.ts +1 -0
  10. package/dist/constants.d.ts.map +1 -1
  11. package/dist/constants.js +2 -0
  12. package/dist/constants.js.map +1 -1
  13. package/dist/cpu.cjs +189 -0
  14. package/dist/cpu.cjs.map +1 -0
  15. package/dist/cpu.d.cts +24 -0
  16. package/dist/cpu.d.ts +24 -0
  17. package/dist/cpu.d.ts.map +1 -0
  18. package/dist/cpu.js +152 -0
  19. package/dist/cpu.js.map +1 -0
  20. package/dist/cpu.test.cjs +227 -0
  21. package/dist/cpu.test.cjs.map +1 -0
  22. package/dist/cpu.test.js +204 -0
  23. package/dist/cpu.test.js.map +1 -0
  24. package/dist/index.cjs +12 -10
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +13 -13
  27. package/dist/index.d.ts +13 -13
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +11 -10
  30. package/dist/index.js.map +1 -1
  31. package/dist/inference/interruption/defaults.cjs +1 -1
  32. package/dist/inference/interruption/defaults.cjs.map +1 -1
  33. package/dist/inference/interruption/defaults.d.cts +1 -1
  34. package/dist/inference/interruption/defaults.d.ts +1 -1
  35. package/dist/inference/interruption/defaults.d.ts.map +1 -1
  36. package/dist/inference/interruption/defaults.js +1 -1
  37. package/dist/inference/interruption/defaults.js.map +1 -1
  38. package/dist/inference/interruption/http_transport.cjs +44 -28
  39. package/dist/inference/interruption/http_transport.cjs.map +1 -1
  40. package/dist/inference/interruption/http_transport.d.ts.map +1 -1
  41. package/dist/inference/interruption/http_transport.js +45 -29
  42. package/dist/inference/interruption/http_transport.js.map +1 -1
  43. package/dist/inference/interruption/interruption_detector.cjs +22 -5
  44. package/dist/inference/interruption/interruption_detector.cjs.map +1 -1
  45. package/dist/inference/interruption/interruption_detector.d.cts +2 -2
  46. package/dist/inference/interruption/interruption_detector.d.ts +2 -2
  47. package/dist/inference/interruption/interruption_detector.d.ts.map +1 -1
  48. package/dist/inference/interruption/interruption_detector.js +22 -5
  49. package/dist/inference/interruption/interruption_detector.js.map +1 -1
  50. package/dist/inference/interruption/interruption_stream.cjs +4 -4
  51. package/dist/inference/interruption/interruption_stream.cjs.map +1 -1
  52. package/dist/inference/interruption/interruption_stream.js +4 -4
  53. package/dist/inference/interruption/interruption_stream.js.map +1 -1
  54. package/dist/inference/interruption/types.cjs.map +1 -1
  55. package/dist/inference/interruption/types.d.cts +2 -2
  56. package/dist/inference/interruption/types.d.ts +2 -2
  57. package/dist/inference/interruption/types.d.ts.map +1 -1
  58. package/dist/inference/interruption/ws_transport.cjs +60 -47
  59. package/dist/inference/interruption/ws_transport.cjs.map +1 -1
  60. package/dist/inference/interruption/ws_transport.d.ts.map +1 -1
  61. package/dist/inference/interruption/ws_transport.js +60 -47
  62. package/dist/inference/interruption/ws_transport.js.map +1 -1
  63. package/dist/inference/llm.cjs.map +1 -1
  64. package/dist/inference/llm.d.cts +1 -1
  65. package/dist/inference/llm.d.ts +1 -1
  66. package/dist/inference/llm.d.ts.map +1 -1
  67. package/dist/inference/llm.js.map +1 -1
  68. package/dist/inference/stt.cjs +20 -12
  69. package/dist/inference/stt.cjs.map +1 -1
  70. package/dist/inference/stt.d.cts +3 -2
  71. package/dist/inference/stt.d.ts +3 -2
  72. package/dist/inference/stt.d.ts.map +1 -1
  73. package/dist/inference/stt.js +20 -12
  74. package/dist/inference/stt.js.map +1 -1
  75. package/dist/inference/stt.test.cjs +14 -0
  76. package/dist/inference/stt.test.cjs.map +1 -1
  77. package/dist/inference/stt.test.js +14 -0
  78. package/dist/inference/stt.test.js.map +1 -1
  79. package/dist/inference/tts.cjs +13 -4
  80. package/dist/inference/tts.cjs.map +1 -1
  81. package/dist/inference/tts.d.cts +8 -1
  82. package/dist/inference/tts.d.ts +8 -1
  83. package/dist/inference/tts.d.ts.map +1 -1
  84. package/dist/inference/tts.js +13 -4
  85. package/dist/inference/tts.js.map +1 -1
  86. package/dist/inference/tts.test.cjs +10 -0
  87. package/dist/inference/tts.test.cjs.map +1 -1
  88. package/dist/inference/tts.test.js +10 -0
  89. package/dist/inference/tts.test.js.map +1 -1
  90. package/dist/ipc/job_proc_lazy_main.cjs +41 -23
  91. package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
  92. package/dist/ipc/job_proc_lazy_main.js +41 -23
  93. package/dist/ipc/job_proc_lazy_main.js.map +1 -1
  94. package/dist/job.cjs +1 -1
  95. package/dist/job.cjs.map +1 -1
  96. package/dist/job.js +1 -1
  97. package/dist/job.js.map +1 -1
  98. package/dist/language.cjs +394 -0
  99. package/dist/language.cjs.map +1 -0
  100. package/dist/language.d.cts +15 -0
  101. package/dist/language.d.ts +15 -0
  102. package/dist/language.d.ts.map +1 -0
  103. package/dist/language.js +363 -0
  104. package/dist/language.js.map +1 -0
  105. package/dist/language.test.cjs +43 -0
  106. package/dist/language.test.cjs.map +1 -0
  107. package/dist/language.test.js +49 -0
  108. package/dist/language.test.js.map +1 -0
  109. package/dist/llm/index.cjs +2 -0
  110. package/dist/llm/index.cjs.map +1 -1
  111. package/dist/llm/index.d.cts +1 -1
  112. package/dist/llm/index.d.ts +1 -1
  113. package/dist/llm/index.d.ts.map +1 -1
  114. package/dist/llm/index.js +2 -0
  115. package/dist/llm/index.js.map +1 -1
  116. package/dist/stream/deferred_stream.cjs +6 -2
  117. package/dist/stream/deferred_stream.cjs.map +1 -1
  118. package/dist/stream/deferred_stream.d.ts.map +1 -1
  119. package/dist/stream/deferred_stream.js +6 -2
  120. package/dist/stream/deferred_stream.js.map +1 -1
  121. package/dist/stt/stt.cjs.map +1 -1
  122. package/dist/stt/stt.d.cts +2 -1
  123. package/dist/stt/stt.d.ts +2 -1
  124. package/dist/stt/stt.d.ts.map +1 -1
  125. package/dist/stt/stt.js.map +1 -1
  126. package/dist/utils.cjs +15 -0
  127. package/dist/utils.cjs.map +1 -1
  128. package/dist/utils.d.cts +8 -0
  129. package/dist/utils.d.ts +8 -0
  130. package/dist/utils.d.ts.map +1 -1
  131. package/dist/utils.js +13 -0
  132. package/dist/utils.js.map +1 -1
  133. package/dist/version.cjs +1 -1
  134. package/dist/version.js +1 -1
  135. package/dist/voice/agent.cjs +14 -17
  136. package/dist/voice/agent.cjs.map +1 -1
  137. package/dist/voice/agent.d.cts +10 -11
  138. package/dist/voice/agent.d.ts +10 -11
  139. package/dist/voice/agent.d.ts.map +1 -1
  140. package/dist/voice/agent.js +15 -18
  141. package/dist/voice/agent.js.map +1 -1
  142. package/dist/voice/agent.test.cjs +194 -0
  143. package/dist/voice/agent.test.cjs.map +1 -1
  144. package/dist/voice/agent.test.js +195 -1
  145. package/dist/voice/agent.test.js.map +1 -1
  146. package/dist/voice/agent_activity.cjs +116 -39
  147. package/dist/voice/agent_activity.cjs.map +1 -1
  148. package/dist/voice/agent_activity.d.cts +2 -0
  149. package/dist/voice/agent_activity.d.ts +2 -0
  150. package/dist/voice/agent_activity.d.ts.map +1 -1
  151. package/dist/voice/agent_activity.js +117 -40
  152. package/dist/voice/agent_activity.js.map +1 -1
  153. package/dist/voice/agent_activity.test.cjs +135 -0
  154. package/dist/voice/agent_activity.test.cjs.map +1 -0
  155. package/dist/voice/agent_activity.test.js +134 -0
  156. package/dist/voice/agent_activity.test.js.map +1 -0
  157. package/dist/voice/agent_session.cjs +38 -38
  158. package/dist/voice/agent_session.cjs.map +1 -1
  159. package/dist/voice/agent_session.d.cts +65 -56
  160. package/dist/voice/agent_session.d.ts +65 -56
  161. package/dist/voice/agent_session.d.ts.map +1 -1
  162. package/dist/voice/agent_session.js +37 -37
  163. package/dist/voice/agent_session.js.map +1 -1
  164. package/dist/voice/audio_recognition.cjs +106 -52
  165. package/dist/voice/audio_recognition.cjs.map +1 -1
  166. package/dist/voice/audio_recognition.d.cts +4 -2
  167. package/dist/voice/audio_recognition.d.ts +4 -2
  168. package/dist/voice/audio_recognition.d.ts.map +1 -1
  169. package/dist/voice/audio_recognition.js +106 -52
  170. package/dist/voice/audio_recognition.js.map +1 -1
  171. package/dist/voice/audio_recognition_span.test.cjs +84 -22
  172. package/dist/voice/audio_recognition_span.test.cjs.map +1 -1
  173. package/dist/voice/audio_recognition_span.test.js +90 -23
  174. package/dist/voice/audio_recognition_span.test.js.map +1 -1
  175. package/dist/voice/events.cjs +1 -1
  176. package/dist/voice/events.cjs.map +1 -1
  177. package/dist/voice/events.d.cts +4 -3
  178. package/dist/voice/events.d.ts +4 -3
  179. package/dist/voice/events.d.ts.map +1 -1
  180. package/dist/voice/events.js +1 -1
  181. package/dist/voice/events.js.map +1 -1
  182. package/dist/voice/index.cjs +9 -1
  183. package/dist/voice/index.cjs.map +1 -1
  184. package/dist/voice/index.d.cts +1 -1
  185. package/dist/voice/index.d.ts +1 -1
  186. package/dist/voice/index.d.ts.map +1 -1
  187. package/dist/voice/index.js +10 -1
  188. package/dist/voice/index.js.map +1 -1
  189. package/dist/voice/remote_session.cjs +922 -0
  190. package/dist/voice/remote_session.cjs.map +1 -0
  191. package/dist/voice/remote_session.d.cts +108 -0
  192. package/dist/voice/remote_session.d.ts +108 -0
  193. package/dist/voice/remote_session.d.ts.map +1 -0
  194. package/dist/voice/remote_session.js +887 -0
  195. package/dist/voice/remote_session.js.map +1 -0
  196. package/dist/voice/report.cjs +11 -10
  197. package/dist/voice/report.cjs.map +1 -1
  198. package/dist/voice/report.d.cts +5 -3
  199. package/dist/voice/report.d.ts +5 -3
  200. package/dist/voice/report.d.ts.map +1 -1
  201. package/dist/voice/report.js +11 -10
  202. package/dist/voice/report.js.map +1 -1
  203. package/dist/voice/report.test.cjs +15 -0
  204. package/dist/voice/report.test.cjs.map +1 -1
  205. package/dist/voice/report.test.js +15 -0
  206. package/dist/voice/report.test.js.map +1 -1
  207. package/dist/voice/room_io/room_io.cjs +39 -0
  208. package/dist/voice/room_io/room_io.cjs.map +1 -1
  209. package/dist/voice/room_io/room_io.d.cts +3 -1
  210. package/dist/voice/room_io/room_io.d.ts +3 -1
  211. package/dist/voice/room_io/room_io.d.ts.map +1 -1
  212. package/dist/voice/room_io/room_io.js +40 -1
  213. package/dist/voice/room_io/room_io.js.map +1 -1
  214. package/dist/voice/turn_config/interruption.cjs.map +1 -1
  215. package/dist/voice/turn_config/interruption.d.cts +1 -1
  216. package/dist/voice/turn_config/interruption.d.ts +1 -1
  217. package/dist/voice/turn_config/interruption.d.ts.map +1 -1
  218. package/dist/voice/turn_config/interruption.js.map +1 -1
  219. package/dist/voice/turn_config/utils.cjs +95 -35
  220. package/dist/voice/turn_config/utils.cjs.map +1 -1
  221. package/dist/voice/turn_config/utils.d.cts +17 -5
  222. package/dist/voice/turn_config/utils.d.ts +17 -5
  223. package/dist/voice/turn_config/utils.d.ts.map +1 -1
  224. package/dist/voice/turn_config/utils.js +93 -35
  225. package/dist/voice/turn_config/utils.js.map +1 -1
  226. package/dist/voice/turn_config/utils.test.cjs +83 -41
  227. package/dist/voice/turn_config/utils.test.cjs.map +1 -1
  228. package/dist/voice/turn_config/utils.test.js +84 -42
  229. package/dist/voice/turn_config/utils.test.js.map +1 -1
  230. package/dist/worker.cjs +6 -29
  231. package/dist/worker.cjs.map +1 -1
  232. package/dist/worker.d.ts.map +1 -1
  233. package/dist/worker.js +6 -19
  234. package/dist/worker.js.map +1 -1
  235. package/package.json +3 -2
  236. package/src/cli.ts +2 -0
  237. package/src/constants.ts +1 -0
  238. package/src/cpu.test.ts +239 -0
  239. package/src/cpu.ts +173 -0
  240. package/src/index.ts +13 -15
  241. package/src/inference/interruption/defaults.ts +1 -1
  242. package/src/inference/interruption/http_transport.ts +49 -30
  243. package/src/inference/interruption/interruption_detector.ts +22 -6
  244. package/src/inference/interruption/interruption_stream.ts +4 -4
  245. package/src/inference/interruption/types.ts +2 -2
  246. package/src/inference/interruption/ws_transport.ts +63 -59
  247. package/src/inference/llm.ts +3 -1
  248. package/src/inference/stt.test.ts +17 -0
  249. package/src/inference/stt.ts +22 -14
  250. package/src/inference/tts.test.ts +12 -0
  251. package/src/inference/tts.ts +22 -6
  252. package/src/ipc/job_proc_lazy_main.ts +44 -24
  253. package/src/job.ts +1 -1
  254. package/src/language.test.ts +62 -0
  255. package/src/language.ts +380 -0
  256. package/src/llm/index.ts +2 -0
  257. package/src/stream/deferred_stream.ts +5 -1
  258. package/src/stt/stt.ts +2 -1
  259. package/src/utils.ts +20 -0
  260. package/src/voice/agent.test.ts +208 -1
  261. package/src/voice/agent.ts +21 -22
  262. package/src/voice/agent_activity.test.ts +194 -0
  263. package/src/voice/agent_activity.ts +161 -43
  264. package/src/voice/agent_session.ts +103 -92
  265. package/src/voice/audio_recognition.ts +124 -61
  266. package/src/voice/audio_recognition_span.test.ts +115 -35
  267. package/src/voice/events.ts +4 -3
  268. package/src/voice/index.ts +10 -1
  269. package/src/voice/remote_session.ts +1083 -0
  270. package/src/voice/report.test.ts +22 -3
  271. package/src/voice/report.ts +31 -14
  272. package/src/voice/room_io/room_io.ts +52 -2
  273. package/src/voice/turn_config/interruption.ts +1 -1
  274. package/src/voice/turn_config/utils.test.ts +91 -43
  275. package/src/voice/turn_config/utils.ts +120 -56
  276. package/src/worker.ts +34 -50
  277. package/dist/voice/client_events.cjs +0 -554
  278. package/dist/voice/client_events.cjs.map +0 -1
  279. package/dist/voice/client_events.d.cts +0 -195
  280. package/dist/voice/client_events.d.ts +0 -195
  281. package/dist/voice/client_events.d.ts.map +0 -1
  282. package/dist/voice/client_events.js +0 -548
  283. package/dist/voice/client_events.js.map +0 -1
  284. package/dist/voice/wire_format.cjs +0 -798
  285. package/dist/voice/wire_format.cjs.map +0 -1
  286. package/dist/voice/wire_format.d.cts +0 -5503
  287. package/dist/voice/wire_format.d.ts +0 -5503
  288. package/dist/voice/wire_format.d.ts.map +0 -1
  289. package/dist/voice/wire_format.js +0 -728
  290. package/dist/voice/wire_format.js.map +0 -1
  291. package/src/voice/client_events.ts +0 -838
  292. package/src/voice/wire_format.ts +0 -827
@@ -4,7 +4,10 @@ import { tool } from "../llm/index.js";
4
4
  import { initializeLogger } from "../log.js";
5
5
  import { Task } from "../utils.js";
6
6
  import { Agent, AgentTask, _setActivityTaskInfo } from "./agent.js";
7
- import { agentActivityStorage } from "./agent_activity.js";
7
+ import { AgentActivity, agentActivityStorage } from "./agent_activity.js";
8
+ import { defaultEndpointingOptions } from "./turn_config/endpointing.js";
9
+ import { defaultInterruptionOptions } from "./turn_config/interruption.js";
10
+ vi.mock("ofetch", () => ({ ofetch: vi.fn() }));
8
11
  initializeLogger({ pretty: false, level: "error" });
9
12
  describe("Agent", () => {
10
13
  it("should create agent with basic instructions", () => {
@@ -176,5 +179,196 @@ describe("Agent", () => {
176
179
  await expect(wrapper.result).resolves.toBe("ok");
177
180
  expect(closeOldActivity).toHaveBeenCalledTimes(1);
178
181
  });
182
+ describe("Agent constructor option migration", () => {
183
+ it("should set allowInterruptions to false via deprecated constructor field", () => {
184
+ var _a, _b;
185
+ const agent = new Agent({ instructions: "test", allowInterruptions: false });
186
+ expect((_b = (_a = agent.turnHandling) == null ? void 0 : _a.interruption) == null ? void 0 : _b.enabled).toBe(false);
187
+ });
188
+ it("should not set derived properties when no compatibility fields are provided", () => {
189
+ const agent = new Agent({ instructions: "test" });
190
+ expect(agent.turnHandling).toBeUndefined();
191
+ });
192
+ it("should expose minConsecutiveSpeechDelay", () => {
193
+ const agent = new Agent({ instructions: "test", minConsecutiveSpeechDelay: 1.5 });
194
+ expect(agent.minConsecutiveSpeechDelay).toBe(1.5);
195
+ });
196
+ it("should ignore deprecated constructor fields when turnHandling is provided", () => {
197
+ var _a, _b, _c, _d, _e, _f, _g;
198
+ const agent = new Agent({
199
+ instructions: "test",
200
+ turnHandling: {
201
+ endpointing: { minDelay: 999 },
202
+ interruption: {},
203
+ turnDetection: "vad"
204
+ },
205
+ allowInterruptions: false
206
+ });
207
+ expect((_b = (_a = agent.turnHandling) == null ? void 0 : _a.endpointing) == null ? void 0 : _b.minDelay).toBe(999);
208
+ expect((_d = (_c = agent.turnHandling) == null ? void 0 : _c.endpointing) == null ? void 0 : _d.maxDelay).toBeUndefined();
209
+ expect((_f = (_e = agent.turnHandling) == null ? void 0 : _e.interruption) == null ? void 0 : _f.enabled).toBeUndefined();
210
+ expect((_g = agent.turnHandling) == null ? void 0 : _g.turnDetection).toBe("vad");
211
+ });
212
+ it("should let turnHandling override deprecated constructor fields on conflicts", () => {
213
+ var _a, _b, _c, _d, _e, _f, _g;
214
+ const agent = new Agent({
215
+ instructions: "test",
216
+ turnHandling: {
217
+ endpointing: { minDelay: 999, maxDelay: 4e3 },
218
+ interruption: { enabled: true },
219
+ turnDetection: "vad"
220
+ },
221
+ allowInterruptions: false,
222
+ turnDetection: "stt"
223
+ });
224
+ expect((_b = (_a = agent.turnHandling) == null ? void 0 : _a.endpointing) == null ? void 0 : _b.minDelay).toBe(999);
225
+ expect((_d = (_c = agent.turnHandling) == null ? void 0 : _c.endpointing) == null ? void 0 : _d.maxDelay).toBe(4e3);
226
+ expect((_f = (_e = agent.turnHandling) == null ? void 0 : _e.interruption) == null ? void 0 : _f.enabled).toBe(true);
227
+ expect((_g = agent.turnHandling) == null ? void 0 : _g.turnDetection).toBe("vad");
228
+ });
229
+ it("should set interruptionDetection from turnHandling.interruption.mode", () => {
230
+ var _a, _b;
231
+ const agent = new Agent({
232
+ instructions: "test",
233
+ turnHandling: {
234
+ interruption: { mode: "adaptive" },
235
+ endpointing: {},
236
+ turnDetection: void 0
237
+ }
238
+ });
239
+ expect((_b = (_a = agent.turnHandling) == null ? void 0 : _a.interruption) == null ? void 0 : _b.mode).toBe("adaptive");
240
+ });
241
+ it("should let AgentActivity prefer agent-level overrides over session defaults", () => {
242
+ var _a, _b;
243
+ const agent = new Agent({
244
+ instructions: "test",
245
+ turnHandling: {
246
+ endpointing: { minDelay: 111, maxDelay: 222 },
247
+ interruption: { enabled: false },
248
+ turnDetection: "manual"
249
+ }
250
+ });
251
+ const session = {
252
+ options: {
253
+ turnHandling: {
254
+ endpointing: defaultEndpointingOptions,
255
+ interruption: defaultInterruptionOptions
256
+ }
257
+ },
258
+ turnDetection: "stt",
259
+ useTtsAlignedTranscript: true,
260
+ vad: void 0,
261
+ stt: void 0,
262
+ llm: void 0,
263
+ tts: void 0,
264
+ interruptionDetection: void 0
265
+ };
266
+ const activity = new AgentActivity(agent, session);
267
+ expect(activity.allowInterruptions).toBe(false);
268
+ expect(activity.turnDetection).toBe("manual");
269
+ expect((_a = activity.turnHandling.endpointing) == null ? void 0 : _a.minDelay).toBe(111);
270
+ expect((_b = activity.turnHandling.endpointing) == null ? void 0 : _b.maxDelay).toBe(222);
271
+ });
272
+ it("should disable adaptive interruption detection in default mode when prerequisites are missing", () => {
273
+ const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;
274
+ process.env.LIVEKIT_REMOTE_EOT_URL = "http://localhost:9999";
275
+ try {
276
+ const agent = new Agent({ instructions: "test" });
277
+ const session = {
278
+ options: {
279
+ turnHandling: {
280
+ endpointing: defaultEndpointingOptions,
281
+ interruption: defaultInterruptionOptions
282
+ }
283
+ },
284
+ sessionOptions: {
285
+ turnHandling: {
286
+ endpointing: defaultEndpointingOptions,
287
+ interruption: defaultInterruptionOptions
288
+ }
289
+ },
290
+ turnDetection: "manual",
291
+ useTtsAlignedTranscript: true,
292
+ vad: {},
293
+ stt: {
294
+ capabilities: {
295
+ alignedTranscript: true,
296
+ streaming: true
297
+ }
298
+ },
299
+ llm: void 0,
300
+ tts: void 0,
301
+ interruptionDetection: void 0
302
+ };
303
+ const activity = new AgentActivity(agent, session);
304
+ expect(activity.interruptionDetector).toBeUndefined();
305
+ } finally {
306
+ if (previousRemoteEotUrl === void 0) {
307
+ delete process.env.LIVEKIT_REMOTE_EOT_URL;
308
+ } else {
309
+ process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;
310
+ }
311
+ }
312
+ });
313
+ it("should warn when session explicitly requests adaptive detection even if agent overrides it", () => {
314
+ const activity = Object.create(AgentActivity.prototype);
315
+ activity.agent = {
316
+ turnHandling: { interruption: { mode: "vad" } },
317
+ turnDetection: void 0
318
+ };
319
+ activity.agentSession = {
320
+ interruptionDetection: "adaptive",
321
+ turnDetection: "manual"
322
+ };
323
+ activity.logger = { warn: vi.fn() };
324
+ expect(activity.resolveInterruptionDetector()).toBeUndefined();
325
+ expect(activity.logger.warn).toHaveBeenCalledWith(
326
+ "interruptionDetection is provided, but it's not compatible with the current configuration and will be disabled"
327
+ );
328
+ });
329
+ it("should disable adaptive interruption detection when interruptions are disabled", () => {
330
+ const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;
331
+ process.env.LIVEKIT_REMOTE_EOT_URL = "http://localhost:9999";
332
+ try {
333
+ const activity = Object.create(AgentActivity.prototype);
334
+ activity.agent = {
335
+ turnHandling: {
336
+ interruption: { enabled: false }
337
+ },
338
+ turnDetection: void 0,
339
+ stt: void 0,
340
+ vad: void 0,
341
+ llm: void 0
342
+ };
343
+ activity.agentSession = {
344
+ interruptionDetection: void 0,
345
+ turnDetection: "stt",
346
+ sessionOptions: {
347
+ turnHandling: {
348
+ interruption: defaultInterruptionOptions,
349
+ endpointing: defaultEndpointingOptions
350
+ }
351
+ },
352
+ stt: {
353
+ capabilities: {
354
+ alignedTranscript: true,
355
+ streaming: true
356
+ }
357
+ },
358
+ vad: {},
359
+ llm: void 0
360
+ };
361
+ activity.logger = { warn: vi.fn() };
362
+ expect(activity.resolveInterruptionDetector()).toBeUndefined();
363
+ expect(activity.logger.warn).not.toHaveBeenCalled();
364
+ } finally {
365
+ if (previousRemoteEotUrl === void 0) {
366
+ delete process.env.LIVEKIT_REMOTE_EOT_URL;
367
+ } else {
368
+ process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;
369
+ }
370
+ }
371
+ });
372
+ });
179
373
  });
180
374
  //# sourceMappingURL=agent.test.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/voice/agent.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { describe, expect, it, vi } from 'vitest';\nimport { z } from 'zod';\nimport { tool } from '../llm/index.js';\nimport { initializeLogger } from '../log.js';\nimport { Task } from '../utils.js';\nimport { Agent, AgentTask, _setActivityTaskInfo } from './agent.js';\nimport { agentActivityStorage } from './agent_activity.js';\n\ninitializeLogger({ pretty: false, level: 'error' });\n\ndescribe('Agent', () => {\n it('should create agent with basic instructions', () => {\n const instructions = 'You are a helpful assistant';\n const agent = new Agent({ instructions });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n });\n\n it('should create agent with instructions and tools', () => {\n const instructions = 'You are a helpful assistant with tools';\n\n // Create mock tools using the tool function\n const mockTool1 = tool({\n description: 'First test tool',\n parameters: z.object({}),\n execute: async () => 'tool1 result',\n });\n\n const mockTool2 = tool({\n description: 'Second test tool',\n parameters: z.object({\n input: z.string().describe('Input parameter'),\n }),\n execute: async ({ input }) => `tool2: ${input}`,\n });\n\n const agent = new Agent({\n instructions,\n tools: {\n getTool1: mockTool1,\n getTool2: mockTool2,\n },\n });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n\n // Assert tools are set correctly\n const agentTools = agent.toolCtx;\n expect(Object.keys(agentTools)).toHaveLength(2);\n expect(agentTools).toHaveProperty('getTool1');\n expect(agentTools).toHaveProperty('getTool2');\n\n // Verify tool properties with proper checks\n expect(agentTools.getTool1?.description).toBe('First test tool');\n expect(agentTools.getTool2?.description).toBe('Second test tool');\n });\n\n it('should return a copy of tools, not the original reference', () => {\n const instructions = 'You are a helpful assistant';\n const mockTool = tool({\n description: 'Test tool',\n parameters: z.object({}),\n execute: async () => 'result',\n });\n\n const tools = { testTool: mockTool };\n const agent = new Agent({ instructions, tools });\n\n const tools1 = agent.toolCtx;\n const tools2 = agent.toolCtx;\n\n // Should return different object references\n expect(tools1).not.toBe(tools2);\n expect(tools1).not.toBe(tools);\n\n // Should contain the same set of tools\n expect(tools1).toEqual(tools2);\n expect(tools1).toEqual(tools);\n });\n\n it('should require AgentTask to run inside task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n await expect(task.run()).rejects.toThrow('must be executed inside a Task context');\n });\n\n it('should require AgentTask to run inside inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'should only be awaited inside function tools or the onEnter/onExit methods of an Agent',\n );\n });\n\n it('should allow AgentTask run from inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const mockSession = {\n currentAgent: oldAgent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: async () => {},\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n });\n\n it('should require AgentTask to run inside AgentActivity context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'must be executed inside an AgentActivity context',\n );\n });\n\n it('should close old activity when current agent changes while AgentTask is pending', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const switchedAgent = new Agent({ instructions: 'switched agent' });\n const closeOldActivity = vi.fn(async () => {});\n\n const mockSession = {\n currentAgent: oldAgent as Agent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n mockSession.currentAgent = switchedAgent;\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: closeOldActivity,\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n expect(closeOldActivity).toHaveBeenCalledTimes(1);\n });\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/voice/agent.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { describe, expect, it, vi } from 'vitest';\nimport { z } from 'zod';\nimport { tool } from '../llm/index.js';\nimport { initializeLogger } from '../log.js';\nimport { Task } from '../utils.js';\nimport { Agent, AgentTask, _setActivityTaskInfo } from './agent.js';\nimport { AgentActivity, agentActivityStorage } from './agent_activity.js';\nimport { defaultEndpointingOptions } from './turn_config/endpointing.js';\nimport { defaultInterruptionOptions } from './turn_config/interruption.js';\n\nvi.mock('ofetch', () => ({ ofetch: vi.fn() }));\n\ninitializeLogger({ pretty: false, level: 'error' });\n\ndescribe('Agent', () => {\n it('should create agent with basic instructions', () => {\n const instructions = 'You are a helpful assistant';\n const agent = new Agent({ instructions });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n });\n\n it('should create agent with instructions and tools', () => {\n const instructions = 'You are a helpful assistant with tools';\n\n // Create mock tools using the tool function\n const mockTool1 = tool({\n description: 'First test tool',\n parameters: z.object({}),\n execute: async () => 'tool1 result',\n });\n\n const mockTool2 = tool({\n description: 'Second test tool',\n parameters: z.object({\n input: z.string().describe('Input parameter'),\n }),\n execute: async ({ input }) => `tool2: ${input}`,\n });\n\n const agent = new Agent({\n instructions,\n tools: {\n getTool1: mockTool1,\n getTool2: mockTool2,\n },\n });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n\n // Assert tools are set correctly\n const agentTools = agent.toolCtx;\n expect(Object.keys(agentTools)).toHaveLength(2);\n expect(agentTools).toHaveProperty('getTool1');\n expect(agentTools).toHaveProperty('getTool2');\n\n // Verify tool properties with proper checks\n expect(agentTools.getTool1?.description).toBe('First test tool');\n expect(agentTools.getTool2?.description).toBe('Second test tool');\n });\n\n it('should return a copy of tools, not the original reference', () => {\n const instructions = 'You are a helpful assistant';\n const mockTool = tool({\n description: 'Test tool',\n parameters: z.object({}),\n execute: async () => 'result',\n });\n\n const tools = { testTool: mockTool };\n const agent = new Agent({ instructions, tools });\n\n const tools1 = agent.toolCtx;\n const tools2 = agent.toolCtx;\n\n // Should return different object references\n expect(tools1).not.toBe(tools2);\n expect(tools1).not.toBe(tools);\n\n // Should contain the same set of tools\n expect(tools1).toEqual(tools2);\n expect(tools1).toEqual(tools);\n });\n\n it('should require AgentTask to run inside task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n await expect(task.run()).rejects.toThrow('must be executed inside a Task context');\n });\n\n it('should require AgentTask to run inside inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'should only be awaited inside function tools or the onEnter/onExit methods of an Agent',\n );\n });\n\n it('should allow AgentTask run from inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const mockSession = {\n currentAgent: oldAgent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: async () => {},\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n });\n\n it('should require AgentTask to run inside AgentActivity context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'must be executed inside an AgentActivity context',\n );\n });\n\n it('should close old activity when current agent changes while AgentTask is pending', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const switchedAgent = new Agent({ instructions: 'switched agent' });\n const closeOldActivity = vi.fn(async () => {});\n\n const mockSession = {\n currentAgent: oldAgent as Agent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n mockSession.currentAgent = switchedAgent;\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: closeOldActivity,\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n expect(closeOldActivity).toHaveBeenCalledTimes(1);\n });\n\n describe('Agent constructor option migration', () => {\n it('should set allowInterruptions to false via deprecated constructor field', () => {\n const agent = new Agent({ instructions: 'test', allowInterruptions: false });\n expect(agent.turnHandling?.interruption?.enabled).toBe(false);\n });\n\n it('should not set derived properties when no compatibility fields are provided', () => {\n const agent = new Agent({ instructions: 'test' });\n expect(agent.turnHandling).toBeUndefined();\n });\n\n it('should expose minConsecutiveSpeechDelay', () => {\n const agent = new Agent({ instructions: 'test', minConsecutiveSpeechDelay: 1.5 });\n expect(agent.minConsecutiveSpeechDelay).toBe(1.5);\n });\n\n it('should ignore deprecated constructor fields when turnHandling is provided', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n endpointing: { minDelay: 999 },\n interruption: {},\n turnDetection: 'vad',\n },\n allowInterruptions: false,\n });\n expect(agent.turnHandling?.endpointing?.minDelay).toBe(999);\n expect(agent.turnHandling?.endpointing?.maxDelay).toBeUndefined();\n expect(agent.turnHandling?.interruption?.enabled).toBeUndefined();\n expect(agent.turnHandling?.turnDetection).toBe('vad');\n });\n\n it('should let turnHandling override deprecated constructor fields on conflicts', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n endpointing: { minDelay: 999, maxDelay: 4000 },\n interruption: { enabled: true },\n turnDetection: 'vad',\n },\n allowInterruptions: false,\n turnDetection: 'stt',\n });\n expect(agent.turnHandling?.endpointing?.minDelay).toBe(999);\n expect(agent.turnHandling?.endpointing?.maxDelay).toBe(4000);\n expect(agent.turnHandling?.interruption?.enabled).toBe(true);\n expect(agent.turnHandling?.turnDetection).toBe('vad');\n });\n\n it('should set interruptionDetection from turnHandling.interruption.mode', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n interruption: { mode: 'adaptive' },\n endpointing: {},\n turnDetection: undefined,\n },\n });\n expect(agent.turnHandling?.interruption?.mode).toBe('adaptive');\n });\n\n it('should let AgentActivity prefer agent-level overrides over session defaults', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n endpointing: { minDelay: 111, maxDelay: 222 },\n interruption: { enabled: false },\n turnDetection: 'manual',\n },\n });\n const session = {\n options: {\n turnHandling: {\n endpointing: defaultEndpointingOptions,\n interruption: defaultInterruptionOptions,\n },\n },\n turnDetection: 'stt',\n useTtsAlignedTranscript: true,\n vad: undefined,\n stt: undefined,\n llm: undefined,\n tts: undefined,\n interruptionDetection: undefined,\n } as any;\n\n const activity = new AgentActivity(agent as any, session);\n\n expect(activity.allowInterruptions).toBe(false);\n expect(activity.turnDetection).toBe('manual');\n expect(activity.turnHandling.endpointing?.minDelay).toBe(111);\n expect(activity.turnHandling.endpointing?.maxDelay).toBe(222);\n });\n\n it('should disable adaptive interruption detection in default mode when prerequisites are missing', () => {\n const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;\n process.env.LIVEKIT_REMOTE_EOT_URL = 'http://localhost:9999';\n\n try {\n const agent = new Agent({ instructions: 'test' });\n const session = {\n options: {\n turnHandling: {\n endpointing: defaultEndpointingOptions,\n interruption: defaultInterruptionOptions,\n },\n },\n sessionOptions: {\n turnHandling: {\n endpointing: defaultEndpointingOptions,\n interruption: defaultInterruptionOptions,\n },\n },\n turnDetection: 'manual',\n useTtsAlignedTranscript: true,\n vad: {},\n stt: {\n capabilities: {\n alignedTranscript: true,\n streaming: true,\n },\n },\n llm: undefined,\n tts: undefined,\n interruptionDetection: undefined,\n } as any;\n\n const activity = new AgentActivity(agent as any, session);\n expect((activity as any).interruptionDetector).toBeUndefined();\n } finally {\n if (previousRemoteEotUrl === undefined) {\n delete process.env.LIVEKIT_REMOTE_EOT_URL;\n } else {\n process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;\n }\n }\n });\n\n it('should warn when session explicitly requests adaptive detection even if agent overrides it', () => {\n const activity = Object.create(AgentActivity.prototype) as any;\n activity.agent = {\n turnHandling: { interruption: { mode: 'vad' } },\n turnDetection: undefined,\n };\n activity.agentSession = {\n interruptionDetection: 'adaptive',\n turnDetection: 'manual',\n };\n activity.logger = { warn: vi.fn() };\n\n expect(activity.resolveInterruptionDetector()).toBeUndefined();\n expect(activity.logger.warn).toHaveBeenCalledWith(\n \"interruptionDetection is provided, but it's not compatible with the current configuration and will be disabled\",\n );\n });\n\n it('should disable adaptive interruption detection when interruptions are disabled', () => {\n const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;\n process.env.LIVEKIT_REMOTE_EOT_URL = 'http://localhost:9999';\n\n try {\n const activity = Object.create(AgentActivity.prototype) as any;\n activity.agent = {\n turnHandling: {\n interruption: { enabled: false },\n },\n turnDetection: undefined,\n stt: undefined,\n vad: undefined,\n llm: undefined,\n };\n activity.agentSession = {\n interruptionDetection: undefined,\n turnDetection: 'stt',\n sessionOptions: {\n turnHandling: {\n interruption: defaultInterruptionOptions,\n endpointing: defaultEndpointingOptions,\n },\n },\n stt: {\n capabilities: {\n alignedTranscript: true,\n streaming: true,\n },\n },\n vad: {},\n llm: undefined,\n };\n activity.logger = { warn: vi.fn() };\n\n expect(activity.resolveInterruptionDetector()).toBeUndefined();\n expect(activity.logger.warn).not.toHaveBeenCalled();\n } finally {\n if (previousRemoteEotUrl === undefined) {\n delete process.env.LIVEKIT_REMOTE_EOT_URL;\n } else {\n process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;\n }\n }\n });\n });\n});\n"],"mappings":"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","names":[]}
@@ -83,9 +83,10 @@ class AgentActivity {
83
83
  onRealtimeInputAudioTranscriptionCompleted = (ev) => this.onInputAudioTranscriptionCompleted(ev);
84
84
  onModelError = (ev) => this.onError(ev);
85
85
  onInterruptionOverlappingSpeech = (ev) => {
86
- this.agentSession.emit(import_events.AgentSessionEventTypes.UserOverlappingSpeech, ev);
86
+ this.agentSession.emit(import_events.AgentSessionEventTypes.OverlappingSpeech, ev);
87
87
  };
88
88
  onInterruptionMetricsCollected = (ev) => {
89
+ this.agentSession._usageCollector.collect(ev);
89
90
  this.agentSession.emit(
90
91
  import_events.AgentSessionEventTypes.MetricsCollected,
91
92
  (0, import_events.createMetricsCollectedEvent)({ metrics: ev })
@@ -94,6 +95,11 @@ class AgentActivity {
94
95
  onInterruptionError = (ev) => {
95
96
  const errorEvent = (0, import_events.createErrorEvent)(ev, this.interruptionDetector);
96
97
  this.agentSession.emit(import_events.AgentSessionEventTypes.Error, errorEvent);
98
+ if (!ev.recoverable) {
99
+ this.agentSession._onError(ev);
100
+ this.fallbackToVadInterruption();
101
+ return;
102
+ }
97
103
  this.agentSession._onError(ev);
98
104
  };
99
105
  /** @internal */
@@ -181,7 +187,7 @@ class AgentActivity {
181
187
  }
182
188
  }
183
189
  async _startSession(options) {
184
- var _a;
190
+ var _a, _b, _c, _d, _e;
185
191
  const { spanName, runOnEnter } = options;
186
192
  const startSpan = import_telemetry.tracer.startSpan({
187
193
  name: spanName,
@@ -256,10 +262,10 @@ class AgentActivity {
256
262
  turnDetector: typeof this.turnDetection === "string" ? void 0 : this.turnDetection,
257
263
  turnDetectionMode: this.turnDetectionMode,
258
264
  interruptionDetection: this.interruptionDetector,
259
- minEndpointingDelay: this.agentSession.options.turnHandling.endpointing.minDelay,
260
- maxEndpointingDelay: this.agentSession.options.turnHandling.endpointing.maxDelay,
265
+ minEndpointingDelay: ((_b = (_a = this.agent.turnHandling) == null ? void 0 : _a.endpointing) == null ? void 0 : _b.minDelay) ?? this.agentSession.sessionOptions.turnHandling.endpointing.minDelay,
266
+ maxEndpointingDelay: ((_d = (_c = this.agent.turnHandling) == null ? void 0 : _c.endpointing) == null ? void 0 : _d.maxDelay) ?? this.agentSession.sessionOptions.turnHandling.endpointing.maxDelay,
261
267
  rootSpanContext: this.agentSession.rootSpanContext,
262
- sttModel: (_a = this.stt) == null ? void 0 : _a.label,
268
+ sttModel: (_e = this.stt) == null ? void 0 : _e.label,
263
269
  sttProvider: this.getSttProvider(),
264
270
  getLinkedParticipant: () => {
265
271
  var _a2;
@@ -319,15 +325,31 @@ class AgentActivity {
319
325
  return this.realtimeSession;
320
326
  }
321
327
  get allowInterruptions() {
322
- var _a;
323
- return ((_a = this.agentSession.options.turnHandling.interruption) == null ? void 0 : _a.mode) !== false;
328
+ var _a, _b;
329
+ return ((_b = (_a = this.agent.turnHandling) == null ? void 0 : _a.interruption) == null ? void 0 : _b.enabled) ?? this.agentSession.sessionOptions.turnHandling.interruption.enabled;
324
330
  }
325
331
  get useTtsAlignedTranscript() {
326
332
  return this.agent.useTtsAlignedTranscript ?? this.agentSession.useTtsAlignedTranscript;
327
333
  }
328
334
  get turnDetection() {
329
- return this.agentSession.turnDetection;
330
- }
335
+ var _a;
336
+ return ((_a = this.agent.turnHandling) == null ? void 0 : _a.turnDetection) ?? this.agentSession.turnDetection;
337
+ }
338
+ get turnHandling() {
339
+ return this.agent.turnHandling ?? this.agentSession.sessionOptions.turnHandling;
340
+ }
341
+ // get minEndpointingDelay(): number {
342
+ // return (
343
+ // this.agent.turnHandling?.endpointing?.minDelay ??
344
+ // this.agentSession.sessionOptions.turnHandling.endpointing.minDelay
345
+ // );
346
+ // }
347
+ // get maxEndpointingDelay(): number {
348
+ // return (
349
+ // this.agent.turnHandling?.endpointing?.maxDelay ??
350
+ // this.agentSession.sessionOptions.turnHandling.endpointing.maxDelay
351
+ // );
352
+ // }
331
353
  get toolCtx() {
332
354
  return this.agent.toolCtx;
333
355
  }
@@ -393,12 +415,18 @@ class AgentActivity {
393
415
  }
394
416
  });
395
417
  this.audioStreamId = this.audioStream.addInputStream(audioStream);
396
- const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.pipeThrough(aecWarmupAudioFilter).tee();
397
- if (this.realtimeSession) {
418
+ if (this.realtimeSession && this.audioRecognition) {
419
+ const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.pipeThrough(aecWarmupAudioFilter).tee();
398
420
  this.realtimeSession.setInputAudioStream(realtimeAudioStream);
399
- }
400
- if (this.audioRecognition) {
401
421
  this.audioRecognition.setInputAudioStream(recognitionAudioStream);
422
+ } else if (this.realtimeSession) {
423
+ this.realtimeSession.setInputAudioStream(
424
+ this.audioStream.stream.pipeThrough(aecWarmupAudioFilter)
425
+ );
426
+ } else if (this.audioRecognition) {
427
+ this.audioRecognition.setInputAudioStream(
428
+ this.audioStream.stream.pipeThrough(aecWarmupAudioFilter)
429
+ );
402
430
  }
403
431
  }
404
432
  detachAudioInput() {
@@ -473,6 +501,7 @@ class AgentActivity {
473
501
  this.realtimeSpans.delete(ev.requestId);
474
502
  }
475
503
  }
504
+ this.agentSession._usageCollector.collect(ev);
476
505
  this.agentSession.emit(
477
506
  import_events.AgentSessionEventTypes.MetricsCollected,
478
507
  (0, import_events.createMetricsCollectedEvent)({ metrics: ev })
@@ -585,7 +614,10 @@ class AgentActivity {
585
614
  if (ev) {
586
615
  speechStartTime = speechStartTime - ev.speechDuration - ev.inferenceDuration;
587
616
  }
588
- this.agentSession._updateUserState("speaking", speechStartTime);
617
+ this.agentSession._updateUserState("speaking", {
618
+ lastSpeakingTime: speechStartTime,
619
+ otelContext: import_api.context.active()
620
+ });
589
621
  if (this.isInterruptionDetectionEnabled && this.audioRecognition) {
590
622
  this.audioRecognition.onStartOfOverlapSpeech(
591
623
  ev.speechDuration,
@@ -605,14 +637,17 @@ class AgentActivity {
605
637
  this.agentSession._userSpeakingSpan
606
638
  );
607
639
  }
608
- this.agentSession._updateUserState("listening", speechEndTime);
640
+ this.agentSession._updateUserState("listening", {
641
+ lastSpeakingTime: speechEndTime,
642
+ otelContext: import_api.context.active()
643
+ });
609
644
  }
610
645
  onVADInferenceDone(ev) {
611
646
  var _a;
612
647
  if (this.turnDetection === "manual" || this.turnDetection === "realtime_llm") {
613
648
  return;
614
649
  }
615
- if (ev.speechDuration >= ((_a = this.agentSession.options.turnHandling.interruption) == null ? void 0 : _a.minDuration)) {
650
+ if (ev.speechDuration >= ((_a = this.agentSession.sessionOptions.turnHandling.interruption) == null ? void 0 : _a.minDuration)) {
616
651
  this.interruptByAudioActivity();
617
652
  }
618
653
  }
@@ -627,11 +662,11 @@ class AgentActivity {
627
662
  if (this.llm instanceof import_llm.RealtimeModel && this.llm.capabilities.turnDetection) {
628
663
  return;
629
664
  }
630
- if (this.stt && ((_a = this.agentSession.options.turnHandling.interruption) == null ? void 0 : _a.minWords) > 0 && this.audioRecognition) {
665
+ if (this.stt && ((_a = this.agentSession.sessionOptions.turnHandling.interruption) == null ? void 0 : _a.minWords) > 0 && this.audioRecognition) {
631
666
  const text = this.audioRecognition.currentTranscript;
632
667
  const normalizedText = text ?? "";
633
668
  const wordCount = (0, import_word.splitWords)(normalizedText, true).length;
634
- if (wordCount < ((_b = this.agentSession.options.turnHandling.interruption) == null ? void 0 : _b.minWords)) {
669
+ if (wordCount < ((_b = this.agentSession.sessionOptions.turnHandling.interruption) == null ? void 0 : _b.minWords)) {
635
670
  return;
636
671
  }
637
672
  }
@@ -649,7 +684,7 @@ class AgentActivity {
649
684
  this.restoreInterruptionByAudioActivity();
650
685
  this.interruptByAudioActivity();
651
686
  if (this.audioRecognition) {
652
- this.audioRecognition.onEndOfAgentSpeech(ev.overlapStartedAt || ev.timestamp);
687
+ this.audioRecognition.onEndOfAgentSpeech(ev.overlapStartedAt || ev.detectedAt);
653
688
  }
654
689
  }
655
690
  onInterimTranscript(ev) {
@@ -687,7 +722,7 @@ class AgentActivity {
687
722
  }
688
723
  }
689
724
  onPreemptiveGeneration(info) {
690
- if (!this.agentSession.options.preemptiveGeneration || this.schedulingPaused || this._currentSpeech !== void 0 && !this._currentSpeech.interrupted || !(this.llm instanceof import_llm.LLM)) {
725
+ if (!this.agentSession.sessionOptions.preemptiveGeneration || this.schedulingPaused || this._currentSpeech !== void 0 && !this._currentSpeech.interrupted || !(this.llm instanceof import_llm.LLM)) {
691
726
  return;
692
727
  }
693
728
  this.cancelPreemptiveGeneration();
@@ -768,14 +803,14 @@ class AgentActivity {
768
803
  );
769
804
  return true;
770
805
  }
771
- if (this.stt && this.turnDetection !== "manual" && this._currentSpeech && this._currentSpeech.allowInterruptions && !this._currentSpeech.interrupted && ((_a = this.agentSession.options.turnHandling.interruption) == null ? void 0 : _a.minWords) > 0) {
806
+ if (this.stt && this.turnDetection !== "manual" && this._currentSpeech && this._currentSpeech.allowInterruptions && !this._currentSpeech.interrupted && ((_a = this.agentSession.sessionOptions.turnHandling.interruption) == null ? void 0 : _a.minWords) > 0) {
772
807
  const wordCount = (0, import_word.splitWords)(info.newTranscript, true).length;
773
- if (wordCount < ((_b = this.agentSession.options.turnHandling.interruption) == null ? void 0 : _b.minWords)) {
808
+ if (wordCount < ((_b = this.agentSession.sessionOptions.turnHandling.interruption) == null ? void 0 : _b.minWords)) {
774
809
  this.cancelPreemptiveGeneration();
775
810
  this.logger.info(
776
811
  {
777
812
  wordCount,
778
- minInterruptionWords: this.agentSession.options.turnHandling.interruption.minWords
813
+ minInterruptionWords: this.agentSession.sessionOptions.turnHandling.interruption.minWords
779
814
  },
780
815
  "skipping user input, word count below minimum interruption threshold"
781
816
  );
@@ -809,9 +844,12 @@ class AgentActivity {
809
844
  throw new Error("Speech queue is empty");
810
845
  }
811
846
  const speechHandle = heapItem[2];
847
+ if (speechHandle.interrupted || speechHandle.done()) {
848
+ continue;
849
+ }
812
850
  this._currentSpeech = speechHandle;
813
851
  speechHandle._authorizeGeneration();
814
- await speechHandle._waitForGeneration();
852
+ await speechHandle.waitIfNotInterrupted([speechHandle._waitForGeneration()]);
815
853
  this._currentSpeech = void 0;
816
854
  }
817
855
  const toWait = this.getDrainPendingSpeechTasks();
@@ -951,7 +989,16 @@ ${instructions}`;
951
989
  speech.interrupt(force);
952
990
  }
953
991
  (_a = this.realtimeSession) == null ? void 0 : _a.interrupt();
954
- if (currentSpeech === void 0) {
992
+ if (force) {
993
+ for (const task of this.speechTasks) {
994
+ task.cancel();
995
+ }
996
+ if (currentSpeech && !currentSpeech.done()) {
997
+ currentSpeech._markDone();
998
+ }
999
+ this.speechQueue.clear();
1000
+ future.resolve();
1001
+ } else if (currentSpeech === void 0) {
955
1002
  future.resolve();
956
1003
  } else {
957
1004
  currentSpeech.addDoneCallback(() => {
@@ -1398,9 +1445,7 @@ ${instructions}`;
1398
1445
  audioOutput.clearBuffer();
1399
1446
  }
1400
1447
  replyAbortController.abort();
1401
- await Promise.allSettled(
1402
- tasks.map((task) => task.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT))
1403
- );
1448
+ await (0, import_utils.cancelAndWait)(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);
1404
1449
  let forwardedText = (textOut == null ? void 0 : textOut.text) || "";
1405
1450
  if (audioOutput) {
1406
1451
  const playbackEv = await audioOutput.waitForPlayout();
@@ -1481,7 +1526,7 @@ ${instructions}`;
1481
1526
  speechHandle._markGenerationDone();
1482
1527
  await executeToolsTask.result;
1483
1528
  if (toolOutput.output.length === 0) return;
1484
- const { maxToolSteps } = this.agentSession.options;
1529
+ const { maxToolSteps } = this.agentSession.sessionOptions;
1485
1530
  if (speechHandle.numSteps >= maxToolSteps) {
1486
1531
  this.logger.warn(
1487
1532
  { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },
@@ -1832,7 +1877,7 @@ ${instructions}`;
1832
1877
  if (toolOutput.output.length === 0) {
1833
1878
  return;
1834
1879
  }
1835
- const { maxToolSteps } = this.agentSession.options;
1880
+ const { maxToolSteps } = this.agentSession.sessionOptions;
1836
1881
  if (speechHandle.numSteps >= maxToolSteps) {
1837
1882
  this.logger.warn(
1838
1883
  { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },
@@ -2051,15 +2096,16 @@ ${instructions}`;
2051
2096
  const unlock = await this.lock.lock();
2052
2097
  try {
2053
2098
  this.cancelPreemptiveGeneration();
2099
+ await (0, import_utils.cancelAndWait)(Array.from(this.speechTasks), AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);
2100
+ if (this._currentSpeech && !this._currentSpeech.done()) {
2101
+ this._currentSpeech._markDone();
2102
+ }
2054
2103
  await this._closeSessionResources();
2055
2104
  if (this._mainTask) {
2056
2105
  await this._mainTask.cancelAndWait();
2057
2106
  }
2058
2107
  if (this.interruptionDetector) {
2059
- this.interruptionDetector.off(
2060
- "user_overlapping_speech",
2061
- this.onInterruptionOverlappingSpeech
2062
- );
2108
+ this.interruptionDetector.off("overlapping_speech", this.onInterruptionOverlappingSpeech);
2063
2109
  this.interruptionDetector.off("metrics_collected", this.onInterruptionMetricsCollected);
2064
2110
  this.interruptionDetector.off("error", this.onInterruptionError);
2065
2111
  }
@@ -2069,21 +2115,33 @@ ${instructions}`;
2069
2115
  }
2070
2116
  }
2071
2117
  resolveInterruptionDetector() {
2072
- const interruptionDetection = this.agent.interruptionDetection ?? this.agentSession.interruptionDetection;
2118
+ var _a, _b;
2119
+ const agentInterruptionDetection = (_b = (_a = this.agent.turnHandling) == null ? void 0 : _a.interruption) == null ? void 0 : _b.mode;
2120
+ const sessionInterruptionDetection = this.agentSession.interruptionDetection;
2073
2121
  if (!(this.stt && this.stt.capabilities.alignedTranscript && this.stt.capabilities.streaming && this.vad && this.turnDetection !== "manual" && this.turnDetection !== "realtime_llm" && !(this.llm instanceof import_llm.RealtimeModel))) {
2074
- if (interruptionDetection === "adaptive") {
2122
+ if (agentInterruptionDetection === "adaptive" || sessionInterruptionDetection === "adaptive") {
2075
2123
  this.logger.warn(
2076
2124
  "interruptionDetection is provided, but it's not compatible with the current configuration and will be disabled"
2077
2125
  );
2078
- return void 0;
2079
2126
  }
2127
+ return void 0;
2128
+ }
2129
+ if (!this.allowInterruptions) {
2130
+ return void 0;
2131
+ }
2132
+ if (agentInterruptionDetection === "vad") {
2133
+ return void 0;
2080
2134
  }
2081
- if (interruptionDetection !== void 0 && interruptionDetection === false || interruptionDetection === "vad") {
2135
+ if (sessionInterruptionDetection === "vad") {
2136
+ return void 0;
2137
+ }
2138
+ if (agentInterruptionDetection === void 0 && sessionInterruptionDetection === void 0 && !(0, import_utils.isHosted)() && !(0, import_utils.isDevMode)()) {
2139
+ this.logger.info("adaptive interruption is disabled by default in production mode");
2082
2140
  return void 0;
2083
2141
  }
2084
2142
  try {
2085
2143
  const detector = new import_interruption_detector.AdaptiveInterruptionDetector();
2086
- detector.on("user_overlapping_speech", this.onInterruptionOverlappingSpeech);
2144
+ detector.on("overlapping_speech", this.onInterruptionOverlappingSpeech);
2087
2145
  detector.on("metrics_collected", this.onInterruptionMetricsCollected);
2088
2146
  detector.on("error", this.onInterruptionError);
2089
2147
  return detector;
@@ -2095,6 +2153,25 @@ ${instructions}`;
2095
2153
  restoreInterruptionByAudioActivity() {
2096
2154
  this.isInterruptionByAudioActivityEnabled = this.isDefaultInterruptionByAudioActivityEnabled;
2097
2155
  }
2156
+ fallbackToVadInterruption() {
2157
+ if (!this.isInterruptionDetectionEnabled) return;
2158
+ this.isInterruptionDetectionEnabled = false;
2159
+ this.restoreInterruptionByAudioActivity();
2160
+ if (this.interruptionDetector) {
2161
+ this.interruptionDetector.off("overlapping_speech", this.onInterruptionOverlappingSpeech);
2162
+ this.interruptionDetector.off("metrics_collected", this.onInterruptionMetricsCollected);
2163
+ this.interruptionDetector.off("error", this.onInterruptionError);
2164
+ this.interruptionDetector = void 0;
2165
+ }
2166
+ if (this.audioRecognition) {
2167
+ this.audioRecognition.disableInterruptionDetection().catch((err) => {
2168
+ this.logger.warn({ err }, "error while disabling interruption detection");
2169
+ });
2170
+ }
2171
+ this.logger.warn(
2172
+ "adaptive interruption disabled due to unrecoverable error, falling back to VAD-based interruption"
2173
+ );
2174
+ }
2098
2175
  async _closeSessionResources() {
2099
2176
  var _a, _b, _c;
2100
2177
  if (this.llm instanceof import_llm.LLM) {