@moureau/pipeflow 0.0.1 → 0.0.3

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 (336) hide show
  1. package/README.md +280 -130
  2. package/dist/cjs/agents/agent.js +1 -1
  3. package/dist/cjs/agents/agent.js.map +3 -3
  4. package/dist/cjs/agents/tools/tools.js +1 -1
  5. package/dist/cjs/agents/tools/tools.js.map +3 -3
  6. package/dist/cjs/client/client.js +2 -0
  7. package/dist/cjs/client/client.js.map +7 -0
  8. package/dist/cjs/client/index.js +2 -0
  9. package/dist/cjs/client/index.js.map +7 -0
  10. package/dist/cjs/client/json.js +2 -0
  11. package/dist/cjs/client/json.js.map +7 -0
  12. package/dist/cjs/client/protocol/websocket.js +2 -0
  13. package/dist/cjs/client/protocol/websocket.js.map +7 -0
  14. package/dist/cjs/client/protocol.js +2 -0
  15. package/dist/cjs/client/protocol.js.map +7 -0
  16. package/dist/cjs/conversations/conversation/conversation.js +1 -1
  17. package/dist/cjs/conversations/conversation/conversation.js.map +3 -3
  18. package/dist/cjs/conversations/conversations.js +1 -1
  19. package/dist/cjs/conversations/conversations.js.map +3 -3
  20. package/dist/cjs/conversations/index.js +1 -1
  21. package/dist/cjs/conversations/index.js.map +3 -3
  22. package/dist/cjs/conversations/orchestration/coordination/coordination.js +10 -0
  23. package/dist/cjs/conversations/orchestration/coordination/coordination.js.map +7 -0
  24. package/dist/cjs/conversations/orchestration/coordination/index.js +2 -0
  25. package/dist/cjs/conversations/orchestration/coordination/index.js.map +7 -0
  26. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js +4 -0
  27. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js.map +7 -0
  28. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/index.js +2 -0
  29. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/index.js.map +7 -0
  30. package/dist/cjs/conversations/orchestration/orchestrator/generation/generation.js +2 -0
  31. package/dist/cjs/conversations/orchestration/orchestrator/generation/generation.js.map +7 -0
  32. package/dist/cjs/conversations/orchestration/orchestrator/generation/index.js +2 -0
  33. package/dist/cjs/conversations/orchestration/orchestrator/generation/index.js.map +7 -0
  34. package/dist/cjs/conversations/orchestration/orchestrator/history/history.js +4 -0
  35. package/dist/cjs/conversations/orchestration/orchestrator/history/history.js.map +7 -0
  36. package/dist/cjs/conversations/orchestration/orchestrator/history/index.js +2 -0
  37. package/dist/cjs/conversations/orchestration/orchestrator/history/index.js.map +7 -0
  38. package/dist/cjs/conversations/orchestration/orchestrator/index.js +1 -1
  39. package/dist/cjs/conversations/orchestration/orchestrator/index.js.map +3 -3
  40. package/dist/cjs/conversations/orchestration/orchestrator/orchestrator.js +1 -2
  41. package/dist/cjs/conversations/orchestration/orchestrator/orchestrator.js.map +3 -3
  42. package/dist/cjs/conversations/orchestration/orchestrator/routing/index.js +2 -0
  43. package/dist/cjs/conversations/orchestration/orchestrator/routing/index.js.map +7 -0
  44. package/dist/cjs/conversations/orchestration/orchestrator/routing/routing.js +23 -0
  45. package/dist/cjs/conversations/orchestration/orchestrator/routing/routing.js.map +7 -0
  46. package/dist/cjs/conversations/orchestration/orchestrator/speech/index.js +2 -0
  47. package/dist/cjs/conversations/orchestration/orchestrator/speech/index.js.map +7 -0
  48. package/dist/cjs/conversations/orchestration/orchestrator/speech/speech.js +2 -0
  49. package/dist/cjs/conversations/orchestration/orchestrator/speech/speech.js.map +7 -0
  50. package/dist/cjs/conversations/orchestration/orchestrator/tools/index.js +2 -0
  51. package/dist/cjs/conversations/orchestration/orchestrator/tools/index.js.map +7 -0
  52. package/dist/cjs/conversations/orchestration/orchestrator/tools/tools.js +2 -0
  53. package/dist/cjs/conversations/orchestration/orchestrator/tools/tools.js.map +7 -0
  54. package/dist/cjs/conversations/orchestration/test-harness.js +2 -0
  55. package/dist/cjs/conversations/orchestration/test-harness.js.map +7 -0
  56. package/dist/cjs/conversations/orchestration/text-chunker/index.js +2 -0
  57. package/dist/cjs/conversations/orchestration/text-chunker/index.js.map +7 -0
  58. package/dist/cjs/conversations/orchestration/text-chunker/text-chunker.js +3 -0
  59. package/dist/cjs/conversations/orchestration/text-chunker/text-chunker.js.map +7 -0
  60. package/dist/cjs/conversations/stream/conversation-stream.js +2 -0
  61. package/dist/cjs/conversations/stream/conversation-stream.js.map +7 -0
  62. package/dist/cjs/conversations/stream/index.js +2 -0
  63. package/dist/cjs/conversations/stream/index.js.map +7 -0
  64. package/dist/cjs/conversations/types.js +1 -1
  65. package/dist/cjs/conversations/types.js.map +2 -2
  66. package/dist/cjs/index.js +1 -1
  67. package/dist/cjs/index.js.map +3 -3
  68. package/dist/cjs/persistence/adapters/sqlite/sqlite.js +18 -14
  69. package/dist/cjs/persistence/adapters/sqlite/sqlite.js.map +3 -3
  70. package/dist/cjs/pipeflow/index.js +2 -0
  71. package/dist/cjs/pipeflow/index.js.map +7 -0
  72. package/dist/cjs/pipeflow/pipeflow.js +2 -0
  73. package/dist/cjs/pipeflow/pipeflow.js.map +7 -0
  74. package/dist/cjs/providers/index.js +1 -1
  75. package/dist/cjs/providers/index.js.map +2 -2
  76. package/dist/cjs/providers/llm/adapters/claude/claude.js +5 -0
  77. package/dist/cjs/providers/llm/adapters/claude/claude.js.map +7 -0
  78. package/dist/cjs/providers/llm/adapters/claude/index.js +2 -0
  79. package/dist/cjs/providers/llm/adapters/claude/index.js.map +7 -0
  80. package/dist/cjs/providers/llm/adapters/deepseek/deepseek.js +1 -1
  81. package/dist/cjs/providers/llm/adapters/deepseek/deepseek.js.map +3 -3
  82. package/dist/cjs/providers/llm/adapters/index.js +1 -1
  83. package/dist/cjs/providers/llm/adapters/index.js.map +3 -3
  84. package/dist/cjs/providers/llm/adapters/openai/index.js +2 -0
  85. package/dist/cjs/providers/llm/adapters/openai/index.js.map +7 -0
  86. package/dist/cjs/providers/llm/adapters/openai/openai.js +2 -0
  87. package/dist/cjs/providers/llm/adapters/openai/openai.js.map +7 -0
  88. package/dist/cjs/providers/llm/adapters/openai-compatible.js +10 -0
  89. package/dist/cjs/providers/llm/adapters/openai-compatible.js.map +7 -0
  90. package/dist/cjs/providers/llm/adapters/openrouter/index.js +2 -0
  91. package/dist/cjs/providers/llm/adapters/openrouter/index.js.map +7 -0
  92. package/dist/cjs/providers/llm/adapters/openrouter/openrouter.js +2 -0
  93. package/dist/cjs/providers/llm/adapters/openrouter/openrouter.js.map +7 -0
  94. package/dist/cjs/providers/llm/index.js +1 -1
  95. package/dist/cjs/providers/llm/index.js.map +3 -3
  96. package/dist/cjs/providers/llm/toolmode/index.js +2 -0
  97. package/dist/cjs/providers/llm/toolmode/index.js.map +7 -0
  98. package/dist/cjs/providers/llm/toolmode/toolmode.js +2 -0
  99. package/dist/cjs/providers/llm/toolmode/toolmode.js.map +7 -0
  100. package/dist/cjs/providers/llm/types.js +1 -1
  101. package/dist/cjs/providers/llm/types.js.map +3 -3
  102. package/dist/cjs/providers/stt/adapters/deepgram/deepgram.js +1 -1
  103. package/dist/cjs/providers/stt/adapters/deepgram/deepgram.js.map +3 -3
  104. package/dist/cjs/providers/stt/adapters/index.js +1 -1
  105. package/dist/cjs/providers/stt/adapters/index.js.map +3 -3
  106. package/dist/cjs/providers/stt/adapters/openrouter/index.js +2 -0
  107. package/dist/cjs/providers/stt/adapters/openrouter/index.js.map +7 -0
  108. package/dist/cjs/providers/stt/adapters/openrouter/openrouter.js +2 -0
  109. package/dist/cjs/providers/stt/adapters/openrouter/openrouter.js.map +7 -0
  110. package/dist/cjs/providers/tts/adapters/index.js +1 -1
  111. package/dist/cjs/providers/tts/adapters/index.js.map +3 -3
  112. package/dist/cjs/providers/tts/adapters/kokoro/kokoro.js +4 -1
  113. package/dist/cjs/providers/tts/adapters/kokoro/kokoro.js.map +3 -3
  114. package/dist/cjs/providers/tts/adapters/openrouter/index.js +2 -0
  115. package/dist/cjs/providers/tts/adapters/openrouter/index.js.map +7 -0
  116. package/dist/cjs/providers/tts/adapters/openrouter/openrouter.js +2 -0
  117. package/dist/cjs/providers/tts/adapters/openrouter/openrouter.js.map +7 -0
  118. package/dist/cjs/transport/streamobject/field-stream/field-stream.js +2 -0
  119. package/dist/cjs/transport/streamobject/field-stream/field-stream.js.map +7 -0
  120. package/dist/cjs/transport/streamobject/field-stream/index.js +2 -0
  121. package/dist/cjs/transport/streamobject/field-stream/index.js.map +7 -0
  122. package/dist/cjs/transport/streamobject/index.js +2 -0
  123. package/dist/cjs/transport/streamobject/index.js.map +7 -0
  124. package/dist/cjs/transport/streamobject/json-adapter/index.js +2 -0
  125. package/dist/cjs/transport/streamobject/json-adapter/index.js.map +7 -0
  126. package/dist/cjs/transport/streamobject/json-adapter/json-adapter.js +4 -0
  127. package/dist/cjs/transport/streamobject/json-adapter/json-adapter.js.map +7 -0
  128. package/dist/cjs/transport/streamobject/reference/index.js +2 -0
  129. package/dist/cjs/transport/streamobject/reference/index.js.map +7 -0
  130. package/dist/cjs/transport/streamobject/reference/reference.js +2 -0
  131. package/dist/cjs/transport/streamobject/reference/reference.js.map +7 -0
  132. package/dist/cjs/transport/streamobject/stream-object/index.js +2 -0
  133. package/dist/cjs/transport/streamobject/stream-object/index.js.map +7 -0
  134. package/dist/cjs/transport/streamobject/stream-object/stream-object.js +2 -0
  135. package/dist/cjs/transport/streamobject/stream-object/stream-object.js.map +7 -0
  136. package/dist/esm/agents/agent.js +1 -1
  137. package/dist/esm/agents/agent.js.map +3 -3
  138. package/dist/esm/agents/tools/tools.js +1 -1
  139. package/dist/esm/agents/tools/tools.js.map +3 -3
  140. package/dist/esm/client/client.js +2 -0
  141. package/dist/esm/client/client.js.map +7 -0
  142. package/dist/esm/client/index.js +2 -0
  143. package/dist/esm/client/index.js.map +7 -0
  144. package/dist/esm/client/json.js +2 -0
  145. package/dist/esm/client/json.js.map +7 -0
  146. package/dist/esm/client/protocol/websocket.js +2 -0
  147. package/dist/esm/client/protocol/websocket.js.map +7 -0
  148. package/dist/esm/client/protocol.js +1 -0
  149. package/dist/esm/client/protocol.js.map +7 -0
  150. package/dist/esm/conversations/conversation/conversation.js +1 -1
  151. package/dist/esm/conversations/conversation/conversation.js.map +3 -3
  152. package/dist/esm/conversations/conversations.js +1 -1
  153. package/dist/esm/conversations/conversations.js.map +3 -3
  154. package/dist/esm/conversations/index.js +1 -1
  155. package/dist/esm/conversations/index.js.map +3 -3
  156. package/dist/esm/conversations/orchestration/coordination/coordination.js +10 -0
  157. package/dist/esm/conversations/orchestration/coordination/coordination.js.map +7 -0
  158. package/dist/esm/conversations/orchestration/coordination/index.js +2 -0
  159. package/dist/esm/conversations/orchestration/coordination/index.js.map +7 -0
  160. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js +4 -0
  161. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js.map +7 -0
  162. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/index.js +2 -0
  163. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/index.js.map +7 -0
  164. package/dist/esm/conversations/orchestration/orchestrator/generation/generation.js +2 -0
  165. package/dist/esm/conversations/orchestration/orchestrator/generation/generation.js.map +7 -0
  166. package/dist/esm/conversations/orchestration/orchestrator/generation/index.js +2 -0
  167. package/dist/esm/conversations/orchestration/orchestrator/generation/index.js.map +7 -0
  168. package/dist/esm/conversations/orchestration/orchestrator/history/history.js +4 -0
  169. package/dist/esm/conversations/orchestration/orchestrator/history/history.js.map +7 -0
  170. package/dist/esm/conversations/orchestration/orchestrator/history/index.js +2 -0
  171. package/dist/esm/conversations/orchestration/orchestrator/history/index.js.map +7 -0
  172. package/dist/esm/conversations/orchestration/orchestrator/index.js +1 -1
  173. package/dist/esm/conversations/orchestration/orchestrator/index.js.map +3 -3
  174. package/dist/esm/conversations/orchestration/orchestrator/orchestrator.js +1 -2
  175. package/dist/esm/conversations/orchestration/orchestrator/orchestrator.js.map +3 -3
  176. package/dist/esm/conversations/orchestration/orchestrator/routing/index.js +2 -0
  177. package/dist/esm/conversations/orchestration/orchestrator/routing/index.js.map +7 -0
  178. package/dist/esm/conversations/orchestration/orchestrator/routing/routing.js +23 -0
  179. package/dist/esm/conversations/orchestration/orchestrator/routing/routing.js.map +7 -0
  180. package/dist/esm/conversations/orchestration/orchestrator/speech/index.js +2 -0
  181. package/dist/esm/conversations/orchestration/orchestrator/speech/index.js.map +7 -0
  182. package/dist/esm/conversations/orchestration/orchestrator/speech/speech.js +2 -0
  183. package/dist/esm/conversations/orchestration/orchestrator/speech/speech.js.map +7 -0
  184. package/dist/esm/conversations/orchestration/orchestrator/tools/index.js +2 -0
  185. package/dist/esm/conversations/orchestration/orchestrator/tools/index.js.map +7 -0
  186. package/dist/esm/conversations/orchestration/orchestrator/tools/tools.js +2 -0
  187. package/dist/esm/conversations/orchestration/orchestrator/tools/tools.js.map +7 -0
  188. package/dist/esm/conversations/orchestration/test-harness.js +2 -0
  189. package/dist/esm/conversations/orchestration/test-harness.js.map +7 -0
  190. package/dist/esm/conversations/orchestration/text-chunker/index.js +2 -0
  191. package/dist/esm/conversations/orchestration/text-chunker/index.js.map +7 -0
  192. package/dist/esm/conversations/orchestration/text-chunker/text-chunker.js +3 -0
  193. package/dist/esm/conversations/orchestration/text-chunker/text-chunker.js.map +7 -0
  194. package/dist/esm/conversations/stream/conversation-stream.js +2 -0
  195. package/dist/esm/conversations/stream/conversation-stream.js.map +7 -0
  196. package/dist/esm/conversations/stream/index.js +2 -0
  197. package/dist/esm/conversations/stream/index.js.map +7 -0
  198. package/dist/esm/conversations/types.js +1 -1
  199. package/dist/esm/conversations/types.js.map +2 -2
  200. package/dist/esm/index.js +1 -1
  201. package/dist/esm/index.js.map +3 -3
  202. package/dist/esm/persistence/adapters/sqlite/sqlite.js +18 -14
  203. package/dist/esm/persistence/adapters/sqlite/sqlite.js.map +3 -3
  204. package/dist/esm/pipeflow/index.js +2 -0
  205. package/dist/esm/pipeflow/index.js.map +7 -0
  206. package/dist/esm/pipeflow/pipeflow.js +2 -0
  207. package/dist/esm/pipeflow/pipeflow.js.map +7 -0
  208. package/dist/esm/providers/index.js +1 -1
  209. package/dist/esm/providers/index.js.map +3 -3
  210. package/dist/esm/providers/llm/adapters/claude/claude.js +5 -0
  211. package/dist/esm/providers/llm/adapters/claude/claude.js.map +7 -0
  212. package/dist/esm/providers/llm/adapters/claude/index.js +2 -0
  213. package/dist/esm/providers/llm/adapters/claude/index.js.map +7 -0
  214. package/dist/esm/providers/llm/adapters/deepseek/deepseek.js +1 -1
  215. package/dist/esm/providers/llm/adapters/deepseek/deepseek.js.map +3 -3
  216. package/dist/esm/providers/llm/adapters/index.js +1 -1
  217. package/dist/esm/providers/llm/adapters/index.js.map +3 -3
  218. package/dist/esm/providers/llm/adapters/openai/index.js +2 -0
  219. package/dist/esm/providers/llm/adapters/openai/index.js.map +7 -0
  220. package/dist/esm/providers/llm/adapters/openai/openai.js +2 -0
  221. package/dist/esm/providers/llm/adapters/openai/openai.js.map +7 -0
  222. package/dist/esm/providers/llm/adapters/openai-compatible.js +10 -0
  223. package/dist/esm/providers/llm/adapters/openai-compatible.js.map +7 -0
  224. package/dist/esm/providers/llm/adapters/openrouter/index.js +2 -0
  225. package/dist/esm/providers/llm/adapters/openrouter/index.js.map +7 -0
  226. package/dist/esm/providers/llm/adapters/openrouter/openrouter.js +2 -0
  227. package/dist/esm/providers/llm/adapters/openrouter/openrouter.js.map +7 -0
  228. package/dist/esm/providers/llm/index.js +1 -1
  229. package/dist/esm/providers/llm/index.js.map +3 -3
  230. package/dist/esm/providers/llm/toolmode/index.js +2 -0
  231. package/dist/esm/providers/llm/toolmode/index.js.map +7 -0
  232. package/dist/esm/providers/llm/toolmode/toolmode.js +2 -0
  233. package/dist/esm/providers/llm/toolmode/toolmode.js.map +7 -0
  234. package/dist/esm/providers/llm/types.js +1 -0
  235. package/dist/esm/providers/llm/types.js.map +4 -4
  236. package/dist/esm/providers/stt/adapters/deepgram/deepgram.js +1 -1
  237. package/dist/esm/providers/stt/adapters/deepgram/deepgram.js.map +3 -3
  238. package/dist/esm/providers/stt/adapters/index.js +1 -1
  239. package/dist/esm/providers/stt/adapters/index.js.map +3 -3
  240. package/dist/esm/providers/stt/adapters/openrouter/index.js +2 -0
  241. package/dist/esm/providers/stt/adapters/openrouter/index.js.map +7 -0
  242. package/dist/esm/providers/stt/adapters/openrouter/openrouter.js +2 -0
  243. package/dist/esm/providers/stt/adapters/openrouter/openrouter.js.map +7 -0
  244. package/dist/esm/providers/tts/adapters/index.js +1 -1
  245. package/dist/esm/providers/tts/adapters/index.js.map +3 -3
  246. package/dist/esm/providers/tts/adapters/kokoro/kokoro.js +4 -1
  247. package/dist/esm/providers/tts/adapters/kokoro/kokoro.js.map +3 -3
  248. package/dist/esm/providers/tts/adapters/openrouter/index.js +2 -0
  249. package/dist/esm/providers/tts/adapters/openrouter/index.js.map +7 -0
  250. package/dist/esm/providers/tts/adapters/openrouter/openrouter.js +2 -0
  251. package/dist/esm/providers/tts/adapters/openrouter/openrouter.js.map +7 -0
  252. package/dist/esm/transport/streamobject/field-stream/field-stream.js +2 -0
  253. package/dist/esm/transport/streamobject/field-stream/field-stream.js.map +7 -0
  254. package/dist/esm/transport/streamobject/field-stream/index.js +2 -0
  255. package/dist/esm/transport/streamobject/field-stream/index.js.map +7 -0
  256. package/dist/esm/transport/streamobject/index.js +2 -0
  257. package/dist/esm/transport/streamobject/index.js.map +7 -0
  258. package/dist/esm/transport/streamobject/json-adapter/index.js +2 -0
  259. package/dist/esm/transport/streamobject/json-adapter/index.js.map +7 -0
  260. package/dist/esm/transport/streamobject/json-adapter/json-adapter.js +4 -0
  261. package/dist/esm/transport/streamobject/json-adapter/json-adapter.js.map +7 -0
  262. package/dist/esm/transport/streamobject/reference/index.js +2 -0
  263. package/dist/esm/transport/streamobject/reference/index.js.map +7 -0
  264. package/dist/esm/transport/streamobject/reference/reference.js +2 -0
  265. package/dist/esm/transport/streamobject/reference/reference.js.map +7 -0
  266. package/dist/esm/transport/streamobject/stream-object/index.js +2 -0
  267. package/dist/esm/transport/streamobject/stream-object/index.js.map +7 -0
  268. package/dist/esm/transport/streamobject/stream-object/stream-object.js +2 -0
  269. package/dist/esm/transport/streamobject/stream-object/stream-object.js.map +7 -0
  270. package/dist/types/agents/agent.d.ts +3 -0
  271. package/dist/types/agents/tools/tools.d.ts +28 -6
  272. package/dist/types/client/client.d.ts +186 -0
  273. package/dist/types/client/index.d.ts +31 -0
  274. package/dist/types/client/json.d.ts +13 -0
  275. package/dist/types/client/protocol/websocket.d.ts +56 -0
  276. package/dist/types/client/protocol.d.ts +46 -0
  277. package/dist/types/conversations/conversation/conversation.d.ts +130 -6
  278. package/dist/types/conversations/conversations.d.ts +35 -1
  279. package/dist/types/conversations/index.d.ts +2 -1
  280. package/dist/types/conversations/orchestration/coordination/coordination.d.ts +192 -0
  281. package/dist/types/conversations/orchestration/coordination/index.d.ts +2 -0
  282. package/dist/types/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.d.ts +108 -0
  283. package/dist/types/conversations/orchestration/orchestrator/coordination-runner/index.d.ts +2 -0
  284. package/dist/types/conversations/orchestration/orchestrator/generation/generation.d.ts +60 -0
  285. package/dist/types/conversations/orchestration/orchestrator/generation/index.d.ts +2 -0
  286. package/dist/types/conversations/orchestration/orchestrator/history/history.d.ts +62 -0
  287. package/dist/types/conversations/orchestration/orchestrator/history/index.d.ts +1 -0
  288. package/dist/types/conversations/orchestration/orchestrator/index.d.ts +10 -0
  289. package/dist/types/conversations/orchestration/orchestrator/orchestrator.d.ts +68 -31
  290. package/dist/types/conversations/orchestration/orchestrator/routing/index.d.ts +1 -0
  291. package/dist/types/conversations/orchestration/orchestrator/routing/routing.d.ts +19 -0
  292. package/dist/types/conversations/orchestration/orchestrator/speech/index.d.ts +2 -0
  293. package/dist/types/conversations/orchestration/orchestrator/speech/speech.d.ts +78 -0
  294. package/dist/types/conversations/orchestration/orchestrator/tools/index.d.ts +2 -0
  295. package/dist/types/conversations/orchestration/orchestrator/tools/tools.d.ts +65 -0
  296. package/dist/types/conversations/orchestration/test-harness.d.ts +100 -0
  297. package/dist/types/conversations/orchestration/text-chunker/index.d.ts +1 -0
  298. package/dist/types/conversations/orchestration/text-chunker/text-chunker.d.ts +39 -0
  299. package/dist/types/conversations/stream/conversation-stream.d.ts +42 -0
  300. package/dist/types/conversations/stream/index.d.ts +1 -0
  301. package/dist/types/conversations/types.d.ts +32 -0
  302. package/dist/types/index.d.ts +5 -38
  303. package/dist/types/pipeflow/index.d.ts +2 -0
  304. package/dist/types/pipeflow/pipeflow.d.ts +43 -0
  305. package/dist/types/providers/index.d.ts +1 -1
  306. package/dist/types/providers/llm/adapters/claude/claude.d.ts +45 -0
  307. package/dist/types/providers/llm/adapters/claude/index.d.ts +2 -0
  308. package/dist/types/providers/llm/adapters/deepseek/deepseek.d.ts +23 -2
  309. package/dist/types/providers/llm/adapters/index.d.ts +3 -0
  310. package/dist/types/providers/llm/adapters/openai/index.d.ts +2 -0
  311. package/dist/types/providers/llm/adapters/openai/openai.d.ts +45 -0
  312. package/dist/types/providers/llm/adapters/openai-compatible.d.ts +44 -0
  313. package/dist/types/providers/llm/adapters/openrouter/index.d.ts +2 -0
  314. package/dist/types/providers/llm/adapters/openrouter/openrouter.d.ts +60 -0
  315. package/dist/types/providers/llm/index.d.ts +5 -2
  316. package/dist/types/providers/llm/toolmode/index.d.ts +2 -0
  317. package/dist/types/providers/llm/toolmode/toolmode.d.ts +99 -0
  318. package/dist/types/providers/llm/types.d.ts +65 -0
  319. package/dist/types/providers/stt/adapters/deepgram/deepgram.d.ts +4 -1
  320. package/dist/types/providers/stt/adapters/index.d.ts +1 -0
  321. package/dist/types/providers/stt/adapters/openrouter/index.d.ts +2 -0
  322. package/dist/types/providers/stt/adapters/openrouter/openrouter.d.ts +196 -0
  323. package/dist/types/providers/tts/adapters/index.d.ts +1 -0
  324. package/dist/types/providers/tts/adapters/kokoro/kokoro.d.ts +18 -3
  325. package/dist/types/providers/tts/adapters/openrouter/index.d.ts +2 -0
  326. package/dist/types/providers/tts/adapters/openrouter/openrouter.d.ts +64 -0
  327. package/dist/types/transport/streamobject/field-stream/field-stream.d.ts +85 -0
  328. package/dist/types/transport/streamobject/field-stream/index.d.ts +2 -0
  329. package/dist/types/transport/streamobject/index.d.ts +8 -0
  330. package/dist/types/transport/streamobject/json-adapter/index.d.ts +2 -0
  331. package/dist/types/transport/streamobject/json-adapter/json-adapter.d.ts +65 -0
  332. package/dist/types/transport/streamobject/reference/index.d.ts +2 -0
  333. package/dist/types/transport/streamobject/reference/reference.d.ts +127 -0
  334. package/dist/types/transport/streamobject/stream-object/index.d.ts +2 -0
  335. package/dist/types/transport/streamobject/stream-object/stream-object.d.ts +31 -0
  336. package/package.json +29 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/conversations/orchestration/orchestrator/orchestrator.ts"],
4
- "sourcesContent": ["import type { Agent } from \"../../../agents/agent\";\nimport type { Conversation } from \"../../conversation/conversation\";\nimport type { Persistence } from \"../../../persistence/persistence\";\nimport type {\n LLM,\n LLMMessage,\n LLMToolCall,\n LLMToolDefinition,\n} from \"../../../providers/llm/types\";\nimport type { STT, STTSession } from \"../../../providers/stt/types\";\nimport type { TTS } from \"../../../providers/tts/types\";\nimport type { AudioChunk, ToolCallResult, Turn, UserId } from \"../../types\";\n\nexport interface OrchestratorOptions {\n conversation: Conversation;\n /**\n * The agent driving the realtime loop. Omit it for transcription-only\n * mode (audio in, turns and transcripts out \u2014 no LLM or TTS required).\n */\n agent?: Agent;\n /** Defaults to the agent's LLM. */\n llm?: LLM;\n stt: STT;\n /** Required when an agent is attached. */\n tts?: TTS;\n /** Used to rehydrate conversation history on start. */\n persistence?: Persistence;\n /** How long to wait for the application to resolve a tool call. */\n toolTimeoutMs?: number;\n /** Safety bound on tool-call round trips per generation. */\n maxToolIterations?: number;\n temperature?: number;\n maxTokens?: number;\n}\n\ninterface SttSessionEntry {\n session: STTSession;\n turnStartedAt: number | null;\n}\n\ninterface ResolvedToolCall {\n id: string;\n name: string;\n result?: unknown;\n error?: string;\n}\n\n/**\n * The realtime conversation state machine.\n *\n * Wires the conversation to the providers:\n *\n * ```text\n * audio-in \u2500\u2500\u25BA STT \u2500\u2500\u25BA turn \u2500\u2500\u25BA LLM \u2500\u2500\u25BA TTS \u2500\u2500\u25BA audio-out\n * \u2502\n * \u2514\u2500\u25BA tool-call \u2500\u2500\u25BA app resolves \u2500\u2500\u25BA resume\n * ```\n *\n * Deltas stream to TTS immediately (so the agent can narrate while a tool\n * runs), tool calls pause the generation until the application resolves\n * them, and interruptions cancel the current generation \u2014 discarding any\n * stale tool results or audio via a generation epoch.\n */\nexport class Orchestrator {\n private readonly conversation: Conversation;\n private readonly agent: Agent | undefined;\n private readonly llm: LLM | undefined;\n private readonly stt: STT;\n private readonly tts: TTS | undefined;\n private readonly persistence: Persistence | undefined;\n private readonly toolTimeoutMs: number;\n private readonly maxToolIterations: number;\n private readonly temperature: number | undefined;\n private readonly maxTokens: number | undefined;\n\n private started = false;\n private generating = false;\n private epoch = 0;\n private readonly unsubscribers: (() => void)[] = [];\n private readonly sttSessions = new Map<UserId, SttSessionEntry>();\n private readonly history: LLMMessage[] = [];\n private readonly toolWaiters = new Map<string, (result: ToolCallResult) => void>();\n private generationChain: Promise<void> = Promise.resolve();\n private speechChain: Promise<void> = Promise.resolve();\n private speechBuffer = \"\";\n private pendingTurns = 0;\n private pendingGenerations = 0;\n private audioSequence = 0;\n private turnSequence = 0;\n\n constructor(options: OrchestratorOptions) {\n const llm = options.llm ?? options.agent?.llm;\n if (!options.stt) {\n throw new Error(\"Orchestrator requires an STT provider\");\n }\n if (options.agent && !llm) {\n throw new Error(\n \"Orchestrator requires an LLM when an agent is attached: \" +\n \"pass one explicitly or configure the agent with one\",\n );\n }\n if (options.agent && !options.tts) {\n throw new Error(\"Orchestrator requires a TTS provider when an agent is attached\");\n }\n this.conversation = options.conversation;\n this.agent = options.agent;\n this.llm = llm;\n this.stt = options.stt;\n this.tts = options.tts;\n this.persistence = options.persistence;\n this.toolTimeoutMs = options.toolTimeoutMs ?? 30_000;\n this.maxToolIterations = options.maxToolIterations ?? 10;\n this.temperature = options.temperature;\n this.maxTokens = options.maxTokens;\n }\n\n /**\n * Attach to the conversation: rehydrate history from persistence and\n * subscribe to conversation events.\n */\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n if (this.persistence) {\n const [turns, generations] = await Promise.all([\n this.persistence.listTurns(this.conversation.id),\n this.persistence.listGenerations(this.conversation.id),\n ]);\n const entries: Array<\n | { at: number; kind: \"turn\"; turn: Turn }\n | { at: number; kind: \"generation\"; text: string }\n > = [\n ...turns.map((turn) => ({ at: turn.startedAt, kind: \"turn\" as const, turn })),\n ...generations\n .filter((generation) => generation.status === \"completed\")\n .map((generation) => ({\n at: generation.startedAt,\n kind: \"generation\" as const,\n text: generation.text,\n })),\n ].sort((a, b) => a.at - b.at);\n\n for (const entry of entries) {\n if (entry.kind === \"turn\") {\n this.history.push({\n role: \"user\",\n content: `${entry.turn.participantName}: ${entry.turn.text}`,\n });\n } else {\n this.history.push({ role: \"assistant\", content: entry.text });\n }\n }\n }\n\n this.unsubscribers.push(\n this.conversation.on(\"stop\", () => void this.stop()),\n this.conversation.on(\"audio-in\", (payload) => this.onAudioIn(payload)),\n this.conversation.on(\"interrupt\", () => this.onInterrupt()),\n this.conversation.on(\"tool-call-result\", (payload) =>\n this.onToolCallResult(payload.result),\n ),\n );\n }\n\n async stop(): Promise<void> {\n if (!this.started) return;\n this.started = false;\n this.epoch++;\n this.llm?.stop();\n this.tts?.stop();\n this.cancelToolWaiters(\"conversation stopped\");\n this.speechBuffer = \"\";\n for (const unsubscribe of this.unsubscribers) unsubscribe();\n this.unsubscribers.length = 0;\n const sessions = [...this.sttSessions.values()];\n this.sttSessions.clear();\n for (const { session } of sessions) {\n await session.end().catch(() => {});\n }\n }\n\n /**\n * Resolve once every queued and in-flight turn and generation has\n * finished processing. Useful for tests and graceful shutdown.\n */\n async whenIdle(): Promise<void> {\n for (;;) {\n while (\n this.pendingTurns > 0 ||\n this.pendingGenerations > 0 ||\n this.generating\n ) {\n await Bun.sleep(1);\n }\n // Give work scheduled in the same microtask turn a chance to register.\n await Promise.resolve();\n if (\n this.pendingTurns === 0 &&\n this.pendingGenerations === 0 &&\n !this.generating\n ) {\n return;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Conversation event handlers\n // -------------------------------------------------------------------------\n\n private onAudioIn(payload: { userId: UserId; audio: AudioChunk }): void {\n let entry = this.sttSessions.get(payload.userId);\n if (!entry) {\n const session = this.stt.start({});\n session.on(\"partial\", (text) => this.onPartial(payload.userId, text));\n session.on(\"final\", (text) => this.onFinal(payload.userId, text));\n session.on(\"error\", (error) => this.onProviderError(error));\n entry = { session, turnStartedAt: null };\n this.sttSessions.set(payload.userId, entry);\n }\n\n if (entry.turnStartedAt === null) {\n entry.turnStartedAt = Date.now();\n }\n entry.session.write(payload.audio.data);\n\n // Barge-in: a participant speaks while the agent is responding (or about\n // to). The interrupting audio is already queued to STT above.\n if (this.pendingGenerations > 0) {\n this.conversation.interrupt();\n }\n }\n\n private onPartial(userId: UserId, text: string): void {\n const trimmed = text.trim();\n if (!trimmed) return;\n this.conversation.emit(\"partial-transcript\", {\n conversationId: this.conversation.id,\n userId,\n text: trimmed,\n });\n }\n\n private onFinal(userId: UserId, text: string): void {\n const trimmed = text.trim();\n if (!trimmed) return;\n const participant = this.conversation.state.participants.get(userId);\n if (!participant) return;\n\n const entry = this.sttSessions.get(userId);\n const startedAt = entry?.turnStartedAt ?? Date.now();\n if (entry) entry.turnStartedAt = null;\n\n const turn: Turn = {\n id: crypto.randomUUID(),\n conversationId: this.conversation.id,\n participantId: userId,\n participantName: participant.aliases[0] ?? userId,\n text: trimmed,\n sequence: this.turnSequence++,\n startedAt,\n endedAt: Date.now(),\n };\n\n // Track synchronously so `whenIdle()` can observe in-flight work.\n this.pendingTurns++;\n void this.processTurn(turn);\n }\n\n private async processTurn(turn: Turn): Promise<void> {\n try {\n await this.conversation.pushTurn(turn);\n await this.conversation.pushTranscript({\n speaker: turn.participantName,\n speakerKind: \"participant\",\n text: turn.text,\n });\n this.history.push({\n role: \"user\",\n content: `${turn.participantName}: ${turn.text}`,\n });\n if (this.agent) {\n this.queueGeneration();\n }\n } finally {\n this.pendingTurns--;\n }\n }\n\n private onInterrupt(): void {\n this.epoch++;\n this.llm?.stop();\n this.tts?.stop();\n this.cancelToolWaiters(\"interrupted\");\n this.speechBuffer = \"\";\n }\n\n private onToolCallResult(result: ToolCallResult): void {\n const resolve = this.toolWaiters.get(result.id);\n if (!resolve) return; // stale, timed out, or already resolved\n this.toolWaiters.delete(result.id);\n resolve(result);\n }\n\n private onProviderError(error: Error): void {\n this.conversation.emit(\"error\", { conversationId: this.conversation.id, error });\n }\n\n // -------------------------------------------------------------------------\n // Generation\n // -------------------------------------------------------------------------\n\n private queueGeneration(): void {\n this.pendingGenerations++;\n const epoch = this.epoch;\n this.generationChain = this.generationChain.then(async () => {\n if (this.epoch !== epoch) {\n // Superseded by an interruption while queued.\n this.pendingGenerations--;\n return;\n }\n try {\n await this.generate();\n } finally {\n this.pendingGenerations--;\n }\n });\n }\n\n private async generate(): Promise<void> {\n const { agent, llm, tts } = this;\n if (!agent || !llm || !tts) return;\n this.generating = true;\n try {\n await this.runGeneration(this.epoch, agent, llm, tts);\n } finally {\n this.generating = false;\n }\n }\n\n private async runGeneration(\n epoch: number,\n agent: Agent,\n llm: LLM,\n tts: TTS,\n ): Promise<void> {\n await this.conversation.pushGeneration({\n id: crypto.randomUUID(),\n conversationId: this.conversation.id,\n agentName: agent.name,\n text: \"\",\n status: \"streaming\",\n startedAt: Date.now(),\n });\n\n const definitions: LLMToolDefinition[] = agent.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters ?? { type: \"object\", properties: {} },\n }));\n\n const messages: LLMMessage[] = [];\n if (agent.context) {\n messages.push({ role: \"system\", content: agent.context });\n }\n messages.push(...this.history);\n\n let text = \"\";\n\n try {\n for (let iteration = 0; iteration < this.maxToolIterations; iteration++) {\n if (this.epoch !== epoch) return;\n\n const toolCalls: LLMToolCall[] = [];\n let done = false;\n\n for await (const event of llm.stream({\n messages,\n tools: definitions,\n temperature: this.temperature,\n maxTokens: this.maxTokens,\n })) {\n if (this.epoch !== epoch) return;\n switch (event.type) {\n case \"delta\":\n text += event.content;\n this.feedDelta(event.content);\n break;\n case \"tool_call\":\n toolCalls.push({ id: event.id, name: event.name, arguments: event.arguments });\n break;\n case \"error\":\n throw event.error;\n case \"done\":\n done = true;\n }\n }\n\n if (this.epoch !== epoch) return;\n\n if (toolCalls.length > 0) {\n // Pause the response: let the narration finish, hand the calls to\n // the application, and resume once they are resolved.\n this.flushSpeech();\n messages.push({ role: \"assistant\", content: text, toolCalls });\n const results = await this.resolveToolCalls(toolCalls, epoch);\n if (this.epoch !== epoch) return;\n for (const result of results) {\n messages.push({\n role: \"tool\",\n toolCallId: result.id,\n name: result.name,\n content: JSON.stringify(\n result.error !== undefined ? { error: result.error } : result.result,\n ),\n });\n }\n continue;\n }\n\n if (done) break;\n }\n\n if (this.epoch !== epoch) return;\n\n this.flushSpeech();\n await this.speechChain;\n\n if (this.epoch !== epoch) return;\n\n await this.conversation.completeGeneration(text);\n await this.conversation.pushTranscript({\n speaker: agent.name,\n speakerKind: \"agent\",\n text,\n });\n this.history.push({ role: \"assistant\", content: text });\n } catch (error) {\n if (this.epoch !== epoch) return; // interrupted \u2014 discard everything\n this.conversation.emit(\"error\", {\n conversationId: this.conversation.id,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n // Finalize whatever was generated so the conversation state stays\n // consistent even though the provider failed.\n await this.conversation.completeGeneration(text);\n if (text) {\n await this.conversation.pushTranscript({\n speaker: agent.name,\n speakerKind: \"agent\",\n text,\n });\n this.history.push({ role: \"assistant\", content: text });\n }\n }\n }\n\n private async resolveToolCalls(\n calls: LLMToolCall[],\n epoch: number,\n ): Promise<ResolvedToolCall[]> {\n const resolutions = calls.map((call) => this.waitForToolResult(call.id, epoch));\n for (const call of calls) {\n let args: unknown;\n try {\n args = JSON.parse(call.arguments);\n } catch {\n args = call.arguments;\n }\n this.conversation.requestToolCall({\n id: call.id,\n name: call.name,\n arguments: args,\n });\n }\n\n const results = await Promise.all(resolutions);\n return results.map((result, index) => {\n const call = calls[index]!;\n return {\n id: result.id,\n name: call.name,\n result: \"result\" in result ? result.result : undefined,\n error: \"error\" in result ? result.error : undefined,\n };\n });\n }\n\n private waitForToolResult(id: string, _epoch: number): Promise<ToolCallResult> {\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n this.toolWaiters.delete(id);\n resolve({ id, error: `Tool call \"${id}\" timed out` });\n }, this.toolTimeoutMs);\n this.toolWaiters.set(id, (result) => {\n clearTimeout(timeout);\n resolve(result);\n });\n });\n }\n\n private cancelToolWaiters(reason: string): void {\n for (const [id, resolve] of [...this.toolWaiters]) {\n this.toolWaiters.delete(id);\n resolve({ id, error: reason });\n }\n }\n\n // -------------------------------------------------------------------------\n // Speech (LLM deltas \u2192 sentence buffering \u2192 TTS \u2192 audio-out)\n // -------------------------------------------------------------------------\n\n private feedDelta(delta: string): void {\n this.speechBuffer += delta;\n // Flush every complete sentence so multi-sentence deltas (and deltas\n // that span several sentences) are spoken as separate TTS requests.\n for (;;) {\n let boundary = -1;\n for (let i = 0; i < this.speechBuffer.length; i++) {\n const ch = this.speechBuffer[i];\n if (ch === \".\" || ch === \"!\" || ch === \"?\" || ch === \"\\n\") {\n boundary = i;\n break;\n }\n }\n if (boundary < 0) break;\n const sentence = this.speechBuffer.slice(0, boundary + 1).trim();\n this.speechBuffer = this.speechBuffer.slice(boundary + 1);\n if (sentence) this.speak(sentence);\n }\n }\n\n private flushSpeech(): void {\n const rest = this.speechBuffer.trim();\n this.speechBuffer = \"\";\n if (rest) this.speak(rest);\n }\n\n /** Synthesize a sentence and push the audio chunks out to the app. */\n private speak(sentence: string): void {\n const tts = this.tts;\n if (!tts) return;\n const epoch = this.epoch;\n this.speechChain = this.speechChain.then(async () => {\n if (!this.started || this.epoch !== epoch) return;\n try {\n for await (const chunk of tts.stream({ text: sentence })) {\n if (!this.started || this.epoch !== epoch) break;\n this.conversation.pushAudio({\n data: chunk,\n timestamp: Date.now(),\n sequence: this.audioSequence++,\n });\n }\n } catch (error) {\n if (this.epoch !== epoch) return; // interrupted\n this.conversation.emit(\"error\", {\n conversationId: this.conversation.id,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n });\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["orchestrator_exports", "__export", "Orchestrator", "__toCommonJS", "Orchestrator", "__name", "options", "llm", "turns", "generations", "entries", "turn", "generation", "a", "b", "entry", "payload", "unsubscribe", "sessions", "session", "text", "error", "userId", "trimmed", "participant", "startedAt", "result", "resolve", "epoch", "agent", "tts", "definitions", "tool", "messages", "iteration", "toolCalls", "done", "event", "results", "calls", "resolutions", "call", "args", "index", "id", "_epoch", "timeout", "reason", "delta", "boundary", "i", "ch", "sentence", "rest", "chunk"]
4
+ "sourcesContent": ["import type { Agent } from \"../../../agents/agent\";\nimport type { Tool } from \"../../../agents/tools/tools\";\nimport type { Conversation } from \"../../conversation/conversation\";\nimport type { Persistence } from \"../../../persistence/persistence\";\nimport type {\n LLM,\n LLMMessage,\n LLMToolDefinition,\n} from \"../../../providers/llm/types\";\nimport type { STT, STTSession } from \"../../../providers/stt/types\";\nimport type { TTS } from \"../../../providers/tts/types\";\nimport type { AudioChunk, Turn, UserId } from \"../../types\";\nimport type { CoordinationRegistration } from \"../coordination/coordination\";\nimport { ConversationHistory, type HistoryWindow } from \"./history/history\";\nimport { findAddressedAgent, pickAgent } from \"./routing/routing\";\nimport { GenerationRunner } from \"./generation/generation\";\nimport { SpeechPipeline } from \"./speech/speech\";\nimport { ToolCallManager } from \"./tools/tools\";\nimport { CoordinationRunner } from \"./coordination-runner/coordination-runner\";\n\n/**\n * Extra attempts after a transient provider failure that produced no output.\n * Kept tiny: each attempt is a fresh LLM request (latency + cost), and the\n * failure is usually a one-off upstream abort.\n */\nconst MAX_TRANSIENT_GENERATION_RETRIES = 1;\n\n/**\n * True for provider failures worth one silent retry: mid-stream aborts (the\n * Bedrock-via-OpenRouter failure nova models show as \"provider aborted the\n * stream\"), idle timeouts, and HTTP 429/5xx. Real failures (400, auth, bad\n * requests) are not retried.\n */\nfunction isTransientProviderError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return /aborted the stream|timed out|idle timeout|\\b(429|50[0-9])\\b/i.test(error.message);\n}\n\nexport interface OrchestratorOptions {\n conversation: Conversation;\n /**\n * The agents the orchestrator routes turns to. With more than one agent,\n * unaddressed turns run through the built-in `understand` coordination,\n * which can delegate to agents, ask the user, or answer directly. Omit\n * for transcription-only mode (audio in, turns and transcripts out \u2014 no\n * LLM or TTS required).\n */\n agents?: Agent[];\n /** Defaults to the first agent's LLM. */\n llm?: LLM;\n /** STT for voice turns. Omit for text-only conversations (`send()`). */\n stt?: STT;\n /** TTS for spoken output. Not required for text-only conversations. */\n tts?: TTS;\n /** Used to rehydrate conversation history on start. */\n persistence?: Persistence;\n /** How long to wait for a tool call to resolve (auto-executed or app-managed). */\n toolTimeoutMs?: number;\n /** Safety bound on tool-call round trips per generation. */\n maxToolIterations?: number;\n /**\n * Execute the agents' tools automatically (default `true`), feeding each\n * tool's result \u2014 or a caught error \u2014 back into the model loop, like\n * `Agent.run()` does. Set `false` for the application-managed contract:\n * listen for `tool-call` events and resolve each call yourself with\n * `conversation.resolveToolCall()`. The `tool-call` event fires in both\n * modes, so apps can observe every call.\n */\n autoExecuteTools?: boolean;\n /**\n * Additional coordinations the runtime can delegate to, registered by\n * name (the key is the coordination's name).\n */\n coordinations?: Record<string, CoordinationRegistration>;\n /** Safety bound on LLM reasoning steps per coordination execution. */\n maxCoordinationSteps?: number;\n temperature?: number;\n maxTokens?: number;\n /**\n * How much conversation history each LLM request carries (default\n * `{ maxTurns: 5, maxChars: 4000 }` \u2014 provider TTFT grows with input size,\n * and a bounded window keeps requests in the fast regime). Pass `false` to\n * always send the full history.\n */\n historyWindow?: HistoryWindow | false;\n /**\n * How many TTS synthesis requests may be in flight at once (default 2).\n * More lets the sentences of a multi-sentence reply synthesize in parallel\n * (kills the gaps between them) at the cost of provider concurrency \u2014 some\n * free TTS variants rate-limit concurrent requests. Passed through to the\n * speech pipeline; see `SpeechPipelineOptions.maxConcurrentRequests`.\n */\n maxConcurrentTtsRequests?: number;\n}\n\ninterface SttSessionEntry {\n session: STTSession;\n turnStartedAt: number | null;\n}\n\n/**\n * The realtime conversation state machine and multi-agent coordinator.\n *\n * Wires the conversation to the providers and routes each turn to an agent.\n * The heavy machinery lives in focused collaborators \u2014 history, routing,\n * generation, speech, tools, and coordination \u2014 so this class owns only the\n * lifecycle and event wiring:\n *\n * ```text\n * audio-in \u2500\u2500\u25BA STT \u2500\u2500\u25BA turn \u2500\u2500\u25BA coordinator \u2500\u2500\u25BA agent \u2500\u2500\u25BA LLM \u2500\u2500\u25BA TTS \u2500\u2500\u25BA audio-out\n * \u2502\n * \u2514\u2500\u25BA tool-call \u2500\u2500\u25BA tool runs \u2500\u2500\u25BA resume\n * ```\n *\n * Deltas stream to TTS immediately (so the agent can narrate while a tool\n * runs), tool calls pause the generation while the tool executes \u2014 the\n * framework runs the agent's own tools by default, or the application\n * resolves them when `autoExecuteTools` is off \u2014 and interruptions cancel\n * the current generation, discarding any stale tool results or audio via a\n * generation epoch.\n */\nexport class Orchestrator {\n private readonly conversation: Conversation;\n private readonly agents: Agent[];\n private readonly llm: LLM | undefined;\n private readonly stt: STT | undefined;\n private readonly tts: TTS | undefined;\n private readonly persistence: Persistence | undefined;\n private readonly maxToolIterations: number;\n private readonly historyWindow: HistoryWindow | false;\n private readonly temperature: number | undefined;\n private readonly maxTokens: number | undefined;\n\n private readonly history: ConversationHistory;\n private readonly speech: SpeechPipeline;\n private readonly tools: ToolCallManager;\n private readonly generation: GenerationRunner;\n private readonly coordination: CoordinationRunner;\n\n private started = false;\n private generating = false;\n private epoch = 0;\n private generationChain: Promise<void> = Promise.resolve();\n private readonly unsubscribers: (() => void)[] = [];\n private readonly sttSessions = new Map<UserId, SttSessionEntry>();\n private pendingTurns = 0;\n private pendingGenerations = 0;\n private turnSequence = 0;\n\n constructor(options: OrchestratorOptions) {\n const agents = options.agents ?? [];\n const llm = options.llm ?? agents[0]?.llm;\n if (agents.length > 0 && !llm) {\n throw new Error(\n \"Orchestrator requires an LLM when agents are attached: \" +\n \"pass one explicitly or configure an agent with one\",\n );\n }\n this.conversation = options.conversation;\n this.agents = agents;\n this.llm = llm;\n this.stt = options.stt;\n this.tts = options.tts;\n this.persistence = options.persistence;\n this.maxToolIterations = options.maxToolIterations ?? 10;\n this.historyWindow = options.historyWindow ?? { maxTurns: 5, maxChars: 4_000 };\n this.temperature = options.temperature;\n this.maxTokens = options.maxTokens;\n\n this.history = new ConversationHistory();\n this.speech = new SpeechPipeline({\n tts: this.tts,\n conversation: this.conversation,\n isCurrent: (epoch) => this.started && epoch === this.epoch,\n ...(options.maxConcurrentTtsRequests !== undefined\n ? { maxConcurrentRequests: options.maxConcurrentTtsRequests }\n : {}),\n });\n // The registry spans every agent's tools, so top-level generations and\n // delegated sub-generations both auto-execute the tools the routed agent\n // actually registered (the definitions each LLM sees are scoped to that\n // agent; on a name collision the last agent wins).\n const toolRegistry = new Map<string, Tool<never, unknown>>();\n for (const agent of agents) {\n for (const tool of agent.tools) toolRegistry.set(tool.name, tool);\n }\n this.tools = new ToolCallManager(this.conversation, options.toolTimeoutMs ?? 30_000, {\n tools: toolRegistry,\n autoExecute: options.autoExecuteTools ?? true,\n });\n this.generation = new GenerationRunner();\n this.coordination = new CoordinationRunner({\n conversation: this.conversation,\n agents: () => this.agents,\n llm: () => this.llm,\n history: this.history,\n historyWindow: this.historyWindow,\n speech: this.speech,\n generation: this.generation,\n tools: this.tools,\n maxCoordinationSteps: options.maxCoordinationSteps ?? 20,\n maxToolIterations: this.maxToolIterations,\n temperature: this.temperature,\n maxTokens: this.maxTokens,\n currentEpoch: () => this.epoch,\n isCurrent: (epoch) => this.started && epoch === this.epoch,\n });\n this.coordination.register(options.coordinations ?? {}, agents);\n }\n\n /**\n * Attach to the conversation: rehydrate history from persistence and\n * subscribe to conversation events.\n */\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n if (this.persistence) {\n const [turns, generations] = await Promise.all([\n this.persistence.listTurns(this.conversation.id),\n this.persistence.listGenerations(this.conversation.id),\n ]);\n this.history.rehydrate(turns, generations, this.conversation);\n }\n\n this.unsubscribers.push(\n this.conversation.on(\"stop\", () => void this.stop()),\n this.conversation.on(\"audio-in\", (payload) => this.onAudioIn(payload)),\n this.conversation.on(\"text-in\", ({ userId, text }) => this.onFinal(userId, text)),\n this.conversation.on(\"interrupt\", () => this.onInterrupt()),\n this.conversation.on(\"tool-call-result\", ({ result }) => this.tools.handleResult(result)),\n );\n }\n\n async stop(): Promise<void> {\n if (!this.started) return;\n this.started = false;\n this.epoch++;\n this.coordination.cancel();\n this.stopLlms();\n this.speech.stop();\n this.tools.cancelAll(\"conversation stopped\");\n for (const unsubscribe of this.unsubscribers) unsubscribe();\n this.unsubscribers.length = 0;\n const sessions = [...this.sttSessions.values()];\n this.sttSessions.clear();\n for (const { session } of sessions) {\n await session.end().catch(() => {});\n }\n }\n\n /**\n * Resolve once every queued and in-flight turn and generation has\n * finished processing. Useful for tests and graceful shutdown.\n */\n async whenIdle(): Promise<void> {\n for (;;) {\n while (\n this.pendingTurns > 0 ||\n this.pendingGenerations > 0 ||\n this.generating\n ) {\n await Bun.sleep(1);\n }\n // Give work scheduled in the same microtask turn a chance to register.\n await Promise.resolve();\n if (\n this.pendingTurns === 0 &&\n this.pendingGenerations === 0 &&\n !this.generating\n ) {\n return;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Conversation event handlers\n // -------------------------------------------------------------------------\n\n private onAudioIn(payload: { userId: UserId; audio: AudioChunk }): void {\n if (!this.stt) return; // text-only conversation\n let entry = this.sttSessions.get(payload.userId);\n if (!entry) {\n const session = this.stt.start({});\n session.on(\"partial\", (text) => this.onPartial(payload.userId, text));\n session.on(\"final\", (text) => this.onFinal(payload.userId, text));\n session.on(\"error\", (error) => this.onProviderError(error));\n entry = { session, turnStartedAt: null };\n this.sttSessions.set(payload.userId, entry);\n }\n\n if (entry.turnStartedAt === null) {\n entry.turnStartedAt = Date.now();\n }\n entry.session.write(payload.audio.data);\n\n if (this.coordination.hasPending()) {\n // The participant is answering a pending question \u2014 this audio is the\n // answer, not an interruption. Stop the question's playback only; the\n // coordination stays parked and resumes on the final transcript.\n this.speech.stop();\n return;\n }\n\n // Barge-in: a participant speaks while the agent is responding (or about\n // to). The interrupting audio is already queued to STT above.\n if (this.pendingGenerations > 0) {\n this.conversation.interrupt();\n }\n }\n\n private onPartial(userId: UserId, text: string): void {\n const trimmed = text.trim();\n if (!trimmed) return;\n this.conversation.emit(\"partial-transcript\", {\n conversationId: this.conversation.id,\n userId,\n text: trimmed,\n });\n }\n\n private onFinal(userId: UserId, text: string): void {\n const trimmed = text.trim();\n if (!trimmed) return;\n const participant = this.conversation.state.participants.get(userId);\n if (!participant) return;\n\n const entry = this.sttSessions.get(userId);\n const startedAt = entry?.turnStartedAt ?? Date.now();\n if (entry) entry.turnStartedAt = null;\n\n const turn: Turn = {\n id: crypto.randomUUID(),\n conversationId: this.conversation.id,\n participantId: userId,\n participantName: participant.aliases[0] ?? userId,\n text: trimmed,\n sequence: this.turnSequence++,\n startedAt,\n endedAt: Date.now(),\n };\n\n // Track synchronously so `whenIdle()` can observe in-flight work.\n this.pendingTurns++;\n void this.processTurn(turn);\n }\n\n private async processTurn(turn: Turn): Promise<void> {\n try {\n await this.conversation.pushTurn(turn);\n await this.conversation.pushTranscript({\n speaker: turn.participantName,\n speakerKind: \"participant\",\n text: turn.text,\n });\n this.history.addUserTurn(turn, this.conversation);\n if (this.agents.length === 0) return;\n\n if (this.coordination.hasPending()) {\n // The user answered a pending coordination question: resume it with\n // this turn instead of starting a fresh generation.\n this.enqueueCoordinationRun(() => this.coordination.resume(turn));\n return;\n }\n\n if (this.agents.length === 1 || findAddressedAgent(this.agents, turn.text)) {\n // Single-agent conversations, and turns that explicitly address an\n // agent by name/alias, route straight to that agent.\n this.queueGeneration(turn);\n return;\n }\n\n // Otherwise the built-in `understand` coordination decides: delegate to\n // agents, ask the user, or answer directly.\n this.enqueueCoordinationRun(() => this.coordination.runDefault(turn));\n } finally {\n this.pendingTurns--;\n }\n }\n\n private onInterrupt(): void {\n this.epoch++;\n this.coordination.cancel();\n this.stopLlms();\n this.speech.stop();\n this.tools.cancelAll(\"interrupted\");\n }\n\n /** Cancel every LLM in play: the shared one and each agent's own. */\n private stopLlms(): void {\n const seen = new Set<LLM>();\n if (this.llm) seen.add(this.llm);\n for (const agent of this.agents) {\n if (agent.llm) seen.add(agent.llm);\n }\n for (const llm of seen) llm.stop();\n }\n\n private onProviderError(error: Error): void {\n this.conversation.emit(\"error\", { conversationId: this.conversation.id, error });\n }\n\n // -------------------------------------------------------------------------\n // Generation\n // -------------------------------------------------------------------------\n\n private queueGeneration(turn: Turn): void {\n this.pendingGenerations++;\n const epoch = this.epoch;\n this.generationChain = this.generationChain.then(async () => {\n if (this.epoch !== epoch) {\n // Superseded by an interruption while queued.\n this.pendingGenerations--;\n return;\n }\n try {\n await this.generate(turn);\n } finally {\n this.pendingGenerations--;\n }\n });\n }\n\n private async generate(turn: Turn): Promise<void> {\n if (this.agents.length === 0) return;\n // The coordinator routes this turn to an agent by name/alias, falling\n // back to the first agent in the roster.\n const agent = pickAgent(this.agents, turn.text);\n if (!agent) return;\n // Prefer the routed agent's own LLM so agents with different providers\n // keep their intelligence; fall back to the shared LLM.\n const llm = agent.llm ?? this.llm;\n if (!llm) return;\n this.generating = true;\n try {\n await this.runGeneration(this.epoch, turn, agent, llm);\n } finally {\n this.generating = false;\n }\n }\n\n private async runGeneration(\n epoch: number,\n turn: Turn,\n agent: Agent,\n llm: LLM,\n ): Promise<void> {\n const generationId = crypto.randomUUID();\n await this.conversation.pushGeneration({\n id: generationId,\n conversationId: this.conversation.id,\n agentName: agent.name,\n text: \"\",\n status: \"streaming\",\n startedAt: Date.now(),\n });\n\n const definitions: LLMToolDefinition[] = agent.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters ?? { type: \"object\", properties: {} },\n }));\n\n const messages: LLMMessage[] = [];\n if (agent.context) {\n messages.push({ role: \"system\", name: agent.name, content: agent.context });\n }\n messages.push(...this.history.windowed(this.historyWindow));\n\n // Run the generation, retrying transient provider failures that happen\n // before anything was produced (e.g. the Bedrock-via-OpenRouter mid-stream\n // abort nova models show as \"provider aborted the stream\"). Retrying is\n // safe only when nothing was streamed and no tool ran \u2014 otherwise the\n // user would hear the partial reply twice or a tool would re-execute.\n let outcome: Awaited<ReturnType<GenerationRunner[\"run\"]>>;\n for (let attempt = 0; ; attempt++) {\n outcome = await this.generation.run({\n agentName: agent.name,\n llm,\n messages,\n tools: definitions,\n temperature: this.temperature,\n maxTokens: this.maxTokens,\n maxToolIterations: this.maxToolIterations,\n isCurrent: () => this.epoch === epoch,\n // With one agent every assistant turn is the same speaker, so the\n // per-agent `name` fields are redundant \u2014 and some providers render\n // them as role headers (\"Scout:\") that weaker models imitate by\n // prefixing every reply with the agent's name.\n agentNames: this.agents.length > 1,\n onDelta: (delta) => this.speech.feed(delta, epoch),\n resolveToolCalls: (calls) => this.tools.resolveCalls(calls),\n });\n if (this.epoch !== epoch) return;\n const retryable =\n attempt < MAX_TRANSIENT_GENERATION_RETRIES &&\n outcome.status === \"error\" &&\n outcome.text.length === 0 &&\n (outcome.toolRounds ?? 0) === 0 &&\n isTransientProviderError(outcome.error);\n if (!retryable) break;\n }\n\n // A stale run (interrupt/stop) is discarded entirely \u2014 the conversation\n // already marked the generation cancelled.\n if (this.epoch !== epoch) return;\n if (outcome.status === \"interrupted\") return;\n\n if (outcome.status === \"error\") {\n this.conversation.emit(\"error\", {\n conversationId: this.conversation.id,\n error: outcome.error instanceof Error ? outcome.error : new Error(String(outcome.error)),\n });\n // Finalize whatever was generated so the conversation state stays\n // consistent even though the provider failed.\n await this.conversation.completeGeneration(outcome.text);\n if (outcome.text) {\n await this.conversation.pushTranscript({\n speaker: agent.name,\n speakerKind: \"agent\",\n text: outcome.text,\n });\n this.history.addAssistant(agent.name, outcome.text);\n }\n return;\n }\n\n this.speech.flush(epoch);\n await this.speech.waitForIdle();\n if (this.epoch !== epoch) return;\n\n await this.conversation.completeGeneration(outcome.text);\n await this.conversation.pushTranscript({\n speaker: agent.name,\n speakerKind: \"agent\",\n text: outcome.text,\n });\n this.history.addAssistant(agent.name, outcome.text);\n }\n\n // -------------------------------------------------------------------------\n // Coordination (serialized with agent generations: one track at a time)\n // -------------------------------------------------------------------------\n\n private enqueueCoordinationRun(run: () => Promise<void>): void {\n this.pendingGenerations++;\n this.generationChain = this.generationChain.then(async () => {\n this.generating = true;\n try {\n await run();\n } finally {\n this.generating = false;\n this.pendingGenerations--;\n }\n });\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["orchestrator_exports", "__export", "Orchestrator", "__toCommonJS", "import_history", "import_routing", "import_generation", "import_speech", "import_tools", "import_coordination_runner", "MAX_TRANSIENT_GENERATION_RETRIES", "isTransientProviderError", "error", "__name", "Orchestrator", "options", "agents", "llm", "epoch", "toolRegistry", "agent", "tool", "turns", "generations", "payload", "userId", "text", "result", "unsubscribe", "sessions", "session", "entry", "trimmed", "participant", "startedAt", "turn", "seen", "generationId", "definitions", "messages", "outcome", "attempt", "delta", "calls", "run"]
7
7
  }
@@ -0,0 +1,2 @@
1
+ "use strict";var i=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var o=(n,d)=>{for(var r in d)i(n,r,{get:d[r],enumerable:!0})},p=(n,d,r,A)=>{if(d&&typeof d=="object"||typeof d=="function")for(let t of g(d))!m.call(n,t)&&t!==r&&i(n,t,{get:()=>d[t],enumerable:!(A=f(d,t))||A.enumerable});return n};var s=n=>p(i({},"__esModule",{value:!0}),n);var a={};o(a,{buildUnderstandPrompt:()=>e.buildUnderstandPrompt,findAddressedAgent:()=>e.findAddressedAgent,findAgentByName:()=>e.findAgentByName,pickAgent:()=>e.pickAgent});module.exports=s(a);var e=require("./routing.js");
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/conversations/orchestration/orchestrator/routing/index.ts"],
4
+ "sourcesContent": ["export {\n buildUnderstandPrompt,\n findAddressedAgent,\n findAgentByName,\n pickAgent,\n} from \"./routing\";\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,gLAAAE,EAAAF,GAAA,IAAAG,EAKO",
6
+ "names": ["routing_exports", "__export", "__toCommonJS", "import_routing"]
7
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";var s=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var u=Object.prototype.hasOwnProperty;var r=(n,t)=>s(n,"name",{value:t,configurable:!0});var c=(n,t)=>{for(var o in t)s(n,o,{get:t[o],enumerable:!0})},d=(n,t,o,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of l(t))!u.call(n,a)&&a!==o&&s(n,a,{get:()=>t[a],enumerable:!(e=i(t,a))||e.enumerable});return n};var f=n=>d(s({},"__esModule",{value:!0}),n);var p={};c(p,{buildUnderstandPrompt:()=>y,findAddressedAgent:()=>m,findAgentByName:()=>h,pickAgent:()=>g});module.exports=f(p);function g(n,t){if(n.length===0)return null;const o=t.toLowerCase();for(const e of n){if(e.name&&o.includes(e.name.toLowerCase()))return e;for(const a of e.aliases)if(o.includes(a.toLowerCase()))return e}return n[0]}r(g,"pickAgent");function m(n,t){const o=t.toLowerCase();for(const e of n){if(e.name&&o.includes(e.name.toLowerCase()))return e;for(const a of e.aliases)if(o.includes(a.toLowerCase()))return e}return null}r(m,"findAddressedAgent");function h(n,t){const o=t.trim().toLowerCase();for(const e of n){if(e.name.toLowerCase()===o)return e;for(const a of e.aliases)if(a.toLowerCase()===o)return e}return null}r(h,"findAgentByName");function y(n){return`You are the conversation coordinator.
2
+
3
+ Your job is to understand what the user is trying to accomplish and decide what
4
+ should happen next. You never perform domain work yourself.
5
+
6
+ The available agents are:
7
+ ${n.map(o=>{const e=o.aliases.length>0?` (aliases: ${o.aliases.join(", ")})`:"";return`- ${o.name}${e}`}).join(`
8
+ `)}
9
+
10
+ Decide the best next step and take exactly one:
11
+ - delegate to one or more agents ("agents"), each with a self-contained prompt
12
+ describing exactly what to do and any context they need;
13
+ - pass the work to another coordination ("coordination");
14
+ - ask the user for missing details ("clarify") when the request is ambiguous or
15
+ missing critical information \u2014 batch every missing detail into the "missing"
16
+ array in one call, never one question at a time. You may ask at most twice
17
+ per request; after that, state reasonable assumptions and answer;
18
+ - answer directly ("complete") when you have everything you need.
19
+
20
+ When you delegate, briefly narrate what you are doing, wait for the results,
21
+ then compose a single concise spoken answer and complete. Do not narrate your
22
+ internal reasoning.`}r(y,"buildUnderstandPrompt");
23
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/conversations/orchestration/orchestrator/routing/routing.ts"],
4
+ "sourcesContent": ["import type { Agent } from \"../../../../agents/agent\";\n\n/**\n * Pick the agent that should handle a turn.\n *\n * The first agent whose name or alias appears in the turn text wins;\n * otherwise the first agent in the roster is the default. Matching is\n * case-insensitive substring matching, so \"ask the technical specialist\"\n * addresses an agent named \"Technical Specialist\" (or aliased \"tech\").\n */\nexport function pickAgent(agents: readonly Agent[], text: string): Agent | null {\n if (agents.length === 0) return null;\n const normalized = text.toLowerCase();\n for (const agent of agents) {\n if (agent.name && normalized.includes(agent.name.toLowerCase())) return agent;\n for (const alias of agent.aliases) {\n if (normalized.includes(alias.toLowerCase())) return agent;\n }\n }\n return agents[0]!;\n}\n\n/**\n * Like `pickAgent` but without the default: only returns an agent the turn\n * explicitly addresses by name or alias.\n */\nexport function findAddressedAgent(\n agents: readonly Agent[],\n text: string,\n): Agent | null {\n const normalized = text.toLowerCase();\n for (const agent of agents) {\n if (agent.name && normalized.includes(agent.name.toLowerCase())) return agent;\n for (const alias of agent.aliases) {\n if (normalized.includes(alias.toLowerCase())) return agent;\n }\n }\n return null;\n}\n\n/** Resolve a task's agent by exact name or alias (case-insensitive). */\nexport function findAgentByName(\n agents: readonly Agent[],\n nameOrAlias: string,\n): Agent | null {\n const normalized = nameOrAlias.trim().toLowerCase();\n for (const agent of agents) {\n if (agent.name.toLowerCase() === normalized) return agent;\n for (const alias of agent.aliases) {\n if (alias.toLowerCase() === normalized) return agent;\n }\n }\n return null;\n}\n\n/** The built-in coordinator: understands the request and decides what's next. */\nexport function buildUnderstandPrompt(agents: readonly Agent[]): string {\n const roster = agents\n .map((agent) => {\n const aliases =\n agent.aliases.length > 0 ? ` (aliases: ${agent.aliases.join(\", \")})` : \"\";\n return `- ${agent.name}${aliases}`;\n })\n .join(\"\\n\");\n return `You are the conversation coordinator.\n\nYour job is to understand what the user is trying to accomplish and decide what\nshould happen next. You never perform domain work yourself.\n\nThe available agents are:\n${roster}\n\nDecide the best next step and take exactly one:\n- delegate to one or more agents (\"agents\"), each with a self-contained prompt\n describing exactly what to do and any context they need;\n- pass the work to another coordination (\"coordination\");\n- ask the user for missing details (\"clarify\") when the request is ambiguous or\n missing critical information \u2014 batch every missing detail into the \"missing\"\n array in one call, never one question at a time. You may ask at most twice\n per request; after that, state reasonable assumptions and answer;\n- answer directly (\"complete\") when you have everything you need.\n\nWhen you delegate, briefly narrate what you are doing, wait for the results,\nthen compose a single concise spoken answer and complete. Do not narrate your\ninternal reasoning.`;\n}\n"],
5
+ "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,2BAAAE,EAAA,uBAAAC,EAAA,oBAAAC,EAAA,cAAAC,IAAA,eAAAC,EAAAN,GAUO,SAASO,EAAUC,EAA0BC,EAA4B,CAC9E,GAAID,EAAO,SAAW,EAAG,OAAO,KAChC,MAAME,EAAaD,EAAK,YAAY,EACpC,UAAWE,KAASH,EAAQ,CAC1B,GAAIG,EAAM,MAAQD,EAAW,SAASC,EAAM,KAAK,YAAY,CAAC,EAAG,OAAOA,EACxE,UAAWC,KAASD,EAAM,QACxB,GAAID,EAAW,SAASE,EAAM,YAAY,CAAC,EAAG,OAAOD,CAEzD,CACA,OAAOH,EAAO,CAAC,CACjB,CAVgBK,EAAAN,EAAA,aAgBT,SAASO,EACdN,EACAC,EACc,CACd,MAAMC,EAAaD,EAAK,YAAY,EACpC,UAAWE,KAASH,EAAQ,CAC1B,GAAIG,EAAM,MAAQD,EAAW,SAASC,EAAM,KAAK,YAAY,CAAC,EAAG,OAAOA,EACxE,UAAWC,KAASD,EAAM,QACxB,GAAID,EAAW,SAASE,EAAM,YAAY,CAAC,EAAG,OAAOD,CAEzD,CACA,OAAO,IACT,CAZgBE,EAAAC,EAAA,sBAeT,SAASC,EACdP,EACAQ,EACc,CACd,MAAMN,EAAaM,EAAY,KAAK,EAAE,YAAY,EAClD,UAAWL,KAASH,EAAQ,CAC1B,GAAIG,EAAM,KAAK,YAAY,IAAMD,EAAY,OAAOC,EACpD,UAAWC,KAASD,EAAM,QACxB,GAAIC,EAAM,YAAY,IAAMF,EAAY,OAAOC,CAEnD,CACA,OAAO,IACT,CAZgBE,EAAAE,EAAA,mBAeT,SAASE,EAAsBT,EAAkC,CAQtE,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAPQA,EACZ,IAAKG,GAAU,CACd,MAAMO,EACJP,EAAM,QAAQ,OAAS,EAAI,cAAcA,EAAM,QAAQ,KAAK,IAAI,CAAC,IAAM,GACzE,MAAO,KAAKA,EAAM,IAAI,GAAGO,CAAO,EAClC,CAAC,EACA,KAAK;AAAA,CAAI,CAON;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAeR,CA7BgBL,EAAAI,EAAA",
6
+ "names": ["routing_exports", "__export", "buildUnderstandPrompt", "findAddressedAgent", "findAgentByName", "pickAgent", "__toCommonJS", "pickAgent", "agents", "text", "normalized", "agent", "alias", "__name", "findAddressedAgent", "findAgentByName", "nameOrAlias", "buildUnderstandPrompt", "aliases"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var r=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var n=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var l=(p,e)=>{for(var o in e)r(p,o,{get:e[o],enumerable:!0})},m=(p,e,o,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of n(e))!f.call(p,i)&&i!==o&&r(p,i,{get:()=>e[i],enumerable:!(t=h(e,i))||t.enumerable});return p};var s=p=>m(r({},"__esModule",{value:!0}),p);var x={};l(x,{SpeechPipeline:()=>c.SpeechPipeline});module.exports=s(x);var c=require("./speech.js");
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/conversations/orchestration/orchestrator/speech/index.ts"],
4
+ "sourcesContent": ["export { SpeechPipeline } from \"./speech\";\nexport type { SpeechPipelineOptions } from \"./speech\";\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,sDAAAE,EAAAF,GAAA,IAAAG,EAA+B",
6
+ "names": ["speech_exports", "__export", "__toCommonJS", "import_speech"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var o=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var u=(s,t)=>o(s,"name",{value:t,configurable:!0});var d=(s,t)=>{for(var e in t)o(s,e,{get:t[e],enumerable:!0})},T=(s,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of f(t))!l.call(s,i)&&i!==e&&o(s,i,{get:()=>t[i],enumerable:!(n=m(t,i))||n.enumerable});return s};var g=s=>T(o({},"__esModule",{value:!0}),s);var x={};d(x,{SpeechPipeline:()=>C});module.exports=g(x);var p=require("../../text-chunker/text-chunker.js");class C{static{u(this,"SpeechPipeline")}tts;conversation;isCurrent;maxConcurrent;chunker=new p.TextChunker;speechEpoch=0;chain=Promise.resolve();audioSequence=0;queue=[];inFlight=0;constructor(t){this.tts=t.tts,this.conversation=t.conversation,this.isCurrent=t.isCurrent,this.maxConcurrent=Math.max(1,t.maxConcurrentRequests??2)}feed(t,e){if(t.length!==0){this.conversation.noteTiming("firstToken"),this.conversation.pushTextDelta(t);for(const n of this.chunker.push(t))this.speak(n,e)}}flush(t){const e=this.chunker.flush();e&&this.speak(e,t)}speak(t,e){if(!this.tts)return;this.conversation.noteTiming("firstTtsText");const i=this.speechEpoch;this.queue.push({sentence:t,epoch:e,speechEpoch:i}),this.startNext()}startNext(){const t=this.tts;for(;t&&this.inFlight<this.maxConcurrent&&this.queue.length>0;){const{sentence:e,epoch:n,speechEpoch:i}=this.queue.shift();this.inFlight++;const h=t.stream({text:e}),a=h.next();a.catch(()=>{}),this.chain=this.chain.then(async()=>{try{if(!this.isCurrent(n)||this.speechEpoch!==i)return;this.conversation.noteTiming("firstTtsRequest");let r=!0;const c=await a;c.done||(r=!1,this.conversation.noteTiming("firstTtsAudio"),this.conversation.pushAudio({data:c.value,timestamp:Date.now(),sequence:this.audioSequence++}));for await(const v of h){if(!this.isCurrent(n)||this.speechEpoch!==i)break;r&&(r=!1,this.conversation.noteTiming("firstTtsAudio")),this.conversation.pushAudio({data:v,timestamp:Date.now(),sequence:this.audioSequence++})}}catch(r){if(!this.isCurrent(n)||this.speechEpoch!==i)return;this.conversation.emit("error",{conversationId:this.conversation.id,error:r instanceof Error?r:new Error(String(r))})}finally{this.inFlight--,this.startNext()}})}}stop(){this.speechEpoch++,this.chunker.clear(),this.queue.length=0,this.tts?.stop()}async waitForIdle(){for(;;){if(this.queue.length===0&&this.inFlight===0)return;await this.chain}}}
2
+ //# sourceMappingURL=speech.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/conversations/orchestration/orchestrator/speech/speech.ts"],
4
+ "sourcesContent": ["import type { Conversation } from \"../../../conversation/conversation\";\nimport type { TTS } from \"../../../../providers/tts/types\";\nimport { TextChunker } from \"../../text-chunker/text-chunker\";\n\nexport interface SpeechPipelineOptions {\n /** TTS provider; omitted for text-only conversations. */\n tts?: TTS;\n conversation: Conversation;\n /**\n * True while the generation that produced the speech is still current.\n * The captured generation epoch is passed back in, so an interrupt (epoch\n * bump) or a stop drops queued and in-flight synthesis.\n */\n isCurrent(epoch: number): boolean;\n /**\n * How many synthesis requests may be in flight at once. Sentences are\n * started as soon as a slot is free \u2014 the next one synthesizes while the\n * current one is still streaming \u2014 so playback never waits for the whole\n * reply, but a burst of many sentences can't flood the provider (free TTS\n * variants rate-limit concurrent requests). Default 2.\n */\n maxConcurrentRequests?: number;\n}\n\n/**\n * Turns the LLM delta stream into speakable audio: expose the text stream\n * semantically (`text-delta`), buffer sentences through the `TextChunker`,\n * and synthesize each chunk through the TTS provider on a serial chain.\n *\n * Owns the chunker, the speech epoch (bumped by `stop()`), the synthesis\n * chain, and the audio sequence \u2014 the orchestrator only decides *when*\n * speech is current.\n */\nexport class SpeechPipeline {\n private readonly tts: TTS | undefined;\n private readonly conversation: Conversation;\n private readonly isCurrent: (epoch: number) => boolean;\n private readonly maxConcurrent: number;\n private readonly chunker = new TextChunker();\n private speechEpoch = 0;\n private chain: Promise<void> = Promise.resolve();\n private audioSequence = 0;\n /** Flushed sentences still waiting for a synthesis slot. */\n private readonly queue: {\n sentence: string;\n epoch: number;\n speechEpoch: number;\n }[] = [];\n /** Synthesis requests started but not yet fully delivered. */\n private inFlight = 0;\n\n constructor(options: SpeechPipelineOptions) {\n this.tts = options.tts;\n this.conversation = options.conversation;\n this.isCurrent = options.isCurrent;\n this.maxConcurrent = Math.max(1, options.maxConcurrentRequests ?? 2);\n }\n\n /**\n * Stream an LLM delta to the application and the TTS pipeline. Empty\n * deltas (reasoning-only frames) are skipped so they never reach the\n * text-delta event or the chunker.\n */\n feed(delta: string, epoch: number): void {\n if (delta.length === 0) return;\n // First-token latency for the in-flight generation.\n this.conversation.noteTiming(\"firstToken\");\n // Expose the text stream semantically: applications can render or act on\n // partial replies without waiting for the generation to complete.\n this.conversation.pushTextDelta(delta);\n // The chunker turns the token stream into speakable chunks: strong\n // sentence boundaries flush immediately, long clauses flush at soft\n // boundaries, and nothing waits indefinitely for punctuation.\n for (const chunk of this.chunker.push(delta)) {\n this.speak(chunk, epoch);\n }\n }\n\n /** Speak any remaining buffered text as a final chunk. */\n flush(epoch: number): void {\n const rest = this.chunker.flush();\n if (rest) this.speak(rest, epoch);\n }\n\n /**\n * Queue a sentence for synthesis, starting it if a slot is free. The text\n * order is preserved end to end: requests start in flush order, and delivery\n * below is serialized through `chain`, so sentence N never overtakes N-1.\n */\n speak(sentence: string, epoch: number): void {\n const tts = this.tts;\n if (!tts) return;\n // Buffering boundary: the first sentence flushed to TTS.\n this.conversation.noteTiming(\"firstTtsText\");\n const speechEpoch = this.speechEpoch;\n this.queue.push({ sentence, epoch, speechEpoch });\n this.startNext();\n }\n\n /**\n * Start synthesis for queued sentences up to the concurrency bound. A\n * sentence's request is fired as soon as a slot is free \u2014 while the previous\n * sentence is still streaming/playing \u2014 so the first piece is ready first\n * and later pieces overlap it, without ever flooding the provider with one\n * request per sentence of a long reply.\n */\n private startNext(): void {\n const tts = this.tts;\n while (tts && this.inFlight < this.maxConcurrent && this.queue.length > 0) {\n const { sentence, epoch, speechEpoch } = this.queue.shift()!;\n this.inFlight++;\n // Begin synthesis immediately \u2014 the provider request overlaps the\n // previous sentence's playback. Consuming the first chunk eagerly is\n // what starts the request; delivery still happens in order through the\n // serial chain below.\n const stream = tts.stream({ text: sentence });\n const firstChunk = stream.next();\n void firstChunk.catch(() => {});\n this.chain = this.chain.then(async () => {\n try {\n if (!this.isCurrent(epoch) || this.speechEpoch !== speechEpoch) return;\n // The TTS provider was asked to synthesize.\n this.conversation.noteTiming(\"firstTtsRequest\");\n let first = true;\n const head = await firstChunk;\n if (!head.done) {\n first = false;\n // The provider produced its first audio chunk.\n this.conversation.noteTiming(\"firstTtsAudio\");\n this.conversation.pushAudio({\n data: head.value,\n timestamp: Date.now(),\n sequence: this.audioSequence++,\n });\n }\n // The generator's async iterator is the generator itself, so this\n // continues from where the eager `next()` left off.\n for await (const chunk of stream) {\n if (!this.isCurrent(epoch) || this.speechEpoch !== speechEpoch) {\n break;\n }\n if (first) {\n first = false;\n // The provider produced its first audio chunk.\n this.conversation.noteTiming(\"firstTtsAudio\");\n }\n this.conversation.pushAudio({\n data: chunk,\n timestamp: Date.now(),\n sequence: this.audioSequence++,\n });\n }\n } catch (error) {\n // A stop (speech epoch bump) or an interrupt (generation epoch bump)\n // aborts the stream \u2014 that's not a provider failure. Anything else\n // reaches the application as an error.\n if (!this.isCurrent(epoch) || this.speechEpoch !== speechEpoch) return;\n this.conversation.emit(\"error\", {\n conversationId: this.conversation.id,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n } finally {\n // The request is fully read and delivered: free the slot for the\n // next queued sentence.\n this.inFlight--;\n this.startNext();\n }\n });\n }\n }\n\n /**\n * Stop the current TTS playback and drop buffered text without cancelling\n * the generation (barge-in, interrupt, stop).\n */\n stop(): void {\n this.speechEpoch++;\n this.chunker.clear();\n this.queue.length = 0;\n this.tts?.stop();\n }\n\n /**\n * Resolve when every queued and in-flight sentence has been synthesized and\n * delivered. Unlike the delivery chain alone, this also waits for sentences\n * still waiting on a synthesis slot.\n */\n async waitForIdle(): Promise<void> {\n for (;;) {\n if (this.queue.length === 0 && this.inFlight === 0) return;\n await this.chain;\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["speech_exports", "__export", "SpeechPipeline", "__toCommonJS", "import_text_chunker", "SpeechPipeline", "__name", "options", "delta", "epoch", "chunk", "rest", "sentence", "speechEpoch", "tts", "stream", "firstChunk", "first", "head", "error"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var s=Object.prototype.hasOwnProperty;var x=(l,o)=>{for(var r in o)a(l,r,{get:o[r],enumerable:!0})},C=(l,o,r,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of m(o))!s.call(l,e)&&e!==r&&a(l,e,{get:()=>o[e],enumerable:!(t=f(o,e))||t.enumerable});return l};var T=l=>C(a({},"__esModule",{value:!0}),l);var d={};x(d,{ToolCallManager:()=>p.ToolCallManager});module.exports=T(d);var p=require("./tools.js");
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/conversations/orchestration/orchestrator/tools/index.ts"],
4
+ "sourcesContent": ["export { ToolCallManager } from \"./tools\";\nexport type { ResolvedToolCall } from \"./tools\";\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,wDAAAE,EAAAF,GAAA,IAAAG,EAAgC",
6
+ "names": ["tools_exports", "__export", "__toCommonJS", "import_tools"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var a=(n,e)=>s(n,"name",{value:e,configurable:!0});var m=(n,e)=>{for(var t in e)s(n,t,{get:e[t],enumerable:!0})},c=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of d(e))!v.call(n,o)&&o!==t&&s(n,o,{get:()=>e[o],enumerable:!(r=u(e,o))||r.enumerable});return n};var p=n=>c(s({},"__esModule",{value:!0}),n);var h={};m(h,{ToolCallManager:()=>g});module.exports=p(h);class g{static{a(this,"ToolCallManager")}conversation;timeoutMs;tools;autoExecute;waiters=new Map;constructor(e,t,r={}){this.conversation=e,this.timeoutMs=t,this.tools=r.tools,this.autoExecute=r.autoExecute??!0}async resolveCalls(e){const t=e.map(o=>this.wait(o.id));for(const o of e){const i=this.parseArguments(o.arguments);this.conversation.requestToolCall({id:o.id,name:o.name,arguments:i}),this.autoExecute&&this.runToolAndResolve(o,i)}return(await Promise.all(t)).map((o,i)=>{const l=e[i];return{id:o.id,name:l.name,result:"result"in o?o.result:void 0,error:"error"in o?o.error:void 0}})}handleResult(e){const t=this.waiters.get(e.id);t&&(this.waiters.delete(e.id),t(e))}cancelAll(e){for(const[t,r]of[...this.waiters])this.waiters.delete(t),r({id:t,error:e})}async runToolAndResolve(e,t){if(this.isPending(e.id))try{const r=this.tools?.get(e.name);if(!r){this.resolveIfPending({id:e.id,error:`Unknown tool "${e.name}"`});return}const o=await r.execute(t);this.resolveIfPending({id:e.id,result:o})}catch(r){this.resolveIfPending({id:e.id,error:r instanceof Error?r.message:String(r)})}}resolveIfPending(e){this.isPending(e.id)&&this.conversation.resolveToolCall(e)}isPending(e){return this.conversation.pendingToolCalls.some(t=>t.id===e)}parseArguments(e){try{return JSON.parse(e)}catch{return e}}wait(e){return new Promise(t=>{const r=setTimeout(()=>{this.waiters.delete(e),t({id:e,error:`Tool call "${e}" timed out`})},this.timeoutMs);this.waiters.set(e,o=>{clearTimeout(r),t(o)})})}}
2
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/conversations/orchestration/orchestrator/tools/tools.ts"],
4
+ "sourcesContent": ["import type { Conversation } from \"../../../conversation/conversation\";\nimport type { LLMToolCall } from \"../../../../providers/llm/types\";\nimport type { ToolCallResult } from \"../../../types\";\nimport type { Tool } from \"../../../../agents/tools/tools\";\n\nexport interface ResolvedToolCall {\n id: string;\n name: string;\n result?: unknown;\n error?: string;\n}\n\nexport interface ToolCallManagerOptions {\n /**\n * The tools the framework can execute on the agent's behalf, keyed by\n * name. Built from the orchestrated agents' tool registries.\n */\n tools?: ReadonlyMap<string, Tool<never, unknown>>;\n /**\n * Execute tool calls automatically (default `true`), feeding each tool's\n * result \u2014 or a caught error \u2014 back into the model loop. Set `false` to\n * keep the application-managed contract: listen for `tool-call`, execute\n * the tool in your own backend, and report back with\n * `resolveToolCall()`. `tool-call` events are still emitted for\n * visibility in either mode.\n */\n autoExecute?: boolean;\n}\n\n/**\n * Resolves the tool calls a generation issues. By default it runs the\n * matching tool itself (the conversation agents' tools auto-execute, exactly\n * like `Agent.run()`); with `autoExecute: false` it hands the calls to the\n * application and resolves them once the application reports back (or a\n * timeout fires). Stale results \u2014 timed out, already resolved, or superseded\n * by an interrupt \u2014 are dropped.\n */\nexport class ToolCallManager {\n private readonly conversation: Conversation;\n private readonly timeoutMs: number;\n private readonly tools: ReadonlyMap<string, Tool<never, unknown>> | undefined;\n private readonly autoExecute: boolean;\n private readonly waiters = new Map<string, (result: ToolCallResult) => void>();\n\n constructor(\n conversation: Conversation,\n timeoutMs: number,\n options: ToolCallManagerOptions = {},\n ) {\n this.conversation = conversation;\n this.timeoutMs = timeoutMs;\n this.tools = options.tools;\n this.autoExecute = options.autoExecute ?? true;\n }\n\n /**\n * Resolve a batch of tool calls. In auto-execute mode each call's tool\n * runs on the agent's behalf (errors caught and returned to the model);\n * otherwise the application resolves them. Either way the calls are\n * emitted as `tool-call` events and resolved in call order, with either a\n * result or an error string.\n */\n async resolveCalls(calls: LLMToolCall[]): Promise<ResolvedToolCall[]> {\n const resolutions = calls.map((call) => this.wait(call.id));\n for (const call of calls) {\n const args = this.parseArguments(call.arguments);\n this.conversation.requestToolCall({\n id: call.id,\n name: call.name,\n arguments: args,\n });\n if (this.autoExecute) {\n // Run the tool on the agent's behalf. The waiter above still bounds\n // the round trip if the tool hangs.\n void this.runToolAndResolve(call, args);\n }\n }\n\n const results = await Promise.all(resolutions);\n return results.map((result, index) => {\n const call = calls[index]!;\n return {\n id: result.id,\n name: call.name,\n result: \"result\" in result ? result.result : undefined,\n error: \"error\" in result ? result.error : undefined,\n };\n });\n }\n\n /** Resolve a waiter from a `tool-call-result` event; stale results drop. */\n handleResult(result: ToolCallResult): void {\n const resolve = this.waiters.get(result.id);\n if (!resolve) return;\n this.waiters.delete(result.id);\n resolve(result);\n }\n\n /** Force-resolve every pending call (interrupt, stop). */\n cancelAll(reason: string): void {\n for (const [id, resolve] of [...this.waiters]) {\n this.waiters.delete(id);\n resolve({ id, error: reason });\n }\n }\n\n /**\n * Execute one tool call and resolve it with the tool's result (or a\n * caught error). If the application already resolved the call in its\n * `tool-call` handler \u2014 the app-managed path \u2014 the tool is not run twice.\n */\n private async runToolAndResolve(call: LLMToolCall, args: unknown): Promise<void> {\n if (!this.isPending(call.id)) return;\n try {\n const tool = this.tools?.get(call.name);\n if (!tool) {\n this.resolveIfPending({\n id: call.id,\n error: `Unknown tool \"${call.name}\"`,\n });\n return;\n }\n const result = await tool.execute(args as never);\n this.resolveIfPending({ id: call.id, result });\n } catch (error) {\n this.resolveIfPending({\n id: call.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /** Resolve through the conversation only while the call is still pending. */\n private resolveIfPending(result: ToolCallResult): void {\n if (!this.isPending(result.id)) return;\n this.conversation.resolveToolCall(result);\n }\n\n private isPending(id: string): boolean {\n return this.conversation.pendingToolCalls.some((call) => call.id === id);\n }\n\n private parseArguments(argumentsJson: string): unknown {\n try {\n return JSON.parse(argumentsJson);\n } catch {\n return argumentsJson;\n }\n }\n\n private wait(id: string): Promise<ToolCallResult> {\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n this.waiters.delete(id);\n resolve({ id, error: `Tool call \"${id}\" timed out` });\n }, this.timeoutMs);\n this.waiters.set(id, (result) => {\n clearTimeout(timeout);\n resolve(result);\n });\n });\n }\n}\n"],
5
+ "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,qBAAAE,IAAA,eAAAC,EAAAH,GAqCO,MAAMI,CAAgB,CArC7B,MAqC6B,CAAAC,EAAA,wBACV,aACA,UACA,MACA,YACA,QAAU,IAAI,IAE/B,YACEC,EACAC,EACAC,EAAkC,CAAC,EACnC,CACA,KAAK,aAAeF,EACpB,KAAK,UAAYC,EACjB,KAAK,MAAQC,EAAQ,MACrB,KAAK,YAAcA,EAAQ,aAAe,EAC5C,CASA,MAAM,aAAaC,EAAmD,CACpE,MAAMC,EAAcD,EAAM,IAAKE,GAAS,KAAK,KAAKA,EAAK,EAAE,CAAC,EAC1D,UAAWA,KAAQF,EAAO,CACxB,MAAMG,EAAO,KAAK,eAAeD,EAAK,SAAS,EAC/C,KAAK,aAAa,gBAAgB,CAChC,GAAIA,EAAK,GACT,KAAMA,EAAK,KACX,UAAWC,CACb,CAAC,EACG,KAAK,aAGF,KAAK,kBAAkBD,EAAMC,CAAI,CAE1C,CAGA,OADgB,MAAM,QAAQ,IAAIF,CAAW,GAC9B,IAAI,CAACG,EAAQC,IAAU,CACpC,MAAMH,EAAOF,EAAMK,CAAK,EACxB,MAAO,CACL,GAAID,EAAO,GACX,KAAMF,EAAK,KACX,OAAQ,WAAYE,EAASA,EAAO,OAAS,OAC7C,MAAO,UAAWA,EAASA,EAAO,MAAQ,MAC5C,CACF,CAAC,CACH,CAGA,aAAaA,EAA8B,CACzC,MAAME,EAAU,KAAK,QAAQ,IAAIF,EAAO,EAAE,EACrCE,IACL,KAAK,QAAQ,OAAOF,EAAO,EAAE,EAC7BE,EAAQF,CAAM,EAChB,CAGA,UAAUG,EAAsB,CAC9B,SAAW,CAACC,EAAIF,CAAO,GAAK,CAAC,GAAG,KAAK,OAAO,EAC1C,KAAK,QAAQ,OAAOE,CAAE,EACtBF,EAAQ,CAAE,GAAAE,EAAI,MAAOD,CAAO,CAAC,CAEjC,CAOA,MAAc,kBAAkBL,EAAmBC,EAA8B,CAC/E,GAAK,KAAK,UAAUD,EAAK,EAAE,EAC3B,GAAI,CACF,MAAMO,EAAO,KAAK,OAAO,IAAIP,EAAK,IAAI,EACtC,GAAI,CAACO,EAAM,CACT,KAAK,iBAAiB,CACpB,GAAIP,EAAK,GACT,MAAO,iBAAiBA,EAAK,IAAI,GACnC,CAAC,EACD,MACF,CACA,MAAME,EAAS,MAAMK,EAAK,QAAQN,CAAa,EAC/C,KAAK,iBAAiB,CAAE,GAAID,EAAK,GAAI,OAAAE,CAAO,CAAC,CAC/C,OAASM,EAAO,CACd,KAAK,iBAAiB,CACpB,GAAIR,EAAK,GACT,MAAOQ,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAC9D,CAAC,CACH,CACF,CAGQ,iBAAiBN,EAA8B,CAChD,KAAK,UAAUA,EAAO,EAAE,GAC7B,KAAK,aAAa,gBAAgBA,CAAM,CAC1C,CAEQ,UAAUI,EAAqB,CACrC,OAAO,KAAK,aAAa,iBAAiB,KAAMN,GAASA,EAAK,KAAOM,CAAE,CACzE,CAEQ,eAAeG,EAAgC,CACrD,GAAI,CACF,OAAO,KAAK,MAAMA,CAAa,CACjC,MAAQ,CACN,OAAOA,CACT,CACF,CAEQ,KAAKH,EAAqC,CAChD,OAAO,IAAI,QAASF,GAAY,CAC9B,MAAMM,EAAU,WAAW,IAAM,CAC/B,KAAK,QAAQ,OAAOJ,CAAE,EACtBF,EAAQ,CAAE,GAAAE,EAAI,MAAO,cAAcA,CAAE,aAAc,CAAC,CACtD,EAAG,KAAK,SAAS,EACjB,KAAK,QAAQ,IAAIA,EAAKJ,GAAW,CAC/B,aAAaQ,CAAO,EACpBN,EAAQF,CAAM,CAChB,CAAC,CACH,CAAC,CACH,CACF",
6
+ "names": ["tools_exports", "__export", "ToolCallManager", "__toCommonJS", "ToolCallManager", "__name", "conversation", "timeoutMs", "options", "calls", "resolutions", "call", "args", "result", "index", "resolve", "reason", "id", "tool", "error", "argumentsJson", "timeout"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var u=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var i=(r,t)=>u(r,"name",{value:t,configurable:!0});var k=(r,t)=>{for(var e in t)u(r,e,{get:t[e],enumerable:!0})},A=(r,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of g(t))!b.call(r,s)&&s!==e&&u(r,s,{get:()=>t[s],enumerable:!(o=M(t,s))||o.enumerable});return r};var E=r=>A(u({},"__esModule",{value:!0}),r);var O={};k(O,{FakeLLM:()=>d,FakeSTT:()=>v,FakeSTTSession:()=>L,FakeTTS:()=>S,SlowTTS:()=>F,respond:()=>x,setup:()=>R,setupRoster:()=>H,speak:()=>q,waitFor:()=>C});module.exports=E(O);var p=require("../../agents/agent.js"),U=require("../../agents/tools/tools.js"),w=require("../conversation/conversation.js"),T=require("../../persistence/adapters/memory/memory.js"),h=require("./orchestrator/orchestrator.js");class d{constructor(t){this.script=t}script;static{i(this,"FakeLLM")}requests=[];stopCalls=[];controllers=new Set;async*stream(t){const e=new AbortController;this.controllers.add(e),this.requests.push(t);try{for await(const o of this.script(t,e.signal)){if(e.signal.aborted)throw new DOMException("The operation was aborted.","AbortError");yield o}}finally{this.controllers.delete(e)}}stop(){this.stopCalls.push(Date.now());for(const t of this.controllers)t.abort()}}class v{static{i(this,"FakeSTT")}sessions=[];startOptions=[];start(t={}){const e=new L;return this.sessions.push(e),this.startOptions.push(t),e}cancel(){}}class L{static{i(this,"FakeSTTSession")}written=[];ended=0;listeners={partial:new Set,final:new Set,error:new Set};write(t){this.written.push(t)}async end(){this.ended++}on(t,e){this.listeners[t].add(e)}emitPartial(t){for(const e of this.listeners.partial)e(t)}emitFinal(t){for(const e of this.listeners.final)e(t)}emitError(t){for(const e of this.listeners.error)e(t)}}class S{constructor(t){this.chunksFor=t}chunksFor;static{i(this,"FakeTTS")}requests=[];controllers=new Set;async*stream(t){this.requests.push(t);const e=new AbortController;this.controllers.add(e);try{for(const o of this.chunksFor(t.text)){if(e.signal.aborted)throw new DOMException("The operation was aborted.","AbortError");yield o}}finally{this.controllers.delete(e)}}stop(){for(const t of this.controllers)t.abort()}}class F{constructor(t,e=20){this.chunksFor=t;this.delayMs=e}chunksFor;delayMs;static{i(this,"SlowTTS")}requests=[];controllers=new Set;async*stream(t){this.requests.push(t);const e=new AbortController;this.controllers.add(e);try{for(const o of this.chunksFor(t.text)){if(await Bun.sleep(this.delayMs),e.signal.aborted)throw new DOMException("The operation was aborted.","AbortError");yield o}}finally{this.controllers.delete(e)}}stop(){for(const t of this.controllers)t.abort()}}function R(r){return(async()=>{const t=new T.MemoryPersistence,e=new w.Conversation({id:"conv-1",persistence:t}),o=r.llm??new d(r.script),s=new v,a=r.tts??new S(r.ttsChunks??(m=>[new TextEncoder().encode(m)])),c=new p.Agent({name:"Jarvis",context:r.context??"Be concise.",llm:o,tools:r.tools}),l=new h.Orchestrator({conversation:e,agents:[c],llm:o,stt:s,tts:a,persistence:t,toolTimeoutMs:r.toolTimeoutMs??3e4,historyWindow:r.historyWindow,autoExecuteTools:r.autoExecuteTools});return e.start(),await e.participate({userId:"alice",aliases:["al"]}),await l.start(),{conversation:e,orchestrator:l,llm:o,stt:s,tts:a,persistence:t}})()}i(R,"setup");async function C(r,t=2e3){const e=Date.now();for(;!r();){if(Date.now()-e>t)throw new Error("waitFor timed out");await Bun.sleep(2)}}i(C,"waitFor");async function q(r,t,e){r.conversation.listen({userId:t,audio:new Uint8Array([1])}),r.stt.sessions.at(-1).emitFinal(e),await r.orchestrator.whenIdle()}i(q,"speak");function x(r){return async function*(){yield{type:"delta",content:r},yield{type:"done"}}}i(x,"respond");function H(r){return(async()=>{const t=new T.MemoryPersistence,e=new w.Conversation({id:"conv-1",persistence:t}),o=new v,s=new S(n=>[new TextEncoder().encode(n)]),a=new d(r.coordinatorScript),c=new Map([["Jarvis",a]]),l=[new p.Agent({name:"Jarvis",context:"Be concise.",llm:a})];for(const[n,y]of Object.entries(r.scripts)){const f=new d(y);c.set(n,f),l.push(new p.Agent({name:n,context:`You are ${n}.`,llm:f,tools:r.tools?.[n]}))}if(l.length===1){const n=new d(x("ok"));c.set("Helper",n),l.push(new p.Agent({name:"Helper",context:"You help.",llm:n}))}for(const[n,y]of Object.entries(r.coordinations??{}))c.set(n,y.llm);const m=new h.Orchestrator({conversation:e,agents:l,llm:a,coordinations:r.coordinations,maxCoordinationSteps:r.maxCoordinationSteps,autoExecuteTools:r.autoExecuteTools,stt:o,tts:s,persistence:t});return e.start(),await e.participate({userId:"alice",aliases:["al"]}),await m.start(),{conversation:e,orchestrator:m,llm:a,stt:o,tts:s,persistence:t,llms:c}})()}i(H,"setupRoster");
2
+ //# sourceMappingURL=test-harness.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/conversations/orchestration/test-harness.ts"],
4
+ "sourcesContent": ["// Shared test doubles and harnesses for the orchestrator integration suites.\n// Import from here rather than re-implementing fakes per test file.\n\nimport { Agent } from \"../../agents/agent\";\nimport { Tool } from \"../../agents/tools/tools\";\nimport { Conversation } from \"../conversation/conversation\";\nimport { MemoryPersistence } from \"../../persistence/adapters/memory/memory\";\nimport { Orchestrator } from \"./orchestrator/orchestrator\";\nimport type { HistoryWindow } from \"./orchestrator/history/history\";\nimport type {\n LLM,\n LLMEvent,\n LLMRequest,\n} from \"../../providers/llm/types\";\nimport type { STT, STTOptions, STTSession } from \"../../providers/stt/types\";\nimport type { TTS, TTSRequest } from \"../../providers/tts/types\";\n\n// ---------------------------------------------------------------------------\n// Fake providers\n// ---------------------------------------------------------------------------\n\nexport type LLMScript = (request: LLMRequest, signal: AbortSignal) => AsyncIterable<LLMEvent>;\n\nexport class FakeLLM implements LLM {\n readonly requests: LLMRequest[] = [];\n readonly stopCalls: number[] = [];\n private readonly controllers = new Set<AbortController>();\n\n constructor(private readonly script: LLMScript) {}\n\n async *stream(request: LLMRequest): AsyncGenerator<LLMEvent> {\n const controller = new AbortController();\n this.controllers.add(controller);\n this.requests.push(request);\n try {\n for await (const event of this.script(request, controller.signal)) {\n if (controller.signal.aborted) {\n throw new DOMException(\"The operation was aborted.\", \"AbortError\");\n }\n yield event;\n }\n } finally {\n this.controllers.delete(controller);\n }\n }\n\n stop(): void {\n this.stopCalls.push(Date.now());\n for (const controller of this.controllers) controller.abort();\n }\n}\n\nexport class FakeSTT implements STT {\n readonly sessions: FakeSTTSession[] = [];\n readonly startOptions: STTOptions[] = [];\n\n start(options: STTOptions = {}): FakeSTTSession {\n const session = new FakeSTTSession();\n this.sessions.push(session);\n this.startOptions.push(options);\n return session;\n }\n\n cancel(): void {}\n}\n\nexport type FakeSessionEvent = \"partial\" | \"final\" | \"error\";\n\nexport class FakeSTTSession implements STTSession {\n readonly written: Uint8Array[] = [];\n ended = 0;\n private readonly listeners: Record<\n FakeSessionEvent,\n Set<(...args: any[]) => void>\n > = {\n partial: new Set(),\n final: new Set(),\n error: new Set(),\n };\n\n write(audio: Uint8Array): void {\n this.written.push(audio);\n }\n\n async end(): Promise<void> {\n this.ended++;\n }\n\n on(event: \"partial\", listener: (transcript: string) => void): void;\n on(event: \"final\", listener: (transcript: string) => void): void;\n on(event: \"error\", listener: (error: Error) => void): void;\n on(event: FakeSessionEvent, listener: (...args: any[]) => void): void {\n this.listeners[event].add(listener);\n }\n\n emitPartial(text: string): void {\n for (const listener of this.listeners.partial) listener(text);\n }\n\n emitFinal(text: string): void {\n for (const listener of this.listeners.final) listener(text);\n }\n\n emitError(error: Error): void {\n for (const listener of this.listeners.error) listener(error);\n }\n}\n\nexport class FakeTTS implements TTS {\n readonly requests: TTSRequest[] = [];\n private readonly controllers = new Set<AbortController>();\n\n constructor(private readonly chunksFor: (text: string) => Uint8Array[]) {}\n\n async *stream(request: TTSRequest): AsyncGenerator<Uint8Array> {\n this.requests.push(request);\n const controller = new AbortController();\n this.controllers.add(controller);\n try {\n for (const chunk of this.chunksFor(request.text)) {\n if (controller.signal.aborted) {\n throw new DOMException(\"The operation was aborted.\", \"AbortError\");\n }\n yield chunk;\n }\n } finally {\n this.controllers.delete(controller);\n }\n }\n\n stop(): void {\n for (const controller of this.controllers) controller.abort();\n }\n}\n\n/**\n * A TTS that streams one chunk at a time with a delay, so audio is still\n * mid-flight when an interrupt arrives.\n */\nexport class SlowTTS implements TTS {\n readonly requests: TTSRequest[] = [];\n private readonly controllers = new Set<AbortController>();\n\n constructor(\n private readonly chunksFor: (text: string) => Uint8Array[],\n private readonly delayMs = 20,\n ) {}\n\n async *stream(request: TTSRequest): AsyncGenerator<Uint8Array> {\n this.requests.push(request);\n const controller = new AbortController();\n this.controllers.add(controller);\n try {\n for (const chunk of this.chunksFor(request.text)) {\n await Bun.sleep(this.delayMs);\n if (controller.signal.aborted) {\n throw new DOMException(\"The operation was aborted.\", \"AbortError\");\n }\n yield chunk;\n }\n } finally {\n this.controllers.delete(controller);\n }\n }\n\n stop(): void {\n for (const controller of this.controllers) controller.abort();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Harness\n// ---------------------------------------------------------------------------\n\nexport type TtsHarness = FakeTTS | SlowTTS;\n\nexport interface Harness {\n conversation: Conversation;\n orchestrator: Orchestrator;\n llm: FakeLLM;\n stt: FakeSTT;\n tts: TtsHarness;\n persistence: MemoryPersistence;\n}\n\nexport function setup(options: {\n script: LLMScript;\n ttsChunks?: (text: string) => Uint8Array[];\n tts?: TtsHarness;\n tools?: Tool<never, unknown>[];\n toolTimeoutMs?: number;\n context?: string;\n /** Inject a real LLM (e.g. an adapter over a mocked fetch) instead of a scripted fake. */\n llm?: LLM;\n /** Override the conversation-history window (default 5 turns / 4k chars). */\n historyWindow?: HistoryWindow | false;\n /** Auto-execute the agent's tools (default true); see OrchestratorOptions. */\n autoExecuteTools?: boolean;\n}): Promise<Harness> {\n return (async () => {\n const persistence = new MemoryPersistence();\n const conversation = new Conversation({ id: \"conv-1\", persistence });\n const llm = options.llm ?? new FakeLLM(options.script);\n const stt = new FakeSTT();\n const tts =\n options.tts ??\n new FakeTTS(\n options.ttsChunks ?? ((text) => [new TextEncoder().encode(text)]),\n );\n const agent = new Agent({\n name: \"Jarvis\",\n context: options.context ?? \"Be concise.\",\n llm,\n tools: options.tools,\n });\n const orchestrator = new Orchestrator({\n conversation,\n agents: [agent],\n llm,\n stt,\n tts,\n persistence,\n toolTimeoutMs: options.toolTimeoutMs ?? 30_000,\n historyWindow: options.historyWindow,\n autoExecuteTools: options.autoExecuteTools,\n });\n\n conversation.start();\n await conversation.participate({ userId: \"alice\", aliases: [\"al\"] });\n await orchestrator.start();\n\n return {\n conversation,\n orchestrator,\n // When a real LLM is injected (the stall-recovery suite) it replaces\n // the fake; that suite never reads `.requests`, so the type stays the\n // fake's for the rest of the file.\n llm: llm as FakeLLM,\n stt,\n tts,\n persistence,\n };\n })();\n}\n\nexport async function waitFor(condition: () => boolean, timeoutMs = 2000): Promise<void> {\n const start = Date.now();\n while (!condition()) {\n if (Date.now() - start > timeoutMs) {\n throw new Error(\"waitFor timed out\");\n }\n await Bun.sleep(2);\n }\n}\n\nexport async function speak(harness: Harness, userId: string, text: string): Promise<void> {\n harness.conversation.listen({ userId, audio: new Uint8Array([1]) });\n harness.stt.sessions.at(-1)!.emitFinal(text);\n await harness.orchestrator.whenIdle();\n}\n\nexport function respond(text: string): LLMScript {\n return async function* () {\n yield { type: \"delta\", content: text };\n yield { type: \"done\" };\n };\n}\n\n// ---------------------------------------------------------------------------\n// Multi-agent roster harness (coordinator + named specialists)\n// ---------------------------------------------------------------------------\n\nexport type RosterHarness = Harness & { llms: Map<string, FakeLLM> };\n\nexport function setupRoster(options: {\n coordinatorScript: LLMScript;\n scripts: Record<string, LLMScript>;\n tools?: Record<string, Tool<never, unknown>[]>;\n coordinations?: Record<string, { prompt: string; llm: FakeLLM }>;\n maxCoordinationSteps?: number;\n /** Auto-execute the agents' tools (default true); see OrchestratorOptions. */\n autoExecuteTools?: boolean;\n}): Promise<RosterHarness> {\n return (async () => {\n const persistence = new MemoryPersistence();\n const conversation = new Conversation({ id: \"conv-1\", persistence });\n const stt = new FakeSTT();\n const tts = new FakeTTS((text) => [new TextEncoder().encode(text)]);\n\n const coordinatorLlm = new FakeLLM(options.coordinatorScript);\n const llms = new Map<string, FakeLLM>([[\"Jarvis\", coordinatorLlm]]);\n const agents: Agent[] = [\n new Agent({ name: \"Jarvis\", context: \"Be concise.\", llm: coordinatorLlm }),\n ];\n for (const [name, script] of Object.entries(options.scripts)) {\n const llm = new FakeLLM(script);\n llms.set(name, llm);\n agents.push(\n new Agent({\n name,\n context: `You are ${name}.`,\n llm,\n tools: options.tools?.[name],\n }),\n );\n }\n // The built-in `understand` coordination only activates with a roster of\n // more than one agent, so guarantee one for tests that only exercise the\n // coordination itself.\n if (agents.length === 1) {\n const helperLlm = new FakeLLM(respond(\"ok\"));\n llms.set(\"Helper\", helperLlm);\n agents.push(new Agent({ name: \"Helper\", context: \"You help.\", llm: helperLlm }));\n }\n for (const [name, coordination] of Object.entries(options.coordinations ?? {})) {\n llms.set(name, coordination.llm);\n }\n\n const orchestrator = new Orchestrator({\n conversation,\n agents,\n llm: coordinatorLlm,\n coordinations: options.coordinations,\n maxCoordinationSteps: options.maxCoordinationSteps,\n autoExecuteTools: options.autoExecuteTools,\n stt,\n tts,\n persistence,\n });\n\n conversation.start();\n await conversation.participate({ userId: \"alice\", aliases: [\"al\"] });\n await orchestrator.start();\n\n return { conversation, orchestrator, llm: coordinatorLlm, stt, tts, persistence, llms };\n })();\n}\n"],
5
+ "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,YAAAC,EAAA,mBAAAC,EAAA,YAAAC,EAAA,YAAAC,EAAA,YAAAC,EAAA,UAAAC,EAAA,gBAAAC,EAAA,UAAAC,EAAA,YAAAC,IAAA,eAAAC,EAAAZ,GAGA,IAAAa,EAAsB,8BACtBC,EAAqB,oCACrBC,EAA6B,wCAC7BC,EAAkC,oDAClCC,EAA6B,uCAgBtB,MAAMC,CAAuB,CAKlC,YAA6BC,EAAmB,CAAnB,YAAAA,CAAoB,CAApB,OA5B/B,MAuBoC,CAAAC,EAAA,gBACzB,SAAyB,CAAC,EAC1B,UAAsB,CAAC,EACf,YAAc,IAAI,IAInC,MAAO,OAAOC,EAA+C,CAC3D,MAAMC,EAAa,IAAI,gBACvB,KAAK,YAAY,IAAIA,CAAU,EAC/B,KAAK,SAAS,KAAKD,CAAO,EAC1B,GAAI,CACF,gBAAiBE,KAAS,KAAK,OAAOF,EAASC,EAAW,MAAM,EAAG,CACjE,GAAIA,EAAW,OAAO,QACpB,MAAM,IAAI,aAAa,6BAA8B,YAAY,EAEnE,MAAMC,CACR,CACF,QAAE,CACA,KAAK,YAAY,OAAOD,CAAU,CACpC,CACF,CAEA,MAAa,CACX,KAAK,UAAU,KAAK,KAAK,IAAI,CAAC,EAC9B,UAAWA,KAAc,KAAK,YAAaA,EAAW,MAAM,CAC9D,CACF,CAEO,MAAME,CAAuB,CApDpC,MAoDoC,CAAAJ,EAAA,gBACzB,SAA6B,CAAC,EAC9B,aAA6B,CAAC,EAEvC,MAAMK,EAAsB,CAAC,EAAmB,CAC9C,MAAMC,EAAU,IAAIC,EACpB,YAAK,SAAS,KAAKD,CAAO,EAC1B,KAAK,aAAa,KAAKD,CAAO,EACvBC,CACT,CAEA,QAAe,CAAC,CAClB,CAIO,MAAMC,CAAqC,CApElD,MAoEkD,CAAAP,EAAA,uBACvC,QAAwB,CAAC,EAClC,MAAQ,EACS,UAGb,CACF,QAAS,IAAI,IACb,MAAO,IAAI,IACX,MAAO,IAAI,GACb,EAEA,MAAMQ,EAAyB,CAC7B,KAAK,QAAQ,KAAKA,CAAK,CACzB,CAEA,MAAM,KAAqB,CACzB,KAAK,OACP,CAKA,GAAGL,EAAyBM,EAA0C,CACpE,KAAK,UAAUN,CAAK,EAAE,IAAIM,CAAQ,CACpC,CAEA,YAAYC,EAAoB,CAC9B,UAAWD,KAAY,KAAK,UAAU,QAASA,EAASC,CAAI,CAC9D,CAEA,UAAUA,EAAoB,CAC5B,UAAWD,KAAY,KAAK,UAAU,MAAOA,EAASC,CAAI,CAC5D,CAEA,UAAUC,EAAoB,CAC5B,UAAWF,KAAY,KAAK,UAAU,MAAOA,EAASE,CAAK,CAC7D,CACF,CAEO,MAAMC,CAAuB,CAIlC,YAA6BC,EAA2C,CAA3C,eAAAA,CAA4C,CAA5C,UAhH/B,MA4GoC,CAAAb,EAAA,gBACzB,SAAyB,CAAC,EAClB,YAAc,IAAI,IAInC,MAAO,OAAOC,EAAiD,CAC7D,KAAK,SAAS,KAAKA,CAAO,EAC1B,MAAMC,EAAa,IAAI,gBACvB,KAAK,YAAY,IAAIA,CAAU,EAC/B,GAAI,CACF,UAAWY,KAAS,KAAK,UAAUb,EAAQ,IAAI,EAAG,CAChD,GAAIC,EAAW,OAAO,QACpB,MAAM,IAAI,aAAa,6BAA8B,YAAY,EAEnE,MAAMY,CACR,CACF,QAAE,CACA,KAAK,YAAY,OAAOZ,CAAU,CACpC,CACF,CAEA,MAAa,CACX,UAAWA,KAAc,KAAK,YAAaA,EAAW,MAAM,CAC9D,CACF,CAMO,MAAMa,CAAuB,CAIlC,YACmBF,EACAG,EAAU,GAC3B,CAFiB,eAAAH,EACA,aAAAG,CAChB,CAFgB,UACA,QAjJrB,MA2IoC,CAAAhB,EAAA,gBACzB,SAAyB,CAAC,EAClB,YAAc,IAAI,IAOnC,MAAO,OAAOC,EAAiD,CAC7D,KAAK,SAAS,KAAKA,CAAO,EAC1B,MAAMC,EAAa,IAAI,gBACvB,KAAK,YAAY,IAAIA,CAAU,EAC/B,GAAI,CACF,UAAWY,KAAS,KAAK,UAAUb,EAAQ,IAAI,EAAG,CAEhD,GADA,MAAM,IAAI,MAAM,KAAK,OAAO,EACxBC,EAAW,OAAO,QACpB,MAAM,IAAI,aAAa,6BAA8B,YAAY,EAEnE,MAAMY,CACR,CACF,QAAE,CACA,KAAK,YAAY,OAAOZ,CAAU,CACpC,CACF,CAEA,MAAa,CACX,UAAWA,KAAc,KAAK,YAAaA,EAAW,MAAM,CAC9D,CACF,CAiBO,SAASe,EAAMZ,EAaD,CACnB,OAAQ,SAAY,CAClB,MAAMa,EAAc,IAAI,oBAClBC,EAAe,IAAI,eAAa,CAAE,GAAI,SAAU,YAAAD,CAAY,CAAC,EAC7DE,EAAMf,EAAQ,KAAO,IAAIP,EAAQO,EAAQ,MAAM,EAC/CgB,EAAM,IAAIjB,EACVkB,EACJjB,EAAQ,KACR,IAAIO,EACFP,EAAQ,YAAeK,GAAS,CAAC,IAAI,YAAY,EAAE,OAAOA,CAAI,CAAC,EACjE,EACIa,EAAQ,IAAI,QAAM,CACtB,KAAM,SACN,QAASlB,EAAQ,SAAW,cAC5B,IAAAe,EACA,MAAOf,EAAQ,KACjB,CAAC,EACKmB,EAAe,IAAI,eAAa,CACpC,aAAAL,EACA,OAAQ,CAACI,CAAK,EACd,IAAAH,EACA,IAAAC,EACA,IAAAC,EACA,YAAAJ,EACA,cAAeb,EAAQ,eAAiB,IACxC,cAAeA,EAAQ,cACvB,iBAAkBA,EAAQ,gBAC5B,CAAC,EAED,OAAAc,EAAa,MAAM,EACnB,MAAMA,EAAa,YAAY,CAAE,OAAQ,QAAS,QAAS,CAAC,IAAI,CAAE,CAAC,EACnE,MAAMK,EAAa,MAAM,EAElB,CACL,aAAAL,EACA,aAAAK,EAIA,IAAKJ,EACL,IAAAC,EACA,IAAAC,EACA,YAAAJ,CACF,CACF,GAAG,CACL,CA1DgBlB,EAAAiB,EAAA,SA4DhB,eAAsBQ,EAAQC,EAA0BC,EAAY,IAAqB,CACvF,MAAMC,EAAQ,KAAK,IAAI,EACvB,KAAO,CAACF,EAAU,GAAG,CACnB,GAAI,KAAK,IAAI,EAAIE,EAAQD,EACvB,MAAM,IAAI,MAAM,mBAAmB,EAErC,MAAM,IAAI,MAAM,CAAC,CACnB,CACF,CARsB3B,EAAAyB,EAAA,WAUtB,eAAsBI,EAAMC,EAAkBC,EAAgBrB,EAA6B,CACzFoB,EAAQ,aAAa,OAAO,CAAE,OAAAC,EAAQ,MAAO,IAAI,WAAW,CAAC,CAAC,CAAC,CAAE,CAAC,EAClED,EAAQ,IAAI,SAAS,GAAG,EAAE,EAAG,UAAUpB,CAAI,EAC3C,MAAMoB,EAAQ,aAAa,SAAS,CACtC,CAJsB9B,EAAA6B,EAAA,SAMf,SAASG,EAAQtB,EAAyB,CAC/C,OAAO,iBAAmB,CACxB,KAAM,CAAE,KAAM,QAAS,QAASA,CAAK,EACrC,KAAM,CAAE,KAAM,MAAO,CACvB,CACF,CALgBV,EAAAgC,EAAA,WAaT,SAASC,EAAY5B,EAQD,CACzB,OAAQ,SAAY,CAClB,MAAMa,EAAc,IAAI,oBAClBC,EAAe,IAAI,eAAa,CAAE,GAAI,SAAU,YAAAD,CAAY,CAAC,EAC7DG,EAAM,IAAIjB,EACVkB,EAAM,IAAIV,EAASF,GAAS,CAAC,IAAI,YAAY,EAAE,OAAOA,CAAI,CAAC,CAAC,EAE5DwB,EAAiB,IAAIpC,EAAQO,EAAQ,iBAAiB,EACtD8B,EAAO,IAAI,IAAqB,CAAC,CAAC,SAAUD,CAAc,CAAC,CAAC,EAC5DE,EAAkB,CACtB,IAAI,QAAM,CAAE,KAAM,SAAU,QAAS,cAAe,IAAKF,CAAe,CAAC,CAC3E,EACA,SAAW,CAACG,EAAMtC,CAAM,IAAK,OAAO,QAAQM,EAAQ,OAAO,EAAG,CAC5D,MAAMe,EAAM,IAAItB,EAAQC,CAAM,EAC9BoC,EAAK,IAAIE,EAAMjB,CAAG,EAClBgB,EAAO,KACL,IAAI,QAAM,CACR,KAAAC,EACA,QAAS,WAAWA,CAAI,IACxB,IAAAjB,EACA,MAAOf,EAAQ,QAAQgC,CAAI,CAC7B,CAAC,CACH,CACF,CAIA,GAAID,EAAO,SAAW,EAAG,CACvB,MAAME,EAAY,IAAIxC,EAAQkC,EAAQ,IAAI,CAAC,EAC3CG,EAAK,IAAI,SAAUG,CAAS,EAC5BF,EAAO,KAAK,IAAI,QAAM,CAAE,KAAM,SAAU,QAAS,YAAa,IAAKE,CAAU,CAAC,CAAC,CACjF,CACA,SAAW,CAACD,EAAME,CAAY,IAAK,OAAO,QAAQlC,EAAQ,eAAiB,CAAC,CAAC,EAC3E8B,EAAK,IAAIE,EAAME,EAAa,GAAG,EAGjC,MAAMf,EAAe,IAAI,eAAa,CACpC,aAAAL,EACA,OAAAiB,EACA,IAAKF,EACL,cAAe7B,EAAQ,cACvB,qBAAsBA,EAAQ,qBAC9B,iBAAkBA,EAAQ,iBAC1B,IAAAgB,EACA,IAAAC,EACA,YAAAJ,CACF,CAAC,EAED,OAAAC,EAAa,MAAM,EACnB,MAAMA,EAAa,YAAY,CAAE,OAAQ,QAAS,QAAS,CAAC,IAAI,CAAE,CAAC,EACnE,MAAMK,EAAa,MAAM,EAElB,CAAE,aAAAL,EAAc,aAAAK,EAAc,IAAKU,EAAgB,IAAAb,EAAK,IAAAC,EAAK,YAAAJ,EAAa,KAAAiB,CAAK,CACxF,GAAG,CACL,CA9DgBnC,EAAAiC,EAAA",
6
+ "names": ["test_harness_exports", "__export", "FakeLLM", "FakeSTT", "FakeSTTSession", "FakeTTS", "SlowTTS", "respond", "setup", "setupRoster", "speak", "waitFor", "__toCommonJS", "import_agent", "import_tools", "import_conversation", "import_memory", "import_orchestrator", "FakeLLM", "script", "__name", "request", "controller", "event", "FakeSTT", "options", "session", "FakeSTTSession", "audio", "listener", "text", "error", "FakeTTS", "chunksFor", "chunk", "SlowTTS", "delayMs", "setup", "persistence", "conversation", "llm", "stt", "tts", "agent", "orchestrator", "waitFor", "condition", "timeoutMs", "start", "speak", "harness", "userId", "respond", "setupRoster", "coordinatorLlm", "llms", "agents", "name", "helperLlm", "coordination"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var a=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var p=(r,o,f,x)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of c(o))!d.call(r,e)&&e!==f&&a(r,e,{get:()=>o[e],enumerable:!(x=b(o,e))||x.enumerable});return r},t=(r,o,f)=>(p(r,o,"default"),f&&p(f,o,"default"));var g=r=>p(a({},"__esModule",{value:!0}),r);var m={};module.exports=g(m);t(m,require("./text-chunker.js"),module.exports);
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/conversations/orchestration/text-chunker/index.ts"],
4
+ "sourcesContent": ["export * from './text-chunker';\n"],
5
+ "mappings": "iaAAA,IAAAA,EAAA,kBAAAC,EAAAD,GAAAE,EAAAF,EAAc,0BAAd",
6
+ "names": ["text_chunker_exports", "__toCommonJS", "__reExport"]
7
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";var i=Object.defineProperty;var s=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var u=(e,t)=>i(e,"name",{value:t,configurable:!0});var a=(e,t)=>{for(var r in t)i(e,r,{get:t[r],enumerable:!0})},l=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let h of f(t))!g.call(e,h)&&h!==r&&i(e,h,{get:()=>t[h],enumerable:!(n=s(t,h))||n.enumerable});return e};var b=e=>l(i({},"__esModule",{value:!0}),e);var L={};a(L,{TextChunker:()=>c});module.exports=b(L);const o=new Set([".","!","?",`
2
+ `]),m=new Set([",",";",":"]);class c{static{u(this,"TextChunker")}targetLength;maxLength;minSoftLength;buffer="";constructor(t={}){this.targetLength=t.targetLength??80,this.maxLength=t.maxLength??140,this.minSoftLength=t.minSoftLength??40}push(t){this.buffer+=t;const r=[];for(;;){const n=this.takeNext();if(n===null)break;n.length>0&&r.push(n)}return r}flush(){const t=this.buffer.trim();return this.buffer="",t.length>0?t:null}clear(){this.buffer=""}takeNext(){if(this.buffer.length===0)return null;for(let t=0;t<this.buffer.length;t++)if(o.has(this.buffer[t]))return this.takeThrough(t);if(this.buffer.length>=this.targetLength){for(let t=this.buffer.length-1;t>=0;t--)if(m.has(this.buffer[t])){if(t+1>=this.minSoftLength)return this.takeThrough(t);break}}return this.buffer.length>=this.maxLength?this.takeThrough(this.maxLength-1):null}takeThrough(t){const r=this.buffer.slice(0,t+1).trim();return this.buffer=this.buffer.slice(t+1),r}}
3
+ //# sourceMappingURL=text-chunker.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/conversations/orchestration/text-chunker/text-chunker.ts"],
4
+ "sourcesContent": ["/**\n * Streaming text segmenter for speech.\n *\n * Turns an incremental LLM token stream into speakable chunks with a boundary\n * hierarchy, so TTS never waits indefinitely for punctuation:\n *\n * 1. **Strong boundary** \u2014 `. ! ? \\n` flush immediately (sentence end).\n * 2. **Soft boundary** \u2014 once the buffer is long enough, split at the last\n * `, ; :` that yields a chunk of at least `minSoftLength` characters.\n * 3. **Hard cap** \u2014 at `maxLength` the buffer flushes regardless of\n * punctuation.\n *\n * The heuristics are intentionally internal and benchmark-driven rather than\n * configurable through the public API.\n */\n\nconst STRONG_BOUNDARIES = new Set([\".\", \"!\", \"?\", \"\\n\"]);\nconst SOFT_BOUNDARIES = new Set([\",\", \";\", \":\"]);\n\nexport interface TextChunkerOptions {\n /** Buffer length at which a soft boundary becomes eligible. Default 80. */\n targetLength?: number;\n /** Hard cap before an unconditional flush. Default 140. */\n maxLength?: number;\n /** Smallest chunk a soft boundary may produce. Default 40. */\n minSoftLength?: number;\n}\n\nexport class TextChunker {\n private readonly targetLength: number;\n private readonly maxLength: number;\n private readonly minSoftLength: number;\n private buffer = \"\";\n\n constructor(options: TextChunkerOptions = {}) {\n this.targetLength = options.targetLength ?? 80;\n this.maxLength = options.maxLength ?? 140;\n this.minSoftLength = options.minSoftLength ?? 40;\n }\n\n /** Feed tokens; returns zero or more complete chunks to synthesize. */\n push(delta: string): string[] {\n this.buffer += delta;\n const chunks: string[] = [];\n for (;;) {\n const chunk = this.takeNext();\n if (chunk === null) break;\n if (chunk.length > 0) chunks.push(chunk);\n }\n return chunks;\n }\n\n /** Flush any remaining buffered text as a final chunk (or null). */\n flush(): string | null {\n const rest = this.buffer.trim();\n this.buffer = \"\";\n return rest.length > 0 ? rest : null;\n }\n\n /** Drop the buffer (interrupt, stop). */\n clear(): void {\n this.buffer = \"\";\n }\n\n private takeNext(): string | null {\n if (this.buffer.length === 0) return null;\n\n // 1. Strong boundary \u2014 flush at the first sentence end for low latency.\n for (let i = 0; i < this.buffer.length; i++) {\n if (STRONG_BOUNDARIES.has(this.buffer[i]!)) return this.takeThrough(i);\n }\n\n // 2. Soft boundary once the buffer is long enough: prefer the last\n // comma/semicolon/colon, as long as it yields a chunk of at least\n // minSoftLength (never split a short clause off early).\n if (this.buffer.length >= this.targetLength) {\n for (let i = this.buffer.length - 1; i >= 0; i--) {\n if (SOFT_BOUNDARIES.has(this.buffer[i]!)) {\n if (i + 1 >= this.minSoftLength) return this.takeThrough(i);\n break; // any earlier boundary is even smaller\n }\n }\n }\n\n // 3. Hard cap \u2014 never wait indefinitely for punctuation.\n if (this.buffer.length >= this.maxLength) {\n return this.takeThrough(this.maxLength - 1);\n }\n\n return null;\n }\n\n /** Cut the buffer through index `i` (inclusive) and return the text. */\n private takeThrough(i: number): string {\n const chunk = this.buffer.slice(0, i + 1).trim();\n this.buffer = this.buffer.slice(i + 1);\n return chunk;\n }\n}\n"],
5
+ "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iBAAAE,IAAA,eAAAC,EAAAH,GAgBA,MAAMI,EAAoB,IAAI,IAAI,CAAC,IAAK,IAAK,IAAK;AAAA,CAAI,CAAC,EACjDC,EAAkB,IAAI,IAAI,CAAC,IAAK,IAAK,GAAG,CAAC,EAWxC,MAAMC,CAAY,CA5BzB,MA4ByB,CAAAC,EAAA,oBACN,aACA,UACA,cACT,OAAS,GAEjB,YAAYC,EAA8B,CAAC,EAAG,CAC5C,KAAK,aAAeA,EAAQ,cAAgB,GAC5C,KAAK,UAAYA,EAAQ,WAAa,IACtC,KAAK,cAAgBA,EAAQ,eAAiB,EAChD,CAGA,KAAKC,EAAyB,CAC5B,KAAK,QAAUA,EACf,MAAMC,EAAmB,CAAC,EAC1B,OAAS,CACP,MAAMC,EAAQ,KAAK,SAAS,EAC5B,GAAIA,IAAU,KAAM,MAChBA,EAAM,OAAS,GAAGD,EAAO,KAAKC,CAAK,CACzC,CACA,OAAOD,CACT,CAGA,OAAuB,CACrB,MAAME,EAAO,KAAK,OAAO,KAAK,EAC9B,YAAK,OAAS,GACPA,EAAK,OAAS,EAAIA,EAAO,IAClC,CAGA,OAAc,CACZ,KAAK,OAAS,EAChB,CAEQ,UAA0B,CAChC,GAAI,KAAK,OAAO,SAAW,EAAG,OAAO,KAGrC,QAASC,EAAI,EAAGA,EAAI,KAAK,OAAO,OAAQA,IACtC,GAAIT,EAAkB,IAAI,KAAK,OAAOS,CAAC,CAAE,EAAG,OAAO,KAAK,YAAYA,CAAC,EAMvE,GAAI,KAAK,OAAO,QAAU,KAAK,cAC7B,QAASA,EAAI,KAAK,OAAO,OAAS,EAAGA,GAAK,EAAGA,IAC3C,GAAIR,EAAgB,IAAI,KAAK,OAAOQ,CAAC,CAAE,EAAG,CACxC,GAAIA,EAAI,GAAK,KAAK,cAAe,OAAO,KAAK,YAAYA,CAAC,EAC1D,KACF,EAKJ,OAAI,KAAK,OAAO,QAAU,KAAK,UACtB,KAAK,YAAY,KAAK,UAAY,CAAC,EAGrC,IACT,CAGQ,YAAYA,EAAmB,CACrC,MAAMF,EAAQ,KAAK,OAAO,MAAM,EAAGE,EAAI,CAAC,EAAE,KAAK,EAC/C,YAAK,OAAS,KAAK,OAAO,MAAMA,EAAI,CAAC,EAC9BF,CACT,CACF",
6
+ "names": ["text_chunker_exports", "__export", "TextChunker", "__toCommonJS", "STRONG_BOUNDARIES", "SOFT_BOUNDARIES", "TextChunker", "__name", "options", "delta", "chunks", "chunk", "rest", "i"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var o=(i,e)=>r(i,"name",{value:e,configurable:!0});var u=(i,e)=>{for(var t in e)r(i,t,{get:e[t],enumerable:!0})},d=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of m(e))!h.call(i,s)&&s!==t&&r(i,s,{get:()=>e[s],enumerable:!(n=p(e,s))||n.enumerable});return i};var v=i=>d(r({},"__esModule",{value:!0}),i);var g={};u(g,{ConversationStream:()=>b});module.exports=v(g);var l=require("../../transport/streamobject/field-stream/field-stream.js");const f=[{path:["agent"],type:"string",maxLength:128},{path:["text"],type:"string",mode:"array",maxItems:4096,maxLength:4096}],a=0,c=1;class b extends l.FieldStream{static{o(this,"ConversationStream")}unsubscribers;active=null;constructor(e){super(f,{onCancel:o(()=>e.interrupt(),"onCancel")}),this.unsubscribers=[e.on("text-delta",({text:t,agentName:n})=>this.onDelta(t,n)),e.on("generation-complete",()=>this.completeReply()),e.on("error",({error:t})=>this.fail(t)),e.on("interrupt",()=>this.abortReply())]}dispose(){for(const e of this.unsubscribers)e()}onDelta(e,t){this.active===null&&(this.beginObject(),this.active={agentName:t,items:[]},t!==void 0&&this.emitField(a,t));const n=this.active.items.length;this.active.items.push(e),this.emitItem(c,n,e)}completeReply(){const e=this.active;if(e===null)return;this.active=null;const t=[];e.agentName!==void 0&&t.push({kind:"field",field:a,value:e.agentName}),t.push({kind:"field",field:c,value:e.items}),t.push({kind:"object-complete"}),this.emitObject(t)}abortReply(){this.active=null,this.cancelObject()}}
2
+ //# sourceMappingURL=conversation-stream.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/conversations/stream/conversation-stream.ts"],
4
+ "sourcesContent": ["/**\n * ConversationStream \u2014 the conversation's semantic reply stream.\n *\n * Turns a Conversation's event stream (LLM text fragments + generation\n * completion) into FieldStream completion events: consumers act on partial\n * reply text without waiting for the reply to finish.\n *\n * const replies = new ConversationStream(conversation);\n * replies.whenItem(\"text\", (fragment, i) => render(fragment));\n * replies.when(\"agent\", (agent) => showSpeaker(agent));\n * replies.whenObjectDone((reply) => finalize(reply));\n * replies.cancel(); // aborts the current generation (interrupts the LLM)\n *\n * One semantic object per top-level generation (agent or coordination\n * reply). The `text` field is an ordered sequence of completed text\n * fragments \u2014 semantically \"the next fragment of the reply arrived\", not\n * \"whatever happened to be inside a provider SSE packet\". Fragment sizes are\n * an implementation detail of the producer and may be coalesced later.\n *\n * Lifecycle per reply:\n *\n * first fragment \u2500\u2500\u25B6 STREAMING \u2500\u2500generation-complete\u2500\u2500\u25B6 DONE\n * \u251C\u2500\u2500cancel()/interrupt\u2500\u2500\u25B6 CANCELLED\n * \u2514\u2500\u2500provider error\u2500\u2500\u2500\u2500\u2500\u2500\u25B6 FAILED\n *\n * Each boundary fires at most once; no completion event fires after a\n * terminal state. Interruptions and errors leave already-delivered fragments\n * as valid partial state. Delegated sub-generation results do not terminate\n * the top-level reply \u2014 only the top-level generation's completion does.\n */\nimport { FieldStream } from \"../../transport/streamobject/field-stream/field-stream\";\nimport type {\n Event,\n Schema,\n} from \"../../transport/streamobject/reference/reference\";\nimport type { Conversation } from \"../conversation/conversation\";\n\nconst REPLY_SCHEMA: Schema = [\n { path: [\"agent\"], type: \"string\", maxLength: 128 },\n { path: [\"text\"], type: \"string\", mode: \"array\", maxItems: 4096, maxLength: 4096 },\n];\n\nconst AGENT_FIELD = 0;\nconst TEXT_FIELD = 1;\n\nexport class ConversationStream extends FieldStream {\n private readonly unsubscribers: Array<() => void>;\n private active: { agentName: string | undefined; items: string[] } | null = null;\n\n constructor(conversation: Conversation) {\n // cancel() interrupts the conversation, which stops the current\n // generation's LLM through the orchestrator. Idempotent.\n super(REPLY_SCHEMA, { onCancel: () => conversation.interrupt() });\n this.unsubscribers = [\n conversation.on(\"text-delta\", ({ text, agentName }) => this.onDelta(text, agentName)),\n conversation.on(\"generation-complete\", () => this.completeReply()),\n conversation.on(\"error\", ({ error }) => this.fail(error)),\n conversation.on(\"interrupt\", () => this.abortReply()),\n ];\n }\n\n /** Stop listening to the conversation. */\n dispose(): void {\n for (const unsubscribe of this.unsubscribers) unsubscribe();\n }\n\n private onDelta(text: string, agentName: string | undefined): void {\n if (this.active === null) {\n this.beginObject();\n this.active = { agentName, items: [] };\n if (agentName !== undefined) this.emitField(AGENT_FIELD, agentName);\n }\n const index = this.active.items.length;\n this.active.items.push(text);\n this.emitItem(TEXT_FIELD, index, text);\n }\n\n private completeReply(): void {\n const active = this.active;\n if (active === null) return;\n this.active = null;\n const events: Event[] = [];\n if (active.agentName !== undefined) {\n events.push({ kind: \"field\", field: AGENT_FIELD, value: active.agentName });\n }\n events.push({ kind: \"field\", field: TEXT_FIELD, value: active.items });\n events.push({ kind: \"object-complete\" });\n this.emitObject(events);\n }\n\n private abortReply(): void {\n this.active = null;\n this.cancelObject(); // delivered fragments remain valid partial state\n }\n}\n"],
5
+ "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,wBAAAE,IAAA,eAAAC,EAAAH,GA8BA,IAAAI,EAA4B,kEAO5B,MAAMC,EAAuB,CAC3B,CAAE,KAAM,CAAC,OAAO,EAAG,KAAM,SAAU,UAAW,GAAI,EAClD,CAAE,KAAM,CAAC,MAAM,EAAG,KAAM,SAAU,KAAM,QAAS,SAAU,KAAM,UAAW,IAAK,CACnF,EAEMC,EAAc,EACdC,EAAa,EAEZ,MAAMC,UAA2B,aAAY,CA7CpD,MA6CoD,CAAAC,EAAA,2BACjC,cACT,OAAoE,KAE5E,YAAYC,EAA4B,CAGtC,MAAML,EAAc,CAAE,SAAUI,EAAA,IAAMC,EAAa,UAAU,EAA7B,WAA+B,CAAC,EAChE,KAAK,cAAgB,CACnBA,EAAa,GAAG,aAAc,CAAC,CAAE,KAAAC,EAAM,UAAAC,CAAU,IAAM,KAAK,QAAQD,EAAMC,CAAS,CAAC,EACpFF,EAAa,GAAG,sBAAuB,IAAM,KAAK,cAAc,CAAC,EACjEA,EAAa,GAAG,QAAS,CAAC,CAAE,MAAAG,CAAM,IAAM,KAAK,KAAKA,CAAK,CAAC,EACxDH,EAAa,GAAG,YAAa,IAAM,KAAK,WAAW,CAAC,CACtD,CACF,CAGA,SAAgB,CACd,UAAWI,KAAe,KAAK,cAAeA,EAAY,CAC5D,CAEQ,QAAQH,EAAcC,EAAqC,CAC7D,KAAK,SAAW,OAClB,KAAK,YAAY,EACjB,KAAK,OAAS,CAAE,UAAAA,EAAW,MAAO,CAAC,CAAE,EACjCA,IAAc,QAAW,KAAK,UAAUN,EAAaM,CAAS,GAEpE,MAAMG,EAAQ,KAAK,OAAO,MAAM,OAChC,KAAK,OAAO,MAAM,KAAKJ,CAAI,EAC3B,KAAK,SAASJ,EAAYQ,EAAOJ,CAAI,CACvC,CAEQ,eAAsB,CAC5B,MAAMK,EAAS,KAAK,OACpB,GAAIA,IAAW,KAAM,OACrB,KAAK,OAAS,KACd,MAAMC,EAAkB,CAAC,EACrBD,EAAO,YAAc,QACvBC,EAAO,KAAK,CAAE,KAAM,QAAS,MAAOX,EAAa,MAAOU,EAAO,SAAU,CAAC,EAE5EC,EAAO,KAAK,CAAE,KAAM,QAAS,MAAOV,EAAY,MAAOS,EAAO,KAAM,CAAC,EACrEC,EAAO,KAAK,CAAE,KAAM,iBAAkB,CAAC,EACvC,KAAK,WAAWA,CAAM,CACxB,CAEQ,YAAmB,CACzB,KAAK,OAAS,KACd,KAAK,aAAa,CACpB,CACF",
6
+ "names": ["conversation_stream_exports", "__export", "ConversationStream", "__toCommonJS", "import_field_stream", "REPLY_SCHEMA", "AGENT_FIELD", "TEXT_FIELD", "ConversationStream", "__name", "conversation", "text", "agentName", "error", "unsubscribe", "index", "active", "events"]
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var s=(r,o)=>{for(var t in o)a(r,t,{get:o[t],enumerable:!0})},v=(r,o,t,m)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of i(o))!p.call(r,e)&&e!==t&&a(r,e,{get:()=>o[e],enumerable:!(m=f(o,e))||m.enumerable});return r};var x=r=>v(a({},"__esModule",{value:!0}),r);var C={};s(C,{ConversationStream:()=>n.ConversationStream});module.exports=x(C);var n=require("./conversation-stream.js");
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/conversations/stream/index.ts"],
4
+ "sourcesContent": ["export { ConversationStream } from \"./conversation-stream\";\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,8DAAAE,EAAAF,GAAA,IAAAG,EAAmC",
6
+ "names": ["stream_exports", "__export", "__toCommonJS", "import_conversation_stream"]
7
+ }
@@ -1,2 +1,2 @@
1
- "use strict";var a=Object.defineProperty;var o=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var s=(t,e)=>a(t,"name",{value:e,configurable:!0});var d=(t,e)=>{for(var r in e)a(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of u(e))!p.call(t,n)&&n!==r&&a(t,n,{get:()=>e[n],enumerable:!(i=o(e,n))||i.enumerable});return t};var l=t=>c(a({},"__esModule",{value:!0}),t);var m={};d(m,{createConversationState:()=>g});module.exports=l(m);function g(t="created"){return{status:t,participants:new Map,floor:null,currentTurn:null,currentGeneration:null,transcriptCount:0}}s(g,"createConversationState");
1
+ "use strict";var i=Object.defineProperty;var o=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var s=(t,e)=>i(t,"name",{value:e,configurable:!0});var d=(t,e)=>{for(var r in e)i(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of u(e))!p.call(t,n)&&n!==r&&i(t,n,{get:()=>e[n],enumerable:!(a=o(e,n))||a.enumerable});return t};var l=t=>c(i({},"__esModule",{value:!0}),t);var g={};d(g,{createConversationState:()=>m});module.exports=l(g);function m(t="created"){return{status:t,participants:new Map,floor:null,currentTurn:null,currentGeneration:null,transcriptCount:0}}s(m,"createConversationState");
2
2
  //# sourceMappingURL=types.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/conversations/types.ts"],
4
- "sourcesContent": ["/**\n * Core domain types shared across Pipeflow modules.\n */\n\n// ---------------------------------------------------------------------------\n// Identities\n// ---------------------------------------------------------------------------\n\nexport type ConversationId = string;\nexport type UserId = string;\nexport type TurnId = string;\n\n// ---------------------------------------------------------------------------\n// Participants\n// ---------------------------------------------------------------------------\n\nexport interface ParticipantInput {\n userId: UserId;\n aliases?: string[];\n}\n\nexport interface Participant {\n userId: UserId;\n aliases: string[];\n joinedAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// Turns & generations\n// ---------------------------------------------------------------------------\n\nexport interface Turn {\n id: TurnId;\n conversationId: ConversationId;\n participantId: UserId;\n participantName: string;\n text: string;\n sequence: number;\n startedAt: number;\n endedAt: number;\n}\n\nexport type GenerationStatus = \"streaming\" | \"completed\" | \"cancelled\";\n\nexport interface Generation {\n id: string;\n conversationId: ConversationId;\n agentName: string;\n text: string;\n status: GenerationStatus;\n startedAt: number;\n endedAt?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Tool calls\n// ---------------------------------------------------------------------------\n\nexport interface ToolCall {\n id: string;\n name: string;\n /** Parsed arguments, or the raw JSON string if parsing failed. */\n arguments: unknown;\n}\n\nexport type ToolCallResult =\n | { id: string; result: unknown }\n | { id: string; error: string };\n\n// ---------------------------------------------------------------------------\n// Audio\n// ---------------------------------------------------------------------------\n\nexport interface AudioChunk {\n data: Uint8Array;\n timestamp: number;\n sequence: number;\n}\n\n// ---------------------------------------------------------------------------\n// Conversation state\n// ---------------------------------------------------------------------------\n\nexport type ConversationStatus = \"created\" | \"started\" | \"stopped\";\n\nexport interface ConversationState {\n status: ConversationStatus;\n participants: Map<UserId, Participant>;\n floor: UserId | null;\n currentTurn: Turn | null;\n currentGeneration: Generation | null;\n transcriptCount: number;\n}\n\nexport function createConversationState(\n status: ConversationStatus = \"created\",\n): ConversationState {\n return {\n status,\n participants: new Map(),\n floor: null,\n currentTurn: null,\n currentGeneration: null,\n transcriptCount: 0,\n };\n}\n"],
5
- "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,6BAAAE,IAAA,eAAAC,EAAAH,GA8FO,SAASI,EACdC,EAA6B,UACV,CACnB,MAAO,CACL,OAAAA,EACA,aAAc,IAAI,IAClB,MAAO,KACP,YAAa,KACb,kBAAmB,KACnB,gBAAiB,CACnB,CACF,CAXgBC,EAAAF,EAAA",
4
+ "sourcesContent": ["/**\n * Core domain types shared across Pipeflow modules.\n */\n\n// ---------------------------------------------------------------------------\n// Identities\n// ---------------------------------------------------------------------------\n\nexport type ConversationId = string;\nexport type UserId = string;\nexport type TurnId = string;\n\n// ---------------------------------------------------------------------------\n// Participants\n// ---------------------------------------------------------------------------\n\nexport interface ParticipantInput {\n userId: UserId;\n aliases?: string[];\n}\n\nexport interface Participant {\n userId: UserId;\n aliases: string[];\n joinedAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// Turns & generations\n// ---------------------------------------------------------------------------\n\nexport interface Turn {\n id: TurnId;\n conversationId: ConversationId;\n participantId: UserId;\n participantName: string;\n text: string;\n sequence: number;\n startedAt: number;\n endedAt: number;\n}\n\nexport type GenerationStatus = \"streaming\" | \"completed\" | \"cancelled\";\n\n/**\n * Latency instrumentation for a generation. Times are epoch milliseconds;\n * only `startedAt` is always present. The chain distinguishes each hop:\n *\n * ```text\n * turn \u2192 first LLM token \u2192 first TTS text (buffering flush)\n * \u2192 TTS requested \u2192 TTS first audio \u2192 audio delivered \u2192 completed\n * ```\n */\nexport interface GenerationTiming {\n startedAt: number;\n /** First LLM delta of this generation (first-token latency). */\n firstTokenAt?: number;\n /** First sentence flushed to TTS (text buffering latency). */\n firstTtsTextAt?: number;\n /** First TTS stream request issued (queue latency). */\n firstTtsRequestAt?: number;\n /** First audio chunk produced by the TTS provider (provider latency). */\n firstTtsAudioAt?: number;\n /** First TTS audio chunk delivered to the application (transport latency). */\n firstAudioAt?: number;\n completedAt?: number;\n}\n\nexport interface Generation {\n id: string;\n conversationId: ConversationId;\n agentName: string;\n text: string;\n status: GenerationStatus;\n startedAt: number;\n endedAt?: number;\n /**\n * \"sub\" marks a task dispatched to another agent by the coordinator.\n * Regular agent replies omit this field.\n */\n kind?: \"sub\";\n /** For sub-generations: the id of the coordinator generation that dispatched them. */\n parentGenerationId?: string;\n /** Latency instrumentation, recorded as the generation streams. */\n timing?: GenerationTiming;\n}\n\n// ---------------------------------------------------------------------------\n// Tool calls\n// ---------------------------------------------------------------------------\n\nexport interface ToolCall {\n id: string;\n name: string;\n /** Parsed arguments, or the raw JSON string if parsing failed. */\n arguments: unknown;\n}\n\nexport type ToolCallResult =\n | { id: string; result: unknown }\n | { id: string; error: string };\n\n// ---------------------------------------------------------------------------\n// Audio\n// ---------------------------------------------------------------------------\n\nexport interface AudioChunk {\n data: Uint8Array;\n timestamp: number;\n sequence: number;\n}\n\n// ---------------------------------------------------------------------------\n// Conversation state\n// ---------------------------------------------------------------------------\n\nexport type ConversationStatus = \"created\" | \"started\" | \"stopped\";\n\nexport interface ConversationState {\n status: ConversationStatus;\n participants: Map<UserId, Participant>;\n floor: UserId | null;\n currentTurn: Turn | null;\n currentGeneration: Generation | null;\n transcriptCount: number;\n}\n\nexport function createConversationState(\n status: ConversationStatus = \"created\",\n): ConversationState {\n return {\n status,\n participants: new Map(),\n floor: null,\n currentTurn: null,\n currentGeneration: null,\n transcriptCount: 0,\n };\n}\n"],
5
+ "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,6BAAAE,IAAA,eAAAC,EAAAH,GA+HO,SAASI,EACdC,EAA6B,UACV,CACnB,MAAO,CACL,OAAAA,EACA,aAAc,IAAI,IAClB,MAAO,KACP,YAAa,KACb,kBAAmB,KACnB,gBAAiB,CACnB,CACF,CAXgBC,EAAAF,EAAA",
6
6
  "names": ["types_exports", "__export", "createConversationState", "__toCommonJS", "createConversationState", "status", "__name"]
7
7
  }
package/dist/cjs/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var n=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var a=(e,t)=>n(e,"name",{value:t,configurable:!0});var d=(e,t)=>{for(var o in t)n(e,o,{get:t[o],enumerable:!0})},v=(e,t,o,l)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of y(t))!f.call(e,s)&&s!==o&&n(e,s,{get:()=>t[s],enumerable:!(l=c(t,s))||l.enumerable});return e};var u=e=>v(n({},"__esModule",{value:!0}),e);var x={};d(x,{Agent:()=>i.Agent,Conversation:()=>r.Conversation,Conversations:()=>r.Conversations,Orchestrator:()=>r.Orchestrator,Pipeflow:()=>C,PipeflowTool:()=>p.Tool,Tool:()=>p.Tool,TranscriptEntry:()=>r.TranscriptEntry,Transcription:()=>r.Transcription});module.exports=u(x);var i=require("./agents/agent.js"),m=require("./conversations/conversations.js"),T=require("./persistence/adapters/memory/memory.js"),p=require("./agents/tools/tools.js"),r=require("./conversations/index.js");class C{static{a(this,"Pipeflow")}llm;stt;tts;conversations;constructor(t={}){this.llm=t.llm,this.stt=t.stt,this.tts=t.tts;const o=t.persistence??new T.MemoryPersistence;this.conversations=new m.Conversations(o)}agent(t){return new i.Agent({...t,llm:t.llm??this.llm})}}
1
+ "use strict";var p=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var u=Object.prototype.hasOwnProperty;var x=(e,t)=>{for(var n in t)p(e,n,{get:t[n],enumerable:!0})},m=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of f(t))!u.call(e,r)&&r!==n&&p(e,r,{get:()=>t[r],enumerable:!(i=T(t,r))||i.enumerable});return e};var v=e=>m(p({},"__esModule",{value:!0}),e);var y={};x(y,{Agent:()=>l.Agent,Conversation:()=>o.Conversation,Conversations:()=>o.Conversations,Pipeflow:()=>a.Pipeflow,PipeflowTool:()=>s.Tool,Tool:()=>s.Tool,TranscriptEntry:()=>o.TranscriptEntry,Transcription:()=>o.Transcription});module.exports=v(y);var a=require("./pipeflow.js"),l=require("./agents/agent.js"),s=require("./agents/tools/tools.js"),o=require("./conversations/index.js");
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
- "sourcesContent": ["import { Agent, type AgentOptions } from \"./agents/agent\";\nimport { Conversations } from \"./conversations/conversations\";\nimport { MemoryPersistence } from \"./persistence/adapters/memory/memory\";\nimport type { Persistence } from \"./persistence/persistence\";\nimport type { LLM } from \"./providers/llm/types\";\nimport type { STT } from \"./providers/stt/types\";\nimport type { TTS } from \"./providers/tts/types\";\n\nexport interface PipeflowOptions {\n llm?: LLM;\n stt?: STT;\n tts?: TTS;\n persistence?: Persistence;\n}\n\n/**\n * The Pipeflow entry point.\n *\n * ```ts\n * const pipeflow = new Pipeflow({ llm });\n * const agent = pipeflow.agent({ name: \"Jarvis\", context: \"...\" });\n * const conversation = await pipeflow.conversations.create({ agents: [agent] });\n * ```\n */\nexport class Pipeflow {\n readonly llm: LLM | undefined;\n readonly stt: STT | undefined;\n readonly tts: TTS | undefined;\n readonly conversations: Conversations;\n\n constructor(options: PipeflowOptions = {}) {\n this.llm = options.llm;\n this.stt = options.stt;\n this.tts = options.tts;\n const persistence = options.persistence ?? new MemoryPersistence();\n this.conversations = new Conversations(persistence);\n }\n\n /**\n * Create an agent. Agents inherit the Pipeflow instance's LLM provider so\n * `agent.run()` works out of the box.\n */\n agent(options: Omit<AgentOptions, \"llm\"> & { llm?: LLM }): Agent {\n return new Agent({ ...options, llm: options.llm ?? this.llm });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Core public API\n// ---------------------------------------------------------------------------\n\nexport { Agent };\nexport type {\n AgentOptions,\n AgentRunRequest,\n AgentRunResult,\n ExecutedToolCall,\n} from \"./agents/agent\";\nexport { Tool, Tool as PipeflowTool } from \"./agents/tools/tools\";\nexport type { ToolOptions } from \"./agents/tools/tools\";\n\nexport {\n Conversation,\n Conversations,\n Orchestrator,\n Transcription,\n TranscriptEntry,\n} from \"./conversations/index\";\nexport type {\n AudioChunk,\n ConversationEvents,\n ConversationId,\n ConversationOptions,\n ConversationState,\n ConversationStatus,\n CreateConversationOptions,\n Generation,\n GenerationStatus,\n OrchestratorOptions,\n Participant,\n ParticipantInput,\n ToolCall,\n ToolCallResult,\n TranscriptEntryInput,\n TranscriptSpeakerKind,\n Turn,\n TurnId,\n UserId,\n} from \"./conversations/index\";\n\n// ---------------------------------------------------------------------------\n// Configuration interfaces.\n//\n// Provider and persistence *implementations* are intentionally not exported\n// from the main entry \u2014 they are replaceable implementation detail. Import\n// them from their module subpaths when needed:\n//\n// import { DeepSeekLLM } from \"pipeflow/providers\";\n// import { SQLitePersistence } from \"pipeflow/persistence\";\n// import { MemoryTransport } from \"pipeflow/transport\";\n// ---------------------------------------------------------------------------\n\nexport type { LLM, LLMMessage } from \"./providers/llm/types\";\nexport type { STT } from \"./providers/stt/types\";\nexport type { TTS } from \"./providers/tts/types\";\nexport type { Persistence } from \"./persistence/persistence\";\n"],
5
- "mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,kIAAAE,EAAA,iIAAAC,EAAAH,GAAA,IAAAI,EAAyC,0BACzCC,EAA8B,yCAC9BC,EAAkC,gDAwDlCC,EAA2C,gCAG3CF,EAMO,iCA3CA,MAAMG,CAAS,CAxBtB,MAwBsB,CAAAC,EAAA,iBACX,IACA,IACA,IACA,cAET,YAAYC,EAA2B,CAAC,EAAG,CACzC,KAAK,IAAMA,EAAQ,IACnB,KAAK,IAAMA,EAAQ,IACnB,KAAK,IAAMA,EAAQ,IACnB,MAAMC,EAAcD,EAAQ,aAAe,IAAI,oBAC/C,KAAK,cAAgB,IAAI,gBAAcC,CAAW,CACpD,CAMA,MAAMD,EAA2D,CAC/D,OAAO,IAAI,QAAM,CAAE,GAAGA,EAAS,IAAKA,EAAQ,KAAO,KAAK,GAAI,CAAC,CAC/D,CACF",
6
- "names": ["index_exports", "__export", "Pipeflow", "__toCommonJS", "import_agent", "import_conversations", "import_memory", "import_tools", "Pipeflow", "__name", "options", "persistence"]
4
+ "sourcesContent": ["// ---------------------------------------------------------------------------\n// Core public API\n// ---------------------------------------------------------------------------\n\nexport { Pipeflow } from \"./pipeflow\";\nexport type { PipeflowOptions } from \"./pipeflow\";\n\nexport { Agent } from \"./agents/agent\";\nexport type {\n AgentOptions,\n AgentRunRequest,\n AgentRunResult,\n ExecutedToolCall,\n} from \"./agents/agent\";\nexport { Tool, Tool as PipeflowTool } from \"./agents/tools/tools\";\nexport type { ToolOptions } from \"./agents/tools/tools\";\n\nexport {\n Conversation,\n Conversations,\n Transcription,\n TranscriptEntry,\n} from \"./conversations/index\";\nexport type {\n AudioChunk,\n ConversationEvents,\n ConversationId,\n ConversationOptions,\n ConversationState,\n ConversationStatus,\n CreateConversationOptions,\n Generation,\n GenerationStatus,\n Participant,\n ParticipantInput,\n ToolCall,\n ToolCallResult,\n TranscriptEntryInput,\n TranscriptSpeakerKind,\n Turn,\n TurnId,\n UserId,\n} from \"./conversations/index\";\n\n// Realtime machinery (Orchestrator and friends) lives behind the\n// `@moureau/pipeflow/conversations` subpath \u2014 it is implementation detail\n// that `Conversation.start()` attaches automatically.\n\n// ---------------------------------------------------------------------------\n// Configuration interfaces.\n//\n// Provider and persistence *implementations* are intentionally not exported\n// from the main entry \u2014 they are replaceable implementation detail. Import\n// them from their module subpaths when needed:\n//\n// import { DeepSeekLLM } from \"pipeflow/providers\";\n// import { SQLitePersistence } from \"pipeflow/persistence\";\n// import { MemoryTransport } from \"pipeflow/transport\";\n// ---------------------------------------------------------------------------\n\nexport type { LLM, LLMMessage } from \"./providers/llm/types\";\nexport type { STT } from \"./providers/stt/types\";\nexport type { TTS } from \"./providers/tts/types\";\nexport type { Persistence } from \"./persistence/persistence\";\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,8OAAAE,EAAAF,GAIA,IAAAG,EAAyB,sBAGzBC,EAAsB,0BAOtBC,EAA2C,gCAG3CC,EAKO",
6
+ "names": ["index_exports", "__export", "__toCommonJS", "import_pipeflow", "import_agent", "import_tools", "import_conversations"]
7
7
  }