@moureau/pipeflow 0.0.1 → 0.0.2

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 (311) hide show
  1. package/README.md +245 -117
  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/conversations/conversation/conversation.js +1 -1
  7. package/dist/cjs/conversations/conversation/conversation.js.map +3 -3
  8. package/dist/cjs/conversations/conversations.js +1 -1
  9. package/dist/cjs/conversations/conversations.js.map +3 -3
  10. package/dist/cjs/conversations/index.js +1 -1
  11. package/dist/cjs/conversations/index.js.map +3 -3
  12. package/dist/cjs/conversations/orchestration/coordination/coordination.js +10 -0
  13. package/dist/cjs/conversations/orchestration/coordination/coordination.js.map +7 -0
  14. package/dist/cjs/conversations/orchestration/coordination/index.js +2 -0
  15. package/dist/cjs/conversations/orchestration/coordination/index.js.map +7 -0
  16. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js +4 -0
  17. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js.map +7 -0
  18. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/index.js +2 -0
  19. package/dist/cjs/conversations/orchestration/orchestrator/coordination-runner/index.js.map +7 -0
  20. package/dist/cjs/conversations/orchestration/orchestrator/generation/generation.js +2 -0
  21. package/dist/cjs/conversations/orchestration/orchestrator/generation/generation.js.map +7 -0
  22. package/dist/cjs/conversations/orchestration/orchestrator/generation/index.js +2 -0
  23. package/dist/cjs/conversations/orchestration/orchestrator/generation/index.js.map +7 -0
  24. package/dist/cjs/conversations/orchestration/orchestrator/history/history.js +4 -0
  25. package/dist/cjs/conversations/orchestration/orchestrator/history/history.js.map +7 -0
  26. package/dist/cjs/conversations/orchestration/orchestrator/history/index.js +2 -0
  27. package/dist/cjs/conversations/orchestration/orchestrator/history/index.js.map +7 -0
  28. package/dist/cjs/conversations/orchestration/orchestrator/index.js +1 -1
  29. package/dist/cjs/conversations/orchestration/orchestrator/index.js.map +3 -3
  30. package/dist/cjs/conversations/orchestration/orchestrator/orchestrator.js +1 -2
  31. package/dist/cjs/conversations/orchestration/orchestrator/orchestrator.js.map +3 -3
  32. package/dist/cjs/conversations/orchestration/orchestrator/routing/index.js +2 -0
  33. package/dist/cjs/conversations/orchestration/orchestrator/routing/index.js.map +7 -0
  34. package/dist/cjs/conversations/orchestration/orchestrator/routing/routing.js +23 -0
  35. package/dist/cjs/conversations/orchestration/orchestrator/routing/routing.js.map +7 -0
  36. package/dist/cjs/conversations/orchestration/orchestrator/speech/index.js +2 -0
  37. package/dist/cjs/conversations/orchestration/orchestrator/speech/index.js.map +7 -0
  38. package/dist/cjs/conversations/orchestration/orchestrator/speech/speech.js +2 -0
  39. package/dist/cjs/conversations/orchestration/orchestrator/speech/speech.js.map +7 -0
  40. package/dist/cjs/conversations/orchestration/orchestrator/tools/index.js +2 -0
  41. package/dist/cjs/conversations/orchestration/orchestrator/tools/index.js.map +7 -0
  42. package/dist/cjs/conversations/orchestration/orchestrator/tools/tools.js +2 -0
  43. package/dist/cjs/conversations/orchestration/orchestrator/tools/tools.js.map +7 -0
  44. package/dist/cjs/conversations/orchestration/test-harness.js +2 -0
  45. package/dist/cjs/conversations/orchestration/test-harness.js.map +7 -0
  46. package/dist/cjs/conversations/orchestration/text-chunker/index.js +2 -0
  47. package/dist/cjs/conversations/orchestration/text-chunker/index.js.map +7 -0
  48. package/dist/cjs/conversations/orchestration/text-chunker/text-chunker.js +3 -0
  49. package/dist/cjs/conversations/orchestration/text-chunker/text-chunker.js.map +7 -0
  50. package/dist/cjs/conversations/stream/conversation-stream.js +2 -0
  51. package/dist/cjs/conversations/stream/conversation-stream.js.map +7 -0
  52. package/dist/cjs/conversations/stream/index.js +2 -0
  53. package/dist/cjs/conversations/stream/index.js.map +7 -0
  54. package/dist/cjs/conversations/types.js +1 -1
  55. package/dist/cjs/conversations/types.js.map +2 -2
  56. package/dist/cjs/index.js +1 -1
  57. package/dist/cjs/index.js.map +3 -3
  58. package/dist/cjs/persistence/adapters/sqlite/sqlite.js +18 -14
  59. package/dist/cjs/persistence/adapters/sqlite/sqlite.js.map +3 -3
  60. package/dist/cjs/pipeflow/index.js +2 -0
  61. package/dist/cjs/pipeflow/index.js.map +7 -0
  62. package/dist/cjs/pipeflow/pipeflow.js +2 -0
  63. package/dist/cjs/pipeflow/pipeflow.js.map +7 -0
  64. package/dist/cjs/providers/index.js +1 -1
  65. package/dist/cjs/providers/index.js.map +2 -2
  66. package/dist/cjs/providers/llm/adapters/claude/claude.js +5 -0
  67. package/dist/cjs/providers/llm/adapters/claude/claude.js.map +7 -0
  68. package/dist/cjs/providers/llm/adapters/claude/index.js +2 -0
  69. package/dist/cjs/providers/llm/adapters/claude/index.js.map +7 -0
  70. package/dist/cjs/providers/llm/adapters/deepseek/deepseek.js +1 -1
  71. package/dist/cjs/providers/llm/adapters/deepseek/deepseek.js.map +3 -3
  72. package/dist/cjs/providers/llm/adapters/index.js +1 -1
  73. package/dist/cjs/providers/llm/adapters/index.js.map +3 -3
  74. package/dist/cjs/providers/llm/adapters/openai/index.js +2 -0
  75. package/dist/cjs/providers/llm/adapters/openai/index.js.map +7 -0
  76. package/dist/cjs/providers/llm/adapters/openai/openai.js +2 -0
  77. package/dist/cjs/providers/llm/adapters/openai/openai.js.map +7 -0
  78. package/dist/cjs/providers/llm/adapters/openai-compatible.js +10 -0
  79. package/dist/cjs/providers/llm/adapters/openai-compatible.js.map +7 -0
  80. package/dist/cjs/providers/llm/adapters/openrouter/index.js +2 -0
  81. package/dist/cjs/providers/llm/adapters/openrouter/index.js.map +7 -0
  82. package/dist/cjs/providers/llm/adapters/openrouter/openrouter.js +2 -0
  83. package/dist/cjs/providers/llm/adapters/openrouter/openrouter.js.map +7 -0
  84. package/dist/cjs/providers/llm/index.js +1 -1
  85. package/dist/cjs/providers/llm/index.js.map +3 -3
  86. package/dist/cjs/providers/llm/toolmode/index.js +2 -0
  87. package/dist/cjs/providers/llm/toolmode/index.js.map +7 -0
  88. package/dist/cjs/providers/llm/toolmode/toolmode.js +2 -0
  89. package/dist/cjs/providers/llm/toolmode/toolmode.js.map +7 -0
  90. package/dist/cjs/providers/llm/types.js +1 -1
  91. package/dist/cjs/providers/llm/types.js.map +3 -3
  92. package/dist/cjs/providers/stt/adapters/deepgram/deepgram.js +1 -1
  93. package/dist/cjs/providers/stt/adapters/deepgram/deepgram.js.map +3 -3
  94. package/dist/cjs/providers/stt/adapters/index.js +1 -1
  95. package/dist/cjs/providers/stt/adapters/index.js.map +3 -3
  96. package/dist/cjs/providers/stt/adapters/openrouter/index.js +2 -0
  97. package/dist/cjs/providers/stt/adapters/openrouter/index.js.map +7 -0
  98. package/dist/cjs/providers/stt/adapters/openrouter/openrouter.js +2 -0
  99. package/dist/cjs/providers/stt/adapters/openrouter/openrouter.js.map +7 -0
  100. package/dist/cjs/providers/tts/adapters/index.js +1 -1
  101. package/dist/cjs/providers/tts/adapters/index.js.map +3 -3
  102. package/dist/cjs/providers/tts/adapters/kokoro/kokoro.js +4 -1
  103. package/dist/cjs/providers/tts/adapters/kokoro/kokoro.js.map +3 -3
  104. package/dist/cjs/providers/tts/adapters/openrouter/index.js +2 -0
  105. package/dist/cjs/providers/tts/adapters/openrouter/index.js.map +7 -0
  106. package/dist/cjs/providers/tts/adapters/openrouter/openrouter.js +2 -0
  107. package/dist/cjs/providers/tts/adapters/openrouter/openrouter.js.map +7 -0
  108. package/dist/cjs/transport/streamobject/field-stream/field-stream.js +2 -0
  109. package/dist/cjs/transport/streamobject/field-stream/field-stream.js.map +7 -0
  110. package/dist/cjs/transport/streamobject/field-stream/index.js +2 -0
  111. package/dist/cjs/transport/streamobject/field-stream/index.js.map +7 -0
  112. package/dist/cjs/transport/streamobject/index.js +2 -0
  113. package/dist/cjs/transport/streamobject/index.js.map +7 -0
  114. package/dist/cjs/transport/streamobject/json-adapter/index.js +2 -0
  115. package/dist/cjs/transport/streamobject/json-adapter/index.js.map +7 -0
  116. package/dist/cjs/transport/streamobject/json-adapter/json-adapter.js +4 -0
  117. package/dist/cjs/transport/streamobject/json-adapter/json-adapter.js.map +7 -0
  118. package/dist/cjs/transport/streamobject/reference/index.js +2 -0
  119. package/dist/cjs/transport/streamobject/reference/index.js.map +7 -0
  120. package/dist/cjs/transport/streamobject/reference/reference.js +2 -0
  121. package/dist/cjs/transport/streamobject/reference/reference.js.map +7 -0
  122. package/dist/cjs/transport/streamobject/stream-object/index.js +2 -0
  123. package/dist/cjs/transport/streamobject/stream-object/index.js.map +7 -0
  124. package/dist/cjs/transport/streamobject/stream-object/stream-object.js +2 -0
  125. package/dist/cjs/transport/streamobject/stream-object/stream-object.js.map +7 -0
  126. package/dist/esm/agents/agent.js +1 -1
  127. package/dist/esm/agents/agent.js.map +3 -3
  128. package/dist/esm/agents/tools/tools.js +1 -1
  129. package/dist/esm/agents/tools/tools.js.map +3 -3
  130. package/dist/esm/conversations/conversation/conversation.js +1 -1
  131. package/dist/esm/conversations/conversation/conversation.js.map +3 -3
  132. package/dist/esm/conversations/conversations.js +1 -1
  133. package/dist/esm/conversations/conversations.js.map +3 -3
  134. package/dist/esm/conversations/index.js +1 -1
  135. package/dist/esm/conversations/index.js.map +3 -3
  136. package/dist/esm/conversations/orchestration/coordination/coordination.js +10 -0
  137. package/dist/esm/conversations/orchestration/coordination/coordination.js.map +7 -0
  138. package/dist/esm/conversations/orchestration/coordination/index.js +2 -0
  139. package/dist/esm/conversations/orchestration/coordination/index.js.map +7 -0
  140. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js +4 -0
  141. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.js.map +7 -0
  142. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/index.js +2 -0
  143. package/dist/esm/conversations/orchestration/orchestrator/coordination-runner/index.js.map +7 -0
  144. package/dist/esm/conversations/orchestration/orchestrator/generation/generation.js +2 -0
  145. package/dist/esm/conversations/orchestration/orchestrator/generation/generation.js.map +7 -0
  146. package/dist/esm/conversations/orchestration/orchestrator/generation/index.js +2 -0
  147. package/dist/esm/conversations/orchestration/orchestrator/generation/index.js.map +7 -0
  148. package/dist/esm/conversations/orchestration/orchestrator/history/history.js +4 -0
  149. package/dist/esm/conversations/orchestration/orchestrator/history/history.js.map +7 -0
  150. package/dist/esm/conversations/orchestration/orchestrator/history/index.js +2 -0
  151. package/dist/esm/conversations/orchestration/orchestrator/history/index.js.map +7 -0
  152. package/dist/esm/conversations/orchestration/orchestrator/index.js +1 -1
  153. package/dist/esm/conversations/orchestration/orchestrator/index.js.map +3 -3
  154. package/dist/esm/conversations/orchestration/orchestrator/orchestrator.js +1 -2
  155. package/dist/esm/conversations/orchestration/orchestrator/orchestrator.js.map +3 -3
  156. package/dist/esm/conversations/orchestration/orchestrator/routing/index.js +2 -0
  157. package/dist/esm/conversations/orchestration/orchestrator/routing/index.js.map +7 -0
  158. package/dist/esm/conversations/orchestration/orchestrator/routing/routing.js +23 -0
  159. package/dist/esm/conversations/orchestration/orchestrator/routing/routing.js.map +7 -0
  160. package/dist/esm/conversations/orchestration/orchestrator/speech/index.js +2 -0
  161. package/dist/esm/conversations/orchestration/orchestrator/speech/index.js.map +7 -0
  162. package/dist/esm/conversations/orchestration/orchestrator/speech/speech.js +2 -0
  163. package/dist/esm/conversations/orchestration/orchestrator/speech/speech.js.map +7 -0
  164. package/dist/esm/conversations/orchestration/orchestrator/tools/index.js +2 -0
  165. package/dist/esm/conversations/orchestration/orchestrator/tools/index.js.map +7 -0
  166. package/dist/esm/conversations/orchestration/orchestrator/tools/tools.js +2 -0
  167. package/dist/esm/conversations/orchestration/orchestrator/tools/tools.js.map +7 -0
  168. package/dist/esm/conversations/orchestration/test-harness.js +2 -0
  169. package/dist/esm/conversations/orchestration/test-harness.js.map +7 -0
  170. package/dist/esm/conversations/orchestration/text-chunker/index.js +2 -0
  171. package/dist/esm/conversations/orchestration/text-chunker/index.js.map +7 -0
  172. package/dist/esm/conversations/orchestration/text-chunker/text-chunker.js +3 -0
  173. package/dist/esm/conversations/orchestration/text-chunker/text-chunker.js.map +7 -0
  174. package/dist/esm/conversations/stream/conversation-stream.js +2 -0
  175. package/dist/esm/conversations/stream/conversation-stream.js.map +7 -0
  176. package/dist/esm/conversations/stream/index.js +2 -0
  177. package/dist/esm/conversations/stream/index.js.map +7 -0
  178. package/dist/esm/conversations/types.js +1 -1
  179. package/dist/esm/conversations/types.js.map +2 -2
  180. package/dist/esm/index.js +1 -1
  181. package/dist/esm/index.js.map +3 -3
  182. package/dist/esm/persistence/adapters/sqlite/sqlite.js +18 -14
  183. package/dist/esm/persistence/adapters/sqlite/sqlite.js.map +3 -3
  184. package/dist/esm/pipeflow/index.js +2 -0
  185. package/dist/esm/pipeflow/index.js.map +7 -0
  186. package/dist/esm/pipeflow/pipeflow.js +2 -0
  187. package/dist/esm/pipeflow/pipeflow.js.map +7 -0
  188. package/dist/esm/providers/index.js +1 -1
  189. package/dist/esm/providers/index.js.map +3 -3
  190. package/dist/esm/providers/llm/adapters/claude/claude.js +5 -0
  191. package/dist/esm/providers/llm/adapters/claude/claude.js.map +7 -0
  192. package/dist/esm/providers/llm/adapters/claude/index.js +2 -0
  193. package/dist/esm/providers/llm/adapters/claude/index.js.map +7 -0
  194. package/dist/esm/providers/llm/adapters/deepseek/deepseek.js +1 -1
  195. package/dist/esm/providers/llm/adapters/deepseek/deepseek.js.map +3 -3
  196. package/dist/esm/providers/llm/adapters/index.js +1 -1
  197. package/dist/esm/providers/llm/adapters/index.js.map +3 -3
  198. package/dist/esm/providers/llm/adapters/openai/index.js +2 -0
  199. package/dist/esm/providers/llm/adapters/openai/index.js.map +7 -0
  200. package/dist/esm/providers/llm/adapters/openai/openai.js +2 -0
  201. package/dist/esm/providers/llm/adapters/openai/openai.js.map +7 -0
  202. package/dist/esm/providers/llm/adapters/openai-compatible.js +10 -0
  203. package/dist/esm/providers/llm/adapters/openai-compatible.js.map +7 -0
  204. package/dist/esm/providers/llm/adapters/openrouter/index.js +2 -0
  205. package/dist/esm/providers/llm/adapters/openrouter/index.js.map +7 -0
  206. package/dist/esm/providers/llm/adapters/openrouter/openrouter.js +2 -0
  207. package/dist/esm/providers/llm/adapters/openrouter/openrouter.js.map +7 -0
  208. package/dist/esm/providers/llm/index.js +1 -1
  209. package/dist/esm/providers/llm/index.js.map +3 -3
  210. package/dist/esm/providers/llm/toolmode/index.js +2 -0
  211. package/dist/esm/providers/llm/toolmode/index.js.map +7 -0
  212. package/dist/esm/providers/llm/toolmode/toolmode.js +2 -0
  213. package/dist/esm/providers/llm/toolmode/toolmode.js.map +7 -0
  214. package/dist/esm/providers/llm/types.js +1 -0
  215. package/dist/esm/providers/llm/types.js.map +4 -4
  216. package/dist/esm/providers/stt/adapters/deepgram/deepgram.js +1 -1
  217. package/dist/esm/providers/stt/adapters/deepgram/deepgram.js.map +3 -3
  218. package/dist/esm/providers/stt/adapters/index.js +1 -1
  219. package/dist/esm/providers/stt/adapters/index.js.map +3 -3
  220. package/dist/esm/providers/stt/adapters/openrouter/index.js +2 -0
  221. package/dist/esm/providers/stt/adapters/openrouter/index.js.map +7 -0
  222. package/dist/esm/providers/stt/adapters/openrouter/openrouter.js +2 -0
  223. package/dist/esm/providers/stt/adapters/openrouter/openrouter.js.map +7 -0
  224. package/dist/esm/providers/tts/adapters/index.js +1 -1
  225. package/dist/esm/providers/tts/adapters/index.js.map +3 -3
  226. package/dist/esm/providers/tts/adapters/kokoro/kokoro.js +4 -1
  227. package/dist/esm/providers/tts/adapters/kokoro/kokoro.js.map +3 -3
  228. package/dist/esm/providers/tts/adapters/openrouter/index.js +2 -0
  229. package/dist/esm/providers/tts/adapters/openrouter/index.js.map +7 -0
  230. package/dist/esm/providers/tts/adapters/openrouter/openrouter.js +2 -0
  231. package/dist/esm/providers/tts/adapters/openrouter/openrouter.js.map +7 -0
  232. package/dist/esm/transport/streamobject/field-stream/field-stream.js +2 -0
  233. package/dist/esm/transport/streamobject/field-stream/field-stream.js.map +7 -0
  234. package/dist/esm/transport/streamobject/field-stream/index.js +2 -0
  235. package/dist/esm/transport/streamobject/field-stream/index.js.map +7 -0
  236. package/dist/esm/transport/streamobject/index.js +2 -0
  237. package/dist/esm/transport/streamobject/index.js.map +7 -0
  238. package/dist/esm/transport/streamobject/json-adapter/index.js +2 -0
  239. package/dist/esm/transport/streamobject/json-adapter/index.js.map +7 -0
  240. package/dist/esm/transport/streamobject/json-adapter/json-adapter.js +4 -0
  241. package/dist/esm/transport/streamobject/json-adapter/json-adapter.js.map +7 -0
  242. package/dist/esm/transport/streamobject/reference/index.js +2 -0
  243. package/dist/esm/transport/streamobject/reference/index.js.map +7 -0
  244. package/dist/esm/transport/streamobject/reference/reference.js +2 -0
  245. package/dist/esm/transport/streamobject/reference/reference.js.map +7 -0
  246. package/dist/esm/transport/streamobject/stream-object/index.js +2 -0
  247. package/dist/esm/transport/streamobject/stream-object/index.js.map +7 -0
  248. package/dist/esm/transport/streamobject/stream-object/stream-object.js +2 -0
  249. package/dist/esm/transport/streamobject/stream-object/stream-object.js.map +7 -0
  250. package/dist/types/agents/agent.d.ts +3 -0
  251. package/dist/types/agents/tools/tools.d.ts +28 -6
  252. package/dist/types/conversations/conversation/conversation.d.ts +85 -6
  253. package/dist/types/conversations/conversations.d.ts +11 -1
  254. package/dist/types/conversations/index.d.ts +2 -1
  255. package/dist/types/conversations/orchestration/coordination/coordination.d.ts +192 -0
  256. package/dist/types/conversations/orchestration/coordination/index.d.ts +2 -0
  257. package/dist/types/conversations/orchestration/orchestrator/coordination-runner/coordination-runner.d.ts +108 -0
  258. package/dist/types/conversations/orchestration/orchestrator/coordination-runner/index.d.ts +2 -0
  259. package/dist/types/conversations/orchestration/orchestrator/generation/generation.d.ts +43 -0
  260. package/dist/types/conversations/orchestration/orchestrator/generation/index.d.ts +2 -0
  261. package/dist/types/conversations/orchestration/orchestrator/history/history.d.ts +62 -0
  262. package/dist/types/conversations/orchestration/orchestrator/history/index.d.ts +1 -0
  263. package/dist/types/conversations/orchestration/orchestrator/index.d.ts +10 -0
  264. package/dist/types/conversations/orchestration/orchestrator/orchestrator.d.ts +45 -27
  265. package/dist/types/conversations/orchestration/orchestrator/routing/index.d.ts +1 -0
  266. package/dist/types/conversations/orchestration/orchestrator/routing/routing.d.ts +19 -0
  267. package/dist/types/conversations/orchestration/orchestrator/speech/index.d.ts +2 -0
  268. package/dist/types/conversations/orchestration/orchestrator/speech/speech.d.ts +49 -0
  269. package/dist/types/conversations/orchestration/orchestrator/tools/index.d.ts +2 -0
  270. package/dist/types/conversations/orchestration/orchestrator/tools/tools.d.ts +31 -0
  271. package/dist/types/conversations/orchestration/test-harness.d.ts +96 -0
  272. package/dist/types/conversations/orchestration/text-chunker/index.d.ts +1 -0
  273. package/dist/types/conversations/orchestration/text-chunker/text-chunker.d.ts +39 -0
  274. package/dist/types/conversations/stream/conversation-stream.d.ts +42 -0
  275. package/dist/types/conversations/stream/index.d.ts +1 -0
  276. package/dist/types/conversations/types.d.ts +32 -0
  277. package/dist/types/index.d.ts +5 -38
  278. package/dist/types/pipeflow/index.d.ts +2 -0
  279. package/dist/types/pipeflow/pipeflow.d.ts +35 -0
  280. package/dist/types/providers/index.d.ts +1 -1
  281. package/dist/types/providers/llm/adapters/claude/claude.d.ts +45 -0
  282. package/dist/types/providers/llm/adapters/claude/index.d.ts +2 -0
  283. package/dist/types/providers/llm/adapters/deepseek/deepseek.d.ts +23 -2
  284. package/dist/types/providers/llm/adapters/index.d.ts +3 -0
  285. package/dist/types/providers/llm/adapters/openai/index.d.ts +2 -0
  286. package/dist/types/providers/llm/adapters/openai/openai.d.ts +45 -0
  287. package/dist/types/providers/llm/adapters/openai-compatible.d.ts +44 -0
  288. package/dist/types/providers/llm/adapters/openrouter/index.d.ts +2 -0
  289. package/dist/types/providers/llm/adapters/openrouter/openrouter.d.ts +60 -0
  290. package/dist/types/providers/llm/index.d.ts +5 -2
  291. package/dist/types/providers/llm/toolmode/index.d.ts +2 -0
  292. package/dist/types/providers/llm/toolmode/toolmode.d.ts +99 -0
  293. package/dist/types/providers/llm/types.d.ts +62 -0
  294. package/dist/types/providers/stt/adapters/deepgram/deepgram.d.ts +4 -1
  295. package/dist/types/providers/stt/adapters/index.d.ts +1 -0
  296. package/dist/types/providers/stt/adapters/openrouter/index.d.ts +2 -0
  297. package/dist/types/providers/stt/adapters/openrouter/openrouter.d.ts +94 -0
  298. package/dist/types/providers/tts/adapters/index.d.ts +1 -0
  299. package/dist/types/providers/tts/adapters/kokoro/kokoro.d.ts +17 -2
  300. package/dist/types/providers/tts/adapters/openrouter/index.d.ts +2 -0
  301. package/dist/types/providers/tts/adapters/openrouter/openrouter.d.ts +45 -0
  302. package/dist/types/transport/streamobject/field-stream/field-stream.d.ts +85 -0
  303. package/dist/types/transport/streamobject/field-stream/index.d.ts +2 -0
  304. package/dist/types/transport/streamobject/index.d.ts +8 -0
  305. package/dist/types/transport/streamobject/json-adapter/index.d.ts +2 -0
  306. package/dist/types/transport/streamobject/json-adapter/json-adapter.d.ts +65 -0
  307. package/dist/types/transport/streamobject/reference/index.d.ts +2 -0
  308. package/dist/types/transport/streamobject/reference/reference.d.ts +127 -0
  309. package/dist/types/transport/streamobject/stream-object/index.d.ts +2 -0
  310. package/dist/types/transport/streamobject/stream-object/stream-object.d.ts +31 -0
  311. package/package.json +23 -2
@@ -1,3 +1,2 @@
1
- var m=Object.defineProperty;var d=(u,t)=>m(u,"name",{value:t,configurable:!0});class f{static{d(this,"Orchestrator")}conversation;agent;llm;stt;tts;persistence;toolTimeoutMs;maxToolIterations;temperature;maxTokens;started=!1;generating=!1;epoch=0;unsubscribers=[];sttSessions=new Map;history=[];toolWaiters=new Map;generationChain=Promise.resolve();speechChain=Promise.resolve();speechBuffer="";pendingTurns=0;pendingGenerations=0;audioSequence=0;turnSequence=0;constructor(t){const e=t.llm??t.agent?.llm;if(!t.stt)throw new Error("Orchestrator requires an STT provider");if(t.agent&&!e)throw new Error("Orchestrator requires an LLM when an agent is attached: pass one explicitly or configure the agent with one");if(t.agent&&!t.tts)throw new Error("Orchestrator requires a TTS provider when an agent is attached");this.conversation=t.conversation,this.agent=t.agent,this.llm=e,this.stt=t.stt,this.tts=t.tts,this.persistence=t.persistence,this.toolTimeoutMs=t.toolTimeoutMs??3e4,this.maxToolIterations=t.maxToolIterations??10,this.temperature=t.temperature,this.maxTokens=t.maxTokens}async start(){if(!this.started){if(this.started=!0,this.persistence){const[t,e]=await Promise.all([this.persistence.listTurns(this.conversation.id),this.persistence.listGenerations(this.conversation.id)]),r=[...t.map(s=>({at:s.startedAt,kind:"turn",turn:s})),...e.filter(s=>s.status==="completed").map(s=>({at:s.startedAt,kind:"generation",text:s.text}))].sort((s,i)=>s.at-i.at);for(const s of r)s.kind==="turn"?this.history.push({role:"user",content:`${s.turn.participantName}: ${s.turn.text}`}):this.history.push({role:"assistant",content:s.text})}this.unsubscribers.push(this.conversation.on("stop",()=>{this.stop()}),this.conversation.on("audio-in",t=>this.onAudioIn(t)),this.conversation.on("interrupt",()=>this.onInterrupt()),this.conversation.on("tool-call-result",t=>this.onToolCallResult(t.result)))}}async stop(){if(!this.started)return;this.started=!1,this.epoch++,this.llm?.stop(),this.tts?.stop(),this.cancelToolWaiters("conversation stopped"),this.speechBuffer="";for(const e of this.unsubscribers)e();this.unsubscribers.length=0;const t=[...this.sttSessions.values()];this.sttSessions.clear();for(const{session:e}of t)await e.end().catch(()=>{})}async whenIdle(){for(;;){for(;this.pendingTurns>0||this.pendingGenerations>0||this.generating;)await Bun.sleep(1);if(await Promise.resolve(),this.pendingTurns===0&&this.pendingGenerations===0&&!this.generating)return}}onAudioIn(t){let e=this.sttSessions.get(t.userId);if(!e){const r=this.stt.start({});r.on("partial",s=>this.onPartial(t.userId,s)),r.on("final",s=>this.onFinal(t.userId,s)),r.on("error",s=>this.onProviderError(s)),e={session:r,turnStartedAt:null},this.sttSessions.set(t.userId,e)}e.turnStartedAt===null&&(e.turnStartedAt=Date.now()),e.session.write(t.audio.data),this.pendingGenerations>0&&this.conversation.interrupt()}onPartial(t,e){const r=e.trim();r&&this.conversation.emit("partial-transcript",{conversationId:this.conversation.id,userId:t,text:r})}onFinal(t,e){const r=e.trim();if(!r)return;const s=this.conversation.state.participants.get(t);if(!s)return;const i=this.sttSessions.get(t),n=i?.turnStartedAt??Date.now();i&&(i.turnStartedAt=null);const o={id:crypto.randomUUID(),conversationId:this.conversation.id,participantId:t,participantName:s.aliases[0]??t,text:r,sequence:this.turnSequence++,startedAt:n,endedAt:Date.now()};this.pendingTurns++,this.processTurn(o)}async processTurn(t){try{await this.conversation.pushTurn(t),await this.conversation.pushTranscript({speaker:t.participantName,speakerKind:"participant",text:t.text}),this.history.push({role:"user",content:`${t.participantName}: ${t.text}`}),this.agent&&this.queueGeneration()}finally{this.pendingTurns--}}onInterrupt(){this.epoch++,this.llm?.stop(),this.tts?.stop(),this.cancelToolWaiters("interrupted"),this.speechBuffer=""}onToolCallResult(t){const e=this.toolWaiters.get(t.id);e&&(this.toolWaiters.delete(t.id),e(t))}onProviderError(t){this.conversation.emit("error",{conversationId:this.conversation.id,error:t})}queueGeneration(){this.pendingGenerations++;const t=this.epoch;this.generationChain=this.generationChain.then(async()=>{if(this.epoch!==t){this.pendingGenerations--;return}try{await this.generate()}finally{this.pendingGenerations--}})}async generate(){const{agent:t,llm:e,tts:r}=this;if(!(!t||!e||!r)){this.generating=!0;try{await this.runGeneration(this.epoch,t,e,r)}finally{this.generating=!1}}}async runGeneration(t,e,r,s){await this.conversation.pushGeneration({id:crypto.randomUUID(),conversationId:this.conversation.id,agentName:e.name,text:"",status:"streaming",startedAt:Date.now()});const i=e.tools.map(a=>({name:a.name,description:a.description,parameters:a.parameters??{type:"object",properties:{}}})),n=[];e.context&&n.push({role:"system",content:e.context}),n.push(...this.history);let o="";try{for(let a=0;a<this.maxToolIterations;a++){if(this.epoch!==t)return;const l=[];let p=!1;for await(const h of r.stream({messages:n,tools:i,temperature:this.temperature,maxTokens:this.maxTokens})){if(this.epoch!==t)return;switch(h.type){case"delta":o+=h.content,this.feedDelta(h.content);break;case"tool_call":l.push({id:h.id,name:h.name,arguments:h.arguments});break;case"error":throw h.error;case"done":p=!0}}if(this.epoch!==t)return;if(l.length>0){this.flushSpeech(),n.push({role:"assistant",content:o,toolCalls:l});const h=await this.resolveToolCalls(l,t);if(this.epoch!==t)return;for(const c of h)n.push({role:"tool",toolCallId:c.id,name:c.name,content:JSON.stringify(c.error!==void 0?{error:c.error}:c.result)});continue}if(p)break}if(this.epoch!==t||(this.flushSpeech(),await this.speechChain,this.epoch!==t))return;await this.conversation.completeGeneration(o),await this.conversation.pushTranscript({speaker:e.name,speakerKind:"agent",text:o}),this.history.push({role:"assistant",content:o})}catch(a){if(this.epoch!==t)return;this.conversation.emit("error",{conversationId:this.conversation.id,error:a instanceof Error?a:new Error(String(a))}),await this.conversation.completeGeneration(o),o&&(await this.conversation.pushTranscript({speaker:e.name,speakerKind:"agent",text:o}),this.history.push({role:"assistant",content:o}))}}async resolveToolCalls(t,e){const r=t.map(i=>this.waitForToolResult(i.id,e));for(const i of t){let n;try{n=JSON.parse(i.arguments)}catch{n=i.arguments}this.conversation.requestToolCall({id:i.id,name:i.name,arguments:n})}return(await Promise.all(r)).map((i,n)=>{const o=t[n];return{id:i.id,name:o.name,result:"result"in i?i.result:void 0,error:"error"in i?i.error:void 0}})}waitForToolResult(t,e){return new Promise(r=>{const s=setTimeout(()=>{this.toolWaiters.delete(t),r({id:t,error:`Tool call "${t}" timed out`})},this.toolTimeoutMs);this.toolWaiters.set(t,i=>{clearTimeout(s),r(i)})})}cancelToolWaiters(t){for(const[e,r]of[...this.toolWaiters])this.toolWaiters.delete(e),r({id:e,error:t})}feedDelta(t){for(this.speechBuffer+=t;;){let e=-1;for(let s=0;s<this.speechBuffer.length;s++){const i=this.speechBuffer[s];if(i==="."||i==="!"||i==="?"||i===`
2
- `){e=s;break}}if(e<0)break;const r=this.speechBuffer.slice(0,e+1).trim();this.speechBuffer=this.speechBuffer.slice(e+1),r&&this.speak(r)}}flushSpeech(){const t=this.speechBuffer.trim();this.speechBuffer="",t&&this.speak(t)}speak(t){const e=this.tts;if(!e)return;const r=this.epoch;this.speechChain=this.speechChain.then(async()=>{if(!(!this.started||this.epoch!==r))try{for await(const s of e.stream({text:t})){if(!this.started||this.epoch!==r)break;this.conversation.pushAudio({data:s,timestamp:Date.now(),sequence:this.audioSequence++})}}catch(s){if(this.epoch!==r)return;this.conversation.emit("error",{conversationId:this.conversation.id,error:s instanceof Error?s:new Error(String(s))})}})}}export{f as Orchestrator};
1
+ var p=Object.defineProperty;var r=(c,t)=>p(c,"name",{value:t,configurable:!0});import{ConversationHistory as l}from"./history/history.js";import{findAddressedAgent as u,pickAgent as m}from"./routing/routing.js";import{GenerationRunner as v}from"./generation/generation.js";import{SpeechPipeline as g}from"./speech/speech.js";import{ToolCallManager as f}from"./tools/tools.js";import{CoordinationRunner as y}from"./coordination-runner/coordination-runner.js";class L{static{r(this,"Orchestrator")}conversation;agents;llm;stt;tts;persistence;maxToolIterations;historyWindow;temperature;maxTokens;history;speech;tools;generation;coordination;started=!1;generating=!1;epoch=0;generationChain=Promise.resolve();unsubscribers=[];sttSessions=new Map;pendingTurns=0;pendingGenerations=0;turnSequence=0;constructor(t){const e=t.agents??[],i=t.llm??e[0]?.llm;if(e.length>0&&!i)throw new Error("Orchestrator requires an LLM when agents are attached: pass one explicitly or configure an agent with one");this.conversation=t.conversation,this.agents=e,this.llm=i,this.stt=t.stt,this.tts=t.tts,this.persistence=t.persistence,this.maxToolIterations=t.maxToolIterations??10,this.historyWindow=t.historyWindow??{maxTurns:5,maxChars:4e3},this.temperature=t.temperature,this.maxTokens=t.maxTokens,this.history=new l,this.speech=new g({tts:this.tts,conversation:this.conversation,isCurrent:r(n=>this.started&&n===this.epoch,"isCurrent")}),this.tools=new f(this.conversation,t.toolTimeoutMs??3e4),this.generation=new v,this.coordination=new y({conversation:this.conversation,agents:r(()=>this.agents,"agents"),llm:r(()=>this.llm,"llm"),history:this.history,historyWindow:this.historyWindow,speech:this.speech,generation:this.generation,tools:this.tools,maxCoordinationSteps:t.maxCoordinationSteps??20,maxToolIterations:this.maxToolIterations,temperature:this.temperature,maxTokens:this.maxTokens,currentEpoch:r(()=>this.epoch,"currentEpoch"),isCurrent:r(n=>this.started&&n===this.epoch,"isCurrent")}),this.coordination.register(t.coordinations??{},e)}async start(){if(!this.started){if(this.started=!0,this.persistence){const[t,e]=await Promise.all([this.persistence.listTurns(this.conversation.id),this.persistence.listGenerations(this.conversation.id)]);this.history.rehydrate(t,e,this.conversation)}this.unsubscribers.push(this.conversation.on("stop",()=>{this.stop()}),this.conversation.on("audio-in",t=>this.onAudioIn(t)),this.conversation.on("text-in",({userId:t,text:e})=>this.onFinal(t,e)),this.conversation.on("interrupt",()=>this.onInterrupt()),this.conversation.on("tool-call-result",({result:t})=>this.tools.handleResult(t)))}}async stop(){if(!this.started)return;this.started=!1,this.epoch++,this.coordination.cancel(),this.stopLlms(),this.speech.stop(),this.tools.cancelAll("conversation stopped");for(const e of this.unsubscribers)e();this.unsubscribers.length=0;const t=[...this.sttSessions.values()];this.sttSessions.clear();for(const{session:e}of t)await e.end().catch(()=>{})}async whenIdle(){for(;;){for(;this.pendingTurns>0||this.pendingGenerations>0||this.generating;)await Bun.sleep(1);if(await Promise.resolve(),this.pendingTurns===0&&this.pendingGenerations===0&&!this.generating)return}}onAudioIn(t){if(!this.stt)return;let e=this.sttSessions.get(t.userId);if(!e){const i=this.stt.start({});i.on("partial",n=>this.onPartial(t.userId,n)),i.on("final",n=>this.onFinal(t.userId,n)),i.on("error",n=>this.onProviderError(n)),e={session:i,turnStartedAt:null},this.sttSessions.set(t.userId,e)}if(e.turnStartedAt===null&&(e.turnStartedAt=Date.now()),e.session.write(t.audio.data),this.coordination.hasPending()){this.speech.stop();return}this.pendingGenerations>0&&this.conversation.interrupt()}onPartial(t,e){const i=e.trim();i&&this.conversation.emit("partial-transcript",{conversationId:this.conversation.id,userId:t,text:i})}onFinal(t,e){const i=e.trim();if(!i)return;const n=this.conversation.state.participants.get(t);if(!n)return;const a=this.sttSessions.get(t),d=a?.turnStartedAt??Date.now();a&&(a.turnStartedAt=null);const h={id:crypto.randomUUID(),conversationId:this.conversation.id,participantId:t,participantName:n.aliases[0]??t,text:i,sequence:this.turnSequence++,startedAt:d,endedAt:Date.now()};this.pendingTurns++,this.processTurn(h)}async processTurn(t){try{if(await this.conversation.pushTurn(t),await this.conversation.pushTranscript({speaker:t.participantName,speakerKind:"participant",text:t.text}),this.history.addUserTurn(t,this.conversation),this.agents.length===0)return;if(this.coordination.hasPending()){this.enqueueCoordinationRun(()=>this.coordination.resume(t));return}if(this.agents.length===1||u(this.agents,t.text)){this.queueGeneration(t);return}this.enqueueCoordinationRun(()=>this.coordination.runDefault(t))}finally{this.pendingTurns--}}onInterrupt(){this.epoch++,this.coordination.cancel(),this.stopLlms(),this.speech.stop(),this.tools.cancelAll("interrupted")}stopLlms(){const t=new Set;this.llm&&t.add(this.llm);for(const e of this.agents)e.llm&&t.add(e.llm);for(const e of t)e.stop()}onProviderError(t){this.conversation.emit("error",{conversationId:this.conversation.id,error:t})}queueGeneration(t){this.pendingGenerations++;const e=this.epoch;this.generationChain=this.generationChain.then(async()=>{if(this.epoch!==e){this.pendingGenerations--;return}try{await this.generate(t)}finally{this.pendingGenerations--}})}async generate(t){if(this.agents.length===0)return;const e=m(this.agents,t.text);if(!e)return;const i=e.llm??this.llm;if(i){this.generating=!0;try{await this.runGeneration(this.epoch,t,e,i)}finally{this.generating=!1}}}async runGeneration(t,e,i,n){const a=crypto.randomUUID();await this.conversation.pushGeneration({id:a,conversationId:this.conversation.id,agentName:i.name,text:"",status:"streaming",startedAt:Date.now()});const d=i.tools.map(o=>({name:o.name,description:o.description,parameters:o.parameters??{type:"object",properties:{}}})),h=[];i.context&&h.push({role:"system",name:i.name,content:i.context}),h.push(...this.history.windowed(this.historyWindow));const s=await this.generation.run({agentName:i.name,llm:n,messages:h,tools:d,temperature:this.temperature,maxTokens:this.maxTokens,maxToolIterations:this.maxToolIterations,isCurrent:r(()=>this.epoch===t,"isCurrent"),onDelta:r(o=>this.speech.feed(o,t),"onDelta"),resolveToolCalls:r(o=>this.tools.resolveCalls(o),"resolveToolCalls")});if(this.epoch===t&&s.status!=="interrupted"){if(s.status==="error"){this.conversation.emit("error",{conversationId:this.conversation.id,error:s.error instanceof Error?s.error:new Error(String(s.error))}),await this.conversation.completeGeneration(s.text),s.text&&(await this.conversation.pushTranscript({speaker:i.name,speakerKind:"agent",text:s.text}),this.history.addAssistant(i.name,s.text));return}this.speech.flush(t),await this.speech.waitForIdle(),this.epoch===t&&(await this.conversation.completeGeneration(s.text),await this.conversation.pushTranscript({speaker:i.name,speakerKind:"agent",text:s.text}),this.history.addAssistant(i.name,s.text))}}enqueueCoordinationRun(t){this.pendingGenerations++,this.generationChain=this.generationChain.then(async()=>{this.generating=!0;try{await t()}finally{this.generating=!1,this.pendingGenerations--}})}}export{L as Orchestrator};
3
2
  //# sourceMappingURL=orchestrator.js.map
@@ -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", "__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 { 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\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 the application to resolve a tool call. */\n toolTimeoutMs?: number;\n /** Safety bound on tool-call round trips per generation. */\n maxToolIterations?: number;\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 * Bounds 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\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 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 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 });\n this.tools = new ToolCallManager(this.conversation, options.toolTimeoutMs ?? 30_000);\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 const 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 onDelta: (delta) => this.speech.feed(delta, epoch),\n resolveToolCalls: (calls) => this.tools.resolveCalls(calls),\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": ["ConversationHistory", "findAddressedAgent", "pickAgent", "GenerationRunner", "SpeechPipeline", "ToolCallManager", "CoordinationRunner", "Orchestrator", "__name", "options", "agents", "llm", "epoch", "turns", "generations", "payload", "userId", "text", "result", "unsubscribe", "sessions", "session", "entry", "error", "trimmed", "participant", "startedAt", "turn", "seen", "agent", "generationId", "definitions", "tool", "messages", "outcome", "delta", "calls", "run"]
7
7
  }
@@ -0,0 +1,2 @@
1
+ import{buildUnderstandPrompt as n,findAddressedAgent as t,findAgentByName as r,pickAgent as i}from"./routing.js";export{n as buildUnderstandPrompt,t as findAddressedAgent,r as findAgentByName,i as pickAgent};
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": "AAAA,OACE,yBAAAA,EACA,sBAAAC,EACA,mBAAAC,EACA,aAAAC,MACK",
6
+ "names": ["buildUnderstandPrompt", "findAddressedAgent", "findAgentByName", "pickAgent"]
7
+ }
@@ -0,0 +1,23 @@
1
+ var s=Object.defineProperty;var r=(t,o)=>s(t,"name",{value:o,configurable:!0});function l(t,o){if(t.length===0)return null;const n=o.toLowerCase();for(const e of t){if(e.name&&n.includes(e.name.toLowerCase()))return e;for(const a of e.aliases)if(n.includes(a.toLowerCase()))return e}return t[0]}r(l,"pickAgent");function u(t,o){const n=o.toLowerCase();for(const e of t){if(e.name&&n.includes(e.name.toLowerCase()))return e;for(const a of e.aliases)if(n.includes(a.toLowerCase()))return e}return null}r(u,"findAddressedAgent");function c(t,o){const n=o.trim().toLowerCase();for(const e of t){if(e.name.toLowerCase()===n)return e;for(const a of e.aliases)if(a.toLowerCase()===n)return e}return null}r(c,"findAgentByName");function d(t){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
+ ${t.map(n=>{const e=n.aliases.length>0?` (aliases: ${n.aliases.join(", ")})`:"";return`- ${n.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(d,"buildUnderstandPrompt");export{d as buildUnderstandPrompt,u as findAddressedAgent,c as findAgentByName,l as pickAgent};
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": "+EAUO,SAASA,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": ["pickAgent", "agents", "text", "normalized", "agent", "alias", "__name", "findAddressedAgent", "findAgentByName", "nameOrAlias", "buildUnderstandPrompt", "aliases"]
7
+ }
@@ -0,0 +1,2 @@
1
+ import{SpeechPipeline as i}from"./speech.js";export{i as SpeechPipeline};
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": "AAAA,OAAS,kBAAAA,MAAsB",
6
+ "names": ["SpeechPipeline"]
7
+ }
@@ -0,0 +1,2 @@
1
+ var c=Object.defineProperty;var o=(s,t)=>c(s,"name",{value:t,configurable:!0});import{TextChunker as a}from"../../text-chunker/text-chunker.js";class v{static{o(this,"SpeechPipeline")}tts;conversation;isCurrent;chunker=new a;speechEpoch=0;chain=Promise.resolve();audioSequence=0;constructor(t){this.tts=t.tts,this.conversation=t.conversation,this.isCurrent=t.isCurrent}feed(t,e){if(t.length!==0){this.conversation.noteTiming("firstToken"),this.conversation.pushTextDelta(t);for(const r of this.chunker.push(t))this.speak(r,e)}}flush(t){const e=this.chunker.flush();e&&this.speak(e,t)}speak(t,e){const r=this.tts;if(!r)return;this.conversation.noteTiming("firstTtsText");const n=this.speechEpoch;this.chain=this.chain.then(async()=>{if(!(!this.isCurrent(e)||this.speechEpoch!==n)){this.conversation.noteTiming("firstTtsRequest");try{let i=!0;for await(const h of r.stream({text:t})){if(!this.isCurrent(e)||this.speechEpoch!==n)break;i&&(i=!1,this.conversation.noteTiming("firstTtsAudio")),this.conversation.pushAudio({data:h,timestamp:Date.now(),sequence:this.audioSequence++})}}catch(i){if(!this.isCurrent(e))return;this.conversation.emit("error",{conversationId:this.conversation.id,error:i instanceof Error?i:new Error(String(i))})}}})}stop(){this.speechEpoch++,this.chunker.clear(),this.tts?.stop()}waitForIdle(){return this.chain}}export{v as SpeechPipeline};
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\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 chunker = new TextChunker();\n private speechEpoch = 0;\n private chain: Promise<void> = Promise.resolve();\n private audioSequence = 0;\n\n constructor(options: SpeechPipelineOptions) {\n this.tts = options.tts;\n this.conversation = options.conversation;\n this.isCurrent = options.isCurrent;\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 /** Synthesize a sentence and push the audio chunks out to the app. */\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.chain = this.chain.then(async () => {\n if (!this.isCurrent(epoch) || this.speechEpoch !== speechEpoch) {\n return;\n }\n // The TTS provider was asked to synthesize.\n this.conversation.noteTiming(\"firstTtsRequest\");\n try {\n let first = true;\n for await (const chunk of tts.stream({ text: sentence })) {\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 if (!this.isCurrent(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 /**\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.tts?.stop();\n }\n\n /** Resolve when queued TTS synthesis has settled. */\n waitForIdle(): Promise<void> {\n return this.chain;\n }\n}\n"],
5
+ "mappings": "+EAEA,OAAS,eAAAA,MAAmB,kCAuBrB,MAAMC,CAAe,CAzB5B,MAyB4B,CAAAC,EAAA,uBACT,IACA,aACA,UACA,QAAU,IAAIF,EACvB,YAAc,EACd,MAAuB,QAAQ,QAAQ,EACvC,cAAgB,EAExB,YAAYG,EAAgC,CAC1C,KAAK,IAAMA,EAAQ,IACnB,KAAK,aAAeA,EAAQ,aAC5B,KAAK,UAAYA,EAAQ,SAC3B,CAOA,KAAKC,EAAeC,EAAqB,CACvC,GAAID,EAAM,SAAW,EAErB,MAAK,aAAa,WAAW,YAAY,EAGzC,KAAK,aAAa,cAAcA,CAAK,EAIrC,UAAWE,KAAS,KAAK,QAAQ,KAAKF,CAAK,EACzC,KAAK,MAAME,EAAOD,CAAK,EAE3B,CAGA,MAAMA,EAAqB,CACzB,MAAME,EAAO,KAAK,QAAQ,MAAM,EAC5BA,GAAM,KAAK,MAAMA,EAAMF,CAAK,CAClC,CAGA,MAAMG,EAAkBH,EAAqB,CAC3C,MAAMI,EAAM,KAAK,IACjB,GAAI,CAACA,EAAK,OAEV,KAAK,aAAa,WAAW,cAAc,EAC3C,MAAMC,EAAc,KAAK,YACzB,KAAK,MAAQ,KAAK,MAAM,KAAK,SAAY,CACvC,GAAI,GAAC,KAAK,UAAUL,CAAK,GAAK,KAAK,cAAgBK,GAInD,MAAK,aAAa,WAAW,iBAAiB,EAC9C,GAAI,CACF,IAAIC,EAAQ,GACZ,gBAAiBL,KAASG,EAAI,OAAO,CAAE,KAAMD,CAAS,CAAC,EAAG,CACxD,GAAI,CAAC,KAAK,UAAUH,CAAK,GAAK,KAAK,cAAgBK,EACjD,MAEEC,IACFA,EAAQ,GAER,KAAK,aAAa,WAAW,eAAe,GAE9C,KAAK,aAAa,UAAU,CAC1B,KAAML,EACN,UAAW,KAAK,IAAI,EACpB,SAAU,KAAK,eACjB,CAAC,CACH,CACF,OAASM,EAAO,CACd,GAAI,CAAC,KAAK,UAAUP,CAAK,EAAG,OAC5B,KAAK,aAAa,KAAK,QAAS,CAC9B,eAAgB,KAAK,aAAa,GAClC,MAAOO,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,CACjE,CAAC,CACH,EACF,CAAC,CACH,CAMA,MAAa,CACX,KAAK,cACL,KAAK,QAAQ,MAAM,EACnB,KAAK,KAAK,KAAK,CACjB,CAGA,aAA6B,CAC3B,OAAO,KAAK,KACd,CACF",
6
+ "names": ["TextChunker", "SpeechPipeline", "__name", "options", "delta", "epoch", "chunk", "rest", "sentence", "tts", "speechEpoch", "first", "error"]
7
+ }
@@ -0,0 +1,2 @@
1
+ import{ToolCallManager as e}from"./tools.js";export{e as ToolCallManager};
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": "AAAA,OAAS,mBAAAA,MAAuB",
6
+ "names": ["ToolCallManager"]
7
+ }
@@ -0,0 +1,2 @@
1
+ var a=Object.defineProperty;var n=(i,e)=>a(i,"name",{value:e,configurable:!0});class u{static{n(this,"ToolCallManager")}conversation;timeoutMs;waiters=new Map;constructor(e,o){this.conversation=e,this.timeoutMs=o}async resolveCalls(e){const o=e.map(t=>this.wait(t.id));for(const t of e){let r;try{r=JSON.parse(t.arguments)}catch{r=t.arguments}this.conversation.requestToolCall({id:t.id,name:t.name,arguments:r})}return(await Promise.all(o)).map((t,r)=>{const l=e[r];return{id:t.id,name:l.name,result:"result"in t?t.result:void 0,error:"error"in t?t.error:void 0}})}handleResult(e){const o=this.waiters.get(e.id);o&&(this.waiters.delete(e.id),o(e))}cancelAll(e){for(const[o,s]of[...this.waiters])this.waiters.delete(o),s({id:o,error:e})}wait(e){return new Promise(o=>{const s=setTimeout(()=>{this.waiters.delete(e),o({id:e,error:`Tool call "${e}" timed out`})},this.timeoutMs);this.waiters.set(e,t=>{clearTimeout(s),o(t)})})}}export{u as ToolCallManager};
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\";\n\nexport interface ResolvedToolCall {\n id: string;\n name: string;\n result?: unknown;\n error?: string;\n}\n\n/**\n * Tracks tool calls handed to the application and resolves them once the\n * application reports back (or a timeout fires). Stale results \u2014 timed out,\n * already resolved, or superseded by an interrupt \u2014 are dropped.\n */\nexport class ToolCallManager {\n private readonly conversation: Conversation;\n private readonly timeoutMs: number;\n private readonly waiters = new Map<string, (result: ToolCallResult) => void>();\n\n constructor(conversation: Conversation, timeoutMs: number) {\n this.conversation = conversation;\n this.timeoutMs = timeoutMs;\n }\n\n /**\n * Hand the calls to the application and resolve each one once it is\n * answered or times out. Returns them in call order, with either a result\n * 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 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 /** 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 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": "+EAgBO,MAAMA,CAAgB,CAhB7B,MAgB6B,CAAAC,EAAA,wBACV,aACA,UACA,QAAU,IAAI,IAE/B,YAAYC,EAA4BC,EAAmB,CACzD,KAAK,aAAeD,EACpB,KAAK,UAAYC,CACnB,CAOA,MAAM,aAAaC,EAAmD,CACpE,MAAMC,EAAcD,EAAM,IAAKE,GAAS,KAAK,KAAKA,EAAK,EAAE,CAAC,EAC1D,UAAWA,KAAQF,EAAO,CACxB,IAAIG,EACJ,GAAI,CACFA,EAAO,KAAK,MAAMD,EAAK,SAAS,CAClC,MAAQ,CACNC,EAAOD,EAAK,SACd,CACA,KAAK,aAAa,gBAAgB,CAChC,GAAIA,EAAK,GACT,KAAMA,EAAK,KACX,UAAWC,CACb,CAAC,CACH,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,CAEQ,KAAKC,EAAqC,CAChD,OAAO,IAAI,QAASF,GAAY,CAC9B,MAAMG,EAAU,WAAW,IAAM,CAC/B,KAAK,QAAQ,OAAOD,CAAE,EACtBF,EAAQ,CAAE,GAAAE,EAAI,MAAO,cAAcA,CAAE,aAAc,CAAC,CACtD,EAAG,KAAK,SAAS,EACjB,KAAK,QAAQ,IAAIA,EAAKJ,GAAW,CAC/B,aAAaK,CAAO,EACpBH,EAAQF,CAAM,CAChB,CAAC,CACH,CAAC,CACH,CACF",
6
+ "names": ["ToolCallManager", "__name", "conversation", "timeoutMs", "calls", "resolutions", "call", "args", "result", "index", "resolve", "reason", "id", "timeout"]
7
+ }
@@ -0,0 +1,2 @@
1
+ var f=Object.defineProperty;var n=(r,t)=>f(r,"name",{value:t,configurable:!0});import{Agent as d}from"../../agents/agent.js";import"../../agents/tools/tools.js";import{Conversation as h}from"../conversation/conversation.js";import{MemoryPersistence as u}from"../../persistence/adapters/memory/memory.js";import{Orchestrator as T}from"./orchestrator/orchestrator.js";class m{constructor(t){this.script=t}script;static{n(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{n(this,"FakeSTT")}sessions=[];startOptions=[];start(t={}){const e=new L;return this.sessions.push(e),this.startOptions.push(t),e}cancel(){}}class L{static{n(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{n(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 R{constructor(t,e=20){this.chunksFor=t;this.delayMs=e}chunksFor;delayMs;static{n(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 C(r){return(async()=>{const t=new u,e=new h({id:"conv-1",persistence:t}),o=r.llm??new m(r.script),c=new v,i=r.tts??new S(r.ttsChunks??(p=>[new TextEncoder().encode(p)])),l=new d({name:"Jarvis",context:r.context??"Be concise.",llm:o,tools:r.tools}),a=new T({conversation:e,agents:[l],llm:o,stt:c,tts:i,persistence:t,toolTimeoutMs:r.toolTimeoutMs??3e4,historyWindow:r.historyWindow});return e.start(),await e.participate({userId:"alice",aliases:["al"]}),await a.start(),{conversation:e,orchestrator:a,llm:o,stt:c,tts:i,persistence:t}})()}n(C,"setup");async function q(r,t=2e3){const e=Date.now();for(;!r();){if(Date.now()-e>t)throw new Error("waitFor timed out");await Bun.sleep(2)}}n(q,"waitFor");async function H(r,t,e){r.conversation.listen({userId:t,audio:new Uint8Array([1])}),r.stt.sessions.at(-1).emitFinal(e),await r.orchestrator.whenIdle()}n(H,"speak");function x(r){return async function*(){yield{type:"delta",content:r},yield{type:"done"}}}n(x,"respond");function O(r){return(async()=>{const t=new u,e=new h({id:"conv-1",persistence:t}),o=new v,c=new S(s=>[new TextEncoder().encode(s)]),i=new m(r.coordinatorScript),l=new Map([["Jarvis",i]]),a=[new d({name:"Jarvis",context:"Be concise.",llm:i})];for(const[s,y]of Object.entries(r.scripts)){const w=new m(y);l.set(s,w),a.push(new d({name:s,context:`You are ${s}.`,llm:w,tools:r.tools?.[s]}))}if(a.length===1){const s=new m(x("ok"));l.set("Helper",s),a.push(new d({name:"Helper",context:"You help.",llm:s}))}for(const[s,y]of Object.entries(r.coordinations??{}))l.set(s,y.llm);const p=new T({conversation:e,agents:a,llm:i,coordinations:r.coordinations,maxCoordinationSteps:r.maxCoordinationSteps,stt:o,tts:c,persistence:t});return e.start(),await e.participate({userId:"alice",aliases:["al"]}),await p.start(),{conversation:e,orchestrator:p,llm:i,stt:o,tts:c,persistence:t,llms:l}})()}n(O,"setupRoster");export{m as FakeLLM,v as FakeSTT,L as FakeSTTSession,S as FakeTTS,R as SlowTTS,x as respond,C as setup,O as setupRoster,H as speak,q as waitFor};
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}): 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 });\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}): 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 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": "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",
6
+ "names": ["Agent", "Conversation", "MemoryPersistence", "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
+ export*from"./text-chunker.js";
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": "AAAA,WAAc",
6
+ "names": []
7
+ }
@@ -0,0 +1,3 @@
1
+ var i=Object.defineProperty;var h=(n,t)=>i(n,"name",{value:t,configurable:!0});const u=new Set([".","!","?",`
2
+ `]),s=new Set([",",";",":"]);class g{static{h(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 e=[];for(;;){const r=this.takeNext();if(r===null)break;r.length>0&&e.push(r)}return e}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(u.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(s.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 e=this.buffer.slice(0,t+1).trim();return this.buffer=this.buffer.slice(t+1),e}}export{g as TextChunker};
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": "+EAgBA,MAAMA,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": ["STRONG_BOUNDARIES", "SOFT_BOUNDARIES", "TextChunker", "__name", "options", "delta", "chunks", "chunk", "rest", "i"]
7
+ }
@@ -0,0 +1,2 @@
1
+ var a=Object.defineProperty;var n=(s,e)=>a(s,"name",{value:e,configurable:!0});import{FieldStream as c}from"../../transport/streamobject/field-stream/field-stream.js";const l=[{path:["agent"],type:"string",maxLength:128},{path:["text"],type:"string",mode:"array",maxItems:4096,maxLength:4096}],r=0,o=1;class h extends c{static{n(this,"ConversationStream")}unsubscribers;active=null;constructor(e){super(l,{onCancel:n(()=>e.interrupt(),"onCancel")}),this.unsubscribers=[e.on("text-delta",({text:t,agentName:i})=>this.onDelta(t,i)),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(r,t));const i=this.active.items.length;this.active.items.push(e),this.emitItem(o,i,e)}completeReply(){const e=this.active;if(e===null)return;this.active=null;const t=[];e.agentName!==void 0&&t.push({kind:"field",field:r,value:e.agentName}),t.push({kind:"field",field:o,value:e.items}),t.push({kind:"object-complete"}),this.emitObject(t)}abortReply(){this.active=null,this.cancelObject()}}export{h as ConversationStream};
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": "+EA8BA,OAAS,eAAAA,MAAmB,yDAO5B,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,UAA2BJ,CAAY,CA7CpD,MA6CoD,CAAAK,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": ["FieldStream", "REPLY_SCHEMA", "AGENT_FIELD", "TEXT_FIELD", "ConversationStream", "__name", "conversation", "text", "agentName", "error", "unsubscribe", "index", "active", "events"]
7
+ }
@@ -0,0 +1,2 @@
1
+ import{ConversationStream as e}from"./conversation-stream.js";export{e as ConversationStream};
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": "AAAA,OAAS,sBAAAA,MAA0B",
6
+ "names": ["ConversationStream"]
7
+ }
@@ -1,2 +1,2 @@
1
- var r=Object.defineProperty;var e=(t,n)=>r(t,"name",{value:n,configurable:!0});function i(t="created"){return{status:t,participants:new Map,floor:null,currentTurn:null,currentGeneration:null,transcriptCount:0}}e(i,"createConversationState");export{i as createConversationState};
1
+ var r=Object.defineProperty;var e=(t,n)=>r(t,"name",{value:n,configurable:!0});function a(t="created"){return{status:t,participants:new Map,floor:null,currentTurn:null,currentGeneration:null,transcriptCount:0}}e(a,"createConversationState");export{a as 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": "+EA8FO,SAASA,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": "+EA+HO,SAASA,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": ["createConversationState", "status", "__name"]
7
7
  }
package/dist/esm/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var n=Object.defineProperty;var r=(e,t)=>n(e,"name",{value:t,configurable:!0});import{Agent as o}from"./agents/agent.js";import{Conversations as i}from"./conversations/conversations.js";import{MemoryPersistence as p}from"./persistence/adapters/memory/memory.js";class c{static{r(this,"Pipeflow")}llm;stt;tts;conversations;constructor(t={}){this.llm=t.llm,this.stt=t.stt,this.tts=t.tts;const s=t.persistence??new p;this.conversations=new i(s)}agent(t){return new o({...t,llm:t.llm??this.llm})}}import{Tool as d,Tool as v}from"./agents/tools/tools.js";import{Conversation as C,Conversations as x,Orchestrator as g,Transcription as L,TranscriptEntry as O}from"./conversations/index.js";export{o as Agent,C as Conversation,x as Conversations,g as Orchestrator,c as Pipeflow,v as PipeflowTool,d as Tool,O as TranscriptEntry,L as Transcription};
1
+ import{Pipeflow as e}from"./pipeflow.js";import{Agent as n}from"./agents/agent.js";import{Tool as p,Tool as i}from"./agents/tools/tools.js";import{Conversation as l,Conversations as T,Transcription as f,TranscriptEntry as u}from"./conversations/index.js";export{n as Agent,l as Conversation,T as Conversations,e as Pipeflow,i as PipeflowTool,p as Tool,u as TranscriptEntry,f as Transcription};
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": "+EAAA,OAAS,SAAAA,MAAgC,iBACzC,OAAS,iBAAAC,MAAqB,gCAC9B,OAAS,qBAAAC,MAAyB,uCAsB3B,MAAMC,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,IAAIH,EAC/C,KAAK,cAAgB,IAAID,EAAcK,CAAW,CACpD,CAMA,MAAMD,EAA2D,CAC/D,OAAO,IAAIL,EAAM,CAAE,GAAGK,EAAS,IAAKA,EAAQ,KAAO,KAAK,GAAI,CAAC,CAC/D,CACF,CAaA,OAAS,QAAAE,EAAc,QAARA,MAA4B,uBAG3C,OACE,gBAAAC,EACA,iBAAAP,EACA,gBAAAQ,EACA,iBAAAC,EACA,mBAAAC,MACK",
6
- "names": ["Agent", "Conversations", "MemoryPersistence", "Pipeflow", "__name", "options", "persistence", "Tool", "Conversation", "Orchestrator", "Transcription", "TranscriptEntry"]
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": "AAIA,OAAS,YAAAA,MAAgB,aAGzB,OAAS,SAAAC,MAAa,iBAOtB,OAAS,QAAAC,EAAc,QAARA,MAA4B,uBAG3C,OACE,gBAAAC,EACA,iBAAAC,EACA,iBAAAC,EACA,mBAAAC,MACK",
6
+ "names": ["Pipeflow", "Agent", "Tool", "Conversation", "Conversations", "Transcription", "TranscriptEntry"]
7
7
  }