@pipedog/core 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (736) hide show
  1. package/LICENSE +25 -0
  2. package/NOTICE +9 -0
  3. package/dist/adapters/base_llm_adapter.d.ts +266 -0
  4. package/dist/adapters/base_llm_adapter.js +489 -0
  5. package/dist/adapters/index.d.ts +2 -0
  6. package/dist/adapters/index.js +8 -0
  7. package/dist/adapters/schemas/direct_function.d.ts +202 -0
  8. package/dist/adapters/schemas/direct_function.js +302 -0
  9. package/dist/adapters/schemas/function_schema.d.ts +67 -0
  10. package/dist/adapters/schemas/function_schema.js +72 -0
  11. package/dist/adapters/schemas/index.d.ts +2 -0
  12. package/dist/adapters/schemas/index.js +8 -0
  13. package/dist/adapters/schemas/tools_schema.d.ts +57 -0
  14. package/dist/adapters/schemas/tools_schema.js +79 -0
  15. package/dist/adapters/services/index.d.ts +2 -0
  16. package/dist/adapters/services/index.js +8 -0
  17. package/dist/adapters/services/open_ai_adapter.d.ts +147 -0
  18. package/dist/adapters/services/open_ai_adapter.js +250 -0
  19. package/dist/audio/dtmf/dtmf_data.d.ts +3 -0
  20. package/dist/audio/dtmf/dtmf_data.js +22 -0
  21. package/dist/audio/dtmf/index.d.ts +2 -0
  22. package/dist/audio/dtmf/index.js +8 -0
  23. package/dist/audio/dtmf/types.d.ts +31 -0
  24. package/dist/audio/dtmf/types.js +35 -0
  25. package/dist/audio/dtmf/utils.d.ts +13 -0
  26. package/dist/audio/dtmf/utils.js +62 -0
  27. package/dist/audio/filters/base_audio_filter.d.ts +51 -0
  28. package/dist/audio/filters/base_audio_filter.js +17 -0
  29. package/dist/audio/filters/index.d.ts +2 -0
  30. package/dist/audio/filters/index.js +8 -0
  31. package/dist/audio/index.d.ts +2 -0
  32. package/dist/audio/index.js +8 -0
  33. package/dist/audio/krisp_instance.d.ts +95 -0
  34. package/dist/audio/krisp_instance.js +229 -0
  35. package/dist/audio/mixers/base_audio_mixer.d.ts +56 -0
  36. package/dist/audio/mixers/base_audio_mixer.js +16 -0
  37. package/dist/audio/mixers/index.d.ts +2 -0
  38. package/dist/audio/mixers/index.js +8 -0
  39. package/dist/audio/resamplers/base_audio_resampler.d.ts +46 -0
  40. package/dist/audio/resamplers/base_audio_resampler.js +35 -0
  41. package/dist/audio/resamplers/engine.d.ts +60 -0
  42. package/dist/audio/resamplers/engine.js +89 -0
  43. package/dist/audio/resamplers/index.d.ts +2 -0
  44. package/dist/audio/resamplers/index.js +8 -0
  45. package/dist/audio/resamplers/resampy_resampler.d.ts +10 -0
  46. package/dist/audio/resamplers/resampy_resampler.js +15 -0
  47. package/dist/audio/resamplers/sinc_engine.d.ts +10 -0
  48. package/dist/audio/resamplers/sinc_engine.js +235 -0
  49. package/dist/audio/resamplers/soxr_resampler.d.ts +58 -0
  50. package/dist/audio/resamplers/soxr_resampler.js +79 -0
  51. package/dist/audio/resamplers/soxr_stream_resampler.d.ts +78 -0
  52. package/dist/audio/resamplers/soxr_stream_resampler.js +159 -0
  53. package/dist/audio/turn/base_turn_analyzer.d.ts +84 -0
  54. package/dist/audio/turn/base_turn_analyzer.js +61 -0
  55. package/dist/audio/turn/index.d.ts +2 -0
  56. package/dist/audio/turn/index.js +8 -0
  57. package/dist/audio/turn/smart_turn/_whisper_features.d.ts +30 -0
  58. package/dist/audio/turn/smart_turn/_whisper_features.js +225 -0
  59. package/dist/audio/turn/smart_turn/base_smart_turn.d.ts +94 -0
  60. package/dist/audio/turn/smart_turn/base_smart_turn.js +239 -0
  61. package/dist/audio/turn/smart_turn/local_smart_turn_v3.d.ts +76 -0
  62. package/dist/audio/turn/smart_turn/local_smart_turn_v3.js +151 -0
  63. package/dist/audio/utils.d.ts +224 -0
  64. package/dist/audio/utils.js +634 -0
  65. package/dist/audio/vad/data/index.d.ts +2 -0
  66. package/dist/audio/vad/data/index.js +8 -0
  67. package/dist/audio/vad/index.d.ts +2 -0
  68. package/dist/audio/vad/index.js +8 -0
  69. package/dist/audio/vad/vad_analyzer.d.ts +134 -0
  70. package/dist/audio/vad/vad_analyzer.js +249 -0
  71. package/dist/audio/vad/vad_controller.d.ts +143 -0
  72. package/dist/audio/vad/vad_controller.js +228 -0
  73. package/dist/audio/volume.d.ts +38 -0
  74. package/dist/audio/volume.js +75 -0
  75. package/dist/bus/adapters/base.d.ts +35 -0
  76. package/dist/bus/adapters/base.js +19 -0
  77. package/dist/bus/adapters/index.d.ts +10 -0
  78. package/dist/bus/adapters/index.js +15 -0
  79. package/dist/bus/adapters/llm_context_adapter.d.ts +36 -0
  80. package/dist/bus/adapters/llm_context_adapter.js +82 -0
  81. package/dist/bus/adapters/tools_schema_adapter.d.ts +25 -0
  82. package/dist/bus/adapters/tools_schema_adapter.js +70 -0
  83. package/dist/bus/bridge_processor.d.ts +111 -0
  84. package/dist/bus/bridge_processor.js +166 -0
  85. package/dist/bus/bus.d.ts +110 -0
  86. package/dist/bus/bus.js +200 -0
  87. package/dist/bus/index.d.ts +22 -0
  88. package/dist/bus/index.js +27 -0
  89. package/dist/bus/local/async_queue.d.ts +12 -0
  90. package/dist/bus/local/async_queue.js +21 -0
  91. package/dist/bus/local/index.d.ts +3 -0
  92. package/dist/bus/local/index.js +8 -0
  93. package/dist/bus/messages.d.ts +378 -0
  94. package/dist/bus/messages.js +357 -0
  95. package/dist/bus/network/index.d.ts +16 -0
  96. package/dist/bus/network/index.js +21 -0
  97. package/dist/bus/queue.d.ts +27 -0
  98. package/dist/bus/queue.js +51 -0
  99. package/dist/bus/serializers/base.d.ts +25 -0
  100. package/dist/bus/serializers/base.js +14 -0
  101. package/dist/bus/serializers/index.d.ts +9 -0
  102. package/dist/bus/serializers/index.js +14 -0
  103. package/dist/bus/serializers/json.d.ts +77 -0
  104. package/dist/bus/serializers/json.js +367 -0
  105. package/dist/bus/subscriber.d.ts +46 -0
  106. package/dist/bus/subscriber.js +27 -0
  107. package/dist/bus/ui/index.d.ts +3 -0
  108. package/dist/bus/ui/index.js +8 -0
  109. package/dist/bus/ui/messages.d.ts +186 -0
  110. package/dist/bus/ui/messages.js +171 -0
  111. package/dist/classifiers/base_classifier.d.ts +263 -0
  112. package/dist/classifiers/base_classifier.js +346 -0
  113. package/dist/classifiers/cloudflare/clef/classifier.d.ts +70 -0
  114. package/dist/classifiers/cloudflare/clef/classifier.js +204 -0
  115. package/dist/classifiers/cloudflare/clef/client.d.ts +104 -0
  116. package/dist/classifiers/cloudflare/clef/client.js +234 -0
  117. package/dist/classifiers/cloudflare/clef/index.d.ts +2 -0
  118. package/dist/classifiers/cloudflare/clef/index.js +8 -0
  119. package/dist/classifiers/cloudflare/index.d.ts +2 -0
  120. package/dist/classifiers/cloudflare/index.js +8 -0
  121. package/dist/classifiers/http_client.d.ts +70 -0
  122. package/dist/classifiers/http_client.js +161 -0
  123. package/dist/classifiers/index.d.ts +2 -0
  124. package/dist/classifiers/index.js +8 -0
  125. package/dist/classifiers/jev/classifier.d.ts +8 -0
  126. package/dist/classifiers/jev/classifier.js +13 -0
  127. package/dist/classifiers/jev/client.d.ts +8 -0
  128. package/dist/classifiers/jev/client.js +13 -0
  129. package/dist/classifiers/jev/index.d.ts +2 -0
  130. package/dist/classifiers/jev/index.js +8 -0
  131. package/dist/classifiers/llm/classifier.d.ts +72 -0
  132. package/dist/classifiers/llm/classifier.js +304 -0
  133. package/dist/classifiers/llm/index.d.ts +2 -0
  134. package/dist/classifiers/llm/index.js +8 -0
  135. package/dist/classifiers/openai/decisions/classifier.d.ts +77 -0
  136. package/dist/classifiers/openai/decisions/classifier.js +241 -0
  137. package/dist/classifiers/openai/decisions/client.d.ts +108 -0
  138. package/dist/classifiers/openai/decisions/client.js +234 -0
  139. package/dist/classifiers/openai/decisions/index.d.ts +2 -0
  140. package/dist/classifiers/openai/decisions/index.js +8 -0
  141. package/dist/classifiers/openai/index.d.ts +2 -0
  142. package/dist/classifiers/openai/index.js +8 -0
  143. package/dist/classifiers/typesafe/index.d.ts +2 -0
  144. package/dist/classifiers/typesafe/index.js +8 -0
  145. package/dist/classifiers/typesafe/jev/classifier.d.ts +70 -0
  146. package/dist/classifiers/typesafe/jev/classifier.js +220 -0
  147. package/dist/classifiers/typesafe/jev/client.d.ts +105 -0
  148. package/dist/classifiers/typesafe/jev/client.js +233 -0
  149. package/dist/classifiers/typesafe/jev/index.d.ts +2 -0
  150. package/dist/classifiers/typesafe/jev/index.js +8 -0
  151. package/dist/clocks/base_clock.d.ts +13 -0
  152. package/dist/clocks/base_clock.js +14 -0
  153. package/dist/clocks/index.d.ts +2 -0
  154. package/dist/clocks/index.js +8 -0
  155. package/dist/clocks/system_clock.d.ts +15 -0
  156. package/dist/clocks/system_clock.js +25 -0
  157. package/dist/frames/frames.d.ts +2533 -0
  158. package/dist/frames/frames.js +2485 -0
  159. package/dist/frames/index.d.ts +2 -0
  160. package/dist/frames/index.js +8 -0
  161. package/dist/frames/protobufs/frames_pb2.d.ts +229 -0
  162. package/dist/frames/protobufs/frames_pb2.js +466 -0
  163. package/dist/index.d.ts +11 -0
  164. package/dist/index.js +56 -0
  165. package/dist/metrics/index.d.ts +2 -0
  166. package/dist/metrics/index.js +8 -0
  167. package/dist/metrics/metrics.d.ts +276 -0
  168. package/dist/metrics/metrics.js +254 -0
  169. package/dist/observers/base_observer.d.ts +173 -0
  170. package/dist/observers/base_observer.js +151 -0
  171. package/dist/observers/error_observer.d.ts +75 -0
  172. package/dist/observers/error_observer.js +87 -0
  173. package/dist/observers/function_call_observer.d.ts +157 -0
  174. package/dist/observers/function_call_observer.js +222 -0
  175. package/dist/observers/index.d.ts +2 -0
  176. package/dist/observers/index.js +8 -0
  177. package/dist/observers/loggers/debug_log_observer.d.ts +91 -0
  178. package/dist/observers/loggers/debug_log_observer.js +228 -0
  179. package/dist/observers/loggers/index.d.ts +2 -0
  180. package/dist/observers/loggers/index.js +8 -0
  181. package/dist/observers/loggers/llm_log_observer.d.ts +24 -0
  182. package/dist/observers/loggers/llm_log_observer.js +110 -0
  183. package/dist/observers/loggers/metrics_log_observer.d.ts +85 -0
  184. package/dist/observers/loggers/metrics_log_observer.js +186 -0
  185. package/dist/observers/loggers/transcription_log_observer.d.ts +23 -0
  186. package/dist/observers/loggers/transcription_log_observer.js +74 -0
  187. package/dist/observers/service_metrics_observer.d.ts +168 -0
  188. package/dist/observers/service_metrics_observer.js +236 -0
  189. package/dist/observers/speaking_observer.d.ts +104 -0
  190. package/dist/observers/speaking_observer.js +150 -0
  191. package/dist/observers/startup_timing_observer.d.ts +221 -0
  192. package/dist/observers/startup_timing_observer.js +365 -0
  193. package/dist/observers/turn_tracking_observer.d.ts +78 -0
  194. package/dist/observers/turn_tracking_observer.js +189 -0
  195. package/dist/observers/user_bot_latency_observer.d.ts +411 -0
  196. package/dist/observers/user_bot_latency_observer.js +974 -0
  197. package/dist/pipeline/base_pipeline.d.ts +49 -0
  198. package/dist/pipeline/base_pipeline.js +101 -0
  199. package/dist/pipeline/capabilities.d.ts +76 -0
  200. package/dist/pipeline/capabilities.js +97 -0
  201. package/dist/pipeline/index.d.ts +2 -0
  202. package/dist/pipeline/index.js +8 -0
  203. package/dist/pipeline/job_context.d.ts +317 -0
  204. package/dist/pipeline/job_context.js +450 -0
  205. package/dist/pipeline/job_decorator.d.ts +54 -0
  206. package/dist/pipeline/job_decorator.js +92 -0
  207. package/dist/pipeline/llm_switcher.d.ts +84 -0
  208. package/dist/pipeline/llm_switcher.js +107 -0
  209. package/dist/pipeline/llm_with_backend.d.ts +435 -0
  210. package/dist/pipeline/llm_with_backend.js +806 -0
  211. package/dist/pipeline/parallel_pipeline.d.ts +83 -0
  212. package/dist/pipeline/parallel_pipeline.js +200 -0
  213. package/dist/pipeline/pipeline.d.ts +126 -0
  214. package/dist/pipeline/pipeline.js +196 -0
  215. package/dist/pipeline/service_switcher.d.ts +287 -0
  216. package/dist/pipeline/service_switcher.js +509 -0
  217. package/dist/pipeline/sync_parallel_pipeline.d.ts +192 -0
  218. package/dist/pipeline/sync_parallel_pipeline.js +387 -0
  219. package/dist/pipeline/worker.d.ts +821 -0
  220. package/dist/pipeline/worker.js +1656 -0
  221. package/dist/pipeline/worker_observer.d.ts +131 -0
  222. package/dist/pipeline/worker_observer.js +274 -0
  223. package/dist/pipeline/worker_ready_decorator.d.ts +45 -0
  224. package/dist/pipeline/worker_ready_decorator.js +76 -0
  225. package/dist/processors/aggregators/async_tool_messages.d.ts +146 -0
  226. package/dist/processors/aggregators/async_tool_messages.js +291 -0
  227. package/dist/processors/aggregators/dtmf_aggregator.d.ts +61 -0
  228. package/dist/processors/aggregators/dtmf_aggregator.js +144 -0
  229. package/dist/processors/aggregators/gated.d.ts +43 -0
  230. package/dist/processors/aggregators/gated.js +86 -0
  231. package/dist/processors/aggregators/gated_llm_context.d.ts +42 -0
  232. package/dist/processors/aggregators/gated_llm_context.js +86 -0
  233. package/dist/processors/aggregators/index.d.ts +2 -0
  234. package/dist/processors/aggregators/index.js +8 -0
  235. package/dist/processors/aggregators/llm_context.d.ts +370 -0
  236. package/dist/processors/aggregators/llm_context.js +580 -0
  237. package/dist/processors/aggregators/llm_context_summarizer.d.ts +219 -0
  238. package/dist/processors/aggregators/llm_context_summarizer.js +447 -0
  239. package/dist/processors/aggregators/llm_response.d.ts +37 -0
  240. package/dist/processors/aggregators/llm_response.js +71 -0
  241. package/dist/processors/aggregators/llm_response_universal.d.ts +966 -0
  242. package/dist/processors/aggregators/llm_response_universal.js +2394 -0
  243. package/dist/processors/aggregators/llm_text_processor.d.ts +53 -0
  244. package/dist/processors/aggregators/llm_text_processor.js +102 -0
  245. package/dist/processors/aggregators/sentence.d.ts +39 -0
  246. package/dist/processors/aggregators/sentence.js +69 -0
  247. package/dist/processors/async_generator.d.ts +42 -0
  248. package/dist/processors/async_generator.js +76 -0
  249. package/dist/processors/audio/audio_buffer_processor.d.ts +241 -0
  250. package/dist/processors/audio/audio_buffer_processor.js +565 -0
  251. package/dist/processors/audio/index.d.ts +2 -0
  252. package/dist/processors/audio/index.js +8 -0
  253. package/dist/processors/audio/vad_processor.d.ts +67 -0
  254. package/dist/processors/audio/vad_processor.js +103 -0
  255. package/dist/processors/consumer_processor.d.ts +49 -0
  256. package/dist/processors/consumer_processor.js +85 -0
  257. package/dist/processors/filters/frame_filter.d.ts +39 -0
  258. package/dist/processors/filters/frame_filter.js +52 -0
  259. package/dist/processors/filters/function_filter.d.ts +59 -0
  260. package/dist/processors/filters/function_filter.js +78 -0
  261. package/dist/processors/filters/identity_filter.d.ts +33 -0
  262. package/dist/processors/filters/identity_filter.js +37 -0
  263. package/dist/processors/filters/index.d.ts +2 -0
  264. package/dist/processors/filters/index.js +8 -0
  265. package/dist/processors/filters/null_filter.d.ts +34 -0
  266. package/dist/processors/filters/null_filter.js +47 -0
  267. package/dist/processors/filters/wake_notifier_filter.d.ts +48 -0
  268. package/dist/processors/filters/wake_notifier_filter.js +49 -0
  269. package/dist/processors/frame_processor.d.ts +360 -0
  270. package/dist/processors/frame_processor.js +932 -0
  271. package/dist/processors/frameworks/index.d.ts +2 -0
  272. package/dist/processors/frameworks/index.js +8 -0
  273. package/dist/processors/frameworks/rtvi/frames.d.ts +241 -0
  274. package/dist/processors/frameworks/rtvi/frames.js +259 -0
  275. package/dist/processors/frameworks/rtvi/index.d.ts +6 -0
  276. package/dist/processors/frameworks/rtvi/index.js +11 -0
  277. package/dist/processors/frameworks/rtvi/models.d.ts +1741 -0
  278. package/dist/processors/frameworks/rtvi/models.js +1807 -0
  279. package/dist/processors/frameworks/rtvi/observer.d.ts +340 -0
  280. package/dist/processors/frameworks/rtvi/observer.js +1113 -0
  281. package/dist/processors/frameworks/rtvi/processor.d.ts +182 -0
  282. package/dist/processors/frameworks/rtvi/processor.js +676 -0
  283. package/dist/processors/idle_frame_processor.d.ts +44 -0
  284. package/dist/processors/idle_frame_processor.js +86 -0
  285. package/dist/processors/index.d.ts +2 -0
  286. package/dist/processors/index.js +8 -0
  287. package/dist/processors/logger.d.ts +42 -0
  288. package/dist/processors/logger.js +87 -0
  289. package/dist/processors/metrics/frame_processor_metrics.d.ts +172 -0
  290. package/dist/processors/metrics/frame_processor_metrics.js +372 -0
  291. package/dist/processors/metrics/index.d.ts +2 -0
  292. package/dist/processors/metrics/index.js +8 -0
  293. package/dist/processors/producer_processor.d.ts +68 -0
  294. package/dist/processors/producer_processor.js +78 -0
  295. package/dist/processors/text_transformer.d.ts +30 -0
  296. package/dist/processors/text_transformer.js +48 -0
  297. package/dist/registry/index.d.ts +3 -0
  298. package/dist/registry/index.js +8 -0
  299. package/dist/registry/registry.d.ts +69 -0
  300. package/dist/registry/registry.js +149 -0
  301. package/dist/registry/types.d.ts +47 -0
  302. package/dist/registry/types.js +39 -0
  303. package/dist/serializers/base_serializer.d.ts +94 -0
  304. package/dist/serializers/base_serializer.js +82 -0
  305. package/dist/serializers/index.d.ts +2 -0
  306. package/dist/serializers/index.js +8 -0
  307. package/dist/services/ai_service.d.ts +145 -0
  308. package/dist/services/ai_service.js +262 -0
  309. package/dist/services/anthropic/index.d.ts +2 -0
  310. package/dist/services/anthropic/index.js +7 -0
  311. package/dist/services/assemblyai/index.d.ts +2 -0
  312. package/dist/services/assemblyai/index.js +7 -0
  313. package/dist/services/asyncai/index.d.ts +2 -0
  314. package/dist/services/asyncai/index.js +7 -0
  315. package/dist/services/aws/index.d.ts +2 -0
  316. package/dist/services/aws/index.js +7 -0
  317. package/dist/services/azure/index.d.ts +2 -0
  318. package/dist/services/azure/index.js +7 -0
  319. package/dist/services/baseten/index.d.ts +2 -0
  320. package/dist/services/baseten/index.js +7 -0
  321. package/dist/services/bland/index.d.ts +2 -0
  322. package/dist/services/bland/index.js +7 -0
  323. package/dist/services/camb/index.d.ts +2 -0
  324. package/dist/services/camb/index.js +7 -0
  325. package/dist/services/cartesia/index.d.ts +2 -0
  326. package/dist/services/cartesia/index.js +7 -0
  327. package/dist/services/cerebras/index.d.ts +2 -0
  328. package/dist/services/cerebras/index.js +7 -0
  329. package/dist/services/crusoe/index.d.ts +2 -0
  330. package/dist/services/crusoe/index.js +7 -0
  331. package/dist/services/deepgram/index.d.ts +2 -0
  332. package/dist/services/deepgram/index.js +7 -0
  333. package/dist/services/deepseek/index.d.ts +2 -0
  334. package/dist/services/deepseek/index.js +7 -0
  335. package/dist/services/elevenlabs/index.d.ts +2 -0
  336. package/dist/services/elevenlabs/index.js +7 -0
  337. package/dist/services/fal/index.d.ts +2 -0
  338. package/dist/services/fal/index.js +7 -0
  339. package/dist/services/fireworks/index.d.ts +2 -0
  340. package/dist/services/fireworks/index.js +7 -0
  341. package/dist/services/fish/index.d.ts +2 -0
  342. package/dist/services/fish/index.js +7 -0
  343. package/dist/services/funasr/index.d.ts +3 -0
  344. package/dist/services/funasr/index.js +8 -0
  345. package/dist/services/gladia/index.d.ts +2 -0
  346. package/dist/services/gladia/index.js +7 -0
  347. package/dist/services/google/index.d.ts +2 -0
  348. package/dist/services/google/index.js +7 -0
  349. package/dist/services/gradium/index.d.ts +2 -0
  350. package/dist/services/gradium/index.js +7 -0
  351. package/dist/services/grok/index.d.ts +2 -0
  352. package/dist/services/grok/index.js +7 -0
  353. package/dist/services/groq/index.d.ts +2 -0
  354. package/dist/services/groq/index.js +7 -0
  355. package/dist/services/heygen/index.d.ts +2 -0
  356. package/dist/services/heygen/index.js +7 -0
  357. package/dist/services/hume/index.d.ts +2 -0
  358. package/dist/services/hume/index.js +7 -0
  359. package/dist/services/image_service.d.ts +52 -0
  360. package/dist/services/image_service.js +60 -0
  361. package/dist/services/inception/index.d.ts +2 -0
  362. package/dist/services/inception/index.js +7 -0
  363. package/dist/services/index.d.ts +2 -0
  364. package/dist/services/index.js +8 -0
  365. package/dist/services/inworld/index.d.ts +2 -0
  366. package/dist/services/inworld/index.js +7 -0
  367. package/dist/services/keenable/index.d.ts +2 -0
  368. package/dist/services/keenable/index.js +7 -0
  369. package/dist/services/kokoro/index.d.ts +2 -0
  370. package/dist/services/kokoro/index.js +7 -0
  371. package/dist/services/llm_service.d.ts +1106 -0
  372. package/dist/services/llm_service.js +2231 -0
  373. package/dist/services/mem0/index.d.ts +2 -0
  374. package/dist/services/mem0/index.js +7 -0
  375. package/dist/services/meta/index.d.ts +2 -0
  376. package/dist/services/meta/index.js +7 -0
  377. package/dist/services/minimax/index.d.ts +2 -0
  378. package/dist/services/minimax/index.js +7 -0
  379. package/dist/services/mistral/index.d.ts +2 -0
  380. package/dist/services/mistral/index.js +7 -0
  381. package/dist/services/moondream/index.d.ts +2 -0
  382. package/dist/services/moondream/index.js +7 -0
  383. package/dist/services/moonshine/index.d.ts +2 -0
  384. package/dist/services/moonshine/index.js +7 -0
  385. package/dist/services/nebius/index.d.ts +2 -0
  386. package/dist/services/nebius/index.js +7 -0
  387. package/dist/services/neuphonic/index.d.ts +2 -0
  388. package/dist/services/neuphonic/index.js +7 -0
  389. package/dist/services/novita/index.d.ts +2 -0
  390. package/dist/services/novita/index.js +7 -0
  391. package/dist/services/nvidia/index.d.ts +2 -0
  392. package/dist/services/nvidia/index.js +11 -0
  393. package/dist/services/ollama/index.d.ts +2 -0
  394. package/dist/services/ollama/index.js +7 -0
  395. package/dist/services/openai/index.d.ts +2 -0
  396. package/dist/services/openai/index.js +7 -0
  397. package/dist/services/openclaw/index.d.ts +14 -0
  398. package/dist/services/openclaw/index.js +19 -0
  399. package/dist/services/openrouter/index.d.ts +2 -0
  400. package/dist/services/openrouter/index.js +7 -0
  401. package/dist/services/perplexity/index.d.ts +2 -0
  402. package/dist/services/perplexity/index.js +7 -0
  403. package/dist/services/piper/index.d.ts +2 -0
  404. package/dist/services/piper/index.js +7 -0
  405. package/dist/services/pocket_tts/index.d.ts +2 -0
  406. package/dist/services/pocket_tts/index.js +7 -0
  407. package/dist/services/qwen/index.d.ts +2 -0
  408. package/dist/services/qwen/index.js +7 -0
  409. package/dist/services/resembleai/index.d.ts +2 -0
  410. package/dist/services/resembleai/index.js +7 -0
  411. package/dist/services/rime/index.d.ts +2 -0
  412. package/dist/services/rime/index.js +7 -0
  413. package/dist/services/sambanova/index.d.ts +2 -0
  414. package/dist/services/sambanova/index.js +7 -0
  415. package/dist/services/sarvam/index.d.ts +2 -0
  416. package/dist/services/sarvam/index.js +7 -0
  417. package/dist/services/settings.d.ts +356 -0
  418. package/dist/services/settings.js +437 -0
  419. package/dist/services/simli/index.d.ts +2 -0
  420. package/dist/services/simli/index.js +7 -0
  421. package/dist/services/smallest/index.d.ts +2 -0
  422. package/dist/services/smallest/index.js +7 -0
  423. package/dist/services/soniox/index.d.ts +2 -0
  424. package/dist/services/soniox/index.js +7 -0
  425. package/dist/services/speechify/index.d.ts +2 -0
  426. package/dist/services/speechify/index.js +7 -0
  427. package/dist/services/speechmatics/index.d.ts +2 -0
  428. package/dist/services/speechmatics/index.js +7 -0
  429. package/dist/services/stt_latency.d.ts +62 -0
  430. package/dist/services/stt_latency.js +71 -0
  431. package/dist/services/stt_service.d.ts +601 -0
  432. package/dist/services/stt_service.js +1044 -0
  433. package/dist/services/tavus/index.d.ts +2 -0
  434. package/dist/services/tavus/index.js +7 -0
  435. package/dist/services/together/index.d.ts +2 -0
  436. package/dist/services/together/index.js +7 -0
  437. package/dist/services/tts_service.d.ts +909 -0
  438. package/dist/services/tts_service.js +2018 -0
  439. package/dist/services/ultravox/index.d.ts +2 -0
  440. package/dist/services/ultravox/index.js +9 -0
  441. package/dist/services/vision_service.d.ts +56 -0
  442. package/dist/services/vision_service.js +62 -0
  443. package/dist/services/websocket_service.d.ts +213 -0
  444. package/dist/services/websocket_service.js +654 -0
  445. package/dist/services/whisper/index.d.ts +2 -0
  446. package/dist/services/whisper/index.js +9 -0
  447. package/dist/services/xai/index.d.ts +2 -0
  448. package/dist/services/xai/index.js +9 -0
  449. package/dist/services/xtts/index.d.ts +2 -0
  450. package/dist/services/xtts/index.js +9 -0
  451. package/dist/tests/index.d.ts +2 -0
  452. package/dist/tests/index.js +8 -0
  453. package/dist/tests/utils.d.ts +123 -0
  454. package/dist/tests/utils.js +212 -0
  455. package/dist/transcriptions/index.d.ts +2 -0
  456. package/dist/transcriptions/index.js +8 -0
  457. package/dist/transcriptions/language.d.ts +376 -0
  458. package/dist/transcriptions/language.js +543 -0
  459. package/dist/transports/base_input.d.ts +149 -0
  460. package/dist/transports/base_input.js +338 -0
  461. package/dist/transports/base_output.d.ts +432 -0
  462. package/dist/transports/base_output.js +1231 -0
  463. package/dist/transports/base_transport.d.ts +223 -0
  464. package/dist/transports/base_transport.js +167 -0
  465. package/dist/transports/daily/index.d.ts +2 -0
  466. package/dist/transports/daily/index.js +9 -0
  467. package/dist/transports/heygen/index.d.ts +2 -0
  468. package/dist/transports/heygen/index.js +9 -0
  469. package/dist/transports/index.d.ts +2 -0
  470. package/dist/transports/index.js +8 -0
  471. package/dist/transports/lemonslice/index.d.ts +2 -0
  472. package/dist/transports/lemonslice/index.js +9 -0
  473. package/dist/transports/livekit/index.d.ts +2 -0
  474. package/dist/transports/livekit/index.js +9 -0
  475. package/dist/transports/local/index.d.ts +2 -0
  476. package/dist/transports/local/index.js +9 -0
  477. package/dist/transports/moq/index.d.ts +2 -0
  478. package/dist/transports/moq/index.js +9 -0
  479. package/dist/transports/smallwebrtc/index.d.ts +2 -0
  480. package/dist/transports/smallwebrtc/index.js +9 -0
  481. package/dist/transports/tavus/index.d.ts +2 -0
  482. package/dist/transports/tavus/index.js +9 -0
  483. package/dist/transports/video_in_sampler.d.ts +157 -0
  484. package/dist/transports/video_in_sampler.js +258 -0
  485. package/dist/transports/vonage/index.d.ts +2 -0
  486. package/dist/transports/vonage/index.js +9 -0
  487. package/dist/transports/websocket/index.d.ts +2 -0
  488. package/dist/transports/websocket/index.js +9 -0
  489. package/dist/transports/whatsapp/index.d.ts +2 -0
  490. package/dist/transports/whatsapp/index.js +9 -0
  491. package/dist/turns/eager_end_of_turn_mixin.d.ts +70 -0
  492. package/dist/turns/eager_end_of_turn_mixin.js +122 -0
  493. package/dist/turns/empty_user_turn.d.ts +55 -0
  494. package/dist/turns/empty_user_turn.js +53 -0
  495. package/dist/turns/index.d.ts +2 -0
  496. package/dist/turns/index.js +8 -0
  497. package/dist/turns/speculation_gate.d.ts +169 -0
  498. package/dist/turns/speculation_gate.js +294 -0
  499. package/dist/turns/types.d.ts +33 -0
  500. package/dist/turns/types.js +35 -0
  501. package/dist/turns/user_idle_controller.d.ts +94 -0
  502. package/dist/turns/user_idle_controller.js +187 -0
  503. package/dist/turns/user_mute/always_user_mute_strategy.d.ts +15 -0
  504. package/dist/turns/user_mute/always_user_mute_strategy.js +29 -0
  505. package/dist/turns/user_mute/base_user_mute_strategy.d.ts +39 -0
  506. package/dist/turns/user_mute/base_user_mute_strategy.js +45 -0
  507. package/dist/turns/user_mute/first_speech_user_mute_strategy.d.ts +28 -0
  508. package/dist/turns/user_mute/first_speech_user_mute_strategy.js +52 -0
  509. package/dist/turns/user_mute/function_call_user_mute_strategy.d.ts +25 -0
  510. package/dist/turns/user_mute/function_call_user_mute_strategy.js +50 -0
  511. package/dist/turns/user_mute/index.d.ts +6 -0
  512. package/dist/turns/user_mute/index.js +11 -0
  513. package/dist/turns/user_mute/mute_until_first_bot_complete_user_mute_strategy.d.ts +43 -0
  514. package/dist/turns/user_mute/mute_until_first_bot_complete_user_mute_strategy.js +76 -0
  515. package/dist/turns/user_start/base_user_turn_start_strategy.d.ts +135 -0
  516. package/dist/turns/user_start/base_user_turn_start_strategy.js +134 -0
  517. package/dist/turns/user_start/external_user_turn_start_strategy.d.ts +45 -0
  518. package/dist/turns/user_start/external_user_turn_start_strategy.js +64 -0
  519. package/dist/turns/user_start/index.d.ts +8 -0
  520. package/dist/turns/user_start/index.js +16 -0
  521. package/dist/turns/user_start/krisp_viva_ip_user_turn_start_strategy.d.ts +133 -0
  522. package/dist/turns/user_start/krisp_viva_ip_user_turn_start_strategy.js +243 -0
  523. package/dist/turns/user_start/min_words_user_turn_start_strategy.d.ts +60 -0
  524. package/dist/turns/user_start/min_words_user_turn_start_strategy.js +102 -0
  525. package/dist/turns/user_start/transcription_user_turn_start_strategy.d.ts +29 -0
  526. package/dist/turns/user_start/transcription_user_turn_start_strategy.js +43 -0
  527. package/dist/turns/user_start/vad_user_turn_start_strategy.d.ts +20 -0
  528. package/dist/turns/user_start/vad_user_turn_start_strategy.js +31 -0
  529. package/dist/turns/user_start/wake_phrase_user_turn_start_strategy.d.ts +141 -0
  530. package/dist/turns/user_start/wake_phrase_user_turn_start_strategy.js +238 -0
  531. package/dist/turns/user_stop/base_user_turn_stop_strategy.d.ts +174 -0
  532. package/dist/turns/user_stop/base_user_turn_stop_strategy.js +170 -0
  533. package/dist/turns/user_stop/deferred_user_turn_stop_strategy.d.ts +81 -0
  534. package/dist/turns/user_stop/deferred_user_turn_stop_strategy.js +107 -0
  535. package/dist/turns/user_stop/eager_match_policy.d.ts +36 -0
  536. package/dist/turns/user_stop/eager_match_policy.js +50 -0
  537. package/dist/turns/user_stop/eager_user_turn_stop_strategy.d.ts +84 -0
  538. package/dist/turns/user_stop/eager_user_turn_stop_strategy.js +154 -0
  539. package/dist/turns/user_stop/external_user_turn_completion_stop_strategy.d.ts +45 -0
  540. package/dist/turns/user_stop/external_user_turn_completion_stop_strategy.js +55 -0
  541. package/dist/turns/user_stop/external_user_turn_stop_strategy.d.ts +115 -0
  542. package/dist/turns/user_stop/external_user_turn_stop_strategy.js +205 -0
  543. package/dist/turns/user_stop/index.d.ts +10 -0
  544. package/dist/turns/user_stop/index.js +15 -0
  545. package/dist/turns/user_stop/llm_turn_completion_user_turn_stop_strategy.d.ts +44 -0
  546. package/dist/turns/user_stop/llm_turn_completion_user_turn_stop_strategy.js +59 -0
  547. package/dist/turns/user_stop/speech_timeout_user_turn_stop_strategy.d.ts +140 -0
  548. package/dist/turns/user_stop/speech_timeout_user_turn_stop_strategy.js +303 -0
  549. package/dist/turns/user_stop/turn_analyzer_user_turn_stop_strategy.d.ts +135 -0
  550. package/dist/turns/user_stop/turn_analyzer_user_turn_stop_strategy.js +332 -0
  551. package/dist/turns/user_turn_completion_mixin.d.ts +147 -0
  552. package/dist/turns/user_turn_completion_mixin.js +591 -0
  553. package/dist/turns/user_turn_controller.d.ts +134 -0
  554. package/dist/turns/user_turn_controller.js +335 -0
  555. package/dist/turns/user_turn_processor.d.ts +87 -0
  556. package/dist/turns/user_turn_processor.js +180 -0
  557. package/dist/turns/user_turn_strategies.d.ts +187 -0
  558. package/dist/turns/user_turn_strategies.js +222 -0
  559. package/dist/utils/async_tool_cancellation.d.ts +35 -0
  560. package/dist/utils/async_tool_cancellation.js +78 -0
  561. package/dist/utils/asyncio/index.d.ts +2 -0
  562. package/dist/utils/asyncio/index.js +7 -0
  563. package/dist/utils/asyncio/task_manager.d.ts +49 -0
  564. package/dist/utils/asyncio/task_manager.js +105 -0
  565. package/dist/utils/base_object.d.ts +76 -0
  566. package/dist/utils/base_object.js +154 -0
  567. package/dist/utils/context/aggregated_frame_sequencer.d.ts +491 -0
  568. package/dist/utils/context/aggregated_frame_sequencer.js +803 -0
  569. package/dist/utils/context/audio_context_manager.d.ts +131 -0
  570. package/dist/utils/context/audio_context_manager.js +233 -0
  571. package/dist/utils/context/index.d.ts +2 -0
  572. package/dist/utils/context/index.js +7 -0
  573. package/dist/utils/context/llm_context_summarization.d.ts +258 -0
  574. package/dist/utils/context/llm_context_summarization.js +511 -0
  575. package/dist/utils/context/text_segment_map.d.ts +611 -0
  576. package/dist/utils/context/text_segment_map.js +1132 -0
  577. package/dist/utils/context/word_completion_tracker.d.ts +273 -0
  578. package/dist/utils/context/word_completion_tracker.js +441 -0
  579. package/dist/utils/context/word_timestamp_tracker.d.ts +72 -0
  580. package/dist/utils/context/word_timestamp_tracker.js +98 -0
  581. package/dist/utils/deprecation.d.ts +28 -0
  582. package/dist/utils/deprecation.js +75 -0
  583. package/dist/utils/env.d.ts +38 -0
  584. package/dist/utils/env.js +62 -0
  585. package/dist/utils/errors.d.ts +75 -0
  586. package/dist/utils/errors.js +202 -0
  587. package/dist/utils/file_resolver.d.ts +126 -0
  588. package/dist/utils/file_resolver.js +314 -0
  589. package/dist/utils/file_storage.d.ts +115 -0
  590. package/dist/utils/file_storage.js +178 -0
  591. package/dist/utils/frame_queue.d.ts +36 -0
  592. package/dist/utils/frame_queue.js +66 -0
  593. package/dist/utils/http.d.ts +39 -0
  594. package/dist/utils/http.js +53 -0
  595. package/dist/utils/image.d.ts +14 -0
  596. package/dist/utils/image.js +63 -0
  597. package/dist/utils/index.d.ts +2 -0
  598. package/dist/utils/index.js +8 -0
  599. package/dist/utils/jpeg_encoder.d.ts +14 -0
  600. package/dist/utils/jpeg_encoder.js +315 -0
  601. package/dist/utils/log_config.d.ts +34 -0
  602. package/dist/utils/log_config.js +76 -0
  603. package/dist/utils/logger.d.ts +40 -0
  604. package/dist/utils/logger.js +91 -0
  605. package/dist/utils/mixin.d.ts +14 -0
  606. package/dist/utils/mixin.js +63 -0
  607. package/dist/utils/network.d.ts +73 -0
  608. package/dist/utils/network.js +90 -0
  609. package/dist/utils/security/allowed_origins.d.ts +16 -0
  610. package/dist/utils/security/allowed_origins.js +34 -0
  611. package/dist/utils/security/index.d.ts +2 -0
  612. package/dist/utils/security/index.js +7 -0
  613. package/dist/utils/security/redaction.d.ts +27 -0
  614. package/dist/utils/security/redaction.js +123 -0
  615. package/dist/utils/security/ssrf.d.ts +79 -0
  616. package/dist/utils/security/ssrf.js +327 -0
  617. package/dist/utils/shared.d.ts +35 -0
  618. package/dist/utils/shared.js +136 -0
  619. package/dist/utils/startup.d.ts +17 -0
  620. package/dist/utils/startup.js +130 -0
  621. package/dist/utils/string.d.ts +116 -0
  622. package/dist/utils/string.js +460 -0
  623. package/dist/utils/sync/base_notifier.d.ts +25 -0
  624. package/dist/utils/sync/base_notifier.js +16 -0
  625. package/dist/utils/sync/event_notifier.d.ts +38 -0
  626. package/dist/utils/sync/event_notifier.js +51 -0
  627. package/dist/utils/sync/index.d.ts +2 -0
  628. package/dist/utils/sync/index.js +7 -0
  629. package/dist/utils/text/alnum_utils.d.ts +109 -0
  630. package/dist/utils/text/alnum_utils.js +262 -0
  631. package/dist/utils/text/base_text_aggregator.d.ts +146 -0
  632. package/dist/utils/text/base_text_aggregator.js +102 -0
  633. package/dist/utils/text/base_text_filter.d.ts +54 -0
  634. package/dist/utils/text/base_text_filter.js +50 -0
  635. package/dist/utils/text/index.d.ts +2 -0
  636. package/dist/utils/text/index.js +7 -0
  637. package/dist/utils/text/markdown_text_filter.d.ts +147 -0
  638. package/dist/utils/text/markdown_text_filter.js +522 -0
  639. package/dist/utils/text/markup_utils.d.ts +54 -0
  640. package/dist/utils/text/markup_utils.js +156 -0
  641. package/dist/utils/text/pattern_pair_aggregator.d.ts +251 -0
  642. package/dist/utils/text/pattern_pair_aggregator.js +478 -0
  643. package/dist/utils/text/phonemes.d.ts +60 -0
  644. package/dist/utils/text/phonemes.js +172 -0
  645. package/dist/utils/text/simple_text_aggregator.d.ts +135 -0
  646. package/dist/utils/text/simple_text_aggregator.js +254 -0
  647. package/dist/utils/text/skip_tags_aggregator.d.ts +85 -0
  648. package/dist/utils/text/skip_tags_aggregator.js +147 -0
  649. package/dist/utils/text/transforms/acronyms.d.ts +21 -0
  650. package/dist/utils/text/transforms/acronyms.js +31 -0
  651. package/dist/utils/text/transforms/currency.d.ts +16 -0
  652. package/dist/utils/text/transforms/currency.js +56 -0
  653. package/dist/utils/text/transforms/dates.d.ts +18 -0
  654. package/dist/utils/text/transforms/dates.js +102 -0
  655. package/dist/utils/text/transforms/email.d.ts +17 -0
  656. package/dist/utils/text/transforms/email.js +35 -0
  657. package/dist/utils/text/transforms/index.d.ts +37 -0
  658. package/dist/utils/text/transforms/index.js +42 -0
  659. package/dist/utils/text/transforms/numbers.d.ts +25 -0
  660. package/dist/utils/text/transforms/numbers.js +59 -0
  661. package/dist/utils/text/transforms/percentages.d.ts +16 -0
  662. package/dist/utils/text/transforms/percentages.js +32 -0
  663. package/dist/utils/text/transforms/phone.d.ts +21 -0
  664. package/dist/utils/text/transforms/phone.js +39 -0
  665. package/dist/utils/text/transforms/pronunciations.d.ts +65 -0
  666. package/dist/utils/text/transforms/pronunciations.js +112 -0
  667. package/dist/utils/text/transforms/replacements.d.ts +39 -0
  668. package/dist/utils/text/transforms/replacements.js +46 -0
  669. package/dist/utils/text/transforms/strip_markdown.d.ts +25 -0
  670. package/dist/utils/text/transforms/strip_markdown.js +60 -0
  671. package/dist/utils/text/transforms/units.d.ts +22 -0
  672. package/dist/utils/text/transforms/units.js +81 -0
  673. package/dist/utils/text/transforms/voice_formatter.d.ts +86 -0
  674. package/dist/utils/text/transforms/voice_formatter.js +98 -0
  675. package/dist/utils/text/unicode_digits.d.ts +3 -0
  676. package/dist/utils/text/unicode_digits.js +34 -0
  677. package/dist/utils/text/word_timestamp_utils.d.ts +26 -0
  678. package/dist/utils/text/word_timestamp_utils.js +52 -0
  679. package/dist/utils/time.d.ts +13 -0
  680. package/dist/utils/time.js +31 -0
  681. package/dist/utils/tracing/index.d.ts +3 -0
  682. package/dist/utils/tracing/index.js +8 -0
  683. package/dist/utils/tracing/service_attributes.d.ts +198 -0
  684. package/dist/utils/tracing/service_attributes.js +434 -0
  685. package/dist/utils/tracing/service_decorators.d.ts +214 -0
  686. package/dist/utils/tracing/service_decorators.js +1662 -0
  687. package/dist/utils/tracing/setup.d.ts +107 -0
  688. package/dist/utils/tracing/setup.js +160 -0
  689. package/dist/utils/tracing/tracing_context.d.ts +55 -0
  690. package/dist/utils/tracing/tracing_context.js +97 -0
  691. package/dist/utils/tracing/turn_trace_observer.d.ts +95 -0
  692. package/dist/utils/tracing/turn_trace_observer.js +233 -0
  693. package/dist/utils/types.d.ts +80 -0
  694. package/dist/utils/types.js +108 -0
  695. package/dist/utils/utils.d.ts +5 -0
  696. package/dist/utils/utils.js +22 -0
  697. package/dist/utils/yaml.d.ts +179 -0
  698. package/dist/utils/yaml.js +556 -0
  699. package/dist/version.d.ts +3 -0
  700. package/dist/version.js +7 -0
  701. package/dist/workers/base_worker.d.ts +772 -0
  702. package/dist/workers/base_worker.js +1298 -0
  703. package/dist/workers/index.d.ts +2 -0
  704. package/dist/workers/index.js +8 -0
  705. package/dist/workers/llm/backend_llm_worker.d.ts +552 -0
  706. package/dist/workers/llm/backend_llm_worker.js +1055 -0
  707. package/dist/workers/llm/index.d.ts +6 -0
  708. package/dist/workers/llm/index.js +11 -0
  709. package/dist/workers/llm/llm_context_worker.d.ts +66 -0
  710. package/dist/workers/llm/llm_context_worker.js +72 -0
  711. package/dist/workers/llm/llm_worker.d.ts +180 -0
  712. package/dist/workers/llm/llm_worker.js +323 -0
  713. package/dist/workers/llm/tool_decorator.d.ts +68 -0
  714. package/dist/workers/llm/tool_decorator.js +60 -0
  715. package/dist/workers/proxy/index.d.ts +3 -0
  716. package/dist/workers/proxy/index.js +9 -0
  717. package/dist/workers/proxy/websocket/client.d.ts +110 -0
  718. package/dist/workers/proxy/websocket/client.js +196 -0
  719. package/dist/workers/proxy/websocket/index.d.ts +3 -0
  720. package/dist/workers/proxy/websocket/index.js +10 -0
  721. package/dist/workers/runner.d.ts +268 -0
  722. package/dist/workers/runner.js +489 -0
  723. package/dist/workers/ui/index.d.ts +22 -0
  724. package/dist/workers/ui/index.js +27 -0
  725. package/dist/workers/ui/ui_event_decorator.d.ts +43 -0
  726. package/dist/workers/ui/ui_event_decorator.js +75 -0
  727. package/dist/workers/ui/ui_job_context.d.ts +12 -0
  728. package/dist/workers/ui/ui_job_context.js +17 -0
  729. package/dist/workers/ui/ui_prompts.d.ts +21 -0
  730. package/dist/workers/ui/ui_prompts.js +41 -0
  731. package/dist/workers/ui/ui_tools.d.ts +32 -0
  732. package/dist/workers/ui/ui_tools.js +112 -0
  733. package/dist/workers/ui/ui_worker.d.ts +571 -0
  734. package/dist/workers/ui/ui_worker.js +1156 -0
  735. package/package.json +61 -3
  736. package/README.md +0 -5
@@ -0,0 +1,806 @@
1
+ // Copyright (c) 2024-2026, Daily
2
+ // Copyright (c) 2026, pipedog contributors
3
+ // SPDX-License-Identifier: BSD-2-Clause
4
+ //
5
+ // Ported from pipecat: src/pipecat/pipeline/llm_with_backend.py
6
+ /**
7
+ * An LLM with a backend: a conversational frontend delegating the rest.
8
+ *
9
+ * The frontend is any LLM service, text or speech-to-speech, and holds the
10
+ * conversation. The backend is a `BackendLLMWorker` running a heavier model
11
+ * with the tools, and does the work the frontend hands off. `LLMWithBackend`
12
+ * wraps the frontend so the pair drops into a pipeline where an LLM goes, and
13
+ * installs the tools that join them.
14
+ *
15
+ * The two exchange messages. The frontend's `delegate` tool puts a message to
16
+ * the backend and returns at once; what the backend has to say comes back as a
17
+ * stream of outputs, each appended to the frontend's conversation as a message
18
+ * marked `Backend:`, spoken or silent as the backend's flag says. A second
19
+ * request joins the first, and a correction changes or stops it. How a request
20
+ * is worded is the `BackendRequestStrategy`'s business, and the
21
+ * `BackendConnector` owns the tools, the session with the backend, and how
22
+ * each output is rendered into the conversation.
23
+ */
24
+ import { Event, rethrowIfCancelled, TimeoutError, waitFor } from "@pipedog/asyncio";
25
+ import { FunctionSchema } from "../adapters/schemas/function_schema.js";
26
+ import { FunctionCallResultProperties, LLMMessagesAppendFrame } from "../frames/frames.js";
27
+ import { LLMSpecificMessage, } from "../processors/aggregators/llm_context.js";
28
+ import { RTVIServerMessageFrame } from "../processors/frameworks/rtvi/frames.js";
29
+ import { NotImplementedError, } from "../services/llm_service.js";
30
+ import { logger } from "../utils/logger.js";
31
+ import { _BackendSession, _renderExplicitRequest, _renderTranscriptRequest, BackendError, BackendIdle, BackendLLMWorker, BackendOutput, BackendToolCall, EXPLICIT_REQUEST_INSTRUCTION, TRANSCRIPT_REQUEST_INSTRUCTION, } from "../workers/llm/backend_llm_worker.js";
32
+ import { Pipeline } from "./pipeline.js";
33
+ /** Name of the tool the frontend calls to delegate. */
34
+ export const DELEGATE_TOOL_NAME = "delegate";
35
+ /** How a backend output is marked in the frontend's conversation. */
36
+ export const BACKEND_MESSAGE_PREFIX = "Backend: ";
37
+ /** How a backend reasoning summary is marked in the frontend's conversation. */
38
+ export const BACKEND_THOUGHT_PREFIX = "Backend (thinking): ";
39
+ /**
40
+ * How a backend note, text its model wrote without the mark that asks for the
41
+ * user to be told it, is marked in the frontend's conversation.
42
+ */
43
+ export const BACKEND_NOTE_PREFIX = "Backend (note): ";
44
+ /** How a function call the backend is making is marked in the frontend's conversation. */
45
+ export const BACKEND_WORKING_PREFIX = "Backend (working): ";
46
+ /** Every mark a rendered backend message can open with. */
47
+ export const BACKEND_PREFIXES = [
48
+ BACKEND_MESSAGE_PREFIX,
49
+ BACKEND_THOUGHT_PREFIX,
50
+ BACKEND_NOTE_PREFIX,
51
+ BACKEND_WORKING_PREFIX,
52
+ ];
53
+ /**
54
+ * Carried on each spoken backend message, so the frontend relays it on
55
+ * whatever turn it lands on, a user's turn included, where the standing
56
+ * instruction alone leaves it unsaid.
57
+ */
58
+ export const RELAY_NOTE = "(Relay this to the user now, in your own words, once, even if the conversation has " +
59
+ "moved on. If the user has just said something you have not answered yet, answer that " +
60
+ "first and relay this at the end of the same reply.)";
61
+ /** Where the request strategy's own guidance goes in `FRONTEND_PAIRING_INSTRUCTION`. */
62
+ export const STRATEGY_PLACEHOLDER = "{strategy}";
63
+ /**
64
+ * How the frontend's model works with a backend, appended to its system
65
+ * instruction: when and how to delegate, that to the user there is one
66
+ * assistant, what to do after delegating, and what to do with the backend's
67
+ * messages. The request strategy's guidance (how the request is worded) goes
68
+ * where `STRATEGY_PLACEHOLDER` stands, inside the delegating paragraph. The
69
+ * frontend's own system instruction says what the backend is for.
70
+ * `new BackendConnector({ frontendPairingInstruction })` replaces it.
71
+ *
72
+ * The order of the paragraphs matters, and the placeholder's place inside the
73
+ * first one: with the one-assistant paragraph first, or the strategy's
74
+ * guidance in a paragraph of its own, gpt-4.1 answers a user's "never mind"
75
+ * with "I won't make any changes" and no delegate call in nearly every run,
76
+ * where this order delegates the stop every time.
77
+ */
78
+ export const FRONTEND_PAIRING_INSTRUCTION = "DELEGATING: Delegate to the backend when any part of what the user asks needs a backend " +
79
+ "tool or careful reasoning, and whenever the user says anything about work already " +
80
+ "handed over: a change, a narrowing, or calling it off, in any words, even in passing. " +
81
+ "Whether that work goes on is not yours to decide: hand the message over and the " +
82
+ "backend decides. You cannot stop or change that work yourself, and nothing you say " +
83
+ "reaches the backend: only a delegate call does, so saying you will stop without one " +
84
+ "leaves the work running. A request that arrives while the backend is already working " +
85
+ "is delegated like any other. Do not delegate only when the message neither needs " +
86
+ "backend work nor concerns work already handed over: small talk, or a question you can " +
87
+ "answer from a result you already have, or when you need a brief clarification first. " +
88
+ "Delegate before giving any answer that depends on backend work, and do not guess the " +
89
+ "result while waiting. To delegate, call the delegate tool at once, in that same reply, " +
90
+ `and do the rest of the reply yourself around it. ${STRATEGY_PLACEHOLDER}\n\n` +
91
+ "ONE ASSISTANT: To the user there is one assistant, you: never mention the backend, " +
92
+ "delegation, a handoff or tools. Say what is being done as your own doing, such as \"I'm " +
93
+ 'checking" or "I\'ve fixed it", never "the backend is checking". A stop or a change you ' +
94
+ "hand over is your own doing too: never say that you passed it along, relayed it, handed " +
95
+ "it over or told anyone.\n\n" +
96
+ "AFTER DELEGATING: Acknowledge briefly, without offering updates or asking whether to " +
97
+ "go ahead, and do whatever else the user asked that you can do yourself. The result says " +
98
+ "whether the backend was idle or already working; if it was working, your request joins " +
99
+ "that work. The backend sees nothing of the conversation but what you delegate, so every " +
100
+ "new request that needs it takes a delegate call of its own, even while it is still " +
101
+ "working on an earlier one; that includes the user saying yes to something you or the " +
102
+ "backend offered to do, and the user calling off or changing work already under way, " +
103
+ "which the backend keeps doing until you hand that over. Saying you will check " +
104
+ "or look into something is not doing it: " +
105
+ "the backend hears nothing until you call delegate, so a reply that promises backend " +
106
+ "work calls delegate in that same reply. When the user asks whether work is under way, " +
107
+ "look at the conversation: if you never delegated it, say it is not started yet and delegate " +
108
+ "it then. When you hand over a stop or a change, the backend stops or changes the work as " +
109
+ "told: tell the user plainly that you are stopping or changing it, and do not promise results " +
110
+ "from work the user called off.\n\n" +
111
+ "BACKEND MESSAGES: The backend works on its own after you delegate and may be doing " +
112
+ "several things at once. What it has to say arrives as messages in the conversation " +
113
+ `marked "${BACKEND_MESSAGE_PREFIX.trim()}": a result, a question for the user, or news ` +
114
+ "worth an update, on whatever turn happens to be in progress by then. Such a message is " +
115
+ "owed to the user, whatever the conversation has moved on to: small talk, other " +
116
+ "questions or a long wait do not make it unwanted. If the user has said something you " +
117
+ "have not answered yet, answer that first, then relay the message at the end of that " +
118
+ "same reply, in your own words. If you have already answered everything the user said, " +
119
+ "relay just the message; do not repeat or rephrase your earlier reply. Relay each " +
120
+ "message once. Only when the user has cancelled or changed what they asked for does a " +
121
+ "message go unsaid, and then say only what still helps. Messages marked " +
122
+ `"${BACKEND_WORKING_PREFIX.trim()}", "${BACKEND_NOTE_PREFIX.trim()}" and ` +
123
+ `"${BACKEND_THOUGHT_PREFIX.trim()}" are what the backend is doing and thinking. They ` +
124
+ "carry no results: what a call found reaches you only in a message marked " +
125
+ `"${BACKEND_MESSAGE_PREFIX.trim()}", so never describe or guess what a call found. Never ` +
126
+ "relay them on their own, but when the user asks how the work is going, answer from the " +
127
+ "latest of them, concretely: name the step, such as which file it is reading or that it " +
128
+ "is running the tests, rather than saying only that it is still working. Never state a " +
129
+ "result you have not received from the backend, and never say work is done that the " +
130
+ "backend has not said is done.";
131
+ /** The transcript strategy's guidance, in the pairing instruction's delegating paragraph. */
132
+ export const TRANSCRIPT_FRONTEND_INSTRUCTION = "A delegation hands over the whole conversation, not one item: the backend reads it and " +
133
+ "does everything in it that is its job, so delegate once per reply however many things " +
134
+ "the user asked for, and do not word the request.";
135
+ /** How the transcript strategy describes the `delegate` tool. */
136
+ export const TRANSCRIPT_TOOL_DESCRIPTION = "Hand the conversation over to the backend, which reads it and does everything in it " +
137
+ "that needs a backend tool or careful reasoning. Call this as soon as any part of what " +
138
+ "the user asks needs that, and do the rest yourself. One handoff per reply, however " +
139
+ "many things the user asked for: two questions, or one question about two places, is " +
140
+ "one handoff. The backend sees nothing but what is handed over, so a request the user " +
141
+ "makes after your last handoff needs a handoff of its own, even while the backend is " +
142
+ "still working, and so does anything the user says about work already handed over: a " +
143
+ "change, a narrowing, or calling it off, in any words. It takes no arguments. Keep " +
144
+ "talking with the user while it works.";
145
+ /** The explicit strategy's guidance, in the pairing instruction's delegating paragraph. */
146
+ export const EXPLICIT_FRONTEND_INSTRUCTION = "Word the request so it stands on its own: the user's goal, the exact " +
147
+ "details they gave and their latest correction, with everything new they asked for in " +
148
+ "the one request, so you delegate once per reply however many things that is. Work " +
149
+ "already handed over stays with the backend: a new request joins it, so do not restate " +
150
+ "earlier requests; a correction names what changes, and a stop names what to stop.";
151
+ /** How the explicit strategy describes the `delegate` tool. */
152
+ export const EXPLICIT_TOOL_DESCRIPTION = "Hand a request to the backend, which does everything in it that needs a backend tool " +
153
+ "or careful reasoning. Call this as soon as any part of what the user asks needs that, " +
154
+ "with the request worded to stand on its own, and do the rest yourself. One call per " +
155
+ "reply, however many things the user asked for: two questions, or one question about " +
156
+ "two places, go in one request. Work already handed over stays with the backend, so " +
157
+ "send only what is new, including anything the user says about that work, such as to " +
158
+ "stop or change it. Keep talking with the user while it works.";
159
+ /** Python's `repr()` of a string: single-quoted unless it holds only single quotes. */
160
+ function reprStr(s) {
161
+ const quote = s.includes("'") && !s.includes('"') ? '"' : "'";
162
+ let out = "";
163
+ for (const ch of s) {
164
+ if (ch === "\\")
165
+ out += "\\\\";
166
+ else if (ch === quote)
167
+ out += `\\${ch}`;
168
+ else if (ch === "\n")
169
+ out += "\\n";
170
+ else if (ch === "\r")
171
+ out += "\\r";
172
+ else if (ch === "\t")
173
+ out += "\\t";
174
+ else if (ch < " " || ch === "\x7f")
175
+ out += `\\x${ch.charCodeAt(0).toString(16).padStart(2, "0")}`;
176
+ else
177
+ out += ch;
178
+ }
179
+ return `${quote}${out}${quote}`;
180
+ }
181
+ /** Approximation of Python's `repr()` for log lines and rendered arguments. */
182
+ function repr(value) {
183
+ if (value === null || value === undefined)
184
+ return "None";
185
+ if (typeof value === "string")
186
+ return reprStr(value);
187
+ if (typeof value === "boolean")
188
+ return value ? "True" : "False";
189
+ if (typeof value === "object") {
190
+ try {
191
+ return JSON.stringify(value);
192
+ }
193
+ catch {
194
+ return String(value);
195
+ }
196
+ }
197
+ return String(value);
198
+ }
199
+ /**
200
+ * What a connector needs to know about the layers it joins.
201
+ *
202
+ * - `backendName`: name of the backend worker, local or registered elsewhere.
203
+ * - `frontendIsRealtime`: whether the frontend is a speech-to-speech service,
204
+ * whose context can lag the audio, which changes how a delegation words its
205
+ * request.
206
+ */
207
+ export class ConnectorContext {
208
+ backendName;
209
+ frontendIsRealtime;
210
+ constructor(options) {
211
+ this.backendName = options.backendName;
212
+ this.frontendIsRealtime = options.frontendIsRealtime;
213
+ }
214
+ }
215
+ // ---------------------------------------------------------------------------
216
+ // Request strategies: frontend → backend
217
+ //
218
+ // Two ways for a delegate call to become the backend's request, chosen by
219
+ // frontend kind when the app gives none. TranscriptBackendRequestStrategy
220
+ // hands over the conversation since the previous delegation: the default for
221
+ // a text frontend, whose context is current when the tool runs.
222
+ // ExplicitBackendRequestStrategy has the frontend model word the request
223
+ // itself: the default for a speech-to-speech frontend, which responds to audio
224
+ // before the transcript of that audio reaches its context, so the turns that
225
+ // prompted a handoff may not be in the context yet, and a transcript taken
226
+ // then would miss them.
227
+ // ---------------------------------------------------------------------------
228
+ /**
229
+ * Defines the `delegate` tool the frontend calls, and turns a call into the
230
+ * request the backend receives.
231
+ *
232
+ * The tool's parameters are this strategy's to declare, so the connector's
233
+ * handler has one signature and reads whatever was declared back from
234
+ * `params.arguments` in `composeRequest`.
235
+ */
236
+ export class BackendRequestStrategy {
237
+ /** JSON-schema properties of the `delegate` tool; empty when it takes none. */
238
+ toolParameters = {};
239
+ /** Which of the properties are required. */
240
+ toolRequired = [];
241
+ /**
242
+ * The strategy's guidance to the frontend model, if any: how the request is
243
+ * worded. It goes where the pairing instruction's `STRATEGY_PLACEHOLDER`
244
+ * stands.
245
+ */
246
+ frontendInstruction = null;
247
+ /** How the `delegate` tool is described to the frontend model. */
248
+ toolDescription = "";
249
+ /**
250
+ * Whether the strategy reads the conversation from the frontend's context,
251
+ * so it needs that context to be current when the `delegate` tool runs. A
252
+ * speech-to-speech frontend's context lags the audio, so the connector
253
+ * refuses such a strategy there.
254
+ */
255
+ requiresContext = false;
256
+ /**
257
+ * Turn a `delegate` call into the text put to the backend.
258
+ *
259
+ * @param params The call, carrying the arguments the tool declared and the
260
+ * frontend's context.
261
+ * @returns The request text, or null when the call carries nothing new for
262
+ * the backend, in which case nothing is sent.
263
+ */
264
+ async composeRequest(_params) {
265
+ throw new NotImplementedError();
266
+ }
267
+ }
268
+ /**
269
+ * Hands the backend the conversation and lets it work out the request.
270
+ *
271
+ * The frontend model calls the tool with no arguments; the request is the
272
+ * transcript of what was said since the previous delegation (the whole
273
+ * conversation the first time), rendered by `_renderTranscriptRequest`. The
274
+ * backend's own messages in the conversation are left out: the backend
275
+ * already has what it said. The default for a text frontend, whose context is
276
+ * current when the tool runs.
277
+ *
278
+ * The cursor assumes the conversation accrues. A rewritten context or a failed
279
+ * delegation's turns are not re-sent; the user's next request carries what
280
+ * matters. A call that finds no new turn since the previous delegation sends
281
+ * nothing.
282
+ */
283
+ export class TranscriptBackendRequestStrategy extends BackendRequestStrategy {
284
+ requiresContext = true;
285
+ _requestInstruction;
286
+ _delegatedThrough = 0;
287
+ /** Initialize the strategy. */
288
+ constructor(options = {}) {
289
+ super();
290
+ this.frontendInstruction =
291
+ options.frontendInstruction === undefined
292
+ ? TRANSCRIPT_FRONTEND_INSTRUCTION
293
+ : options.frontendInstruction;
294
+ this.toolDescription = options.toolDescription ?? TRANSCRIPT_TOOL_DESCRIPTION;
295
+ this._requestInstruction = options.requestInstruction ?? TRANSCRIPT_REQUEST_INSTRUCTION;
296
+ }
297
+ /** Render the turns since the previous delegation as the request. */
298
+ async composeRequest(params) {
299
+ const messages = params.context.getMessages();
300
+ if (this._delegatedThrough > messages.length) {
301
+ // The context holds fewer messages than the previous delegation read:
302
+ // it was reset since, so the transcript starts from the top.
303
+ this._delegatedThrough = 0;
304
+ }
305
+ // An LLMSpecificMessage, in a service's own format, is not a user or
306
+ // assistant turn, so the transcript leaves it out.
307
+ const conversation = messages
308
+ .slice(this._delegatedThrough)
309
+ .filter((m) => isStandardMessage(m) && !_isBackendMessage(m));
310
+ const first = this._delegatedThrough === 0;
311
+ this._delegatedThrough = messages.length;
312
+ if (!conversation.some((m) => m.role === "user" || m.role === "assistant")) {
313
+ return null;
314
+ }
315
+ return _renderTranscriptRequest(conversation, {
316
+ instruction: this._requestInstruction,
317
+ first,
318
+ });
319
+ }
320
+ }
321
+ /**
322
+ * Has the frontend model word the request itself.
323
+ *
324
+ * The tool takes a `request` argument, which is sent to the backend as it
325
+ * stands. The default for a speech-to-speech frontend, which responds to audio
326
+ * before the transcript of that audio reaches its context, so the turns that
327
+ * prompted a handoff may not be recorded when the tool runs.
328
+ */
329
+ export class ExplicitBackendRequestStrategy extends BackendRequestStrategy {
330
+ toolParameters = {
331
+ request: {
332
+ type: "string",
333
+ description: "What the user is asking for now, self-contained: their goal, the details " +
334
+ "they gave (places, dates, names) and their latest correction, or what they " +
335
+ "said about work already under way, such as to stop it or change it. Work " +
336
+ "already handed over stays with the backend; a new request joins it, so do " +
337
+ "not restate earlier requests.",
338
+ },
339
+ };
340
+ toolRequired = ["request"];
341
+ _requestInstruction;
342
+ /** Initialize the strategy. */
343
+ constructor(options = {}) {
344
+ super();
345
+ this.frontendInstruction =
346
+ options.frontendInstruction === undefined
347
+ ? EXPLICIT_FRONTEND_INSTRUCTION
348
+ : options.frontendInstruction;
349
+ this.toolDescription = options.toolDescription ?? EXPLICIT_TOOL_DESCRIPTION;
350
+ this._requestInstruction = options.requestInstruction ?? EXPLICIT_REQUEST_INSTRUCTION;
351
+ }
352
+ /** Send the model's request as it stands, with the reporting expectation after it. */
353
+ async composeRequest(params) {
354
+ const raw = params.arguments.request;
355
+ const request = String(raw || "").trim();
356
+ if (!request) {
357
+ return null;
358
+ }
359
+ return _renderExplicitRequest(request, { instruction: this._requestInstruction });
360
+ }
361
+ }
362
+ /** Whether a context message is a plain (dict) message rather than an LLM-specific one. */
363
+ function isStandardMessage(message) {
364
+ return (message !== null && typeof message === "object" && !(message instanceof LLMSpecificMessage));
365
+ }
366
+ /** Whether a context message is one the connector rendered from a backend output. */
367
+ export function _isBackendMessage(message) {
368
+ if (!isStandardMessage(message)) {
369
+ return false;
370
+ }
371
+ const content = message.content;
372
+ return (message.role === "developer" &&
373
+ typeof content === "string" &&
374
+ BACKEND_PREFIXES.some((prefix) => content.startsWith(prefix)));
375
+ }
376
+ /**
377
+ * Joins the two layers: the tools the frontend calls, the session with the
378
+ * backend, and what each output becomes.
379
+ *
380
+ * A request strategy defines the `delegate` tool and composes the request. It
381
+ * may be given, or left to the connector to pick by frontend kind once bound:
382
+ * `TranscriptBackendRequestStrategy` for a text frontend,
383
+ * `ExplicitBackendRequestStrategy` for a speech-to-speech one, whose context
384
+ * lags the audio. A given strategy that reads the frontend's context
385
+ * (`BackendRequestStrategy.requiresContext`) is refused for a speech-to-speech
386
+ * frontend.
387
+ *
388
+ * The connector holds the session with the backend for the frontend's life,
389
+ * and turns each output the backend sends into a message appended to the
390
+ * frontend's conversation with `renderOutput`, run or not as the output's
391
+ * `prefersSpoken` flag says. The function calls the backend makes on the way
392
+ * are reported in the frontend's pipeline for clients to show; nothing else in
393
+ * the pipeline sees them.
394
+ *
395
+ * @example
396
+ * const connector = new BackendConnector({ respondOnDelegate: false });
397
+ */
398
+ export class BackendConnector {
399
+ _requestStrategy;
400
+ _frontendPairingInstruction;
401
+ _respondOnDelegate;
402
+ _timeoutSecs;
403
+ _clientTrace;
404
+ _context = null;
405
+ _tools = [];
406
+ _session = null;
407
+ _sessionOpen = new Event();
408
+ /** Initialize the connector. */
409
+ constructor(options = {}) {
410
+ this._requestStrategy = options.requestStrategy ?? null;
411
+ this._frontendPairingInstruction =
412
+ options.frontendPairingInstruction ?? FRONTEND_PAIRING_INSTRUCTION;
413
+ this._respondOnDelegate = options.respondOnDelegate ?? true;
414
+ this._timeoutSecs = options.timeoutSecs === undefined ? 30 : options.timeoutSecs;
415
+ this._clientTrace = options.clientTrace ?? false;
416
+ }
417
+ /** The request strategy in use. Available once bound. */
418
+ get requestStrategy() {
419
+ if (this._requestStrategy === null)
420
+ throw new Error("connector not bound");
421
+ return this._requestStrategy;
422
+ }
423
+ /** The tools to install on the frontend. Available once bound. */
424
+ get tools() {
425
+ if (this._tools.length === 0)
426
+ throw new Error("connector not bound");
427
+ return this._tools;
428
+ }
429
+ /** The `delegate` tool. Available once bound. */
430
+ get tool() {
431
+ return this.tools[0];
432
+ }
433
+ /**
434
+ * What is appended to the frontend's system instruction: the pairing
435
+ * instruction with the strategy's guidance in place. Available once bound.
436
+ */
437
+ get frontendInstruction() {
438
+ const pairing = this._frontendPairingInstruction;
439
+ const guidance = this.requestStrategy.frontendInstruction || "";
440
+ if (pairing.includes(STRATEGY_PLACEHOLDER)) {
441
+ return pairing.replaceAll(STRATEGY_PLACEHOLDER, guidance).replaceAll(" \n", "\n").trim();
442
+ }
443
+ return [pairing, guidance].filter((p) => p).join("\n\n") || null;
444
+ }
445
+ /** The session with the backend, while one is open. */
446
+ get session() {
447
+ return this._session;
448
+ }
449
+ /**
450
+ * Settle the strategy for the layers being joined and build the tools.
451
+ *
452
+ * @param context The layers.
453
+ * @throws Error If the frontend is speech-to-speech and the strategy reads
454
+ * the frontend's context, which lags the audio there.
455
+ */
456
+ bind(context) {
457
+ this._context = context;
458
+ if (this._requestStrategy === null) {
459
+ this._requestStrategy = context.frontendIsRealtime
460
+ ? new ExplicitBackendRequestStrategy()
461
+ : new TranscriptBackendRequestStrategy();
462
+ }
463
+ if (context.frontendIsRealtime && this._requestStrategy.requiresContext) {
464
+ throw new Error(`${this._requestStrategy.constructor.name} reads the conversation from the ` +
465
+ "frontend's context, which lags the audio on a speech-to-speech frontend. " +
466
+ "Use a request strategy that doesn't read the context, such as " +
467
+ "ExplicitBackendRequestStrategy.");
468
+ }
469
+ this._tools = this.buildTools();
470
+ }
471
+ /**
472
+ * Build the tools to install on the frontend: `delegate`.
473
+ *
474
+ * Override to install tools of another shape entirely; the service reads
475
+ * nothing else from the connector but `frontendInstruction`.
476
+ *
477
+ * @returns The tools, each carrying its handler.
478
+ */
479
+ buildTools() {
480
+ const delegate = async (params) => {
481
+ await this.delegate(params);
482
+ };
483
+ return [
484
+ new FunctionSchema({
485
+ name: DELEGATE_TOOL_NAME,
486
+ description: this.requestStrategy.toolDescription,
487
+ properties: this.requestStrategy.toolParameters,
488
+ required: this.requestStrategy.toolRequired,
489
+ handler: delegate,
490
+ }),
491
+ ];
492
+ }
493
+ /**
494
+ * Hold the session with the backend, delivering what it produces, until cancelled.
495
+ *
496
+ * @param worker The pipeline worker the frontend runs in.
497
+ * @param frontend The frontend service, which takes the deliveries.
498
+ */
499
+ async runSession(worker, frontend) {
500
+ const context = this._context;
501
+ if (context === null)
502
+ throw new Error("connector not bound");
503
+ try {
504
+ const session = new _BackendSession(worker, context.backendName, {
505
+ timeoutSecs: this._timeoutSecs,
506
+ });
507
+ await session.run(async (session) => {
508
+ this._session = session;
509
+ this._sessionOpen.set();
510
+ for await (const event of session) {
511
+ await this.deliver(frontend, event);
512
+ }
513
+ if (!session.detached) {
514
+ logger.warning(`Backend '${context.backendName}' went away`);
515
+ }
516
+ });
517
+ }
518
+ catch (e) {
519
+ rethrowIfCancelled(e);
520
+ logger.error(`The session with backend '${context.backendName}' failed: ${e instanceof Error ? e.message : e}`);
521
+ }
522
+ finally {
523
+ this._session = null;
524
+ this._sessionOpen.clear();
525
+ }
526
+ }
527
+ /** The session, once it is open; waits for it up to the timeout. */
528
+ async _openSession() {
529
+ if (this._session === null) {
530
+ try {
531
+ await waitFor(() => this._sessionOpen.wait(), this._timeoutSecs);
532
+ }
533
+ catch (e) {
534
+ if (e instanceof TimeoutError) {
535
+ throw new Error("the backend is not attached");
536
+ }
537
+ throw e;
538
+ }
539
+ }
540
+ if (this._session === null)
541
+ throw new Error("the backend is not attached");
542
+ return this._session;
543
+ }
544
+ /**
545
+ * Put the request a `delegate` call carries to the backend, and settle the call at once.
546
+ *
547
+ * @param params The `delegate` call.
548
+ */
549
+ async delegate(params) {
550
+ const context = this._context;
551
+ if (context === null)
552
+ throw new Error("connector not bound");
553
+ const request = await this.requestStrategy.composeRequest(params);
554
+ if (request === null) {
555
+ // No turns since the previous delegation: the backend already has
556
+ // everything the transcript would carry, so nothing is sent.
557
+ logger.debug(`Delegate call ${params.toolCallId} carries nothing new; not sent`);
558
+ await params.resultCallback({ status: "already_delegated" }, { properties: new FunctionCallResultProperties({ runLlm: false }) });
559
+ return;
560
+ }
561
+ logger.debug(`Delegating to '${context.backendName}': ${repr(request)}`);
562
+ const session = await this._openSession();
563
+ const status = await session.send(request);
564
+ await this._trace(params.llm, { event: "request", text: request, backend: status });
565
+ await params.resultCallback({ status: "delegated", backend: status }, { properties: new FunctionCallResultProperties({ runLlm: this._respondOnDelegate }) });
566
+ }
567
+ /**
568
+ * Deliver one thing the backend produced to the frontend.
569
+ *
570
+ * An output becomes a message appended to the frontend's conversation, which
571
+ * runs the frontend when the output asks to be spoken. A function call phase
572
+ * is reported as the `ExternalFunctionCall*Frame` for it, which the RTVI
573
+ * observer turns into function-call events. An error becomes a spoken
574
+ * message, so the user hears the work stopped. The appended messages are
575
+ * uninterruptible: one queued while the bot speaks waits behind that speech,
576
+ * and an interruption clears the speech but must leave the message to be
577
+ * recorded.
578
+ *
579
+ * @param frontend The frontend service.
580
+ * @param event What the backend produced.
581
+ */
582
+ async deliver(frontend, event) {
583
+ if (event instanceof BackendOutput) {
584
+ await this._trace(frontend, {
585
+ event: "output",
586
+ text: event.text,
587
+ spoken: event.prefersSpoken,
588
+ thought: event.isThought,
589
+ });
590
+ logger.debug(`Backend output (${event.prefersSpoken ? "spoken" : "silent"}` +
591
+ `${event.isThought ? ", thought" : ""}): ${repr(event.text)}`);
592
+ const message = this.renderOutput(event);
593
+ if (message !== null) {
594
+ await this._append(frontend, new LLMMessagesAppendFrame({ messages: [message], runLlm: event.prefersSpoken }));
595
+ }
596
+ }
597
+ else if (event instanceof BackendToolCall) {
598
+ await this._trace(frontend, {
599
+ event: "tool_call",
600
+ phase: event.phase,
601
+ name: event.functionName,
602
+ arguments: event.arguments,
603
+ result: event.result,
604
+ });
605
+ await frontend.pushFrame(event.toFrame());
606
+ const message = this.renderToolCall(event);
607
+ if (message !== null) {
608
+ await this._append(frontend, new LLMMessagesAppendFrame({ messages: [message], runLlm: false }));
609
+ }
610
+ }
611
+ else if (event instanceof BackendError) {
612
+ await this._trace(frontend, { event: "error", error: event.error });
613
+ logger.warning(`Backend error: ${event.error}`);
614
+ await this._append(frontend, new LLMMessagesAppendFrame({
615
+ messages: [
616
+ {
617
+ role: "developer",
618
+ content: `${BACKEND_MESSAGE_PREFIX}The work could not be completed.\n\n${RELAY_NOTE}`,
619
+ },
620
+ ],
621
+ runLlm: true,
622
+ }));
623
+ }
624
+ else if (event instanceof BackendIdle) {
625
+ await this._trace(frontend, { event: "idle" });
626
+ logger.debug("Backend is idle");
627
+ }
628
+ }
629
+ /** Send one exchange with the backend to the client, when tracing is on. */
630
+ async _trace(frontend, data) {
631
+ if (this._clientTrace) {
632
+ await frontend.pushFrame(new RTVIServerMessageFrame({ data: { type: "llm-with-backend", ...data } }));
633
+ }
634
+ }
635
+ /** Queue a message into the frontend's conversation, past any interruption on the way. */
636
+ async _append(frontend, frame) {
637
+ frame.interruptible = false;
638
+ await frontend.queueFrame(frame);
639
+ }
640
+ /**
641
+ * Render a backend output as the message the frontend's conversation takes in.
642
+ *
643
+ * Override for another wording, role, or to leave some outputs out by
644
+ * returning null. The default marks the message so the frontend can tell it
645
+ * from the user's and its own, and so the transcript request strategy can
646
+ * leave it out of what it sends the backend: a spoken output as `Backend:`
647
+ * with `RELAY_NOTE` after it, a silent one as `Backend (note):`, a reasoning
648
+ * summary as `Backend (thinking):`.
649
+ *
650
+ * @param output The output.
651
+ * @returns The message, or null to deliver nothing for this output.
652
+ */
653
+ renderOutput(output) {
654
+ if (!output.text) {
655
+ return null;
656
+ }
657
+ if (output.isThought) {
658
+ return { role: "developer", content: `${BACKEND_THOUGHT_PREFIX}${output.text}` };
659
+ }
660
+ if (!output.prefersSpoken) {
661
+ return { role: "developer", content: `${BACKEND_NOTE_PREFIX}${output.text}` };
662
+ }
663
+ return {
664
+ role: "developer",
665
+ content: `${BACKEND_MESSAGE_PREFIX}${output.text}\n\n${RELAY_NOTE}`,
666
+ };
667
+ }
668
+ /**
669
+ * Render a phase of a backend function call as a message the frontend's
670
+ * conversation takes in, silently.
671
+ *
672
+ * The default records each call as it starts, with its arguments, so the
673
+ * frontend can say what the backend is doing if asked; the other phases are
674
+ * not recorded. Override to record more, less, or nothing.
675
+ *
676
+ * @param call The phase of the call.
677
+ * @returns The message, or null to record nothing for this phase.
678
+ */
679
+ renderToolCall(call) {
680
+ if (call.phase !== "in_progress") {
681
+ return null;
682
+ }
683
+ const args = Object.entries(call.arguments ?? {})
684
+ .map(([k, v]) => `${k}=${repr(v)}`)
685
+ .join(", ");
686
+ return {
687
+ role: "developer",
688
+ content: `${BACKEND_WORKING_PREFIX}${call.functionName}(${args})`,
689
+ };
690
+ }
691
+ }
692
+ /**
693
+ * A conversational LLM, kept fast and light, with a backend that does the
694
+ * work it hands off.
695
+ *
696
+ * **Alpha.** The API is unstable: names, arguments, the strategies and the job
697
+ * contract are likely to change between releases.
698
+ *
699
+ * Put it where the LLM goes in a pipeline. It is a `Pipeline`, not an
700
+ * `LLMService`: functions, settings updates, event handlers and a
701
+ * `FlowManager` go on `frontend`. It wraps the frontend service, installs the
702
+ * connector's tools on it as built-in tools, appends the connector's guidance
703
+ * to the frontend's system instruction, adds a local backend worker to the
704
+ * pipeline worker so the app never wires it up, and holds the session with
705
+ * the backend for the pipeline's life. A built-in tool is sent on every
706
+ * inference beside whatever tools the frontend has, and never enters the
707
+ * context's tool set, so a tool change announced to the model never mentions
708
+ * it. The tools are the backend's; the frontend has `delegate` and no more,
709
+ * though a tool it must keep, in its context or configured on the service,
710
+ * stays.
711
+ *
712
+ * The guidance is the connector's pairing instruction (how to work with a
713
+ * backend: when and how to delegate, and what to do with the backend's
714
+ * messages) with the strategy's (how the request is worded) in place. The
715
+ * frontend's own system instruction is the place to say what the backend is
716
+ * for, in plain words, as the backend's own instruction does: no tool names,
717
+ * nothing to update when a tool changes.
718
+ *
719
+ * @example
720
+ * const llm = new LLMWithBackend({
721
+ * frontend: new OpenAILLMService({ ... }),
722
+ * backend: new BackendLLMWorker({
723
+ * llm: new AnthropicLLMService({ ... }),
724
+ * context: new LLMContext({ tools: [getWeather] }),
725
+ * }),
726
+ * });
727
+ * const pipeline = new Pipeline([transport.input(), stt, userAgg, llm, tts, transport.output(), assistantAgg]);
728
+ */
729
+ export class LLMWithBackend extends Pipeline {
730
+ _frontend;
731
+ _backend;
732
+ _connector;
733
+ _sessionTask = null;
734
+ /**
735
+ * Initialize the service.
736
+ *
737
+ * @throws Error If the frontend service declines the role, or the
738
+ * connector's request strategy reads the frontend's context and the
739
+ * frontend is speech-to-speech.
740
+ */
741
+ constructor(options) {
742
+ const { frontend, backend } = options;
743
+ logger.warning("LLMWithBackend is alpha: its API is likely to change between releases.");
744
+ const objection = frontend.llmWithBackendRoleObjection("frontend");
745
+ if (objection) {
746
+ throw new Error(objection);
747
+ }
748
+ const connector = options.connector || new BackendConnector();
749
+ connector.bind(new ConnectorContext({
750
+ backendName: typeof backend === "string" ? backend : backend.name,
751
+ frontendIsRealtime: frontend.serviceMetadataFrame().isRealtimeService,
752
+ }));
753
+ const instruction = connector.frontendInstruction;
754
+ if (instruction) {
755
+ frontend.appendSystemInstruction(instruction);
756
+ }
757
+ for (const tool of connector.tools) {
758
+ frontend.registerFunction(tool.name, tool.handler, {
759
+ cancelOnInterruption: false,
760
+ });
761
+ frontend.getLlmAdapter().builtinTools[tool.name] = tool;
762
+ }
763
+ super([frontend]);
764
+ this._frontend = frontend;
765
+ this._backend = backend;
766
+ this._connector = connector;
767
+ }
768
+ /** The frontend LLM service. */
769
+ get frontend() {
770
+ return this._frontend;
771
+ }
772
+ /** The backend worker, or its name. */
773
+ get backend() {
774
+ return this._backend;
775
+ }
776
+ /** The connector joining the two layers. */
777
+ get connector() {
778
+ return this._connector;
779
+ }
780
+ /** The `delegate` tool installed on the frontend. */
781
+ get tool() {
782
+ return this._connector.tool;
783
+ }
784
+ /**
785
+ * Register a local backend worker as a child of the pipeline worker, set up
786
+ * the frontend, and open the session.
787
+ */
788
+ async setup(setup) {
789
+ // Before setting the frontend up: it gets the StartFrame as soon as its
790
+ // own setup is done, and can delegate from then on.
791
+ if (this._backend instanceof BackendLLMWorker) {
792
+ await setup.pipelineWorker.addWorkers(this._backend);
793
+ }
794
+ await super.setup(setup);
795
+ this._sessionTask = this.createTask(() => this._connector.runSession(this.pipelineWorker, this._frontend), `${this}::backend_session`);
796
+ }
797
+ /** Close the session with the backend, then clean up the frontend. */
798
+ async cleanup() {
799
+ if (this._sessionTask !== null) {
800
+ await this.cancelTask(this._sessionTask);
801
+ this._sessionTask = null;
802
+ }
803
+ await super.cleanup();
804
+ }
805
+ }
806
+ //# sourceMappingURL=llm_with_backend.js.map